Snap for 9550355 from 2c94df4e4919c129bc5ed99ad012659395a2257d to sdk-release

Change-Id: I8640c3ef14b4548251b8ee7c626bd75bd5d07239
diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 0000000..e2b197d
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,2 @@
+[patch.crates-io]
+bssl-ffi = { package = "bssl-sys", version = "0.1.0", path = "../../../boringssl/build/rust", optional=true }
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..1b8def3
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "7db5cc72d326360ffa62398201635effedb885c6"
+  },
+  "path_in_vcs": "openssl"
+}
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index a93e396..4e9011c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,5 @@
-// This file is generated by cargo2android.py --config cargo2android.json.
+// This file is generated by cargo2android.py --config ./cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
 
 // WARNING! This crate has a change in dependency structure that is not yet
 // reflected on crates.io. This means that the automated update tool will
@@ -48,40 +49,24 @@
     name: "libopenssl",
     host_supported: true,
     crate_name: "openssl",
-    srcs: ["openssl/src/lib.rs"],
-    vendor_available: true,
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.10.43",
+    srcs: ["src/lib.rs"],
     edition: "2018",
-    cfgs: [
-        "boringssl",
-    ],
-    features: [
-        "boringssl",
-    ],
-    proc_macros: [
-        "libopenssl_macros",
-    ],
+    features: ["unstable_boringssl"],
+    cfgs: ["boringssl", "soong"],
     rustlibs: [
         "libbitflags",
-        "libbssl_ffi",
         "libcfg_if",
+        "libbssl_ffi",
         "libforeign_types",
         "liblibc",
         "libonce_cell",
     ],
+    proc_macros: ["libopenssl_macros"],
     apex_available: [
         "//apex_available:platform",
         "com.android.virt",
     ],
-}
-
-rust_proc_macro {
-    name: "libopenssl_macros",
-    crate_name: "openssl_macros",
-    srcs: ["openssl-macros/src/lib.rs"],
-    edition: "2018",
-    rustlibs: [
-        "libquote",
-	"libsyn",
-	"libproc_macro2",
-    ],
+    vendor_available: true,
 }
diff --git a/openssl/CHANGELOG.md b/CHANGELOG.md
similarity index 90%
rename from openssl/CHANGELOG.md
rename to CHANGELOG.md
index 3604cae..3156498 100644
--- a/openssl/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,73 @@
 
 ## [Unreleased]
 
+## [v0.10.43] - 2022-11-23
+
+### Added
+
+* Added `Nid::BRAINPOOL_P256R1`, `Nid::BRAINPOOL_P384R1`, `Nid::BRAINPOOL_P512R1`.
+* Added `BigNumRef::copy_from_slice`.
+* Added `Cipher` constructors for Camellia, CAST5, and IDEA ciphers.
+* Added `DsaSig`.
+* Added `X509StoreBuilderRef::set_param`.
+* Added `X509VerifyParam::new`, `X509VerifyParamRef::set_time`, and `X509VerifyParamRef::set_depth`.
+
+## [v0.10.42] - 2022-09-26
+
+### Added
+
+* Added `SslRef::psk_identity_hint` and  `SslRef::psk_identity`.
+* Added SHA-3 constants to `Nid`.
+* Added `SslOptions::PRIORITIZE_CHACHA`.
+* Added `X509ReqRef::to_text`.
+* Added `MdCtxRef::size`.
+* Added `X509NameRef::try_cmp`.
+* Added `MdCtxRef::reset`.
+* Added experimental, unstable support for BoringSSL.
+
+### Fixed
+
+* Fixed `MdCtxRef::digest_verify_init` to support `PKey`s with only public components.
+
+## [v0.10.41] - 2022-06-09
+
+### Fixed
+
+* Fixed a use-after-free in `Error::function` and `Error::file` with OpenSSL 3.x.
+
+### Added
+
+* Added `MessageDigest::block_size` and `MdRef::block_size`.
+* Implemented `Ord` and `Eq` for `X509` and `X509Ref`.
+* Added `X509Extension::add_alias`.
+* Added SM4 support.
+* Added `EcGroup::from_components` `EcGropuRef::set_generator`, and `EcPointRef::set_affine_coordinates_gfp`.
+
+## [v0.10.40] - 2022-05-04
+
+### Fixed
+
+* Fixed the openssl-sys dependency version.
+
+## [v0.10.39] - 2022-05-02
+
+### Deprecated
+
+* Deprecated `SslContextBuilder::set_tmp_ecdh_callback` and `SslRef::set_tmp_ecdh_callback`.
+
+### Added
+
+* Added `SslRef::extms_support`.
+* Added `Nid::create`.
+* Added `CipherCtx`, which exposes a more direct interface to `EVP_CIPHER_CTX`.
+* Added `PkeyCtx`, which exposes a more direct interface to `EVP_PKEY_CTX`.
+* Added `MdCtx`, which exposes a more direct interface to `EVP_MD_CTX`.
+* Added `Pkcs12Builder::mac_md`.
+* Added `Provider`.
+* Added `X509Ref::issuer_name_hash`.
+* Added `Decrypter::set_rsa_oaep_label`.
+* Added `X509Ref::to_text`.
+
 ## [v0.10.38] - 2021-10-31
 
 ### Added
@@ -574,7 +641,12 @@
 
 Look at the [release tags] for information about older releases.
 
-[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.38...master
+[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.43...master
+[v0.10.43]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.42...openssl-v0.10.43
+[v0.10.42]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.41...openssl-v0.10.42
+[v0.10.41]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.40...openssl-v0.10.41
+[v0.10.40]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.39...openssl-v0.10.40
+[v0.10.39]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.38...openssl-v0.10.39
 [v0.10.38]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.37...openssl-v0.10.38
 [v0.10.37]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.36...openssl-v0.10.37
 [v0.10.36]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.35...openssl-v0.10.36
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..2ab7922
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,463 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bindgen"
+version = "0.60.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "clap",
+ "env_logger",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "which",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bssl-sys"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "312d12393c060384f2e6ed14c7b4be37b3dd90249857485613c1a91b9a1abb5c"
+
+[[package]]
+name = "cc"
+version = "1.0.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "clap"
+version = "3.2.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
+dependencies = [
+ "atty",
+ "bitflags",
+ "clap_lex",
+ "indexmap",
+ "strsim",
+ "termcolor",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "either"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+
+[[package]]
+name = "env_logger"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hex"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "indexmap"
+version = "1.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.137"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
+[[package]]
+name = "openssl"
+version = "0.10.43"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "hex",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-src"
+version = "111.24.0+1.1.1s"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3498f259dab01178c6228c6b00dcef0ed2a2d5e20d648c017861227773ea4abd"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132"
+dependencies = [
+ "autocfg",
+ "bindgen",
+ "bssl-sys",
+ "cc",
+ "libc",
+ "openssl-src",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "os_str_bytes"
+version = "6.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "shlex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "which"
+version = "4.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
+dependencies = [
+ "either",
+ "libc",
+ "once_cell",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
index 63e983a..bd166a8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,11 +1,65 @@
-[workspace]
-members = [
-    "openssl",
-    "openssl-errors",
-    "openssl-macros",
-    "openssl-sys",
-    "systest",
-]
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
 
-[patch.crates-io]
-bindgen = { git = "https://github.com/daviddrysdale/rust-bindgen", branch = "allowlist-file" }
+[package]
+edition = "2018"
+name = "openssl"
+version = "0.10.43"
+authors = ["Steven Fackler <sfackler@gmail.com>"]
+description = "OpenSSL bindings"
+readme = "README.md"
+keywords = [
+    "crypto",
+    "tls",
+    "ssl",
+    "dtls",
+]
+categories = [
+    "cryptography",
+    "api-bindings",
+]
+license = "Apache-2.0"
+repository = "https://github.com/sfackler/rust-openssl"
+
+[dependencies.bitflags]
+version = "1.0"
+
+[dependencies.cfg-if]
+version = "1.0"
+
+[dependencies.ffi]
+version = "0.9.78"
+package = "openssl-sys"
+
+[dependencies.foreign-types]
+version = "0.3.1"
+
+[dependencies.libc]
+version = "0.2"
+
+[dependencies.once_cell]
+version = "1.5.2"
+
+[dependencies.openssl-macros]
+version = "0.1.0"
+
+[dev-dependencies.hex]
+version = "0.3"
+
+[features]
+bindgen = ["ffi/bindgen"]
+default = []
+unstable_boringssl = ["ffi/unstable_boringssl"]
+v101 = []
+v102 = []
+v110 = []
+v111 = []
+vendored = ["ffi/vendored"]
diff --git a/openssl/Cargo.toml b/Cargo.toml.orig
similarity index 65%
rename from openssl/Cargo.toml
rename to Cargo.toml.orig
index 4bb8db4..b6204e4 100644
--- a/openssl/Cargo.toml
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "openssl"
-version = "0.10.38"
+version = "0.10.43"
 authors = ["Steven Fackler <sfackler@gmail.com>"]
 license = "Apache-2.0"
 description = "OpenSSL bindings"
@@ -19,8 +19,8 @@
 
 vendored = ['ffi/vendored']
 bindgen = ['ffi/bindgen']
-boringssl = ["bssl-ffi"]
-default = ["ffi"]
+unstable_boringssl = ["ffi/unstable_boringssl"]
+default = []
 
 [dependencies]
 bitflags = "1.0"
@@ -29,9 +29,8 @@
 libc = "0.2"
 once_cell = "1.5.2"
 
-openssl-macros = { path = "../openssl-macros" }
-bssl-ffi = { package = "bssl-sys", version = "0.1.0", path = "../../boringssl/build/rust", optional=true }
-ffi = { package = "openssl-sys", version = "0.9.69", path = "../openssl-sys", optional = true}
+openssl-macros = { version = "0.1.0", path = "../openssl-macros" }
+ffi = { package = "openssl-sys", version = "0.9.78", path = "../openssl-sys" }
 
 [dev-dependencies]
 hex = "0.3"
diff --git a/METADATA b/METADATA
index 5ac4e62..72a81ff 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/openssl
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
 name: "openssl"
 description: "OpenSSL bindings"
 third_party {
@@ -6,14 +10,14 @@
     value: "https://crates.io/crates/openssl"
   }
   url {
-    type: GIT
-    value: "https://github.com/sfackler/rust-openssl"
+    type: ARCHIVE
+    value: "https://static.crates.io/crates/openssl/openssl-0.10.43.crate"
   }
-  version: "973936042c31a868d0ade4f3bcbd25d317015c05"
+  version: "0.10.43"
   license_type: NOTICE
   last_upgrade_date {
     year: 2022
-    month: 4
-    day: 11
+    month: 12
+    day: 1
   }
 }
diff --git a/README.android b/README.android
new file mode 100644
index 0000000..6499cfe
--- /dev/null
+++ b/README.android
@@ -0,0 +1,31 @@
+## Steps for updating this crate
+
+1.  In order to run cargo2android, for this crate, the BoringSSL rust bindings first needs to be
+    built. Copy `googletest` to `boringssl`, which is needed to build the rust bindings
+
+    ```
+    $ cp -r external/googletest/googletest external/boringssl/src/third_party/
+    ```
+2.  Build the rust bindings (More information at
+    https://boringssl.googlesource.com/boringssl/+/HEAD/BUILDING.md)
+
+    ```
+    $ cd external/boringssl
+    $ mkdir build && cd build
+    $ cmake .. -DRUST_BINDINGS=x86_64-unknown-linux-gnu
+    $ make
+    ```
+3.  Run `tools/external_updater/updater.sh update rust/crates/openssl`. Cargo errors causing the
+    command to fail are expected (since the boringSSL crate is outside of the `openssl` directory,
+    redshell is not able to access it).
+4.  The repository should now be in a `tmp_auto_upgrade` branch, and the Android.bp will contain
+    some error message.
+5.  Run cargo2android
+
+    ```
+    $ cargo2android.py --config ./cargo2android.json
+    ```
+6.  Clean up the changes in external/boringssl repository, and double check that the resulting
+    Android.bp builds correctly by running `m libopenssl`.
+7.  Commit the changes and upload the CL.
+8.  `external/rust/crates/openssl-macros` should also be updated at the same time.
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 9cce328..d2182d6 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,49 +1,23 @@
 // Generated by update_crate_tests.py for tests that depend on this crate.
 {
-  "presubmit": [
+  "imports": [
     {
-      "name": "apkdmverity.test"
+      "path": "packages/modules/Virtualization/apkdmverity"
     },
     {
-      "name": "authfs_device_test_src_lib"
+      "path": "packages/modules/Virtualization/authfs"
     },
     {
-      "name": "libapkverify.integration_test"
+      "path": "packages/modules/Virtualization/avmd"
     },
     {
-      "name": "libapkverify.test"
+      "path": "packages/modules/Virtualization/libs/apkverify"
     },
     {
-      "name": "libidsig.test"
+      "path": "packages/modules/Virtualization/microdroid_manager"
     },
     {
-      "name": "microdroid_manager_test"
-    },
-    {
-      "name": "virtualizationservice_device_test"
-    }
-  ],
-  "presubmit-rust": [
-    {
-      "name": "apkdmverity.test"
-    },
-    {
-      "name": "authfs_device_test_src_lib"
-    },
-    {
-      "name": "libapkverify.integration_test"
-    },
-    {
-      "name": "libapkverify.test"
-    },
-    {
-      "name": "libidsig.test"
-    },
-    {
-      "name": "microdroid_manager_test"
-    },
-    {
-      "name": "virtualizationservice_device_test"
+      "path": "packages/modules/Virtualization/virtualizationmanager"
     }
   ]
 }
diff --git a/THIRD_PARTY b/THIRD_PARTY
deleted file mode 100644
index aa6920c..0000000
--- a/THIRD_PARTY
+++ /dev/null
@@ -1,148 +0,0 @@
-rust-openssl contains code from OpenSSL, under the following license:
-
-OpenSSL License
-  ---------------
-
-/* ====================================================================
- * Copyright (c) 1998-2011 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.]
- */
-
-===============================================================================
-
-openssl-sys
-
-Copyright (c) 2014 Alex Crichton
-
-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.
diff --git a/openssl/build.rs b/build.rs
similarity index 83%
rename from openssl/build.rs
rename to build.rs
index 8104f07..fc64922 100644
--- a/openssl/build.rs
+++ b/build.rs
@@ -7,7 +7,7 @@
         println!("cargo:rustc-cfg=libressl");
     }
 
-    if env::var("CARGO_FEATURE_BORINGSSL").is_ok() {
+    if env::var("CARGO_FEATURE_UNSTABLE_BORINGSSL").is_ok() {
         println!("cargo:rustc-cfg=boringssl");
         return;
     }
@@ -51,6 +51,10 @@
     if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") {
         let version = u64::from_str_radix(&version, 16).unwrap();
 
+        if version >= 0x2_05_01_00_0 {
+            println!("cargo:rustc-cfg=libressl251");
+        }
+
         if version >= 0x2_06_01_00_0 {
             println!("cargo:rustc-cfg=libressl261");
         }
@@ -86,5 +90,17 @@
         if version >= 0x3_04_00_00_0 {
             println!("cargo:rustc-cfg=libressl340");
         }
+
+        if version >= 0x3_05_00_00_0 {
+            println!("cargo:rustc-cfg=libressl350");
+        }
+
+        if version >= 0x3_06_00_00_0 {
+            println!("cargo:rustc-cfg=libressl360");
+        }
+
+        if version >= 0x3_06_01_00_0 {
+            println!("cargo:rustc-cfg=libressl361");
+        }
     }
 }
diff --git a/cargo2android.json b/cargo2android.json
index 41450f8..4caae30 100644
--- a/cargo2android.json
+++ b/cargo2android.json
@@ -4,7 +4,8 @@
     "com.android.virt"
   ],
   "device": true,
-  "features": "boringssl",
+  "features": "unstable_boringssl",
   "run": true,
-  "vendor-available": true
+  "vendor-available": true,
+  "patch": "patches/Android.bp.diff"
 }
diff --git a/openssl/examples/mk_certs.rs b/examples/mk_certs.rs
similarity index 100%
rename from openssl/examples/mk_certs.rs
rename to examples/mk_certs.rs
diff --git a/openssl-macros/Cargo.toml b/openssl-macros/Cargo.toml
deleted file mode 100644
index 684e31e..0000000
--- a/openssl-macros/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "openssl-macros"
-version = "0.1.0"
-edition = "2018"
-
-[lib]
-proc-macro = true
-
-[dependencies]
-proc-macro2 = "1"
-quote = "1"
-syn = { version = "1", features = ["full"] }
diff --git a/openssl-macros/src/lib.rs b/openssl-macros/src/lib.rs
deleted file mode 100644
index c007409..0000000
--- a/openssl-macros/src/lib.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use proc_macro::TokenStream;
-use proc_macro2::Ident;
-use quote::quote;
-use syn::{parse_macro_input, ItemFn};
-
-#[proc_macro_attribute]
-pub fn corresponds(attr: TokenStream, item: TokenStream) -> TokenStream {
-    let function = parse_macro_input!(attr as Ident);
-    let item = parse_macro_input!(item as ItemFn);
-
-    let function = function.to_string();
-    let line = format!(
-        "This corresponds to [`{0}`](https://www.openssl.org/docs/manmaster/man3/{0}.html).",
-        function
-    );
-
-    let attrs = item.attrs;
-    let vis = item.vis;
-    let sig = item.sig;
-    let block = item.block;
-
-    let out = quote! {
-        #(#attrs)*
-        #[doc = ""]
-        #[doc = #line]
-        #[doc(alias = #function)]
-        #vis #sig #block
-    };
-    out.into()
-}
diff --git a/openssl/LICENSE b/openssl/LICENSE
deleted file mode 100644
index f259067..0000000
--- a/openssl/LICENSE
+++ /dev/null
@@ -1,15 +0,0 @@
-Copyright 2011-2017 Google Inc.
-          2013 Jack Lloyd
-          2013-2014 Steven Fackler
-
-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.
diff --git a/openssl/README.md b/openssl/README.md
deleted file mode 120000
index 32d46ee..0000000
--- a/openssl/README.md
+++ /dev/null
@@ -1 +0,0 @@
-../README.md
\ No newline at end of file
diff --git a/openssl/src/conf.rs b/openssl/src/conf.rs
deleted file mode 100644
index e21f069..0000000
--- a/openssl/src/conf.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-//! Interface for processing OpenSSL configuration files.
-
-use crate::cvt_p;
-use crate::error::ErrorStack;
-use openssl_macros::corresponds;
-
-#[cfg(not(boringssl))]
-pub struct ConfMethod(*mut ffi::CONF_METHOD);
-
-#[cfg(not(boringssl))]
-impl ConfMethod {
-    /// Retrieve handle to the default OpenSSL configuration file processing function.
-    #[corresponds(NCONF_default)]
-    pub fn default() -> ConfMethod {
-        unsafe {
-            ffi::init();
-            // `NCONF` stands for "New Conf", as described in crypto/conf/conf_lib.c. This is
-            // a newer API than the "CONF classic" functions.
-            ConfMethod(ffi::NCONF_default())
-        }
-    }
-
-    /// Construct from raw pointer.
-    ///
-    /// # Safety
-    ///
-    /// The caller must ensure that the pointer is valid.
-    pub unsafe fn from_ptr(ptr: *mut ffi::CONF_METHOD) -> ConfMethod {
-        ConfMethod(ptr)
-    }
-
-    /// Convert to raw pointer.
-    pub fn as_ptr(&self) -> *mut ffi::CONF_METHOD {
-        self.0
-    }
-}
-
-foreign_type_and_impl_send_sync! {
-    type CType = ffi::CONF;
-    fn drop = ffi::NCONF_free;
-
-    pub struct Conf;
-    pub struct ConfRef;
-}
-
-#[cfg(not(boringssl))]
-impl Conf {
-    /// Create a configuration parser.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use openssl::conf::{Conf, ConfMethod};
-    ///
-    /// let conf = Conf::new(ConfMethod::default());
-    /// ```
-    #[corresponds(NCONF_new)]
-    pub fn new(method: ConfMethod) -> Result<Conf, ErrorStack> {
-        unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) }
-    }
-}
diff --git a/patches/Android.bp.diff b/patches/Android.bp.diff
new file mode 100644
index 0000000..9f7b012
--- /dev/null
+++ b/patches/Android.bp.diff
@@ -0,0 +1,18 @@
+diff --git a/Android.bp b/Android.bp
+index 2282c66..4e9011c 100644
+--- a/Android.bp
++++ b/Android.bp
+@@ -54,11 +54,11 @@ rust_library {
+     srcs: ["src/lib.rs"],
+     edition: "2018",
+     features: ["unstable_boringssl"],
+-    cfgs: ["boringssl"],
++    cfgs: ["boringssl", "soong"],
+     rustlibs: [
+         "libbitflags",
+         "libcfg_if",
+-        "libopenssl_sys",
++        "libbssl_ffi",
+         "libforeign_types",
+         "liblibc",
+         "libonce_cell",
diff --git a/patches/local_changes.diff b/patches/local_changes.diff
new file mode 100644
index 0000000..06702fa
--- /dev/null
+++ b/patches/local_changes.diff
@@ -0,0 +1,525 @@
+diff --git a/.cargo/config.toml b/.cargo/config.toml
+new file mode 100644
+index 0000000..e2b197d
+--- /dev/null
++++ b/.cargo/config.toml
+@@ -0,0 +1,2 @@
++[patch.crates-io]
++bssl-ffi = { package = "bssl-sys", version = "0.1.0", path = "../../../boringssl/build/rust", optional=true }
+diff --git a/src/cipher.rs b/src/cipher.rs
+index ab5f49d..84a8265 100644
+--- a/src/cipher.rs
++++ b/src/cipher.rs
+@@ -208,6 +208,7 @@ impl Cipher {
+         unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb1() as *mut _) }
+     }
+ 
++    #[cfg(not(boringssl))]
+     pub fn aes_192_cfb128() -> &'static CipherRef {
+         unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb128() as *mut _) }
+     }
+@@ -253,6 +254,7 @@ impl Cipher {
+         unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb1() as *mut _) }
+     }
+ 
++    #[cfg(not(boringssl))]
+     pub fn aes_256_cfb128() -> &'static CipherRef {
+         unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb128() as *mut _) }
+     }
+@@ -282,11 +284,13 @@ impl Cipher {
+     }
+ 
+     #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++    #[cfg(not(boringssl))]
+     pub fn bf_cbc() -> &'static CipherRef {
+         unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) }
+     }
+ 
+     #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++    #[cfg(not(boringssl))]
+     pub fn bf_ecb() -> &'static CipherRef {
+         unsafe { CipherRef::from_ptr(ffi::EVP_bf_ecb() as *mut _) }
+     }
+diff --git a/src/ec.rs b/src/ec.rs
+index a6a6dc9..88dcaaf 100644
+--- a/src/ec.rs
++++ b/src/ec.rs
+@@ -908,6 +908,26 @@ impl EcKey<Private> {
+         EcKey<Private>,
+         ffi::d2i_ECPrivateKey
+     }
++
++    /// Decodes a DER-encoded elliptic curve private key structure for the specified curve.
++    #[corresponds(EC_KEY_parse_private_key)]
++    #[cfg(boringssl)]
++    pub fn private_key_from_der_for_group(
++        der: &[u8],
++        group: &EcGroupRef,
++    ) -> Result<EcKey<Private>, ErrorStack> {
++        unsafe {
++            let mut cbs = ffi::CBS {
++                data: der.as_ptr(),
++                len: der.len(),
++            };
++            cvt_p(ffi::EC_KEY_parse_private_key(
++                &mut cbs as *mut ffi::CBS,
++                group.as_ptr(),
++            ))
++            .map(|p| EcKey::from_ptr(p))
++        }
++    }
+ }
+ 
+ impl<T> Clone for EcKey<T> {
+diff --git a/src/encrypt.rs b/src/encrypt.rs
+index 3cb10fc..34a9eb8 100644
+--- a/src/encrypt.rs
++++ b/src/encrypt.rs
+@@ -148,7 +148,7 @@ impl<'a> Encrypter<'a> {
+     /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
+     ///
+     /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
+-    #[cfg(any(ossl102, libressl310))]
++    #[cfg(any(ossl102, libressl310, boringssl))]
+     pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
+         unsafe {
+             cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
+@@ -352,7 +352,7 @@ impl<'a> Decrypter<'a> {
+     /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
+     ///
+     /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
+-    #[cfg(any(ossl102, libressl310))]
++    #[cfg(any(ossl102, libressl310, boringssl))]
+     pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
+         unsafe {
+             cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
+diff --git a/src/hkdf.rs b/src/hkdf.rs
+new file mode 100644
+index 0000000..cc7e5b3
+--- /dev/null
++++ b/src/hkdf.rs
+@@ -0,0 +1,89 @@
++use crate::cvt;
++use crate::error::ErrorStack;
++use crate::md::MdRef;
++use foreign_types::ForeignTypeRef;
++use openssl_macros::corresponds;
++
++/// Computes HKDF (as specified by RFC 5869).
++///
++/// HKDF is an Extract-and-Expand algorithm. It does not do any key stretching,
++/// and as such, is not suited to be used alone to generate a key from a
++/// password.
++#[corresponds(HKDF)]
++#[inline]
++pub fn hkdf(
++    out_key: &mut [u8],
++    md: &MdRef,
++    secret: &[u8],
++    salt: &[u8],
++    info: &[u8],
++) -> Result<(), ErrorStack> {
++    unsafe {
++        cvt(ffi::HKDF(
++            out_key.as_mut_ptr(),
++            out_key.len(),
++            md.as_ptr(),
++            secret.as_ptr(),
++            secret.len(),
++            salt.as_ptr(),
++            salt.len(),
++            info.as_ptr(),
++            info.len(),
++        ))?;
++    }
++
++    Ok(())
++}
++
++/// Computes a HKDF PRK (as specified by RFC 5869).
++///
++/// WARNING: This function orders the inputs differently from RFC 5869
++/// specification. Double-check which parameter is the secret/IKM and which is
++/// the salt when using.
++#[corresponds(HKDF_extract)]
++#[inline]
++pub fn hkdf_extract<'a>(
++    out_key: &'a mut [u8],
++    md: &MdRef,
++    secret: &[u8],
++    salt: &[u8],
++) -> Result<&'a [u8], ErrorStack> {
++    let mut out_len = out_key.len();
++    unsafe {
++        cvt(ffi::HKDF_extract(
++            out_key.as_mut_ptr(),
++            &mut out_len,
++            md.as_ptr(),
++            secret.as_ptr(),
++            secret.len(),
++            salt.as_ptr(),
++            salt.len(),
++        ))?;
++    }
++
++    Ok(&out_key[..out_len])
++}
++
++/// Computes a HKDF OKM (as specified by RFC 5869).
++#[corresponds(HKDF_expand)]
++#[inline]
++pub fn hkdf_expand(
++    out_key: &mut [u8],
++    md: &MdRef,
++    prk: &[u8],
++    info: &[u8],
++) -> Result<(), ErrorStack> {
++    unsafe {
++        cvt(ffi::HKDF_expand(
++            out_key.as_mut_ptr(),
++            out_key.len(),
++            md.as_ptr(),
++            prk.as_ptr(),
++            prk.len(),
++            info.as_ptr(),
++            info.len(),
++        ))?;
++    }
++
++    Ok(())
++}
+diff --git a/src/hmac.rs b/src/hmac.rs
+new file mode 100644
+index 0000000..601ae01
+--- /dev/null
++++ b/src/hmac.rs
+@@ -0,0 +1,68 @@
++use crate::cvt_p;
++use crate::error::ErrorStack;
++use crate::md::MdRef;
++use foreign_types::ForeignTypeRef;
++use openssl_macros::corresponds;
++use libc::{c_void, c_uint};
++use std::convert::TryFrom;
++
++/// Computes the HMAC as a one-shot operation.
++///
++/// Calculates the HMAC of data, using the given |key|
++/// and hash function |md|, and returns the result re-using the space from
++/// buffer |out|. On entry, |out| must contain at least |EVP_MD_size| bytes
++/// of space. The actual length of the result is used to resize the returned
++/// slice. An output size of |EVP_MAX_MD_SIZE| will always be large enough.
++/// It returns a resized |out| or ErrorStack on error.
++#[corresponds(HMAC)]
++#[inline]
++pub fn hmac<'a>(
++    md: &MdRef,
++    key: &[u8],
++    data: &[u8],
++    out: &'a mut [u8]
++) -> Result<&'a [u8], ErrorStack> {
++    let mut out_len = c_uint::try_from(out.len()).unwrap();
++    unsafe {
++        cvt_p(ffi::HMAC(
++            md.as_ptr(),
++            key.as_ptr() as *const c_void,
++            key.len(),
++            data.as_ptr(),
++            data.len(),
++            out.as_mut_ptr(),
++            &mut out_len
++            ))?;
++    }
++    Ok(&out[..out_len as usize])
++}
++
++#[cfg(test)]
++mod tests {
++    use super::*;
++    use crate::md::Md;
++    use crate::memcmp;
++
++    const SHA_256_DIGEST_SIZE:usize = 32;
++
++    #[test]
++    fn hmac_sha256_test() {
++        let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
++        let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
++        let key:[u8; 20] = [0x0b; 20];
++        let data = b"Hi There";
++        let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
++        expect!(memcmp::eq(&hmac_result, &expected_hmac));
++    }
++
++    #[test]
++    fn hmac_sha256_test_big_buffer() {
++        let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
++        let mut out: [u8; 100] = [0; 100];
++        let key:[u8;20] = [0x0b; 20];
++        let data = b"Hi There";
++        let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
++        expect_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE);
++        expect!(memcmp::eq(&hmac_result, &expected_hmac));
++    }
++}
+diff --git a/src/lib.rs b/src/lib.rs
+index 891651e..48b7ed1 100644
+--- a/src/lib.rs
++++ b/src/lib.rs
+@@ -120,6 +120,9 @@
+ #![doc(html_root_url = "https://docs.rs/openssl/0.10")]
+ #![warn(rust_2018_idioms)]
+ 
++#[cfg(all(soong, boringssl))]
++extern crate bssl_ffi as ffi;
++
+ #[doc(inline)]
+ pub use ffi::init;
+ 
+@@ -155,6 +158,10 @@ pub mod ex_data;
+ #[cfg(not(any(libressl, ossl300)))]
+ pub mod fips;
+ pub mod hash;
++#[cfg(boringssl)]
++pub mod hkdf;
++#[cfg(boringssl)]
++pub mod hmac;
+ #[cfg(ossl300)]
+ pub mod lib_ctx;
+ pub mod md;
+diff --git a/src/pkey.rs b/src/pkey.rs
+index 7d438eb..7eaf068 100644
+--- a/src/pkey.rs
++++ b/src/pkey.rs
+@@ -47,7 +47,7 @@ use crate::dh::Dh;
+ use crate::dsa::Dsa;
+ use crate::ec::EcKey;
+ use crate::error::ErrorStack;
+-#[cfg(ossl110)]
++#[cfg(any(boringssl, ossl110))]
+ use crate::pkey_ctx::PkeyCtx;
+ use crate::rsa::Rsa;
+ use crate::symm::Cipher;
+@@ -89,11 +89,11 @@ impl Id {
+     #[cfg(ossl110)]
+     pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);
+ 
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
+     #[cfg(ossl111)]
+     pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
+     #[cfg(ossl111)]
+     pub const X448: Id = Id(ffi::EVP_PKEY_X448);
+@@ -243,7 +243,7 @@ where
+     /// This function only works for algorithms that support raw public keys.
+     /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
+     #[corresponds(EVP_PKEY_get_raw_public_key)]
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
+         unsafe {
+             let mut len = 0;
+@@ -294,7 +294,7 @@ where
+     /// This function only works for algorithms that support raw private keys.
+     /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
+     #[corresponds(EVP_PKEY_get_raw_private_key)]
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
+         unsafe {
+             let mut len = 0;
+@@ -475,7 +475,7 @@ impl PKey<Private> {
+         ctx.keygen()
+     }
+ 
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     fn generate_eddsa(id: Id) -> Result<PKey<Private>, ErrorStack> {
+         let mut ctx = PkeyCtx::new_id(id)?;
+         ctx.keygen_init()?;
+@@ -505,7 +505,7 @@ impl PKey<Private> {
+     /// assert_eq!(secret.len(), 32);
+     /// # Ok(()) }
+     /// ```
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
+         PKey::generate_eddsa(Id::X25519)
+     }
+@@ -559,7 +559,7 @@ impl PKey<Private> {
+     /// assert_eq!(signature.len(), 64);
+     /// # Ok(()) }
+     /// ```
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
+         PKey::generate_eddsa(Id::ED25519)
+     }
+@@ -709,7 +709,7 @@ impl PKey<Private> {
+     ///
+     /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448
+     #[corresponds(EVP_PKEY_new_raw_private_key)]
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn private_key_from_raw_bytes(
+         bytes: &[u8],
+         key_type: Id,
+@@ -750,7 +750,7 @@ impl PKey<Public> {
+     ///
+     /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448
+     #[corresponds(EVP_PKEY_new_raw_public_key)]
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn public_key_from_raw_bytes(
+         bytes: &[u8],
+         key_type: Id,
+diff --git a/src/sign.rs b/src/sign.rs
+index 457ff12..4de8ad0 100644
+--- a/src/sign.rs
++++ b/src/sign.rs
+@@ -290,7 +290,7 @@ impl<'a> Signer<'a> {
+         self.len_intern()
+     }
+ 
+-    #[cfg(not(ossl111))]
++    #[cfg(not(any(boringssl, ossl111)))]
+     fn len_intern(&self) -> Result<usize, ErrorStack> {
+         unsafe {
+             let mut len = 0;
+@@ -303,7 +303,7 @@ impl<'a> Signer<'a> {
+         }
+     }
+ 
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     fn len_intern(&self) -> Result<usize, ErrorStack> {
+         unsafe {
+             let mut len = 0;
+@@ -360,7 +360,7 @@ impl<'a> Signer<'a> {
+     /// OpenSSL documentation at [`EVP_DigestSign`].
+     ///
+     /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn sign_oneshot(
+         &mut self,
+         sig_buf: &mut [u8],
+@@ -382,7 +382,7 @@ impl<'a> Signer<'a> {
+     /// Returns the signature.
+     ///
+     /// This is a simple convenience wrapper over `len` and `sign_oneshot`.
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn sign_oneshot_to_vec(&mut self, data_buf: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+         let mut sig_buf = vec![0; self.len()?];
+         let len = self.sign_oneshot(&mut sig_buf, data_buf)?;
+@@ -594,7 +594,7 @@ impl<'a> Verifier<'a> {
+     /// OpenSSL documentation at [`EVP_DigestVerify`].
+     ///
+     /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html
+-    #[cfg(ossl111)]
++    #[cfg(any(boringssl, ossl111))]
+     pub fn verify_oneshot(&mut self, signature: &[u8], buf: &[u8]) -> Result<bool, ErrorStack> {
+         unsafe {
+             let r = ffi::EVP_DigestVerify(
+diff --git a/src/symm.rs b/src/symm.rs
+index c75bbc0..beff5fc 100644
+--- a/src/symm.rs
++++ b/src/symm.rs
+@@ -119,6 +119,7 @@ impl Cipher {
+         unsafe { Cipher(ffi::EVP_aes_128_cfb1()) }
+     }
+ 
++    #[cfg(not(boringssl))]
+     pub fn aes_128_cfb128() -> Cipher {
+         unsafe { Cipher(ffi::EVP_aes_128_cfb128()) }
+     }
+@@ -164,6 +165,7 @@ impl Cipher {
+         unsafe { Cipher(ffi::EVP_aes_192_cfb1()) }
+     }
+ 
++    #[cfg(not(boringssl))]
+     pub fn aes_192_cfb128() -> Cipher {
+         unsafe { Cipher(ffi::EVP_aes_192_cfb128()) }
+     }
+@@ -214,6 +216,7 @@ impl Cipher {
+         unsafe { Cipher(ffi::EVP_aes_256_cfb1()) }
+     }
+ 
++    #[cfg(not(boringssl))]
+     pub fn aes_256_cfb128() -> Cipher {
+         unsafe { Cipher(ffi::EVP_aes_256_cfb128()) }
+     }
+@@ -242,12 +245,12 @@ impl Cipher {
+         unsafe { Cipher(ffi::EVP_aes_256_ocb()) }
+     }
+ 
+-    #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))]
+     pub fn bf_cbc() -> Cipher {
+         unsafe { Cipher(ffi::EVP_bf_cbc()) }
+     }
+ 
+-    #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))]
+     pub fn bf_ecb() -> Cipher {
+         unsafe { Cipher(ffi::EVP_bf_ecb()) }
+     }
+diff --git a/src/x509/mod.rs b/src/x509/mod.rs
+index edd54aa..45f2467 100644
+--- a/src/x509/mod.rs
++++ b/src/x509/mod.rs
+@@ -353,6 +353,19 @@ impl X509Builder {
+         unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
+     }
+ 
++    /// Signs the certificate with a private key but without a digest.
++    ///
++    /// This is the only way to sign with Ed25519 keys as BoringSSL doesn't support the null
++    /// message digest.
++    #[cfg(boringssl)]
++    #[corresponds(X509_sign)]
++    pub fn sign_without_digest<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
++    where
++        T: HasPrivate,
++    {
++        unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), ptr::null())).map(|_| ()) }
++    }
++
+     /// Consumes the builder, returning the certificate.
+     pub fn build(self) -> X509 {
+         self.0
+@@ -1260,6 +1273,29 @@ impl X509ReqBuilder {
+         }
+     }
+ 
++    /// Sign the request using a private key without a digest.
++    ///
++    /// This is the only way to sign with Ed25519 keys as BoringSSL doesn't support the null
++    /// message digest.
++    ///
++    /// This corresponds to [`X509_REQ_sign`].
++    ///
++    /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html
++    #[cfg(boringssl)]
++    pub fn sign_without_digest<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
++    where
++        T: HasPrivate,
++    {
++        unsafe {
++            cvt(ffi::X509_REQ_sign(
++                self.0.as_ptr(),
++                key.as_ptr(),
++                ptr::null(),
++            ))
++            .map(|_| ())
++        }
++    }
++
+     /// Returns the `X509Req`.
+     pub fn build(self) -> X509Req {
+         self.0
diff --git a/openssl/src/aes.rs b/src/aes.rs
similarity index 92%
rename from openssl/src/aes.rs
rename to src/aes.rs
index a0447e8..440dd05 100644
--- a/openssl/src/aes.rs
+++ b/src/aes.rs
@@ -21,22 +21,27 @@
 //! [`Cipher`]: ../symm/struct.Cipher.html
 //!
 //! # Examples
-//!
-//! ## AES IGE
-//! ```rust
-//! use openssl::aes::{AesKey, aes_ige};
-//! use openssl::symm::Mode;
-//!
-//! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
-//! let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
-//! let mut iv = *b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\
-//!                 \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
-//!
-//!  let key = AesKey::new_encrypt(key).unwrap();
-//!  let mut output = [0u8; 16];
-//!  aes_ige(plaintext, &mut output, &key, &mut iv, Mode::Encrypt);
-//!  assert_eq!(output, *b"\xa6\xad\x97\x4d\x5c\xea\x1d\x36\xd2\xf3\x67\x98\x09\x07\xed\x32");
-//! ```
+
+#![cfg_attr(
+    not(boringssl),
+    doc = r#"\
+## AES IGE
+```rust
+use openssl::aes::{AesKey, aes_ige};
+use openssl::symm::Mode;
+
+let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
+let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
+let mut iv = *b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\
+                \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
+
+ let key = AesKey::new_encrypt(key).unwrap();
+ let mut output = [0u8; 16];
+ aes_ige(plaintext, &mut output, &key, &mut iv, Mode::Encrypt);
+ assert_eq!(output, *b"\xa6\xad\x97\x4d\x5c\xea\x1d\x36\xd2\xf3\x67\x98\x09\x07\xed\x32");
+```"#
+)]
+
 //!
 //! ## Key wrapping
 //! ```rust
@@ -60,6 +65,7 @@
 use std::mem::MaybeUninit;
 use std::ptr;
 
+#[cfg(not(boringssl))]
 use crate::symm::Mode;
 use openssl_macros::corresponds;
 
@@ -256,6 +262,7 @@
     use hex::FromHex;
 
     use super::*;
+    #[cfg(not(boringssl))]
     use crate::symm::Mode;
 
     // From https://www.mgp25.com/AESIGE/
diff --git a/openssl/src/asn1.rs b/src/asn1.rs
similarity index 100%
rename from openssl/src/asn1.rs
rename to src/asn1.rs
diff --git a/openssl/src/base64.rs b/src/base64.rs
similarity index 96%
rename from openssl/src/base64.rs
rename to src/base64.rs
index 75822d6..bfa8cbc 100644
--- a/openssl/src/base64.rs
+++ b/src/base64.rs
@@ -1,13 +1,8 @@
 //! Base64 encoding support.
-use crate::cvt_n;
 use crate::error::ErrorStack;
+use crate::{cvt_n, LenType};
+use libc::c_int;
 use openssl_macros::corresponds;
-use libc::{c_int, size_t};
-
-#[cfg(not(boringssl))]
-type LenType = c_int;
-#[cfg(boringssl)]
-type LenType = size_t;
 
 /// Encodes a slice of bytes to a base64 string.
 ///
diff --git a/openssl/src/bio.rs b/src/bio.rs
similarity index 98%
rename from openssl/src/bio.rs
rename to src/bio.rs
index 717ccd0..6a72552 100644
--- a/openssl/src/bio.rs
+++ b/src/bio.rs
@@ -67,6 +67,7 @@
         }
     }
 
+    #[cfg(not(boringssl))]
     pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBio {
         MemBio(bio)
     }
diff --git a/openssl/src/bn.rs b/src/bn.rs
similarity index 96%
rename from openssl/src/bn.rs
rename to src/bn.rs
index c15ab53..68c94f9 100644
--- a/openssl/src/bn.rs
+++ b/src/bn.rs
@@ -33,11 +33,11 @@
 use crate::asn1::Asn1Integer;
 use crate::error::ErrorStack;
 use crate::string::OpensslString;
-use crate::{cvt, cvt_n, cvt_p};
+use crate::{cvt, cvt_n, cvt_p, LenType};
 use openssl_macros::corresponds;
 
 cfg_if! {
-    if #[cfg(ossl110)] {
+    if #[cfg(any(ossl110, libressl350))] {
         use ffi::{
             BN_get_rfc2409_prime_1024, BN_get_rfc2409_prime_768, BN_get_rfc3526_prime_1536,
             BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096,
@@ -809,7 +809,7 @@
     /// assert_eq!(&bn_vec, &[0, 0, 0x45, 0x43]);
     /// ```
     #[corresponds(BN_bn2binpad)]
-    #[cfg(ossl110)]
+    #[cfg(any(boringssl, ossl110))]
     pub fn to_vec_padded(&self, pad_to: i32) -> Result<Vec<u8>, ErrorStack> {
         let mut v = Vec::with_capacity(pad_to as usize);
         unsafe {
@@ -841,7 +841,7 @@
     /// # use openssl::bn::BigNum;
     /// let s = -BigNum::from_u32(0x99ff).unwrap();
     ///
-    /// assert_eq!(&**s.to_hex_str().unwrap(), "-99FF");
+    /// assert_eq!(s.to_hex_str().unwrap().to_uppercase(), "-99FF");
     /// ```
     #[corresponds(BN_bn2hex)]
     pub fn to_hex_str(&self) -> Result<OpensslString, ErrorStack> {
@@ -1070,13 +1070,38 @@
     pub fn from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
         unsafe {
             ffi::init();
-            assert!(n.len() <= c_int::max_value() as usize);
-            #[cfg(boringssl)]
-            let len = n.len();
-            #[cfg(not(boringssl))]
-            let len = n.len() as c_int;
+            assert!(n.len() <= LenType::max_value() as usize);
 
-            cvt_p(ffi::BN_bin2bn(n.as_ptr(), len, ptr::null_mut())).map(|p| BigNum::from_ptr(p))
+            cvt_p(ffi::BN_bin2bn(
+                n.as_ptr(),
+                n.len() as LenType,
+                ptr::null_mut(),
+            ))
+            .map(|p| BigNum::from_ptr(p))
+        }
+    }
+
+    /// Copies data from a slice overwriting what was in the BigNum.
+    ///
+    /// This function can be used to copy data from a slice to a
+    /// [secure BigNum][`BigNum::new_secure`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use openssl::bn::BigNum;
+    /// let mut bignum = BigNum::new().unwrap();
+    /// bignum.copy_from_slice(&[0x12, 0x00, 0x34]).unwrap();
+    ///
+    /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap());
+    /// ```
+    #[corresponds(BN_bin2bn)]
+    pub fn copy_from_slice(&mut self, n: &[u8]) -> Result<(), ErrorStack> {
+        unsafe {
+            assert!(n.len() <= LenType::max_value() as usize);
+
+            cvt_p(ffi::BN_bin2bn(n.as_ptr(), n.len() as LenType, self.0))?;
+            Ok(())
         }
     }
 }
diff --git a/openssl/src/cipher.rs b/src/cipher.rs
similarity index 80%
rename from openssl/src/cipher.rs
rename to src/cipher.rs
index 1801c44..84a8265 100644
--- a/openssl/src/cipher.rs
+++ b/src/cipher.rs
@@ -332,6 +332,56 @@
         unsafe { CipherRef::from_ptr(ffi::EVP_rc4() as *mut _) }
     }
 
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+    pub fn camellia128_cfb128() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_cfb128() as *mut _) }
+    }
+
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+    pub fn camellia128_ecb() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_ecb() as *mut _) }
+    }
+
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+    pub fn camellia192_cfb128() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cfb128() as *mut _) }
+    }
+
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+    pub fn camellia192_ecb() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_ecb() as *mut _) }
+    }
+
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+    pub fn camellia256_cfb128() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cfb128() as *mut _) }
+    }
+
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+    pub fn camellia256_ecb() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ecb() as *mut _) }
+    }
+
+    #[cfg(not(boringssl))]
+    pub fn cast5_cfb64() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cfb64() as *mut _) }
+    }
+
+    #[cfg(not(boringssl))]
+    pub fn cast5_ecb() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ecb() as *mut _) }
+    }
+
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_IDEA")))]
+    pub fn idea_cfb64() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_idea_cfb64() as *mut _) }
+    }
+
+    #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_IDEA")))]
+    pub fn idea_ecb() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_idea_ecb() as *mut _) }
+    }
+
     #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))]
     pub fn chacha20() -> &'static CipherRef {
         unsafe { CipherRef::from_ptr(ffi::EVP_chacha20() as *mut _) }
@@ -365,6 +415,31 @@
     pub fn seed_ofb() -> &'static CipherRef {
         unsafe { CipherRef::from_ptr(ffi::EVP_seed_ofb() as *mut _) }
     }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_ecb() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ecb() as *mut _) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_cbc() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_sm4_cbc() as *mut _) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_ctr() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ctr() as *mut _) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_cfb128() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_sm4_cfb128() as *mut _) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_ofb() -> &'static CipherRef {
+        unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ofb() as *mut _) }
+    }
 }
 
 /// A reference to a [`Cipher`].
diff --git a/openssl/src/cipher_ctx.rs b/src/cipher_ctx.rs
similarity index 98%
rename from openssl/src/cipher_ctx.rs
rename to src/cipher_ctx.rs
index 3f32ec2..8e01711 100644
--- a/openssl/src/cipher_ctx.rs
+++ b/src/cipher_ctx.rs
@@ -52,13 +52,14 @@
 
 use crate::cipher::CipherRef;
 use crate::error::ErrorStack;
+#[cfg(not(boringssl))]
 use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef};
 use crate::{cvt, cvt_p};
 use cfg_if::cfg_if;
 use foreign_types::{ForeignType, ForeignTypeRef};
-use std::convert::{TryInto, TryFrom};
 use libc::{c_int, c_uchar};
 use openssl_macros::corresponds;
+use std::convert::{TryFrom, TryInto};
 use std::ptr;
 
 cfg_if! {
@@ -338,10 +339,11 @@
     pub fn set_key_length(&mut self, len: usize) -> Result<(), ErrorStack> {
         self.assert_cipher();
 
-        let len = c_int::try_from(len).unwrap();
-
         unsafe {
-            cvt(ffi::EVP_CIPHER_CTX_set_key_length(self.as_ptr(), len.try_into().unwrap()))?;
+            cvt(ffi::EVP_CIPHER_CTX_set_key_length(
+                self.as_ptr(),
+                len.try_into().unwrap(),
+            ))?;
         }
 
         Ok(())
@@ -405,7 +407,7 @@
 
     /// Retrieves the calculated authentication tag from the context.
     ///
-    /// This should be called after `[Self::cipher_final]`, and is only supported by authenticated ciphers.
+    /// This should be called after [`Self::cipher_final`], and is only supported by authenticated ciphers.
     ///
     /// The size of the buffer indicates the size of the tag. While some ciphers support a range of tag sizes, it is
     /// recommended to pick the maximum size.
@@ -587,6 +589,7 @@
 mod test {
     use super::*;
     use crate::cipher::Cipher;
+    #[cfg(not(boringssl))]
     use std::slice;
 
     #[test]
diff --git a/openssl/src/cms.rs b/src/cms.rs
similarity index 100%
rename from openssl/src/cms.rs
rename to src/cms.rs
diff --git a/src/conf.rs b/src/conf.rs
new file mode 100644
index 0000000..2c54cf2
--- /dev/null
+++ b/src/conf.rs
@@ -0,0 +1,64 @@
+//! Interface for processing OpenSSL configuration files.
+
+foreign_type_and_impl_send_sync! {
+    type CType = ffi::CONF;
+    fn drop = ffi::NCONF_free;
+
+    pub struct Conf;
+    pub struct ConfRef;
+}
+
+#[cfg(not(boringssl))]
+mod methods {
+    use super::Conf;
+    use crate::cvt_p;
+    use crate::error::ErrorStack;
+    use openssl_macros::corresponds;
+
+    pub struct ConfMethod(*mut ffi::CONF_METHOD);
+
+    impl ConfMethod {
+        /// Retrieve handle to the default OpenSSL configuration file processing function.
+        #[corresponds(NCONF_default)]
+        pub fn default() -> ConfMethod {
+            unsafe {
+                ffi::init();
+                // `NCONF` stands for "New Conf", as described in crypto/conf/conf_lib.c. This is
+                // a newer API than the "CONF classic" functions.
+                ConfMethod(ffi::NCONF_default())
+            }
+        }
+
+        /// Construct from raw pointer.
+        ///
+        /// # Safety
+        ///
+        /// The caller must ensure that the pointer is valid.
+        pub unsafe fn from_ptr(ptr: *mut ffi::CONF_METHOD) -> ConfMethod {
+            ConfMethod(ptr)
+        }
+
+        /// Convert to raw pointer.
+        pub fn as_ptr(&self) -> *mut ffi::CONF_METHOD {
+            self.0
+        }
+    }
+
+    impl Conf {
+        /// Create a configuration parser.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// use openssl::conf::{Conf, ConfMethod};
+        ///
+        /// let conf = Conf::new(ConfMethod::default());
+        /// ```
+        #[corresponds(NCONF_new)]
+        pub fn new(method: ConfMethod) -> Result<Conf, ErrorStack> {
+            unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) }
+        }
+    }
+}
+#[cfg(not(boringssl))]
+pub use methods::*;
diff --git a/openssl/src/derive.rs b/src/derive.rs
similarity index 100%
rename from openssl/src/derive.rs
rename to src/derive.rs
diff --git a/openssl/src/dh.rs b/src/dh.rs
similarity index 100%
rename from openssl/src/dh.rs
rename to src/dh.rs
diff --git a/openssl/src/dsa.rs b/src/dsa.rs
similarity index 68%
rename from openssl/src/dsa.rs
rename to src/dsa.rs
index 7f04f4e..5f59ba8 100644
--- a/openssl/src/dsa.rs
+++ b/src/dsa.rs
@@ -7,7 +7,7 @@
 
 use cfg_if::cfg_if;
 use foreign_types::{ForeignType, ForeignTypeRef};
-use libc::{c_int, c_uint};
+use libc::c_int;
 use std::fmt;
 use std::mem;
 use std::ptr;
@@ -179,7 +179,7 @@
     }
 }
 #[cfg(boringssl)]
-type BitType = c_uint;
+type BitType = libc::c_uint;
 #[cfg(not(boringssl))]
 type BitType = c_int;
 
@@ -344,12 +344,168 @@
     }
 }
 
+foreign_type_and_impl_send_sync! {
+    type CType = ffi::DSA_SIG;
+    fn drop = ffi::DSA_SIG_free;
+
+    /// Object representing DSA signature.
+    ///
+    /// DSA signatures consist of two components: `r` and `s`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::convert::TryInto;
+    ///
+    /// use openssl::bn::BigNum;
+    /// use openssl::dsa::{Dsa, DsaSig};
+    /// use openssl::hash::MessageDigest;
+    /// use openssl::pkey::PKey;
+    /// use openssl::sign::{Signer, Verifier};
+    ///
+    /// const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    /// let dsa_ref = Dsa::generate(1024).unwrap();
+    ///
+    /// let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap();
+    /// let priv_key: PKey<_> = dsa_ref.try_into().unwrap();
+    ///
+    /// let mut signer = if let Ok(signer) = Signer::new(MessageDigest::sha256(), &priv_key) {
+    ///     signer
+    /// } else {
+    ///     // DSA signing is not supported (eg. BoringSSL)
+    ///     return;
+    /// };
+    ///
+    /// signer.update(TEST_DATA).unwrap();
+    ///
+    /// let signature = signer.sign_to_vec().unwrap();
+    /// // Parse DER-encoded DSA signature
+    /// let signature = DsaSig::from_der(&signature).unwrap();
+    ///
+    /// // Extract components `r` and `s`
+    /// let r = BigNum::from_slice(&signature.r().to_vec()).unwrap();
+    /// let s = BigNum::from_slice(&signature.s().to_vec()).unwrap();
+    ///
+    /// // Construct new DSA signature from components
+    /// let signature = DsaSig::from_private_components(r, s).unwrap();
+    ///
+    /// // Serialize DSA signature to DER
+    /// let signature = signature.to_der().unwrap();
+    ///
+    /// let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap();
+    /// verifier.update(TEST_DATA).unwrap();
+    /// assert!(verifier.verify(&signature[..]).unwrap());
+    /// ```
+    pub struct DsaSig;
+
+    /// Reference to a [`DsaSig`].
+    pub struct DsaSigRef;
+}
+
+impl DsaSig {
+    /// Returns a new `DsaSig` by setting the `r` and `s` values associated with an DSA signature.
+    #[corresponds(DSA_SIG_set0)]
+    pub fn from_private_components(r: BigNum, s: BigNum) -> Result<Self, ErrorStack> {
+        unsafe {
+            let sig = cvt_p(ffi::DSA_SIG_new())?;
+            DSA_SIG_set0(sig, r.as_ptr(), s.as_ptr());
+            mem::forget((r, s));
+            Ok(DsaSig::from_ptr(sig))
+        }
+    }
+
+    from_der! {
+        /// Decodes a DER-encoded DSA signature.
+        #[corresponds(d2i_DSA_SIG)]
+        from_der,
+        DsaSig,
+        ffi::d2i_DSA_SIG
+    }
+}
+
+impl fmt::Debug for DsaSig {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("DsaSig")
+            .field("r", self.r())
+            .field("s", self.s())
+            .finish()
+    }
+}
+
+impl DsaSigRef {
+    to_der! {
+        /// Serializes the DSA signature into a DER-encoded `DSASignature` structure.
+        #[corresponds(i2d_DSA_SIG)]
+        to_der,
+        ffi::i2d_DSA_SIG
+    }
+
+    /// Returns internal component `r` of an `DsaSig`.
+    #[corresponds(DSA_SIG_get0)]
+    pub fn r(&self) -> &BigNumRef {
+        unsafe {
+            let mut r = ptr::null();
+            DSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut());
+            BigNumRef::from_const_ptr(r)
+        }
+    }
+
+    /// Returns internal component `s` of an `DsaSig`.
+    #[corresponds(DSA_SIG_get0)]
+    pub fn s(&self) -> &BigNumRef {
+        unsafe {
+            let mut s = ptr::null();
+            DSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s);
+            BigNumRef::from_const_ptr(s)
+        }
+    }
+}
+
+cfg_if! {
+    if #[cfg(any(ossl110, libressl273))] {
+        use ffi::{DSA_SIG_set0, DSA_SIG_get0};
+    } else {
+        #[allow(bad_style)]
+        unsafe fn DSA_SIG_set0(
+            sig: *mut ffi::DSA_SIG,
+            r: *mut ffi::BIGNUM,
+            s: *mut ffi::BIGNUM,
+        ) -> c_int {
+            if r.is_null() || s.is_null() {
+                return 0;
+            }
+            ffi::BN_clear_free((*sig).r);
+            ffi::BN_clear_free((*sig).s);
+            (*sig).r = r;
+            (*sig).s = s;
+            1
+        }
+
+        #[allow(bad_style)]
+        unsafe fn DSA_SIG_get0(
+            sig: *const ffi::DSA_SIG,
+            pr: *mut *const ffi::BIGNUM,
+            ps: *mut *const ffi::BIGNUM)
+        {
+            if !pr.is_null() {
+                (*pr) = (*sig).r;
+            }
+            if !ps.is_null() {
+                (*ps) = (*sig).s;
+            }
+        }
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
     use crate::bn::BigNumContext;
+    #[cfg(not(boringssl))]
     use crate::hash::MessageDigest;
+    #[cfg(not(boringssl))]
     use crate::pkey::PKey;
+    #[cfg(not(boringssl))]
     use crate::sign::{Signer, Verifier};
 
     #[test]
@@ -442,9 +598,50 @@
     }
 
     #[test]
+    #[cfg(not(boringssl))]
+    fn test_signature_der() {
+        use std::convert::TryInto;
+
+        const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+        let dsa_ref = Dsa::generate(1024).unwrap();
+
+        let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap();
+        let priv_key: PKey<_> = dsa_ref.try_into().unwrap();
+
+        let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap();
+        signer.update(TEST_DATA).unwrap();
+
+        let signature = signer.sign_to_vec().unwrap();
+        eprintln!("{:?}", signature);
+        let signature = DsaSig::from_der(&signature).unwrap();
+
+        let r = BigNum::from_slice(&signature.r().to_vec()).unwrap();
+        let s = BigNum::from_slice(&signature.s().to_vec()).unwrap();
+
+        let signature = DsaSig::from_private_components(r, s).unwrap();
+        let signature = signature.to_der().unwrap();
+
+        let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap();
+        verifier.update(TEST_DATA).unwrap();
+        assert!(verifier.verify(&signature[..]).unwrap());
+    }
+
+    #[test]
     #[allow(clippy::redundant_clone)]
     fn clone() {
         let key = Dsa::generate(2048).unwrap();
         drop(key.clone());
     }
+
+    #[test]
+    fn dsa_sig_debug() {
+        let sig = DsaSig::from_der(&[
+            48, 46, 2, 21, 0, 135, 169, 24, 58, 153, 37, 175, 248, 200, 45, 251, 112, 238, 238, 89,
+            172, 177, 182, 166, 237, 2, 21, 0, 159, 146, 151, 237, 187, 8, 82, 115, 14, 183, 103,
+            12, 203, 46, 161, 208, 251, 167, 123, 131,
+        ])
+        .unwrap();
+        let s = format!("{:?}", sig);
+        assert_eq!(s, "DsaSig { r: 774484690634577222213819810519929266740561094381, s: 910998676210681457251421818099943952372231273347 }");
+    }
 }
diff --git a/openssl/src/ec.rs b/src/ec.rs
similarity index 85%
rename from openssl/src/ec.rs
rename to src/ec.rs
index 13f8bb3..88dcaaf 100644
--- a/openssl/src/ec.rs
+++ b/src/ec.rs
@@ -14,13 +14,13 @@
 //!
 //! [`EcGroup`]: struct.EcGroup.html
 //! [`Nid`]: ../nid/struct.Nid.html
-//! [Eliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography
+//! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography
 use foreign_types::{ForeignType, ForeignTypeRef};
 use libc::c_int;
 use std::fmt;
 use std::ptr;
 
-use crate::bn::{BigNumContextRef, BigNumRef};
+use crate::bn::{BigNum, BigNumContextRef, BigNumRef};
 use crate::error::ErrorStack;
 use crate::nid::Nid;
 use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
@@ -123,6 +123,25 @@
             cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup)
         }
     }
+
+    /// Returns the group for given parameters
+    #[corresponds(EC_GROUP_new_curve_GFp)]
+    pub fn from_components(
+        p: BigNum,
+        a: BigNum,
+        b: BigNum,
+        ctx: &mut BigNumContextRef,
+    ) -> Result<EcGroup, ErrorStack> {
+        unsafe {
+            cvt_p(ffi::EC_GROUP_new_curve_GFp(
+                p.as_ptr(),
+                a.as_ptr(),
+                b.as_ptr(),
+                ctx.as_ptr(),
+            ))
+            .map(EcGroup)
+        }
+    }
 }
 
 impl EcGroupRef {
@@ -214,6 +233,25 @@
         }
     }
 
+    /// Sets the generator point for the given curve
+    #[corresponds(EC_GROUP_set_generator)]
+    pub fn set_generator(
+        &mut self,
+        generator: EcPoint,
+        order: BigNum,
+        cofactor: BigNum,
+    ) -> Result<(), ErrorStack> {
+        unsafe {
+            cvt(ffi::EC_GROUP_set_generator(
+                self.as_ptr(),
+                generator.as_ptr(),
+                order.as_ptr(),
+                cofactor.as_ptr(),
+            ))
+            .map(|_| ())
+        }
+    }
+
     /// Places the order of the curve in the provided `BigNum`.
     #[corresponds(EC_GROUP_get_order)]
     pub fn order(
@@ -476,6 +514,28 @@
         }
     }
 
+    /// Sets affine coordinates of a curve over a prime field using the provided
+    /// `x` and `y` `BigNum`s
+    #[corresponds(EC_POINT_set_affine_coordinates_GFp)]
+    pub fn set_affine_coordinates_gfp(
+        &mut self,
+        group: &EcGroupRef,
+        x: &BigNumRef,
+        y: &BigNumRef,
+        ctx: &mut BigNumContextRef,
+    ) -> Result<(), ErrorStack> {
+        unsafe {
+            cvt(ffi::EC_POINT_set_affine_coordinates_GFp(
+                group.as_ptr(),
+                self.as_ptr(),
+                x.as_ptr(),
+                y.as_ptr(),
+                ctx.as_ptr(),
+            ))
+            .map(|_| ())
+        }
+    }
+
     /// Places affine coordinates of a curve over a binary field in the provided
     /// `x` and `y` `BigNum`s
     #[corresponds(EC_POINT_get_affine_coordinates_GF2m)]
@@ -848,6 +908,26 @@
         EcKey<Private>,
         ffi::d2i_ECPrivateKey
     }
+
+    /// Decodes a DER-encoded elliptic curve private key structure for the specified curve.
+    #[corresponds(EC_KEY_parse_private_key)]
+    #[cfg(boringssl)]
+    pub fn private_key_from_der_for_group(
+        der: &[u8],
+        group: &EcGroupRef,
+    ) -> Result<EcKey<Private>, ErrorStack> {
+        unsafe {
+            let mut cbs = ffi::CBS {
+                data: der.as_ptr(),
+                len: der.len(),
+            };
+            cvt_p(ffi::EC_KEY_parse_private_key(
+                &mut cbs as *mut ffi::CBS,
+                group.as_ptr(),
+            ))
+            .map(|p| EcKey::from_ptr(p))
+        }
+    }
 }
 
 impl<T> Clone for EcKey<T> {
@@ -882,6 +962,97 @@
     }
 
     #[test]
+    fn ec_group_from_components() {
+        // parameters are from secp256r1
+        let p = BigNum::from_hex_str(
+            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+        )
+        .unwrap();
+        let a = BigNum::from_hex_str(
+            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+        )
+        .unwrap();
+        let b = BigNum::from_hex_str(
+            "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+        )
+        .unwrap();
+        let mut ctx = BigNumContext::new().unwrap();
+
+        let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
+    }
+
+    #[test]
+    fn ec_point_set_affine() {
+        // parameters are from secp256r1
+        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+        let mut ctx = BigNumContext::new().unwrap();
+        let mut gen_point = EcPoint::new(&group).unwrap();
+        let gen_x = BigNum::from_hex_str(
+            "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+        )
+        .unwrap();
+        let gen_y = BigNum::from_hex_str(
+            "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+        )
+        .unwrap();
+        gen_point
+            .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
+            .unwrap();
+        assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
+    }
+
+    #[test]
+    fn ec_group_set_generator() {
+        // parameters are from secp256r1
+        let mut ctx = BigNumContext::new().unwrap();
+        let p = BigNum::from_hex_str(
+            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+        )
+        .unwrap();
+        let a = BigNum::from_hex_str(
+            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+        )
+        .unwrap();
+        let b = BigNum::from_hex_str(
+            "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+        )
+        .unwrap();
+
+        let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
+
+        let mut gen_point = EcPoint::new(&group).unwrap();
+        let gen_x = BigNum::from_hex_str(
+            "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+        )
+        .unwrap();
+        let gen_y = BigNum::from_hex_str(
+            "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+        )
+        .unwrap();
+        gen_point
+            .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
+            .unwrap();
+
+        let order = BigNum::from_hex_str(
+            "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+        )
+        .unwrap();
+        let cofactor = BigNum::from_hex_str("01").unwrap();
+        group.set_generator(gen_point, order, cofactor).unwrap();
+        let mut constructed_order = BigNum::new().unwrap();
+        group.order(&mut constructed_order, &mut ctx).unwrap();
+
+        let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+        let mut named_order = BigNum::new().unwrap();
+        named_group.order(&mut named_order, &mut ctx).unwrap();
+
+        assert_eq!(
+            constructed_order.ucmp(&named_order),
+            std::cmp::Ordering::Equal
+        );
+    }
+
+    #[test]
     fn cofactor() {
         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
         let mut ctx = BigNumContext::new().unwrap();
diff --git a/openssl/src/ecdsa.rs b/src/ecdsa.rs
similarity index 97%
rename from openssl/src/ecdsa.rs
rename to src/ecdsa.rs
index e0c6c1b..0a960e7 100644
--- a/openssl/src/ecdsa.rs
+++ b/src/ecdsa.rs
@@ -2,7 +2,7 @@
 
 use cfg_if::cfg_if;
 use foreign_types::{ForeignType, ForeignTypeRef};
-use libc::{c_int, size_t};
+use libc::c_int;
 use std::mem;
 use std::ptr;
 
@@ -11,7 +11,7 @@
 use crate::error::ErrorStack;
 use crate::pkey::{HasPrivate, HasPublic};
 use crate::util::ForeignTypeRefExt;
-use crate::{cvt_n, cvt_p};
+use crate::{cvt_n, cvt_p, LenType};
 use openssl_macros::corresponds;
 
 foreign_type_and_impl_send_sync! {
@@ -24,11 +24,6 @@
     pub struct EcdsaSigRef;
 }
 
-#[cfg(boringssl)]
-type LenType = size_t;
-#[cfg(not(boringssl))]
-type LenType = c_int;
-
 impl EcdsaSig {
     /// Computes a digital signature of the hash value `data` using the private EC key eckey.
     #[corresponds(ECDSA_do_sign)]
diff --git a/openssl/src/encrypt.rs b/src/encrypt.rs
similarity index 99%
rename from openssl/src/encrypt.rs
rename to src/encrypt.rs
index 3cb10fc..34a9eb8 100644
--- a/openssl/src/encrypt.rs
+++ b/src/encrypt.rs
@@ -148,7 +148,7 @@
     /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
     ///
     /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
-    #[cfg(any(ossl102, libressl310))]
+    #[cfg(any(ossl102, libressl310, boringssl))]
     pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
         unsafe {
             cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
@@ -352,7 +352,7 @@
     /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
     ///
     /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
-    #[cfg(any(ossl102, libressl310))]
+    #[cfg(any(ossl102, libressl310, boringssl))]
     pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
         unsafe {
             cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
diff --git a/openssl/src/envelope.rs b/src/envelope.rs
similarity index 100%
rename from openssl/src/envelope.rs
rename to src/envelope.rs
diff --git a/openssl/src/error.rs b/src/error.rs
similarity index 82%
rename from openssl/src/error.rs
rename to src/error.rs
index 572937b..58b4d70 100644
--- a/openssl/src/error.rs
+++ b/src/error.rs
@@ -16,8 +16,9 @@
 //! }
 //! ```
 use cfg_if::cfg_if;
-use libc::{c_char, c_int, c_uint, c_ulong};
+use libc::{c_char, c_int};
 use std::borrow::Cow;
+#[cfg(boringssl)]
 use std::convert::TryInto;
 use std::error;
 use std::ffi::CStr;
@@ -27,9 +28,9 @@
 use std::str;
 
 #[cfg(not(boringssl))]
-type ErrType = c_ulong;
+type ErrType = libc::c_ulong;
 #[cfg(boringssl)]
-type ErrType = c_uint;
+type ErrType = libc::c_uint;
 
 /// Collection of [`Error`]s from OpenSSL.
 ///
@@ -98,9 +99,9 @@
 #[derive(Clone)]
 pub struct Error {
     code: ErrType,
-    file: *const c_char,
+    file: ShimStr,
     line: c_int,
-    func: *const c_char,
+    func: Option<ShimStr>,
     data: Option<Cow<'static, str>>,
 }
 
@@ -138,6 +139,15 @@
                     } else {
                         None
                     };
+
+                    let file = ShimStr::new(file);
+
+                    let func = if func.is_null() {
+                        None
+                    } else {
+                        Some(ShimStr::new(func))
+                    };
+
                     Some(Error {
                         code,
                         file,
@@ -183,7 +193,11 @@
     fn put_error(&self) {
         unsafe {
             ffi::ERR_new();
-            ffi::ERR_set_debug(self.file, self.line, self.func);
+            ffi::ERR_set_debug(
+                self.file.as_ptr(),
+                self.line,
+                self.func.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
+            );
             ffi::ERR_set_error(
                 ffi::ERR_GET_LIB(self.code),
                 ffi::ERR_GET_REASON(self.code),
@@ -194,13 +208,17 @@
 
     #[cfg(not(ossl300))]
     fn put_error(&self) {
+        #[cfg(not(boringssl))]
+        let line = self.line;
+        #[cfg(boringssl)]
+        let line = self.line.try_into().unwrap();
         unsafe {
             ffi::ERR_put_error(
                 ffi::ERR_GET_LIB(self.code),
                 ffi::ERR_GET_FUNC(self.code),
                 ffi::ERR_GET_REASON(self.code),
-                self.file,
-                self.line.try_into().unwrap(),
+                self.file.as_ptr(),
+                line,
             );
         }
     }
@@ -223,14 +241,8 @@
     }
 
     /// Returns the name of the function reporting the error.
-    pub fn function(&self) -> Option<&'static str> {
-        unsafe {
-            if self.func.is_null() {
-                return None;
-            }
-            let bytes = CStr::from_ptr(self.func).to_bytes();
-            Some(str::from_utf8(bytes).unwrap())
-        }
+    pub fn function(&self) -> Option<RetStr<'_>> {
+        self.func.as_ref().map(|s| s.as_str())
     }
 
     /// Returns the reason for the error.
@@ -246,12 +258,8 @@
     }
 
     /// Returns the name of the source file which encountered the error.
-    pub fn file(&self) -> &'static str {
-        unsafe {
-            assert!(!self.file.is_null());
-            let bytes = CStr::from_ptr(self.file as *const _).to_bytes();
-            str::from_utf8(bytes).unwrap()
-        }
+    pub fn file(&self) -> RetStr<'_> {
+        self.file.as_str()
     }
 
     /// Returns the line in the source file which encountered the error.
@@ -317,7 +325,27 @@
 
 cfg_if! {
     if #[cfg(ossl300)] {
+        use std::ffi::{CString};
         use ffi::ERR_get_error_all;
+
+        type RetStr<'a> = &'a str;
+
+        #[derive(Clone)]
+        struct ShimStr(CString);
+
+        impl ShimStr {
+            unsafe fn new(s: *const c_char) -> Self {
+                ShimStr(CStr::from_ptr(s).to_owned())
+            }
+
+            fn as_ptr(&self) -> *const c_char {
+                self.0.as_ptr()
+            }
+
+            fn as_str(&self) -> &str {
+                self.0.to_str().unwrap()
+            }
+        }
     } else {
         #[allow(bad_style)]
         unsafe extern "C" fn ERR_get_error_all(
@@ -331,5 +359,26 @@
             *func = ffi::ERR_func_error_string(code);
             code
         }
+
+        type RetStr<'a> = &'static str;
+
+        #[derive(Clone)]
+        struct ShimStr(*const c_char);
+
+        impl ShimStr {
+            unsafe fn new(s: *const c_char) -> Self {
+                ShimStr(s)
+            }
+
+            fn as_ptr(&self) -> *const c_char {
+                self.0
+            }
+
+            fn as_str(&self) -> &'static str {
+                unsafe {
+                    CStr::from_ptr(self.0).to_str().unwrap()
+                }
+            }
+        }
     }
 }
diff --git a/openssl/src/ex_data.rs b/src/ex_data.rs
similarity index 100%
rename from openssl/src/ex_data.rs
rename to src/ex_data.rs
diff --git a/openssl/src/fips.rs b/src/fips.rs
similarity index 100%
rename from openssl/src/fips.rs
rename to src/fips.rs
diff --git a/openssl/src/hash.rs b/src/hash.rs
similarity index 91%
rename from openssl/src/hash.rs
rename to src/hash.rs
index a7c02fa..fd83869 100644
--- a/openssl/src/hash.rs
+++ b/src/hash.rs
@@ -484,6 +484,7 @@
 
         assert_eq!(MessageDigest::md5().block_size(), 64);
         assert_eq!(MessageDigest::md5().size(), 16);
+        assert_eq!(MessageDigest::md5().type_().as_raw(), Nid::MD5.as_raw());
     }
 
     #[test]
@@ -546,6 +547,7 @@
 
         assert_eq!(MessageDigest::sha1().block_size(), 64);
         assert_eq!(MessageDigest::sha1().size(), 20);
+        assert_eq!(MessageDigest::sha1().type_().as_raw(), Nid::SHA1.as_raw());
     }
 
     #[test]
@@ -561,6 +563,30 @@
 
         assert_eq!(MessageDigest::sha256().block_size(), 64);
         assert_eq!(MessageDigest::sha256().size(), 32);
+        assert_eq!(
+            MessageDigest::sha256().type_().as_raw(),
+            Nid::SHA256.as_raw()
+        );
+    }
+
+    #[test]
+    fn test_sha512() {
+        let tests = [(
+            "737465766566696e647365766572797468696e67",
+            "ba61d1f1af0f2dd80729f6cc900f19c0966bd38ba5c75e4471ef11b771dfe7551afab7fcbd300fdc4418f2\
+            b07a028fcd99e7b6446a566f2d9bcd7c604a1ea801",
+        )];
+
+        for test in tests.iter() {
+            hash_test(MessageDigest::sha512(), test);
+        }
+
+        assert_eq!(MessageDigest::sha512().block_size(), 128);
+        assert_eq!(MessageDigest::sha512().size(), 64);
+        assert_eq!(
+            MessageDigest::sha512().type_().as_raw(),
+            Nid::SHA512.as_raw()
+        );
     }
 
     #[cfg(ossl111)]
@@ -577,6 +603,10 @@
 
         assert_eq!(MessageDigest::sha3_224().block_size(), 144);
         assert_eq!(MessageDigest::sha3_224().size(), 28);
+        assert_eq!(
+            MessageDigest::sha3_224().type_().as_raw(),
+            Nid::SHA3_224.as_raw()
+        );
     }
 
     #[cfg(ossl111)]
@@ -593,6 +623,10 @@
 
         assert_eq!(MessageDigest::sha3_256().block_size(), 136);
         assert_eq!(MessageDigest::sha3_256().size(), 32);
+        assert_eq!(
+            MessageDigest::sha3_256().type_().as_raw(),
+            Nid::SHA3_256.as_raw()
+        );
     }
 
     #[cfg(ossl111)]
@@ -609,6 +643,10 @@
 
         assert_eq!(MessageDigest::sha3_384().block_size(), 104);
         assert_eq!(MessageDigest::sha3_384().size(), 48);
+        assert_eq!(
+            MessageDigest::sha3_384().type_().as_raw(),
+            Nid::SHA3_384.as_raw()
+        );
     }
 
     #[cfg(ossl111)]
@@ -625,6 +663,10 @@
 
         assert_eq!(MessageDigest::sha3_512().block_size(), 72);
         assert_eq!(MessageDigest::sha3_512().size(), 64);
+        assert_eq!(
+            MessageDigest::sha3_512().type_().as_raw(),
+            Nid::SHA3_512.as_raw()
+        );
     }
 
     #[cfg(ossl111)]
@@ -641,6 +683,10 @@
 
         assert_eq!(MessageDigest::shake_128().block_size(), 168);
         assert_eq!(MessageDigest::shake_128().size(), 16);
+        assert_eq!(
+            MessageDigest::shake_128().type_().as_raw(),
+            Nid::SHAKE128.as_raw()
+        );
     }
 
     #[cfg(ossl111)]
@@ -657,6 +703,10 @@
 
         assert_eq!(MessageDigest::shake_256().block_size(), 136);
         assert_eq!(MessageDigest::shake_256().size(), 32);
+        assert_eq!(
+            MessageDigest::shake_256().type_().as_raw(),
+            Nid::SHAKE256.as_raw()
+        );
     }
 
     #[test]
@@ -674,6 +724,10 @@
 
         assert_eq!(MessageDigest::ripemd160().block_size(), 64);
         assert_eq!(MessageDigest::ripemd160().size(), 20);
+        assert_eq!(
+            MessageDigest::ripemd160().type_().as_raw(),
+            Nid::RIPEMD160.as_raw()
+        );
     }
 
     #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
@@ -690,6 +744,7 @@
 
         assert_eq!(MessageDigest::sm3().block_size(), 64);
         assert_eq!(MessageDigest::sm3().size(), 32);
+        assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw());
     }
 
     #[test]
diff --git a/openssl/src/hkdf.rs b/src/hkdf.rs
similarity index 100%
rename from openssl/src/hkdf.rs
rename to src/hkdf.rs
diff --git a/openssl/src/hmac.rs b/src/hmac.rs
similarity index 100%
rename from openssl/src/hmac.rs
rename to src/hmac.rs
diff --git a/openssl/src/lib.rs b/src/lib.rs
similarity index 96%
rename from openssl/src/lib.rs
rename to src/lib.rs
index 0bba5b9..b91d067 100644
--- a/openssl/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,7 @@
 //! Bindings to OpenSSL
 //!
 //! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through
-//! 1.1.1 and LibreSSL versions 2.5 through 3.4.1 are supported.
+//! 3.x.x and LibreSSL versions 2.5 through 3.4.1 are supported.
 //!
 //! # Building
 //!
@@ -120,7 +120,7 @@
 #![doc(html_root_url = "https://docs.rs/openssl/0.10")]
 #![warn(rust_2018_idioms)]
 
-#[cfg(boringssl)]
+#[cfg(all(soong,boringssl))]
 extern crate bssl_ffi as ffi;
 
 #[doc(inline)]
@@ -191,6 +191,11 @@
 pub mod version;
 pub mod x509;
 
+#[cfg(boringssl)]
+type LenType = libc::size_t;
+#[cfg(not(boringssl))]
+type LenType = libc::c_int;
+
 #[inline]
 fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
     if r.is_null() {
diff --git a/openssl/src/lib_ctx.rs b/src/lib_ctx.rs
similarity index 100%
rename from openssl/src/lib_ctx.rs
rename to src/lib_ctx.rs
diff --git a/openssl/src/macros.rs b/src/macros.rs
similarity index 100%
rename from openssl/src/macros.rs
rename to src/macros.rs
diff --git a/openssl/src/md.rs b/src/md.rs
similarity index 100%
rename from openssl/src/md.rs
rename to src/md.rs
diff --git a/openssl/src/md_ctx.rs b/src/md_ctx.rs
similarity index 67%
rename from openssl/src/md_ctx.rs
rename to src/md_ctx.rs
index 2d587e5..c4d3f06 100644
--- a/openssl/src/md_ctx.rs
+++ b/src/md_ctx.rs
@@ -50,34 +50,40 @@
 //! assert!(valid);
 //! ```
 //!
-//! Compute and verify an HMAC-SHA256
-//!
-//! ```
-//! use openssl::md::Md;
-//! use openssl::md_ctx::MdCtx;
-//! use openssl::memcmp;
-//! use openssl::pkey::PKey;
-//!
-//! // Create a key with the HMAC secret.
-//! let key = PKey::hmac(b"my secret").unwrap();
-//!
-//! let text = b"Some Crypto Text";
-//!
-//! // Compute the HMAC.
-//! let mut ctx = MdCtx::new().unwrap();
-//! ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap();
-//! ctx.digest_sign_update(text).unwrap();
-//! let mut hmac = vec![];
-//! ctx.digest_sign_final_to_vec(&mut hmac).unwrap();
-//!
-//! // Verify the HMAC. You can't use MdCtx to do this; instead use a constant time equality check.
-//! # let target = hmac.clone();
-//! let valid = memcmp::eq(&hmac, &target);
-//! assert!(valid);
-//! ```
+
+#![cfg_attr(
+    not(boringssl),
+    doc = r#"\
+Compute and verify an HMAC-SHA256
+
+```
+use openssl::md::Md;
+use openssl::md_ctx::MdCtx;
+use openssl::memcmp;
+use openssl::pkey::PKey;
+
+// Create a key with the HMAC secret.
+let key = PKey::hmac(b"my secret").unwrap();
+
+let text = b"Some Crypto Text";
+
+// Compute the HMAC.
+let mut ctx = MdCtx::new().unwrap();
+ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap();
+ctx.digest_sign_update(text).unwrap();
+let mut hmac = vec![];
+ctx.digest_sign_final_to_vec(&mut hmac).unwrap();
+
+// Verify the HMAC. You can't use MdCtx to do this; instead use a constant time equality check.
+# let target = hmac.clone();
+let valid = memcmp::eq(&hmac, &target);
+assert!(valid);
+```"#
+)]
+
 use crate::error::ErrorStack;
 use crate::md::MdRef;
-use crate::pkey::{HasPrivate, PKeyRef};
+use crate::pkey::{HasPrivate, HasPublic, PKeyRef};
 use crate::pkey_ctx::PkeyCtxRef;
 use crate::{cvt, cvt_n, cvt_p};
 use cfg_if::cfg_if;
@@ -170,7 +176,7 @@
         pkey: &PKeyRef<T>,
     ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack>
     where
-        T: HasPrivate,
+        T: HasPublic,
     {
         unsafe {
             let mut p = ptr::null_mut();
@@ -373,6 +379,24 @@
             Ok(r == 1)
         }
     }
+
+    /// Returns the size of the message digest, i.e. the size of the hash
+    #[corresponds(EVP_MD_CTX_size)]
+    #[inline]
+    pub fn size(&self) -> usize {
+        unsafe { ffi::EVP_MD_CTX_size(self.as_ptr()) as usize }
+    }
+
+    /// Resets the underlying EVP_MD_CTX instance
+    #[corresponds(EVP_MD_CTX_reset)]
+    #[cfg(ossl111)]
+    #[inline]
+    pub fn reset(&mut self) -> Result<(), ErrorStack> {
+        unsafe {
+            let _ = cvt(ffi::EVP_MD_CTX_reset(self.as_ptr()))?;
+            Ok(())
+        }
+    }
 }
 
 #[cfg(test)]
@@ -403,4 +427,114 @@
         let valid = ctx.digest_verify_final(&signature).unwrap();
         assert!(!valid);
     }
+
+    #[test]
+    fn verify_success() {
+        let key1 = Rsa::generate(2048).unwrap();
+        let key1 = PKey::from_rsa(key1).unwrap();
+
+        let md = Md::sha256();
+        let data = b"Some Crypto Text";
+
+        let mut ctx = MdCtx::new().unwrap();
+        ctx.digest_sign_init(Some(md), &key1).unwrap();
+        ctx.digest_sign_update(data).unwrap();
+        let mut signature = vec![];
+        ctx.digest_sign_final_to_vec(&mut signature).unwrap();
+
+        let good_data = b"Some Crypto Text";
+
+        ctx.digest_verify_init(Some(md), &key1).unwrap();
+        ctx.digest_verify_update(good_data).unwrap();
+        let valid = ctx.digest_verify_final(&signature).unwrap();
+        assert!(valid);
+    }
+
+    #[test]
+    fn verify_with_public_success() {
+        let rsa = Rsa::generate(2048).unwrap();
+        let key1 = PKey::from_rsa(rsa.clone()).unwrap();
+
+        let md = Md::sha256();
+        let data = b"Some Crypto Text";
+
+        let mut ctx = MdCtx::new().unwrap();
+        ctx.digest_sign_init(Some(md), &key1).unwrap();
+        ctx.digest_sign_update(data).unwrap();
+        let mut signature = vec![];
+        ctx.digest_sign_final_to_vec(&mut signature).unwrap();
+
+        let good_data = b"Some Crypto Text";
+
+        // try to verify using only public components of the key
+        let n = rsa.n().to_owned().unwrap();
+        let e = rsa.e().to_owned().unwrap();
+
+        let rsa = Rsa::from_public_components(n, e).unwrap();
+        let key1 = PKey::from_rsa(rsa).unwrap();
+
+        ctx.digest_verify_init(Some(md), &key1).unwrap();
+        ctx.digest_verify_update(good_data).unwrap();
+        let valid = ctx.digest_verify_final(&signature).unwrap();
+        assert!(valid);
+    }
+
+    #[test]
+    fn verify_md_ctx_size() {
+        let mut ctx = MdCtx::new().unwrap();
+        ctx.digest_init(Md::sha224()).unwrap();
+        assert_eq!(Md::sha224().size(), ctx.size());
+        assert_eq!(Md::sha224().size(), 28);
+
+        let mut ctx = MdCtx::new().unwrap();
+        ctx.digest_init(Md::sha256()).unwrap();
+        assert_eq!(Md::sha256().size(), ctx.size());
+        assert_eq!(Md::sha256().size(), 32);
+
+        let mut ctx = MdCtx::new().unwrap();
+        ctx.digest_init(Md::sha384()).unwrap();
+        assert_eq!(Md::sha384().size(), ctx.size());
+        assert_eq!(Md::sha384().size(), 48);
+
+        let mut ctx = MdCtx::new().unwrap();
+        ctx.digest_init(Md::sha512()).unwrap();
+        assert_eq!(Md::sha512().size(), ctx.size());
+        assert_eq!(Md::sha512().size(), 64);
+    }
+
+    #[test]
+    #[cfg(ossl111)]
+    fn verify_md_ctx_reset() {
+        let hello_expected =
+            hex::decode("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969")
+                .unwrap();
+        let world_expected =
+            hex::decode("78ae647dc5544d227130a0682a51e30bc7777fbb6d8a8f17007463a3ecd1d524")
+                .unwrap();
+        // Calculate SHA-256 digest of "Hello"
+        let mut ctx = MdCtx::new().unwrap();
+        ctx.digest_init(Md::sha256()).unwrap();
+        ctx.digest_update(b"Hello").unwrap();
+        let mut result = vec![0; 32];
+        let result_len = ctx.digest_final(result.as_mut_slice()).unwrap();
+        assert_eq!(result_len, result.len());
+        // Validate result of "Hello"
+        assert_eq!(result, hello_expected);
+
+        // Create new context
+        let mut ctx = MdCtx::new().unwrap();
+        // Initialize and update to "Hello"
+        ctx.digest_init(Md::sha256()).unwrap();
+        ctx.digest_update(b"Hello").unwrap();
+        // Now reset, init to SHA-256 and use "World"
+        ctx.reset().unwrap();
+        ctx.digest_init(Md::sha256()).unwrap();
+        ctx.digest_update(b"World").unwrap();
+
+        let mut reset_result = vec![0; 32];
+        let result_len = ctx.digest_final(reset_result.as_mut_slice()).unwrap();
+        assert_eq!(result_len, reset_result.len());
+        // Validate result of digest of "World"
+        assert_eq!(reset_result, world_expected);
+    }
 }
diff --git a/openssl/src/memcmp.rs b/src/memcmp.rs
similarity index 100%
rename from openssl/src/memcmp.rs
rename to src/memcmp.rs
diff --git a/openssl/src/nid.rs b/src/nid.rs
similarity index 98%
rename from openssl/src/nid.rs
rename to src/nid.rs
index d454428..eadae31 100644
--- a/openssl/src/nid.rs
+++ b/src/nid.rs
@@ -215,6 +215,12 @@
     pub const SECT409R1: Nid = Nid(ffi::NID_sect409r1);
     pub const SECT571K1: Nid = Nid(ffi::NID_sect571k1);
     pub const SECT571R1: Nid = Nid(ffi::NID_sect571r1);
+    #[cfg(ossl110)]
+    pub const BRAINPOOL_P256R1: Nid = Nid(ffi::NID_brainpoolP256r1);
+    #[cfg(ossl110)]
+    pub const BRAINPOOL_P384R1: Nid = Nid(ffi::NID_brainpoolP384r1);
+    #[cfg(ossl110)]
+    pub const BRAINPOOL_P512R1: Nid = Nid(ffi::NID_brainpoolP512r1);
     pub const WAP_WSG_IDM_ECID_WTLS1: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls1);
     pub const WAP_WSG_IDM_ECID_WTLS3: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls3);
     pub const WAP_WSG_IDM_ECID_WTLS4: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls4);
@@ -1068,6 +1074,20 @@
     pub const AES_128_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_128_cbc_hmac_sha1);
     pub const AES_192_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_192_cbc_hmac_sha1);
     pub const AES_256_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_256_cbc_hmac_sha1);
+    #[cfg(any(ossl111, libressl291))]
+    pub const SM3: Nid = Nid(ffi::NID_sm3);
+    #[cfg(ossl111)]
+    pub const SHA3_224: Nid = Nid(ffi::NID_sha3_224);
+    #[cfg(ossl111)]
+    pub const SHA3_256: Nid = Nid(ffi::NID_sha3_256);
+    #[cfg(ossl111)]
+    pub const SHA3_384: Nid = Nid(ffi::NID_sha3_384);
+    #[cfg(ossl111)]
+    pub const SHA3_512: Nid = Nid(ffi::NID_sha3_512);
+    #[cfg(ossl111)]
+    pub const SHAKE128: Nid = Nid(ffi::NID_shake128);
+    #[cfg(ossl111)]
+    pub const SHAKE256: Nid = Nid(ffi::NID_shake256);
 }
 
 #[cfg(test)]
diff --git a/openssl/src/ocsp.rs b/src/ocsp.rs
similarity index 100%
rename from openssl/src/ocsp.rs
rename to src/ocsp.rs
diff --git a/openssl/src/pkcs12.rs b/src/pkcs12.rs
similarity index 98%
rename from openssl/src/pkcs12.rs
rename to src/pkcs12.rs
index 758c7b9..d4e19dc 100644
--- a/openssl/src/pkcs12.rs
+++ b/src/pkcs12.rs
@@ -6,6 +6,7 @@
 use std::ptr;
 
 use crate::error::ErrorStack;
+#[cfg(not(boringssl))]
 use crate::hash::MessageDigest;
 use crate::nid::Nid;
 use crate::pkey::{HasPrivate, PKey, PKeyRef, Private};
@@ -196,7 +197,7 @@
                 nid_key,
                 nid_cert,
                 self.iter,
-                -1,
+                self.mac_iter,
                 keytype,
             ))
             .map(Pkcs12)?;
@@ -268,7 +269,9 @@
         let der = include_bytes!("../test/keystore-empty-chain.p12");
         let pkcs12 = Pkcs12::from_der(der).unwrap();
         let parsed = pkcs12.parse("cassandra").unwrap();
-        assert!(parsed.chain.is_none());
+        if let Some(stack) = parsed.chain {
+            assert_eq!(stack.len(), 0);
+        }
     }
 
     #[test]
diff --git a/openssl/src/pkcs5.rs b/src/pkcs5.rs
similarity index 100%
rename from openssl/src/pkcs5.rs
rename to src/pkcs5.rs
diff --git a/openssl/src/pkcs7.rs b/src/pkcs7.rs
similarity index 97%
rename from openssl/src/pkcs7.rs
rename to src/pkcs7.rs
index e1b30f9..ae4571d 100644
--- a/openssl/src/pkcs7.rs
+++ b/src/pkcs7.rs
@@ -361,7 +361,9 @@
         assert_eq!(content.expect("should be non-empty"), message.as_bytes());
     }
 
+    /// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2
     #[test]
+    #[cfg_attr(all(libressl360, not(libressl361)), ignore)]
     fn sign_verify_test_normal() {
         let cert = include_bytes!("../test/cert.pem");
         let cert = X509::from_pem(cert).unwrap();
@@ -397,7 +399,9 @@
         assert!(content.is_none());
     }
 
+    /// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2
     #[test]
+    #[cfg_attr(all(libressl360, not(libressl361)), ignore)]
     fn signers() {
         let cert = include_bytes!("../test/cert.pem");
         let cert = X509::from_pem(cert).unwrap();
diff --git a/openssl/src/pkey.rs b/src/pkey.rs
similarity index 90%
rename from openssl/src/pkey.rs
rename to src/pkey.rs
index 5b5a4e0..7eaf068 100644
--- a/openssl/src/pkey.rs
+++ b/src/pkey.rs
@@ -80,7 +80,7 @@
     pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
     #[cfg(not(boringssl))]
     pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
-#[cfg(not(boringssl))]
+    #[cfg(not(boringssl))]
     pub const CMAC: Id = Id(ffi::EVP_PKEY_CMAC);
     pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
     pub const DH: Id = Id(ffi::EVP_PKEY_DH);
@@ -238,10 +238,10 @@
         unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
     }
 
-    /// Raw byte representation of a public key
+    /// Raw byte representation of a public key.
     ///
     /// This function only works for algorithms that support raw public keys.
-    /// Currently this is: X25519, ED25519, X448 or ED448
+    /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
     #[corresponds(EVP_PKEY_get_raw_public_key)]
     #[cfg(any(boringssl, ossl111))]
     pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
@@ -289,10 +289,10 @@
         ffi::i2d_PrivateKey
     }
 
-    /// Raw byte representation of a private key
+    /// Raw byte representation of a private key.
     ///
     /// This function only works for algorithms that support raw private keys.
-    /// Currently this is: HMAC, X25519, ED25519, X448 or ED448
+    /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
     #[corresponds(EVP_PKEY_get_raw_private_key)]
     #[cfg(any(boringssl, ossl111))]
     pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
@@ -465,7 +465,7 @@
     /// # Note
     ///
     /// To compute CMAC values, use the `sign` module.
-    #[cfg(any(not(boringssl), ossl110))]
+    #[cfg(all(not(boringssl), ossl110))]
     #[allow(clippy::trivially_copy_pass_by_ref)]
     pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
         let mut ctx = PkeyCtx::new_id(Id::CMAC)?;
@@ -482,25 +482,109 @@
         ctx.keygen()
     }
 
-    /// Generates a new private Ed25519 key
+    /// Generates a new private X25519 key.
+    ///
+    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// use openssl::pkey::{PKey, Id};
+    /// use openssl::derive::Deriver;
+    ///
+    /// let public = // ...
+    /// # &PKey::generate_x25519()?.raw_public_key()?;
+    /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X25519)?;
+    ///
+    /// let key = PKey::generate_x25519()?;
+    /// let mut deriver = Deriver::new(&key)?;
+    /// deriver.set_peer(&public_key)?;
+    ///
+    /// let secret = deriver.derive_to_vec()?;
+    /// assert_eq!(secret.len(), 32);
+    /// # Ok(()) }
+    /// ```
     #[cfg(any(boringssl, ossl111))]
     pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
         PKey::generate_eddsa(Id::X25519)
     }
 
-    /// Generates a new private Ed448 key
+    /// Generates a new private X448 key.
+    ///
+    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// use openssl::pkey::{PKey, Id};
+    /// use openssl::derive::Deriver;
+    ///
+    /// let public = // ...
+    /// # &PKey::generate_x448()?.raw_public_key()?;
+    /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X448)?;
+    ///
+    /// let key = PKey::generate_x448()?;
+    /// let mut deriver = Deriver::new(&key)?;
+    /// deriver.set_peer(&public_key)?;
+    ///
+    /// let secret = deriver.derive_to_vec()?;
+    /// assert_eq!(secret.len(), 56);
+    /// # Ok(()) }
+    /// ```
     #[cfg(ossl111)]
     pub fn generate_x448() -> Result<PKey<Private>, ErrorStack> {
         PKey::generate_eddsa(Id::X448)
     }
 
-    /// Generates a new private Ed25519 key
+    /// Generates a new private Ed25519 key.
+    ///
+    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// use openssl::pkey::{PKey, Id};
+    /// use openssl::sign::Signer;
+    ///
+    /// let key = PKey::generate_ed25519()?;
+    /// let public_key = key.raw_public_key()?;
+    ///
+    /// let mut signer = Signer::new_without_digest(&key)?;
+    /// let digest = // ...
+    /// # &vec![0; 32];
+    /// let signature = signer.sign_oneshot_to_vec(digest)?;
+    /// assert_eq!(signature.len(), 64);
+    /// # Ok(()) }
+    /// ```
     #[cfg(any(boringssl, ossl111))]
     pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
         PKey::generate_eddsa(Id::ED25519)
     }
 
-    /// Generates a new private Ed448 key
+    /// Generates a new private Ed448 key.
+    ///
+    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// use openssl::pkey::{PKey, Id};
+    /// use openssl::sign::Signer;
+    ///
+    /// let key = PKey::generate_ed448()?;
+    /// let public_key = key.raw_public_key()?;
+    ///
+    /// let mut signer = Signer::new_without_digest(&key)?;
+    /// let digest = // ...
+    /// # &vec![0; 32];
+    /// let signature = signer.sign_oneshot_to_vec(digest)?;
+    /// assert_eq!(signature.len(), 114);
+    /// # Ok(()) }
+    /// ```
     #[cfg(ossl111)]
     pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> {
         PKey::generate_eddsa(Id::ED448)
@@ -512,6 +596,8 @@
     #[corresponds(EVP_EC_gen)]
     #[cfg(ossl300)]
     pub fn ec_gen(curve: &str) -> Result<PKey<Private>, ErrorStack> {
+        ffi::init();
+
         let curve = CString::new(curve).unwrap();
         unsafe {
             let ptr = cvt_p(ffi::EVP_EC_gen(curve.as_ptr()))?;
@@ -767,6 +853,7 @@
 mod tests {
     use std::convert::TryInto;
 
+    #[cfg(not(boringssl))]
     use crate::dh::Dh;
     use crate::dsa::Dsa;
     use crate::ec::EcKey;
diff --git a/openssl/src/pkey_ctx.rs b/src/pkey_ctx.rs
similarity index 96%
rename from openssl/src/pkey_ctx.rs
rename to src/pkey_ctx.rs
index a1d8a22..f79372f 100644
--- a/openssl/src/pkey_ctx.rs
+++ b/src/pkey_ctx.rs
@@ -19,20 +19,25 @@
 //! let mut ciphertext = vec![];
 //! ctx.encrypt_to_vec(data, &mut ciphertext).unwrap();
 //! ```
-//!
-//! Generate a CMAC key
-//!
-//! ```
-//! use openssl::pkey_ctx::PkeyCtx;
-//! use openssl::pkey::Id;
-//! use openssl::cipher::Cipher;
-//!
-//! let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap();
-//! ctx.keygen_init().unwrap();
-//! ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap();
-//! ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap();
-//! let cmac_key = ctx.keygen().unwrap();
-//! ```
+
+#![cfg_attr(
+    not(boringssl),
+    doc = r#"\
+Generate a CMAC key
+
+```
+use openssl::pkey_ctx::PkeyCtx;
+use openssl::pkey::Id;
+use openssl::cipher::Cipher;
+
+let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap();
+ctx.keygen_init().unwrap();
+ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap();
+ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap();
+let cmac_key = ctx.keygen().unwrap();
+```"#
+)]
+
 //!
 //! Sign and verify data with RSA
 //!
@@ -59,15 +64,15 @@
 //! let valid = ctx.verify(text, &signature).unwrap();
 //! assert!(valid);
 //! ```
+#[cfg(not(boringssl))]
 use crate::cipher::CipherRef;
 use crate::error::ErrorStack;
 use crate::md::MdRef;
 use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private};
 use crate::rsa::Padding;
-#[cfg(any(boringssl, ossl102, libressl310))]
-use crate::util;
 use crate::{cvt, cvt_n, cvt_p};
 use foreign_types::{ForeignType, ForeignTypeRef};
+#[cfg(not(boringssl))]
 use libc::c_int;
 use openssl_macros::corresponds;
 use std::convert::TryFrom;
@@ -398,15 +403,20 @@
     ///
     /// This is only useful for RSA keys.
     #[corresponds(EVP_PKEY_CTX_set0_rsa_oaep_label)]
-    #[cfg(any(ossl102, libressl310))]
+    #[cfg(any(ossl102, libressl310, boringssl))]
     pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> {
-        let len = c_int::try_from(label.len()).unwrap();
+        use crate::LenType;
+        let len = LenType::try_from(label.len()).unwrap();
 
         unsafe {
             let p = ffi::OPENSSL_malloc(label.len() as _);
             ptr::copy_nonoverlapping(label.as_ptr(), p as *mut _, label.len());
 
-            let r = cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label(self.as_ptr(), p, len));
+            let r = cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label(
+                self.as_ptr(),
+                p as *mut _,
+                len,
+            ));
             if r.is_err() {
                 ffi::OPENSSL_free(p);
             }
@@ -591,6 +601,7 @@
 #[cfg(test)]
 mod test {
     use super::*;
+    #[cfg(not(boringssl))]
     use crate::cipher::Cipher;
     use crate::ec::{EcGroup, EcKey};
     #[cfg(any(ossl102, libressl310))]
diff --git a/openssl/src/provider.rs b/src/provider.rs
similarity index 100%
rename from openssl/src/provider.rs
rename to src/provider.rs
diff --git a/openssl/src/rand.rs b/src/rand.rs
similarity index 80%
rename from openssl/src/rand.rs
rename to src/rand.rs
index ff1dd44..8317951 100644
--- a/openssl/src/rand.rs
+++ b/src/rand.rs
@@ -10,17 +10,12 @@
 //! let mut buf = [0; 256];
 //! rand_bytes(&mut buf).unwrap();
 //! ```
-use libc::{c_int, size_t};
+use libc::c_int;
 
-use crate::cvt;
 use crate::error::ErrorStack;
+use crate::{cvt, LenType};
 use openssl_macros::corresponds;
 
-#[cfg(not(boringssl))]
-type RandType = c_int;
-#[cfg(boringssl)]
-type RandType = size_t;
-
 /// Fill buffer with cryptographically strong pseudo-random bytes.
 ///
 /// # Examples
@@ -38,7 +33,7 @@
     unsafe {
         ffi::init();
         assert!(buf.len() <= c_int::max_value() as usize);
-        cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as RandType)).map(|_| ())
+        cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as LenType)).map(|_| ())
     }
 }
 
@@ -49,7 +44,7 @@
 #[cfg(ossl111)]
 pub fn keep_random_devices_open(keep: bool) {
     unsafe {
-        ffi::RAND_keep_random_devices_open(keep as RandType);
+        ffi::RAND_keep_random_devices_open(keep as LenType);
     }
 }
 
diff --git a/openssl/src/rsa.rs b/src/rsa.rs
similarity index 96%
rename from openssl/src/rsa.rs
rename to src/rsa.rs
index 0bb9e71..b5d0967 100644
--- a/openssl/src/rsa.rs
+++ b/src/rsa.rs
@@ -25,7 +25,7 @@
 //! ```
 use cfg_if::cfg_if;
 use foreign_types::{ForeignType, ForeignTypeRef};
-use libc::{c_int, size_t};
+use libc::c_int;
 use std::fmt;
 use std::mem;
 use std::ptr;
@@ -34,14 +34,9 @@
 use crate::error::ErrorStack;
 use crate::pkey::{HasPrivate, HasPublic, Private, Public};
 use crate::util::ForeignTypeRefExt;
-use crate::{cvt, cvt_n, cvt_p};
+use crate::{cvt, cvt_n, cvt_p, LenType};
 use openssl_macros::corresponds;
 
-#[cfg(boringssl)]
-type BitType = size_t;
-#[cfg(not(boringssl))]
-type BitType = c_int;
-
 /// Type of encryption padding to use.
 ///
 /// Random length padding is primarily used to prevent attackers from
@@ -139,7 +134,7 @@
 
         unsafe {
             let len = cvt_n(ffi::RSA_private_decrypt(
-                from.len() as BitType,
+                from.len() as LenType,
                 from.as_ptr(),
                 to.as_mut_ptr(),
                 self.as_ptr(),
@@ -167,7 +162,7 @@
 
         unsafe {
             let len = cvt_n(ffi::RSA_private_encrypt(
-                from.len() as BitType,
+                from.len() as LenType,
                 from.as_ptr(),
                 to.as_mut_ptr(),
                 self.as_ptr(),
@@ -310,7 +305,7 @@
 
         unsafe {
             let len = cvt_n(ffi::RSA_public_decrypt(
-                from.len() as BitType,
+                from.len() as LenType,
                 from.as_ptr(),
                 to.as_mut_ptr(),
                 self.as_ptr(),
@@ -337,7 +332,7 @@
 
         unsafe {
             let len = cvt_n(ffi::RSA_public_encrypt(
-                from.len() as BitType,
+                from.len() as LenType,
                 from.as_ptr(),
                 to.as_mut_ptr(),
                 self.as_ptr(),
@@ -495,8 +490,18 @@
 impl Rsa<Private> {
     /// Creates a new RSA key with private components (public components are assumed).
     ///
-    /// This a convenience method over
-    /// `Rsa::build(n, e, d)?.set_factors(p, q)?.set_crt_params(dmp1, dmq1, iqmp)?.build()`
+    /// This a convenience method over:
+    /// ```
+    /// # use openssl::rsa::RsaPrivateKeyBuilder;
+    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// # let bn = || openssl::bn::BigNum::new().unwrap();
+    /// # let (n, e, d, p, q, dmp1, dmq1, iqmp) = (bn(), bn(), bn(), bn(), bn(), bn(), bn(), bn());
+    /// RsaPrivateKeyBuilder::new(n, e, d)?
+    ///     .set_factors(p, q)?
+    ///     .set_crt_params(dmp1, dmq1, iqmp)?
+    ///     .build();
+    /// # Ok(()) }
+    /// ```
     #[allow(clippy::too_many_arguments, clippy::many_single_char_names)]
     pub fn from_private_components(
         n: BigNum,
diff --git a/openssl/src/sha.rs b/src/sha.rs
similarity index 100%
rename from openssl/src/sha.rs
rename to src/sha.rs
diff --git a/openssl/src/sign.rs b/src/sign.rs
similarity index 97%
rename from openssl/src/sign.rs
rename to src/sign.rs
index aecbaec..4de8ad0 100644
--- a/openssl/src/sign.rs
+++ b/src/sign.rs
@@ -34,33 +34,39 @@
 //! verifier.update(data2).unwrap();
 //! assert!(verifier.verify(&signature).unwrap());
 //! ```
-//!
-//! Compute an HMAC:
-//!
-//! ```rust
-//! use openssl::hash::MessageDigest;
-//! use openssl::memcmp;
-//! use openssl::pkey::PKey;
-//! use openssl::sign::Signer;
-//!
-//! // Create a PKey
-//! let key = PKey::hmac(b"my secret").unwrap();
-//!
-//! let data = b"hello, world!";
-//! let data2 = b"hola, mundo!";
-//!
-//! // Compute the HMAC
-//! let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap();
-//! signer.update(data).unwrap();
-//! signer.update(data2).unwrap();
-//! let hmac = signer.sign_to_vec().unwrap();
-//!
-//! // `Verifier` cannot be used with HMACs; use the `memcmp::eq` function instead
-//! //
-//! // Do not simply check for equality with `==`!
-//! # let target = hmac.clone();
-//! assert!(memcmp::eq(&hmac, &target));
-//! ```
+
+#![cfg_attr(
+    not(boringssl),
+    doc = r#"\
+
+Compute an HMAC:
+
+```rust
+use openssl::hash::MessageDigest;
+use openssl::memcmp;
+use openssl::pkey::PKey;
+use openssl::sign::Signer;
+
+// Create a PKey
+let key = PKey::hmac(b"my secret").unwrap();
+
+let data = b"hello, world!";
+let data2 = b"hola, mundo!";
+
+// Compute the HMAC
+let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap();
+signer.update(data).unwrap();
+signer.update(data2).unwrap();
+let hmac = signer.sign_to_vec().unwrap();
+
+// `Verifier` cannot be used with HMACs; use the `memcmp::eq` function instead
+//
+// Do not simply check for equality with `==`!
+# let target = hmac.clone();
+assert!(memcmp::eq(&hmac, &target));
+```"#
+)]
+
 use cfg_if::cfg_if;
 use foreign_types::ForeignTypeRef;
 use libc::c_int;
@@ -637,6 +643,7 @@
 #[cfg(test)]
 mod test {
     use hex::{self, FromHex};
+    #[cfg(not(boringssl))]
     use std::iter;
 
     use crate::ec::{EcGroup, EcKey};
diff --git a/openssl/src/srtp.rs b/src/srtp.rs
similarity index 100%
rename from openssl/src/srtp.rs
rename to src/srtp.rs
diff --git a/openssl/src/ssl/bio.rs b/src/ssl/bio.rs
similarity index 98%
rename from openssl/src/ssl/bio.rs
rename to src/ssl/bio.rs
index 3ace35e..36cea23 100644
--- a/openssl/src/ssl/bio.rs
+++ b/src/ssl/bio.rs
@@ -183,7 +183,7 @@
 
     let data = BIO_get_data(bio);
     assert!(!data.is_null());
-    Box::<StreamState<S>>::from_raw(data as *mut _);
+    let _ = Box::<StreamState<S>>::from_raw(data as *mut _);
     BIO_set_data(bio, ptr::null_mut());
     BIO_set_init(bio, 0);
     1
@@ -257,7 +257,7 @@
         impl Drop for BIO_METHOD {
             fn drop(&mut self) {
                 unsafe {
-                    Box::<ffi::BIO_METHOD>::from_raw(self.0);
+                    let _ = Box::<ffi::BIO_METHOD>::from_raw(self.0);
                 }
             }
         }
diff --git a/openssl/src/ssl/callbacks.rs b/src/ssl/callbacks.rs
similarity index 99%
rename from openssl/src/ssl/callbacks.rs
rename to src/ssl/callbacks.rs
index e4db9dc..45760dc 100644
--- a/openssl/src/ssl/callbacks.rs
+++ b/src/ssl/callbacks.rs
@@ -518,6 +518,7 @@
     }
 }
 
+#[cfg(not(boringssl))]
 cfg_if! {
     if #[cfg(any(ossl110, libressl280))] {
         type CookiePtr = *const c_uchar;
@@ -526,6 +527,7 @@
     }
 }
 
+#[cfg(not(boringssl))]
 pub extern "C" fn raw_cookie_verify<F>(
     ssl: *mut ffi::SSL,
     cookie: CookiePtr,
diff --git a/openssl/src/ssl/connector.rs b/src/ssl/connector.rs
similarity index 98%
rename from openssl/src/ssl/connector.rs
rename to src/ssl/connector.rs
index 991d3e2..39f729d 100644
--- a/openssl/src/ssl/connector.rs
+++ b/src/ssl/connector.rs
@@ -4,6 +4,8 @@
 
 use crate::dh::Dh;
 use crate::error::ErrorStack;
+#[cfg(any(ossl111, libressl340))]
+use crate::ssl::SslVersion;
 use crate::ssl::{
     HandshakeError, Ssl, SslContext, SslContextBuilder, SslContextRef, SslMethod, SslMode,
     SslOptions, SslRef, SslStream, SslVerifyMode,
@@ -105,7 +107,7 @@
 
     /// Returns a shared reference to the inner raw `SslContext`.
     pub fn context(&self) -> &SslContextRef {
-        &*self.0
+        &self.0
     }
 }
 
@@ -239,7 +241,7 @@
              ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
              DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
         )?;
-        #[cfg(ossl111)]
+        #[cfg(any(ossl111, libressl340))]
         ctx.set_ciphersuites(
             "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256",
         )?;
@@ -251,13 +253,13 @@
     /// This corresponds to the modern configuration of version 5 of Mozilla's server side TLS recommendations.
     /// See its [documentation][docs] for more details on specifics.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     ///
     /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn mozilla_modern_v5(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
         let mut ctx = ctx(method)?;
-        ctx.set_options(SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_3);
+        ctx.set_min_proto_version(Some(SslVersion::TLS1_3))?;
         ctx.set_ciphersuites(
             "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256",
         )?;
@@ -275,7 +277,7 @@
     pub fn mozilla_intermediate(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
         let mut ctx = ctx(method)?;
         ctx.set_options(SslOptions::CIPHER_SERVER_PREFERENCE);
-        #[cfg(ossl111)]
+        #[cfg(any(ossl111, libressl340))]
         ctx.set_options(SslOptions::NO_TLSV1_3);
         let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?;
         ctx.set_tmp_dh(&dh)?;
@@ -305,7 +307,7 @@
         ctx.set_options(
             SslOptions::CIPHER_SERVER_PREFERENCE | SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1,
         );
-        #[cfg(ossl111)]
+        #[cfg(any(ossl111, libressl340))]
         ctx.set_options(SslOptions::NO_TLSV1_3);
         setup_curves(&mut ctx)?;
         ctx.set_cipher_list(
@@ -332,7 +334,7 @@
 
     /// Returns a shared reference to the inner raw `SslContext`.
     pub fn context(&self) -> &SslContextRef {
-        &*self.0
+        &self.0
     }
 }
 
diff --git a/openssl/src/ssl/error.rs b/src/ssl/error.rs
similarity index 100%
rename from openssl/src/ssl/error.rs
rename to src/ssl/error.rs
diff --git a/openssl/src/ssl/mod.rs b/src/ssl/mod.rs
similarity index 95%
rename from openssl/src/ssl/mod.rs
rename to src/ssl/mod.rs
index 8d01db0..4f349a4 100644
--- a/openssl/src/ssl/mod.rs
+++ b/src/ssl/mod.rs
@@ -57,27 +57,6 @@
 //!     }
 //! }
 //! ```
-// use bitflags::bitflags;
-// use cfg_if::cfg_if;
-// use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
-use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void};
-// use once_cell::sync::{Lazy, OnceCell};
-// use std::any::TypeId;
-// use std::cmp;
-// use std::collections::HashMap;
-// use std::ffi::{CStr, CString};
-// use std::fmt;
-// use std::io;
-// use std::io::prelude::*;
-// use std::marker::PhantomData;
-// use std::mem::{self, ManuallyDrop};
-// use std::ops::{Deref, DerefMut};
-// use std::panic::resume_unwind;
-// use std::path::Path;
-// use std::ptr;
-// use std::slice;
-// use std::str;
-// use std::sync::{Arc, Mutex};
 use crate::dh::{Dh, DhRef};
 #[cfg(all(ossl101, not(ossl110)))]
 use crate::ec::EcKey;
@@ -86,7 +65,7 @@
 use crate::ex_data::Index;
 #[cfg(ossl111)]
 use crate::hash::MessageDigest;
-#[cfg(ossl110)]
+#[cfg(any(ossl110, libressl270))]
 use crate::nid::Nid;
 use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
 use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
@@ -103,6 +82,7 @@
 use bitflags::bitflags;
 use cfg_if::cfg_if;
 use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
+use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_void};
 use once_cell::sync::{Lazy, OnceCell};
 use openssl_macros::corresponds;
 use std::any::TypeId;
@@ -155,7 +135,7 @@
     if #[cfg(ossl300)] {
         type SslOptionsRepr = u64;
     } else if #[cfg(boringssl)] {
-        type SslOptionsRepr = i32;
+        type SslOptionsRepr = u32;
     } else {
         type SslOptionsRepr = libc::c_ulong;
     }
@@ -165,16 +145,16 @@
     /// Options controlling the behavior of an `SslContext`.
     pub struct SslOptions: SslOptionsRepr {
         /// Disables a countermeasure against an SSLv3/TLSv1.0 vulnerability affecting CBC ciphers.
-        const DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+        const DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS as SslOptionsRepr;
 
         /// A "reasonable default" set of options which enables compatibility flags.
         #[cfg(not(boringssl))]
-        const ALL = ffi::SSL_OP_ALL;
+        const ALL = ffi::SSL_OP_ALL as SslOptionsRepr;
 
         /// Do not query the MTU.
         ///
         /// Only affects DTLS connections.
-        const NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU;
+        const NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU as SslOptionsRepr;
 
         /// Enables Cookie Exchange as described in [RFC 4347 Section 4.2.1].
         ///
@@ -182,75 +162,75 @@
         ///
         /// [RFC 4347 Section 4.2.1]: https://tools.ietf.org/html/rfc4347#section-4.2.1
         #[cfg(not(boringssl))]
-        const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE;
+        const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE as SslOptionsRepr;
 
         /// Disables the use of session tickets for session resumption.
-        const NO_TICKET = ffi::SSL_OP_NO_TICKET;
+        const NO_TICKET = ffi::SSL_OP_NO_TICKET as SslOptionsRepr;
 
         /// Always start a new session when performing a renegotiation on the server side.
         #[cfg(not(boringssl))]
         const NO_SESSION_RESUMPTION_ON_RENEGOTIATION =
-            ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
+            ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION as SslOptionsRepr;
 
         /// Disables the use of TLS compression.
         #[cfg(not(boringssl))]
-        const NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION;
+        const NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION as SslOptionsRepr;
 
         /// Allow legacy insecure renegotiation with servers or clients that do not support secure
         /// renegotiation.
         const ALLOW_UNSAFE_LEGACY_RENEGOTIATION =
-            ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+            ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION as SslOptionsRepr;
 
         /// Creates a new key for each session when using ECDHE.
         ///
         /// This is always enabled in OpenSSL 1.1.0.
-        const SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE;
+        const SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE as SslOptionsRepr;
 
         /// Creates a new key for each session when using DHE.
         ///
         /// This is always enabled in OpenSSL 1.1.0.
-        const SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE;
+        const SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE as SslOptionsRepr;
 
         /// Use the server's preferences rather than the client's when selecting a cipher.
         ///
         /// This has no effect on the client side.
-        const CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE;
+        const CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE as SslOptionsRepr;
 
         /// Disables version rollback attach detection.
-        const TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG;
+        const TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG as SslOptionsRepr;
 
         /// Disables the use of SSLv2.
-        const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2;
+        const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2 as SslOptionsRepr;
 
         /// Disables the use of SSLv3.
-        const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3;
+        const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3 as SslOptionsRepr;
 
         /// Disables the use of TLSv1.0.
-        const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1;
+        const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1 as SslOptionsRepr;
 
         /// Disables the use of TLSv1.1.
-        const NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1;
+        const NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1 as SslOptionsRepr;
 
         /// Disables the use of TLSv1.2.
-        const NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2;
+        const NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2 as SslOptionsRepr;
 
         /// Disables the use of TLSv1.3.
         ///
-        /// Requires OpenSSL 1.1.1 or newer.
-        #[cfg(ossl111)]
-        const NO_TLSV1_3 = ffi::SSL_OP_NO_TLSv1_3;
+        /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
+        #[cfg(any(boringssl, ossl111, libressl340))]
+        const NO_TLSV1_3 = ffi::SSL_OP_NO_TLSv1_3 as SslOptionsRepr;
 
         /// Disables the use of DTLSv1.0
         ///
         /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer.
-        #[cfg(any(ossl102, ossl110, libressl332))]
-        const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1;
+        #[cfg(any(boringssl, ossl102, ossl110, libressl332))]
+        const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1 as SslOptionsRepr;
 
         /// Disables the use of DTLSv1.2.
         ///
         /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer.
-        #[cfg(any(ossl102, ossl110, libressl332))]
-        const NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2;
+        #[cfg(any(boringssl, ossl102, ossl110, libressl332))]
+        const NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2 as SslOptionsRepr;
 
         /// Disables the use of all (D)TLS protocol versions.
         ///
@@ -268,20 +248,34 @@
         /// let options = SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_2;
         /// ```
         #[cfg(any(ossl102, ossl110))]
-        const NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK;
+        const NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK as SslOptionsRepr;
 
         /// Disallow all renegotiation in TLSv1.2 and earlier.
         ///
         /// Requires OpenSSL 1.1.0h or newer.
-        #[cfg(ossl110h)]
-        const NO_RENEGOTIATION = ffi::SSL_OP_NO_RENEGOTIATION;
+        #[cfg(any(boringssl, ossl110h))]
+        const NO_RENEGOTIATION = ffi::SSL_OP_NO_RENEGOTIATION as SslOptionsRepr;
 
         /// Enable TLSv1.3 Compatibility mode.
         ///
         /// Requires OpenSSL 1.1.1 or newer. This is on by default in 1.1.1, but a future version
         /// may have this disabled by default.
         #[cfg(ossl111)]
-        const ENABLE_MIDDLEBOX_COMPAT = ffi::SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+        const ENABLE_MIDDLEBOX_COMPAT = ffi::SSL_OP_ENABLE_MIDDLEBOX_COMPAT as SslOptionsRepr;
+
+        /// Prioritize ChaCha ciphers when preferred by clients.
+        ///
+        /// Temporarily reprioritize ChaCha20-Poly1305 ciphers to the top of the server cipher list
+        /// if a ChaCha20-Poly1305 cipher is at the top of the client cipher list. This helps those
+        /// clients (e.g. mobile) use ChaCha20-Poly1305 if that cipher is anywhere in the server
+        /// cipher list; but still allows other clients to use AES and other ciphers.
+        ///
+        /// Requires enable [`SslOptions::CIPHER_SERVER_PREFERENCE`].
+        /// Requires OpenSSL 1.1.1 or newer.
+        ///
+        /// [`SslOptions::CIPHER_SERVER_PREFERENCE`]: struct.SslOptions.html#associatedconstant.CIPHER_SERVER_PREFERENCE
+        #[cfg(ossl111)]
+        const PRIORITIZE_CHACHA = ffi::SSL_OP_PRIORITIZE_CHACHA as SslOptionsRepr;
     }
 }
 
@@ -564,7 +558,7 @@
     _argp: *mut c_void,
 ) {
     if !ptr.is_null() {
-        Box::<T>::from_raw(ptr as *mut T);
+        let _ = Box::<T>::from_raw(ptr as *mut T);
     }
 }
 
@@ -647,27 +641,21 @@
 
     /// TLSv1.3
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
-    #[cfg(ossl111)]
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
+    #[cfg(any(ossl111, libressl340))]
     pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION);
 }
 
 cfg_if! {
     if #[cfg(boringssl)] {
-        type SslTy = i32;
-        type SslModeTy = i32;
         type SslCacheTy = i64;
-        type SslCacheSize = c_ulong;
+        type SslCacheSize = libc::c_ulong;
         type MtuTy = u32;
-        type BitTy = u32;
         type SizeTy = usize;
     } else {
-        type SslTy = u64;
-        type SslModeTy = i64;
         type SslCacheTy = i64;
         type SslCacheSize = c_long;
-        type MtuTy = i64;
-        type BitTy = u64;
+        type MtuTy = c_long;
         type SizeTy = u32;
     }
 }
@@ -778,13 +766,12 @@
             // still stored in ex data to manage the lifetime.
             let arg = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback);
             ffi::SSL_CTX_set_tlsext_servername_arg(self.as_ptr(), arg);
-
-            let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>;
+            #[cfg(boringssl)]
+            ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(raw_sni::<F>));
             #[cfg(not(boringssl))]
-            let f: extern "C" fn() = mem::transmute(f);
-            ffi::SSL_CTX_set_tlsext_servername_callback(
+            ffi::SSL_CTX_set_tlsext_servername_callback__fixed_rust(
                 self.as_ptr(),
-                Some(f),
+                Some(raw_sni::<F>),
             );
         }
     }
@@ -840,7 +827,7 @@
     #[corresponds(SSL_CTX_set_mode)]
     pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
         unsafe {
-            let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits() as MtuTy) as SslModeTy;
+            let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits() as MtuTy) as SslBitType;
             SslMode { bits }
         }
     }
@@ -939,7 +926,6 @@
     /// Add the provided CA certificate to the list sent by the server to the client when
     /// requesting client-side TLS authentication.
     #[corresponds(SSL_CTX_add_client_CA)]
-    #[cfg(not(libressl))]
     pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> {
         unsafe { cvt(ffi::SSL_CTX_add_client_CA(self.as_ptr(), cacert.as_ptr())).map(|_| ()) }
     }
@@ -1081,9 +1067,9 @@
     /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of
     /// preference.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_CTX_set_ciphersuites)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
         let cipher_list = CString::new(cipher_list).unwrap();
         unsafe {
@@ -1113,14 +1099,14 @@
     #[corresponds(SSL_CTX_set_options)]
     pub fn set_options(&mut self, option: SslOptions) -> SslOptions {
         let bits =
-            unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits() as BitTy) } as SslTy;
+            unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) } as SslOptionsRepr;
         SslOptions { bits }
     }
 
     /// Returns the options used by the context.
     #[corresponds(SSL_CTX_get_options)]
     pub fn options(&self) -> SslOptions {
-        let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) } as SslTy;
+        let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) } as SslOptionsRepr;
         SslOptions { bits }
     }
 
@@ -1128,7 +1114,7 @@
     #[corresponds(SSL_CTX_clear_options)]
     pub fn clear_options(&mut self, option: SslOptions) -> SslOptions {
         let bits =
-            unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits() as BitTy) } as SslTy;
+            unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) } as SslOptionsRepr;
         SslOptions { bits }
     }
 
@@ -1632,9 +1618,9 @@
     ///
     /// Defaults to 0.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_CTX_set_max_early_data)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
         if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 {
             Ok(())
@@ -1691,9 +1677,9 @@
 
     /// Sets the context's supported elliptic curve groups.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 2.5.1 or newer.
     #[corresponds(SSL_CTX_set1_groups_list)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl251))]
     pub fn set_groups_list(&mut self, groups: &str) -> Result<(), ErrorStack> {
         let groups = CString::new(groups).unwrap();
         unsafe {
@@ -1791,9 +1777,9 @@
 impl SslContextRef {
     /// Returns the certificate associated with this `SslContext`, if present.
     ///
-    /// Requires OpenSSL 1.0.2 or newer.
+    /// Requires OpenSSL 1.0.2 or LibreSSL 2.7.0 or newer.
     #[corresponds(SSL_CTX_get0_certificate)]
-    #[cfg(any(ossl102, ossl110))]
+    #[cfg(any(ossl102, libressl270))]
     pub fn certificate(&self) -> Option<&X509Ref> {
         unsafe {
             let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr());
@@ -1803,9 +1789,9 @@
 
     /// Returns the private key associated with this `SslContext`, if present.
     ///
-    /// Requires OpenSSL 1.0.2 or newer.
+    /// Requires OpenSSL 1.0.2 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_CTX_get0_privatekey)]
-    #[cfg(any(ossl102, ossl110))]
+    #[cfg(any(ossl102, libressl340))]
     pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
         unsafe {
             let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr());
@@ -1844,9 +1830,9 @@
 
     /// Gets the maximum amount of early data that will be accepted on incoming connections.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_CTX_get_max_early_data)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn max_early_data(&self) -> u32 {
         unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) }
     }
@@ -2026,9 +2012,9 @@
 
     /// Returns the NID corresponding to the cipher.
     ///
-    /// Requires OpenSSL 1.1.0 or newer.
+    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
     #[corresponds(SSL_CIPHER_get_cipher_nid)]
-    #[cfg(any(ossl110))]
+    #[cfg(any(ossl110, libressl270))]
     pub fn cipher_nid(&self) -> Option<Nid> {
         let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) };
         if n == 0 {
@@ -2108,9 +2094,9 @@
 
     /// Gets the maximum amount of early data that can be sent on this session.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_SESSION_get_max_early_data)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn max_early_data(&self) -> u32 {
         unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) }
     }
@@ -2133,9 +2119,9 @@
 
     /// Returns the session's TLS protocol version.
     ///
-    /// Requires OpenSSL 1.1.0 or newer.
+    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
     #[corresponds(SSL_SESSION_get_protocol_version)]
-    #[cfg(ossl110)]
+    #[cfg(any(ossl110, libressl270))]
     pub fn protocol_version(&self) -> SslVersion {
         unsafe {
             let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr());
@@ -2363,7 +2349,7 @@
             #[cfg(boringssl)]
             ffi::SSL_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh_ssl::<F>));
             #[cfg(not(boringssl))]
-            ffi::SSL_set_tmp_dh_callback(self.as_ptr(), raw_tmp_dh_ssl::<F>);
+            ffi::SSL_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh_ssl::<F>));
         }
     }
 
@@ -2394,11 +2380,11 @@
 
     /// Like [`SslContextBuilder::set_ecdh_auto`].
     ///
-    /// Requires OpenSSL 1.0.2.
+    /// Requires OpenSSL 1.0.2 or LibreSSL.
     ///
     /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
     #[corresponds(SSL_set_ecdh_auto)]
-    #[cfg(all(ossl102, not(ossl110)))]
+    #[cfg(any(all(ossl102, not(ossl110)), libressl))]
     pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
         unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
     }
@@ -2726,9 +2712,9 @@
     /// Returns the number of bytes copied, or if the buffer is empty, the size of the `client_random`
     /// value.
     ///
-    /// Requires OpenSSL 1.1.0 or newer.
+    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
     #[corresponds(SSL_get_client_random)]
-    #[cfg(any(ossl110))]
+    #[cfg(any(ossl110, libressl270))]
     pub fn client_random(&self, buf: &mut [u8]) -> usize {
         unsafe {
             ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
@@ -2740,9 +2726,9 @@
     /// Returns the number of bytes copied, or if the buffer is empty, the size of the `server_random`
     /// value.
     ///
-    /// Requires OpenSSL 1.1.0 or newer.
+    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
     #[corresponds(SSL_get_server_random)]
-    #[cfg(any(ossl110))]
+    #[cfg(any(ossl110, libressl270))]
     pub fn server_random(&self, buf: &mut [u8]) -> usize {
         unsafe {
             ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
@@ -2874,7 +2860,7 @@
             cvt(ffi::SSL_set_tlsext_status_ocsp_resp(
                 self.as_ptr(),
                 p as *mut c_uchar,
-                response.len() as i64,
+                response.len() as c_long,
             ) as c_int)
             .map(|_| ())
         }
@@ -2930,9 +2916,9 @@
 
     /// Sets the maximum amount of early data that will be accepted on this connection.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_set_max_early_data)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
         if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 {
             Ok(())
@@ -2943,9 +2929,9 @@
 
     /// Gets the maximum amount of early data that can be sent on this connection.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_get_max_early_data)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn max_early_data(&self) -> u32 {
         unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) }
     }
@@ -3088,6 +3074,36 @@
     pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> {
         unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as MtuTy) as c_int).map(|_| ()) }
     }
+
+    /// Returns the PSK identity hint used during connection setup.
+    ///
+    /// May return `None` if no PSK identity hint was used during the connection setup.
+    #[corresponds(SSL_get_psk_identity_hint)]
+    #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
+    pub fn psk_identity_hint(&self) -> Option<&[u8]> {
+        unsafe {
+            let ptr = ffi::SSL_get_psk_identity_hint(self.as_ptr());
+            if ptr.is_null() {
+                None
+            } else {
+                Some(CStr::from_ptr(ptr).to_bytes())
+            }
+        }
+    }
+
+    /// Returns the PSK identity used during connection setup.
+    #[corresponds(SSL_get_psk_identity)]
+    #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
+    pub fn psk_identity(&self) -> Option<&[u8]> {
+        unsafe {
+            let ptr = ffi::SSL_get_psk_identity(self.as_ptr());
+            if ptr.is_null() {
+                None
+            } else {
+                Some(CStr::from_ptr(ptr).to_bytes())
+            }
+        }
+    }
 }
 
 /// An SSL stream midway through the handshake process.
@@ -3223,9 +3239,9 @@
     ///
     /// Returns `Ok(0)` if all early data has been read.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_read_early_data)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
         let mut read = 0;
         let ret = unsafe {
@@ -3249,9 +3265,9 @@
     /// Useful for reducing latency, but vulnerable to replay attacks. Call
     /// [`SslRef::set_connect_state`] first.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     #[corresponds(SSL_write_early_data)]
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
         let mut written = 0;
         let ret = unsafe {
@@ -3667,12 +3683,12 @@
     ///
     /// Returns `Ok(0)` if all early data has been read.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     ///
     /// This corresponds to [`SSL_read_early_data`].
     ///
     /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
         self.inner.read_early_data(buf)
     }
@@ -3682,12 +3698,12 @@
     /// Useful for reducing latency, but vulnerable to replay attacks. Call
     /// `set_connect_state` first.
     ///
-    /// Requires OpenSSL 1.1.1 or newer.
+    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
     ///
     /// This corresponds to [`SSL_write_early_data`].
     ///
     /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
         self.inner.write_early_data(buf)
     }
diff --git a/openssl/src/ssl/test/mod.rs b/src/ssl/test/mod.rs
similarity index 96%
rename from openssl/src/ssl/test/mod.rs
rename to src/ssl/test/mod.rs
index 0c65029..ab8d79a 100644
--- a/openssl/src/ssl/test/mod.rs
+++ b/src/ssl/test/mod.rs
@@ -204,7 +204,7 @@
             CALLED_BACK.store(true, Ordering::SeqCst);
             let cert = x509.current_cert().unwrap();
             let digest = cert.digest(MessageDigest::sha1()).unwrap();
-            assert_eq!(hex::encode(&digest), expected);
+            assert_eq!(hex::encode(digest), expected);
             true
         });
 
@@ -226,7 +226,7 @@
             CALLED_BACK.store(true, Ordering::SeqCst);
             let cert = x509.current_cert().unwrap();
             let digest = cert.digest(MessageDigest::sha1()).unwrap();
-            assert_eq!(hex::encode(&digest), expected);
+            assert_eq!(hex::encode(digest), expected);
             true
         });
 
@@ -319,9 +319,9 @@
         let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap();
         ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32")
             .unwrap();
-        ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM)
+        ctx.set_certificate_file(Path::new("test/cert.pem"), SslFiletype::PEM)
             .unwrap();
-        ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM)
+        ctx.set_private_key_file(Path::new("test/key.pem"), SslFiletype::PEM)
             .unwrap();
         let mut ssl = Ssl::new(&ctx.build()).unwrap();
         ssl.set_mtu(1500).unwrap();
@@ -375,9 +375,9 @@
     let guard = thread::spawn(move || {
         let stream = listener.accept().unwrap().0;
         let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap();
-        ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM)
+        ctx.set_certificate_file(Path::new("test/cert.pem"), SslFiletype::PEM)
             .unwrap();
-        ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM)
+        ctx.set_private_key_file(Path::new("test/key.pem"), SslFiletype::PEM)
             .unwrap();
         let mut ssl = Ssl::new(&ctx.build()).unwrap();
         ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32")
@@ -555,7 +555,7 @@
 }
 
 #[test]
-#[cfg_attr(libressl321, ignore)]
+#[cfg_attr(all(libressl321, not(libressl340)), ignore)]
 #[should_panic(expected = "blammo")]
 fn flush_panic() {
     struct ExplodingStream(TcpStream);
@@ -795,7 +795,7 @@
 }
 
 #[test]
-#[cfg(ossl111)]
+#[cfg(any(ossl111, libressl340))]
 fn connector_client_server_mozilla_modern_v5() {
     test_mozilla_server(SslAcceptor::mozilla_modern_v5);
 }
@@ -843,7 +843,7 @@
 }
 
 #[test]
-#[cfg_attr(any(libressl321, boringssl), ignore)]
+#[cfg_attr(any(all(libressl321, not(libressl340)), boringssl), ignore)]
 fn tmp_dh_callback() {
     static CALLED_BACK: AtomicBool = AtomicBool::new(false);
 
@@ -858,7 +858,7 @@
 
     let mut client = server.client();
     // TLS 1.3 has no DH suites, so make sure we don't pick that version
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     client.ctx().set_options(super::SslOptions::NO_TLSV1_3);
     client.ctx().set_cipher_list("EDH").unwrap();
     client.connect();
@@ -891,7 +891,7 @@
 }
 
 #[test]
-#[cfg_attr(any(libressl321, boringssl), ignore)]
+#[cfg_attr(any(all(libressl321, not(libressl340)), boringssl), ignore)]
 fn tmp_dh_callback_ssl() {
     static CALLED_BACK: AtomicBool = AtomicBool::new(false);
 
@@ -908,7 +908,7 @@
 
     let mut client = server.client();
     // TLS 1.3 has no DH suites, so make sure we don't pick that version
-    #[cfg(ossl111)]
+    #[cfg(any(ossl111, libressl340))]
     client.ctx().set_options(super::SslOptions::NO_TLSV1_3);
     client.ctx().set_cipher_list("EDH").unwrap();
     client.connect();
@@ -949,6 +949,7 @@
     assert!(ssl.session().is_none());
 }
 
+/// possible LibreSSL bug since 3.2.1
 #[test]
 #[cfg_attr(libressl321, ignore)]
 fn active_session() {
@@ -1006,6 +1007,7 @@
     assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst));
 }
 
+/// possible LibreSSL bug since 3.2.1
 #[test]
 #[cfg_attr(libressl321, ignore)]
 fn new_session_callback() {
@@ -1030,6 +1032,7 @@
     assert!(CALLED_BACK.load(Ordering::SeqCst));
 }
 
+/// possible LibreSSL bug since 3.2.1
 #[test]
 #[cfg_attr(libressl321, ignore)]
 fn new_session_callback_swapped_ctx() {
@@ -1070,9 +1073,9 @@
     let guard = thread::spawn(move || {
         let stream = listener.accept().unwrap().0;
         let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
-        ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM)
+        ctx.set_certificate_file(Path::new("test/cert.pem"), SslFiletype::PEM)
             .unwrap();
-        ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM)
+        ctx.set_private_key_file(Path::new("test/key.pem"), SslFiletype::PEM)
             .unwrap();
         let ssl = Ssl::new(&ctx.build()).unwrap();
         let mut stream = ssl.accept(stream).unwrap();
@@ -1268,10 +1271,10 @@
 
     let mut server_ctx = SslContext::builder(SslMethod::tls()).unwrap();
     server_ctx
-        .set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM)
+        .set_certificate_file(Path::new("test/cert.pem"), SslFiletype::PEM)
         .unwrap();
     server_ctx
-        .set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM)
+        .set_private_key_file(Path::new("test/key.pem"), SslFiletype::PEM)
         .unwrap();
     const COOKIE: &[u8] = b"chocolate chip";
     server_ctx.set_stateless_cookie_generate_cb(|_tls, buf| {
@@ -1317,9 +1320,7 @@
     let mut server = Server::builder();
     server.ctx().set_cipher_list(CIPHER).unwrap();
     server.ctx().set_psk_server_callback(|_, identity, psk| {
-        eprintln!("hello???!");
         assert!(identity.unwrap_or(&[]) == CLIENT_IDENT);
-        eprintln!("hello???!");
         psk[..PSK.len()].copy_from_slice(PSK);
         SERVER_CALLED.store(true, Ordering::SeqCst);
         Ok(PSK.len())
@@ -1329,13 +1330,12 @@
 
     let mut client = server.client();
     // This test relies on TLS 1.2 suites
-    #[cfg(ossl111)]
+    #[cfg(any(boringssl, ossl111))]
     client.ctx().set_options(super::SslOptions::NO_TLSV1_3);
     client.ctx().set_cipher_list(CIPHER).unwrap();
     client
         .ctx()
         .set_psk_client_callback(move |_, _, identity, psk| {
-            eprintln!("hello???! 2");
             identity[..CLIENT_IDENT.len()].copy_from_slice(CLIENT_IDENT);
             identity[CLIENT_IDENT.len()] = 0;
             psk[..PSK.len()].copy_from_slice(PSK);
diff --git a/openssl/src/ssl/test/server.rs b/src/ssl/test/server.rs
similarity index 100%
rename from openssl/src/ssl/test/server.rs
rename to src/ssl/test/server.rs
diff --git a/openssl/src/stack.rs b/src/stack.rs
similarity index 95%
rename from openssl/src/stack.rs
rename to src/stack.rs
index 70098df..416efd5 100644
--- a/openssl/src/stack.rs
+++ b/src/stack.rs
@@ -1,6 +1,6 @@
 use cfg_if::cfg_if;
 use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
-use libc::{c_int, size_t};
+use libc::c_int;
 use std::borrow::Borrow;
 use std::convert::AsRef;
 use std::fmt;
@@ -11,12 +11,7 @@
 
 use crate::error::ErrorStack;
 use crate::util::ForeignTypeExt;
-use crate::{cvt, cvt_p};
-
-#[cfg(not(boringssl))]
-type IdxType = c_int;
-#[cfg(boringssl)]
-type IdxType = size_t;
+use crate::{cvt, cvt_p, LenType};
 
 cfg_if! {
     if #[cfg(ossl110)] {
@@ -85,7 +80,7 @@
     fn into_iter(self) -> IntoIter<T> {
         let it = IntoIter {
             stack: self.0,
-            idxs: 0..self.len() as IdxType,
+            idxs: 0..self.len() as LenType,
         };
         mem::forget(self);
         it
@@ -94,13 +89,13 @@
 
 impl<T: Stackable> AsRef<StackRef<T>> for Stack<T> {
     fn as_ref(&self) -> &StackRef<T> {
-        &*self
+        self
     }
 }
 
 impl<T: Stackable> Borrow<StackRef<T>> for Stack<T> {
     fn borrow(&self) -> &StackRef<T> {
-        &*self
+        self
     }
 }
 
@@ -140,7 +135,7 @@
 
 pub struct IntoIter<T: Stackable> {
     stack: *mut T::StackType,
-    idxs: Range<IdxType>,
+    idxs: Range<LenType>,
 }
 
 impl<T: Stackable> Drop for IntoIter<T> {
@@ -209,13 +204,13 @@
     pub fn iter(&self) -> Iter<'_, T> {
         Iter {
             stack: self,
-            idxs: 0..self.len() as IdxType,
+            idxs: 0..self.len() as LenType,
         }
     }
 
     pub fn iter_mut(&mut self) -> IterMut<'_, T> {
         IterMut {
-            idxs: 0..self.len() as IdxType,
+            idxs: 0..self.len() as LenType,
             stack: self,
         }
     }
@@ -262,7 +257,7 @@
     }
 
     unsafe fn _get(&self, idx: usize) -> *mut T::CType {
-        OPENSSL_sk_value(self.as_stack(), idx as IdxType) as *mut _
+        OPENSSL_sk_value(self.as_stack(), idx as LenType) as *mut _
     }
 }
 
@@ -319,7 +314,7 @@
 /// An iterator over the stack's contents.
 pub struct Iter<'a, T: Stackable> {
     stack: &'a StackRef<T>,
-    idxs: Range<IdxType>,
+    idxs: Range<LenType>,
 }
 
 impl<'a, T: Stackable> Iterator for Iter<'a, T> {
@@ -353,7 +348,7 @@
 /// A mutable iterator over the stack's contents.
 pub struct IterMut<'a, T: Stackable> {
     stack: &'a mut StackRef<T>,
-    idxs: Range<IdxType>,
+    idxs: Range<LenType>,
 }
 
 impl<'a, T: Stackable> Iterator for IterMut<'a, T> {
diff --git a/openssl/src/string.rs b/src/string.rs
similarity index 98%
rename from openssl/src/string.rs
rename to src/string.rs
index 559218e..95494b5 100644
--- a/openssl/src/string.rs
+++ b/src/string.rs
@@ -34,7 +34,7 @@
 
 impl AsRef<str> for OpensslString {
     fn as_ref(&self) -> &str {
-        &**self
+        self
     }
 }
 
@@ -57,7 +57,7 @@
 
 impl AsRef<str> for OpensslStringRef {
     fn as_ref(&self) -> &str {
-        &*self
+        self
     }
 }
 
diff --git a/openssl/src/symm.rs b/src/symm.rs
similarity index 95%
rename from openssl/src/symm.rs
rename to src/symm.rs
index 9c9371e..beff5fc 100644
--- a/openssl/src/symm.rs
+++ b/src/symm.rs
@@ -51,11 +51,6 @@
 //! assert_eq!("Foo bar", output_string);
 //! println!("Decrypted: '{}'", output_string);
 //! ```
-
-use libc::{c_int, c_uint};
-use std::cmp;
-use std::ptr;
-
 use crate::cipher::CipherRef;
 use crate::cipher_ctx::{CipherCtx, CipherCtxRef};
 use crate::error::ErrorStack;
@@ -327,6 +322,31 @@
         unsafe { Cipher(ffi::EVP_seed_ofb()) }
     }
 
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_ecb() -> Cipher {
+        unsafe { Cipher(ffi::EVP_sm4_ecb()) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_cbc() -> Cipher {
+        unsafe { Cipher(ffi::EVP_sm4_cbc()) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_ctr() -> Cipher {
+        unsafe { Cipher(ffi::EVP_sm4_ctr()) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_cfb128() -> Cipher {
+        unsafe { Cipher(ffi::EVP_sm4_cfb128()) }
+    }
+
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    pub fn sm4_ofb() -> Cipher {
+        unsafe { Cipher(ffi::EVP_sm4_ofb()) }
+    }
+
     /// Creates a `Cipher` from a raw pointer to its OpenSSL type.
     ///
     /// # Safety
@@ -757,29 +777,24 @@
     Ok(out)
 }
 
-#[cfg(not(boringssl))]
-type CipherRet = c_int;
-#[cfg(boringssl)]
-type CipherRet = c_uint;
-
 cfg_if! {
     if #[cfg(any(boringssl, ossl110, libressl273))] {
         use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length};
     } else {
-        use libc::c_int;
+        use crate::LenType;
 
         #[allow(bad_style)]
-        pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> CipherRet {
+        pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> LenType {
             (*ptr).iv_len
         }
 
         #[allow(bad_style)]
-        pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> CipherRet {
+        pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> LenType {
             (*ptr).block_size
         }
 
         #[allow(bad_style)]
-        pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> CipherRet {
+        pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> LenType {
             (*ptr).key_len
         }
     }
@@ -909,6 +924,7 @@
         }
     }
 
+    #[cfg(not(boringssl))]
     fn cipher_test_nopad(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) {
         let pt = Vec::from_hex(pt).unwrap();
         let ct = Vec::from_hex(ct).unwrap();
@@ -1574,4 +1590,46 @@
 
         cipher_test(super::Cipher::seed_ofb(), pt, ct, key, iv);
     }
+
+    // GB/T 32907-2016
+    // http://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A
+    #[test]
+    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
+    fn test_sm4_ecb() {
+        use std::mem;
+
+        let key = vec![
+            0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
+            0x32, 0x10,
+        ];
+        let pt = vec![
+            0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
+            0x32, 0x10,
+        ];
+        let ct = vec![
+            0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e,
+            0x42, 0x46,
+        ];
+        let ct1 = vec![
+            0x59, 0x52, 0x98, 0xc7, 0xc6, 0xfd, 0x27, 0x1f, 0x04, 0x02, 0xf8, 0x04, 0xc3, 0x3d,
+            0x3f, 0x66,
+        ];
+
+        let block_size = Cipher::sm4_ecb().block_size();
+        let mut c = Crypter::new(Cipher::sm4_ecb(), Mode::Encrypt, &key, None).unwrap();
+        c.pad(false);
+
+        // 1 round
+        let mut r = vec![0; pt.len() + Cipher::sm4_ecb().block_size()];
+        let count = c.update(&pt, &mut r).unwrap();
+        assert_eq!(ct, &r[..count]);
+
+        // 1000000 rounds
+        let mut r1 = vec![0; pt.len() + Cipher::sm4_ecb().block_size()];
+        for _ in 0..999999 {
+            c.update(&r[..block_size], &mut r1).unwrap();
+            mem::swap(&mut r, &mut r1);
+        }
+        assert_eq!(ct1, &r[..count]);
+    }
 }
diff --git a/openssl/src/util.rs b/src/util.rs
similarity index 77%
rename from openssl/src/util.rs
rename to src/util.rs
index be04030..d852a4b 100644
--- a/openssl/src/util.rs
+++ b/src/util.rs
@@ -1,9 +1,6 @@
 use crate::error::ErrorStack;
 use foreign_types::{ForeignType, ForeignTypeRef};
-use std::convert::TryFrom;
 use libc::{c_char, c_int, c_void};
-use crate::{cvt, cvt_p};
-use cfg_if::cfg_if;
 use std::any::Any;
 use std::panic::{self, AssertUnwindSafe};
 use std::slice;
@@ -94,30 +91,3 @@
     }
 }
 impl<FT: ForeignTypeRef> ForeignTypeRefExt for FT {}
-
-#[track_caller]
-#[inline]
-pub fn crypto_malloc(len: usize) -> Result<*mut c_void, ErrorStack> {
-    // 1.0.2 uses c_int but 1.1.0+ uses size_t
-    let len = TryFrom::try_from(len).unwrap();
-
-    unsafe {
-        cvt_p(ffi::CRYPTO_malloc(
-            len,
-            concat!(file!(), "\0").as_ptr() as *const _,
-            line!() as _,
-        ))
-    }
-}
-
-#[track_caller]
-#[inline]
-pub unsafe fn crypto_free(ptr: *mut c_void) {
-    cfg_if! {
-        if #[cfg(any(ossl110, boringssl))] {
-            ffi::CRYPTO_free(ptr, concat!(file!(), "\0").as_ptr() as *const _, line!() as _);
-        } else {
-            ffi::CRYPTO_free(ptr);
-        }
-    }
-}
diff --git a/openssl/src/version.rs b/src/version.rs
similarity index 100%
rename from openssl/src/version.rs
rename to src/version.rs
diff --git a/openssl/src/x509/extension.rs b/src/x509/extension.rs
similarity index 100%
rename from openssl/src/x509/extension.rs
rename to src/x509/extension.rs
diff --git a/openssl/src/x509/mod.rs b/src/x509/mod.rs
similarity index 93%
rename from openssl/src/x509/mod.rs
rename to src/x509/mod.rs
index 4faa26f..45f2467 100644
--- a/openssl/src/x509/mod.rs
+++ b/src/x509/mod.rs
@@ -10,6 +10,7 @@
 use cfg_if::cfg_if;
 use foreign_types::{ForeignType, ForeignTypeRef};
 use libc::{c_int, c_long, c_uint};
+use std::cmp::{self, Ordering};
 use std::error::Error;
 use std::ffi::{CStr, CString};
 use std::fmt;
@@ -227,7 +228,7 @@
     /// the X.509 standard should pass `2` to this method.
     #[corresponds(X509_set_version)]
     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
-        unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
+        unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) }
     }
 
     /// Sets the serial number of the certificate.
@@ -598,6 +599,13 @@
         to_der,
         ffi::i2d_X509
     }
+
+    to_pem! {
+        /// Converts the certificate to human readable text.
+        #[corresponds(X509_print)]
+        to_text,
+        ffi::X509_print
+    }
 }
 
 impl ToOwned for X509Ref {
@@ -611,6 +619,41 @@
     }
 }
 
+impl Ord for X509Ref {
+    fn cmp(&self, other: &Self) -> cmp::Ordering {
+        // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than.
+        // It can't fail if both pointers are valid, which we know is true.
+        let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) };
+        cmp.cmp(&0)
+    }
+}
+
+impl PartialOrd for X509Ref {
+    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialOrd<X509> for X509Ref {
+    fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
+        <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
+    }
+}
+
+impl PartialEq for X509Ref {
+    fn eq(&self, other: &Self) -> bool {
+        self.cmp(other) == cmp::Ordering::Equal
+    }
+}
+
+impl PartialEq<X509> for X509Ref {
+    fn eq(&self, other: &X509) -> bool {
+        <X509Ref as PartialEq<X509Ref>>::eq(self, other)
+    }
+}
+
+impl Eq for X509Ref {}
+
 impl X509 {
     /// Returns a new builder.
     pub fn builder() -> Result<X509Builder, ErrorStack> {
@@ -711,6 +754,38 @@
     type StackType = ffi::stack_st_X509;
 }
 
+impl Ord for X509 {
+    fn cmp(&self, other: &Self) -> cmp::Ordering {
+        X509Ref::cmp(self, other)
+    }
+}
+
+impl PartialOrd for X509 {
+    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+        X509Ref::partial_cmp(self, other)
+    }
+}
+
+impl PartialOrd<X509Ref> for X509 {
+    fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
+        X509Ref::partial_cmp(self, other)
+    }
+}
+
+impl PartialEq for X509 {
+    fn eq(&self, other: &Self) -> bool {
+        X509Ref::eq(self, other)
+    }
+}
+
+impl PartialEq<X509Ref> for X509 {
+    fn eq(&self, other: &X509Ref) -> bool {
+        X509Ref::eq(self, other)
+    }
+}
+
+impl Eq for X509 {}
+
 /// A context object required to construct certain `X509` extension values.
 pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
 
@@ -785,6 +860,17 @@
             cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension)
         }
     }
+
+    /// Adds an alias for an extension
+    ///
+    /// # Safety
+    ///
+    /// This method modifies global state without locking and therefore is not thread safe
+    #[corresponds(X509V3_EXT_add_alias)]
+    pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
+        ffi::init();
+        cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
+    }
 }
 
 /// A builder used to construct an `X509Name`.
@@ -960,6 +1046,21 @@
         }
     }
 
+    /// Compare two names, like [`Ord`] but it may fail.
+    ///
+    /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp`
+    /// call fails.
+    /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may
+    /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails.
+    #[corresponds(X509_NAME_cmp)]
+    pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
+        let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
+        if cfg!(ossl300) && cmp == -2 {
+            return Err(ErrorStack::get());
+        }
+        Ok(cmp.cmp(&0))
+    }
+
     to_der! {
         /// Serializes the certificate into a DER-encoded X509 name structure.
         ///
@@ -1079,7 +1180,13 @@
     ///
     ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html
     pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
-        unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) }
+        unsafe {
+            cvt(ffi::X509_REQ_set_version(
+                self.0.as_ptr(),
+                version as c_long,
+            ))
+            .map(|_| ())
+        }
     }
 
     /// Set the issuer name.
@@ -1175,7 +1282,7 @@
     ///
     /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html
     #[cfg(boringssl)]
-    pub fn sign_without_digset<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
+    pub fn sign_without_digest<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
     where
         T: HasPrivate,
     {
@@ -1259,6 +1366,13 @@
         ffi::i2d_X509_REQ
     }
 
+    to_pem! {
+        /// Converts the request to human readable text.
+        #[corresponds(X509_Req_print)]
+        to_text,
+        ffi::X509_REQ_print
+    }
+
     /// Returns the numerical value of the version field of the certificate request.
     ///
     /// This corresponds to [`X509_REQ_get_version`]
@@ -1395,7 +1509,7 @@
             }
 
             #[cfg(boringssl)]
-            let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
+            let d = (*self.as_ptr()).d.ptr;
             #[cfg(not(boringssl))]
             let d = (*self.as_ptr()).d;
 
@@ -1577,7 +1691,7 @@
 }
 
 cfg_if! {
-    if #[cfg(any(boringssl, ossl110))] {
+    if #[cfg(any(boringssl, ossl110, libressl350))] {
         use ffi::{
             X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
             X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
@@ -1632,7 +1746,7 @@
 }
 
 cfg_if! {
-    if #[cfg(ossl110)] {
+    if #[cfg(any(ossl110, libressl350))] {
         use ffi::X509_OBJECT_free;
     } else if #[cfg(boringssl)] {
         use ffi::X509_OBJECT_free_contents as X509_OBJECT_free;
diff --git a/openssl/src/x509/store.rs b/src/x509/store.rs
similarity index 90%
rename from openssl/src/x509/store.rs
rename to src/x509/store.rs
index f4835d9..120d636 100644
--- a/openssl/src/x509/store.rs
+++ b/src/x509/store.rs
@@ -8,6 +8,7 @@
 //! ```rust
 //! use openssl::x509::store::{X509StoreBuilder, X509Store};
 //! use openssl::x509::{X509, X509Name};
+//! use openssl::asn1::Asn1Time;
 //! use openssl::pkey::PKey;
 //! use openssl::hash::MessageDigest;
 //! use openssl::rsa::Rsa;
@@ -20,11 +21,16 @@
 //! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap();
 //! let name = name.build();
 //!
+//! // Sep 27th, 2016
+//! let sample_time = Asn1Time::from_unix(1474934400).unwrap();
+//!
 //! let mut builder = X509::builder().unwrap();
 //! builder.set_version(2).unwrap();
 //! builder.set_subject_name(&name).unwrap();
 //! builder.set_issuer_name(&name).unwrap();
 //! builder.set_pubkey(&pkey).unwrap();
+//! builder.set_not_before(&sample_time);
+//! builder.set_not_after(&sample_time);
 //! builder.sign(&pkey, MessageDigest::sha256()).unwrap();
 //!
 //! let certificate: X509 = builder.build();
@@ -40,13 +46,15 @@
 use std::mem;
 
 use crate::error::ErrorStack;
+#[cfg(not(boringssl))]
 use crate::ssl::SslFiletype;
 use crate::stack::StackRef;
 #[cfg(any(ossl102, libressl261))]
-use crate::x509::verify::X509VerifyFlags;
+use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef};
 use crate::x509::{X509Object, X509};
 use crate::{cvt, cvt_p};
 use openssl_macros::corresponds;
+#[cfg(not(boringssl))]
 use std::ffi::CString;
 
 foreign_type_and_impl_send_sync! {
@@ -114,6 +122,13 @@
     pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
         unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) }
     }
+
+    /// Sets certificate chain validation related parameters.
+    #[corresponds[X509_STORE_set1_param]]
+    #[cfg(any(ossl102, libressl261))]
+    pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
+        unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())).map(|_| ()) }
+    }
 }
 
 generic_foreign_type_and_impl_send_sync! {
diff --git a/openssl/src/x509/tests.rs b/src/x509/tests.rs
similarity index 71%
rename from openssl/src/x509/tests.rs
rename to src/x509/tests.rs
index 26587d1..ace6175 100644
--- a/openssl/src/x509/tests.rs
+++ b/src/x509/tests.rs
@@ -1,3 +1,5 @@
+use std::cmp::Ordering;
+
 use crate::asn1::Asn1Time;
 use crate::bn::{BigNum, MsbOption};
 use crate::hash::MessageDigest;
@@ -11,11 +13,13 @@
 };
 use crate::x509::store::X509StoreBuilder;
 #[cfg(any(ossl102, libressl261))]
-use crate::x509::verify::X509VerifyFlags;
+use crate::x509::verify::{X509VerifyFlags, X509VerifyParam};
 #[cfg(ossl110)]
 use crate::x509::X509Builder;
 use crate::x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509};
 use hex::{self, FromHex};
+#[cfg(any(ossl102, libressl261))]
+use libc::time_t;
 
 fn pkey() -> PKey<Private> {
     let rsa = Rsa::generate(2048).unwrap();
@@ -283,7 +287,7 @@
     let name = name.build();
 
     let mut builder = X509Req::builder().unwrap();
-    builder.set_version(2).unwrap();
+    builder.set_version(0).unwrap();
     builder.set_subject_name(&name).unwrap();
     builder.set_pubkey(&pkey).unwrap();
 
@@ -479,3 +483,188 @@
     ];
     X509Name::from_der(SUBJECT_DER).unwrap();
 }
+
+#[test]
+fn test_convert_to_text() {
+    let cert = include_bytes!("../../test/cert.pem");
+    let cert = X509::from_pem(cert).unwrap();
+
+    const SUBSTRINGS: &[&str] = &[
+        "Certificate:\n",
+        "Serial Number:",
+        "Signature Algorithm:",
+        "Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd\n",
+        "Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=foobar.com\n",
+        "Subject Public Key Info:",
+    ];
+
+    let text = String::from_utf8(cert.to_text().unwrap()).unwrap();
+
+    for substring in SUBSTRINGS {
+        assert!(
+            text.contains(substring),
+            "{:?} not found inside {}",
+            substring,
+            text
+        );
+    }
+}
+
+#[test]
+fn test_convert_req_to_text() {
+    let csr = include_bytes!("../../test/csr.pem");
+    let csr = X509Req::from_pem(csr).unwrap();
+
+    const SUBSTRINGS: &[&str] = &[
+        "Certificate Request:\n",
+        "Version:",
+        "Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=foobar.com\n",
+        "Subject Public Key Info:",
+        "Signature Algorithm:",
+    ];
+
+    let text = String::from_utf8(csr.to_text().unwrap()).unwrap();
+
+    for substring in SUBSTRINGS {
+        assert!(
+            text.contains(substring),
+            "{:?} not found inside {}",
+            substring,
+            text
+        );
+    }
+}
+
+#[test]
+fn test_name_cmp() {
+    let cert = include_bytes!("../../test/cert.pem");
+    let cert = X509::from_pem(cert).unwrap();
+
+    let subject = cert.subject_name();
+    let issuer = cert.issuer_name();
+    assert_eq!(Ordering::Equal, subject.try_cmp(subject).unwrap());
+    assert_eq!(Ordering::Greater, subject.try_cmp(issuer).unwrap());
+}
+
+#[test]
+#[cfg(any(ossl102, libressl261))]
+fn test_verify_param_set_time_fails_verification() {
+    const TEST_T_2030: time_t = 1893456000;
+
+    let cert = include_bytes!("../../test/cert.pem");
+    let cert = X509::from_pem(cert).unwrap();
+    let ca = include_bytes!("../../test/root-ca.pem");
+    let ca = X509::from_pem(ca).unwrap();
+    let chain = Stack::new().unwrap();
+
+    let mut store_bldr = X509StoreBuilder::new().unwrap();
+    store_bldr.add_cert(ca).unwrap();
+    let mut verify_params = X509VerifyParam::new().unwrap();
+    verify_params.set_time(TEST_T_2030);
+    store_bldr.set_param(&verify_params).unwrap();
+    let store = store_bldr.build();
+
+    let mut context = X509StoreContext::new().unwrap();
+    assert_eq!(
+        context
+            .init(&store, &cert, &chain, |c| {
+                c.verify_cert()?;
+                Ok(c.error())
+            })
+            .unwrap()
+            .error_string(),
+        "certificate has expired"
+    )
+}
+
+#[test]
+#[cfg(any(ossl102, libressl261))]
+fn test_verify_param_set_time() {
+    const TEST_T_2020: time_t = 1577836800;
+
+    let cert = include_bytes!("../../test/cert.pem");
+    let cert = X509::from_pem(cert).unwrap();
+    let ca = include_bytes!("../../test/root-ca.pem");
+    let ca = X509::from_pem(ca).unwrap();
+    let chain = Stack::new().unwrap();
+
+    let mut store_bldr = X509StoreBuilder::new().unwrap();
+    store_bldr.add_cert(ca).unwrap();
+    let mut verify_params = X509VerifyParam::new().unwrap();
+    verify_params.set_time(TEST_T_2020);
+    store_bldr.set_param(&verify_params).unwrap();
+    let store = store_bldr.build();
+
+    let mut context = X509StoreContext::new().unwrap();
+    assert!(context
+        .init(&store, &cert, &chain, |c| c.verify_cert())
+        .unwrap());
+}
+
+#[test]
+#[cfg(any(ossl102, libressl261))]
+fn test_verify_param_set_depth() {
+    let cert = include_bytes!("../../test/leaf.pem");
+    let cert = X509::from_pem(cert).unwrap();
+    let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem");
+    let intermediate_ca = X509::from_pem(intermediate_ca).unwrap();
+    let ca = include_bytes!("../../test/root-ca.pem");
+    let ca = X509::from_pem(ca).unwrap();
+    let mut chain = Stack::new().unwrap();
+    chain.push(intermediate_ca).unwrap();
+
+    let mut store_bldr = X509StoreBuilder::new().unwrap();
+    store_bldr.add_cert(ca).unwrap();
+    let mut verify_params = X509VerifyParam::new().unwrap();
+    // OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do
+    let expected_depth = if cfg!(any(ossl110)) { 1 } else { 2 };
+    verify_params.set_depth(expected_depth);
+    store_bldr.set_param(&verify_params).unwrap();
+    let store = store_bldr.build();
+
+    let mut context = X509StoreContext::new().unwrap();
+    assert!(context
+        .init(&store, &cert, &chain, |c| c.verify_cert())
+        .unwrap());
+}
+
+#[test]
+#[cfg(any(ossl102, libressl261))]
+fn test_verify_param_set_depth_fails_verification() {
+    let cert = include_bytes!("../../test/leaf.pem");
+    let cert = X509::from_pem(cert).unwrap();
+    let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem");
+    let intermediate_ca = X509::from_pem(intermediate_ca).unwrap();
+    let ca = include_bytes!("../../test/root-ca.pem");
+    let ca = X509::from_pem(ca).unwrap();
+    let mut chain = Stack::new().unwrap();
+    chain.push(intermediate_ca).unwrap();
+
+    let mut store_bldr = X509StoreBuilder::new().unwrap();
+    store_bldr.add_cert(ca).unwrap();
+    let mut verify_params = X509VerifyParam::new().unwrap();
+    // OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do
+    let expected_depth = if cfg!(any(ossl110)) { 0 } else { 1 };
+    verify_params.set_depth(expected_depth);
+    store_bldr.set_param(&verify_params).unwrap();
+    let store = store_bldr.build();
+
+    // OpenSSL 1.1.0+ added support for X509_V_ERR_CERT_CHAIN_TOO_LONG, while 1.0.2 simply ignores the intermediate
+    let expected_error = if cfg!(any(ossl110, libressl261)) {
+        "certificate chain too long"
+    } else {
+        "unable to get local issuer certificate"
+    };
+
+    let mut context = X509StoreContext::new().unwrap();
+    assert_eq!(
+        context
+            .init(&store, &cert, &chain, |c| {
+                c.verify_cert()?;
+                Ok(c.error())
+            })
+            .unwrap()
+            .error_string(),
+        expected_error
+    )
+}
diff --git a/openssl/src/x509/verify.rs b/src/x509/verify.rs
similarity index 85%
rename from openssl/src/x509/verify.rs
rename to src/x509/verify.rs
index 4752133..20dd4be 100644
--- a/openssl/src/x509/verify.rs
+++ b/src/x509/verify.rs
@@ -1,10 +1,10 @@
 use bitflags::bitflags;
 use foreign_types::ForeignTypeRef;
-use libc::{c_uint, c_ulong};
+use libc::{c_int, c_uint, c_ulong, time_t};
 use std::net::IpAddr;
 
-use crate::cvt;
 use crate::error::ErrorStack;
+use crate::{cvt, cvt_p};
 use openssl_macros::corresponds;
 
 bitflags! {
@@ -69,6 +69,17 @@
     pub struct X509VerifyParamRef;
 }
 
+impl X509VerifyParam {
+    /// Create an X509VerifyParam
+    #[corresponds(X509_VERIFY_PARAM_new)]
+    pub fn new() -> Result<X509VerifyParam, ErrorStack> {
+        unsafe {
+            ffi::init();
+            cvt_p(ffi::X509_VERIFY_PARAM_new()).map(X509VerifyParam)
+        }
+    }
+}
+
 impl X509VerifyParamRef {
     /// Set the host flags.
     #[corresponds(X509_VERIFY_PARAM_set_hostflags)]
@@ -139,4 +150,16 @@
             .map(|_| ())
         }
     }
+
+    /// Set the verification time, where time is of type time_t, traditionaly defined as seconds since the epoch
+    #[corresponds(X509_VERIFY_PARAM_set_time)]
+    pub fn set_time(&mut self, time: time_t) {
+        unsafe { ffi::X509_VERIFY_PARAM_set_time(self.as_ptr(), time) }
+    }
+
+    /// Set the verification depth
+    #[corresponds(X509_VERIFY_PARAM_set_depth)]
+    pub fn set_depth(&mut self, depth: c_int) {
+        unsafe { ffi::X509_VERIFY_PARAM_set_depth(self.as_ptr(), depth) }
+    }
 }
diff --git a/openssl/test/aia_test_cert.pem b/test/aia_test_cert.pem
similarity index 100%
rename from openssl/test/aia_test_cert.pem
rename to test/aia_test_cert.pem
diff --git a/openssl/test/alt_name_cert.pem b/test/alt_name_cert.pem
similarity index 100%
rename from openssl/test/alt_name_cert.pem
rename to test/alt_name_cert.pem
diff --git a/openssl/test/cert.pem b/test/cert.pem
similarity index 100%
rename from openssl/test/cert.pem
rename to test/cert.pem
diff --git a/openssl/test/certs.pem b/test/certs.pem
similarity index 100%
rename from openssl/test/certs.pem
rename to test/certs.pem
diff --git a/openssl/test/cms.p12 b/test/cms.p12
similarity index 100%
rename from openssl/test/cms.p12
rename to test/cms.p12
Binary files differ
diff --git a/openssl/test/cms_pubkey.der b/test/cms_pubkey.der
similarity index 100%
rename from openssl/test/cms_pubkey.der
rename to test/cms_pubkey.der
Binary files differ
diff --git a/test/csr.pem b/test/csr.pem
new file mode 100644
index 0000000..cf9dde2
--- /dev/null
+++ b/test/csr.pem
@@ -0,0 +1,62 @@
+Certificate Request:
+    Data:
+        Version: 1 (0x0)
+        Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = foobar.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (2048 bit)
+                Modulus:
+                    00:a8:f4:25:8c:44:b3:17:a3:50:85:fe:23:91:87:
+                    d0:78:36:1b:49:17:ff:2d:47:d3:e5:1b:de:6c:36:
+                    fc:96:b9:04:3f:f2:37:de:bf:ef:33:12:ba:65:c5:
+                    f2:e4:b7:4a:49:a9:ca:22:64:6f:20:f4:d5:34:91:
+                    4e:a8:e5:3f:bf:d5:08:19:72:50:80:a1:96:92:d0:
+                    9a:b1:9a:8a:36:62:4f:f5:42:c8:f5:ea:99:cc:05:
+                    cd:74:b9:20:e4:e9:5f:5a:25:25:f5:bc:ac:0e:35:
+                    53:52:c2:21:c0:d4:c8:57:fa:2e:d6:7f:bf:ca:d2:
+                    78:aa:fa:4e:e1:3a:48:65:78:59:16:81:9b:54:ab:
+                    8d:60:5e:1d:55:7c:eb:a0:91:ae:d4:92:d6:27:93:
+                    d9:ab:05:b0:0c:8e:66:a5:a1:93:67:da:93:0c:01:
+                    0c:55:83:84:e1:88:b9:b7:ce:fb:96:aa:f5:c0:49:
+                    6c:d4:65:ce:c8:01:dd:46:6c:de:00:b4:3b:a1:b3:
+                    6e:76:7a:a1:3d:13:88:93:1e:4e:c5:d7:8c:00:4b:
+                    52:56:aa:fe:ba:ea:14:5e:18:7a:e6:64:91:b1:d3:
+                    14:13:33:db:cf:0f:51:cd:e6:dd:94:dc:a4:df:84:
+                    ef:e6:4e:50:14:59:5c:a0:f6:d0:ad:3b:36:e8:2a:
+                    0b:35
+                Exponent: 65537 (0x10001)
+        Attributes:
+            a0:00
+    Signature Algorithm: sha256WithRSAEncryption
+         95:26:e1:84:56:e7:80:da:2c:a4:c0:b5:85:43:61:85:34:84:
+         37:83:c0:bc:cf:70:20:89:46:ce:3d:7e:23:8a:40:a4:a5:fa:
+         c5:e3:3d:ee:e5:05:16:58:93:f9:6c:f3:86:ee:99:cc:e1:04:
+         5c:68:99:da:66:72:a1:95:31:cd:13:6f:a5:6f:fc:a9:ec:75:
+         6a:f7:e5:cf:0e:7b:5f:2f:db:8d:45:e6:66:52:12:1d:c9:ac:
+         3a:86:35:bd:1f:7b:6e:b5:e1:f3:4f:80:6a:06:73:1c:a0:0d:
+         a3:63:b6:40:76:25:b0:e9:96:33:7a:9d:18:7e:5e:93:c0:47:
+         d7:0b:da:b3:03:17:94:d0:0c:78:18:f3:0e:cd:3c:f7:e8:25:
+         08:c2:13:0a:af:1e:5c:48:5f:17:41:b2:2d:d2:0f:37:2e:b3:
+         10:fd:2b:c0:77:e1:17:8a:57:0c:95:5e:c8:03:eb:63:14:2e:
+         46:fd:1e:14:13:9f:38:c1:2f:e9:9b:47:c3:60:a9:d7:6e:a3:
+         d0:af:0b:6f:df:6e:37:f6:d9:a0:1b:dd:1f:a5:a5:33:89:1f:
+         a5:a3:44:14:91:83:c3:c8:b2:6e:fb:3f:f1:6d:d2:51:21:f7:
+         98:20:0a:40:75:a5:60:c3:59:53:08:62:3d:39:e8:83:55:90:
+         1a:bf:51:57
+-----BEGIN CERTIFICATE REQUEST-----
+MIICnzCCAYcCAQAwWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
+ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9v
+YmFyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxej
+UIX+I5GH0Hg2G0kX/y1H0+Ub3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD0
+1TSRTqjlP7/VCBlyUIChlpLQmrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41
+U1LCIcDUyFf6LtZ/v8rSeKr6TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asF
+sAyOZqWhk2fakwwBDFWDhOGIubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0T
+iJMeTsXXjABLUlaq/rrqFF4YeuZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD2
+0K07NugqCzUCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCVJuGEVueA2iykwLWF
+Q2GFNIQ3g8C8z3AgiUbOPX4jikCkpfrF4z3u5QUWWJP5bPOG7pnM4QRcaJnaZnKh
+lTHNE2+lb/yp7HVq9+XPDntfL9uNReZmUhIdyaw6hjW9H3tuteHzT4BqBnMcoA2j
+Y7ZAdiWw6ZYzep0Yfl6TwEfXC9qzAxeU0Ax4GPMOzTz36CUIwhMKrx5cSF8XQbIt
+0g83LrMQ/SvAd+EXilcMlV7IA+tjFC5G/R4UE584wS/pm0fDYKnXbqPQrwtv3243
+9tmgG90fpaUziR+lo0QUkYPDyLJu+z/xbdJRIfeYIApAdaVgw1lTCGI9OeiDVZAa
+v1FX
+-----END CERTIFICATE REQUEST-----
diff --git a/openssl/test/dhparams.pem b/test/dhparams.pem
similarity index 100%
rename from openssl/test/dhparams.pem
rename to test/dhparams.pem
diff --git a/openssl/test/dsa.pem b/test/dsa.pem
similarity index 100%
rename from openssl/test/dsa.pem
rename to test/dsa.pem
diff --git a/openssl/test/dsa.pem.pub b/test/dsa.pem.pub
similarity index 100%
rename from openssl/test/dsa.pem.pub
rename to test/dsa.pem.pub
diff --git a/openssl/test/dsaparam.pem b/test/dsaparam.pem
similarity index 100%
rename from openssl/test/dsaparam.pem
rename to test/dsaparam.pem
diff --git a/openssl/test/identity.p12 b/test/identity.p12
similarity index 100%
rename from openssl/test/identity.p12
rename to test/identity.p12
Binary files differ
diff --git a/test/intermediate-ca.key b/test/intermediate-ca.key
new file mode 100644
index 0000000..48f4495
--- /dev/null
+++ b/test/intermediate-ca.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA1HsHFTpgKeWL/y6oKtARZm0Dy6J/08E0CujmdpVp0xnkXi/A
+RARnbMEbOPfmBUMOkVtQT3+l5aCgIAX+Kg6K7sQvio8nQUgOxuO1YpGlYu9EMtc7
+5fNxA1T0CuXXx8ClfEqW1ZV7ziQV0J4gzvuI26A7XyUhdk1oP/Al3F/94TmH6dtP
+SQ2K901O2zknU+bpPheQy08SE20k/nUOJAsiwtsxqY8hHOL1sXZ4K+I311hl0QpD
+OYf7eBcBdo2Mc5Nzjd9LPGLk1lE3itAXpayFMmfuuA0IdH1gNfy18axFEEVnj6CS
+2epGpmAckUEWUOse1WBhDEt6ddowT1iw7X4mWwIDAQABAoIBAGMGXzuudAiymTc5
+OFiTlbhlkAJEXkyC201GU7nqUmJ2y651lKZeYxEVQimfpszG/rARnXEfbWKCJH4o
+LNbO5kL2na12n/XVrkVU9EDW3fwoxGDpXFoDxaSm4AGAMrs+diFh5b/upb9ho+UQ
+/PtZ0OOCXokuFdU7qB08P3jgJ8LhooqWnZ4AC0rhN85CMNIKs/nrUrnmS3FZLVd/
+NWI9Vfjsndd41Gkho0A7tgOSnwRupk/Bv1b0px31h8ucp9/nLuR8vbGSdS/R9Sta
+pB9KNYYQ3LrhQGjddnEU0gj8qsuWgnoPf7eaWsLVunPLHQzL2hNNKL1eBADm7Lhh
+avIlnrkCgYEA8Q8UhOeIO0sMU8sB4NPTUf2UT9xjURoowGsGgbDEk21eABH6VC33
+VYt5r5xwbZFQvVaTbe+EI1YDpjH1cvpmorEWI47Nm4Vbf9JujW/hoQwuwpzOpdUT
+2G4tfMQrmTw/9HJ0l9+1Ib+A93dB8GvR0NE1uueaWanWvXARInwGiscCgYEA4aZ9
+mbhuwx88sSRMXwxSZw+R5BRrjdC0CeoimGg4/P84bKgc0YsjAha5jWaC/h8xN2Pb
+w45b3hQ0/FP8xohP0bp/5eeiDbqb6JuO5bI3CnfBrVpu1CAuIrf7lhkar3a0wluB
+k03fVHuVLtydACDJBKrZm1F39lpiZiEqlBIp080CgYEAwRwYjwPAEefkHzhQ7+Ah
+uNwQtQ1TjsQLA2J5mumWAJirphjA1jDgo+oQ+Iq1UkEIUjWJ85bd30TntXruK0bH
+c+uzVZbvxXfGvhZAtBN9x/svdn4R2a1hsY9J51prpt0qStRp7MSsoTV9xkEGVOi6
+87K1fV5OOyggvC+Lunlq8D8CgYAVSCOObPOdWYPa3SaKzFm1OKW00iw2qtlgGgH7
+R9EgI14J+W0GYk4B82y6plFycDSvGa7vaazGbDd3GOC9RLvqduF7KHaDPvdXX9yB
+U2aXiSXuGJpdTU+snJeQ13tJ0zNHJWQ6JV0L1cADNHFmQrFSzF5LpMpgpLOlGDmw
+z2m8fQKBgQDclFeonyn0zcXqznun9kAKkMij4s6lSdRgi/5Zh1WbJwOso9oWfwz9
+SSTP2KBO8B+/yFvuo5SWrbNaTz9/KuzMTv4HXz5ukLbyN9Jjtk73fdBBRSjL+zF5
+jU56oXHrwBhEqWQ77Ps60r+FmDjUgUhyJl14ZfkzICUK7NLFxKrvMQ==
+-----END RSA PRIVATE KEY-----
diff --git a/test/intermediate-ca.pem b/test/intermediate-ca.pem
new file mode 100644
index 0000000..266ef59
--- /dev/null
+++ b/test/intermediate-ca.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDszCCApugAwIBAgIEFSQSITANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTIyMTEwMzA3MDc0OVoXDTI2MDgxMTA3MDc0OVowgYkxCzAJ
+BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l
+dCBXaWRnaXRzIFB0eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRt
+ZW50MSAwHgYDVQQDDBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANR7BxU6YCnli/8uqCrQEWZtA8uif9PBNAro
+5naVadMZ5F4vwEQEZ2zBGzj35gVDDpFbUE9/peWgoCAF/ioOiu7EL4qPJ0FIDsbj
+tWKRpWLvRDLXO+XzcQNU9Arl18fApXxKltWVe84kFdCeIM77iNugO18lIXZNaD/w
+Jdxf/eE5h+nbT0kNivdNTts5J1Pm6T4XkMtPEhNtJP51DiQLIsLbMamPIRzi9bF2
+eCviN9dYZdEKQzmH+3gXAXaNjHOTc43fSzxi5NZRN4rQF6WshTJn7rgNCHR9YDX8
+tfGsRRBFZ4+gktnqRqZgHJFBFlDrHtVgYQxLenXaME9YsO1+JlsCAwEAAaNmMGQw
+HQYDVR0OBBYEFAXJImmmxYXx6L1SRRhgP3Tyq2J6MB8GA1UdIwQYMBaAFGzTpQOr
+DV8syY2KnIiniHe4N/2aMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD
+AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQCnUh7iNbnFBjVa4sFx02r65syxUhcvM/ya
+DcSe1esGUwjZLyKVl9BTfQ6kfNa/6Z/t5cprp0R3etalN31dxka7xSDwzFNdBczB
+zYDIVOVlcGLL1Xjozacm6YHo773dqxZS36rVMk3NqNUY6GJJ+CGso2xZShcBg2KG
+fPlNPiRz3847E3dwouDYcP1MXf2ql/Y7dRbE+8kb3bWkSusJVb/4EHjpR7yZjKmh
+eXHVVx1dKnCGRldn3+dSNhN6mxNaSeBE2hb158+diQvL5u3f//va7SOpCi0f4d8E
+UCnLhieyrDlr42XXfz42BqRpqBO1SDjQwzIIc9Fbevwb916OSExp
+-----END CERTIFICATE-----
diff --git a/openssl/test/key.der b/test/key.der
similarity index 100%
rename from openssl/test/key.der
rename to test/key.der
Binary files differ
diff --git a/openssl/test/key.der.pub b/test/key.der.pub
similarity index 100%
rename from openssl/test/key.der.pub
rename to test/key.der.pub
Binary files differ
diff --git a/openssl/test/key.pem b/test/key.pem
similarity index 100%
rename from openssl/test/key.pem
rename to test/key.pem
diff --git a/openssl/test/key.pem.pub b/test/key.pem.pub
similarity index 100%
rename from openssl/test/key.pem.pub
rename to test/key.pem.pub
diff --git a/openssl/test/keystore-empty-chain.p12 b/test/keystore-empty-chain.p12
similarity index 100%
rename from openssl/test/keystore-empty-chain.p12
rename to test/keystore-empty-chain.p12
Binary files differ
diff --git a/test/leaf.pem b/test/leaf.pem
new file mode 100644
index 0000000..0f7aa80
--- /dev/null
+++ b/test/leaf.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDejCCAmICBBUkEiQwDQYJKoZIhvcNAQELBQAwgYkxCzAJBgNVBAYTAkFVMRMw
+EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0
+eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRtZW50MSAwHgYDVQQD
+DBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTAeFw0yMjExMDMwNzE3NTJaFw0yNjA4
+MTEwNzE3NTJaMHkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAsMD0xlYWYg
+RGVwYXJ0bWVudDEYMBYGA1UEAwwPbGVhZi5mb29iYXIuY29tMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs9STUHGIcSOtioK6+02k9Jx4JuYVJ0SB7Ebd
+FAhGiOxBSoOljRVmmALti89QMmRiRqlyJnGJch7AloCCRsLJA0MfUYvauqmKHZFk
+iqtZ1HocHQ/LGNKfkILcclb4xp2nGYntKAyEqer3Qc6aPWAnQAV/+BshU1vlMfwU
+T6vOJRG69mft6dkHEWSzZd7++7HmFQGnDmIs5jBJVCOgKVttkN8Bk2EsTvJi9zl2
+SXLTcVrTAxEvuawv2ZXvdI/Cpt1WW0litXlFLcYBGwt/N93TX/L3Iyw5HcNd/xf9
+QwOr6RR66krQJzKxwcIY934uq6cyTQhexgnffb65qXL4bbV5fwIDAQABMA0GCSqG
+SIb3DQEBCwUAA4IBAQAZf0/r04AeKN2QhQ7Z0o2Iu/Yj3OD2tnbxVoltYk8CRfp3
+7VGl/5PUbmXXBSwMc4Udj88JlreU7iNEPAKtBqFczw0pwNfvxKG4Eh3vsfKrP+5g
+gtVwDG0mWeKJ7udrmFt8N0uwxVYDKp/gv5+Bw2eMew9Eoyenj6k2yg0nbFKzA3EH
+DqngETzX0dhdiYwVcoJFUK5ni3tVl9qi6FpmaTE6C5nTQLyH4CI+vo2x/QHINGaJ
+OzY/rx35iyVqXVqxN/gO/hp6g0nT5zLuMg2rfvcAhdDsD7htYcHiNkofrC8s0oQE
+W+r01EhxdEVvY1nYWanBCF6tktc5v5qf2WMS4ye5
+-----END CERTIFICATE-----
diff --git a/openssl/test/nid_test_cert.pem b/test/nid_test_cert.pem
similarity index 100%
rename from openssl/test/nid_test_cert.pem
rename to test/nid_test_cert.pem
diff --git a/openssl/test/nid_uid_test_cert.pem b/test/nid_uid_test_cert.pem
similarity index 100%
rename from openssl/test/nid_uid_test_cert.pem
rename to test/nid_uid_test_cert.pem
diff --git a/openssl/test/pkcs1.pem.pub b/test/pkcs1.pem.pub
similarity index 100%
rename from openssl/test/pkcs1.pem.pub
rename to test/pkcs1.pem.pub
diff --git a/openssl/test/pkcs8-nocrypt.der b/test/pkcs8-nocrypt.der
similarity index 100%
rename from openssl/test/pkcs8-nocrypt.der
rename to test/pkcs8-nocrypt.der
Binary files differ
diff --git a/openssl/test/pkcs8.der b/test/pkcs8.der
similarity index 100%
rename from openssl/test/pkcs8.der
rename to test/pkcs8.der
Binary files differ
diff --git a/openssl/test/root-ca.key b/test/root-ca.key
similarity index 100%
rename from openssl/test/root-ca.key
rename to test/root-ca.key
diff --git a/openssl/test/root-ca.pem b/test/root-ca.pem
similarity index 100%
rename from openssl/test/root-ca.pem
rename to test/root-ca.pem
diff --git a/openssl/test/rsa-encrypted.pem b/test/rsa-encrypted.pem
similarity index 100%
rename from openssl/test/rsa-encrypted.pem
rename to test/rsa-encrypted.pem
diff --git a/openssl/test/rsa.pem b/test/rsa.pem
similarity index 100%
rename from openssl/test/rsa.pem
rename to test/rsa.pem
diff --git a/openssl/test/rsa.pem.pub b/test/rsa.pem.pub
similarity index 100%
rename from openssl/test/rsa.pem.pub
rename to test/rsa.pem.pub