From d7a4c3770a25e06ebabba1be361da06d766e99c3 Mon Sep 17 00:00:00 2001 From: peizhe <472708703@qq.com> Date: Mon, 17 Apr 2023 09:23:47 +0800 Subject: [PATCH] upgrade openssl version to 0.10.47 Signed-off-by: peizhe <472708703@qq.com> --- Cargo.toml | 8 +- OAT.xml | 65 + README.md | 174 +- appveyor.yml | 50 - openssl-errors/CHANGELOG.md | 20 + openssl-errors/Cargo.toml | 19 + openssl-errors/LICENSE-APACHE | 202 ++ openssl-errors/LICENSE-MIT | 19 + openssl-errors/README.md | 1 + openssl-errors/build.rs | 13 + openssl-errors/src/lib.rs | 388 +++ openssl-errors/tests/test.rs | 95 + openssl-macros/Cargo.toml | 14 + openssl-macros/LICENSE-APACHE | 202 ++ openssl-macros/LICENSE-MIT | 19 + openssl-macros/src/lib.rs | 32 + openssl-sys/CHANGELOG.md | 442 +++ openssl-sys/Cargo.toml | 23 +- openssl-sys/README.md | 0 openssl-sys/build.rs | 543 ---- openssl-sys/build/cfgs.rs | 94 + openssl-sys/build/expando.c | 124 + openssl-sys/build/find_normal.rs | 275 ++ openssl-sys/build/find_vendored.rs | 16 + openssl-sys/build/main.rs | 426 +++ openssl-sys/build/run_bindgen.rs | 236 ++ openssl-sys/src/aes.rs | 7 + openssl-sys/src/asn1.rs | 39 + openssl-sys/src/bio.rs | 72 + openssl-sys/src/bn.rs | 15 + openssl-sys/src/cms.rs | 46 + openssl-sys/src/crypto.rs | 134 + openssl-sys/src/dtls1.rs | 9 + openssl-sys/src/ec.rs | 16 + openssl-sys/src/err.rs | 70 + openssl-sys/src/evp.rs | 285 ++ openssl-sys/src/handwritten/aes.rs | 40 + openssl-sys/src/handwritten/asn1.rs | 60 + openssl-sys/src/handwritten/bio.rs | 107 + openssl-sys/src/handwritten/bn.rs | 168 + openssl-sys/src/handwritten/cms.rs | 65 + openssl-sys/src/handwritten/conf.rs | 7 + openssl-sys/src/handwritten/crypto.rs | 85 + openssl-sys/src/handwritten/dh.rs | 50 + openssl-sys/src/handwritten/dsa.rs | 85 + openssl-sys/src/handwritten/ec.rs | 255 ++ openssl-sys/src/handwritten/err.rs | 55 + openssl-sys/src/handwritten/evp.rs | 600 ++++ openssl-sys/src/handwritten/hmac.rs | 30 + openssl-sys/src/handwritten/kdf.rs | 26 + openssl-sys/src/handwritten/mod.rs | 65 + openssl-sys/src/handwritten/object.rs | 30 + openssl-sys/src/handwritten/ocsp.rs | 89 + openssl-sys/src/handwritten/pem.rs | 191 ++ openssl-sys/src/handwritten/pkcs12.rs | 53 + openssl-sys/src/handwritten/pkcs7.rs | 70 + openssl-sys/src/handwritten/provider.rs | 20 + openssl-sys/src/handwritten/rand.rs | 12 + openssl-sys/src/handwritten/rsa.rs | 124 + openssl-sys/src/handwritten/safestack.rs | 1 + openssl-sys/src/handwritten/sha.rs | 101 + openssl-sys/src/handwritten/srtp.rs | 10 + openssl-sys/src/handwritten/ssl.rs | 913 ++++++ openssl-sys/src/handwritten/stack.rs | 45 + openssl-sys/src/handwritten/tls1.rs | 28 + openssl-sys/src/handwritten/types.rs | 1078 +++++++ openssl-sys/src/handwritten/x509.rs | 666 ++++ openssl-sys/src/handwritten/x509_vfy.rs | 132 + openssl-sys/src/handwritten/x509v3.rs | 104 + openssl-sys/src/lib.rs | 2879 ++--------------- openssl-sys/src/libressl/mod.rs | 600 ---- openssl-sys/src/libressl/v250.rs | 221 -- openssl-sys/src/libressl/v25x.rs | 89 - openssl-sys/src/macros.rs | 298 ++ openssl-sys/src/obj_mac.rs | 982 ++++++ openssl-sys/src/ocsp.rs | 35 + openssl-sys/src/ossl10x.rs | 985 ------ openssl-sys/src/ossl110.rs | 291 -- openssl-sys/src/pem.rs | 3 + openssl-sys/src/pkcs7.rs | 20 + openssl-sys/src/rsa.rs | 101 + openssl-sys/src/sha.rs | 103 + openssl-sys/src/srtp.rs | 14 + openssl-sys/src/ssl.rs | 631 ++++ openssl-sys/src/ssl3.rs | 5 + openssl-sys/src/tls1.rs | 94 + openssl-sys/src/types.rs | 21 + openssl-sys/src/x509.rs | 15 + openssl-sys/src/x509_vfy.rs | 149 + openssl-sys/src/x509v3.rs | 93 + openssl/CHANGELOG.md | 749 +++++ openssl/Cargo.toml | 29 +- openssl/README.md | 0 openssl/build.rs | 110 +- openssl/examples/mk_certs.rs | 90 +- openssl/src/aes.rs | 223 +- openssl/src/asn1.rs | 596 +++- openssl/src/base64.rs | 128 + openssl/src/bio.rs | 31 +- openssl/src/bn.rs | 625 ++-- openssl/src/cipher.rs | 484 +++ openssl/src/cipher_ctx.rs | 841 +++++ openssl/src/cms.rs | 449 ++- openssl/src/conf.rs | 93 +- openssl/src/crypto.rs | 6 - openssl/src/derive.rs | 182 ++ openssl/src/dh.rs | 432 ++- openssl/src/dsa.rs | 650 +++- openssl/src/ec.rs | 1119 ++++--- openssl/src/ec_key.rs | 4 - openssl/src/ecdsa.rs | 224 ++ openssl/src/encrypt.rs | 578 ++++ openssl/src/envelope.rs | 181 ++ openssl/src/error.rs | 256 +- openssl/src/ex_data.rs | 6 + openssl/src/fips.rs | 21 + openssl/src/hash.rs | 591 +++- openssl/src/lib.rs | 191 +- openssl/src/lib_ctx.rs | 22 + openssl/src/macros.rs | 330 +- openssl/src/md.rs | 235 ++ openssl/src/md_ctx.rs | 540 ++++ openssl/src/memcmp.rs | 7 +- openssl/src/nid.rs | 2076 ++++++------ openssl/src/ocsp.rs | 188 +- openssl/src/pkcs12.rs | 322 +- openssl/src/pkcs5.rs | 414 +-- openssl/src/pkcs7.rs | 446 +++ openssl/src/pkey.rs | 1018 +++++- openssl/src/pkey_ctx.rs | 804 +++++ openssl/src/provider.rs | 77 + openssl/src/rand.rs | 26 +- openssl/src/rsa.rs | 854 +++-- openssl/src/sha.rs | 503 +-- openssl/src/sign.rs | 588 +++- openssl/src/srtp.rs | 66 + openssl/src/ssl/bio.rs | 245 +- openssl/src/ssl/callbacks.rs | 685 +++- openssl/src/ssl/connector.rs | 803 ++--- openssl/src/ssl/error.rs | 211 +- openssl/src/ssl/mod.rs | 3750 +++++++++++++++------- openssl/src/ssl/test/mod.rs | 1493 +++++++++ openssl/src/ssl/test/server.rs | 167 + openssl/src/ssl/tests/mod.rs | 1416 -------- openssl/src/ssl/tests/select.rs | 74 - openssl/src/stack.rs | 208 +- openssl/src/string.rs | 62 +- openssl/src/symm.rs | 1201 +++++-- openssl/src/types.rs | 5 - openssl/src/util.rs | 59 +- openssl/src/verify.rs | 68 - openssl/src/version.rs | 59 +- openssl/src/x509/extension.rs | 384 +-- openssl/src/x509/mod.rs | 1859 ++++++++--- openssl/src/x509/store.rs | 246 +- openssl/src/x509/tests.rs | 879 ++++- openssl/src/x509/verify.rs | 191 +- openssl/test/aia_test_cert.pem | 22 + openssl/test/alt_name_cert.pem | 43 +- openssl/test/ca.crt | 88 + openssl/test/cms.p12 | Bin 0 -> 1709 bytes openssl/test/cms_pubkey.der | Bin 0 -> 688 bytes openssl/test/crl-ca.crt | 20 + openssl/test/csr.pem | 62 + openssl/test/dsa-encrypted.pem | 15 - openssl/test/intermediate-ca.key | 27 + openssl/test/intermediate-ca.pem | 22 + openssl/test/leaf.pem | 21 + openssl/test/pkcs1.pem.pub | 8 + openssl/test/pkcs8-nocrypt.der | Bin 0 -> 1216 bytes openssl/test/subca.crt | 88 + openssl/test/test.crl | Bin 0 -> 469 bytes systest/Cargo.toml | 8 +- systest/build.rs | 106 +- systest/src/main.rs | 5 +- test/add_target.sh | 21 - test/build_openssl.sh | 56 - 177 files changed, 34925 insertions(+), 14344 deletions(-) create mode 100644 OAT.xml delete mode 100644 appveyor.yml create mode 100644 openssl-errors/CHANGELOG.md create mode 100644 openssl-errors/Cargo.toml create mode 100644 openssl-errors/LICENSE-APACHE create mode 100644 openssl-errors/LICENSE-MIT create mode 100644 openssl-errors/README.md create mode 100644 openssl-errors/build.rs create mode 100644 openssl-errors/src/lib.rs create mode 100644 openssl-errors/tests/test.rs create mode 100644 openssl-macros/Cargo.toml create mode 100644 openssl-macros/LICENSE-APACHE create mode 100644 openssl-macros/LICENSE-MIT create mode 100644 openssl-macros/src/lib.rs create mode 100644 openssl-sys/CHANGELOG.md mode change 120000 => 100644 openssl-sys/README.md delete mode 100644 openssl-sys/build.rs create mode 100644 openssl-sys/build/cfgs.rs create mode 100644 openssl-sys/build/expando.c create mode 100644 openssl-sys/build/find_normal.rs create mode 100644 openssl-sys/build/find_vendored.rs create mode 100644 openssl-sys/build/main.rs create mode 100644 openssl-sys/build/run_bindgen.rs create mode 100644 openssl-sys/src/aes.rs create mode 100644 openssl-sys/src/asn1.rs create mode 100644 openssl-sys/src/bio.rs create mode 100644 openssl-sys/src/bn.rs create mode 100644 openssl-sys/src/cms.rs create mode 100644 openssl-sys/src/crypto.rs create mode 100644 openssl-sys/src/dtls1.rs create mode 100644 openssl-sys/src/ec.rs create mode 100644 openssl-sys/src/err.rs create mode 100644 openssl-sys/src/evp.rs create mode 100644 openssl-sys/src/handwritten/aes.rs create mode 100644 openssl-sys/src/handwritten/asn1.rs create mode 100644 openssl-sys/src/handwritten/bio.rs create mode 100644 openssl-sys/src/handwritten/bn.rs create mode 100644 openssl-sys/src/handwritten/cms.rs create mode 100644 openssl-sys/src/handwritten/conf.rs create mode 100644 openssl-sys/src/handwritten/crypto.rs create mode 100644 openssl-sys/src/handwritten/dh.rs create mode 100644 openssl-sys/src/handwritten/dsa.rs create mode 100644 openssl-sys/src/handwritten/ec.rs create mode 100644 openssl-sys/src/handwritten/err.rs create mode 100644 openssl-sys/src/handwritten/evp.rs create mode 100644 openssl-sys/src/handwritten/hmac.rs create mode 100644 openssl-sys/src/handwritten/kdf.rs create mode 100644 openssl-sys/src/handwritten/mod.rs create mode 100644 openssl-sys/src/handwritten/object.rs create mode 100644 openssl-sys/src/handwritten/ocsp.rs create mode 100644 openssl-sys/src/handwritten/pem.rs create mode 100644 openssl-sys/src/handwritten/pkcs12.rs create mode 100644 openssl-sys/src/handwritten/pkcs7.rs create mode 100644 openssl-sys/src/handwritten/provider.rs create mode 100644 openssl-sys/src/handwritten/rand.rs create mode 100644 openssl-sys/src/handwritten/rsa.rs create mode 100644 openssl-sys/src/handwritten/safestack.rs create mode 100644 openssl-sys/src/handwritten/sha.rs create mode 100644 openssl-sys/src/handwritten/srtp.rs create mode 100644 openssl-sys/src/handwritten/ssl.rs create mode 100644 openssl-sys/src/handwritten/stack.rs create mode 100644 openssl-sys/src/handwritten/tls1.rs create mode 100644 openssl-sys/src/handwritten/types.rs create mode 100644 openssl-sys/src/handwritten/x509.rs create mode 100644 openssl-sys/src/handwritten/x509_vfy.rs create mode 100644 openssl-sys/src/handwritten/x509v3.rs delete mode 100644 openssl-sys/src/libressl/mod.rs delete mode 100644 openssl-sys/src/libressl/v250.rs delete mode 100644 openssl-sys/src/libressl/v25x.rs create mode 100644 openssl-sys/src/macros.rs create mode 100644 openssl-sys/src/obj_mac.rs create mode 100644 openssl-sys/src/ocsp.rs delete mode 100644 openssl-sys/src/ossl10x.rs delete mode 100644 openssl-sys/src/ossl110.rs create mode 100644 openssl-sys/src/pem.rs create mode 100644 openssl-sys/src/pkcs7.rs create mode 100644 openssl-sys/src/rsa.rs create mode 100644 openssl-sys/src/sha.rs create mode 100644 openssl-sys/src/srtp.rs create mode 100644 openssl-sys/src/ssl.rs create mode 100644 openssl-sys/src/ssl3.rs create mode 100644 openssl-sys/src/tls1.rs create mode 100644 openssl-sys/src/types.rs create mode 100644 openssl-sys/src/x509.rs create mode 100644 openssl-sys/src/x509_vfy.rs create mode 100644 openssl-sys/src/x509v3.rs create mode 100644 openssl/CHANGELOG.md mode change 120000 => 100644 openssl/README.md create mode 100644 openssl/src/base64.rs create mode 100644 openssl/src/cipher.rs create mode 100644 openssl/src/cipher_ctx.rs delete mode 100644 openssl/src/crypto.rs create mode 100644 openssl/src/derive.rs delete mode 100644 openssl/src/ec_key.rs create mode 100644 openssl/src/ecdsa.rs create mode 100644 openssl/src/encrypt.rs create mode 100644 openssl/src/envelope.rs create mode 100644 openssl/src/fips.rs create mode 100644 openssl/src/lib_ctx.rs create mode 100644 openssl/src/md.rs create mode 100644 openssl/src/md_ctx.rs create mode 100644 openssl/src/pkcs7.rs create mode 100644 openssl/src/pkey_ctx.rs create mode 100644 openssl/src/provider.rs create mode 100644 openssl/src/srtp.rs create mode 100644 openssl/src/ssl/test/mod.rs create mode 100644 openssl/src/ssl/test/server.rs delete mode 100644 openssl/src/ssl/tests/mod.rs delete mode 100644 openssl/src/ssl/tests/select.rs delete mode 100644 openssl/src/types.rs delete mode 100644 openssl/src/verify.rs create mode 100644 openssl/test/aia_test_cert.pem create mode 100644 openssl/test/ca.crt create mode 100644 openssl/test/cms.p12 create mode 100644 openssl/test/cms_pubkey.der create mode 100644 openssl/test/crl-ca.crt create mode 100644 openssl/test/csr.pem delete mode 100644 openssl/test/dsa-encrypted.pem create mode 100644 openssl/test/intermediate-ca.key create mode 100644 openssl/test/intermediate-ca.pem create mode 100644 openssl/test/leaf.pem create mode 100644 openssl/test/pkcs1.pem.pub create mode 100644 openssl/test/pkcs8-nocrypt.der create mode 100644 openssl/test/subca.crt create mode 100644 openssl/test/test.crl delete mode 100755 test/add_target.sh delete mode 100755 test/build_openssl.sh diff --git a/Cargo.toml b/Cargo.toml index 2ef99c1..c33c347 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,8 @@ [workspace] -members = ["openssl", "openssl-sys", "systest"] +members = [ + "openssl", + "openssl-errors", + "openssl-macros", + "openssl-sys", + "systest", +] diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 0000000..65fa581 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,65 @@ + + + + + + LICENSE-UNICODE|LICENSE-APACHE|LICENSE-MIT + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 067a538..50c6d57 100644 --- a/README.md +++ b/README.md @@ -1,176 +1,18 @@ # rust-openssl -[![CircleCI](https://circleci.com/gh/sfackler/rust-openssl.svg?style=shield)](https://circleci.com/gh/sfackler/rust-openssl) [![Build status](https://ci.appveyor.com/api/projects/status/d1knobws948pyynk/branch/master?svg=true)](https://ci.appveyor.com/project/sfackler/rust-openssl/branch/master) +[![crates.io](https://img.shields.io/crates/v/openssl.svg)](https://crates.io/crates/openssl) -[Documentation](https://docs.rs/openssl). - -## Warning - -This README does not correspond to rust-openssl 0.7.x or 0.8.x. See -[here](https://github.com/sfackler/rust-openssl/blob/b8fb29db5c246175a096260eacca38180cd77dd0/README.md) -for that README. - -## Building - -rust-openssl depends on OpenSSL version 1.0.1 or above, or LibreSSL. Both the -libraries and headers need to be present in the build environment before this -crate is compiled, and some instructions of how to do this are in the sections -below. - -### Linux - -On Linux, you can typically install OpenSSL via your package manager. The -headers are sometimes provided in a separate package than the runtime libraries -- look for something like `openssl-devel` or `libssl-dev`. You will also need the -regular development utilities, like `pkg-config`, as the custom build script relies -on them. - -```bash -# On Debian and Ubuntu -sudo apt-get install pkg-config libssl-dev -# On Arch Linux -sudo pacman -S openssl -# On Fedora -sudo dnf install openssl-devel -``` - -If installation via a package manager is not possible, or if you're cross -compiling to a separate target, you'll typically need to compile OpenSSL from -source. That can normally be done with: - -``` -curl -O https://www.openssl.org/source/openssl-1.1.0f.tar.gz -tar xf openssl-1.1.0f.tar.gz -cd openssl-1.1.0f -export CC=... -./Configure --prefix=... linux-x86_64 -fPIC -make -j$(nproc) -make install -``` - -### OSX - -Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out -of OSX and this crate also does not support that version of OpenSSL. To use this -crate on OSX you'll need to install OpenSSL via some alternate means, typically -Homebrew: - -```bash -brew install openssl -``` - -Occasionally an update of XCode or MacOS will cause the linker to fail after compilation, to rectify this you may want to try and run: - -```bash -xcode-select --install -``` - -If Homebrew is installed to the default location of `/usr/local`, OpenSSL will be -automatically detected. - -### Windows MSVC - -On MSVC it's unfortunately not always a trivial process acquiring OpenSSL. A couple of possibilities -are downloading precompiled binaries for OpenSSL 1.1.0, or installing OpenSSL 1.0.2 using vcpkg. - -#### Installing OpenSSL 1.1.0 using precompiled binaries - -Perhaps the easiest way to do this right now is to download [precompiled -binaries] and install them on your system. Currently it's recommended to -install the 1.1.0 (non-light) installation if you're choosing this route. - -[precompiled binaries]: http://slproweb.com/products/Win32OpenSSL.html - -Once a precompiled binary is installed you can configure this crate to find the -installation via an environment variable: +OpenSSL bindings for the Rust programming language. -``` -set OPENSSL_DIR=C:\OpenSSL-Win64 -``` - -During the installation process if you select "Copy OpenSSL DLLs to: The OpenSSL binaries (/bin) -directory", you will need to add them to the `PATH` environment variable: - -``` -set PATH=%PATH%;C:\OpenSSL-Win64\bin -``` - -Now you will need to [install root certificates.](#acquiring-root-certificates) - -#### Installing OpenSSL 1.0.2 using vcpkg - -Install [vcpkg](https://github.com/Microsoft/vcpkg), and install the OpenSSL port like this: - -```Batchfile -vcpkg install openssl:x64-windows -set VCPKG_ROOT=c:\path\to\vcpkg\installation -cargo build -``` - -For more information see the vcpkg build helper [documentation](http://docs.rs/vcpkg). -To finsh setting up OpenSSL you will need to [install root certificates.](#acquiring-root-certificates) - -#### Acquiring Root Certificates - -Neither of the above OpenSSL distributions ship with any root certificates. -So to make requests to servers on the internet, you have to install them -manually. Download the [cacert.pem file from here], copy it somewhere safe -(`C:\OpenSSL-Win64\certs` is a good place) and point the `SSL_CERT_FILE` -environment variable there: - -``` -set SSL_CERT_FILE=C:\OpenSSL-Win64\certs\cacert.pem -``` - -[cacert.pem file from here]: https://curl.haxx.se/docs/caextract.html - -After that, you're just a `cargo build` away! - -### Windows GNU (MinGW) - -The easiest way to acquire OpenSSL when working with MinGW is to ensure you're -using [MSYS2](http://msys2.github.io) and to then execute: - -``` -# 32-bit -pacman -S mingw-w64-i686-openssl - -# 64-bit -pacman -S mingw-w64-x86_64-openssl -``` - -And after that, a `cargo build` should be all you need! - -### Manual configuration - -rust-openssl's build script will by default attempt to locate OpenSSL via -pkg-config or other system-specific mechanisms. This will not work in some -situations however, for example cross compiling or when using a copy of OpenSSL -other than the normal system install. - -The build script can be configured via environment variables: +[Documentation](https://docs.rs/openssl). -* `OPENSSL_DIR` - If specified, a directory that will be used to find - OpenSSL installation. It's expected that under this directory the `include` - folder has header files and a `lib` folder has the runtime libraries. -* `OPENSSL_LIB_DIR` - If specified, a directory that will be used to find - OpenSSL libraries. Overrides the `lib` folder implied by `OPENSSL_DIR` - (if specified). -* `OPENSSL_INCLUDE_DIR` - If specified, a directory that will be used to find - OpenSSL header files. Overrides the `include` folder implied by `OPENSSL_DIR` - (if specified). -* `OPENSSL_STATIC` - If specified, OpenSSL libraries will be statically rather - than dynamically linked. -* `OPENSSL_LIBS` - If specified, the names of the OpenSSL libraries that will be - linked, e.g. `ssl:crypto`. +## Release Support -If `OPENSSL_DIR` or `OPENSSL_LIB_DIR` and `OPENSSL_INCLUDE_DIR` is specified, -then the build script will skip the pkg-config step. +The current supported release of `openssl` is 0.10 and `openssl-sys` is 0.9. -For target-specific configuration, each of these environment variables can be -prefixed by an upper-cased target, for example, -`X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR`. This can be useful in cross compilation -contexts. +New major versions will be published at most once per year. After a new +release, the previous major version will be partially supported with bug +fixes for 3 months, after which support will be dropped entirely. ### Contribution diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index bae5d62..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,50 +0,0 @@ -environment: - SSL_CERT_FILE: "C:\\OpenSSL\\cacert.pem" - matrix: - # 1.1.0, 64/32 bit - - TARGET: i686-pc-windows-gnu - BITS: 32 - MSYS2: 1 - OPENSSL_VERSION: 1_1_0g - - TARGET: x86_64-pc-windows-msvc - BITS: 64 - OPENSSL_VERSION: 1_1_0g - OPENSSL_DIR: C:\OpenSSL - - # 1.0.2, 64/32 bit - - TARGET: x86_64-pc-windows-gnu - BITS: 64 - MSYS2: 1 - OPENSSL_VERSION: 1_0_2m - - TARGET: i686-pc-windows-msvc - BITS: 32 - OPENSSL_VERSION: 1_0_2m - OPENSSL_DIR: C:\OpenSSL - - TARGET: x86_64-pc-windows-msvc - VCPKG_DEFAULT_TRIPLET: x64-windows - VCPKGRS_DYNAMIC: 1 -install: - # install OpenSSL - - mkdir C:\OpenSSL - - ps: if (Test-Path env:OPENSSL_VERSION) { Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-${env:OPENSSL_VERSION}.exe" } - - if defined OPENSSL_VERSION Win%BITS%OpenSSL-%OPENSSL_VERSION%.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - - appveyor DownloadFile https://curl.haxx.se/ca/cacert.pem -FileName C:\OpenSSL\cacert.pem - - # Install Rust - - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - - rustup-init.exe -y --default-host %TARGET% - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH% - - rustc -V - - cargo -V - - if defined VCPKG_DEFAULT_TRIPLET git clone https://github.com/Microsoft/vcpkg c:\projects\vcpkg - - if defined VCPKG_DEFAULT_TRIPLET c:\projects\vcpkg\bootstrap-vcpkg.bat - - if defined VCPKG_DEFAULT_TRIPLET set VCPKG_ROOT=c:\projects\vcpkg - - if defined VCPKG_DEFAULT_TRIPLET echo yes > %VCPKG_ROOT%\Downloads\AlwaysAllowDownloads - - if defined VCPKG_DEFAULT_TRIPLET %VCPKG_ROOT%\vcpkg.exe install openssl - -build: false - -test_script: - - cargo run --manifest-path systest/Cargo.toml --target %TARGET% - - cargo test --manifest-path openssl/Cargo.toml --target %TARGET% diff --git a/openssl-errors/CHANGELOG.md b/openssl-errors/CHANGELOG.md new file mode 100644 index 0000000..50610a9 --- /dev/null +++ b/openssl-errors/CHANGELOG.md @@ -0,0 +1,20 @@ +# Change Log + +## [Unreleased] + +## [v0.2.0] - 2021-06-18 + +### Changed + +* Constructors and accessors on the `Function` and `Reason` types have been made private APIs. + +### Added + +* Added support for OpenSSL 3.x.x. + +## v0.1.0 - 2019-03-14 + +Initial release + +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-errors-v0.2.0...master +[v0.2.0]: https://github.com/sfackler/rust-openssl/compare/openssl-errors-v0.1.0...openssl-errors-v0.2.0 diff --git a/openssl-errors/Cargo.toml b/openssl-errors/Cargo.toml new file mode 100644 index 0000000..1f60f0e --- /dev/null +++ b/openssl-errors/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "openssl-errors" +version = "0.2.0" +authors = ["Steven Fackler "] +edition = "2018" +license = "MIT/Apache-2.0" +description = "Custom error library support for the openssl crate." +repository = "https://github.com/sfackler/rust-openssl" +readme = "README.md" +categories = ["api-bindings"] + +[dependencies] +cfg-if = "1.0" +libc = "0.2" + +openssl-sys = { version = "0.9.64", path = "../openssl-sys" } + +[dev-dependencies] +openssl = { version = "0.10.19", path = "../openssl" } diff --git a/openssl-errors/LICENSE-APACHE b/openssl-errors/LICENSE-APACHE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/openssl-errors/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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-errors/LICENSE-MIT b/openssl-errors/LICENSE-MIT new file mode 100644 index 0000000..7c3deb5 --- /dev/null +++ b/openssl-errors/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2019 Steven Fackler + +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-errors/README.md b/openssl-errors/README.md new file mode 100644 index 0000000..32d46ee --- /dev/null +++ b/openssl-errors/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/openssl-errors/build.rs b/openssl-errors/build.rs new file mode 100644 index 0000000..5ecd7ba --- /dev/null +++ b/openssl-errors/build.rs @@ -0,0 +1,13 @@ +#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] + +use std::env; + +fn main() { + if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&version, 16).unwrap(); + + if version >= 0x3_00_00_00_0 { + println!("cargo:rustc-cfg=ossl300"); + } + } +} diff --git a/openssl-errors/src/lib.rs b/openssl-errors/src/lib.rs new file mode 100644 index 0000000..30abc67 --- /dev/null +++ b/openssl-errors/src/lib.rs @@ -0,0 +1,388 @@ +//! Custom error library support for the `openssl` crate. +//! +//! OpenSSL allows third-party libraries to integrate with its error API. This crate provides a safe interface to that. +//! +//! # Examples +//! +//! ``` +//! use openssl_errors::{openssl_errors, put_error}; +//! use openssl::error::Error; +//! +//! // Errors are organized at the top level into "libraries". The +//! // openssl_errors! macro can define these. +//! // +//! // Libraries contain a set of functions and reasons. The library itself, +//! // its functions, and its definitions all all have an associated message +//! // string. This string is what's shown in OpenSSL errors. +//! // +//! // The macro creates a type for each library with associated constants for +//! // its functions and reasons. +//! openssl_errors! { +//! pub library MyLib("my cool library") { +//! functions { +//! FIND_PRIVATE_KEY("find_private_key"); +//! } +//! +//! reasons { +//! IO_ERROR("IO error"); +//! BAD_PASSWORD("invalid private key password"); +//! } +//! } +//! } +//! +//! // The put_error! macro pushes errors onto the OpenSSL error stack. +//! put_error!(MyLib::FIND_PRIVATE_KEY, MyLib::BAD_PASSWORD); +//! +//! // Prints `error:80001002:my cool library:find_private_key:invalid private key password:src/lib.rs:27:` +//! println!("{}", Error::get().unwrap()); +//! +//! // You can also optionally attach an extra string of context using the +//! // standard Rust format syntax. +//! let tries = 2; +//! put_error!(MyLib::FIND_PRIVATE_KEY, MyLib::IO_ERROR, "tried {} times", tries); +//! +//! // Prints `error:80001001:my cool library:find_private_key:IO error:src/lib.rs:34:tried 2 times` +//! println!("{}", Error::get().unwrap()); +//! ``` +#![warn(missing_docs)] +#![doc(html_root_url = "https://docs.rs/openssl-errors/0.2")] + +use cfg_if::cfg_if; +use libc::{c_char, c_int}; +use std::borrow::Cow; +use std::marker::PhantomData; +use std::ptr; + +#[doc(hidden)] +pub mod export { + pub use libc::{c_char, c_int}; + pub use openssl_sys::{ + init, ERR_get_next_error_library, ERR_load_strings, ERR_PACK, ERR_STRING_DATA, + }; + pub use std::borrow::Cow; + pub use std::option::Option; + pub use std::ptr::null; + pub use std::sync::Once; +} + +/// An OpenSSL error library. +pub trait Library { + /// Returns the ID assigned to this library by OpenSSL. + fn id() -> c_int; +} + +cfg_if! { + if #[cfg(ossl300)] { + type FunctionInner = *const c_char; + } else { + type FunctionInner = c_int; + } +} + +/// A function declaration, parameterized by its error library. +pub struct Function(FunctionInner, PhantomData); + +// manual impls necessary for the 3.0.0 case +unsafe impl Sync for Function where T: Sync {} +unsafe impl Send for Function where T: Send {} + +impl Function { + /// This is not considered a part of the crate's public API, and is subject to change at any time. + /// + /// # Safety + /// + /// The inner value must be valid for the lifetime of the process. + #[doc(hidden)] + #[inline] + pub const unsafe fn __from_raw(raw: FunctionInner) -> Function { + Function(raw, PhantomData) + } + + /// This is not considered a part of the crate's public API, and is subject to change at any time. + #[doc(hidden)] + #[inline] + pub const fn __as_raw(&self) -> FunctionInner { + self.0 + } +} + +/// A reason declaration, parameterized by its error library. +pub struct Reason(c_int, PhantomData); + +impl Reason { + /// This is not considered a part of the crate's public API, and is subject to change at any time. + #[doc(hidden)] + #[inline] + pub const fn __from_raw(raw: c_int) -> Reason { + Reason(raw, PhantomData) + } + + /// This is not considered a part of the crate's public API, and is subject to change at any time. + #[doc(hidden)] + #[inline] + pub const fn __as_raw(&self) -> c_int { + self.0 + } +} + +/// This is not considered part of this crate's public API. It is subject to change at any time. +/// +/// # Safety +/// +/// `file` and `message` must be null-terminated. +#[doc(hidden)] +pub unsafe fn __put_error( + func: Function, + reason: Reason, + file: &'static str, + line: u32, + message: Option>, +) where + T: Library, +{ + put_error_inner(T::id(), func.0, reason.0, file, line, message) +} + +unsafe fn put_error_inner( + library: c_int, + func: FunctionInner, + reason: c_int, + file: &'static str, + line: u32, + message: Option>, +) { + cfg_if! { + if #[cfg(ossl300)] { + openssl_sys::ERR_new(); + openssl_sys::ERR_set_debug( + file.as_ptr() as *const c_char, + line as c_int, + func, + ); + openssl_sys::ERR_set_error(library, reason, ptr::null()); + } else { + openssl_sys::ERR_put_error( + library, + func, + reason, + file.as_ptr() as *const c_char, + line as c_int, + ); + } + } + + let data = match message { + Some(Cow::Borrowed(s)) => Some((s.as_ptr() as *const c_char as *mut c_char, 0)), + Some(Cow::Owned(s)) => { + let ptr = openssl_sys::CRYPTO_malloc( + s.len() as _, + concat!(file!(), "\0").as_ptr() as *const c_char, + line!() as c_int, + ) as *mut c_char; + if ptr.is_null() { + None + } else { + ptr::copy_nonoverlapping(s.as_ptr(), ptr as *mut u8, s.len()); + Some((ptr, openssl_sys::ERR_TXT_MALLOCED)) + } + } + None => None, + }; + if let Some((ptr, flags)) = data { + openssl_sys::ERR_set_error_data(ptr, flags | openssl_sys::ERR_TXT_STRING); + } +} + +/// Pushes an error onto the OpenSSL error stack. +/// +/// A function and reason are required, and must be associated with the same error library. An additional formatted +/// message string can also optionally be provided. +#[macro_export] +macro_rules! put_error { + ($function:expr, $reason:expr) => { + unsafe { + $crate::__put_error( + $function, + $reason, + concat!(file!(), "\0"), + line!(), + $crate::export::Option::None, + ); + } + }; + ($function:expr, $reason:expr, $message:expr) => { + unsafe { + $crate::__put_error( + $function, + $reason, + concat!(file!(), "\0"), + line!(), + // go through format_args to ensure the message string is handled in the same way as the args case + $crate::export::Option::Some($crate::export::Cow::Borrowed( + format_args!(concat!($message, "\0")).as_str().unwrap(), + )), + ); + } + }; + ($function:expr, $reason:expr, $message:expr, $($args:tt)*) => { + unsafe { + $crate::__put_error( + $function, + $reason, + concat!(file!(), "\0"), + line!(), + $crate::export::Option::Some($crate::export::Cow::Owned( + format!(concat!($message, "\0"), $($args)*)), + ), + ); + } + }; +} + +/// Defines custom OpenSSL error libraries. +/// +/// The created libraries can be used with the `put_error!` macro to create custom OpenSSL errors. +#[macro_export] +macro_rules! openssl_errors { + ($( + $(#[$lib_attr:meta])* + $lib_vis:vis library $lib_name:ident($lib_str:expr) { + functions { + $( + $(#[$func_attr:meta])* + $func_name:ident($func_str:expr); + )* + } + + reasons { + $( + $(#[$reason_attr:meta])* + $reason_name:ident($reason_str:expr); + )* + } + } + )*) => {$( + $(#[$lib_attr])* + $lib_vis enum $lib_name {} + + impl $crate::Library for $lib_name { + fn id() -> $crate::export::c_int { + static INIT: $crate::export::Once = $crate::export::Once::new(); + static mut LIB_NUM: $crate::export::c_int = 0; + $crate::__openssl_errors_helper! { + @strings $lib_name($lib_str) + functions { $($func_name($func_str);)* } + reasons { $($reason_name($reason_str);)* } + } + + unsafe { + INIT.call_once(|| { + $crate::export::init(); + LIB_NUM = $crate::export::ERR_get_next_error_library(); + STRINGS[0].error = $crate::export::ERR_PACK(LIB_NUM, 0, 0); + $crate::export::ERR_load_strings(LIB_NUM, STRINGS.as_mut_ptr()); + }); + + LIB_NUM + } + } + } + + impl $lib_name { + $crate::openssl_errors!(@func_consts $lib_name; 1; $($(#[$func_attr])* $func_name($func_str);)*); + $crate::openssl_errors!(@reason_consts $lib_name; 1; $($(#[$reason_attr])* $reason_name;)*); + } + )*}; + (@func_consts $lib_name:ident; $n:expr; $(#[$attr:meta])* $name:ident($str:expr); $($tt:tt)*) => { + $(#[$attr])* + pub const $name: $crate::Function<$lib_name> = unsafe { + $crate::Function::__from_raw($crate::__openssl_errors_helper!(@func_value $n, $str)) + }; + $crate::openssl_errors!(@func_consts $lib_name; $n + 1; $($tt)*); + }; + (@func_consts $lib_name:ident; $n:expr;) => {}; + (@reason_consts $lib_name:ident; $n:expr; $(#[$attr:meta])* $name:ident; $($tt:tt)*) => { + $(#[$attr])* + pub const $name: $crate::Reason<$lib_name> = $crate::Reason::__from_raw($n); + $crate::openssl_errors!(@reason_consts $lib_name; $n + 1; $($tt)*); + }; + (@reason_consts $lib_name:ident; $n:expr;) => {}; + (@count $i:ident; $($tt:tt)*) => { + 1 + $crate::openssl_errors!(@count $($tt)*) + }; + (@count) => { 0 }; +} + +cfg_if! { + if #[cfg(ossl300)] { + #[doc(hidden)] + #[macro_export] + macro_rules! __openssl_errors_helper { + ( + @strings $lib_name:ident($lib_str:expr) + functions { $($func_name:ident($func_str:expr);)* } + reasons { $($reason_name:ident($reason_str:expr);)* } + ) => { + static mut STRINGS: [ + $crate::export::ERR_STRING_DATA; + 2 + $crate::openssl_errors!(@count $($reason_name;)*) + ] = [ + $crate::export::ERR_STRING_DATA { + error: 0, + string: concat!($lib_str, "\0").as_ptr() as *const $crate::export::c_char, + }, + $( + $crate::export::ERR_STRING_DATA { + error: $crate::export::ERR_PACK(0, 0, $lib_name::$reason_name.__as_raw()), + string: concat!($reason_str, "\0").as_ptr() as *const $crate::export::c_char, + }, + )* + $crate::export::ERR_STRING_DATA { + error: 0, + string: $crate::export::null(), + } + ]; + }; + (@func_value $n:expr, $func_str:expr) => { + concat!($func_str, "\0").as_ptr() as *const $crate::export::c_char + }; + } + } else { + #[doc(hidden)] + #[macro_export] + macro_rules! __openssl_errors_helper { + ( + @strings $lib_name:ident($lib_str:expr) + functions { $($func_name:ident($func_str:expr);)* } + reasons { $($reason_name:ident($reason_str:expr);)* } + ) => { + static mut STRINGS: [ + $crate::export::ERR_STRING_DATA; + 2 + $crate::openssl_errors!(@count $($func_name;)* $($reason_name;)*) + ] = [ + $crate::export::ERR_STRING_DATA { + error: 0, + string: concat!($lib_str, "\0").as_ptr() as *const $crate::export::c_char, + }, + $( + $crate::export::ERR_STRING_DATA { + error: $crate::export::ERR_PACK(0, $lib_name::$func_name.__as_raw(), 0), + string: concat!($func_str, "\0").as_ptr() as *const $crate::export::c_char, + }, + )* + $( + $crate::export::ERR_STRING_DATA { + error: $crate::export::ERR_PACK(0, 0, $lib_name::$reason_name.__as_raw()), + string: concat!($reason_str, "\0").as_ptr() as *const $crate::export::c_char, + }, + )* + $crate::export::ERR_STRING_DATA { + error: 0, + string: $crate::export::null(), + } + ]; + }; + (@func_value $n:expr, $func_str:expr) => {$n}; + } + } +} diff --git a/openssl-errors/tests/test.rs b/openssl-errors/tests/test.rs new file mode 100644 index 0000000..98259b9 --- /dev/null +++ b/openssl-errors/tests/test.rs @@ -0,0 +1,95 @@ +use cfg_if::cfg_if; +use openssl::error::Error; + +openssl_errors::openssl_errors! { + library Test("test library") { + functions { + FOO("function foo"); + BAR("function bar"); + } + + reasons { + NO_MILK("out of milk"); + NO_BACON("out of bacon"); + } + } +} + +#[test] +fn basic() { + openssl_errors::put_error!(Test::FOO, Test::NO_MILK); + + let error = Error::get().unwrap(); + assert_eq!(error.library().unwrap(), "test library"); + assert_eq!(error.function().unwrap(), "function foo"); + assert_eq!(error.reason().unwrap(), "out of milk"); + // Replace Windows `\` separators with `/` + assert_eq!( + error.file().replace('\\', "/"), + "openssl-errors/tests/test.rs" + ); + assert_eq!(error.line(), line!() - 11); + cfg_if! { + if #[cfg(ossl300)] { + // https://github.com/openssl/openssl/issues/12530 + assert!(error.data().is_none() || error.data() == Some("")); + } else { + assert_eq!(error.data(), None); + } + } +} + +#[test] +fn static_data() { + openssl_errors::put_error!(Test::BAR, Test::NO_BACON, "foobar {{}}"); + + let error = Error::get().unwrap(); + assert_eq!(error.library().unwrap(), "test library"); + assert_eq!(error.function().unwrap(), "function bar"); + assert_eq!(error.reason().unwrap(), "out of bacon"); + // Replace Windows `\` separators with `/` + assert_eq!( + error.file().replace('\\', "/"), + "openssl-errors/tests/test.rs" + ); + assert_eq!(error.line(), line!() - 11); + assert_eq!(error.data(), Some("foobar {}")); +} + +#[test] +fn dynamic_data() { + openssl_errors::put_error!(Test::BAR, Test::NO_MILK, "hello {}", "world"); + + let error = Error::get().unwrap(); + assert_eq!(error.library().unwrap(), "test library"); + assert_eq!(error.function().unwrap(), "function bar"); + assert_eq!(error.reason().unwrap(), "out of milk"); + // Replace Windows `\` separators with `/` + assert_eq!( + error.file().replace('\\', "/"), + "openssl-errors/tests/test.rs" + ); + assert_eq!(error.line(), line!() - 11); + assert_eq!(error.data(), Some("hello world")); +} + +#[test] +fn deferred_error_render() { + openssl_errors::put_error!(Test::BAR, Test::NO_MILK); + + let error = Error::get().unwrap(); + + for _ in 0..100 { + openssl_errors::put_error!(Test::FOO, Test::NO_BACON); + } + + assert_eq!(error.function().unwrap(), "function bar"); + // Replace Windows `\` separators with `/` + assert_eq!( + error.file().replace('\\', "/"), + "openssl-errors/tests/test.rs" + ); + + // clear out the stack for other tests on the same thread + while Error::get().is_some() {} +} diff --git a/openssl-macros/Cargo.toml b/openssl-macros/Cargo.toml new file mode 100644 index 0000000..d55f226 --- /dev/null +++ b/openssl-macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "openssl-macros" +version = "0.1.0" +edition = "2018" +license = "MIT/Apache-2.0" +description = "Internal macros used by the openssl crate." + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1" +quote = "1" +syn = { version = "1", features = ["full"] } diff --git a/openssl-macros/LICENSE-APACHE b/openssl-macros/LICENSE-APACHE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/openssl-macros/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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-macros/LICENSE-MIT b/openssl-macros/LICENSE-MIT new file mode 100644 index 0000000..743bbf8 --- /dev/null +++ b/openssl-macros/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2022 Steven Fackler + +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-macros/src/lib.rs b/openssl-macros/src/lib.rs new file mode 100644 index 0000000..99db988 --- /dev/null +++ b/openssl-macros/src/lib.rs @@ -0,0 +1,32 @@ +#![allow(clippy::uninlined_format_args)] + +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-sys/CHANGELOG.md b/openssl-sys/CHANGELOG.md new file mode 100644 index 0000000..3cb0711 --- /dev/null +++ b/openssl-sys/CHANGELOG.md @@ -0,0 +1,442 @@ +# Change Log + +## [Unreleased] + +## [v0.9.82] - 2023-03-19 + +### Added + +* Added support for LibreSSL 3.7.1. +* Added support for X25519 and Ed25519 on LibreSSL and BoringSSL. + +## [v0.9.81] - 2023-03-14 + +### Fixed + +Fixed builds against OpenSSL built with `no-cast`. + +### Added + +* Added experimental bindgen support for BoringSSL. +* Added `X509_VERIFY_PARAM_set_auth_level`, `X509_VERIFY_PARAM_get_auth_level`, and `X509_VERIFY_PARAM_set_purpose`. +* Added `X509_PURPOSE_*` consts. +* Added `X509_NAME_add_entry`. +* Added `X509_load_crl_file`. +* Added `SSL_set_cipher_list`, `SSL_set_ssl_method`, `SSL_use_PrivateKey_file`, `SSL_use_PrivateKey`, `SSL_use_certificate`, `SSL_use_certificate_chain_file`, `SSL_set_client_CA_list`, `SSL_add_client_CA`, and `SSL_set0_verify_cert_store`. +* Added `X509_PURPOSE`, `X509_STORE_set_purpose`, and `X509_STORE_set_trust`. +* Added `SSL_CTX_set_num_tickets`, `SSL_set_num_tickets`, `SSL_CTX_get_num_tickets`, and `SSL_get_num_tickets`. +* Added `CMS_verify`. + +### Removed + +* Removed an unnecessary link to libatomic for 32-bit android targets. + +## [v0.9.80] - 2022-12-20 + +### Fixed + +* Added `NO_DEPRECATED_3_0` cfg checks for more APIs. + +### Added + +* Added support for LibreSSL 3.7.0. +* Added `SSL_CTRL_CHAIN_CERT` and `SSL_add0_chain_cert`. +* Added `EVP_PKEY_get_security_bits` and `EVP_PKEY_security_bits`. +* Added `OSSL_PROVIDER_set_default_search_path`. + +## [v0.9.79] - 2022-12-06 + +### Added + +* Added `EVP_CIPHER_CTX_num`. +* Added `X509_LOOKUP_file` and `X509_load_cert_file`. + +## [v0.9.78] - 2022-11-23 + +### Added + +* Added support for LibreSSL 3.6.x. +* Added `NID_brainpoolP256r1`, `NID_brainpoolP384r1`, and `NID_brainpool512r1`. +* Added `EVP_camellia_128_cfb128`, `EVP_camellia_128_ecb`, `EVP_camellia_192_cfb128`, `EVP_camellia_192_ecb`, + `EVP_camellia_256_cfb128`, and `EVP_camellia_256_ecb`. +* Added `EVP_cast5_cfb64` and `EVP_cast5_ecb`. +* Added `EVP_idea_cfb64` and `EVP_idea_ecb`. +* Added `DSA_SIG`, `d2i_DSA_SIG`, `i2d_DSA_SIG`, `DSA_SIG_new`, `DSA_SIG_free`, `DSA_SIG_get0`, and `DSA_SIG_set0`. +* Added `X509_STORE_set1_param`, `X509_VERIFY_PARAM_new`, `X509_VERIFY_PARAM_set_time`, and + `X509_VERIFY_PARAM_set_depth`. + +## [v0.9.77] - 2022-10-22 + +### Added + +* Added support for LibreSSL 3.6.0 +* Added `assume_init`. + +## [v0.9.76] - 2022-09-26 + +### Added + +* Added `SSL_get_psk_identity_hint` and `SSL_get_psk_identity`. +* Added SHA-3 NID constants. +* Added `SSL_OP_PRIORITIZE_CHACHA`. +* Added `X509_REQ_print`. +* Added `EVP_MD_CTX_size` and `EVP_MD_CTX_get_size` +* Added `EVP_MD_CTX_reset`. +* Added experimental, unstable support for BoringSSL. + +### Fixed + +* Fixed the deprecation note on `SSL_CTX_set_alpn_select_cb`. + +## [v0.9.75] - 2022-07-09 + +### Added + +* Added SM4 bindings. +* Added `EC_GROUP_set_generator` and `EC_POINT_set_affine_coordinates_GFp`. + +## [v0.9.74] - 2022-06-01 + +### Added + +* Added `EVP_MD_block_size`. +* Added `X509V3_EXT_add_alias`. +* Added `X509_V_ERR_INVALID_CA` back when building against OpenSSL 3.0. + +## [v0.9.73] - 2022-05-02 + +### Added + +* Added support for installations that place libraries in `$OPENSSL_DIR/lib64` in addition to `$OPENSSL_DIR/lib`. +* Added `X509_issuer_name_hash`. +* Added `ASN1_string_set`. +* Added `X509_CRL_dup`, `X509_REQ_dup`, `X509_NAME_dup`, and `X509_dup`. +* Added `X509_print`. +* Added support for LibreSSL 3.5.x. + +## [v0.9.72] - 2021-12-11 + +### Changed + +* Temporarily downgraded the vendored OpenSSL back to 1.1.1 due to significant performance regressions. We will move + back to 3.0.0 when a future release resolves those issues. + +### Added + +* Added `PKCS12_set_mac`. +* Added `EVP_PKEY_sign_init`, `EVP_PKEY_sign`, `EVP_PKEY_verify_init`, and `EVP_PKEY_verify`. +* Added support for LibreSSL 3.4.x. + +## [v0.9.71] + +### Fixed + +* Fixed linkage to static OpenSSL 3.0.0 libraries on some 32 bit Android targets. + +### Added + +* Added support for LibreSSL 3.4.1. +* Added `SSL_get_extms_support` and `SSL_CTRL_GET_EXTMS_SUPPORT`. +* Added `OBJ_create`. +* Added `EVP_CIPHER_CTX_get0_cipher`, `EVP_CIPHER_CTX_get_block_size`, `EVP_CIPHER_CTX_get_key_length`, + `EVP_CIPHER_CTX_get_iv_length`, and `EVP_CIPHER_CTX_get_tag_length`. +* Added `EVP_CIPHER_free`. +* Added `EVP_CIPHER_CTX_rand_key`. +* Added `OSSL_LIB_CTX_new` and `OSSL_LIB_CTX_free`. +* Added `EVP_CIPHER_fetch`. +* Added `EVP_MD_fetch` and `EVP_MD_free`. +* Added `OPENSSL_malloc` and `OPENSSL_free`. +* Added `EVP_DigestSignUpdate` and `EVP_DigestVerifyUpdate`. + +## [v0.9.70] - 2021-10-31 + +### Fixed + +* Fixed linkage to static 3.0.0 OpenSSL libraries on some 32 bit architectures. + +## [v0.9.69] - 2021-10-31 + +### Changed + +* Upgraded the vendored OpenSSL to 3.0.0. + +### Added + +* Added support for automatic detection of Homebrew `openssl@3` installs. +* Added `EVP_PKEY_Q_keygen` and `EVP_EC_gen`. + +## [v0.9.68] - 2021-10-27 + +### Added + +* Added `BN_bn2binpad`. +* Added `i2d_X509_NAME` and `d2i_X509_NAME`. +* Added `BN_FLG_MALLOCED`, `BN_FLG_STATIC_DATA`, `BN_FLG_CONSTTIME`, and `BN_FLG_SECURE`. +* Added `BN_CTX_secure_new`, `BN_secure_new`, `BN_set_flags`, and `BN_get_flags`. + +## [v0.9.67] - 2021-09-21 + +### Added + +* Added support for LibreSSL 3.4.0 + +## [v0.9.66] - 2021-08-17 + +### Added + +* Added `EVP_seed_cbc`, `EVP_seed_cfb128`, `EVP_seed_ecb`, and `EVP_seed_ofb`. +* Added `OBJ_length` and `OBJ_get0_data`. +* Added `i2d_PKCS8PrivateKey_bio`. + +## [v0.9.65] - 2021-06-21 + +### Fixed + +* Restored the accidentally deleted `PEM_read_bio_X509_CRL` function. + +## [v0.9.64] - 2021-06-18 + +### Added + +* Added support for OpenSSL 3.x.x. +* Added `SSL_peek`. +* Added `ERR_LIB_ASN1` and `ASN1_R_HEADER_TOO_LONG`. +* Added `d2i_X509_bio`. +* Added `OBJ_nid2obj`. +* Added `RAND_add`. +* Added `SSL_CTX_set_post_handshake_auth`. +* Added `COMP_get_type`. +* Added `X509_get_default_cert_file_env`, `X509_get_default_cert_file`, `X509_get_default_cert_dir_env`, and + `X509_get_default_cirt_dir`. + +## [v0.9.63] - 2021-05-06 + +### Added + +* Added support for LibreSSL 3.3.x. + +## [v0.9.62] - 2021-04-28 + +### Added + +* Added support for LibreSSL 3.3.2. +* Added `DH_set0_key`. +* Added `EC_POINT_get_affine_coordinates`. + +## [v0.9.61] - 2021-03-13 + +### Added + +* Added support for automatic detection of OpenSSL installations via pkgsrc and MacPorts on macOS. +* Added various `V_ASN1_*` constants. +* Added `DH_generate_parameters_ex`. +* Added `EC_POINT_is_at_infinity` and `EC_POINT_is_on_curve`. +* Added `EVP_CIPHER_nid`. +* Added `EVP_sm3`. +* Added `NID_*` constants related to SM3. +* Added `PKCS7_get0_signers`. +* Added `EVP_PKEY_CTX_set0_rsa_oaep_label`. +* Added `ACCESS_DESCRIPTION` and `ACCESS_DESCRIPTION_free`. + +## [v0.9.60] - 2020-12-24 + +### Added + +* Added support for the default Homebrew install directory on ARM. +* Added `EVP_PKEY_CTX_set_rsa_oaep_md` and `EVP_PKEY_CTRL_RSA_OAEP_MD`. + +## [v0.9.59] - 2020-12-09 + +### Added + +* Added support for LibreSSL 3.2.x, 3.3.0, and 3.3.1. +* Added `DH_generate_parameters`, `DH_generate_key`, `DH_compute_key`, and `DH_size`. +* Added `NID_X25519`, `NID_X448`, `EVP_PKEY_x25519` and `EVP_PKEY_x448`. +* Added `OBJ_txt2obj`. +* Added `d2i_PKCS7` and `i2d_PKCS7`. +* Added `SRTP_AEAD_AES_128_GCM` and `SRTP_AEAD_AES_256_GCM`. + +## [v0.9.58] - 2020-06-05 + +### Added + +* Added `SSL_set_mtu`. +* Added support for LibreSSL 3.2.0. +* Added `PEM_read_bio_EC_PUBKEY`, `PEM_write_bio_EC_PUBKEY`, `d2i_EC_PUBKEY`, and `i2d_EC_PUBKEY`. +* Added `EVP_PKEY_encrypt_init`, `EVP_PKEY_encrypt`, `EVP_PKEY_decrypt_init`, `EVP_PKEY_decrypt`, + `EVP_PKEY_get_raw_public_key`, `EVP_PKEY_new_raw_public_key`, `EVP_PKEY_get_raw_private_key`, + and `EVP_PKEY_new_raw_private_key`. +* Added `OBJ_sn2nid`. + +## [v0.9.57] - 2020-05-24 + +### Added + +* Added support for LibreSSL 3.1.x. + +## [v0.9.56] - 2020-05-07 + +### Fixed + +* Fixed vendored builds on windows-gnu targets. + +### Added + +* Added support for LibreSSL 3.0.0. + +## [v0.9.55] - 2020-04-07 + +### Fixed + +* Fixed windows-msvc library names when using OpenSSL from vcpkg. + +### Added + +* If the `OPENSSL_NO_VENDOR` environment variable is set, vendoring will not be used even if enabled. +* Added `SSL_CTX_get_verify_mode` and `SSL_get_verify_mode`. +* Added `SSL_is_init_finished`. +* Added `SSL_CTX_set_cert_store`. +* Added `TLS_server_method` and `TLS_client_method`. +* Added `X509_STORE_get0_objects`. +* Added `X509_OBJECT_free`, `X509_OBJECT_get_type`, and `X509_OBJECT_get0_X509`. + +## [v0.9.54] - 2020-01-29 + +### Added + +* Added `BIO_CTRL_DGRAM_QUERY_MTU`. +* Added `EVP_EncryptInit_ex`, `EVP_EncryptFinal_ex`, `EVP_DecryptInit_ex`, and `EVP_DecryptFinal_ex`. +* Added `EVP_md_null`. +* Added `EVP_PKCS82PKEY`. +* Added `PKCS8_PRIV_KEY_INFO`, `d2i_PKCS8_PRIV_KEY_INFO`, and `PKCS8_PRIV_KEY_INFO_free`. +* Added `SSL_OP_NO_RENEGOTIATION`. + +## [v0.9.53] - 2019-11-22 + +### Added + +* Added `ASN1_TIME_diff`. +* Added `EC_GROUP_order_bits`. +* Added `EVP_EncodeBlock` and `EVP_DecodeBlock`. +* Added `SSL_CTRL_SET_GROUPS_LIST`, `SSL_CTRL_SET_SIGALGS_LIST`, `SSL_CTX_set1_groups_list`, and + `SSL_CTX_set1_sigalgs_list`. +* Added `Clone` implementations to `SHA_CTX`, `SHA256_CTX`, and `SHA512_CTX`. + +## [v0.9.52] - 2019-10-19 + +### Added + +* Added support for LibreSSL 3.0.x. + +## [v0.9.51] - 2019-10-02 + +### Added + +* Added support for LibreSSL 3.0.1. + +## [v0.9.50] - 2019-10-02 + +### Added + +* Added `CRYPTO_LOCK_EVP_PKEY`. +* Added `EVP_PKEY_ED25519` and `EVP_PKEY_ED448`. +* Added `EVP_DigestSign` and `EVP_DigestVerify`. +* Added `EVP_PKEY_up_ref`. +* Added `NID_ED25519` and `NID_ED448`. + +## [v0.9.49] - 2019-08-15 + +### Added + +* Added support for LibreSSL 3.0.0. + +## [v0.9.48] - 2019-07-19 + +### Added + +* Added `AES_wrap_key` and `AES_unwrap_key`. +* Added `EC_GROUP_get_cofactor`, `EC_GROUP_get0_generator`, and `EC_POINT_dup`. +* Added `EVP_aes_128_ofb`, `EVP_aes_192_ecb`, `EVP_aes_192_cbc`, `EVP_aes_192_cfb1`, `EVP_aes_192_cfb8`, + `EVP_aes_192_cfb_128`, `EVP_aes_192_ctr`, `EVP_aes_192_ccm`, `EVP_aes_192_gcm`, `EVP_aes_192_ofb`, and + `EVP_aes_256_ofb`. +* Added `PEM_read_bio_CMS` and `PEM_write_bio_CMS`. + +## [v0.9.47] - 2019-05-18 + +### Added + +* Added `SSL_CTX_add_client_CA`. + +## [v0.9.46] - 2019-05-08 + +### Added + +* Added support for the LibreSSL 2.9.x series. + +## [v0.9.45] - 2019-05-03 + +### Fixed + +* Reverted a change to windows-gnu library names that caused regressions. + +## [v0.9.44] - 2019-04-30 + +### Added + +* The `DEP_OPENSSL_VENDORED` environment variable tells downstream build scripts if the vendored feature was enabled. +* Added `EVP_SealInit`, `EVP_SealFinal`, `EVP_EncryptUpdate`, `EVP_OpenInit`, `EVP_OpenFinal`, and `EVP_DecryptUpdate`. +* Added `EVP_PKEY_size`. + +### Fixed + +* Fixed library names when targeting windows-gnu and pkg-config fails. + +## [v0.9.43] - 2019-03-20 + +### Added + +* Added `d2i_CMS_ContentInfo` and `CMS_encrypt`. +* Added `X509_verify` and `X509_REQ_verify`. +* Added `EVP_MD_type` and `EVP_GROUP_get_curve_name`. + +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.82..master +[v0.9.82]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.81...openssl-sys-v0.9.82 +[v0.9.81]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.80...openssl-sys-v0.9.81 +[v0.9.80]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.79...openssl-sys-v0.9.80 +[v0.9.79]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.78...openssl-sys-v0.9.79 +[v0.9.78]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.77...openssl-sys-v0.9.78 +[v0.9.77]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.76...openssl-sys-v0.9.77 +[v0.9.76]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.75...openssl-sys-v0.9.76 +[v0.9.75]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.74...openssl-sys-v0.9.75 +[v0.9.74]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.73...openssl-sys-v0.9.74 +[v0.9.73]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.72...openssl-sys-v0.9.73 +[v0.9.72]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.71...openssl-sys-v0.9.72 +[v0.9.71]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.70...openssl-sys-v0.9.71 +[v0.9.70]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.69...openssl-sys-v0.9.70 +[v0.9.69]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.68...openssl-sys-v0.9.69 +[v0.9.68]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.67...openssl-sys-v0.9.68 +[v0.9.67]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.66...openssl-sys-v0.9.67 +[v0.9.66]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.65...openssl-sys-v0.9.66 +[v0.9.65]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.64...openssl-sys-v0.9.65 +[v0.9.64]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.63...openssl-sys-v0.9.64 +[v0.9.63]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.62...openssl-sys-v0.9.63 +[v0.9.62]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.61...openssl-sys-v0.9.62 +[v0.9.61]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.60...openssl-sys-v0.9.61 +[v0.9.60]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.59...openssl-sys-v0.9.60 +[v0.9.59]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.58...openssl-sys-v0.9.59 +[v0.9.58]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.57...openssl-sys-v0.9.58 +[v0.9.57]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.56...openssl-sys-v0.9.57 +[v0.9.56]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.55...openssl-sys-v0.9.56 +[v0.9.55]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.54...openssl-sys-v0.9.55 +[v0.9.54]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.53...openssl-sys-v0.9.54 +[v0.9.53]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.52...openssl-sys-v0.9.53 +[v0.9.52]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.51...openssl-sys-v0.9.52 +[v0.9.51]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.50...openssl-sys-v0.9.51 +[v0.9.50]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.49...openssl-sys-v0.9.50 +[v0.9.49]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.48...openssl-sys-v0.9.49 +[v0.9.48]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.47...openssl-sys-v0.9.48 +[v0.9.47]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.46...openssl-sys-v0.9.47 +[v0.9.46]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.45...openssl-sys-v0.9.46 +[v0.9.45]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.44...openssl-sys-v0.9.45 +[v0.9.44]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.43...openssl-sys-v0.9.44 +[v0.9.43]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.42...openssl-sys-v0.9.43 diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 01d6359..ed3161c 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,25 +1,36 @@ [package] name = "openssl-sys" -version = "0.9.23" -authors = ["Alex Crichton ", - "Steven Fackler "] +version = "0.9.82" +authors = [ + "Alex Crichton ", + "Steven Fackler ", +] license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" readme = "README.md" categories = ["cryptography", "external-ffi-bindings"] links = "openssl" -build = "build.rs" +build = "build/main.rs" +edition = "2018" + +[features] +vendored = ['openssl-src'] +unstable_boringssl = ['bssl-sys'] [dependencies] libc = "0.2" +bssl-sys = { version = "0.1.0", optional = true } [build-dependencies] -pkg-config = "0.3.9" +bindgen = { version = "0.64.0", optional = true, features = ["experimental"] } cc = "1.0" +openssl-src = { version = "111", optional = true } +pkg-config = "0.3.9" +autocfg = "1.0" [target.'cfg(target_env = "msvc")'.build-dependencies] -vcpkg = "0.2" +vcpkg = "0.2.8" # We don't actually use metadeps for annoying reasons but this is still here for tooling [package.metadata.pkg-config] diff --git a/openssl-sys/README.md b/openssl-sys/README.md deleted file mode 120000 index 32d46ee..0000000 --- a/openssl-sys/README.md +++ /dev/null @@ -1 +0,0 @@ -../README.md \ No newline at end of file diff --git a/openssl-sys/README.md b/openssl-sys/README.md new file mode 100644 index 0000000..32d46ee --- /dev/null +++ b/openssl-sys/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs deleted file mode 100644 index ff875be..0000000 --- a/openssl-sys/build.rs +++ /dev/null @@ -1,543 +0,0 @@ -extern crate pkg_config; -#[cfg(target_env = "msvc")] -extern crate vcpkg; -extern crate cc; - -use std::collections::HashSet; -use std::env; -use std::ffi::OsString; -use std::fs::File; -use std::io::{BufWriter, Write}; -use std::path::{Path, PathBuf}; -use std::panic::{self, AssertUnwindSafe}; -use std::process::Command; - -// The set of `OPENSSL_NO_`s that we care about. -const DEFINES: &'static [&'static str] = &[ - "OPENSSL_NO_BUF_FREELISTS", - "OPENSSL_NO_COMP", - "OPENSSL_NO_EC", - "OPENSSL_NO_EC2M", - "OPENSSL_NO_ENGINE", - "OPENSSL_NO_KRB5", - "OPENSSL_NO_NEXTPROTONEG", - "OPENSSL_NO_PSK", - "OPENSSL_NO_RFC3779", - "OPENSSL_NO_SHA", - "OPENSSL_NO_SRP", - "OPENSSL_NO_SSL3_METHOD", - "OPENSSL_NO_TLSEXT", -]; - -enum Version { - Openssl110, - Openssl102, - Openssl101, - Libressl, -} - -fn env(name: &str) -> Option { - let prefix = env::var("TARGET").unwrap().to_uppercase().replace("-", "_"); - let prefixed = format!("{}_{}", prefix, name); - println!("cargo:rerun-if-env-changed={}", prefixed); - - if let Some(var) = env::var_os(&prefixed) { - return Some(var); - } - - println!("cargo:rerun-if-env-changed={}", name); - env::var_os(name) -} - -fn main() { - let target = env::var("TARGET").unwrap(); - - let lib_dir = env("OPENSSL_LIB_DIR").map(PathBuf::from); - let include_dir = env("OPENSSL_INCLUDE_DIR").map(PathBuf::from); - - let (lib_dir, include_dir) = if lib_dir.is_none() || include_dir.is_none() { - let openssl_dir = env("OPENSSL_DIR").unwrap_or_else(|| find_openssl_dir(&target)); - let openssl_dir = Path::new(&openssl_dir); - let lib_dir = lib_dir.unwrap_or_else(|| openssl_dir.join("lib")); - let include_dir = include_dir.unwrap_or_else(|| openssl_dir.join("include")); - (lib_dir, include_dir) - } else { - (lib_dir.unwrap(), include_dir.unwrap()) - }; - - if !Path::new(&lib_dir).exists() { - panic!( - "OpenSSL library directory does not exist: {}", - lib_dir.to_string_lossy() - ); - } - if !Path::new(&include_dir).exists() { - panic!( - "OpenSSL include directory does not exist: {}", - include_dir.to_string_lossy() - ); - } - - println!( - "cargo:rustc-link-search=native={}", - lib_dir.to_string_lossy() - ); - println!("cargo:include={}", include_dir.to_string_lossy()); - - let version = validate_headers(&[include_dir.clone().into()]); - - let libs_env = env("OPENSSL_LIBS"); - let libs = match libs_env.as_ref().and_then(|s| s.to_str()) { - Some(ref v) => v.split(":").collect(), - None => { - match version { - Version::Openssl101 | - Version::Openssl102 if target.contains("windows") => vec!["ssleay32", "libeay32"], - Version::Openssl110 if target.contains("windows") => vec!["libssl", "libcrypto"], - _ => vec!["ssl", "crypto"], - } - } - }; - - - let kind = determine_mode(Path::new(&lib_dir), &libs); - for lib in libs.into_iter() { - println!("cargo:rustc-link-lib={}={}", kind, lib); - } -} - -fn find_openssl_dir(target: &str) -> OsString { - let host = env::var("HOST").unwrap(); - - if host.contains("apple-darwin") && target.contains("apple-darwin") { - let homebrew = Path::new("/usr/local/opt/openssl@1.1"); - if homebrew.exists() { - return homebrew.to_path_buf().into(); - } - let homebrew = Path::new("/usr/local/opt/openssl"); - if homebrew.exists() { - return homebrew.to_path_buf().into(); - } - } - - try_pkg_config(); - try_vcpkg(); - - let mut msg = format!( - " - -Could not find directory of OpenSSL installation, and this `-sys` crate cannot -proceed without this knowledge. If OpenSSL is installed and this crate had -trouble finding it, you can set the `OPENSSL_DIR` environment variable for the -compilation process. - -If you're in a situation where you think the directory *should* be found -automatically, please open a bug at https://github.com/sfackler/rust-openssl -and include information about your system as well as this message. - - $HOST = {} - $TARGET = {} - openssl-sys = {} - -", - host, - target, - env!("CARGO_PKG_VERSION") - ); - - if host.contains("apple-darwin") && target.contains("apple-darwin") { - let system = Path::new("/usr/lib/libssl.0.9.8.dylib"); - if system.exists() { - msg.push_str(&format!( - " - -It looks like you're compiling on macOS, where the system contains a version of -OpenSSL 0.9.8. This crate no longer supports OpenSSL 0.9.8. - -As a consumer of this crate, you can fix this error by using Homebrew to -install the `openssl` package, or as a maintainer you can use the openssl-sys -0.7 crate for support with OpenSSL 0.9.8. - -Unfortunately though the compile cannot continue, so aborting. - -" - )); - } - } - - if host.contains("unknown-linux") && target.contains("unknown-linux-gnu") { - if Command::new("pkg-config").output().is_err() { - msg.push_str(&format!( - " -It looks like you're compiling on Linux and also targeting Linux. Currently this -requires the `pkg-config` utility to find OpenSSL but unfortunately `pkg-config` -could not be found. If you have OpenSSL installed you can likely fix this by -installing `pkg-config`. - -" - )); - } - } - - if host.contains("windows") && target.contains("windows-gnu") { - msg.push_str(&format!( - " -It looks like you're compiling for MinGW but you may not have either OpenSSL or -pkg-config installed. You can install these two dependencies with: - - pacman -S openssl-devel pkg-config - -and try building this crate again. - -" - )); - } - - if host.contains("windows") && target.contains("windows-msvc") { - msg.push_str(&format!( - " -It looks like you're compiling for MSVC but we couldn't detect an OpenSSL -installation. If there isn't one installed then you can try the rust-openssl -README for more information about how to download precompiled binaries of -OpenSSL: - - https://github.com/sfackler/rust-openssl#windows - -" - )); - } - - panic!(msg); -} - -/// Attempt to find OpenSSL through pkg-config. -/// -/// Note that if this succeeds then the function does not return as pkg-config -/// typically tells us all the information that we need. -fn try_pkg_config() { - let target = env::var("TARGET").unwrap(); - let host = env::var("HOST").unwrap(); - - // If we're going to windows-gnu we can use pkg-config, but only so long as - // we're coming from a windows host. - // - // Otherwise if we're going to windows we probably can't use pkg-config. - if target.contains("windows-gnu") && host.contains("windows") { - env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); - } else if target.contains("windows") { - return; - } - - let lib = match pkg_config::Config::new().print_system_libs(false).find( - "openssl", - ) { - Ok(lib) => lib, - Err(e) => { - println!("run pkg_config fail: {:?}", e); - return; - } - }; - - validate_headers(&lib.include_paths); - - for include in lib.include_paths.iter() { - println!("cargo:include={}", include.display()); - } - - std::process::exit(0); -} - -/// Attempt to find OpenSSL through vcpkg. -/// -/// Note that if this succeeds then the function does not return as vcpkg -/// should emit all of the cargo metadata that we need. -#[cfg(target_env = "msvc")] -fn try_vcpkg() { - - // vcpkg will not emit any metadata if it can not find libraries - // appropriate for the target triple with the desired linkage. - - let mut lib = vcpkg::Config::new() - .emit_includes(true) - .lib_name("libcrypto") - .lib_name("libssl") - .probe("openssl"); - - if let Err(e) = lib { - println!("note: vcpkg did not find openssl as libcrypto and libssl : {:?}", - e); - lib = vcpkg::Config::new() - .emit_includes(true) - .lib_name("libeay32") - .lib_name("ssleay32") - .probe("openssl"); - } - if let Err(e) = lib { - println!("note: vcpkg did not find openssl as ssleay32 and libeay32: {:?}", - e); - return; - } - - let lib = lib.unwrap(); - validate_headers(&lib.include_paths); - - println!("cargo:rustc-link-lib=user32"); - println!("cargo:rustc-link-lib=gdi32"); - println!("cargo:rustc-link-lib=crypt32"); - - std::process::exit(0); -} - -#[cfg(not(target_env = "msvc"))] -fn try_vcpkg() {} - -/// Validates the header files found in `include_dir` and then returns the -/// version string of OpenSSL. -fn validate_headers(include_dirs: &[PathBuf]) -> Version { - // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, and 1.1.0. To - // correctly expose the right API from this crate, take a look at - // `opensslv.h` to see what version OpenSSL claims to be. - // - // OpenSSL has a number of build-time configuration options which affect - // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem - // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem. - // - // To handle all this conditional compilation we slurp up the configuration - // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines - // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can - // account for compile differences and such. - let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - path.push("expando.c"); - let mut file = BufWriter::new(File::create(&path).unwrap()); - - write!( - file, - "\ -#include -#include - -#if LIBRESSL_VERSION_NUMBER >= 0x20700000 -RUST_LIBRESSL_NEW -#elif LIBRESSL_VERSION_NUMBER >= 0x20603000 -RUST_LIBRESSL_26X -#elif LIBRESSL_VERSION_NUMBER >= 0x20602000 -RUST_LIBRESSL_262 -#elif LIBRESSL_VERSION_NUMBER >= 0x20601000 -RUST_LIBRESSL_261 -#elif LIBRESSL_VERSION_NUMBER >= 0x20600000 -RUST_LIBRESSL_260 -#elif LIBRESSL_VERSION_NUMBER >= 0x20503000 -RUST_LIBRESSL_25X -#elif LIBRESSL_VERSION_NUMBER >= 0x20502000 -RUST_LIBRESSL_252 -#elif LIBRESSL_VERSION_NUMBER >= 0x20501000 -RUST_LIBRESSL_251 -#elif LIBRESSL_VERSION_NUMBER >= 0x20500000 -RUST_LIBRESSL_250 -#elif defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20500000 -RUST_LIBRESSL_OLD -#elif OPENSSL_VERSION_NUMBER >= 0x10101000 -RUST_OPENSSL_NEW -#elif OPENSSL_VERSION_NUMBER >= 0x10100060 -RUST_OPENSSL_110F -#elif OPENSSL_VERSION_NUMBER >= 0x10100000 -RUST_OPENSSL_110 -#elif OPENSSL_VERSION_NUMBER >= 0x10002000 -RUST_OPENSSL_102 -#elif OPENSSL_VERSION_NUMBER >= 0x10001000 -RUST_OPENSSL_101 -#else -RUST_OPENSSL_OLD -#endif -" - ).unwrap(); - - for define in DEFINES { - write!( - file, - "\ -#ifdef {define} -RUST_{define}_RUST -#endif -", - define = define - ).unwrap(); - } - - file.flush().unwrap(); - drop(file); - - let mut gcc = cc::Build::new(); - for include_dir in include_dirs { - gcc.include(include_dir); - } - // https://github.com/alexcrichton/gcc-rs/issues/133 - let expanded = match panic::catch_unwind(AssertUnwindSafe(|| gcc.file(&path).expand())) { - Ok(expanded) => expanded, - Err(_) => { - panic!( - " -Failed to find OpenSSL development headers. - -You can try fixing this setting the `OPENSSL_DIR` environment variable -pointing to your OpenSSL installation or installing OpenSSL headers package -specific to your distribution: - - # On Ubuntu - sudo apt-get install libssl-dev - # On Arch Linux - sudo pacman -S openssl - # On Fedora - sudo dnf install openssl-devel - -See rust-openssl README for more information: - - https://github.com/sfackler/rust-openssl#linux -" - ); - } - }; - let expanded = String::from_utf8(expanded).unwrap(); - - let mut enabled = vec![]; - for &define in DEFINES { - if expanded.contains(&format!("RUST_{}_RUST", define)) { - println!("cargo:rustc-cfg=osslconf=\"{}\"", define); - enabled.push(define); - } - } - println!("cargo:conf={}", enabled.join(",")); - - if expanded.contains("RUST_LIBRESSL_250") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl250"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=250"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_LIBRESSL_251") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl251"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=251"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_LIBRESSL_252") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl252"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=252"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_LIBRESSL_25X") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl25x"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=25x"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_LIBRESSL_260") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl260"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=260"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_LIBRESSL_261") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl261"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=261"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_LIBRESSL_262") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl262"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=262"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_LIBRESSL_26X") { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl26x"); - println!("cargo:libressl=true"); - println!("cargo:libressl_version=26x"); - println!("cargo:version=101"); - Version::Libressl - } else if expanded.contains("RUST_OPENSSL_110F") { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:rustc-cfg=ossl110f"); - println!("cargo:version=110"); - println!("cargo:patch=f"); - Version::Openssl110 - } else if expanded.contains("RUST_OPENSSL_110") { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:version=110"); - Version::Openssl110 - } else if expanded.contains("RUST_OPENSSL_102") { - println!("cargo:rustc-cfg=ossl102"); - println!("cargo:version=102"); - Version::Openssl102 - } else if expanded.contains("RUST_OPENSSL_101") { - println!("cargo:rustc-cfg=ossl101"); - println!("cargo:version=101"); - Version::Openssl101 - } else { - panic!( - " - -This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, or LibreSSL -2.5 and 2.6.0, but a different version of OpenSSL was found. The build is now -aborting due to this version mismatch. - -" - ); - } -} - -/// Given a libdir for OpenSSL (where artifacts are located) as well as the name -/// of the libraries we're linking to, figure out whether we should link them -/// statically or dynamically. -fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { - // First see if a mode was explicitly requested - let kind = env("OPENSSL_STATIC"); - match kind.as_ref().and_then(|s| s.to_str()).map(|s| &s[..]) { - Some("0") => return "dylib", - Some(_) => return "static", - None => {} - } - - // Next, see what files we actually have to link against, and see what our - // possibilities even are. - let files = libdir - .read_dir() - .unwrap() - .map(|e| e.unwrap()) - .map(|e| e.file_name()) - .filter_map(|e| e.into_string().ok()) - .collect::>(); - let can_static = libs.iter().all(|l| { - files.contains(&format!("lib{}.a", l)) || files.contains(&format!("{}.lib", l)) - }); - let can_dylib = libs.iter().all(|l| { - files.contains(&format!("lib{}.so", l)) || files.contains(&format!("{}.dll", l)) || - files.contains(&format!("lib{}.dylib", l)) - }); - match (can_static, can_dylib) { - (true, false) => return "static", - (false, true) => return "dylib", - (false, false) => { - panic!( - "OpenSSL libdir at `{}` does not contain the required files \ - to either statically or dynamically link OpenSSL", - libdir.display() - ); - } - (true, true) => {} - } - - // Ok, we've got not explicit preference and can *either* link statically or - // link dynamically. In the interest of "security upgrades" and/or "best - // practices with security libs", let's link dynamically. - "dylib" -} diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs new file mode 100644 index 0000000..d925d90 --- /dev/null +++ b/openssl-sys/build/cfgs.rs @@ -0,0 +1,94 @@ +pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<&'static str> { + let mut cfgs = vec![]; + + if let Some(libressl_version) = libressl_version { + cfgs.push("libressl"); + + if libressl_version >= 0x2_05_01_00_0 { + cfgs.push("libressl251"); + } + if libressl_version >= 0x2_05_02_00_0 { + cfgs.push("libressl252"); + } + if libressl_version >= 0x2_06_01_00_0 { + cfgs.push("libressl261"); + } + if libressl_version >= 0x2_07_00_00_0 { + cfgs.push("libressl270"); + } + if libressl_version >= 0x2_07_01_00_0 { + cfgs.push("libressl271"); + } + if libressl_version >= 0x2_07_03_00_0 { + cfgs.push("libressl273"); + } + if libressl_version >= 0x2_08_00_00_0 { + cfgs.push("libressl280"); + } + if libressl_version >= 0x2_08_01_00_0 { + cfgs.push("libressl281"); + } + if libressl_version >= 0x2_09_01_00_0 { + cfgs.push("libressl291"); + } + if libressl_version >= 0x3_02_01_00_0 { + cfgs.push("libressl321"); + } + if libressl_version >= 0x3_03_02_00_0 { + cfgs.push("libressl332"); + } + if libressl_version >= 0x3_04_00_00_0 { + cfgs.push("libressl340"); + } + if libressl_version >= 0x3_05_00_00_0 { + cfgs.push("libressl350"); + } + if libressl_version >= 0x3_06_00_00_0 { + cfgs.push("libressl360"); + } + if libressl_version >= 0x3_07_00_00_0 { + cfgs.push("libressl370"); + } + } else { + let openssl_version = openssl_version.unwrap(); + + if openssl_version >= 0x3_00_00_00_0 { + cfgs.push("ossl300"); + } + if openssl_version >= 0x1_00_01_00_0 { + cfgs.push("ossl101"); + } + if openssl_version >= 0x1_00_02_00_0 { + cfgs.push("ossl102"); + } + if openssl_version >= 0x1_00_02_06_0 { + cfgs.push("ossl102f"); + } + if openssl_version >= 0x1_00_02_08_0 { + cfgs.push("ossl102h"); + } + if openssl_version >= 0x1_01_00_00_0 { + cfgs.push("ossl110"); + } + if openssl_version >= 0x1_01_00_06_0 { + cfgs.push("ossl110f"); + } + if openssl_version >= 0x1_01_00_07_0 { + cfgs.push("ossl110g"); + } + if openssl_version >= 0x1_01_00_08_0 { + cfgs.push("ossl110h"); + } + if openssl_version >= 0x1_01_01_00_0 { + cfgs.push("ossl111"); + } + if openssl_version >= 0x1_01_01_02_0 { + cfgs.push("ossl111b"); + } + if openssl_version >= 0x1_01_01_03_0 { + cfgs.push("ossl111c"); + } + } + + cfgs +} diff --git a/openssl-sys/build/expando.c b/openssl-sys/build/expando.c new file mode 100644 index 0000000..11fb04d --- /dev/null +++ b/openssl-sys/build/expando.c @@ -0,0 +1,124 @@ +#include +#include + +#define VERSION2(n, v) RUST_VERSION_##n##_##v +#define VERSION(n, v) VERSION2(n, v) + +#define NEW_VERSION2(a, b, c) RUST_VERSION_NEW_OPENSSL_##a##_##b##_##c +#define NEW_VERSION(a, b, c) NEW_VERSION2(a, b, c) + +#ifdef LIBRESSL_VERSION_NUMBER +VERSION(LIBRESSL, LIBRESSL_VERSION_NUMBER) +#elif defined OPENSSL_VERSION_MAJOR +NEW_VERSION(OPENSSL_VERSION_MAJOR, OPENSSL_VERSION_MINOR, OPENSSL_VERSION_PATCH) +#else +VERSION(OPENSSL, OPENSSL_VERSION_NUMBER) +#endif + +#ifdef OPENSSL_IS_BORINGSSL +RUST_OPENSSL_IS_BORINGSSL +#endif + +#ifdef OPENSSL_NO_BF +RUST_CONF_OPENSSL_NO_BF +#endif + +#ifdef OPENSSL_NO_BUF_FREELISTS +RUST_CONF_OPENSSL_NO_BUF_FREELISTS +#endif + +#ifdef OPENSSL_NO_CHACHA +RUST_CONF_OPENSSL_NO_CHACHA +#endif + +#ifdef OPENSSL_NO_IDEA +RUST_CONF_OPENSSL_NO_IDEA +#endif + +#ifdef OPENSSL_NO_CAMELLIA +RUST_CONF_OPENSSL_NO_CAMELLIA +#endif + +#ifdef OPENSSL_NO_CAST +RUST_CONF_OPENSSL_NO_CAST +#endif + +#ifdef OPENSSL_NO_CMS +RUST_CONF_OPENSSL_NO_CMS +#endif + +#ifdef OPENSSL_NO_COMP +RUST_CONF_OPENSSL_NO_COMP +#endif + +#ifdef OPENSSL_NO_EC +RUST_CONF_OPENSSL_NO_EC +#endif + +#ifdef OPENSSL_NO_EC2M +RUST_CONF_OPENSSL_NO_EC2M +#endif + +#ifdef OPENSSL_NO_ENGINE +RUST_CONF_OPENSSL_NO_ENGINE +#endif + +#ifdef OPENSSL_NO_KRB5 +RUST_CONF_OPENSSL_NO_KRB5 +#endif + +#ifdef OPENSSL_NO_NEXTPROTONEG +RUST_CONF_OPENSSL_NO_NEXTPROTONEG +#endif + +#ifdef OPENSSL_NO_OCSP +RUST_CONF_OPENSSL_NO_OCSP +#endif + +#ifdef OPENSSL_NO_PSK +RUST_CONF_OPENSSL_NO_PSK +#endif + +#ifdef OPENSSL_NO_RFC3779 +RUST_CONF_OPENSSL_NO_RFC3779 +#endif + +#ifdef OPENSSL_NO_RMD160 +RUST_CONF_OPENSSL_NO_RMD160 +#endif + +#ifdef OPENSSL_NO_SHA +RUST_CONF_OPENSSL_NO_SHA +#endif + +#ifdef OPENSSL_NO_SRP +RUST_CONF_OPENSSL_NO_SRP +#endif + +#ifdef OPENSSL_NO_SSL3_METHOD +RUST_CONF_OPENSSL_NO_SSL3_METHOD +#endif + +#ifdef OPENSSL_NO_TLSEXT +RUST_CONF_OPENSSL_NO_TLSEXT +#endif + +#ifdef OPENSSL_NO_STDIO +RUST_CONF_OPENSSL_NO_STDIO +#endif + +#ifdef OPENSSL_NO_SM3 +RUST_CONF_OPENSSL_NO_SM3 +#endif + +#ifdef OPENSSL_NO_SM4 +RUST_CONF_OPENSSL_NO_SM4 +#endif + +#ifdef OPENSSL_NO_DEPRECATED_3_0 +RUST_CONF_OPENSSL_NO_DEPRECATED_3_0 +#endif + +#ifdef OPENSSL_NO_SEED +RUST_CONF_OPENSSL_NO_SEED +#endif diff --git a/openssl-sys/build/find_normal.rs b/openssl-sys/build/find_normal.rs new file mode 100644 index 0000000..791fc33 --- /dev/null +++ b/openssl-sys/build/find_normal.rs @@ -0,0 +1,275 @@ +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +use std::process::{self, Command}; + +use super::env; + +pub fn get_openssl(target: &str) -> (Vec, PathBuf) { + let lib_dir = env("OPENSSL_LIB_DIR").map(PathBuf::from); + let include_dir = env("OPENSSL_INCLUDE_DIR").map(PathBuf::from); + + match (lib_dir, include_dir) { + (Some(lib_dir), Some(include_dir)) => (vec![lib_dir], include_dir), + (lib_dir, include_dir) => { + let openssl_dir = env("OPENSSL_DIR").unwrap_or_else(|| find_openssl_dir(target)); + let openssl_dir = Path::new(&openssl_dir); + let lib_dir = lib_dir.map(|d| vec![d]).unwrap_or_else(|| { + let mut lib_dirs = vec![]; + // OpenSSL 3.0 now puts it's libraries in lib64/ by default, + // check for both it and lib/. + if openssl_dir.join("lib64").exists() { + lib_dirs.push(openssl_dir.join("lib64")); + } + if openssl_dir.join("lib").exists() { + lib_dirs.push(openssl_dir.join("lib")); + } + lib_dirs + }); + let include_dir = include_dir.unwrap_or_else(|| openssl_dir.join("include")); + (lib_dir, include_dir) + } + } +} + +fn resolve_with_wellknown_homebrew_location(dir: &str) -> Option { + let versions = ["openssl@3", "openssl@1.1"]; + + // Check up default aarch 64 Homebrew installation location first + // for quick resolution if possible. + // `pkg-config` on brew doesn't necessarily contain settings for openssl apparently. + for version in &versions { + let homebrew = Path::new(dir).join(format!("opt/{}", version)); + if homebrew.exists() { + return Some(homebrew); + } + } + + for version in &versions { + // Calling `brew --prefix ` command usually slow and + // takes seconds, and will be used only as a last resort. + let output = execute_command_and_get_output("brew", &["--prefix", version]); + if let Some(ref output) = output { + let homebrew = Path::new(&output); + if homebrew.exists() { + return Some(homebrew.to_path_buf()); + } + } + } + + None +} + +fn resolve_with_wellknown_location(dir: &str) -> Option { + let root_dir = Path::new(dir); + let include_openssl = root_dir.join("include/openssl"); + if include_openssl.exists() { + Some(root_dir.to_path_buf()) + } else { + None + } +} + +fn find_openssl_dir(target: &str) -> OsString { + let host = env::var("HOST").unwrap(); + + if host == target && target.ends_with("-apple-darwin") { + let homebrew_dir = match target { + "aarch64-apple-darwin" => "/opt/homebrew", + _ => "/usr/local", + }; + + if let Some(dir) = resolve_with_wellknown_homebrew_location(homebrew_dir) { + return dir.into(); + } else if let Some(dir) = resolve_with_wellknown_location("/opt/pkg") { + // pkgsrc + return dir.into(); + } else if let Some(dir) = resolve_with_wellknown_location("/opt/local") { + // MacPorts + return dir.into(); + } + } + + try_pkg_config(); + try_vcpkg(); + + // FreeBSD ships with OpenSSL but doesn't include a pkg-config file :( + if host == target && target.contains("freebsd") { + return OsString::from("/usr"); + } + + // DragonFly has libressl (or openssl) in ports, but this doesn't include a pkg-config file + if host == target && target.contains("dragonfly") { + return OsString::from("/usr/local"); + } + + let mut msg = format!( + " + +Could not find directory of OpenSSL installation, and this `-sys` crate cannot +proceed without this knowledge. If OpenSSL is installed and this crate had +trouble finding it, you can set the `OPENSSL_DIR` environment variable for the +compilation process. + +Make sure you also have the development packages of openssl installed. +For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora. + +If you're in a situation where you think the directory *should* be found +automatically, please open a bug at https://github.com/sfackler/rust-openssl +and include information about your system as well as this message. + +$HOST = {} +$TARGET = {} +openssl-sys = {} + +", + host, + target, + env!("CARGO_PKG_VERSION") + ); + + if host.contains("apple-darwin") && target.contains("apple-darwin") { + let system = Path::new("/usr/lib/libssl.0.9.8.dylib"); + if system.exists() { + msg.push_str( + " + +openssl-sys crate build failed: no supported version of OpenSSL found. + +Ways to fix it: +- Use the `vendored` feature of openssl-sys crate to build OpenSSL from source. +- Use Homebrew to install the `openssl` package. + +", + ); + } + } + + if host.contains("unknown-linux") + && target.contains("unknown-linux-gnu") + && Command::new("pkg-config").output().is_err() + { + msg.push_str( + " +It looks like you're compiling on Linux and also targeting Linux. Currently this +requires the `pkg-config` utility to find OpenSSL but unfortunately `pkg-config` +could not be found. If you have OpenSSL installed you can likely fix this by +installing `pkg-config`. + +", + ); + } + + if host.contains("windows") && target.contains("windows-gnu") { + msg.push_str( + " +It looks like you're compiling for MinGW but you may not have either OpenSSL or +pkg-config installed. You can install these two dependencies with: + +pacman -S openssl-devel pkg-config + +and try building this crate again. + +", + ); + } + + if host.contains("windows") && target.contains("windows-msvc") { + msg.push_str( + " +It looks like you're compiling for MSVC but we couldn't detect an OpenSSL +installation. If there isn't one installed then you can try the rust-openssl +README for more information about how to download precompiled binaries of +OpenSSL: + +https://github.com/sfackler/rust-openssl#windows + +", + ); + } + + panic!("{}", msg); +} + +/// Attempt to find OpenSSL through pkg-config. +/// +/// Note that if this succeeds then the function does not return as pkg-config +/// typically tells us all the information that we need. +fn try_pkg_config() { + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + + // If we're going to windows-gnu we can use pkg-config, but only so long as + // we're coming from a windows host. + // + // Otherwise if we're going to windows we probably can't use pkg-config. + if target.contains("windows-gnu") && host.contains("windows") { + env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); + } else if target.contains("windows") { + return; + } + + let lib = match pkg_config::Config::new() + .print_system_libs(false) + .probe("openssl") + { + Ok(lib) => lib, + Err(e) => { + println!("run pkg_config fail: {:?}", e); + return; + } + }; + + super::postprocess(&lib.include_paths); + + for include in lib.include_paths.iter() { + println!("cargo:include={}", include.display()); + } + + process::exit(0); +} + +/// Attempt to find OpenSSL through vcpkg. +/// +/// Note that if this succeeds then the function does not return as vcpkg +/// should emit all of the cargo metadata that we need. +#[cfg(target_env = "msvc")] +fn try_vcpkg() { + // vcpkg will not emit any metadata if it can not find libraries + // appropriate for the target triple with the desired linkage. + + let lib = match vcpkg::Config::new() + .emit_includes(true) + .find_package("openssl") + { + Ok(lib) => lib, + Err(e) => { + println!("note: vcpkg did not find openssl: {}", e); + return; + } + }; + + super::postprocess(&lib.include_paths); + + println!("cargo:rustc-link-lib=user32"); + println!("cargo:rustc-link-lib=gdi32"); + println!("cargo:rustc-link-lib=crypt32"); + + process::exit(0); +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() {} + +fn execute_command_and_get_output(cmd: &str, args: &[&str]) -> Option { + let out = Command::new(cmd).args(args).output(); + if let Ok(ref r1) = out { + if r1.status.success() { + let r2 = String::from_utf8(r1.stdout.clone()); + if let Ok(r3) = r2 { + return Some(r3.trim().to_string()); + } + } + } + + None +} diff --git a/openssl-sys/build/find_vendored.rs b/openssl-sys/build/find_vendored.rs new file mode 100644 index 0000000..c92b2bd --- /dev/null +++ b/openssl-sys/build/find_vendored.rs @@ -0,0 +1,16 @@ +use openssl_src; +use std::path::PathBuf; + +pub fn get_openssl(_target: &str) -> (Vec, PathBuf) { + let artifacts = openssl_src::Build::new().build(); + println!("cargo:vendored=1"); + println!( + "cargo:root={}", + artifacts.lib_dir().parent().unwrap().display() + ); + + ( + vec![artifacts.lib_dir().to_path_buf()], + artifacts.include_dir().to_path_buf(), + ) +} diff --git a/openssl-sys/build/main.rs b/openssl-sys/build/main.rs new file mode 100644 index 0000000..3357518 --- /dev/null +++ b/openssl-sys/build/main.rs @@ -0,0 +1,426 @@ +#![allow( + clippy::inconsistent_digit_grouping, + clippy::uninlined_format_args, + clippy::unusual_byte_groupings +)] + +extern crate autocfg; +#[cfg(feature = "bindgen")] +extern crate bindgen; +extern crate cc; +#[cfg(feature = "vendored")] +extern crate openssl_src; +extern crate pkg_config; +#[cfg(target_env = "msvc")] +extern crate vcpkg; + +use std::collections::HashSet; +use std::env; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +mod cfgs; + +mod find_normal; +#[cfg(feature = "vendored")] +mod find_vendored; +mod run_bindgen; + +#[derive(PartialEq)] +enum Version { + Openssl3xx, + Openssl11x, + Openssl10x, + Libressl, + Boringssl, +} + +fn env_inner(name: &str) -> Option { + let var = env::var_os(name); + println!("cargo:rerun-if-env-changed={}", name); + + match var { + Some(ref v) => println!("{} = {}", name, v.to_string_lossy()), + None => println!("{} unset", name), + } + + var +} + +fn env(name: &str) -> Option { + let prefix = env::var("TARGET").unwrap().to_uppercase().replace('-', "_"); + let prefixed = format!("{}_{}", prefix, name); + env_inner(&prefixed).or_else(|| env_inner(name)) +} + +fn find_openssl(target: &str) -> (Vec, PathBuf) { + #[cfg(feature = "vendored")] + { + // vendor if the feature is present, unless + // OPENSSL_NO_VENDOR exists and isn't `0` + if env("OPENSSL_NO_VENDOR").map_or(true, |s| s == "0") { + return find_vendored::get_openssl(target); + } + } + find_normal::get_openssl(target) +} + +fn check_ssl_kind() { + if cfg!(feature = "unstable_boringssl") { + println!("cargo:rustc-cfg=boringssl"); + println!("cargo:boringssl=true"); + // BoringSSL does not have any build logic, exit early + std::process::exit(0); + } +} + +fn main() { + check_rustc_versions(); + + check_ssl_kind(); + + let target = env::var("TARGET").unwrap(); + + let (lib_dirs, include_dir) = find_openssl(&target); + + if !lib_dirs.iter().all(|p| Path::new(p).exists()) { + panic!("OpenSSL library directory does not exist: {:?}", lib_dirs); + } + if !Path::new(&include_dir).exists() { + panic!( + "OpenSSL include directory does not exist: {}", + include_dir.to_string_lossy() + ); + } + + for lib_dir in lib_dirs.iter() { + println!( + "cargo:rustc-link-search=native={}", + lib_dir.to_string_lossy() + ); + } + println!("cargo:include={}", include_dir.to_string_lossy()); + + let version = postprocess(&[include_dir]); + + let libs_env = env("OPENSSL_LIBS"); + let libs = match libs_env.as_ref().and_then(|s| s.to_str()) { + Some(v) => { + if v.is_empty() { + vec![] + } else { + v.split(':').collect() + } + } + None => match version { + Version::Openssl10x if target.contains("windows") => vec!["ssleay32", "libeay32"], + Version::Openssl3xx | Version::Openssl11x if target.contains("windows-msvc") => { + vec!["libssl", "libcrypto"] + } + _ => vec!["ssl", "crypto"], + }, + }; + + let kind = determine_mode(&lib_dirs, &libs); + for lib in libs.into_iter() { + println!("cargo:rustc-link-lib={}={}", kind, lib); + } + + if kind == "static" && target.contains("windows") { + println!("cargo:rustc-link-lib=dylib=gdi32"); + println!("cargo:rustc-link-lib=dylib=user32"); + println!("cargo:rustc-link-lib=dylib=crypt32"); + println!("cargo:rustc-link-lib=dylib=ws2_32"); + println!("cargo:rustc-link-lib=dylib=advapi32"); + } +} + +fn check_rustc_versions() { + let cfg = autocfg::new(); + + if cfg.probe_rustc_version(1, 31) { + println!("cargo:rustc-cfg=const_fn"); + } +} + +#[allow(clippy::let_and_return)] +fn postprocess(include_dirs: &[PathBuf]) -> Version { + let version = validate_headers(include_dirs); + + // Never run bindgen for BoringSSL, if it was needed we already ran it. + if version != Version::Boringssl { + #[cfg(feature = "bindgen")] + run_bindgen::run(&include_dirs); + } + + version +} + +/// Validates the header files found in `include_dir` and then returns the +/// version string of OpenSSL. +#[allow(clippy::manual_strip)] // we need to support pre-1.45.0 +fn validate_headers(include_dirs: &[PathBuf]) -> Version { + // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, 1.1.0, 1.1.1 and 3.0.0. + // To correctly expose the right API from this crate, take a look at + // `opensslv.h` to see what version OpenSSL claims to be. + // + // OpenSSL has a number of build-time configuration options which affect + // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem + // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem. + // + // To handle all this conditional compilation we slurp up the configuration + // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines + // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can + // account for compile differences and such. + println!("cargo:rerun-if-changed=build/expando.c"); + let mut gcc = cc::Build::new(); + for include_dir in include_dirs { + gcc.include(include_dir); + } + let expanded = match gcc.file("build/expando.c").try_expand() { + Ok(expanded) => expanded, + Err(e) => { + panic!( + " +Header expansion error: +{:?} + +Failed to find OpenSSL development headers. + +You can try fixing this setting the `OPENSSL_DIR` environment variable +pointing to your OpenSSL installation or installing OpenSSL headers package +specific to your distribution: + + # On Ubuntu + sudo apt-get install libssl-dev + # On Arch Linux + sudo pacman -S openssl + # On Fedora + sudo dnf install openssl-devel + # On Alpine Linux + apk add openssl-dev + +See rust-openssl documentation for more information: + + https://docs.rs/openssl +", + e + ); + } + }; + let expanded = String::from_utf8(expanded).unwrap(); + + let mut enabled = vec![]; + let mut openssl_version = None; + let mut libressl_version = None; + let mut is_boringssl = false; + for line in expanded.lines() { + let line = line.trim(); + + let openssl_prefix = "RUST_VERSION_OPENSSL_"; + let new_openssl_prefix = "RUST_VERSION_NEW_OPENSSL_"; + let libressl_prefix = "RUST_VERSION_LIBRESSL_"; + let boringsl_prefix = "RUST_OPENSSL_IS_BORINGSSL"; + let conf_prefix = "RUST_CONF_"; + if line.starts_with(openssl_prefix) { + let version = &line[openssl_prefix.len()..]; + openssl_version = Some(parse_version(version)); + } else if line.starts_with(new_openssl_prefix) { + let version = &line[new_openssl_prefix.len()..]; + openssl_version = Some(parse_new_version(version)); + } else if line.starts_with(libressl_prefix) { + let version = &line[libressl_prefix.len()..]; + libressl_version = Some(parse_version(version)); + } else if line.starts_with(conf_prefix) { + enabled.push(&line[conf_prefix.len()..]); + } else if line.starts_with(boringsl_prefix) { + is_boringssl = true; + } + } + + if is_boringssl { + println!("cargo:rustc-cfg=boringssl"); + println!("cargo:boringssl=true"); + run_bindgen::run_boringssl(include_dirs); + return Version::Boringssl; + } + + // We set this for any non-BoringSSL lib. + println!("cargo:rustc-cfg=openssl"); + + for enabled in &enabled { + println!("cargo:rustc-cfg=osslconf=\"{}\"", enabled); + } + println!("cargo:conf={}", enabled.join(",")); + + for cfg in cfgs::get(openssl_version, libressl_version) { + println!("cargo:rustc-cfg={}", cfg); + } + + if let Some(libressl_version) = libressl_version { + println!("cargo:libressl_version_number={:x}", libressl_version); + + let major = (libressl_version >> 28) as u8; + let minor = (libressl_version >> 20) as u8; + let fix = (libressl_version >> 12) as u8; + let (major, minor, fix) = match (major, minor, fix) { + (2, 5, 0) => ('2', '5', '0'), + (2, 5, 1) => ('2', '5', '1'), + (2, 5, 2) => ('2', '5', '2'), + (2, 5, _) => ('2', '5', 'x'), + (2, 6, 0) => ('2', '6', '0'), + (2, 6, 1) => ('2', '6', '1'), + (2, 6, 2) => ('2', '6', '2'), + (2, 6, _) => ('2', '6', 'x'), + (2, 7, _) => ('2', '7', 'x'), + (2, 8, 0) => ('2', '8', '0'), + (2, 8, 1) => ('2', '8', '1'), + (2, 8, _) => ('2', '8', 'x'), + (2, 9, 0) => ('2', '9', '0'), + (2, 9, _) => ('2', '9', 'x'), + (3, 0, 0) => ('3', '0', '0'), + (3, 0, 1) => ('3', '0', '1'), + (3, 0, _) => ('3', '0', 'x'), + (3, 1, 0) => ('3', '1', '0'), + (3, 1, _) => ('3', '1', 'x'), + (3, 2, 0) => ('3', '2', '0'), + (3, 2, 1) => ('3', '2', '1'), + (3, 2, _) => ('3', '2', 'x'), + (3, 3, 0) => ('3', '3', '0'), + (3, 3, 1) => ('3', '3', '1'), + (3, 3, _) => ('3', '3', 'x'), + (3, 4, 0) => ('3', '4', '0'), + (3, 4, _) => ('3', '4', 'x'), + (3, 5, _) => ('3', '5', 'x'), + (3, 6, 0) => ('3', '6', '0'), + (3, 6, _) => ('3', '6', 'x'), + (3, 7, 0) => ('3', '7', '0'), + (3, 7, 1) => ('3', '7', '1'), + _ => version_error(), + }; + + println!("cargo:libressl=true"); + println!("cargo:libressl_version={}{}{}", major, minor, fix); + println!("cargo:version=101"); + Version::Libressl + } else { + let openssl_version = openssl_version.unwrap(); + println!("cargo:version_number={:x}", openssl_version); + + if openssl_version >= 0x4_00_00_00_0 { + version_error() + } else if openssl_version >= 0x3_00_00_00_0 { + Version::Openssl3xx + } else if openssl_version >= 0x1_01_01_00_0 { + println!("cargo:version=111"); + Version::Openssl11x + } else if openssl_version >= 0x1_01_00_06_0 { + println!("cargo:version=110"); + println!("cargo:patch=f"); + Version::Openssl11x + } else if openssl_version >= 0x1_01_00_00_0 { + println!("cargo:version=110"); + Version::Openssl11x + } else if openssl_version >= 0x1_00_02_00_0 { + println!("cargo:version=102"); + Version::Openssl10x + } else if openssl_version >= 0x1_00_01_00_0 { + println!("cargo:version=101"); + Version::Openssl10x + } else { + version_error() + } + } +} + +fn version_error() -> ! { + panic!( + " + +This crate is only compatible with OpenSSL (version 1.0.1 through 1.1.1, or 3.0.0), or LibreSSL 2.5 +through 3.7.1, but a different version of OpenSSL was found. The build is now aborting +due to this version mismatch. + +" + ); +} + +// parses a string that looks like "0x100020cfL" +#[allow(deprecated)] // trim_right_matches is now trim_end_matches +#[allow(clippy::match_like_matches_macro)] // matches macro requires rust 1.42.0 +fn parse_version(version: &str) -> u64 { + // cut off the 0x prefix + assert!(version.starts_with("0x")); + let version = &version[2..]; + + // and the type specifier suffix + let version = version.trim_right_matches(|c: char| match c { + '0'..='9' | 'a'..='f' | 'A'..='F' => false, + _ => true, + }); + + u64::from_str_radix(version, 16).unwrap() +} + +// parses a string that looks like 3_0_0 +fn parse_new_version(version: &str) -> u64 { + println!("version: {}", version); + let mut it = version.split('_'); + let major = it.next().unwrap().parse::().unwrap(); + let minor = it.next().unwrap().parse::().unwrap(); + let patch = it.next().unwrap().parse::().unwrap(); + + (major << 28) | (minor << 20) | (patch << 4) +} + +/// Given a libdir for OpenSSL (where artifacts are located) as well as the name +/// of the libraries we're linking to, figure out whether we should link them +/// statically or dynamically. +fn determine_mode(libdirs: &[PathBuf], libs: &[&str]) -> &'static str { + // First see if a mode was explicitly requested + let kind = env("OPENSSL_STATIC"); + match kind.as_ref().and_then(|s| s.to_str()) { + Some("0") => return "dylib", + Some(_) => return "static", + None => {} + } + + // Next, see what files we actually have to link against, and see what our + // possibilities even are. + let mut files = HashSet::new(); + for dir in libdirs { + for path in dir + .read_dir() + .unwrap() + .map(|e| e.unwrap()) + .map(|e| e.file_name()) + .filter_map(|e| e.into_string().ok()) + { + files.insert(path); + } + } + let can_static = libs + .iter() + .all(|l| files.contains(&format!("lib{}.a", l)) || files.contains(&format!("{}.lib", l))); + let can_dylib = libs.iter().all(|l| { + files.contains(&format!("lib{}.so", l)) + || files.contains(&format!("{}.dll", l)) + || files.contains(&format!("lib{}.dylib", l)) + }); + match (can_static, can_dylib) { + (true, false) => return "static", + (false, true) => return "dylib", + (false, false) => { + panic!( + "OpenSSL libdir at `{:?}` does not contain the required files \ + to either statically or dynamically link OpenSSL", + libdirs + ); + } + (true, true) => {} + } + + // Ok, we've got not explicit preference and can *either* link statically or + // link dynamically. In the interest of "security upgrades" and/or "best + // practices with security libs", let's link dynamically. + "dylib" +} diff --git a/openssl-sys/build/run_bindgen.rs b/openssl-sys/build/run_bindgen.rs new file mode 100644 index 0000000..0c127ae --- /dev/null +++ b/openssl-sys/build/run_bindgen.rs @@ -0,0 +1,236 @@ +#[cfg(feature = "bindgen")] +use bindgen::callbacks::{MacroParsingBehavior, ParseCallbacks}; +#[cfg(feature = "bindgen")] +use bindgen::{MacroTypeVariation, RustTarget}; +use std::io::Write; +use std::path::PathBuf; +#[cfg(not(feature = "bindgen"))] +use std::process; +use std::{env, fs}; + +const INCLUDES: &str = " +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// this must be included after ssl.h for libressl! +#include + +#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) +#include +#endif + +#if !defined(OPENSSL_IS_BORINGSSL) +#include +#include +#endif + +#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000 +#include +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x30000000 +#include +#endif +"; + +#[cfg(feature = "bindgen")] +pub fn run(include_dirs: &[PathBuf]) { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + let mut builder = bindgen::builder() + .parse_callbacks(Box::new(OpensslCallbacks)) + .rust_target(RustTarget::Stable_1_47) + .ctypes_prefix("::libc") + .raw_line("use libc::*;") + .raw_line("type evp_pkey_st = EVP_PKEY;") + .allowlist_file(".*/openssl/[^/]+\\.h") + .allowlist_recursively(false) + // libc is missing pthread_once_t on macOS + .blocklist_type("CRYPTO_ONCE") + .blocklist_function("CRYPTO_THREAD_run_once") + // we don't want to mess with va_list + .blocklist_function("BIO_vprintf") + .blocklist_function("BIO_vsnprintf") + .blocklist_function("ERR_vset_error") + .blocklist_function("ERR_add_error_vdata") + .blocklist_function("EVP_KDF_vctrl") + .blocklist_type("OSSL_FUNC_core_vset_error_fn") + .blocklist_type("OSSL_FUNC_BIO_vprintf_fn") + .blocklist_type("OSSL_FUNC_BIO_vsnprintf_fn") + // Maintain compatibility for existing enum definitions + .rustified_enum("point_conversion_form_t") + // Maintain compatibility for pre-union definitions + .blocklist_type("GENERAL_NAME") + .blocklist_type("GENERAL_NAME_st") + .blocklist_type("EVP_PKEY") + .blocklist_type("evp_pkey_st") + .layout_tests(false) + .header_contents("includes.h", INCLUDES); + + for include_dir in include_dirs { + builder = builder + .clang_arg("-I") + .clang_arg(include_dir.display().to_string()); + } + + builder + .generate() + .unwrap() + .write_to_file(out_dir.join("bindgen.rs")) + .unwrap(); +} + +#[cfg(feature = "bindgen")] +pub fn run_boringssl(include_dirs: &[PathBuf]) { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let mut builder = bindgen::builder() + .rust_target(RustTarget::Stable_1_47) + .ctypes_prefix("::libc") + .derive_default(false) + .enable_function_attribute_detection() + .size_t_is_usize(true) + .default_macro_constant_type(MacroTypeVariation::Signed) + .rustified_enum("point_conversion_form_t") + .allowlist_file(".*/openssl/[^/]+\\.h") + .wrap_static_fns(true) + .wrap_static_fns_path(out_dir.join("boring_static_wrapper").display().to_string()) + .layout_tests(false) + .header_contents("includes.h", INCLUDES); + + for include_dir in include_dirs { + builder = builder + .clang_arg("-I") + .clang_arg(include_dir.display().to_string()); + } + + builder + .generate() + .unwrap() + .write_to_file(out_dir.join("bindgen.rs")) + .unwrap(); + + fs::File::create(out_dir.join("boring_static_wrapper.h")) + .expect("Failed to create boring_static_wrapper.h") + .write_all(INCLUDES.as_bytes()) + .expect("Failed to write contents to boring_static_wrapper.h"); + + cc::Build::new() + .file(out_dir.join("boring_static_wrapper.c")) + .includes(include_dirs) + .flag("-include") + .flag( + &out_dir + .join("boring_static_wrapper.h") + .display() + .to_string(), + ) + .compile("boring_static_wrapper"); +} + +#[cfg(not(feature = "bindgen"))] +pub fn run_boringssl(include_dirs: &[PathBuf]) { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + fs::File::create(out_dir.join("boring_static_wrapper.h")) + .expect("Failed to create boring_static_wrapper.h") + .write_all(INCLUDES.as_bytes()) + .expect("Failed to write contents to boring_static_wrapper.h"); + + let mut bindgen_cmd = process::Command::new("bindgen"); + bindgen_cmd + .arg("-o") + .arg(out_dir.join("bindgen.rs")) + .arg("--rust-target=1.47") + .arg("--ctypes-prefix=::libc") + .arg("--no-derive-default") + .arg("--enable-function-attribute-detection") + .arg("--size_t-is-usize") + .arg("--default-macro-constant-type=signed") + .arg("--rustified-enum=point_conversion_form_t") + .arg("--allowlist-file=.*/openssl/[^/]+\\.h") + .arg("--experimental") + .arg("--wrap-static-fns") + .arg("--wrap-static-fns-path") + .arg(out_dir.join("boring_static_wrapper").display().to_string()) + .arg("--no-layout-tests") + .arg(out_dir.join("boring_static_wrapper.h")) + .arg("--") + .arg(format!("--target={}", env::var("TARGET").unwrap())); + + for include_dir in include_dirs { + bindgen_cmd.arg("-I").arg(include_dir.display().to_string()); + } + + let result = bindgen_cmd.status().expect("bindgen failed to execute"); + assert!(result.success()); + + cc::Build::new() + .file(out_dir.join("boring_static_wrapper.c")) + .includes(include_dirs) + .flag("-include") + .flag( + &out_dir + .join("boring_static_wrapper.h") + .display() + .to_string(), + ) + .compile("boring_static_wrapper"); +} + +#[derive(Debug)] +struct OpensslCallbacks; + +#[cfg(feature = "bindgen")] +impl ParseCallbacks for OpensslCallbacks { + // for now we'll continue hand-writing constants + fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior { + MacroParsingBehavior::Ignore + } + + fn item_name(&self, original_item_name: &str) -> Option { + match original_item_name { + // Our original definitions of these are wrong, so rename to avoid breakage + "CRYPTO_EX_new" + | "CRYPTO_EX_dup" + | "CRYPTO_EX_free" + | "BIO_meth_set_write" + | "BIO_meth_set_read" + | "BIO_meth_set_puts" + | "BIO_meth_set_ctrl" + | "BIO_meth_set_create" + | "BIO_meth_set_destroy" + | "CRYPTO_set_locking_callback" + | "CRYPTO_set_id_callback" + | "SSL_CTX_set_tmp_dh_callback" + | "SSL_set_tmp_dh_callback" + | "SSL_CTX_set_tmp_ecdh_callback" + | "SSL_set_tmp_ecdh_callback" + | "SSL_CTX_callback_ctrl" + | "SSL_CTX_set_alpn_select_cb" => Some(format!("{}__fixed_rust", original_item_name)), + _ => None, + } + } +} diff --git a/openssl-sys/src/aes.rs b/openssl-sys/src/aes.rs new file mode 100644 index 0000000..ade6e84 --- /dev/null +++ b/openssl-sys/src/aes.rs @@ -0,0 +1,7 @@ +use libc::*; + +pub const AES_ENCRYPT: c_int = 1; +pub const AES_DECRYPT: c_int = 0; + +pub const AES_MAXNR: c_int = 14; +pub const AES_BLOCK_SIZE: c_int = 16; diff --git a/openssl-sys/src/asn1.rs b/openssl-sys/src/asn1.rs new file mode 100644 index 0000000..caf14f7 --- /dev/null +++ b/openssl-sys/src/asn1.rs @@ -0,0 +1,39 @@ +use libc::*; + +use super::*; + +// ASN.1 tag values +pub const V_ASN1_EOC: c_int = 0; +pub const V_ASN1_BOOLEAN: c_int = 1; +pub const V_ASN1_INTEGER: c_int = 2; +pub const V_ASN1_BIT_STRING: c_int = 3; +pub const V_ASN1_OCTET_STRING: c_int = 4; +pub const V_ASN1_NULL: c_int = 5; +pub const V_ASN1_OBJECT: c_int = 6; +pub const V_ASN1_OBJECT_DESCRIPTOR: c_int = 7; +pub const V_ASN1_EXTERNAL: c_int = 8; +pub const V_ASN1_REAL: c_int = 9; +pub const V_ASN1_ENUMERATED: c_int = 10; +pub const V_ASN1_UTF8STRING: c_int = 12; +pub const V_ASN1_SEQUENCE: c_int = 16; +pub const V_ASN1_SET: c_int = 17; +pub const V_ASN1_NUMERICSTRING: c_int = 18; +pub const V_ASN1_PRINTABLESTRING: c_int = 19; +pub const V_ASN1_T61STRING: c_int = 20; +pub const V_ASN1_TELETEXSTRING: c_int = 20; // alias +pub const V_ASN1_VIDEOTEXSTRING: c_int = 21; +pub const V_ASN1_IA5STRING: c_int = 22; +pub const V_ASN1_UTCTIME: c_int = 23; +pub const V_ASN1_GENERALIZEDTIME: c_int = 24; +pub const V_ASN1_GRAPHICSTRING: c_int = 25; +pub const V_ASN1_ISO64STRING: c_int = 26; +pub const V_ASN1_VISIBLESTRING: c_int = 26; // alias +pub const V_ASN1_GENERALSTRING: c_int = 27; +pub const V_ASN1_UNIVERSALSTRING: c_int = 28; +pub const V_ASN1_BMPSTRING: c_int = 30; + +pub const MBSTRING_FLAG: c_int = 0x1000; +pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; +pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; +pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; +pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; diff --git a/openssl-sys/src/bio.rs b/openssl-sys/src/bio.rs new file mode 100644 index 0000000..ea6053b --- /dev/null +++ b/openssl-sys/src/bio.rs @@ -0,0 +1,72 @@ +use libc::*; + +use super::*; + +pub const BIO_TYPE_NONE: c_int = 0; + +pub const BIO_CTRL_EOF: c_int = 2; +pub const BIO_CTRL_INFO: c_int = 3; +pub const BIO_CTRL_FLUSH: c_int = 11; +pub const BIO_CTRL_DGRAM_QUERY_MTU: c_int = 40; +pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130; + +pub unsafe fn BIO_set_retry_read(b: *mut BIO) { + BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY) +} + +pub unsafe fn BIO_set_retry_write(b: *mut BIO) { + BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY) +} + +pub unsafe fn BIO_clear_retry_flags(b: *mut BIO) { + BIO_clear_flags(b, BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY) +} + +pub const BIO_FLAGS_READ: c_int = 0x01; +pub const BIO_FLAGS_WRITE: c_int = 0x02; +pub const BIO_FLAGS_IO_SPECIAL: c_int = 0x04; +pub const BIO_FLAGS_RWS: c_int = BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL; +pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08; + +pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { + BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) +} + +extern "C" { + #[deprecated(note = "use BIO_meth_set_write__fixed_rust instead")] + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_write( + biom: *mut BIO_METHOD, + write: unsafe extern "C" fn(*mut BIO, *const c_char, c_int) -> c_int, + ) -> c_int; + #[deprecated(note = "use BIO_meth_set_read__fixed_rust instead")] + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_read( + biom: *mut BIO_METHOD, + read: unsafe extern "C" fn(*mut BIO, *mut c_char, c_int) -> c_int, + ) -> c_int; + #[deprecated(note = "use BIO_meth_set_puts__fixed_rust instead")] + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_puts( + biom: *mut BIO_METHOD, + read: unsafe extern "C" fn(*mut BIO, *const c_char) -> c_int, + ) -> c_int; + #[deprecated(note = "use BIO_meth_set_ctrl__fixed_rust instead")] + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_ctrl( + biom: *mut BIO_METHOD, + read: unsafe extern "C" fn(*mut BIO, c_int, c_long, *mut c_void) -> c_long, + ) -> c_int; + #[deprecated(note = "use BIO_meth_set_create__fixed_rust instead")] + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_create( + biom: *mut BIO_METHOD, + create: unsafe extern "C" fn(*mut BIO) -> c_int, + ) -> c_int; + #[deprecated(note = "use BIO_meth_set_destroy__fixed_rust instead")] + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_destroy( + biom: *mut BIO_METHOD, + destroy: unsafe extern "C" fn(*mut BIO) -> c_int, + ) -> c_int; +} diff --git a/openssl-sys/src/bn.rs b/openssl-sys/src/bn.rs new file mode 100644 index 0000000..a6bbcce --- /dev/null +++ b/openssl-sys/src/bn.rs @@ -0,0 +1,15 @@ +use libc::*; + +#[cfg(target_pointer_width = "64")] +pub type BN_ULONG = c_ulonglong; +#[cfg(target_pointer_width = "32")] +pub type BN_ULONG = c_uint; + +#[cfg(ossl110)] +pub const BN_FLG_MALLOCED: c_int = 0x01; +#[cfg(ossl110)] +pub const BN_FLG_STATIC_DATA: c_int = 0x02; +#[cfg(ossl110)] +pub const BN_FLG_CONSTTIME: c_int = 0x04; +#[cfg(ossl110)] +pub const BN_FLG_SECURE: c_int = 0x08; diff --git a/openssl-sys/src/cms.rs b/openssl-sys/src/cms.rs new file mode 100644 index 0000000..f008adb --- /dev/null +++ b/openssl-sys/src/cms.rs @@ -0,0 +1,46 @@ +use libc::*; + +#[cfg(ossl101)] +pub const CMS_TEXT: c_uint = 0x1; +#[cfg(ossl101)] +pub const CMS_NOCERTS: c_uint = 0x2; +#[cfg(ossl101)] +pub const CMS_NO_CONTENT_VERIFY: c_uint = 0x4; +#[cfg(ossl101)] +pub const CMS_NO_ATTR_VERIFY: c_uint = 0x8; +#[cfg(ossl101)] +pub const CMS_NOSIGS: c_uint = 0x4 | 0x8; +#[cfg(ossl101)] +pub const CMS_NOINTERN: c_uint = 0x10; +#[cfg(ossl101)] +pub const CMS_NO_SIGNER_CERT_VERIFY: c_uint = 0x20; +#[cfg(ossl101)] +pub const CMS_NOVERIFY: c_uint = 0x20; +#[cfg(ossl101)] +pub const CMS_DETACHED: c_uint = 0x40; +#[cfg(ossl101)] +pub const CMS_BINARY: c_uint = 0x80; +#[cfg(ossl101)] +pub const CMS_NOATTR: c_uint = 0x100; +#[cfg(ossl101)] +pub const CMS_NOSMIMECAP: c_uint = 0x200; +#[cfg(ossl101)] +pub const CMS_NOOLDMIMETYPE: c_uint = 0x400; +#[cfg(ossl101)] +pub const CMS_CRLFEOL: c_uint = 0x800; +#[cfg(ossl101)] +pub const CMS_STREAM: c_uint = 0x1000; +#[cfg(ossl101)] +pub const CMS_NOCRL: c_uint = 0x2000; +#[cfg(ossl101)] +pub const CMS_PARTIAL: c_uint = 0x4000; +#[cfg(ossl101)] +pub const CMS_REUSE_DIGEST: c_uint = 0x8000; +#[cfg(ossl101)] +pub const CMS_USE_KEYID: c_uint = 0x10000; +#[cfg(ossl101)] +pub const CMS_DEBUG_DECRYPT: c_uint = 0x20000; +#[cfg(ossl102)] +pub const CMS_KEY_PARAM: c_uint = 0x40000; +#[cfg(ossl110)] +pub const CMS_ASCIICRLF: c_uint = 0x80000; diff --git a/openssl-sys/src/crypto.rs b/openssl-sys/src/crypto.rs new file mode 100644 index 0000000..35be07e --- /dev/null +++ b/openssl-sys/src/crypto.rs @@ -0,0 +1,134 @@ +use super::*; +use libc::*; + +extern "C" { + #[deprecated(note = "use CRYPTO_set_locking_callback__fixed_rust instead")] + #[cfg(not(ossl110))] + pub fn CRYPTO_set_locking_callback( + func: unsafe extern "C" fn(mode: c_int, n: c_int, file: *const c_char, line: c_int), + ); + + #[deprecated(note = "use CRYPTO_set_id_callback__fixed_rust instead")] + #[cfg(not(ossl110))] + pub fn CRYPTO_set_id_callback(func: unsafe extern "C" fn() -> c_ulong); +} + +cfg_if! { + if #[cfg(ossl110)] { + type CRYPTO_EX_new_ret = (); + type CRYPTO_EX_dup_from = *const CRYPTO_EX_DATA; + } else { + type CRYPTO_EX_new_ret = c_int; + type CRYPTO_EX_dup_from = *mut CRYPTO_EX_DATA; + } +} + +cfg_if! { + if #[cfg(ossl300)] { + type CRYPTO_EX_dup_from_d = *mut *mut c_void; + } else { + type CRYPTO_EX_dup_from_d = *mut c_void; + } +} + +// FIXME should be options +pub type CRYPTO_EX_new = unsafe extern "C" fn( + parent: *mut c_void, + ptr: *mut c_void, + ad: *mut CRYPTO_EX_DATA, + idx: c_int, + argl: c_long, + argp: *mut c_void, +) -> CRYPTO_EX_new_ret; +pub type CRYPTO_EX_dup = unsafe extern "C" fn( + to: *mut CRYPTO_EX_DATA, + from: CRYPTO_EX_dup_from, + from_d: CRYPTO_EX_dup_from_d, + idx: c_int, + argl: c_long, + argp: *mut c_void, +) -> c_int; +pub type CRYPTO_EX_free = unsafe extern "C" fn( + parent: *mut c_void, + ptr: *mut c_void, + ad: *mut CRYPTO_EX_DATA, + idx: c_int, + argl: c_long, + argp: *mut c_void, +); + +#[cfg(ossl110)] +#[inline] +#[track_caller] +pub unsafe fn OPENSSL_malloc(num: usize) -> *mut c_void { + CRYPTO_malloc( + num, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as _, + ) +} + +#[cfg(not(ossl110))] +#[inline] +#[track_caller] +pub unsafe fn OPENSSL_malloc(num: c_int) -> *mut c_void { + CRYPTO_malloc( + num, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as _, + ) +} + +#[cfg(ossl110)] +#[inline] +#[track_caller] +pub unsafe fn OPENSSL_free(addr: *mut c_void) { + CRYPTO_free( + addr, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as _, + ) +} + +#[cfg(not(ossl110))] +#[inline] +pub unsafe fn OPENSSL_free(addr: *mut c_void) { + CRYPTO_free(addr) +} + +#[cfg(not(ossl110))] +pub const CRYPTO_LOCK_X509: c_int = 3; +#[cfg(not(ossl110))] +pub const CRYPTO_LOCK_EVP_PKEY: c_int = 10; +#[cfg(not(ossl110))] +pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; +#[cfg(not(ossl110))] +pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14; + +cfg_if! { + if #[cfg(ossl110)] { + pub const CRYPTO_EX_INDEX_SSL: c_int = 0; + pub const CRYPTO_EX_INDEX_SSL_CTX: c_int = 1; + } else if #[cfg(libressl)] { + pub const CRYPTO_EX_INDEX_SSL: c_int = 1; + pub const CRYPTO_EX_INDEX_SSL_CTX: c_int = 2; + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl271))] { + pub const OPENSSL_VERSION: c_int = 0; + pub const OPENSSL_CFLAGS: c_int = 1; + pub const OPENSSL_BUILT_ON: c_int = 2; + pub const OPENSSL_PLATFORM: c_int = 3; + pub const OPENSSL_DIR: c_int = 4; + } else { + pub const SSLEAY_VERSION: c_int = 0; + pub const SSLEAY_CFLAGS: c_int = 2; + pub const SSLEAY_BUILT_ON: c_int = 3; + pub const SSLEAY_PLATFORM: c_int = 4; + pub const SSLEAY_DIR: c_int = 5; + } +} + +pub const CRYPTO_LOCK: c_int = 1; diff --git a/openssl-sys/src/dtls1.rs b/openssl-sys/src/dtls1.rs new file mode 100644 index 0000000..9ef5e77 --- /dev/null +++ b/openssl-sys/src/dtls1.rs @@ -0,0 +1,9 @@ +use libc::*; + +cfg_if! { + if #[cfg(ossl300)] { + pub const DTLS1_COOKIE_LENGTH: c_uint = 255; + } else { + pub const DTLS1_COOKIE_LENGTH: c_uint = 256; + } +} diff --git a/openssl-sys/src/ec.rs b/openssl-sys/src/ec.rs new file mode 100644 index 0000000..995a84f --- /dev/null +++ b/openssl-sys/src/ec.rs @@ -0,0 +1,16 @@ +use libc::*; +use std::ptr; + +use super::*; + +pub const OPENSSL_EC_NAMED_CURVE: c_int = 1; + +#[cfg(ossl300)] +pub unsafe fn EVP_EC_gen(curve: *const c_char) -> *mut EVP_PKEY { + EVP_PKEY_Q_keygen( + ptr::null_mut(), + ptr::null_mut(), + "EC\0".as_ptr().cast(), + curve, + ) +} diff --git a/openssl-sys/src/err.rs b/openssl-sys/src/err.rs new file mode 100644 index 0000000..5e84e62 --- /dev/null +++ b/openssl-sys/src/err.rs @@ -0,0 +1,70 @@ +use libc::*; + +pub const ERR_TXT_MALLOCED: c_int = 0x01; +pub const ERR_TXT_STRING: c_int = 0x02; + +pub const ERR_LIB_SYS: c_int = 2; +pub const ERR_LIB_PEM: c_int = 9; +pub const ERR_LIB_ASN1: c_int = 13; + +cfg_if! { + if #[cfg(ossl300)] { + pub const ERR_SYSTEM_FLAG: c_ulong = c_int::max_value() as c_ulong + 1; + pub const ERR_SYSTEM_MASK: c_ulong = c_int::max_value() as c_ulong; + + pub const ERR_LIB_OFFSET: c_ulong = 23; + pub const ERR_LIB_MASK: c_ulong = 0xff; + pub const ERR_RFLAGS_OFFSET: c_ulong = 18; + pub const ERR_RFLAGS_MASK: c_ulong = 0x1f; + pub const ERR_REASON_MASK: c_ulong = 0x7FFFFF; + + pub const ERR_RFLAG_FATAL: c_ulong = 0x1 << ERR_RFLAGS_OFFSET; + + const_fn! { + pub const fn ERR_SYSTEM_ERROR(errcode: c_ulong) -> bool { + errcode & ERR_SYSTEM_FLAG != 0 + } + + pub const fn ERR_GET_LIB(errcode: c_ulong) -> c_int { + // hacks since `if` isn't yet stable in const functions :( + ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | + (((errcode >> ERR_LIB_OFFSET) & ERR_LIB_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int + } + + pub const fn ERR_GET_FUNC(_errcode: c_ulong) -> c_int { + 0 + } + + pub const fn ERR_GET_REASON(errcode: c_ulong) -> c_int { + // hacks since `if` isn't yet stable in const functions :( + ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | + ((errcode & ERR_REASON_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int + } + + pub const fn ERR_PACK(lib: c_int, _func: c_int, reason: c_int) -> c_ulong { + ((lib as c_ulong & ERR_LIB_MASK) << ERR_LIB_OFFSET) | + (reason as c_ulong & ERR_REASON_MASK) + } + } + } else { + const_fn! { + pub const fn ERR_PACK(l: c_int, f: c_int, r: c_int) -> c_ulong { + ((l as c_ulong & 0x0FF) << 24) | + ((f as c_ulong & 0xFFF) << 12) | + (r as c_ulong & 0xFFF) + } + + pub const fn ERR_GET_LIB(l: c_ulong) -> c_int { + ((l >> 24) & 0x0FF) as c_int + } + + pub const fn ERR_GET_FUNC(l: c_ulong) -> c_int { + ((l >> 12) & 0xFFF) as c_int + } + + pub const fn ERR_GET_REASON(l: c_ulong) -> c_int { + (l & 0xFFF) as c_int + } + } + } +} diff --git a/openssl-sys/src/evp.rs b/openssl-sys/src/evp.rs new file mode 100644 index 0000000..69b49fb --- /dev/null +++ b/openssl-sys/src/evp.rs @@ -0,0 +1,285 @@ +use super::*; +use libc::*; + +pub const EVP_MAX_MD_SIZE: c_uint = 64; + +pub const PKCS5_SALT_LEN: c_int = 8; +pub const PKCS12_DEFAULT_ITER: c_int = 2048; + +pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; +pub const EVP_PKEY_DSA: c_int = NID_dsa; +pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; +pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; +#[cfg(any(ossl111, libressl370))] +pub const EVP_PKEY_X25519: c_int = NID_X25519; +#[cfg(any(ossl111, libressl370))] +pub const EVP_PKEY_ED25519: c_int = NID_ED25519; +#[cfg(ossl111)] +pub const EVP_PKEY_X448: c_int = NID_X448; +#[cfg(ossl111)] +pub const EVP_PKEY_ED448: c_int = NID_ED448; +pub const EVP_PKEY_HMAC: c_int = NID_hmac; +pub const EVP_PKEY_CMAC: c_int = NID_cmac; +#[cfg(ossl110)] +pub const EVP_PKEY_HKDF: c_int = NID_hkdf; + +pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9; +pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10; +pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11; + +pub unsafe fn EVP_get_digestbynid(type_: c_int) -> *const EVP_MD { + EVP_get_digestbyname(OBJ_nid2sn(type_)) +} + +cfg_if! { + if #[cfg(ossl300)] { + #[inline] + pub unsafe fn EVP_MD_CTX_md(ctx: *const EVP_MD_CTX) -> *const EVP_MD { + EVP_MD_CTX_get0_md(ctx) + } + + #[inline] + pub unsafe fn EVP_MD_CTX_get_size(ctx: *const EVP_MD_CTX) -> c_int { + EVP_MD_get_size(EVP_MD_CTX_get0_md(ctx)) + } + + #[inline] + pub unsafe fn EVP_MD_CTX_size(ctx: *const EVP_MD_CTX) -> c_int { + EVP_MD_CTX_get_size(ctx) + } + + #[inline] + pub unsafe fn EVP_MD_block_size(md: *const EVP_MD) -> c_int { + EVP_MD_get_block_size(md) + } + + #[inline] + pub unsafe fn EVP_MD_size(md: *const EVP_MD) -> c_int { + EVP_MD_get_size(md) + } + + #[inline] + pub unsafe fn EVP_MD_type(md: *const EVP_MD) -> c_int { + EVP_MD_get_type(md) + } + + #[inline] + pub unsafe fn EVP_CIPHER_key_length(cipher: *const EVP_CIPHER) -> c_int { + EVP_CIPHER_get_key_length(cipher) + } + + #[inline] + pub unsafe fn EVP_CIPHER_block_size(cipher: *const EVP_CIPHER) -> c_int { + EVP_CIPHER_get_block_size(cipher) + } + + #[inline] + pub unsafe fn EVP_CIPHER_iv_length(cipher: *const EVP_CIPHER) -> c_int { + EVP_CIPHER_get_iv_length(cipher) + } + + #[inline] + pub unsafe fn EVP_CIPHER_nid(cipher: *const EVP_CIPHER) -> c_int { + EVP_CIPHER_get_nid(cipher) + } + + #[inline] + pub unsafe fn EVP_CIPHER_CTX_block_size(ctx: *const EVP_CIPHER_CTX) -> c_int { + EVP_CIPHER_CTX_get_block_size(ctx) + } + + #[inline] + pub unsafe fn EVP_CIPHER_CTX_key_length(ctx: *const EVP_CIPHER_CTX) -> c_int { + EVP_CIPHER_CTX_get_key_length(ctx) + } + + #[inline] + pub unsafe fn EVP_CIPHER_CTX_iv_length(ctx: *const EVP_CIPHER_CTX) -> c_int { + EVP_CIPHER_CTX_get_iv_length(ctx) + } + + #[inline] + pub unsafe fn EVP_CIPHER_CTX_num(ctx: *const EVP_CIPHER_CTX) -> c_int { + EVP_CIPHER_CTX_get_num(ctx) + } + } else { + pub unsafe fn EVP_MD_CTX_size(ctx: *const EVP_MD_CTX) -> c_int { + EVP_MD_size(EVP_MD_CTX_md(ctx)) + } + } +} +#[cfg(not(ossl300))] +#[inline] +pub unsafe fn EVP_DigestSignUpdate( + ctx: *mut EVP_MD_CTX, + data: *const c_void, + dsize: size_t, +) -> c_int { + EVP_DigestUpdate(ctx, data, dsize) +} +#[cfg(not(ossl300))] +#[inline] +pub unsafe fn EVP_DigestVerifyUpdate( + ctx: *mut EVP_MD_CTX, + data: *const c_void, + dsize: size_t, +) -> c_int { + EVP_DigestUpdate(ctx, data, dsize) +} +#[cfg(ossl300)] +#[inline] +pub unsafe fn EVP_PKEY_size(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_size(pkey) +} + +cfg_if! { + if #[cfg(ossl300)] { + #[inline] + pub unsafe fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_id(pkey) + } + + #[inline] + pub unsafe fn EVP_PKEY_bits(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_bits(pkey) + } + + #[inline] + pub unsafe fn EVP_PKEY_security_bits(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_security_bits(pkey) + } + } +} + +pub const EVP_PKEY_OP_KEYGEN: c_int = 1 << 2; +cfg_if! { + if #[cfg(ossl300)] { + pub const EVP_PKEY_OP_SIGN: c_int = 1 << 4; + pub const EVP_PKEY_OP_VERIFY: c_int = 1 << 5; + pub const EVP_PKEY_OP_VERIFYRECOVER: c_int = 1 << 6; + pub const EVP_PKEY_OP_SIGNCTX: c_int = 1 << 7; + pub const EVP_PKEY_OP_VERIFYCTX: c_int = 1 << 8; + pub const EVP_PKEY_OP_ENCRYPT: c_int = 1 << 9; + pub const EVP_PKEY_OP_DECRYPT: c_int = 1 << 10; + pub const EVP_PKEY_OP_DERIVE: c_int = 1 << 11; + } else { + pub const EVP_PKEY_OP_SIGN: c_int = 1 << 3; + pub const EVP_PKEY_OP_VERIFY: c_int = 1 << 4; + pub const EVP_PKEY_OP_VERIFYRECOVER: c_int = 1 << 5; + pub const EVP_PKEY_OP_SIGNCTX: c_int = 1 << 6; + pub const EVP_PKEY_OP_VERIFYCTX: c_int = 1 << 7; + pub const EVP_PKEY_OP_ENCRYPT: c_int = 1 << 8; + pub const EVP_PKEY_OP_DECRYPT: c_int = 1 << 9; + pub const EVP_PKEY_OP_DERIVE: c_int = 1 << 10; + } +} + +pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN + | EVP_PKEY_OP_VERIFY + | EVP_PKEY_OP_VERIFYRECOVER + | EVP_PKEY_OP_SIGNCTX + | EVP_PKEY_OP_VERIFYCTX; + +pub const EVP_PKEY_OP_TYPE_CRYPT: c_int = EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT; + +pub const EVP_PKEY_CTRL_SET_MAC_KEY: c_int = 6; + +pub const EVP_PKEY_CTRL_CIPHER: c_int = 12; + +pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000; + +#[cfg(ossl111)] +pub const EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND: c_int = 0; + +#[cfg(ossl111)] +pub const EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY: c_int = 1; + +#[cfg(ossl111)] +pub const EVP_PKEY_HKDEF_MODE_EXPAND_ONLY: c_int = 2; + +#[cfg(ossl110)] +pub const EVP_PKEY_CTRL_HKDF_MD: c_int = EVP_PKEY_ALG_CTRL + 3; + +#[cfg(ossl110)] +pub const EVP_PKEY_CTRL_HKDF_SALT: c_int = EVP_PKEY_ALG_CTRL + 4; + +#[cfg(ossl110)] +pub const EVP_PKEY_CTRL_HKDF_KEY: c_int = EVP_PKEY_ALG_CTRL + 5; + +#[cfg(ossl110)] +pub const EVP_PKEY_CTRL_HKDF_INFO: c_int = EVP_PKEY_ALG_CTRL + 6; + +#[cfg(ossl111)] +pub const EVP_PKEY_CTRL_HKDF_MODE: c_int = EVP_PKEY_ALG_CTRL + 7; + +#[cfg(all(ossl111, not(ossl300)))] +pub unsafe fn EVP_PKEY_CTX_set_hkdf_mode(ctx: *mut EVP_PKEY_CTX, mode: c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + -1, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_MODE, + mode, + std::ptr::null_mut(), + ) +} + +#[cfg(all(ossl110, not(ossl300)))] +pub unsafe fn EVP_PKEY_CTX_set_hkdf_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + -1, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_MD, + 0, + md as *mut c_void, + ) +} + +#[cfg(all(ossl110, not(ossl300)))] +pub unsafe fn EVP_PKEY_CTX_set1_hkdf_salt( + ctx: *mut EVP_PKEY_CTX, + salt: *const u8, + saltlen: c_int, +) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + -1, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_SALT, + saltlen, + salt as *mut c_void, + ) +} + +#[cfg(all(ossl110, not(ossl300)))] +pub unsafe fn EVP_PKEY_CTX_set1_hkdf_key( + ctx: *mut EVP_PKEY_CTX, + key: *const u8, + keylen: c_int, +) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + -1, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_KEY, + keylen, + key as *mut c_void, + ) +} + +#[cfg(all(ossl110, not(ossl300)))] +pub unsafe fn EVP_PKEY_CTX_add1_hkdf_info( + ctx: *mut EVP_PKEY_CTX, + info: *const u8, + infolen: c_int, +) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + -1, + EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_HKDF_INFO, + infolen, + info as *mut c_void, + ) +} diff --git a/openssl-sys/src/handwritten/aes.rs b/openssl-sys/src/handwritten/aes.rs new file mode 100644 index 0000000..ba24936 --- /dev/null +++ b/openssl-sys/src/handwritten/aes.rs @@ -0,0 +1,40 @@ +use super::super::*; +use libc::*; + +#[repr(C)] +pub struct AES_KEY { + // There is some business with AES_LONG which is there to ensure the values here are 32 bits + rd_key: [u32; 4 * (AES_MAXNR as usize + 1)], + rounds: c_int, +} + +extern "C" { + pub fn AES_set_encrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; + pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; + + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + pub fn AES_ige_encrypt( + in_: *const c_uchar, + out: *mut c_uchar, + length: size_t, + key: *const AES_KEY, + ivec: *mut c_uchar, + enc: c_int, + ); + + pub fn AES_wrap_key( + key: *mut AES_KEY, + iv: *const c_uchar, + out: *mut c_uchar, + in_: *const c_uchar, + inlen: c_uint, + ) -> c_int; + + pub fn AES_unwrap_key( + key: *mut AES_KEY, + iv: *const c_uchar, + out: *mut c_uchar, + in_: *const c_uchar, + inlen: c_uint, + ) -> c_int; +} diff --git a/openssl-sys/src/handwritten/asn1.rs b/openssl-sys/src/handwritten/asn1.rs new file mode 100644 index 0000000..7163a69 --- /dev/null +++ b/openssl-sys/src/handwritten/asn1.rs @@ -0,0 +1,60 @@ +use super::super::*; +use libc::*; + +#[repr(C)] +pub struct ASN1_ENCODING { + pub enc: *mut c_uchar, + pub len: c_long, + pub modified: c_int, +} + +extern "C" { + pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); +} + +stack!(stack_st_ASN1_OBJECT); + +extern "C" { + pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; + #[cfg(any(ossl110, libressl273))] + pub fn ASN1_STRING_get0_data(x: *const ASN1_STRING) -> *const c_uchar; + #[cfg(any(all(ossl101, not(ossl110)), libressl))] + pub fn ASN1_STRING_data(x: *mut ASN1_STRING) -> *mut c_uchar; + + pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); + + pub fn ASN1_STRING_free(x: *mut ASN1_STRING); + pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + + pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len: c_int) -> c_int; + + pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); + pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; + pub fn ASN1_TIME_new() -> *mut ASN1_TIME; + #[cfg(ossl102)] + pub fn ASN1_TIME_diff( + pday: *mut c_int, + psec: *mut c_int, + from: *const ASN1_TIME, + to: *const ASN1_TIME, + ) -> c_int; + pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); + pub fn ASN1_TIME_print(b: *mut BIO, tm: *const ASN1_TIME) -> c_int; + pub fn ASN1_TIME_set(from: *mut ASN1_TIME, to: time_t) -> *mut ASN1_TIME; + + pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER); + pub fn ASN1_INTEGER_get(dest: *const ASN1_INTEGER) -> c_long; + pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; + pub fn BN_to_ASN1_INTEGER(bn: *const BIGNUM, ai: *mut ASN1_INTEGER) -> *mut ASN1_INTEGER; + pub fn ASN1_INTEGER_to_BN(ai: *const ASN1_INTEGER, bn: *mut BIGNUM) -> *mut BIGNUM; + + pub fn ASN1_TIME_set_string(s: *mut ASN1_TIME, str: *const c_char) -> c_int; + #[cfg(ossl111)] + pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; +} + +const_ptr_api! { + extern "C" { + pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + } +} diff --git a/openssl-sys/src/handwritten/bio.rs b/openssl-sys/src/handwritten/bio.rs new file mode 100644 index 0000000..7d97522 --- /dev/null +++ b/openssl-sys/src/handwritten/bio.rs @@ -0,0 +1,107 @@ +use super::super::*; +use libc::*; + +extern "C" { + pub fn BIO_set_flags(b: *mut BIO, flags: c_int); + pub fn BIO_clear_flags(b: *mut BIO, flags: c_int); +} + +pub type bio_info_cb = + Option; + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum BIO_METHOD {} + } else { + #[repr(C)] + pub struct BIO_METHOD { + pub type_: c_int, + pub name: *const c_char, + pub bwrite: Option c_int>, + pub bread: Option c_int>, + pub bputs: Option c_int>, + pub bgets: Option c_int>, + pub ctrl: Option c_long>, + pub create: Option c_int>, + pub destroy: Option c_int>, + pub callback_ctrl: Option c_long>, + } + } +} + +const_ptr_api! { + extern "C" { + pub fn BIO_s_file() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD; + pub fn BIO_new(type_: #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD) -> *mut BIO; + } +} +extern "C" { + #[cfg(not(osslconf = "OPENSSL_NO_STDIO"))] + pub fn BIO_new_fp(stream: *mut FILE, close_flag: c_int) -> *mut BIO; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_set_data(a: *mut BIO, data: *mut c_void); + #[cfg(any(ossl110, libressl273))] + pub fn BIO_get_data(a: *mut BIO) -> *mut c_void; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_set_init(a: *mut BIO, init: c_int); + pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; + pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; + pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn BIO_free_all(b: *mut BIO); +} + +const_ptr_api! { + extern "C" { + pub fn BIO_s_mem() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD; + pub fn BIO_new_mem_buf(buf: #[const_ptr_if(any(ossl102, libressl280))] c_void, len: c_int) -> *mut BIO; + } +} + +extern "C" { + pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *mut BIO; + + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_new(type_: c_int, name: *const c_char) -> *mut BIO_METHOD; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_free(biom: *mut BIO_METHOD); +} + +#[allow(clashing_extern_declarations)] +extern "C" { + #[cfg(any(ossl110, libressl273))] + #[link_name = "BIO_meth_set_write"] + pub fn BIO_meth_set_write__fixed_rust( + biom: *mut BIO_METHOD, + write: Option c_int>, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + #[link_name = "BIO_meth_set_read"] + pub fn BIO_meth_set_read__fixed_rust( + biom: *mut BIO_METHOD, + read: Option c_int>, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + #[link_name = "BIO_meth_set_puts"] + pub fn BIO_meth_set_puts__fixed_rust( + biom: *mut BIO_METHOD, + read: Option c_int>, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + #[link_name = "BIO_meth_set_ctrl"] + pub fn BIO_meth_set_ctrl__fixed_rust( + biom: *mut BIO_METHOD, + read: Option c_long>, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + #[link_name = "BIO_meth_set_create"] + pub fn BIO_meth_set_create__fixed_rust( + biom: *mut BIO_METHOD, + create: Option c_int>, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + #[link_name = "BIO_meth_set_destroy"] + pub fn BIO_meth_set_destroy__fixed_rust( + biom: *mut BIO_METHOD, + destroy: Option c_int>, + ) -> c_int; +} diff --git a/openssl-sys/src/handwritten/bn.rs b/openssl-sys/src/handwritten/bn.rs new file mode 100644 index 0000000..81348f6 --- /dev/null +++ b/openssl-sys/src/handwritten/bn.rs @@ -0,0 +1,168 @@ +use super::super::*; +use libc::*; + +extern "C" { + pub fn BN_CTX_new() -> *mut BN_CTX; + #[cfg(ossl110)] + pub fn BN_CTX_secure_new() -> *mut BN_CTX; + pub fn BN_CTX_free(ctx: *mut BN_CTX); + pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; + pub fn BN_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; + pub fn BN_new() -> *mut BIGNUM; + #[cfg(ossl110)] + pub fn BN_secure_new() -> *mut BIGNUM; + #[cfg(ossl110)] + pub fn BN_set_flags(b: *mut BIGNUM, n: c_int); + #[cfg(ossl110)] + pub fn BN_get_flags(b: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_num_bits(bn: *const BIGNUM) -> c_int; + pub fn BN_clear_free(bn: *mut BIGNUM); + pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_bn2bin(a: *const BIGNUM, to: *mut u8) -> c_int; + #[cfg(ossl110)] + pub fn BN_bn2binpad(a: *const BIGNUM, to: *mut u8, tolen: c_int) -> c_int; + pub fn BN_sub(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_add(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_mul(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_sqr(r: *mut BIGNUM, a: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); + #[cfg(any(ossl110, libressl350))] + pub fn BN_is_negative(b: *const BIGNUM) -> c_int; + + pub fn BN_div( + dv: *mut BIGNUM, + rem: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_nnmod( + rem: *mut BIGNUM, + a: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_add( + r: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_sub( + r: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_mul( + r: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_sqr( + r: *mut BIGNUM, + a: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn BN_mod_word(r: *const BIGNUM, w: BN_ULONG) -> BN_ULONG; + pub fn BN_div_word(r: *mut BIGNUM, w: BN_ULONG) -> BN_ULONG; + pub fn BN_mul_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_add_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_sub_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_set_word(bn: *mut BIGNUM, n: BN_ULONG) -> c_int; + + pub fn BN_cmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_free(bn: *mut BIGNUM); + pub fn BN_is_bit_set(a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; + pub fn BN_exp(r: *mut BIGNUM, a: *const BIGNUM, p: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + + pub fn BN_mod_exp( + r: *mut BIGNUM, + a: *const BIGNUM, + p: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_rshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_rshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; + pub fn BN_bn2hex(a: *const BIGNUM) -> *mut c_char; + pub fn BN_bn2dec(a: *const BIGNUM) -> *mut c_char; + pub fn BN_hex2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; + pub fn BN_dec2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; + pub fn BN_gcd(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_inverse( + r: *mut BIGNUM, + a: *const BIGNUM, + n: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> *mut BIGNUM; + pub fn BN_clear(bn: *mut BIGNUM); + pub fn BN_dup(n: *const BIGNUM) -> *mut BIGNUM; + pub fn BN_ucmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int; + + pub fn BN_generate_prime_ex( + r: *mut BIGNUM, + bits: c_int, + safe: c_int, + add: *const BIGNUM, + rem: *const BIGNUM, + cb: *mut BN_GENCB, + ) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + pub fn BN_is_prime_ex( + p: *const BIGNUM, + checks: c_int, + ctx: *mut BN_CTX, + cb: *mut BN_GENCB, + ) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + pub fn BN_is_prime_fasttest_ex( + p: *const BIGNUM, + checks: c_int, + ctx: *mut BN_CTX, + do_trial_division: c_int, + cb: *mut BN_GENCB, + ) -> c_int; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + extern "C" { + pub fn BN_get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + } + } else { + extern "C" { + pub fn get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + } + } +} diff --git a/openssl-sys/src/handwritten/cms.rs b/openssl-sys/src/handwritten/cms.rs new file mode 100644 index 0000000..a13ea42 --- /dev/null +++ b/openssl-sys/src/handwritten/cms.rs @@ -0,0 +1,65 @@ +use super::super::*; +use libc::*; + +pub enum CMS_ContentInfo {} + +extern "C" { + #[cfg(ossl101)] + pub fn CMS_ContentInfo_free(cms: *mut CMS_ContentInfo); +} + +const_ptr_api! { + extern "C" { + #[cfg(ossl101)] + pub fn i2d_CMS_ContentInfo(a: #[const_ptr_if(ossl300)] CMS_ContentInfo, pp: *mut *mut c_uchar) -> c_int; + } +} + +extern "C" { + #[cfg(ossl101)] + pub fn d2i_CMS_ContentInfo( + a: *mut *mut CMS_ContentInfo, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn SMIME_read_CMS(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn CMS_sign( + signcert: *mut X509, + pkey: *mut EVP_PKEY, + certs: *mut stack_st_X509, + data: *mut BIO, + flags: c_uint, + ) -> *mut CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn CMS_verify( + cms: *mut CMS_ContentInfo, + certs: *mut stack_st_X509, + store: *mut X509_STORE, + detached_data: *mut BIO, + out: *mut BIO, + flags: c_uint, + ) -> c_int; + + #[cfg(ossl101)] + pub fn CMS_encrypt( + certs: *mut stack_st_X509, + data: *mut BIO, + cipher: *const EVP_CIPHER, + flags: c_uint, + ) -> *mut CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn CMS_decrypt( + cms: *mut CMS_ContentInfo, + pkey: *mut EVP_PKEY, + cert: *mut X509, + dcont: *mut BIO, + out: *mut BIO, + flags: c_uint, + ) -> c_int; +} diff --git a/openssl-sys/src/handwritten/conf.rs b/openssl-sys/src/handwritten/conf.rs new file mode 100644 index 0000000..2348d7d --- /dev/null +++ b/openssl-sys/src/handwritten/conf.rs @@ -0,0 +1,7 @@ +use super::super::*; + +extern "C" { + pub fn NCONF_new(meth: *mut CONF_METHOD) -> *mut CONF; + pub fn NCONF_default() -> *mut CONF_METHOD; + pub fn NCONF_free(conf: *mut CONF); +} diff --git a/openssl-sys/src/handwritten/crypto.rs b/openssl-sys/src/handwritten/crypto.rs new file mode 100644 index 0000000..62ccbce --- /dev/null +++ b/openssl-sys/src/handwritten/crypto.rs @@ -0,0 +1,85 @@ +use super::super::*; +use libc::*; + +stack!(stack_st_void); + +cfg_if! { + if #[cfg(any(ossl110, libressl271))] { + extern "C" { + pub fn OpenSSL_version_num() -> c_ulong; + pub fn OpenSSL_version(key: c_int) -> *const c_char; + } + } else { + extern "C" { + pub fn SSLeay() -> c_ulong; + pub fn SSLeay_version(key: c_int) -> *const c_char; + } + } +} + +extern "C" { + #[cfg(any(ossl110, libressl))] + pub fn CRYPTO_get_ex_new_index( + class_index: c_int, + argl: c_long, + argp: *mut c_void, + new_func: Option, + dup_func: Option, + free_func: Option, + ) -> c_int; + + #[cfg(not(ossl110))] + pub fn CRYPTO_num_locks() -> c_int; +} + +#[allow(clashing_extern_declarations)] +extern "C" { + #[cfg(not(ossl110))] + #[link_name = "CRYPTO_set_locking_callback"] + pub fn CRYPTO_set_locking_callback__fixed_rust( + func: Option, + ); + + #[cfg(not(ossl110))] + #[link_name = "CRYPTO_set_id_callback"] + pub fn CRYPTO_set_id_callback__fixed_rust(func: Option c_ulong>); +} + +extern "C" { + #[cfg(not(ossl110))] + pub fn CRYPTO_add_lock( + pointer: *mut c_int, + amount: c_int, + type_: c_int, + file: *const c_char, + line: c_int, + ) -> c_int; +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn CRYPTO_malloc(num: size_t, file: *const c_char, line: c_int) -> *mut c_void; + pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int); + } + } else { + extern "C" { + pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void; + pub fn CRYPTO_free(buf: *mut c_void); + } + } +} + +extern "C" { + #[cfg(all(ossl101, not(ossl300)))] + pub fn FIPS_mode() -> c_int; + #[cfg(all(ossl101, not(ossl300)))] + pub fn FIPS_mode_set(onoff: c_int) -> c_int; + + pub fn CRYPTO_memcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; + + #[cfg(ossl300)] + pub fn OSSL_LIB_CTX_new() -> *mut OSSL_LIB_CTX; + #[cfg(ossl300)] + pub fn OSSL_LIB_CTX_free(libcts: *mut OSSL_LIB_CTX); +} diff --git a/openssl-sys/src/handwritten/dh.rs b/openssl-sys/src/handwritten/dh.rs new file mode 100644 index 0000000..a4de122 --- /dev/null +++ b/openssl-sys/src/handwritten/dh.rs @@ -0,0 +1,50 @@ +use super::super::*; + +extern "C" { + pub fn DH_new() -> *mut DH; + pub fn DH_free(dh: *mut DH); + + pub fn DH_generate_parameters( + prime_len: c_int, + generator: c_int, + callback: Option, + cb_arg: *mut c_void, + ) -> *mut DH; + + pub fn DH_generate_parameters_ex( + dh: *mut DH, + prime_len: c_int, + generator: c_int, + cb: *mut BN_GENCB, + ) -> c_int; + + pub fn DH_generate_key(dh: *mut DH) -> c_int; + pub fn DH_compute_key(key: *mut c_uchar, pub_key: *const BIGNUM, dh: *mut DH) -> c_int; + pub fn DH_size(dh: *const DH) -> c_int; + + pub fn d2i_DHparams(k: *mut *mut DH, pp: *mut *const c_uchar, length: c_long) -> *mut DH; + pub fn i2d_DHparams(dh: *const DH, pp: *mut *mut c_uchar) -> c_int; + + #[cfg(ossl102)] + pub fn DH_get_1024_160() -> *mut DH; + #[cfg(ossl102)] + pub fn DH_get_2048_224() -> *mut DH; + #[cfg(ossl102)] + pub fn DH_get_2048_256() -> *mut DH; + + #[cfg(any(ossl110, libressl270))] + pub fn DH_set0_pqg(dh: *mut DH, p: *mut BIGNUM, q: *mut BIGNUM, g: *mut BIGNUM) -> c_int; + #[cfg(any(ossl110, libressl270))] + pub fn DH_get0_pqg( + dh: *const DH, + p: *mut *const BIGNUM, + q: *mut *const BIGNUM, + g: *mut *const BIGNUM, + ); + + #[cfg(any(ossl110, libressl270))] + pub fn DH_set0_key(dh: *mut DH, pub_key: *mut BIGNUM, priv_key: *mut BIGNUM) -> c_int; + + #[cfg(any(ossl110, libressl270))] + pub fn DH_get0_key(dh: *const DH, pub_key: *mut *const BIGNUM, priv_key: *mut *const BIGNUM); +} diff --git a/openssl-sys/src/handwritten/dsa.rs b/openssl-sys/src/handwritten/dsa.rs new file mode 100644 index 0000000..be25f23 --- /dev/null +++ b/openssl-sys/src/handwritten/dsa.rs @@ -0,0 +1,85 @@ +use libc::*; + +use super::super::*; + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum DSA_SIG {} + } else { + #[repr(C)] + pub struct DSA_SIG { + pub r: *mut BIGNUM, + pub s: *mut BIGNUM, + } + } +} + +extern "C" { + pub fn DSA_new() -> *mut DSA; + pub fn DSA_free(dsa: *mut DSA); + pub fn DSA_up_ref(dsa: *mut DSA) -> c_int; + pub fn DSA_size(dsa: *const DSA) -> c_int; + pub fn DSA_sign( + dummy: c_int, + dgst: *const c_uchar, + len: c_int, + sigret: *mut c_uchar, + siglen: *mut c_uint, + dsa: *mut DSA, + ) -> c_int; + pub fn DSA_verify( + dummy: c_int, + dgst: *const c_uchar, + len: c_int, + sigbuf: *const c_uchar, + siglen: c_int, + dsa: *mut DSA, + ) -> c_int; + + pub fn d2i_DSAPublicKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; + pub fn d2i_DSAPrivateKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) + -> *mut DSA; + + pub fn DSA_generate_parameters_ex( + dsa: *mut DSA, + bits: c_int, + seed: *const c_uchar, + seed_len: c_int, + counter_ref: *mut c_int, + h_ret: *mut c_ulong, + cb: *mut BN_GENCB, + ) -> c_int; + + pub fn DSA_generate_key(dsa: *mut DSA) -> c_int; + pub fn i2d_DSAPublicKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; + pub fn i2d_DSAPrivateKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; + + #[cfg(any(ossl110, libressl273))] + pub fn DSA_get0_pqg( + d: *const DSA, + p: *mut *const BIGNUM, + q: *mut *const BIGNUM, + q: *mut *const BIGNUM, + ); + #[cfg(any(ossl110, libressl273))] + pub fn DSA_set0_pqg(d: *mut DSA, p: *mut BIGNUM, q: *mut BIGNUM, q: *mut BIGNUM) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn DSA_get0_key(d: *const DSA, pub_key: *mut *const BIGNUM, priv_key: *mut *const BIGNUM); + #[cfg(any(ossl110, libressl273))] + pub fn DSA_set0_key(d: *mut DSA, pub_key: *mut BIGNUM, priv_key: *mut BIGNUM) -> c_int; + pub fn d2i_DSA_SIG( + sig: *mut *mut DSA_SIG, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut DSA_SIG; + pub fn i2d_DSA_SIG(a: *const DSA_SIG, pp: *mut *mut c_uchar) -> c_int; + + pub fn DSA_SIG_new() -> *mut DSA_SIG; + pub fn DSA_SIG_free(sig: *mut DSA_SIG); + + #[cfg(any(ossl110, libressl273))] + pub fn DSA_SIG_get0(sig: *const DSA_SIG, pr: *mut *const BIGNUM, ps: *mut *const BIGNUM); + + #[cfg(any(ossl110, libressl273))] + pub fn DSA_SIG_set0(sig: *mut DSA_SIG, pr: *mut BIGNUM, ps: *mut BIGNUM) -> c_int; +} diff --git a/openssl-sys/src/handwritten/ec.rs b/openssl-sys/src/handwritten/ec.rs new file mode 100644 index 0000000..6ee475f --- /dev/null +++ b/openssl-sys/src/handwritten/ec.rs @@ -0,0 +1,255 @@ +use super::super::*; +use libc::*; + +#[repr(C)] +#[derive(Copy, Clone)] +pub enum point_conversion_form_t { + POINT_CONVERSION_COMPRESSED = 2, + POINT_CONVERSION_UNCOMPRESSED = 4, + POINT_CONVERSION_HYBRID = 6, +} + +pub enum EC_METHOD {} +pub enum EC_GROUP {} +pub enum EC_POINT {} + +extern "C" { + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_GF2m_simple_method() -> *const EC_METHOD; + + pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP; + + pub fn EC_GROUP_free(group: *mut EC_GROUP); + + pub fn EC_GROUP_get_order( + group: *const EC_GROUP, + order: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_GROUP_get_cofactor( + group: *const EC_GROUP, + cofactor: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_GROUP_get0_generator(group: *const EC_GROUP) -> *const EC_POINT; + + pub fn EC_GROUP_set_generator( + group: *mut EC_GROUP, + generator: *const EC_POINT, + order: *const BIGNUM, + cofactor: *const BIGNUM, + ) -> c_int; + + pub fn EC_GROUP_get_curve_name(group: *const EC_GROUP) -> c_int; + + pub fn EC_GROUP_set_asn1_flag(key: *mut EC_GROUP, flag: c_int); + + pub fn EC_GROUP_get_curve_GFp( + group: *const EC_GROUP, + p: *mut BIGNUM, + a: *mut BIGNUM, + b: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_GROUP_get_curve_GF2m( + group: *const EC_GROUP, + p: *mut BIGNUM, + a: *mut BIGNUM, + b: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_GROUP_get_degree(group: *const EC_GROUP) -> c_int; + + #[cfg(ossl110)] + pub fn EC_GROUP_order_bits(group: *const EC_GROUP) -> c_int; + + pub fn EC_GROUP_new_curve_GFp( + p: *const BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> *mut EC_GROUP; + + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_GROUP_new_curve_GF2m( + p: *const BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> *mut EC_GROUP; + + pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP; + + pub fn EC_POINT_is_at_infinity(group: *const EC_GROUP, point: *const EC_POINT) -> c_int; + + pub fn EC_POINT_is_on_curve( + group: *const EC_GROUP, + point: *const EC_POINT, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT; + + pub fn EC_POINT_free(point: *mut EC_POINT); + + pub fn EC_POINT_dup(p: *const EC_POINT, group: *const EC_GROUP) -> *mut EC_POINT; + + #[cfg(ossl111)] + pub fn EC_POINT_get_affine_coordinates( + group: *const EC_GROUP, + p: *const EC_POINT, + x: *mut BIGNUM, + y: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_get_affine_coordinates_GFp( + group: *const EC_GROUP, + p: *const EC_POINT, + x: *mut BIGNUM, + y: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_set_affine_coordinates_GFp( + group: *const EC_GROUP, + p: *mut EC_POINT, + x: *const BIGNUM, + y: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_POINT_get_affine_coordinates_GF2m( + group: *const EC_GROUP, + p: *const EC_POINT, + x: *mut BIGNUM, + y: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_point2oct( + group: *const EC_GROUP, + p: *const EC_POINT, + form: point_conversion_form_t, + buf: *mut c_uchar, + len: size_t, + ctx: *mut BN_CTX, + ) -> size_t; + + pub fn EC_POINT_oct2point( + group: *const EC_GROUP, + p: *mut EC_POINT, + buf: *const c_uchar, + len: size_t, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_add( + group: *const EC_GROUP, + r: *mut EC_POINT, + a: *const EC_POINT, + b: *const EC_POINT, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_invert(group: *const EC_GROUP, r: *mut EC_POINT, ctx: *mut BN_CTX) -> c_int; + + pub fn EC_POINT_cmp( + group: *const EC_GROUP, + a: *const EC_POINT, + b: *const EC_POINT, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_mul( + group: *const EC_GROUP, + r: *mut EC_POINT, + n: *const BIGNUM, + q: *const EC_POINT, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_KEY_new() -> *mut EC_KEY; + + pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY; + + pub fn EC_KEY_free(key: *mut EC_KEY); + + pub fn EC_KEY_dup(key: *const EC_KEY) -> *mut EC_KEY; + + pub fn EC_KEY_up_ref(key: *mut EC_KEY) -> c_int; + + pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP; + + pub fn EC_KEY_set_group(key: *mut EC_KEY, group: *const EC_GROUP) -> c_int; + + pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; + + pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int; + + pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT; + + pub fn EC_KEY_set_public_key(key: *mut EC_KEY, key: *const EC_POINT) -> c_int; + + pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int; + + pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int; + + pub fn EC_KEY_set_public_key_affine_coordinates( + key: *mut EC_KEY, + x: *mut BIGNUM, + y: *mut BIGNUM, + ) -> c_int; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum ECDSA_SIG {} + } else { + #[repr(C)] + pub struct ECDSA_SIG { + pub r: *mut BIGNUM, + pub s: *mut BIGNUM, + } + } +} + +extern "C" { + pub fn ECDSA_SIG_new() -> *mut ECDSA_SIG; + + pub fn ECDSA_SIG_free(sig: *mut ECDSA_SIG); + + #[cfg(any(ossl110, libressl273))] + pub fn ECDSA_SIG_get0(sig: *const ECDSA_SIG, pr: *mut *const BIGNUM, ps: *mut *const BIGNUM); + + #[cfg(any(ossl110, libressl273))] + pub fn ECDSA_SIG_set0(sig: *mut ECDSA_SIG, pr: *mut BIGNUM, ps: *mut BIGNUM) -> c_int; + + pub fn ECDSA_do_sign( + dgst: *const c_uchar, + dgst_len: c_int, + eckey: *mut EC_KEY, + ) -> *mut ECDSA_SIG; + + pub fn ECDSA_do_verify( + dgst: *const c_uchar, + dgst_len: c_int, + sig: *const ECDSA_SIG, + eckey: *mut EC_KEY, + ) -> c_int; + + pub fn d2i_ECDSA_SIG( + sig: *mut *mut ECDSA_SIG, + inp: *mut *const c_uchar, + length: c_long, + ) -> *mut ECDSA_SIG; + + pub fn i2d_ECDSA_SIG(sig: *const ECDSA_SIG, out: *mut *mut c_uchar) -> c_int; +} diff --git a/openssl-sys/src/handwritten/err.rs b/openssl-sys/src/handwritten/err.rs new file mode 100644 index 0000000..5653c1d --- /dev/null +++ b/openssl-sys/src/handwritten/err.rs @@ -0,0 +1,55 @@ +use super::super::*; +use libc::*; + +#[repr(C)] +pub struct ERR_STRING_DATA { + pub error: c_ulong, + pub string: *const c_char, +} + +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn ERR_new(); + pub fn ERR_set_debug(file: *const c_char, line: c_int, func: *const c_char); + pub fn ERR_set_error(lib: c_int, reason: c_int, fmt: *const c_char, ...); + } + } else { + extern "C" { + pub fn ERR_put_error(lib: c_int, func: c_int, reason: c_int, file: *const c_char, line: c_int); + } + } +} + +extern "C" { + pub fn ERR_set_error_data(data: *mut c_char, flags: c_int); + + pub fn ERR_get_error() -> c_ulong; + #[cfg(ossl300)] + pub fn ERR_get_error_all( + file: *mut *const c_char, + line: *mut c_int, + func: *mut *const c_char, + data: *mut *const c_char, + flags: *mut c_int, + ) -> c_ulong; + pub fn ERR_get_error_line_data( + file: *mut *const c_char, + line: *mut c_int, + data: *mut *const c_char, + flags: *mut c_int, + ) -> c_ulong; + pub fn ERR_peek_last_error() -> c_ulong; + pub fn ERR_clear_error(); + pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; + #[cfg(ossl110)] + pub fn ERR_load_strings(lib: c_int, str: *mut ERR_STRING_DATA) -> c_int; + #[cfg(not(ossl110))] + pub fn ERR_load_strings(lib: c_int, str: *mut ERR_STRING_DATA); + #[cfg(not(ossl110))] + pub fn ERR_load_crypto_strings(); + + pub fn ERR_get_next_error_library() -> c_int; +} diff --git a/openssl-sys/src/handwritten/evp.rs b/openssl-sys/src/handwritten/evp.rs new file mode 100644 index 0000000..1a05b7e --- /dev/null +++ b/openssl-sys/src/handwritten/evp.rs @@ -0,0 +1,600 @@ +use super::super::*; +use libc::*; + +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn EVP_MD_get_block_size(md: *const EVP_MD) -> c_int; + pub fn EVP_MD_get_size(md: *const EVP_MD) -> c_int; + pub fn EVP_MD_get_type(md: *const EVP_MD) -> c_int; + + pub fn EVP_MD_CTX_get0_md(ctx: *const EVP_MD_CTX) -> *const EVP_MD; + + pub fn EVP_CIPHER_get_key_length(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_get_block_size(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_get_iv_length(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_get_nid(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_fetch( + ctx: *mut OSSL_LIB_CTX, + algorithm: *const c_char, + properties: *const c_char, + ) -> *mut EVP_CIPHER; + pub fn EVP_CIPHER_free(cipher: *mut EVP_CIPHER); + + pub fn EVP_CIPHER_CTX_get0_cipher(ctx: *const EVP_CIPHER_CTX) -> *const EVP_CIPHER; + pub fn EVP_CIPHER_CTX_get_block_size(ctx: *const EVP_CIPHER_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_get_key_length(ctx: *const EVP_CIPHER_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_get_iv_length(ctx: *const EVP_CIPHER_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_get_tag_length(ctx: *const EVP_CIPHER_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_get_num(ctx: *const EVP_CIPHER_CTX) -> c_int; + } + } else { + extern "C" { + pub fn EVP_MD_block_size(md: *const EVP_MD) -> c_int; + pub fn EVP_MD_size(md: *const EVP_MD) -> c_int; + pub fn EVP_MD_type(md: *const EVP_MD) -> c_int; + + pub fn EVP_MD_CTX_md(ctx: *const EVP_MD_CTX) -> *const EVP_MD; + + pub fn EVP_CIPHER_key_length(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_block_size(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_iv_length(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_nid(cipher: *const EVP_CIPHER) -> c_int; + + pub fn EVP_CIPHER_CTX_cipher(ctx: *const EVP_CIPHER_CTX) -> *const EVP_CIPHER; + pub fn EVP_CIPHER_CTX_block_size(ctx: *const EVP_CIPHER_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_key_length(ctx: *const EVP_CIPHER_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_iv_length(ctx: *const EVP_CIPHER_CTX) -> c_int; + #[cfg(ossl110)] + pub fn EVP_CIPHER_CTX_num(ctx: *const EVP_CIPHER_CTX) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX; + pub fn EVP_MD_CTX_free(ctx: *mut EVP_MD_CTX); + } + } else { + extern "C" { + pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; + pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); + } + } +} + +extern "C" { + pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *mut ENGINE) + -> c_int; + pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const c_void, n: size_t) -> c_int; + pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; + #[cfg(ossl300)] + pub fn EVP_Q_digest( + libctx: *mut OSSL_LIB_CTX, + name: *const c_char, + propq: *const c_char, + data: *const c_void, + count: size_t, + md: *mut c_uchar, + size: *mut size_t, + ) -> c_int; + pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD) -> c_int; + pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; + #[cfg(ossl111)] + pub fn EVP_DigestFinalXOF(ctx: *mut EVP_MD_CTX, res: *mut u8, len: usize) -> c_int; + + #[cfg(ossl300)] + pub fn EVP_MD_fetch( + ctx: *mut OSSL_LIB_CTX, + algorithm: *const c_char, + properties: *const c_char, + ) -> *mut EVP_MD; + + #[cfg(ossl300)] + pub fn EVP_MD_free(md: *mut EVP_MD); + + pub fn EVP_BytesToKey( + typ: *const EVP_CIPHER, + md: *const EVP_MD, + salt: *const u8, + data: *const u8, + datalen: c_int, + count: c_int, + key: *mut u8, + iv: *mut u8, + ) -> c_int; + + pub fn EVP_CipherInit( + ctx: *mut EVP_CIPHER_CTX, + evp: *const EVP_CIPHER, + key: *const u8, + iv: *const u8, + mode: c_int, + ) -> c_int; + pub fn EVP_CipherInit_ex( + ctx: *mut EVP_CIPHER_CTX, + type_: *const EVP_CIPHER, + impl_: *mut ENGINE, + key: *const c_uchar, + iv: *const c_uchar, + enc: c_int, + ) -> c_int; + pub fn EVP_CipherUpdate( + ctx: *mut EVP_CIPHER_CTX, + outbuf: *mut u8, + outlen: *mut c_int, + inbuf: *const u8, + inlen: c_int, + ) -> c_int; + pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: *mut c_int) -> c_int; + + pub fn EVP_DigestSignInit( + ctx: *mut EVP_MD_CTX, + pctx: *mut *mut EVP_PKEY_CTX, + type_: *const EVP_MD, + e: *mut ENGINE, + pkey: *mut EVP_PKEY, + ) -> c_int; + + #[cfg(ossl300)] + pub fn EVP_DigestSignUpdate(ctx: *mut EVP_MD_CTX, data: *const c_void, dsize: size_t) -> c_int; + pub fn EVP_DigestSignFinal( + ctx: *mut EVP_MD_CTX, + sig: *mut c_uchar, + siglen: *mut size_t, + ) -> c_int; + pub fn EVP_DigestVerifyInit( + ctx: *mut EVP_MD_CTX, + pctx: *mut *mut EVP_PKEY_CTX, + type_: *const EVP_MD, + e: *mut ENGINE, + pkey: *mut EVP_PKEY, + ) -> c_int; + #[cfg(ossl300)] + pub fn EVP_DigestVerifyUpdate( + ctx: *mut EVP_MD_CTX, + data: *const c_void, + dsize: size_t, + ) -> c_int; + pub fn EVP_SealInit( + ctx: *mut EVP_CIPHER_CTX, + type_: *const EVP_CIPHER, + ek: *mut *mut c_uchar, + ekl: *mut c_int, + iv: *mut c_uchar, + pubk: *mut *mut EVP_PKEY, + npubk: c_int, + ) -> c_int; + pub fn EVP_SealFinal(ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int) -> c_int; + pub fn EVP_EncryptInit_ex( + ctx: *mut EVP_CIPHER_CTX, + cipher: *const EVP_CIPHER, + impl_: *mut ENGINE, + key: *const c_uchar, + iv: *const c_uchar, + ) -> c_int; + pub fn EVP_EncryptUpdate( + ctx: *mut EVP_CIPHER_CTX, + out: *mut c_uchar, + outl: *mut c_int, + in_: *const u8, + inl: c_int, + ) -> c_int; + pub fn EVP_EncryptFinal_ex( + ctx: *mut EVP_CIPHER_CTX, + out: *mut c_uchar, + outl: *mut c_int, + ) -> c_int; + pub fn EVP_OpenInit( + ctx: *mut EVP_CIPHER_CTX, + type_: *const EVP_CIPHER, + ek: *const c_uchar, + ekl: c_int, + iv: *const c_uchar, + priv_: *mut EVP_PKEY, + ) -> c_int; + pub fn EVP_OpenFinal(ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int) -> c_int; + pub fn EVP_DecryptInit_ex( + ctx: *mut EVP_CIPHER_CTX, + cipher: *const EVP_CIPHER, + impl_: *mut ENGINE, + key: *const c_uchar, + iv: *const c_uchar, + ) -> c_int; + pub fn EVP_DecryptUpdate( + ctx: *mut EVP_CIPHER_CTX, + out: *mut c_uchar, + outl: *mut c_int, + in_: *const u8, + inl: c_int, + ) -> c_int; + pub fn EVP_DecryptFinal_ex( + ctx: *mut EVP_CIPHER_CTX, + outm: *mut c_uchar, + outl: *mut c_int, + ) -> c_int; +} +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn EVP_PKEY_get_size(pkey: *const EVP_PKEY) -> c_int; + } + } else { + const_ptr_api! { + extern "C" { + pub fn EVP_PKEY_size(pkey: #[const_ptr_if(any(ossl111b, libressl280))] EVP_PKEY) -> c_int; + } + } + } +} +cfg_if! { + if #[cfg(any(ossl111, libressl370))] { + extern "C" { + pub fn EVP_DigestSign( + ctx: *mut EVP_MD_CTX, + sigret: *mut c_uchar, + siglen: *mut size_t, + tbs: *const c_uchar, + tbslen: size_t + ) -> c_int; + + pub fn EVP_DigestVerify( + ctx: *mut EVP_MD_CTX, + sigret: *const c_uchar, + siglen: size_t, + tbs: *const c_uchar, + tbslen: size_t + ) -> c_int; + } + } +} +const_ptr_api! { + extern "C" { + pub fn EVP_DigestVerifyFinal( + ctx: *mut EVP_MD_CTX, + sigret: #[const_ptr_if(any(ossl102, libressl280))] c_uchar, + siglen: size_t, + ) -> c_int; + } +} + +extern "C" { + pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; + pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX); + pub fn EVP_MD_CTX_copy_ex(dst: *mut EVP_MD_CTX, src: *const EVP_MD_CTX) -> c_int; + #[cfg(ossl111)] + pub fn EVP_MD_CTX_reset(ctx: *mut EVP_MD_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_set_key_length(ctx: *mut EVP_CIPHER_CTX, keylen: c_int) -> c_int; + pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int; + pub fn EVP_CIPHER_CTX_ctrl( + ctx: *mut EVP_CIPHER_CTX, + type_: c_int, + arg: c_int, + ptr: *mut c_void, + ) -> c_int; + pub fn EVP_CIPHER_CTX_rand_key(ctx: *mut EVP_CIPHER_CTX, key: *mut c_uchar) -> c_int; + + pub fn EVP_md_null() -> *const EVP_MD; + pub fn EVP_md5() -> *const EVP_MD; + pub fn EVP_sha1() -> *const EVP_MD; + pub fn EVP_sha224() -> *const EVP_MD; + pub fn EVP_sha256() -> *const EVP_MD; + pub fn EVP_sha384() -> *const EVP_MD; + pub fn EVP_sha512() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_224() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_256() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_384() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_512() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_shake128() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_shake256() -> *const EVP_MD; + pub fn EVP_ripemd160() -> *const EVP_MD; + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))] + pub fn EVP_sm3() -> *const EVP_MD; + pub fn EVP_des_ecb() -> *const EVP_CIPHER; + pub fn EVP_des_ede3() -> *const EVP_CIPHER; + pub fn EVP_des_ede3_cbc() -> *const EVP_CIPHER; + pub fn EVP_des_ede3_cfb64() -> *const EVP_CIPHER; + pub fn EVP_des_cbc() -> *const EVP_CIPHER; + pub fn EVP_rc4() -> *const EVP_CIPHER; + pub fn EVP_bf_ecb() -> *const EVP_CIPHER; + pub fn EVP_bf_cbc() -> *const EVP_CIPHER; + pub fn EVP_bf_cfb64() -> *const EVP_CIPHER; + pub fn EVP_bf_ofb() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cbc() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cfb1() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cfb8() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cfb128() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ctr() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ccm() -> *const EVP_CIPHER; + pub fn EVP_aes_128_gcm() -> *const EVP_CIPHER; + pub fn EVP_aes_128_xts() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ofb() -> *const EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_aes_128_ocb() -> *const EVP_CIPHER; + pub fn EVP_aes_192_ecb() -> *const EVP_CIPHER; + pub fn EVP_aes_192_cbc() -> *const EVP_CIPHER; + pub fn EVP_aes_192_cfb1() -> *const EVP_CIPHER; + pub fn EVP_aes_192_cfb8() -> *const EVP_CIPHER; + pub fn EVP_aes_192_cfb128() -> *const EVP_CIPHER; + pub fn EVP_aes_192_ctr() -> *const EVP_CIPHER; + pub fn EVP_aes_192_ccm() -> *const EVP_CIPHER; + pub fn EVP_aes_192_gcm() -> *const EVP_CIPHER; + pub fn EVP_aes_192_ofb() -> *const EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_aes_192_ocb() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cfb8() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cfb128() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ctr() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ccm() -> *const EVP_CIPHER; + pub fn EVP_aes_256_gcm() -> *const EVP_CIPHER; + pub fn EVP_aes_256_xts() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ofb() -> *const EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_aes_256_ocb() -> *const EVP_CIPHER; + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] + pub fn EVP_chacha20() -> *const EVP_CIPHER; + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] + pub fn EVP_chacha20_poly1305() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + pub fn EVP_seed_cbc() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + pub fn EVP_seed_cfb128() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + pub fn EVP_seed_ecb() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + pub fn EVP_seed_ofb() -> *const EVP_CIPHER; + + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] + pub fn EVP_sm4_ecb() -> *const EVP_CIPHER; + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] + pub fn EVP_sm4_cbc() -> *const EVP_CIPHER; + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] + pub fn EVP_sm4_cfb128() -> *const EVP_CIPHER; + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] + pub fn EVP_sm4_ofb() -> *const EVP_CIPHER; + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] + pub fn EVP_sm4_ctr() -> *const EVP_CIPHER; + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))] + pub fn EVP_camellia_128_cfb128() -> *const EVP_CIPHER; + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))] + pub fn EVP_camellia_128_ecb() -> *const EVP_CIPHER; + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))] + pub fn EVP_camellia_192_cfb128() -> *const EVP_CIPHER; + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))] + pub fn EVP_camellia_192_ecb() -> *const EVP_CIPHER; + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))] + pub fn EVP_camellia_256_cfb128() -> *const EVP_CIPHER; + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))] + pub fn EVP_camellia_256_ecb() -> *const EVP_CIPHER; + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] + pub fn EVP_cast5_cfb64() -> *const EVP_CIPHER; + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] + pub fn EVP_cast5_ecb() -> *const EVP_CIPHER; + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_IDEA")))] + pub fn EVP_idea_cfb64() -> *const EVP_CIPHER; + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_IDEA")))] + pub fn EVP_idea_ecb() -> *const EVP_CIPHER; + + #[cfg(not(ossl110))] + pub fn OPENSSL_add_all_algorithms_noconf(); + + pub fn EVP_get_digestbyname(name: *const c_char) -> *const EVP_MD; + pub fn EVP_get_cipherbyname(name: *const c_char) -> *const EVP_CIPHER; +} + +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn EVP_PKEY_get_id(pkey: *const EVP_PKEY) -> c_int; + pub fn EVP_PKEY_get_bits(key: *const EVP_PKEY) -> c_int; + pub fn EVP_PKEY_get_security_bits(key: *const EVP_PKEY) -> c_int; + } + + #[inline] + pub unsafe fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_id(pkey) + } + + #[inline] + pub unsafe fn EVP_PKEY_bits(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_bits(pkey) + } + + #[inline] + pub unsafe fn EVP_PKEY_security_bits(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_security_bits(pkey) + } + + } else { + extern "C" { + pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int; + } + const_ptr_api! { + extern "C" { + pub fn EVP_PKEY_bits(key: #[const_ptr_if(any(ossl110, libressl280))] EVP_PKEY) -> c_int; + #[cfg(any(ossl110, libressl360))] + pub fn EVP_PKEY_security_bits(pkey: #[const_ptr_if(any(ossl110, libressl280))] EVP_PKEY) -> c_int; + } + } + } +} +extern "C" { + pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *mut c_void) -> c_int; + + pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; + pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; + pub fn EVP_PKEY_get1_DSA(k: *mut EVP_PKEY) -> *mut DSA; + pub fn EVP_PKEY_get1_DH(k: *mut EVP_PKEY) -> *mut DH; + pub fn EVP_PKEY_get1_EC_KEY(k: *mut EVP_PKEY) -> *mut EC_KEY; + + pub fn EVP_PKEY_new() -> *mut EVP_PKEY; + pub fn EVP_PKEY_free(k: *mut EVP_PKEY); + #[cfg(any(ossl110, libressl270))] + pub fn EVP_PKEY_up_ref(pkey: *mut EVP_PKEY) -> c_int; + + pub fn d2i_AutoPrivateKey( + a: *mut *mut EVP_PKEY, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut EVP_PKEY; + + pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int; + + pub fn EVP_PKEY_copy_parameters(to: *mut EVP_PKEY, from: *const EVP_PKEY) -> c_int; + + pub fn PKCS5_PBKDF2_HMAC_SHA1( + pass: *const c_char, + passlen: c_int, + salt: *const u8, + saltlen: c_int, + iter: c_int, + keylen: c_int, + out: *mut u8, + ) -> c_int; + pub fn PKCS5_PBKDF2_HMAC( + pass: *const c_char, + passlen: c_int, + salt: *const c_uchar, + saltlen: c_int, + iter: c_int, + digest: *const EVP_MD, + keylen: c_int, + out: *mut u8, + ) -> c_int; + + #[cfg(ossl110)] + pub fn EVP_PBE_scrypt( + pass: *const c_char, + passlen: size_t, + salt: *const c_uchar, + saltlen: size_t, + N: u64, + r: u64, + p: u64, + maxmem: u64, + key: *mut c_uchar, + keylen: size_t, + ) -> c_int; + + pub fn EVP_PKEY_CTX_new(k: *mut EVP_PKEY, e: *mut ENGINE) -> *mut EVP_PKEY_CTX; + pub fn EVP_PKEY_CTX_new_id(id: c_int, e: *mut ENGINE) -> *mut EVP_PKEY_CTX; + pub fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX); + + pub fn EVP_PKEY_CTX_ctrl( + ctx: *mut EVP_PKEY_CTX, + keytype: c_int, + optype: c_int, + cmd: c_int, + p1: c_int, + p2: *mut c_void, + ) -> c_int; + + pub fn EVP_PKEY_new_mac_key( + type_: c_int, + e: *mut ENGINE, + key: *const c_uchar, + keylen: c_int, + ) -> *mut EVP_PKEY; + + pub fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_derive_set_peer(ctx: *mut EVP_PKEY_CTX, peer: *mut EVP_PKEY) -> c_int; + pub fn EVP_PKEY_derive(ctx: *mut EVP_PKEY_CTX, key: *mut c_uchar, size: *mut size_t) -> c_int; + + #[cfg(ossl300)] + pub fn EVP_PKEY_Q_keygen( + libctx: *mut OSSL_LIB_CTX, + propq: *const c_char, + type_: *const c_char, + ... + ) -> *mut EVP_PKEY; + pub fn EVP_PKEY_keygen_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_keygen(ctx: *mut EVP_PKEY_CTX, key: *mut *mut EVP_PKEY) -> c_int; + + pub fn EVP_PKEY_sign_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_sign( + ctx: *mut EVP_PKEY_CTX, + sig: *mut c_uchar, + siglen: *mut size_t, + tbs: *const c_uchar, + tbslen: size_t, + ) -> c_int; + pub fn EVP_PKEY_verify_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_verify( + ctx: *mut EVP_PKEY_CTX, + sig: *const c_uchar, + siglen: size_t, + tbs: *const c_uchar, + tbslen: size_t, + ) -> c_int; + pub fn EVP_PKEY_encrypt_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_encrypt( + ctx: *mut EVP_PKEY_CTX, + pout: *mut c_uchar, + poutlen: *mut size_t, + pin: *const c_uchar, + pinlen: size_t, + ) -> c_int; + pub fn EVP_PKEY_decrypt_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_decrypt( + ctx: *mut EVP_PKEY_CTX, + pout: *mut c_uchar, + poutlen: *mut size_t, + pin: *const c_uchar, + pinlen: size_t, + ) -> c_int; +} + +const_ptr_api! { + extern "C" { + pub fn EVP_PKCS82PKEY(p8: #[const_ptr_if(any(ossl110, libressl280))] PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY; + } +} + +cfg_if! { + if #[cfg(any(ossl111, libressl370))] { + extern "C" { + pub fn EVP_PKEY_get_raw_public_key( + pkey: *const EVP_PKEY, + ppub: *mut c_uchar, + len: *mut size_t, + ) -> c_int; + pub fn EVP_PKEY_new_raw_public_key( + ttype: c_int, + e: *mut ENGINE, + key: *const c_uchar, + keylen: size_t, + ) -> *mut EVP_PKEY; + pub fn EVP_PKEY_get_raw_private_key( + pkey: *const EVP_PKEY, + ppriv: *mut c_uchar, + len: *mut size_t, + ) -> c_int; + pub fn EVP_PKEY_new_raw_private_key( + ttype: c_int, + e: *mut ENGINE, + key: *const c_uchar, + keylen: size_t, + ) -> *mut EVP_PKEY; + } + } +} + +extern "C" { + pub fn EVP_EncodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int; + pub fn EVP_DecodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int; +} diff --git a/openssl-sys/src/handwritten/hmac.rs b/openssl-sys/src/handwritten/hmac.rs new file mode 100644 index 0000000..b52d63f --- /dev/null +++ b/openssl-sys/src/handwritten/hmac.rs @@ -0,0 +1,30 @@ +use libc::*; + +use super::super::*; + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + extern "C" { + pub fn HMAC_CTX_new() -> *mut HMAC_CTX; + pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); + } + } else { + extern "C" { + pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX); + pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX); + } + } +} + +extern "C" { + pub fn HMAC_Init_ex( + ctx: *mut HMAC_CTX, + key: *const c_void, + len: c_int, + md: *const EVP_MD, + impl_: *mut ENGINE, + ) -> c_int; + pub fn HMAC_Update(ctx: *mut HMAC_CTX, data: *const c_uchar, len: size_t) -> c_int; + pub fn HMAC_Final(ctx: *mut HMAC_CTX, md: *mut c_uchar, len: *mut c_uint) -> c_int; + pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; +} diff --git a/openssl-sys/src/handwritten/kdf.rs b/openssl-sys/src/handwritten/kdf.rs new file mode 100644 index 0000000..0f14b63 --- /dev/null +++ b/openssl-sys/src/handwritten/kdf.rs @@ -0,0 +1,26 @@ +use super::super::*; +use libc::*; + +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn EVP_PKEY_CTX_set_hkdf_mode(ctx: *mut EVP_PKEY_CTX, mode: c_int) -> c_int; + pub fn EVP_PKEY_CTX_set_hkdf_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int; + pub fn EVP_PKEY_CTX_set1_hkdf_salt( + ctx: *mut EVP_PKEY_CTX, + salt: *const u8, + saltlen: c_int, + ) -> c_int; + pub fn EVP_PKEY_CTX_set1_hkdf_key( + ctx: *mut EVP_PKEY_CTX, + key: *const u8, + keylen: c_int, + ) -> c_int; + pub fn EVP_PKEY_CTX_add1_hkdf_info( + ctx: *mut EVP_PKEY_CTX, + info: *const u8, + infolen: c_int, + ) -> c_int; + } + } +} diff --git a/openssl-sys/src/handwritten/mod.rs b/openssl-sys/src/handwritten/mod.rs new file mode 100644 index 0000000..28aa4ae --- /dev/null +++ b/openssl-sys/src/handwritten/mod.rs @@ -0,0 +1,65 @@ +pub use self::aes::*; +pub use self::asn1::*; +pub use self::bio::*; +pub use self::bn::*; +pub use self::cms::*; +pub use self::conf::*; +pub use self::crypto::*; +pub use self::dh::*; +pub use self::dsa::*; +pub use self::ec::*; +pub use self::err::*; +pub use self::evp::*; +pub use self::hmac::*; +pub use self::kdf::*; +pub use self::object::*; +pub use self::ocsp::*; +pub use self::pem::*; +pub use self::pkcs12::*; +pub use self::pkcs7::*; +pub use self::provider::*; +pub use self::rand::*; +pub use self::rsa::*; +pub use self::safestack::*; +pub use self::sha::*; +pub use self::srtp::*; +pub use self::ssl::*; +pub use self::stack::*; +pub use self::tls1::*; +pub use self::types::*; +pub use self::x509::*; +pub use self::x509_vfy::*; +pub use self::x509v3::*; + +mod aes; +mod asn1; +mod bio; +mod bn; +mod cms; +mod conf; +mod crypto; +mod dh; +mod dsa; +mod ec; +mod err; +mod evp; +mod hmac; +mod kdf; +mod object; +mod ocsp; +mod pem; +mod pkcs12; +mod pkcs7; +mod provider; +mod rand; +mod rsa; +mod safestack; +mod sha; +mod srtp; +mod ssl; +mod stack; +mod tls1; +mod types; +mod x509; +mod x509_vfy; +mod x509v3; diff --git a/openssl-sys/src/handwritten/object.rs b/openssl-sys/src/handwritten/object.rs new file mode 100644 index 0000000..06e6553 --- /dev/null +++ b/openssl-sys/src/handwritten/object.rs @@ -0,0 +1,30 @@ +use libc::*; + +use super::super::*; + +extern "C" { + pub fn OBJ_nid2ln(nid: c_int) -> *const c_char; + pub fn OBJ_nid2sn(nid: c_int) -> *const c_char; + pub fn OBJ_nid2obj(n: c_int) -> *mut ASN1_OBJECT; + pub fn OBJ_obj2nid(o: *const ASN1_OBJECT) -> c_int; + pub fn OBJ_obj2txt( + buf: *mut c_char, + buf_len: c_int, + a: *const ASN1_OBJECT, + no_name: c_int, + ) -> c_int; + + pub fn OBJ_find_sigid_algs(signid: c_int, pdig_nid: *mut c_int, ppkey_nid: *mut c_int) + -> c_int; + pub fn OBJ_sn2nid(sn: *const libc::c_char) -> libc::c_int; + pub fn OBJ_txt2obj(s: *const libc::c_char, no_name: libc::c_int) -> *mut ASN1_OBJECT; + pub fn OBJ_create( + oid: *const libc::c_char, + sn: *const libc::c_char, + ln: *const libc::c_char, + ) -> c_int; + #[cfg(ossl111)] + pub fn OBJ_length(obj: *const ASN1_OBJECT) -> libc::size_t; + #[cfg(ossl111)] + pub fn OBJ_get0_data(obj: *const ASN1_OBJECT) -> *const c_uchar; +} diff --git a/openssl-sys/src/handwritten/ocsp.rs b/openssl-sys/src/handwritten/ocsp.rs new file mode 100644 index 0000000..c194a83 --- /dev/null +++ b/openssl-sys/src/handwritten/ocsp.rs @@ -0,0 +1,89 @@ +use super::super::*; +use libc::*; + +pub enum OCSP_CERTID {} + +pub enum OCSP_ONEREQ {} + +pub enum OCSP_REQUEST {} + +pub enum OCSP_BASICRESP {} + +const_ptr_api! { + extern "C" { + pub fn OCSP_cert_to_id( + dgst: *const EVP_MD, + subject: #[const_ptr_if(any(ossl110, libressl281))] X509, + issuer: #[const_ptr_if(any(ossl110, libressl281))] X509, + ) -> *mut OCSP_CERTID; + } +} + +extern "C" { + pub fn OCSP_request_add0_id(r: *mut OCSP_REQUEST, id: *mut OCSP_CERTID) -> *mut OCSP_ONEREQ; + + pub fn OCSP_resp_find_status( + bs: *mut OCSP_BASICRESP, + id: *mut OCSP_CERTID, + status: *mut c_int, + reason: *mut c_int, + revtime: *mut *mut ASN1_GENERALIZEDTIME, + thisupd: *mut *mut ASN1_GENERALIZEDTIME, + nextupd: *mut *mut ASN1_GENERALIZEDTIME, + ) -> c_int; + pub fn OCSP_check_validity( + thisupd: *mut ASN1_GENERALIZEDTIME, + nextupd: *mut ASN1_GENERALIZEDTIME, + sec: c_long, + maxsec: c_long, + ) -> c_int; + + pub fn OCSP_response_status(resp: *mut OCSP_RESPONSE) -> c_int; + pub fn OCSP_response_get1_basic(resp: *mut OCSP_RESPONSE) -> *mut OCSP_BASICRESP; + + pub fn OCSP_response_create(status: c_int, bs: *mut OCSP_BASICRESP) -> *mut OCSP_RESPONSE; + + pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; + pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP); + pub fn OCSP_RESPONSE_new() -> *mut OCSP_RESPONSE; + pub fn OCSP_RESPONSE_free(r: *mut OCSP_RESPONSE); +} + +const_ptr_api! { + extern "C" { + pub fn i2d_OCSP_RESPONSE(a: #[const_ptr_if(ossl300)] OCSP_RESPONSE, pp: *mut *mut c_uchar) -> c_int; + } +} + +extern "C" { + pub fn d2i_OCSP_RESPONSE( + a: *mut *mut OCSP_RESPONSE, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut OCSP_RESPONSE; + pub fn OCSP_ONEREQ_free(r: *mut OCSP_ONEREQ); + pub fn OCSP_CERTID_free(id: *mut OCSP_CERTID); + pub fn OCSP_REQUEST_new() -> *mut OCSP_REQUEST; + pub fn OCSP_REQUEST_free(r: *mut OCSP_REQUEST); +} + +const_ptr_api! { + extern "C" { + pub fn i2d_OCSP_REQUEST(a: #[const_ptr_if(ossl300)] OCSP_REQUEST, pp: *mut *mut c_uchar) -> c_int; + } +} + +extern "C" { + pub fn d2i_OCSP_REQUEST( + a: *mut *mut OCSP_REQUEST, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut OCSP_REQUEST; + + pub fn OCSP_basic_verify( + bs: *mut OCSP_BASICRESP, + certs: *mut stack_st_X509, + st: *mut X509_STORE, + flags: c_ulong, + ) -> c_int; +} diff --git a/openssl-sys/src/handwritten/pem.rs b/openssl-sys/src/handwritten/pem.rs new file mode 100644 index 0000000..4299717 --- /dev/null +++ b/openssl-sys/src/handwritten/pem.rs @@ -0,0 +1,191 @@ +use super::super::*; +use libc::*; + +pub type pem_password_cb = Option< + unsafe extern "C" fn( + buf: *mut c_char, + size: c_int, + rwflag: c_int, + user_data: *mut c_void, + ) -> c_int, +>; + +const_ptr_api! { + extern "C" { + pub fn PEM_write_bio_X509(bio: *mut BIO, x509: #[const_ptr_if(ossl300)] X509) -> c_int; + pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: #[const_ptr_if(ossl300)] X509_REQ) -> c_int; + pub fn PEM_write_bio_X509_CRL(bio: *mut BIO, x509: #[const_ptr_if(ossl300)] X509_CRL) -> c_int; + pub fn PEM_write_bio_RSAPrivateKey( + bp: *mut BIO, + rsa: #[const_ptr_if(ossl300)] RSA, + cipher: *const EVP_CIPHER, + kstr: #[const_ptr_if(ossl300)] c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_write_bio_RSA_PUBKEY(bp: *mut BIO, rsa: #[const_ptr_if(ossl300)] RSA) -> c_int; + pub fn PEM_write_bio_DSAPrivateKey( + bp: *mut BIO, + dsa: #[const_ptr_if(ossl300)] DSA, + cipher: *const EVP_CIPHER, + kstr: #[const_ptr_if(ossl300)] c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_write_bio_ECPrivateKey( + bio: *mut BIO, + key: #[const_ptr_if(ossl300)] EC_KEY, + cipher: *const EVP_CIPHER, + kstr: #[const_ptr_if(ossl300)] c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_write_bio_DSA_PUBKEY(bp: *mut BIO, dsa: #[const_ptr_if(ossl300)] DSA) -> c_int; + pub fn PEM_write_bio_PrivateKey( + bio: *mut BIO, + pkey: #[const_ptr_if(ossl300)] EVP_PKEY, + cipher: *const EVP_CIPHER, + kstr: #[const_ptr_if(ossl300)] c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: #[const_ptr_if(ossl300)] EVP_PKEY) -> c_int; + pub fn PEM_write_bio_PKCS8PrivateKey( + bio: *mut BIO, + pkey: #[const_ptr_if(ossl300)] EVP_PKEY, + cipher: *const EVP_CIPHER, + kstr: #[const_ptr_if(ossl300)] c_char, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_write_bio_PKCS7(bp: *mut BIO, x: #[const_ptr_if(ossl300)] PKCS7) -> c_int; + pub fn PEM_write_bio_EC_PUBKEY(bp: *mut BIO, ec: #[const_ptr_if(ossl300)] EC_KEY) -> c_int; + pub fn i2d_PKCS8PrivateKey_bio( + bp: *mut BIO, + x: #[const_ptr_if(ossl300)] EVP_PKEY, + enc: *const EVP_CIPHER, + kstr: #[const_ptr_if(ossl300)] c_char, + klen: c_int, + cb: pem_password_cb, + u: *mut c_void, + ) -> c_int; + } +} + +extern "C" { + pub fn PEM_read_bio_X509( + bio: *mut BIO, + out: *mut *mut X509, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut X509; + pub fn PEM_read_bio_X509_REQ( + bio: *mut BIO, + out: *mut *mut X509_REQ, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut X509_REQ; + pub fn PEM_read_bio_X509_CRL( + bio: *mut BIO, + out: *mut *mut X509_CRL, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut X509_CRL; + pub fn PEM_read_bio_RSAPrivateKey( + bio: *mut BIO, + rsa: *mut *mut RSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut RSA; + pub fn PEM_read_bio_RSAPublicKey( + bio: *mut BIO, + rsa: *mut *mut RSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut RSA; + pub fn PEM_write_bio_RSAPublicKey(bp: *mut BIO, rsa: *const RSA) -> c_int; + pub fn PEM_read_bio_RSA_PUBKEY( + bio: *mut BIO, + rsa: *mut *mut RSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut RSA; + pub fn PEM_read_bio_DSAPrivateKey( + bp: *mut BIO, + dsa: *mut *mut DSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut DSA; + pub fn PEM_read_bio_DSA_PUBKEY( + bp: *mut BIO, + dsa: *mut *mut DSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut DSA; + pub fn PEM_read_bio_ECPrivateKey( + bio: *mut BIO, + key: *mut *mut EC_KEY, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut EC_KEY; + pub fn PEM_read_bio_EC_PUBKEY( + bp: *mut BIO, + ec: *mut *mut EC_KEY, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut EC_KEY; + pub fn PEM_read_bio_DHparams( + bio: *mut BIO, + out: *mut *mut DH, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut DH; + pub fn PEM_write_bio_DHparams(bio: *mut BIO, x: *const DH) -> c_int; + pub fn PEM_read_bio_PrivateKey( + bio: *mut BIO, + out: *mut *mut EVP_PKEY, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut EVP_PKEY; + pub fn PEM_read_bio_PUBKEY( + bio: *mut BIO, + out: *mut *mut EVP_PKEY, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut EVP_PKEY; + + pub fn d2i_PKCS8PrivateKey_bio( + bp: *mut BIO, + x: *mut *mut EVP_PKEY, + cb: pem_password_cb, + u: *mut c_void, + ) -> *mut EVP_PKEY; + pub fn d2i_PKCS8_PRIV_KEY_INFO( + k: *mut *mut PKCS8_PRIV_KEY_INFO, + buf: *mut *const u8, + length: c_long, + ) -> *mut PKCS8_PRIV_KEY_INFO; + pub fn PKCS8_PRIV_KEY_INFO_free(p8inf: *mut PKCS8_PRIV_KEY_INFO); + + pub fn PEM_read_bio_PKCS7( + bio: *mut BIO, + out: *mut *mut PKCS7, + cb: pem_password_cb, + u: *mut c_void, + ) -> *mut PKCS7; + + #[cfg(ossl101)] + pub fn PEM_read_bio_CMS( + bio: *mut BIO, + out: *mut *mut CMS_ContentInfo, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut CMS_ContentInfo; + #[cfg(ossl101)] + pub fn PEM_write_bio_CMS(bio: *mut BIO, cms: *const CMS_ContentInfo) -> c_int; +} diff --git a/openssl-sys/src/handwritten/pkcs12.rs b/openssl-sys/src/handwritten/pkcs12.rs new file mode 100644 index 0000000..728c333 --- /dev/null +++ b/openssl-sys/src/handwritten/pkcs12.rs @@ -0,0 +1,53 @@ +use libc::*; + +use super::super::*; + +pub enum PKCS12 {} + +extern "C" { + pub fn PKCS12_free(p12: *mut PKCS12); +} +const_ptr_api! { + extern "C" { + pub fn i2d_PKCS12(a: #[const_ptr_if(ossl300)] PKCS12, buf: *mut *mut u8) -> c_int; + } +} +extern "C" { + pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12; + + pub fn PKCS12_parse( + p12: *mut PKCS12, + pass: *const c_char, + pkey: *mut *mut EVP_PKEY, + cert: *mut *mut X509, + ca: *mut *mut stack_st_X509, + ) -> c_int; + + pub fn PKCS12_set_mac( + p12: *mut PKCS12, + pass: *const c_char, + passlen: c_int, + salt: *mut c_uchar, + saltlen: c_int, + iter: c_int, + md_type: *const EVP_MD, + ) -> c_int; +} +const_ptr_api! { + extern "C" { + pub fn PKCS12_create( + pass: #[const_ptr_if(any(ossl110, libressl280))] c_char, + friendly_name: #[const_ptr_if(any(ossl110, libressl280))] c_char, + pkey: *mut EVP_PKEY, + cert: *mut X509, + ca: *mut stack_st_X509, + nid_key: c_int, + nid_cert: c_int, + iter: c_int, + mac_iter: c_int, + keytype: c_int, + ) -> *mut PKCS12; + + pub fn i2d_PKCS12_bio(b: *mut BIO, a: #[const_ptr_if(ossl300)] PKCS12) -> c_int; + } +} diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs new file mode 100644 index 0000000..78f96ec --- /dev/null +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -0,0 +1,70 @@ +use super::super::*; +use libc::*; + +pub enum PKCS7_SIGNED {} +pub enum PKCS7_ENVELOPE {} +pub enum PKCS7_SIGN_ENVELOPE {} +pub enum PKCS7_DIGEST {} +pub enum PKCS7_ENCRYPT {} +pub enum PKCS7 {} + +extern "C" { + pub fn d2i_PKCS7(a: *mut *mut PKCS7, pp: *mut *const c_uchar, length: c_long) -> *mut PKCS7; +} + +const_ptr_api! { + extern "C" { + pub fn i2d_PKCS7(a: #[const_ptr_if(ossl300)] PKCS7, buf: *mut *mut u8) -> c_int; + } +} + +extern "C" { + pub fn PKCS7_encrypt( + certs: *mut stack_st_X509, + b: *mut BIO, + cipher: *const EVP_CIPHER, + flags: c_int, + ) -> *mut PKCS7; + + pub fn PKCS7_verify( + pkcs7: *mut PKCS7, + certs: *mut stack_st_X509, + store: *mut X509_STORE, + indata: *mut BIO, + out: *mut BIO, + flags: c_int, + ) -> c_int; + + pub fn PKCS7_get0_signers( + pkcs7: *mut PKCS7, + certs: *mut stack_st_X509, + flags: c_int, + ) -> *mut stack_st_X509; + + pub fn PKCS7_sign( + signcert: *mut X509, + pkey: *mut EVP_PKEY, + certs: *mut stack_st_X509, + data: *mut BIO, + flags: c_int, + ) -> *mut PKCS7; + + pub fn PKCS7_decrypt( + pkcs7: *mut PKCS7, + pkey: *mut EVP_PKEY, + cert: *mut X509, + data: *mut BIO, + flags: c_int, + ) -> c_int; + + pub fn PKCS7_free(pkcs7: *mut PKCS7); + + pub fn SMIME_write_PKCS7( + out: *mut BIO, + pkcs7: *mut PKCS7, + data: *mut BIO, + flags: c_int, + ) -> c_int; + + pub fn SMIME_read_PKCS7(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut PKCS7; +} diff --git a/openssl-sys/src/handwritten/provider.rs b/openssl-sys/src/handwritten/provider.rs new file mode 100644 index 0000000..3e18a02 --- /dev/null +++ b/openssl-sys/src/handwritten/provider.rs @@ -0,0 +1,20 @@ +use super::super::*; +use libc::*; + +extern "C" { + #[cfg(ossl300)] + pub fn OSSL_PROVIDER_load(ctx: *mut OSSL_LIB_CTX, name: *const c_char) -> *mut OSSL_PROVIDER; + #[cfg(ossl300)] + pub fn OSSL_PROVIDER_try_load( + ctx: *mut OSSL_LIB_CTX, + name: *const c_char, + retain_fallbacks: c_int, + ) -> *mut OSSL_PROVIDER; + #[cfg(ossl300)] + pub fn OSSL_PROVIDER_unload(prov: *mut OSSL_PROVIDER) -> c_int; + #[cfg(ossl300)] + pub fn OSSL_PROVIDER_set_default_search_path( + ctx: *mut OSSL_LIB_CTX, + path: *const c_char, + ) -> c_int; +} diff --git a/openssl-sys/src/handwritten/rand.rs b/openssl-sys/src/handwritten/rand.rs new file mode 100644 index 0000000..3bf9da5 --- /dev/null +++ b/openssl-sys/src/handwritten/rand.rs @@ -0,0 +1,12 @@ +use libc::*; + +extern "C" { + pub fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int; + + #[cfg(ossl111)] + pub fn RAND_keep_random_devices_open(keep: c_int); + + pub fn RAND_status() -> c_int; + + pub fn RAND_add(buf: *const c_void, num: c_int, randomness: c_double); +} diff --git a/openssl-sys/src/handwritten/rsa.rs b/openssl-sys/src/handwritten/rsa.rs new file mode 100644 index 0000000..d05edfc --- /dev/null +++ b/openssl-sys/src/handwritten/rsa.rs @@ -0,0 +1,124 @@ +use super::super::*; +use libc::*; + +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad_mode: c_int) -> c_int; + pub fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad_mode: *mut c_int) -> c_int; + + pub fn EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx: *mut EVP_PKEY_CTX, len: c_int) -> c_int; + pub fn EVP_PKEY_CTX_set_rsa_mgf1_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int; + } + } +} + +extern "C" { + pub fn RSA_new() -> *mut RSA; + pub fn RSA_size(k: *const RSA) -> c_int; + + #[cfg(any(ossl110, libressl273))] + pub fn RSA_set0_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn RSA_set0_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn RSA_set0_crt_params( + r: *mut RSA, + dmp1: *mut BIGNUM, + dmq1: *mut BIGNUM, + iqmp: *mut BIGNUM, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn RSA_get0_key( + r: *const RSA, + n: *mut *const BIGNUM, + e: *mut *const BIGNUM, + d: *mut *const BIGNUM, + ); + #[cfg(any(ossl110, libressl273))] + pub fn RSA_get0_factors(r: *const RSA, p: *mut *const BIGNUM, q: *mut *const BIGNUM); + #[cfg(any(ossl110, libressl273))] + pub fn RSA_get0_crt_params( + r: *const RSA, + dmp1: *mut *const BIGNUM, + dmq1: *mut *const BIGNUM, + iqmp: *mut *const BIGNUM, + ); + + #[cfg(not(ossl110))] + pub fn RSA_generate_key( + modsz: c_int, + e: c_ulong, + cb: Option, + cbarg: *mut c_void, + ) -> *mut RSA; + + pub fn RSA_generate_key_ex( + rsa: *mut RSA, + bits: c_int, + e: *mut BIGNUM, + cb: *mut BN_GENCB, + ) -> c_int; + + pub fn RSA_public_encrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_private_encrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_public_decrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_private_decrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_check_key(r: *const RSA) -> c_int; + pub fn RSA_free(rsa: *mut RSA); + pub fn RSA_up_ref(rsa: *mut RSA) -> c_int; + + pub fn i2d_RSAPublicKey(k: *const RSA, buf: *mut *mut u8) -> c_int; + pub fn d2i_RSAPublicKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + pub fn i2d_RSAPrivateKey(k: *const RSA, buf: *mut *mut u8) -> c_int; + pub fn d2i_RSAPrivateKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + + pub fn RSA_sign( + t: c_int, + m: *const u8, + mlen: c_uint, + sig: *mut u8, + siglen: *mut c_uint, + k: *mut RSA, + ) -> c_int; + pub fn RSA_verify( + t: c_int, + m: *const u8, + mlen: c_uint, + sig: *const u8, + siglen: c_uint, + k: *mut RSA, + ) -> c_int; + + pub fn RSA_padding_check_PKCS1_type_2( + to: *mut c_uchar, + tlen: c_int, + f: *const c_uchar, + fl: c_int, + rsa_len: c_int, + ) -> c_int; +} diff --git a/openssl-sys/src/handwritten/safestack.rs b/openssl-sys/src/handwritten/safestack.rs new file mode 100644 index 0000000..0bee90d --- /dev/null +++ b/openssl-sys/src/handwritten/safestack.rs @@ -0,0 +1 @@ +stack!(stack_st_OPENSSL_STRING); diff --git a/openssl-sys/src/handwritten/sha.rs b/openssl-sys/src/handwritten/sha.rs new file mode 100644 index 0000000..7d00b59 --- /dev/null +++ b/openssl-sys/src/handwritten/sha.rs @@ -0,0 +1,101 @@ +use super::super::*; +use libc::*; + +cfg_if! { + if #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] { + #[repr(C)] + #[derive(Clone)] + pub struct SHA_CTX { + pub h0: SHA_LONG, + pub h1: SHA_LONG, + pub h2: SHA_LONG, + pub h3: SHA_LONG, + pub h4: SHA_LONG, + pub Nl: SHA_LONG, + pub Nh: SHA_LONG, + pub data: [SHA_LONG; SHA_LBLOCK as usize], + pub num: c_uint, + } + + extern "C" { + pub fn SHA1_Init(c: *mut SHA_CTX) -> c_int; + pub fn SHA1_Update(c: *mut SHA_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA1_Final(md: *mut c_uchar, c: *mut SHA_CTX) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(ossl300))] { + extern "C" { + pub fn SHA1(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; + } + } +} + +cfg_if! { + if #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] { + #[repr(C)] + #[derive(Clone)] + pub struct SHA256_CTX { + pub h: [SHA_LONG; 8], + pub Nl: SHA_LONG, + pub Nh: SHA_LONG, + pub data: [SHA_LONG; SHA_LBLOCK as usize], + pub num: c_uint, + pub md_len: c_uint, + } + + extern "C" { + pub fn SHA224_Init(c: *mut SHA256_CTX) -> c_int; + pub fn SHA224_Update(c: *mut SHA256_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA224_Final(md: *mut c_uchar, c: *mut SHA256_CTX) -> c_int; + pub fn SHA256_Init(c: *mut SHA256_CTX) -> c_int; + pub fn SHA256_Update(c: *mut SHA256_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA256_Final(md: *mut c_uchar, c: *mut SHA256_CTX) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(ossl300))] { + extern "C" { + pub fn SHA224(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; + pub fn SHA256(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; + } + } +} + +cfg_if! { + if #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] { + #[repr(C)] + #[derive(Clone)] + pub struct SHA512_CTX { + pub h: [SHA_LONG64; 8], + pub Nl: SHA_LONG64, + pub Nh: SHA_LONG64, + // this is a union but we don't want to require 1.19 + u: [SHA_LONG64; SHA_LBLOCK as usize], + pub num: c_uint, + pub md_len: c_uint, + } + + extern "C" { + pub fn SHA384_Init(c: *mut SHA512_CTX) -> c_int; + pub fn SHA384_Update(c: *mut SHA512_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA384_Final(md: *mut c_uchar, c: *mut SHA512_CTX) -> c_int; + pub fn SHA512_Init(c: *mut SHA512_CTX) -> c_int; + pub fn SHA512_Update(c: *mut SHA512_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA512_Final(md: *mut c_uchar, c: *mut SHA512_CTX) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(not(ossl300))] { + extern "C" { + pub fn SHA384(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; + pub fn SHA512(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; + } + } +} diff --git a/openssl-sys/src/handwritten/srtp.rs b/openssl-sys/src/handwritten/srtp.rs new file mode 100644 index 0000000..d4c7af8 --- /dev/null +++ b/openssl-sys/src/handwritten/srtp.rs @@ -0,0 +1,10 @@ +use super::super::*; +use libc::*; + +extern "C" { + pub fn SSL_CTX_set_tlsext_use_srtp(ctx: *mut SSL_CTX, profiles: *const c_char) -> c_int; + pub fn SSL_set_tlsext_use_srtp(ssl: *mut SSL, profiles: *const c_char) -> c_int; + + pub fn SSL_get_srtp_profiles(ssl: *mut SSL) -> *mut stack_st_SRTP_PROTECTION_PROFILE; + pub fn SSL_get_selected_srtp_profile(ssl: *mut SSL) -> *mut SRTP_PROTECTION_PROFILE; +} diff --git a/openssl-sys/src/handwritten/ssl.rs b/openssl-sys/src/handwritten/ssl.rs new file mode 100644 index 0000000..f179a04 --- /dev/null +++ b/openssl-sys/src/handwritten/ssl.rs @@ -0,0 +1,913 @@ +use super::super::*; +use libc::*; + +pub enum SSL_METHOD {} +pub enum SSL_CIPHER {} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum SSL_SESSION {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct SSL_SESSION { + ssl_version: c_int, + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], + session_id_length: c_uint, + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + peer: *mut X509, + verify_result: c_long, + timeout: c_long, + time: time_t, + pub references: c_int, + cipher: *const SSL_CIPHER, + cipher_id: c_long, + ciphers: *mut stack_st_SSL_CIPHER, + tlsext_hostname: *mut c_char, + tlsext_tick: *mut c_uchar, + tlsext_ticklen: size_t, + tlsext_tick_lifetime_int: c_long, + internal: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct SSL_SESSION { + ssl_version: c_int, + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], + session_id_length: c_uint, + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + not_resumable: c_int, + sess_cert: *mut c_void, + peer: *mut X509, + verify_result: c_long, + timeout: c_long, + time: time_t, + pub references: c_int, + cipher: *const c_void, + cipher_id: c_ulong, + ciphers: *mut c_void, + ex_data: CRYPTO_EX_DATA, + prev: *mut c_void, + next: *mut c_void, + tlsext_hostname: *mut c_char, + tlsext_ecpointformatlist_length: size_t, + tlsext_ecpointformatlist: *mut u8, + tlsext_ellipticcurvelist_length: size_t, + tlsext_ellipticcurvelist: *mut u16, + tlsext_tick: *mut c_uchar, + tlsext_ticklen: size_t, + tlsext_tick_lifetime_hint: c_long, + } + } else { + #[repr(C)] + pub struct SSL_SESSION { + ssl_version: c_int, + key_arg_length: c_uint, + key_arg: [c_uchar; SSL_MAX_KEY_ARG_LENGTH as usize], + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], + session_id_length: c_uint, + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + krb5_client_princ_len: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + krb5_client_princ: [c_uchar; SSL_MAX_KRB5_PRINCIPAL_LENGTH as usize], + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity_hint: *mut c_char, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity: *mut c_char, + not_resumable: c_int, + sess_cert: *mut c_void, + peer: *mut X509, + verify_result: c_long, + pub references: c_int, + timeout: c_long, + time: c_long, + compress_meth: c_uint, + cipher: *const c_void, + cipher_id: c_ulong, + ciphers: *mut c_void, + ex_data: CRYPTO_EX_DATA, + prev: *mut c_void, + next: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hostname: *mut c_char, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticklen: size_t, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_lifetime_hint: c_long, + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_username: *mut c_char, + } + } +} + +stack!(stack_st_SSL_CIPHER); + +#[repr(C)] +pub struct SRTP_PROTECTION_PROFILE { + pub name: *const c_char, + pub id: c_ulong, +} + +stack!(stack_st_SRTP_PROTECTION_PROFILE); + +pub type tls_session_ticket_ext_cb_fn = + Option c_int>; +pub type tls_session_secret_cb_fn = Option< + unsafe extern "C" fn( + *mut SSL, + *mut c_void, + *mut c_int, + *mut stack_st_SSL_CIPHER, + *mut *mut SSL_CIPHER, + *mut c_void, + ) -> c_int, +>; + +#[cfg(ossl111)] +pub type SSL_custom_ext_add_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut SSL, + ext_type: c_uint, + context: c_uint, + out: *mut *const c_uchar, + outlen: *mut size_t, + x: *mut X509, + chainidx: size_t, + al: *mut c_int, + add_arg: *mut c_void, + ) -> c_int, +>; + +#[cfg(ossl111)] +pub type SSL_custom_ext_free_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut SSL, + ext_type: c_uint, + context: c_uint, + out: *const c_uchar, + add_arg: *mut c_void, + ), +>; + +#[cfg(ossl111)] +pub type SSL_custom_ext_parse_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut SSL, + ext_type: c_uint, + context: c_uint, + input: *const c_uchar, + inlen: size_t, + x: *mut X509, + chainidx: size_t, + al: *mut c_int, + parse_arg: *mut c_void, + ) -> c_int, +>; + +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn SSL_CTX_get_options(ctx: *const SSL_CTX) -> u64; + pub fn SSL_CTX_set_options(ctx: *mut SSL_CTX, op: u64) -> u64; + pub fn SSL_CTX_clear_options(ctx: *mut SSL_CTX, op: u64) -> u64; + } + } else if #[cfg(ossl110)] { + extern "C" { + pub fn SSL_CTX_get_options(ctx: *const SSL_CTX) -> c_ulong; + pub fn SSL_CTX_set_options(ctx: *mut SSL_CTX, op: c_ulong) -> c_ulong; + pub fn SSL_CTX_clear_options(ctx: *mut SSL_CTX, op: c_ulong) -> c_ulong; + } + } +} + +pub type GEN_SESSION_CB = + Option c_int>; + +extern "C" { + pub fn SSL_CTX_sess_set_new_cb( + ctx: *mut SSL_CTX, + new_session_cb: Option c_int>, + ); + pub fn SSL_CTX_sess_set_remove_cb( + ctx: *mut SSL_CTX, + remove_session_cb: Option, + ); +} +cfg_if! { + // const change in passed function pointer signature + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn SSL_CTX_sess_set_get_cb( + ctx: *mut SSL_CTX, + get_session_cb: Option< + unsafe extern "C" fn(*mut SSL, *const c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, + >, + ); + } + } else { + extern "C" { + pub fn SSL_CTX_sess_set_get_cb( + ctx: *mut SSL_CTX, + get_session_cb: Option< + unsafe extern "C" fn(*mut SSL, *mut c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, + >, + ); + } + } +} +extern "C" { + // FIXME change to unsafe extern "C" fn + pub fn SSL_CTX_set_cookie_generate_cb( + s: *mut SSL_CTX, + cb: Option< + extern "C" fn(ssl: *mut SSL, cookie: *mut c_uchar, cookie_len: *mut c_uint) -> c_int, + >, + ); +} + +cfg_if! { + // const change in passed function pointer signature + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn SSL_CTX_set_cookie_verify_cb( + s: *mut SSL_CTX, + cb: Option< + extern "C" fn(ssl: *mut SSL, cookie: *const c_uchar, cookie_len: c_uint) -> c_int, + >, + ); + } + } else { + extern "C" { + pub fn SSL_CTX_set_cookie_verify_cb( + s: *mut SSL_CTX, + cb: Option c_int>, + ); + } + } +} + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_stateless_cookie_generate_cb( + s: *mut SSL_CTX, + cb: Option< + unsafe extern "C" fn( + ssl: *mut SSL, + cookie: *mut c_uchar, + cookie_len: *mut size_t, + ) -> c_int, + >, + ); + #[cfg(ossl111)] + pub fn SSL_CTX_set_stateless_cookie_verify_cb( + s: *mut SSL_CTX, + cb: Option< + unsafe extern "C" fn( + ssl: *mut SSL, + cookie: *const c_uchar, + cookie_len: size_t, + ) -> c_int, + >, + ); + + pub fn SSL_CTX_set_next_protos_advertised_cb( + ssl: *mut SSL_CTX, + cb: extern "C" fn( + ssl: *mut SSL, + out: *mut *const c_uchar, + outlen: *mut c_uint, + arg: *mut c_void, + ) -> c_int, + arg: *mut c_void, + ); + pub fn SSL_CTX_set_next_proto_select_cb( + ssl: *mut SSL_CTX, + cb: extern "C" fn( + ssl: *mut SSL, + out: *mut *mut c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + arg: *mut c_void, + ) -> c_int, + arg: *mut c_void, + ); + pub fn SSL_get0_next_proto_negotiated( + s: *const SSL, + data: *mut *const c_uchar, + len: *mut c_uint, + ); + + pub fn SSL_select_next_proto( + out: *mut *mut c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + client: *const c_uchar, + client_len: c_uint, + ) -> c_int; +} + +extern "C" { + #[cfg(any(ossl102, libressl261))] + pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; + #[cfg(any(ossl102, libressl261))] + pub fn SSL_set_alpn_protos(s: *mut SSL, data: *const c_uchar, len: c_uint) -> c_int; + #[cfg(any(ossl102, libressl261))] + #[link_name = "SSL_CTX_set_alpn_select_cb"] + pub fn SSL_CTX_set_alpn_select_cb__fixed_rust( + ssl: *mut SSL_CTX, + cb: Option< + unsafe extern "C" fn( + ssl: *mut SSL, + out: *mut *const c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + arg: *mut c_void, + ) -> c_int, + >, + arg: *mut c_void, + ); + #[cfg(any(ossl102, libressl261))] + pub fn SSL_get0_alpn_selected(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +extern "C" { + pub fn SSL_CTX_set_psk_client_callback( + ssl: *mut SSL_CTX, + psk_client_cb: Option< + extern "C" fn( + *mut SSL, + *const c_char, + *mut c_char, + c_uint, + *mut c_uchar, + c_uint, + ) -> c_uint, + >, + ); + pub fn SSL_CTX_set_psk_server_callback( + ssl: *mut SSL_CTX, + psk_server_cb: Option< + extern "C" fn(*mut SSL, *const c_char, *mut c_uchar, c_uint) -> c_uint, + >, + ); + pub fn SSL_get_psk_identity_hint(ssl: *const SSL) -> *const c_char; + pub fn SSL_get_psk_identity(ssl: *const SSL) -> *const c_char; +} + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_add_custom_ext( + ctx: *mut SSL_CTX, + ext_type: c_uint, + context: c_uint, + add_cb: SSL_custom_ext_add_cb_ex, + free_cb: SSL_custom_ext_free_cb_ex, + add_arg: *mut c_void, + parse_cb: SSL_custom_ext_parse_cb_ex, + parse_arg: *mut c_void, + ) -> c_int; + + #[cfg(ossl102)] + pub fn SSL_extension_supported(ext_type: c_uint) -> c_int; +} + +#[cfg(ossl111)] +pub type SSL_CTX_keylog_cb_func = + Option; + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_keylog_callback(ctx: *mut SSL_CTX, cb: SSL_CTX_keylog_cb_func); + + #[cfg(any(ossl111, libressl340))] + pub fn SSL_CTX_set_max_early_data(ctx: *mut SSL_CTX, max_early_data: u32) -> c_int; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_CTX_get_max_early_data(ctx: *const SSL_CTX) -> u32; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_set_max_early_data(ctx: *mut SSL, max_early_data: u32) -> c_int; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_get_max_early_data(ctx: *const SSL) -> u32; + + pub fn SSL_get_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; + pub fn SSL_get_peer_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; + + pub fn SSL_CTX_get_verify_mode(ctx: *const SSL_CTX) -> c_int; + pub fn SSL_get_verify_mode(s: *const SSL) -> c_int; +} + +const_ptr_api! { + extern "C" { + #[cfg(ossl110)] + pub fn SSL_is_init_finished(s: #[const_ptr_if(ossl111)] SSL) -> c_int; + } +} + +cfg_if! { + if #[cfg(libressl261)] { + extern "C" { + pub fn SSL_CTX_set_min_proto_version(ctx: *mut SSL_CTX, version: u16) -> c_int; + pub fn SSL_CTX_set_max_proto_version(ctx: *mut SSL_CTX, version: u16) -> c_int; + pub fn SSL_set_min_proto_version(s: *mut SSL, version: u16) -> c_int; + pub fn SSL_set_max_proto_version(s: *mut SSL, version: u16) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(libressl270)] { + extern "C" { + pub fn SSL_CTX_get_min_proto_version(ctx: *mut SSL_CTX) -> c_int; + pub fn SSL_CTX_get_max_proto_version(ctx: *mut SSL_CTX) -> c_int; + pub fn SSL_get_min_proto_version(s: *mut SSL) -> c_int; + pub fn SSL_get_max_proto_version(s: *mut SSL) -> c_int; + } + } +} + +extern "C" { + pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; + pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; + pub fn SSL_CTX_free(ctx: *mut SSL_CTX); + #[cfg(any(ossl110, libressl273))] + pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int; + pub fn SSL_CTX_get_cert_store(ctx: *const SSL_CTX) -> *mut X509_STORE; + pub fn SSL_CTX_set_cert_store(ctx: *mut SSL_CTX, store: *mut X509_STORE); + + pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; + pub fn SSL_CIPHER_get_bits(cipher: *const SSL_CIPHER, alg_bits: *mut c_int) -> c_int; +} +const_ptr_api! { + extern "C" { + pub fn SSL_CIPHER_get_version(cipher: *const SSL_CIPHER) -> #[const_ptr_if(any(ossl110, libressl280))] c_char; + } +} +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CIPHER_get_handshake_digest(cipher: *const SSL_CIPHER) -> *const EVP_MD; + pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char; + #[cfg(ossl111)] + pub fn SSL_CIPHER_standard_name(cipher: *const SSL_CIPHER) -> *const c_char; + #[cfg(ossl111)] + pub fn OPENSSL_cipher_name(rfc_name: *const c_char) -> *const c_char; + + pub fn SSL_pending(ssl: *const SSL) -> c_int; + pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); + pub fn SSL_get_rbio(ssl: *const SSL) -> *mut BIO; + pub fn SSL_get_wbio(ssl: *const SSL) -> *mut BIO; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_CTX_set_ciphersuites(ctx: *mut SSL_CTX, str: *const c_char) -> c_int; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_set_ciphersuites(ssl: *mut SSL, str: *const c_char) -> c_int; + pub fn SSL_set_cipher_list(ssl: *mut SSL, s: *const c_char) -> c_int; + pub fn SSL_set_ssl_method(s: *mut SSL, method: *const SSL_METHOD) -> c_int; + pub fn SSL_set_verify( + ssl: *mut SSL, + mode: c_int, + // FIXME should be unsafe + verify_callback: Option c_int>, + ); + pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int; + pub fn SSL_CTX_use_certificate(ctx: *mut SSL_CTX, cert: *mut X509) -> c_int; + + pub fn SSL_CTX_use_PrivateKey_file( + ctx: *mut SSL_CTX, + key_file: *const c_char, + file_type: c_int, + ) -> c_int; + pub fn SSL_CTX_use_certificate_file( + ctx: *mut SSL_CTX, + cert_file: *const c_char, + file_type: c_int, + ) -> c_int; + pub fn SSL_CTX_use_certificate_chain_file( + ctx: *mut SSL_CTX, + cert_chain_file: *const c_char, + ) -> c_int; + pub fn SSL_use_PrivateKey_file(ssl: *mut SSL, file: *const c_char, type_: c_int) -> c_int; + pub fn SSL_use_PrivateKey(ssl: *mut SSL, pkey: *mut EVP_PKEY) -> c_int; + pub fn SSL_use_certificate(ssl: *mut SSL, x: *mut X509) -> c_int; + #[cfg(any(ossl110, libressl332))] + pub fn SSL_use_certificate_chain_file(ssl: *mut SSL, file: *const c_char) -> c_int; + pub fn SSL_set_client_CA_list(s: *mut SSL, name_list: *mut stack_st_X509_NAME); + pub fn SSL_add_client_CA(ssl: *mut SSL, x: *mut X509) -> c_int; + pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; + + #[cfg(not(ossl110))] + pub fn SSL_load_error_strings(); + pub fn SSL_state_string(ssl: *const SSL) -> *const c_char; + pub fn SSL_state_string_long(ssl: *const SSL) -> *const c_char; + + pub fn SSL_SESSION_get_time(s: *const SSL_SESSION) -> c_long; + pub fn SSL_SESSION_get_timeout(s: *const SSL_SESSION) -> c_long; + #[cfg(any(ossl110, libressl270))] + pub fn SSL_SESSION_get_protocol_version(s: *const SSL_SESSION) -> c_int; + + #[cfg(any(ossl111, libressl340))] + pub fn SSL_SESSION_set_max_early_data(ctx: *mut SSL_SESSION, max_early_data: u32) -> c_int; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_SESSION_get_max_early_data(ctx: *const SSL_SESSION) -> u32; + + pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar; + #[cfg(any(ossl110, libressl273))] + pub fn SSL_SESSION_up_ref(ses: *mut SSL_SESSION) -> c_int; + pub fn SSL_SESSION_free(s: *mut SSL_SESSION); +} +const_ptr_api! { + extern "C" { + pub fn i2d_SSL_SESSION(s: #[const_ptr_if(ossl300)] SSL_SESSION, pp: *mut *mut c_uchar) -> c_int; + } +} +extern "C" { + pub fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int; + pub fn SSL_CTX_add_session(ctx: *mut SSL_CTX, session: *mut SSL_SESSION) -> c_int; + pub fn SSL_CTX_remove_session(ctx: *mut SSL_CTX, session: *mut SSL_SESSION) -> c_int; + pub fn d2i_SSL_SESSION( + a: *mut *mut SSL_SESSION, + pp: *mut *const c_uchar, + len: c_long, + ) -> *mut SSL_SESSION; + + #[cfg(not(ossl300))] + pub fn SSL_get_peer_certificate(ssl: *const SSL) -> *mut X509; + #[cfg(ossl300)] + pub fn SSL_get1_peer_certificate(ssl: *const SSL) -> *mut X509; + + pub fn SSL_get_peer_cert_chain(ssl: *const SSL) -> *mut stack_st_X509; + + pub fn SSL_CTX_set_verify( + ctx: *mut SSL_CTX, + mode: c_int, + verify_callback: Option c_int>, + ); + pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int); + + #[cfg(any(ossl111, libressl340))] + pub fn SSL_CTX_set_post_handshake_auth(ctx: *mut SSL_CTX, val: c_int); + + pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; + + pub fn SSL_CTX_set_session_id_context( + ssl: *mut SSL_CTX, + sid_ctx: *const c_uchar, + sid_ctx_len: c_uint, + ) -> c_int; + + pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; + + #[cfg(any(ossl102, libressl261))] + pub fn SSL_CTX_get0_param(ctx: *mut SSL_CTX) -> *mut X509_VERIFY_PARAM; + + #[cfg(any(ossl102, libressl261))] + pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; +} + +#[cfg(ossl111)] +pub type SSL_client_hello_cb_fn = + Option c_int>; +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_client_hello_cb( + c: *mut SSL_CTX, + cb: SSL_client_hello_cb_fn, + arg: *mut c_void, + ); + #[cfg(ossl111)] + pub fn SSL_client_hello_isv2(s: *mut SSL) -> c_int; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_legacy_version(s: *mut SSL) -> c_uint; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_random(s: *mut SSL, out: *mut *const c_uchar) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_session_id(s: *mut SSL, out: *mut *const c_uchar) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_ciphers(s: *mut SSL, out: *mut *const c_uchar) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_compression_methods( + s: *mut SSL, + out: *mut *const c_uchar, + ) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get1_extensions_present( + s: *mut SSL, + out: *mut *mut c_int, + outlen: *mut size_t, + ) -> c_int; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_ext( + s: *mut SSL, + type_: c_uint, + out: *mut *const c_uchar, + outlen: *mut size_t, + ) -> c_int; + + pub fn SSL_free(ssl: *mut SSL); + pub fn SSL_accept(ssl: *mut SSL) -> c_int; + #[cfg(ossl111)] + pub fn SSL_stateless(s: *mut SSL) -> c_int; + pub fn SSL_connect(ssl: *mut SSL) -> c_int; + pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; + pub fn SSL_peek(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_read_early_data( + s: *mut SSL, + buf: *mut c_void, + num: size_t, + readbytes: *mut size_t, + ) -> c_int; +} + +extern "C" { + pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; + #[cfg(any(ossl111, libressl340))] + pub fn SSL_write_early_data( + s: *mut SSL, + buf: *const c_void, + num: size_t, + written: *mut size_t, + ) -> c_int; + pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn SSL_CTX_ctrl(ctx: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + #[link_name = "SSL_CTX_callback_ctrl"] + pub fn SSL_CTX_callback_ctrl__fixed_rust( + ctx: *mut SSL_CTX, + cmd: c_int, + fp: Option, + ) -> c_long; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl291))] { + extern "C" { + pub fn TLS_method() -> *const SSL_METHOD; + + pub fn DTLS_method() -> *const SSL_METHOD; + + pub fn TLS_server_method() -> *const SSL_METHOD; + + pub fn TLS_client_method() -> *const SSL_METHOD; + } + } else { + extern "C" { + #[cfg(not(osslconf = "OPENSSL_NO_SSL3_METHOD"))] + pub fn SSLv3_method() -> *const SSL_METHOD; + + pub fn SSLv23_method() -> *const SSL_METHOD; + + pub fn SSLv23_client_method() -> *const SSL_METHOD; + + pub fn SSLv23_server_method() -> *const SSL_METHOD; + + pub fn TLSv1_method() -> *const SSL_METHOD; + + pub fn TLSv1_1_method() -> *const SSL_METHOD; + + pub fn TLSv1_2_method() -> *const SSL_METHOD; + + pub fn DTLSv1_method() -> *const SSL_METHOD; + + #[cfg(ossl102)] + pub fn DTLSv1_2_method() -> *const SSL_METHOD; + } + } +} + +extern "C" { + pub fn SSL_get_error(ssl: *const SSL, ret: c_int) -> c_int; + pub fn SSL_get_version(ssl: *const SSL) -> *const c_char; + + pub fn SSL_do_handshake(ssl: *mut SSL) -> c_int; + pub fn SSL_shutdown(ssl: *mut SSL) -> c_int; + + pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME); + + pub fn SSL_CTX_add_client_CA(ctx: *mut SSL_CTX, cacert: *mut X509) -> c_int; + + pub fn SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int; + pub fn SSL_CTX_load_verify_locations( + ctx: *mut SSL_CTX, + CAfile: *const c_char, + CApath: *const c_char, + ) -> c_int; +} + +const_ptr_api! { + extern "C" { + pub fn SSL_get_ssl_method(ssl: #[const_ptr_if(ossl111b)] SSL) -> *const SSL_METHOD; + } +} + +extern "C" { + pub fn SSL_set_connect_state(s: *mut SSL); + pub fn SSL_set_accept_state(s: *mut SSL); + + #[cfg(not(ossl110))] + pub fn SSL_library_init() -> c_int; + + pub fn SSL_CIPHER_description( + cipher: *const SSL_CIPHER, + buf: *mut c_char, + size: c_int, + ) -> *mut c_char; + + pub fn SSL_get_certificate(ssl: *const SSL) -> *mut X509; +} +const_ptr_api! { + extern "C" { + pub fn SSL_get_privatekey(ssl: #[const_ptr_if(any(ossl102, libressl280))] SSL) -> *mut EVP_PKEY; + } +} + +extern "C" { + #[cfg(any(ossl102, libressl270))] + pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; + #[cfg(any(ossl102, libressl340))] + pub fn SSL_CTX_get0_privatekey(ctx: *const SSL_CTX) -> *mut EVP_PKEY; + + pub fn SSL_set_shutdown(ss: *mut SSL, mode: c_int); + pub fn SSL_get_shutdown(ssl: *const SSL) -> c_int; + pub fn SSL_version(ssl: *const SSL) -> c_int; + pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; + pub fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX; + pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX; + + pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long; + #[cfg(ossl110)] + pub fn SSL_get0_verified_chain(ssl: *const SSL) -> *mut stack_st_X509; + + #[cfg(any(ossl110, libressl270))] + pub fn SSL_get_client_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; + #[cfg(any(ossl110, libressl270))] + pub fn SSL_get_server_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; + #[cfg(any(ossl110, libressl273))] + pub fn SSL_SESSION_get_master_key( + session: *const SSL_SESSION, + out: *mut c_uchar, + outlen: size_t, + ) -> size_t; +} + +extern "C" { + #[cfg(not(ossl110))] + pub fn SSL_get_ex_new_index( + argl: c_long, + argp: *mut c_void, + new_func: Option, + dup_func: Option, + free_func: Option, + ) -> c_int; + + pub fn SSL_set_ex_data(ssl: *mut SSL, idx: c_int, data: *mut c_void) -> c_int; + pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void; + + #[cfg(not(ossl110))] + pub fn SSL_CTX_get_ex_new_index( + argl: c_long, + argp: *mut c_void, + new_func: Option, + dup_func: Option, + free_func: Option, + ) -> c_int; + + pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) -> c_int; + pub fn SSL_CTX_get_ex_data(ctx: *const SSL_CTX, idx: c_int) -> *mut c_void; + + pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; +} + +extern "C" { + #[link_name = "SSL_CTX_set_tmp_dh_callback"] + pub fn SSL_CTX_set_tmp_dh_callback__fixed_rust( + ctx: *mut SSL_CTX, + dh: Option< + unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, + >, + ); + #[link_name = "SSL_set_tmp_dh_callback"] + pub fn SSL_set_tmp_dh_callback__fixed_rust( + ctx: *mut SSL, + dh: Option< + unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, + >, + ); + #[cfg(not(ossl110))] + #[link_name = "SSL_CTX_set_tmp_ecdh_callback"] + pub fn SSL_CTX_set_tmp_ecdh_callback__fixed_rust( + ctx: *mut SSL_CTX, + ecdh: Option< + unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut EC_KEY, + >, + ); + #[cfg(not(ossl110))] + #[link_name = "SSL_set_tmp_ecdh_callback"] + pub fn SSL_set_tmp_ecdh_callback__fixed_rust( + ssl: *mut SSL, + ecdh: Option< + unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut EC_KEY, + >, + ); +} + +cfg_if! { + if #[cfg(libressl)] { + extern "C" { + pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const libc::c_void; + } + } else if #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] { + const_ptr_api! { + extern "C" { + pub fn SSL_get_current_compression(ssl: #[const_ptr_if(ossl111b)] SSL) -> *const COMP_METHOD; + } + } + } +} +cfg_if! { + if #[cfg(libressl)] { + extern "C" { + pub fn SSL_COMP_get_name(comp: *const libc::c_void) -> *const c_char; + } + } else if #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] { + extern "C" { + pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; + } + } +} + +#[cfg(not(osslconf = "OPENSSL_NO_COMP"))] +extern "C" { + #[cfg(ossl110)] + pub fn COMP_get_type(meth: *const COMP_METHOD) -> i32; +} + +extern "C" { + #[cfg(any(ossl110, libressl270))] + pub fn SSL_CIPHER_get_cipher_nid(c: *const SSL_CIPHER) -> c_int; + #[cfg(any(ossl110, libressl270))] + pub fn SSL_CIPHER_get_digest_nid(c: *const SSL_CIPHER) -> c_int; +} + +const_ptr_api! { + extern "C" { + #[cfg(ossl110)] + pub fn SSL_session_reused(ssl: #[const_ptr_if(ossl111c)] SSL) -> c_int; + } +} + +const_ptr_api! { + extern "C" { + #[cfg(any(ossl102, libressl273))] + pub fn SSL_is_server(s: #[const_ptr_if(any(ossl110f, libressl273))] SSL) -> c_int; + } +} + +extern "C" { + #[cfg(ossl110)] + pub fn OPENSSL_init_ssl(opts: u64, settings: *const OPENSSL_INIT_SETTINGS) -> c_int; +} + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_num_tickets(ctx: *mut SSL_CTX, num_tickets: size_t) -> c_int; + + #[cfg(ossl111)] + pub fn SSL_set_num_tickets(s: *mut SSL, num_tickets: size_t) -> c_int; + + #[cfg(ossl111)] + pub fn SSL_CTX_get_num_tickets(ctx: *const SSL_CTX) -> size_t; + + #[cfg(ossl111)] + pub fn SSL_get_num_tickets(s: *const SSL) -> size_t; +} diff --git a/openssl-sys/src/handwritten/stack.rs b/openssl-sys/src/handwritten/stack.rs new file mode 100644 index 0000000..7f2feef --- /dev/null +++ b/openssl-sys/src/handwritten/stack.rs @@ -0,0 +1,45 @@ +use libc::*; + +cfg_if! { + if #[cfg(ossl110)] { + pub enum OPENSSL_STACK {} + } else { + #[repr(C)] + pub struct _STACK { + pub num: c_int, + pub data: *mut *mut c_char, + pub sorted: c_int, + pub num_alloc: c_int, + pub comp: Option c_int>, + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn OPENSSL_sk_num(stack: *const OPENSSL_STACK) -> c_int; + pub fn OPENSSL_sk_value(stack: *const OPENSSL_STACK, idx: c_int) -> *mut c_void; + + pub fn OPENSSL_sk_new_null() -> *mut OPENSSL_STACK; + pub fn OPENSSL_sk_free(st: *mut OPENSSL_STACK); + pub fn OPENSSL_sk_pop_free( + st: *mut OPENSSL_STACK, + free: Option, + ); + pub fn OPENSSL_sk_push(st: *mut OPENSSL_STACK, data: *const c_void) -> c_int; + pub fn OPENSSL_sk_pop(st: *mut OPENSSL_STACK) -> *mut c_void; + } + } else { + extern "C" { + pub fn sk_num(st: *const _STACK) -> c_int; + pub fn sk_value(st: *const _STACK, n: c_int) -> *mut c_void; + + pub fn sk_new_null() -> *mut _STACK; + pub fn sk_free(st: *mut _STACK); + pub fn sk_pop_free(st: *mut _STACK, free: Option); + pub fn sk_push(st: *mut _STACK, data: *mut c_void) -> c_int; + pub fn sk_pop(st: *mut _STACK) -> *mut c_void; + } + } +} diff --git a/openssl-sys/src/handwritten/tls1.rs b/openssl-sys/src/handwritten/tls1.rs new file mode 100644 index 0000000..8cf992f --- /dev/null +++ b/openssl-sys/src/handwritten/tls1.rs @@ -0,0 +1,28 @@ +use super::super::*; +use libc::*; + +extern "C" { + pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; + + pub fn SSL_export_keying_material( + s: *mut SSL, + out: *mut c_uchar, + olen: size_t, + label: *const c_char, + llen: size_t, + context: *const c_uchar, + contextlen: size_t, + use_context: c_int, + ) -> c_int; + + #[cfg(ossl111)] + pub fn SSL_export_keying_material_early( + s: *mut SSL, + out: *mut c_uchar, + olen: size_t, + label: *const c_char, + llen: size_t, + context: *const c_uchar, + contextlen: size_t, + ) -> c_int; +} diff --git a/openssl-sys/src/handwritten/types.rs b/openssl-sys/src/handwritten/types.rs new file mode 100644 index 0000000..b229a37 --- /dev/null +++ b/openssl-sys/src/handwritten/types.rs @@ -0,0 +1,1078 @@ +use libc::*; + +#[allow(unused_imports)] +use super::super::*; + +pub enum ASN1_INTEGER {} +pub enum ASN1_GENERALIZEDTIME {} +pub enum ASN1_STRING {} +pub enum ASN1_BIT_STRING {} +pub enum ASN1_TIME {} +pub enum ASN1_TYPE {} +pub enum ASN1_OBJECT {} +pub enum ASN1_OCTET_STRING {} + +pub enum bio_st {} // FIXME remove +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum BIO {} + } else { + #[repr(C)] + pub struct BIO { + pub method: *mut BIO_METHOD, + pub callback: Option< + unsafe extern "C" fn(*mut BIO, c_int, *const c_char, c_int, c_long, c_long) -> c_long, + >, + pub cb_arg: *mut c_char, + pub init: c_int, + pub shutdown: c_int, + pub flags: c_int, + pub retry_reason: c_int, + pub num: c_int, + pub ptr: *mut c_void, + pub next_bio: *mut BIO, + pub prev_bio: *mut BIO, + pub references: c_int, + pub num_read: c_ulong, + pub num_write: c_ulong, + pub ex_data: CRYPTO_EX_DATA, + } + } +} +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum BIGNUM {} + } else { + #[repr(C)] + pub struct BIGNUM { + pub d: *mut BN_ULONG, + pub top: c_int, + pub dmax: c_int, + pub neg: c_int, + pub flags: c_int, + } + } +} +pub enum BN_BLINDING {} +pub enum BN_MONT_CTX {} + +pub enum BN_CTX {} +pub enum BN_GENCB {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum EVP_CIPHER {} + } else { + #[repr(C)] + pub struct EVP_CIPHER { + pub nid: c_int, + pub block_size: c_int, + pub key_len: c_int, + pub iv_len: c_int, + pub flags: c_ulong, + pub init: Option< + unsafe extern "C" fn(*mut EVP_CIPHER_CTX, *const c_uchar, *const c_uchar, c_int) -> c_int, + >, + pub do_cipher: Option< + unsafe extern "C" fn(*mut EVP_CIPHER_CTX, *mut c_uchar, *const c_uchar, size_t) -> c_int, + >, + pub cleanup: Option c_int>, + pub ctx_size: c_int, + pub set_asn1_parameters: + Option c_int>, + pub get_asn1_parameters: + Option c_int>, + pub ctrl: + Option c_int>, + pub app_data: *mut c_void, + } + } +} +pub enum EVP_CIPHER_CTX {} +pub enum EVP_MD {} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum EVP_MD_CTX {} + } else { + #[repr(C)] + pub struct EVP_MD_CTX { + digest: *mut EVP_MD, + engine: *mut ENGINE, + flags: c_ulong, + md_data: *mut c_void, + pctx: *mut EVP_PKEY_CTX, + update: *mut c_void, + } + } +} + +pub enum PKCS8_PRIV_KEY_INFO {} + +pub enum EVP_PKEY_ASN1_METHOD {} + +pub enum EVP_PKEY_CTX {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum HMAC_CTX {} + } else { + #[repr(C)] + pub struct HMAC_CTX { + md: *mut EVP_MD, + md_ctx: EVP_MD_CTX, + i_ctx: EVP_MD_CTX, + o_ctx: EVP_MD_CTX, + key_length: c_uint, + key: [c_uchar; 128], + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum DH {} + } else { + #[repr(C)] + pub struct DH { + pub pad: c_int, + pub version: c_int, + pub p: *mut BIGNUM, + pub g: *mut BIGNUM, + pub length: c_long, + pub pub_key: *mut BIGNUM, + pub priv_key: *mut BIGNUM, + pub flags: c_int, + pub method_mont_p: *mut BN_MONT_CTX, + pub q: *mut BIGNUM, + pub j: *mut BIGNUM, + pub seed: *mut c_uchar, + pub seedlen: c_int, + pub counter: *mut BIGNUM, + pub references: c_int, + pub ex_data: CRYPTO_EX_DATA, + pub meth: *const DH_METHOD, + pub engine: *mut ENGINE, + } + } +} +pub enum DH_METHOD {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum DSA {} + } else { + #[repr(C)] + pub struct DSA { + pub pad: c_int, + pub version: c_long, + pub write_params: c_int, + + pub p: *mut BIGNUM, + pub q: *mut BIGNUM, + pub g: *mut BIGNUM, + pub pub_key: *mut BIGNUM, + pub priv_key: *mut BIGNUM, + pub kinv: *mut BIGNUM, + pub r: *mut BIGNUM, + + pub flags: c_int, + pub method_mont_p: *mut BN_MONT_CTX, + pub references: c_int, + pub ex_data: CRYPTO_EX_DATA, + pub meth: *const DSA_METHOD, + pub engine: *mut ENGINE, + } + } +} +pub enum DSA_METHOD {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum RSA {} + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct RSA { + pub pad: c_int, + pub version: c_long, + pub meth: *const RSA_METHOD, + + pub engine: *mut ENGINE, + pub n: *mut BIGNUM, + pub e: *mut BIGNUM, + pub d: *mut BIGNUM, + pub p: *mut BIGNUM, + pub q: *mut BIGNUM, + pub dmp1: *mut BIGNUM, + pub dmq1: *mut BIGNUM, + pub iqmp: *mut BIGNUM, + + pub ex_data: CRYPTO_EX_DATA, + pub references: c_int, + pub flags: c_int, + + pub _method_mod_n: *mut BN_MONT_CTX, + pub _method_mod_p: *mut BN_MONT_CTX, + pub _method_mod_q: *mut BN_MONT_CTX, + + pub blinding: *mut BN_BLINDING, + pub mt_blinding: *mut BN_BLINDING, + } + } else { + #[repr(C)] + pub struct RSA { + pub pad: c_int, + pub version: c_long, + pub meth: *const RSA_METHOD, + + pub engine: *mut ENGINE, + pub n: *mut BIGNUM, + pub e: *mut BIGNUM, + pub d: *mut BIGNUM, + pub p: *mut BIGNUM, + pub q: *mut BIGNUM, + pub dmp1: *mut BIGNUM, + pub dmq1: *mut BIGNUM, + pub iqmp: *mut BIGNUM, + + pub ex_data: CRYPTO_EX_DATA, + pub references: c_int, + pub flags: c_int, + + pub _method_mod_n: *mut BN_MONT_CTX, + pub _method_mod_p: *mut BN_MONT_CTX, + pub _method_mod_q: *mut BN_MONT_CTX, + + pub bignum_data: *mut c_char, + pub blinding: *mut BN_BLINDING, + pub mt_blinding: *mut BN_BLINDING, + } + } +} +pub enum RSA_METHOD {} + +pub enum EC_KEY {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum X509 {} + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct X509 { + pub cert_info: *mut X509_CINF, + pub sig_alg: *mut X509_ALGOR, + pub signature: *mut ASN1_BIT_STRING, + pub valid: c_int, + pub references: c_int, + pub name: *mut c_char, + pub ex_data: CRYPTO_EX_DATA, + pub ex_pathlen: c_long, + pub ex_pcpathlen: c_long, + pub ex_flags: c_ulong, + pub ex_kusage: c_ulong, + pub ex_xkusage: c_ulong, + pub ex_nscert: c_ulong, + skid: *mut c_void, + akid: *mut c_void, + policy_cache: *mut c_void, + crldp: *mut c_void, + altname: *mut c_void, + nc: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] + sha1_hash: [c_uchar; 20], + aux: *mut c_void, + } + } else { + #[repr(C)] + pub struct X509 { + pub cert_info: *mut X509_CINF, + pub sig_alg: *mut X509_ALGOR, + pub signature: *mut ASN1_BIT_STRING, + pub valid: c_int, + pub references: c_int, + pub name: *mut c_char, + pub ex_data: CRYPTO_EX_DATA, + pub ex_pathlen: c_long, + pub ex_pcpathlen: c_long, + pub ex_flags: c_ulong, + pub ex_kusage: c_ulong, + pub ex_xkusage: c_ulong, + pub ex_nscert: c_ulong, + skid: *mut c_void, + akid: *mut c_void, + policy_cache: *mut c_void, + crldp: *mut c_void, + altname: *mut c_void, + nc: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_addr: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_asid: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] + sha1_hash: [c_uchar; 20], + aux: *mut c_void, + } + } +} +cfg_if! { + if #[cfg(ossl110)] { + pub enum X509_ALGOR {} + } else { + #[repr(C)] + pub struct X509_ALGOR { + pub algorithm: *mut ASN1_OBJECT, + parameter: *mut c_void, + } + } +} + +pub enum X509_LOOKUP_METHOD {} + +pub enum X509_NAME {} + +cfg_if! { + if #[cfg(any(ossl110, libressl270))] { + pub enum X509_STORE {} + } else { + #[repr(C)] + pub struct X509_STORE { + cache: c_int, + pub objs: *mut stack_st_X509_OBJECT, + get_cert_methods: *mut stack_st_X509_LOOKUP, + param: *mut X509_VERIFY_PARAM, + verify: Option c_int>, + verify_cb: Option c_int>, + get_issuer: Option< + extern "C" fn(issuer: *mut *mut X509, ctx: *mut X509_STORE_CTX, x: *mut X509) -> c_int, + >, + check_issued: + Option c_int>, + check_revocation: Option c_int>, + get_crl: Option< + extern "C" fn(ctx: *mut X509_STORE_CTX, crl: *mut *mut X509_CRL, x: *mut X509) -> c_int, + >, + check_crl: Option c_int>, + cert_crl: + Option c_int>, + lookup_certs: + Option *mut stack_st_X509>, + lookup_crls: Option< + extern "C" fn(ctx: *const X509_STORE_CTX, nm: *const X509_NAME) -> *mut stack_st_X509_CRL, + >, + cleanup: Option c_int>, + ex_data: CRYPTO_EX_DATA, + references: c_int, + } + } +} + +pub enum X509_STORE_CTX {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum X509_VERIFY_PARAM {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct X509_VERIFY_PARAM { + pub name: *mut c_char, + pub check_time: time_t, + pub inh_flags: c_ulong, + pub flags: c_ulong, + pub purpose: c_int, + pub trust: c_int, + pub depth: c_int, + pub policies: *mut stack_st_ASN1_OBJECT, + id: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct X509_VERIFY_PARAM { + pub name: *mut c_char, + pub check_time: time_t, + pub inh_flags: c_ulong, + pub flags: c_ulong, + pub purpose: c_int, + pub trust: c_int, + pub depth: c_int, + pub policies: *mut stack_st_ASN1_OBJECT, + //pub id: *mut X509_VERIFY_PARAM_ID, + } + } else { + #[repr(C)] + pub struct X509_VERIFY_PARAM { + pub name: *mut c_char, + pub check_time: time_t, + pub inh_flags: c_ulong, + pub flags: c_ulong, + pub purpose: c_int, + pub trust: c_int, + pub depth: c_int, + pub policies: *mut stack_st_ASN1_OBJECT, + #[cfg(ossl102)] + pub id: *mut X509_VERIFY_PARAM_ID, + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl270))] { + pub enum X509_OBJECT {} + } else { + #[repr(C)] + pub struct X509_OBJECT { + pub type_: c_int, + pub data: X509_OBJECT_data, + } + #[repr(C)] + pub union X509_OBJECT_data { + pub ptr: *mut c_char, + pub x509: *mut X509, + pub crl: *mut X509_CRL, + pub pkey: *mut EVP_PKEY, + } + } +} + +pub enum X509_LOOKUP {} + +#[repr(C)] +pub struct X509V3_CTX { + flags: c_int, + issuer_cert: *mut c_void, + subject_cert: *mut c_void, + subject_req: *mut c_void, + crl: *mut c_void, + db_meth: *mut c_void, + db: *mut c_void, + #[cfg(ossl300)] + issuer_pkey: *mut c_void, + // I like the last comment line, it is copied from OpenSSL sources: + // Maybe more here +} +pub enum CONF {} +#[cfg(ossl110)] +pub enum OPENSSL_INIT_SETTINGS {} + +pub enum ENGINE {} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum SSL {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct SSL { + version: c_int, + method: *const SSL_METHOD, + rbio: *mut BIO, + wbio: *mut BIO, + bbio: *mut BIO, + pub server: c_int, + s3: *mut c_void, + d1: *mut c_void, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut SSL_SESSION, + verify_mode: c_int, + error: c_int, + error_code: c_int, + ctx: *mut SSL_CTX, + verify_result: c_long, + references: c_int, + client_version: c_int, + max_send_fragment: c_uint, + tlsext_hostname: *mut c_char, + tlsext_status_type: c_int, + initial_ctx: *mut SSL_CTX, + enc_read_ctx: *mut EVP_CIPHER_CTX, + read_hash: *mut EVP_MD_CTX, + internal: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct SSL { + version: c_int, + type_: c_int, + method: *const SSL_METHOD, + rbio: *mut c_void, + wbio: *mut c_void, + bbio: *mut c_void, + rwstate: c_int, + in_handshake: c_int, + handshake_func: Option c_int>, + pub server: c_int, + new_session: c_int, + quiet_shutdown: c_int, + shutdown: c_int, + state: c_int, + rstate: c_int, + init_buf: *mut c_void, + init_msg: *mut c_void, + init_num: c_int, + init_off: c_int, + packet: *mut c_uchar, + packet_length: c_uint, + s3: *mut c_void, + d1: *mut c_void, + read_ahead: c_int, + msg_callback: Option< + unsafe extern "C" fn(c_int, + c_int, + c_int, + *const c_void, + size_t, + *mut SSL, + *mut c_void), + >, + msg_callback_arg: *mut c_void, + hit: c_int, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cipher_list_by_id: *mut stack_st_SSL_CIPHER, + mac_flags: c_int, + aead_read_ctx: *mut c_void, + enc_read_ctx: *mut EVP_CIPHER_CTX, + read_hash: *mut EVP_MD_CTX, + aead_write_ctx: *mut c_void, + enc_write_ctx: *mut EVP_CIPHER_CTX, + write_hash: *mut EVP_MD_CTX, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut SSL_SESSION, + generate_session_id: GEN_SESSION_CB, + verify_mode: c_int, + verify_callback: Option c_int>, + info_callback: Option, + error: c_int, + error_code: c_int, + ctx: *mut SSL_CTX, + debug: c_int, + verify_result: c_long, + ex_data: CRYPTO_EX_DATA, + client_CA: *mut stack_st_X509_NAME, + references: c_int, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + first_packet: c_int, + client_version: c_int, + max_send_fragment: c_uint, + tlsext_debug_cb: + Option, + tlsext_debug_arg: *mut c_void, + tlsext_hostname: *mut c_char, + servername_done: c_int, + tlsext_status_type: c_int, + tlsext_status_expected: c_int, + tlsext_ocsp_ids: *mut c_void, + tlsext_ocsp_exts: *mut c_void, + tlsext_ocsp_resp: *mut c_uchar, + tlsext_ocsp_resplen: c_int, + tlsext_ticket_expected: c_int, + tlsext_ecpointformatlist_length: size_t, + tlsext_ecpointformatlist: *mut c_uchar, + tlsext_ellipticcurvelist_length: size_t, + tlsext_ellipticcurvelist: *mut c_uchar, + tlsext_session_ticket: *mut c_void, + tlsext_session_ticket_ext_cb: tls_session_ticket_ext_cb_fn, + tls_session_ticket_ext_cb_arg: *mut c_void, + tls_session_secret_cb: tls_session_secret_cb_fn, + tls_session_secret_cb_arg: *mut c_void, + initial_ctx: *mut SSL_CTX, + next_proto_negotiated: *mut c_uchar, + next_proto_negotiated_len: c_uchar, + srtp_profiles: *mut c_void, + srtp_profile: *mut c_void, + tlsext_heartbeat: c_uint, + tlsext_hb_pending: c_uint, + tlsext_hb_seq: c_uint, + alpn_client_proto_list: *mut c_uchar, + alpn_client_proto_list_len: c_uint, + renegotiate: c_int, + } + } else { + #[repr(C)] + pub struct SSL { + version: c_int, + type_: c_int, + method: *const SSL_METHOD, + rbio: *mut c_void, + wbio: *mut c_void, + bbio: *mut c_void, + rwstate: c_int, + in_handshake: c_int, + handshake_func: Option c_int>, + pub server: c_int, + new_session: c_int, + quiet_session: c_int, + shutdown: c_int, + state: c_int, + rstate: c_int, + init_buf: *mut c_void, + init_msg: *mut c_void, + init_num: c_int, + init_off: c_int, + packet: *mut c_uchar, + packet_length: c_uint, + s2: *mut c_void, + s3: *mut c_void, + d1: *mut c_void, + read_ahead: c_int, + msg_callback: Option< + unsafe extern "C" fn(c_int, c_int, c_int, *const c_void, size_t, *mut SSL, *mut c_void), + >, + msg_callback_arg: *mut c_void, + hit: c_int, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cipher_list_by_id: *mut stack_st_SSL_CIPHER, + mac_flags: c_int, + enc_read_ctx: *mut EVP_CIPHER_CTX, + read_hash: *mut EVP_MD_CTX, + expand: *mut c_void, + enc_write_ctx: *mut EVP_CIPHER_CTX, + write_hash: *mut EVP_MD_CTX, + compress: *mut c_void, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut SSL_SESSION, + generate_session_id: GEN_SESSION_CB, + verify_mode: c_int, + verify_callback: Option c_int>, + info_callback: Option, + error: c_int, + error_code: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + kssl_ctx: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_client_callback: Option< + unsafe extern "C" fn(*mut SSL, *const c_char, *mut c_char, c_uint, *mut c_uchar, c_uint) + -> c_uint, + >, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_server_callback: + Option c_uint>, + ctx: *mut SSL_CTX, + debug: c_int, + verify_result: c_long, + ex_data: CRYPTO_EX_DATA, + client_CA: *mut stack_st_X509_NAME, + references: c_int, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + first_packet: c_int, + client_version: c_int, + max_send_fragment: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_debug_cb: + Option, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_debug_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hostname: *mut c_char, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + servername_done: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_type: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_expected: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_ids: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_exts: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_resp: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_resplen: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticket_expected: c_int, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_len: size_t, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_session_ticket: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_session_ticket_ext_cb: tls_session_ticket_ext_cb_fn, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_ticket_ext_cb_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_secret_cb: tls_session_secret_cb_fn, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_secret_cb_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + initial_ctx: *mut SSL_CTX, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_negotiated: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_negotiated_len: c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + srtp_profiles: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + srtp_profile: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_heartbeat: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hb_pending: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hb_seq: c_uint, + renegotiate: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_ctx: SRP_CTX, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list_len: c_uint, + } + } +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum SSL_CTX {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct SSL_CTX { + method: *const SSL_METHOD, + cipher_list: *mut stack_st_SSL_CIPHER, + cert_store: *mut c_void, + session_timeout: c_long, + pub references: c_int, + extra_certs: *mut stack_st_X509, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + param: *mut X509_VERIFY_PARAM, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + internal: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct SSL_CTX { + method: *mut c_void, + cipher_list: *mut c_void, + cipher_list_by_id: *mut c_void, + cert_store: *mut c_void, + sessions: *mut c_void, + session_cache_size: c_ulong, + session_cache_head: *mut c_void, + session_cache_tail: *mut c_void, + session_cache_mode: c_int, + session_timeout: c_long, + new_session_cb: *mut c_void, + remove_session_cb: *mut c_void, + get_session_cb: *mut c_void, + stats: [c_int; 11], + pub references: c_int, + app_verify_callback: *mut c_void, + app_verify_arg: *mut c_void, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + client_cert_cb: *mut c_void, + app_gen_cookie_cb: *mut c_void, + app_verify_cookie_cb: *mut c_void, + ex_dat: CRYPTO_EX_DATA, + rsa_md5: *mut c_void, + md5: *mut c_void, + sha1: *mut c_void, + extra_certs: *mut c_void, + comp_methods: *mut c_void, + info_callback: *mut c_void, + client_CA: *mut c_void, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + cert: *mut c_void, + read_ahead: c_int, + msg_callback: *mut c_void, + msg_callback_arg: *mut c_void, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; 32], + default_verify_callback: *mut c_void, + generate_session_id: *mut c_void, + param: *mut c_void, + quiet_shutdown: c_int, + max_send_fragment: c_uint, + + #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] + client_cert_engine: *mut c_void, + + tlsext_servername_callback: *mut c_void, + tlsect_servername_arg: *mut c_void, + tlsext_tick_key_name: [c_uchar; 16], + tlsext_tick_hmac_key: [c_uchar; 16], + tlsext_tick_aes_key: [c_uchar; 16], + tlsext_ticket_key_cb: *mut c_void, + tlsext_status_cb: *mut c_void, + tlsext_status_arg: *mut c_void, + tlsext_opaque_prf_input_callback: *mut c_void, + tlsext_opaque_prf_input_callback_arg: *mut c_void, + + next_protos_advertised_cb: *mut c_void, + next_protos_advertised_cb_arg: *mut c_void, + next_proto_select_cb: *mut c_void, + next_proto_select_cb_arg: *mut c_void, + + srtp_profiles: *mut c_void, + } + } else { + #[repr(C)] + pub struct SSL_CTX { + method: *mut c_void, + cipher_list: *mut c_void, + cipher_list_by_id: *mut c_void, + cert_store: *mut c_void, + sessions: *mut c_void, + session_cache_size: c_ulong, + session_cache_head: *mut c_void, + session_cache_tail: *mut c_void, + session_cache_mode: c_int, + session_timeout: c_long, + new_session_cb: *mut c_void, + remove_session_cb: *mut c_void, + get_session_cb: *mut c_void, + stats: [c_int; 11], + pub references: c_int, + app_verify_callback: *mut c_void, + app_verify_arg: *mut c_void, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + client_cert_cb: *mut c_void, + app_gen_cookie_cb: *mut c_void, + app_verify_cookie_cb: *mut c_void, + ex_dat: CRYPTO_EX_DATA, + rsa_md5: *mut c_void, + md5: *mut c_void, + sha1: *mut c_void, + extra_certs: *mut c_void, + comp_methods: *mut c_void, + info_callback: *mut c_void, + client_CA: *mut c_void, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + cert: *mut c_void, + read_ahead: c_int, + msg_callback: *mut c_void, + msg_callback_arg: *mut c_void, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; 32], + default_verify_callback: *mut c_void, + generate_session_id: *mut c_void, + param: *mut c_void, + quiet_shutdown: c_int, + max_send_fragment: c_uint, + + #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] + client_cert_engine: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_servername_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsect_servername_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_key_name: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_hmac_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_aes_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticket_key_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback_arg: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity_hint: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_client_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_server_callback: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + freelist_max_len: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + wbuf_freelist: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + rbuf_freelist: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_ctx: SRP_CTX, + + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_protos_advertised_cb: *mut c_void, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_protos_advertised_cb_arg: *mut c_void, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_select_cb: *mut c_void, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_select_cb_arg: *mut c_void, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl101))] + srtp_profiles: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_select_cb: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_select_cb_arg: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list_len: c_uint, + + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ellipticcurvelist: *mut c_uchar, + } + + #[repr(C)] + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + pub struct SRP_CTX { + SRP_cb_arg: *mut c_void, + TLS_ext_srp_username_callback: *mut c_void, + SRP_verify_param_callback: *mut c_void, + SRP_give_srp_client_pwd_callback: *mut c_void, + login: *mut c_void, + N: *mut c_void, + g: *mut c_void, + s: *mut c_void, + B: *mut c_void, + A: *mut c_void, + a: *mut c_void, + b: *mut c_void, + v: *mut c_void, + info: *mut c_void, + stringth: c_int, + srp_Mask: c_ulong, + } + } +} + +pub enum COMP_CTX {} + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum COMP_METHOD {} + } else { + #[repr(C)] + pub struct COMP_METHOD { + pub type_: c_int, + pub name: *const c_char, + init: Option c_int>, + finish: Option, + compress: Option< + unsafe extern "C" fn( + *mut COMP_CTX, + *mut c_uchar, + c_uint, + *mut c_uchar, + c_uint, + ) -> c_int, + >, + expand: Option< + unsafe extern "C" fn( + *mut COMP_CTX, + *mut c_uchar, + c_uint, + *mut c_uchar, + c_uint, + ) -> c_int, + >, + ctrl: Option c_long>, + callback_ctrl: Option c_long>, + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum CRYPTO_EX_DATA {} + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct CRYPTO_EX_DATA { + pub sk: *mut stack_st_void, + } + } else { + #[repr(C)] + pub struct CRYPTO_EX_DATA { + pub sk: *mut stack_st_void, + pub dummy: c_int, + } + } +} + +pub enum OCSP_RESPONSE {} + +#[cfg(ossl300)] +pub enum OSSL_PROVIDER {} + +#[cfg(ossl300)] +pub enum OSSL_LIB_CTX {} diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs new file mode 100644 index 0000000..8762e5f --- /dev/null +++ b/openssl-sys/src/handwritten/x509.rs @@ -0,0 +1,666 @@ +use super::super::*; +use libc::*; + +#[repr(C)] +pub struct X509_VAL { + pub notBefore: *mut ASN1_TIME, + pub notAfter: *mut ASN1_TIME, +} + +pub enum X509_NAME_ENTRY {} + +stack!(stack_st_X509_NAME); + +pub enum X509_EXTENSION {} + +stack!(stack_st_X509_EXTENSION); + +stack!(stack_st_X509_ATTRIBUTE); + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum X509_REQ_INFO {} + } else { + #[repr(C)] + pub struct X509_REQ_INFO { + pub enc: ASN1_ENCODING, + pub version: *mut ASN1_INTEGER, + pub subject: *mut X509_NAME, + pubkey: *mut c_void, + pub attributes: *mut stack_st_X509_ATTRIBUTE, + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum X509_CRL {} + } else { + #[repr(C)] + pub struct X509_CRL { + pub crl: *mut X509_CRL_INFO, + sig_alg: *mut X509_ALGOR, + signature: *mut c_void, + references: c_int, + flags: c_int, + akid: *mut c_void, + idp: *mut c_void, + idp_flags: c_int, + idp_reasons: c_int, + crl_number: *mut ASN1_INTEGER, + base_crl_number: *mut ASN1_INTEGER, + sha1_hash: [c_uchar; 20], + issuers: *mut c_void, + meth: *const c_void, + meth_data: *mut c_void, + } + } +} + +stack!(stack_st_X509_CRL); + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum X509_CRL_INFO {} + } else { + #[repr(C)] + pub struct X509_CRL_INFO { + version: *mut ASN1_INTEGER, + sig_alg: *mut X509_ALGOR, + pub issuer: *mut X509_NAME, + pub lastUpdate: *mut ASN1_TIME, + pub nextUpdate: *mut ASN1_TIME, + pub revoked: *mut stack_st_X509_REVOKED, + extensions: *mut stack_st_X509_EXTENSION, + enc: ASN1_ENCODING, + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum X509_REVOKED {} + } else { + #[repr(C)] + pub struct X509_REVOKED { + pub serialNumber: *mut ASN1_INTEGER, + pub revocationDate: *mut ASN1_TIME, + pub extensions: *mut stack_st_X509_EXTENSION, + issuer: *mut stack_st_GENERAL_NAME, + reason: c_int, + sequence: c_int, + } + } +} + +stack!(stack_st_X509_REVOKED); + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum X509_REQ {} + } else { + #[repr(C)] + pub struct X509_REQ { + pub req_info: *mut X509_REQ_INFO, + sig_alg: *mut c_void, + signature: *mut c_void, + references: c_int, + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + pub enum X509_CINF {} + } else { + #[repr(C)] + pub struct X509_CINF { + version: *mut c_void, + serialNumber: *mut c_void, + signature: *mut c_void, + issuer: *mut c_void, + pub validity: *mut X509_VAL, + subject: *mut c_void, + key: *mut c_void, + issuerUID: *mut c_void, + subjectUID: *mut c_void, + pub extensions: *mut stack_st_X509_EXTENSION, + enc: ASN1_ENCODING, + } + } +} + +stack!(stack_st_X509); + +stack!(stack_st_X509_OBJECT); + +stack!(stack_st_X509_LOOKUP); + +extern "C" { + pub fn X509_verify_cert_error_string(n: c_long) -> *const c_char; + + pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + + pub fn X509_digest( + x: *const X509, + digest: *const EVP_MD, + buf: *mut c_uchar, + len: *mut c_uint, + ) -> c_int; + + pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; +} + +const_ptr_api! { + extern "C" { + pub fn i2d_X509_bio(b: *mut BIO, x: #[const_ptr_if(ossl300)] X509) -> c_int; + pub fn i2d_X509_REQ_bio(b: *mut BIO, x: #[const_ptr_if(ossl300)] X509_REQ) -> c_int; + pub fn i2d_PrivateKey_bio(b: *mut BIO, x: #[const_ptr_if(ossl300)] EVP_PKEY) -> c_int; + pub fn i2d_PUBKEY_bio(b: *mut BIO, x: #[const_ptr_if(ossl300)] EVP_PKEY) -> c_int; + + pub fn i2d_PUBKEY(k: #[const_ptr_if(ossl300)] EVP_PKEY, buf: *mut *mut u8) -> c_int; + pub fn i2d_RSA_PUBKEY(k: #[const_ptr_if(ossl300)] RSA, buf: *mut *mut u8) -> c_int; + pub fn i2d_DSA_PUBKEY(a: #[const_ptr_if(ossl300)] DSA, pp: *mut *mut c_uchar) -> c_int; + pub fn i2d_PrivateKey(k: #[const_ptr_if(ossl300)] EVP_PKEY, buf: *mut *mut u8) -> c_int; + pub fn i2d_ECPrivateKey(ec_key: #[const_ptr_if(ossl300)] EC_KEY, pp: *mut *mut c_uchar) -> c_int; + pub fn i2d_EC_PUBKEY(a: #[const_ptr_if(ossl300)] EC_KEY, pp: *mut *mut c_uchar) -> c_int; + } +} +extern "C" { + pub fn d2i_PUBKEY(k: *mut *mut EVP_PKEY, buf: *mut *const u8, len: c_long) -> *mut EVP_PKEY; + pub fn d2i_RSA_PUBKEY(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + pub fn d2i_DSA_PUBKEY(k: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; + pub fn d2i_EC_PUBKEY( + a: *mut *mut EC_KEY, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut EC_KEY; + + pub fn d2i_ECPrivateKey( + k: *mut *mut EC_KEY, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut EC_KEY; +} + +const_ptr_api! { + extern "C" { + #[cfg(any(ossl102, libressl350))] + pub fn X509_ALGOR_get0( + paobj: *mut #[const_ptr_if(any(ossl110, libressl350))] ASN1_OBJECT, + pptype: *mut c_int, + ppval: *mut #[const_ptr_if(any(ossl110, libressl350))] c_void, + alg: #[const_ptr_if(any(ossl110, libressl350))] X509_ALGOR, + ); + } +} + +extern "C" { + pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; + + pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; + + pub fn X509_ALGOR_free(x: *mut X509_ALGOR); + + pub fn X509_REVOKED_new() -> *mut X509_REVOKED; + pub fn X509_REVOKED_free(x: *mut X509_REVOKED); +} +const_ptr_api! { + extern "C" { + #[cfg(any(ossl110, libressl270))] + pub fn X509_REVOKED_dup(rev: #[const_ptr_if(ossl300)] X509_REVOKED) -> *mut X509_REVOKED; + } +} + +extern "C" { + pub fn d2i_X509_REVOKED( + a: *mut *mut X509_REVOKED, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_REVOKED; +} +const_ptr_api! { + extern "C" { + pub fn i2d_X509_REVOKED(x: #[const_ptr_if(ossl300)] X509_REVOKED, buf: *mut *mut u8) -> c_int; + } +} +extern "C" { + pub fn X509_CRL_new() -> *mut X509_CRL; + pub fn X509_CRL_free(x: *mut X509_CRL); + pub fn d2i_X509_CRL( + a: *mut *mut X509_CRL, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_CRL; +} +const_ptr_api! { + extern "C" { + pub fn i2d_X509_CRL(x: #[const_ptr_if(ossl300)] X509_CRL, buf: *mut *mut u8) -> c_int; + #[cfg(any(ossl110, libressl270))] + pub fn X509_CRL_dup(x: #[const_ptr_if(ossl300)] X509_CRL) -> *mut X509_CRL; + } +} + +extern "C" { + pub fn X509_REQ_new() -> *mut X509_REQ; + pub fn X509_REQ_free(x: *mut X509_REQ); + pub fn d2i_X509_REQ( + a: *mut *mut X509_REQ, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_REQ; +} +const_ptr_api! { + extern "C" { + pub fn i2d_X509_REQ(x: #[const_ptr_if(ossl300)] X509_REQ, buf: *mut *mut u8) -> c_int; + + #[cfg(any(ossl102, libressl273))] + pub fn X509_get0_signature( + psig: *mut #[const_ptr_if(any(ossl110, libressl273))] ASN1_BIT_STRING, + palg: *mut #[const_ptr_if(any(ossl110, libressl273))] X509_ALGOR, + x: *const X509, + ); + + #[cfg(any(ossl110, libressl270))] + pub fn X509_REQ_dup(x: #[const_ptr_if(ossl300)] X509_REQ) -> *mut X509_REQ; + } +} +extern "C" { + #[cfg(ossl102)] + pub fn X509_get_signature_nid(x: *const X509) -> c_int; + + pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); + + pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); + + pub fn X509_NAME_new() -> *mut X509_NAME; + pub fn X509_NAME_free(x: *mut X509_NAME); + + pub fn X509_new() -> *mut X509; + pub fn X509_free(x: *mut X509); +} +const_ptr_api! { + extern "C" { + pub fn i2d_X509(x: #[const_ptr_if(ossl300)] X509, buf: *mut *mut u8) -> c_int; + #[cfg(any(ossl110, libressl270))] + pub fn X509_NAME_dup(x: #[const_ptr_if(ossl300)] X509_NAME) -> *mut X509_NAME; + #[cfg(any(ossl110, libressl270))] + pub fn X509_dup(x: #[const_ptr_if(ossl300)] X509) -> *mut X509; + #[cfg(any(ossl101, libressl350))] + pub fn X509_NAME_add_entry( + name: *mut X509_NAME, + ne: #[const_ptr_if(any(ossl110, libressl))] X509_NAME_ENTRY, + loc: c_int, + set: c_int, + ) -> c_int; + } +} +extern "C" { + pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; + pub fn d2i_X509_bio(b: *mut BIO, a: *mut *mut X509) -> *mut X509; + + pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY; + + pub fn X509_set_version(x: *mut X509, version: c_long) -> c_int; + #[cfg(ossl110)] + pub fn X509_get_version(x: *const X509) -> c_long; + pub fn X509_set_serialNumber(x: *mut X509, sn: *mut ASN1_INTEGER) -> c_int; + pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; +} +const_ptr_api! { + extern "C" { + pub fn X509_set_issuer_name(x: *mut X509, name: #[const_ptr_if(ossl300)] X509_NAME) -> c_int; + } +} +extern "C" { + pub fn X509_issuer_name_hash(x: *mut X509) -> c_ulong; + pub fn X509_subject_name_hash(x: *mut X509) -> c_ulong; +} +const_ptr_api! { + extern "C" { + pub fn X509_get_issuer_name(x: #[const_ptr_if(any(ossl110, libressl280))] X509) -> *mut X509_NAME; + pub fn X509_set_subject_name(x: *mut X509, name: #[const_ptr_if(ossl300)] X509_NAME) -> c_int; + pub fn X509_get_subject_name(x: #[const_ptr_if(any(ossl110, libressl280))] X509) -> *mut X509_NAME; + } +} +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + extern "C" { + pub fn X509_set1_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set1_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + } + } else { + extern "C" { + pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + } + } +} +extern "C" { + #[cfg(any(ossl110, libressl350))] + pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long; + pub fn X509_REQ_set_version(req: *mut X509_REQ, version: c_long) -> c_int; + #[cfg(any(ossl110, libressl350))] + pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut X509_NAME; +} +const_ptr_api! { + extern "C" { + pub fn X509_REQ_set_subject_name(req: *mut X509_REQ, name: #[const_ptr_if(ossl300)] X509_NAME) -> c_int; + } +} +extern "C" { + pub fn X509_REQ_set_pubkey(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; + pub fn X509_REQ_get_pubkey(req: *mut X509_REQ) -> *mut EVP_PKEY; + pub fn X509_REQ_get_extensions(req: *mut X509_REQ) -> *mut stack_st_X509_EXTENSION; +} +const_ptr_api! { + extern "C" { + pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: #[const_ptr_if(ossl300)] stack_st_X509_EXTENSION) + -> c_int; + } +} +extern "C" { + pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; + pub fn X509_REQ_verify(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn X509_getm_notBefore(x: *const X509) -> *mut ASN1_TIME; + #[cfg(any(ossl110, libressl273))] + pub fn X509_getm_notAfter(x: *const X509) -> *mut ASN1_TIME; + #[cfg(any(ossl110, libressl273))] + pub fn X509_up_ref(x: *mut X509) -> c_int; + + #[cfg(any(ossl110, libressl270))] + pub fn X509_REVOKED_get0_serialNumber(req: *const X509_REVOKED) -> *const ASN1_INTEGER; + #[cfg(any(ossl110, libressl270))] + pub fn X509_REVOKED_get0_revocationDate(req: *const X509_REVOKED) -> *const ASN1_TIME; + #[cfg(any(ossl110, libressl270))] + pub fn X509_REVOKED_get0_extensions(r: *const X509_REVOKED) -> *const stack_st_X509_EXTENSION; + + pub fn X509_REVOKED_set_serialNumber(r: *mut X509_REVOKED, serial: *mut ASN1_INTEGER) -> c_int; + pub fn X509_REVOKED_set_revocationDate(r: *mut X509_REVOKED, tm: *mut ASN1_TIME) -> c_int; + + pub fn X509_CRL_sign(x: *mut X509_CRL, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + pub fn X509_CRL_digest( + x: *const X509_CRL, + digest: *const EVP_MD, + md: *mut c_uchar, + len: *mut c_uint, + ) -> c_int; + pub fn X509_CRL_verify(crl: *mut X509_CRL, pkey: *mut EVP_PKEY) -> c_int; + pub fn X509_CRL_get0_by_cert( + x: *mut X509_CRL, + ret: *mut *mut X509_REVOKED, + cert: *mut X509, + ) -> c_int; +} +const_ptr_api! { + extern "C" { + pub fn X509_CRL_get0_by_serial( + x: *mut X509_CRL, + ret: *mut *mut X509_REVOKED, + serial: #[const_ptr_if(ossl300)] ASN1_INTEGER, + ) -> c_int; + } +} + +extern "C" { + #[cfg(any(ossl110, libressl281))] + pub fn X509_CRL_get_REVOKED(crl: *mut X509_CRL) -> *mut stack_st_X509_REVOKED; + #[cfg(any(ossl110, libressl281))] + pub fn X509_CRL_get0_nextUpdate(x: *const X509_CRL) -> *const ASN1_TIME; + #[cfg(any(ossl110, libressl281))] + pub fn X509_CRL_get0_lastUpdate(x: *const X509_CRL) -> *const ASN1_TIME; + #[cfg(any(ossl110, libressl281))] + pub fn X509_CRL_get_issuer(x: *const X509_CRL) -> *mut X509_NAME; + + #[cfg(ossl110)] + pub fn X509_get0_extensions(req: *const X509) -> *const stack_st_X509_EXTENSION; + + pub fn X509_CRL_set_version(crl: *mut X509_CRL, version: c_long) -> c_int; +} +const_ptr_api! { + extern "C" { + pub fn X509_CRL_set_issuer_name(crl: *mut X509_CRL, name: #[const_ptr_if(ossl300)] X509_NAME) -> c_int; + } +} +extern "C" { + pub fn X509_CRL_sort(crl: *mut X509_CRL) -> c_int; + + #[cfg(any(ossl110, libressl270))] + pub fn X509_CRL_up_ref(crl: *mut X509_CRL) -> c_int; + pub fn X509_CRL_add0_revoked(crl: *mut X509_CRL, rev: *mut X509_REVOKED) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl110, libressl270))] { + extern "C" { + pub fn X509_CRL_set1_lastUpdate(crl: *mut X509_CRL, tm: *const ASN1_TIME) -> c_int; + pub fn X509_CRL_set1_nextUpdate(crl: *mut X509_CRL, tm: *const ASN1_TIME) -> c_int; + } + } else { + // libressl270 kept them, ossl110 "#define"s them to the variants above + extern "C" { + pub fn X509_CRL_set_lastUpdate(crl: *mut X509_CRL, tm: *const ASN1_TIME) -> c_int; + pub fn X509_CRL_set_nextUpdate(crl: *mut X509_CRL, tm: *const ASN1_TIME) -> c_int; + } + } +} + +const_ptr_api! { + extern "C" { + pub fn X509_NAME_entry_count(n: #[const_ptr_if(any(ossl110, libressl280))] X509_NAME) -> c_int; + pub fn X509_NAME_get_index_by_NID(n: #[const_ptr_if(any(ossl300, libressl280))] X509_NAME, nid: c_int, last_pos: c_int) -> c_int; + pub fn X509_NAME_get_entry(n: #[const_ptr_if(any(ossl110, libressl280))] X509_NAME, loc: c_int) -> *mut X509_NAME_ENTRY; + pub fn X509_NAME_add_entry_by_NID( + x: *mut X509_NAME, + field: c_int, + ty: c_int, + bytes: #[const_ptr_if(any(ossl110, libressl280))] c_uchar, + len: c_int, + loc: c_int, + set: c_int, + ) -> c_int; + pub fn i2d_X509_NAME(n: #[const_ptr_if(ossl300)] X509_NAME, buf: *mut *mut u8) -> c_int; + pub fn X509_NAME_ENTRY_get_object(ne: #[const_ptr_if(any(ossl110, libressl280))] X509_NAME_ENTRY) -> *mut ASN1_OBJECT; + pub fn X509_NAME_ENTRY_get_data(ne: #[const_ptr_if(any(ossl110, libressl280))] X509_NAME_ENTRY) -> *mut ASN1_STRING; + } +} +extern "C" { + pub fn X509_NAME_add_entry_by_txt( + x: *mut X509_NAME, + field: *const c_char, + ty: c_int, + bytes: *const c_uchar, + len: c_int, + loc: c_int, + set: c_int, + ) -> c_int; + pub fn d2i_X509_NAME( + n: *mut *mut X509_NAME, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_NAME; +} + +// "raw" X509_EXTENSION related functions +extern "C" { + // in X509 + pub fn X509_delete_ext(x: *mut X509, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; + pub fn X509_add1_ext_i2d( + x: *mut X509, + nid: c_int, + value: *mut c_void, + crit: c_int, + flags: c_ulong, + ) -> c_int; + // in X509_CRL + pub fn X509_CRL_delete_ext(x: *mut X509_CRL, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509_CRL_add_ext(x: *mut X509_CRL, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; + pub fn X509_CRL_add1_ext_i2d( + x: *mut X509_CRL, + nid: c_int, + value: *mut c_void, + crit: c_int, + flags: c_ulong, + ) -> c_int; + // in X509_REVOKED + pub fn X509_REVOKED_delete_ext(x: *mut X509_REVOKED, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509_REVOKED_add_ext( + x: *mut X509_REVOKED, + ext: *mut X509_EXTENSION, + loc: c_int, + ) -> c_int; + pub fn X509_REVOKED_add1_ext_i2d( + x: *mut X509_REVOKED, + nid: c_int, + value: *mut c_void, + crit: c_int, + flags: c_ulong, + ) -> c_int; + // X509_EXTENSION stack + // - these getters always used *const STACK + pub fn X509v3_get_ext_count(x: *const stack_st_X509_EXTENSION) -> c_int; + pub fn X509v3_get_ext_by_NID( + x: *const stack_st_X509_EXTENSION, + nid: c_int, + lastpos: c_int, + ) -> c_int; + pub fn X509v3_get_ext_by_critical( + x: *const stack_st_X509_EXTENSION, + crit: c_int, + lastpos: c_int, + ) -> c_int; + pub fn X509v3_get_ext(x: *const stack_st_X509_EXTENSION, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509v3_delete_ext(x: *mut stack_st_X509_EXTENSION, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509v3_add_ext( + x: *mut *mut stack_st_X509_EXTENSION, + ex: *mut X509_EXTENSION, + loc: c_int, + ) -> *mut stack_st_X509_EXTENSION; + // - X509V3_add1_i2d in x509v3.rs + // X509_EXTENSION itself + pub fn X509_EXTENSION_create_by_NID( + ex: *mut *mut X509_EXTENSION, + nid: c_int, + crit: c_int, + data: *mut ASN1_OCTET_STRING, + ) -> *mut X509_EXTENSION; + pub fn X509_EXTENSION_set_critical(ex: *mut X509_EXTENSION, crit: c_int) -> c_int; + pub fn X509_EXTENSION_set_data(ex: *mut X509_EXTENSION, data: *mut ASN1_OCTET_STRING) -> c_int; + pub fn X509_EXTENSION_get_object(ext: *mut X509_EXTENSION) -> *mut ASN1_OBJECT; + pub fn X509_EXTENSION_get_data(ext: *mut X509_EXTENSION) -> *mut ASN1_OCTET_STRING; +} +const_ptr_api! { + extern "C" { + // in X509 + pub fn X509_get_ext_count(x: #[const_ptr_if(any(ossl110, libressl280))] X509) -> c_int; + pub fn X509_get_ext_by_NID(x: #[const_ptr_if(any(ossl110, libressl280))] X509, nid: c_int, lastpos: c_int) -> c_int; + pub fn X509_get_ext_by_OBJ(x: #[const_ptr_if(any(ossl110, libressl280))] X509, obj: #[const_ptr_if(any(ossl110, libressl280))] ASN1_OBJECT, lastpos: c_int) -> c_int; + pub fn X509_get_ext_by_critical(x: #[const_ptr_if(any(ossl110, libressl280))] X509, crit: c_int, lastpos: c_int) -> c_int; + pub fn X509_get_ext(x: #[const_ptr_if(any(ossl110, libressl280))] X509, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509_get_ext_d2i( + x: #[const_ptr_if(any(ossl110, libressl280))] X509, + nid: c_int, + crit: *mut c_int, + idx: *mut c_int, + ) -> *mut c_void; + // in X509_CRL + pub fn X509_CRL_get_ext_count(x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL) -> c_int; + pub fn X509_CRL_get_ext_by_NID(x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, nid: c_int, lastpos: c_int) -> c_int; + pub fn X509_CRL_get_ext_by_OBJ(x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, obj: #[const_ptr_if(any(ossl110, libressl280))] ASN1_OBJECT, lastpos: c_int) -> c_int; + pub fn X509_CRL_get_ext_by_critical(x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, crit: c_int, lastpos: c_int) -> c_int; + pub fn X509_CRL_get_ext(x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509_CRL_get_ext_d2i( + x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, + nid: c_int, + crit: *mut c_int, + idx: *mut c_int, + ) -> *mut c_void; + // in X509_REVOKED + pub fn X509_REVOKED_get_ext_count(x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED) -> c_int; + pub fn X509_REVOKED_get_ext_by_NID(x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, nid: c_int, lastpos: c_int) -> c_int; + pub fn X509_REVOKED_get_ext_by_OBJ(x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, obj: #[const_ptr_if(any(ossl110, libressl280))] ASN1_OBJECT, lastpos: c_int) -> c_int; + pub fn X509_REVOKED_get_ext_by_critical(x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, crit: c_int, lastpos: c_int) -> c_int; + pub fn X509_REVOKED_get_ext(x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, loc: c_int) -> *mut X509_EXTENSION; + pub fn X509_REVOKED_get_ext_d2i( + x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, + nid: c_int, + crit: *mut c_int, + idx: *mut c_int, + ) -> *mut c_void; + // X509_EXTENSION stack + pub fn X509v3_get_ext_by_OBJ(x: *const stack_st_X509_EXTENSION, obj: #[const_ptr_if(any(ossl110, libressl280))] ASN1_OBJECT, lastpos: c_int) -> c_int; + // X509_EXTENSION itself + pub fn X509_EXTENSION_create_by_OBJ(ex: *mut *mut X509_EXTENSION, obj: #[const_ptr_if(any(ossl110, libressl280))] ASN1_OBJECT, crit: c_int, data: *mut ASN1_OCTET_STRING) -> *mut X509_EXTENSION; + pub fn X509_EXTENSION_set_object(ex: *mut X509_EXTENSION, obj: #[const_ptr_if(any(ossl110, libressl280))] ASN1_OBJECT) -> c_int; + pub fn X509_EXTENSION_get_critical(ex: #[const_ptr_if(any(ossl110, libressl280))] X509_EXTENSION) -> c_int; + } +} + +extern "C" { + pub fn X509_verify_cert(ctx: *mut X509_STORE_CTX) -> c_int; +} + +const_ptr_api! { + extern "C" { + #[cfg(any(ossl110, libressl270))] + pub fn X509_STORE_get0_objects(ctx: #[const_ptr_if(ossl300)] X509_STORE) -> *mut stack_st_X509_OBJECT; + } +} +#[cfg(any(ossl110, libressl270))] +extern "C" { + pub fn X509_OBJECT_get0_X509(x: *const X509_OBJECT) -> *mut X509; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + extern "C" { + pub fn X509_OBJECT_free(a: *mut X509_OBJECT); + } + } else { + extern "C" { + pub fn X509_OBJECT_free_contents(a: *mut X509_OBJECT); + } + } +} + +extern "C" { + pub fn X509_get_default_cert_file_env() -> *const c_char; + pub fn X509_get_default_cert_file() -> *const c_char; + pub fn X509_get_default_cert_dir_env() -> *const c_char; + pub fn X509_get_default_cert_dir() -> *const c_char; +} + +extern "C" { + pub fn X509_cmp(a: *const X509, b: *const X509) -> c_int; + pub fn X509_NAME_cmp(a: *const X509_NAME, b: *const X509_NAME) -> c_int; + pub fn X509_issuer_and_serial_cmp(a: *const X509, b: *const X509) -> c_int; + pub fn X509_issuer_name_cmp(a: *const X509, b: *const X509) -> c_int; + pub fn X509_subject_name_cmp(a: *const X509, b: *const X509) -> c_int; + pub fn X509_CRL_cmp(a: *const X509_CRL, b: *const X509_CRL) -> c_int; + pub fn X509_CRL_match(a: *const X509_CRL, b: *const X509_CRL) -> c_int; +} + +extern "C" { + pub fn X509_print(bio: *mut BIO, x509: *mut X509) -> c_int; + pub fn X509_REQ_print(bio: *mut BIO, req: *mut X509_REQ) -> c_int; +} + +#[repr(C)] +pub struct X509_PURPOSE { + pub purpose: c_int, + pub trust: c_int, // Default trust ID + pub flags: c_int, + pub check_purpose: + Option c_int>, + pub name: *mut c_char, + pub sname: *mut c_char, + pub usr_data: *mut c_void, +} + +const_ptr_api! { + extern "C" { + pub fn X509_PURPOSE_get_by_sname(sname: #[const_ptr_if(any(ossl110, libressl280))] c_char) -> c_int; + pub fn X509_PURPOSE_get0(idx: c_int) -> *mut X509_PURPOSE; + } +} diff --git a/openssl-sys/src/handwritten/x509_vfy.rs b/openssl-sys/src/handwritten/x509_vfy.rs new file mode 100644 index 0000000..9adf63f --- /dev/null +++ b/openssl-sys/src/handwritten/x509_vfy.rs @@ -0,0 +1,132 @@ +use super::super::*; +use libc::*; + +#[cfg(any(libressl, all(ossl102, not(ossl110))))] +pub enum X509_VERIFY_PARAM_ID {} + +extern "C" { + #[cfg(ossl110)] + pub fn X509_LOOKUP_meth_free(method: *mut X509_LOOKUP_METHOD); +} + +extern "C" { + pub fn X509_LOOKUP_free(ctx: *mut X509_LOOKUP); + pub fn X509_LOOKUP_hash_dir() -> *mut X509_LOOKUP_METHOD; + pub fn X509_LOOKUP_file() -> *mut X509_LOOKUP_METHOD; + pub fn X509_LOOKUP_ctrl( + ctx: *mut X509_LOOKUP, + cmd: c_int, + argc: *const c_char, + argl: c_long, + ret: *mut *mut c_char, + ) -> c_int; + pub fn X509_load_cert_file(ctx: *mut X509_LOOKUP, file: *const c_char, _type: c_int) -> c_int; + pub fn X509_load_crl_file(ctx: *mut X509_LOOKUP, file: *const c_char, _type: c_int) -> c_int; +} + +extern "C" { + pub fn X509_STORE_new() -> *mut X509_STORE; + pub fn X509_STORE_free(store: *mut X509_STORE); + + pub fn X509_STORE_CTX_new() -> *mut X509_STORE_CTX; + + pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX); + pub fn X509_STORE_CTX_init( + ctx: *mut X509_STORE_CTX, + store: *mut X509_STORE, + x509: *mut X509, + chain: *mut stack_st_X509, + ) -> c_int; + pub fn X509_STORE_CTX_cleanup(ctx: *mut X509_STORE_CTX); + + pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int; + + pub fn X509_STORE_add_lookup( + store: *mut X509_STORE, + meth: *mut X509_LOOKUP_METHOD, + ) -> *mut X509_LOOKUP; + + pub fn X509_STORE_set_default_paths(store: *mut X509_STORE) -> c_int; + pub fn X509_STORE_set_flags(store: *mut X509_STORE, flags: c_ulong) -> c_int; + pub fn X509_STORE_set_purpose(ctx: *mut X509_STORE, purpose: c_int) -> c_int; + pub fn X509_STORE_set_trust(ctx: *mut X509_STORE, trust: c_int) -> c_int; + +} + +const_ptr_api! { + extern "C" { + pub fn X509_STORE_set1_param(store: *mut X509_STORE, pm: #[const_ptr_if(ossl300)] X509_VERIFY_PARAM) -> c_int; + } +} + +const_ptr_api! { + extern "C" { + pub fn X509_STORE_CTX_get_ex_data(ctx: #[const_ptr_if(ossl300)] X509_STORE_CTX, idx: c_int) -> *mut c_void; + pub fn X509_STORE_CTX_get_error(ctx: #[const_ptr_if(ossl300)] X509_STORE_CTX) -> c_int; + pub fn X509_STORE_CTX_get_error_depth(ctx: #[const_ptr_if(ossl300)] X509_STORE_CTX) -> c_int; + pub fn X509_STORE_CTX_get_current_cert(ctx: #[const_ptr_if(ossl300)] X509_STORE_CTX) -> *mut X509; + } +} +extern "C" { + pub fn X509_STORE_CTX_set_error(ctx: *mut X509_STORE_CTX, error: c_int); +} +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + const_ptr_api! { + extern "C" { + pub fn X509_STORE_CTX_get0_chain(ctx: #[const_ptr_if(ossl300)] X509_STORE_CTX) -> *mut stack_st_X509; + } + } + } else { + extern "C" { + pub fn X509_STORE_CTX_get_chain(ctx: *mut X509_STORE_CTX) -> *mut stack_st_X509; + } + } +} + +extern "C" { + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_new() -> *mut X509_VERIFY_PARAM; + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); + + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set_flags(param: *mut X509_VERIFY_PARAM, flags: c_ulong) -> c_int; + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_clear_flags(param: *mut X509_VERIFY_PARAM, flags: c_ulong) -> c_int; + + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set_time(param: *mut X509_VERIFY_PARAM, t: time_t); + + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set_depth(param: *mut X509_VERIFY_PARAM, depth: c_int); +} +const_ptr_api! { + extern "C" { + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_get_flags(param: #[const_ptr_if(ossl300)] X509_VERIFY_PARAM) -> c_ulong; + } +} + +extern "C" { + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set1_host( + param: *mut X509_VERIFY_PARAM, + name: *const c_char, + namelen: size_t, + ) -> c_int; + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint); + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set1_ip( + param: *mut X509_VERIFY_PARAM, + ip: *const c_uchar, + iplen: size_t, + ) -> c_int; + #[cfg(ossl110)] + pub fn X509_VERIFY_PARAM_set_auth_level(param: *mut X509_VERIFY_PARAM, lvl: c_int); + #[cfg(ossl110)] + pub fn X509_VERIFY_PARAM_get_auth_level(param: *const X509_VERIFY_PARAM) -> c_int; + #[cfg(ossl102)] + pub fn X509_VERIFY_PARAM_set_purpose(param: *mut X509_VERIFY_PARAM, purpose: c_int) -> c_int; +} diff --git a/openssl-sys/src/handwritten/x509v3.rs b/openssl-sys/src/handwritten/x509v3.rs new file mode 100644 index 0000000..d0923e3 --- /dev/null +++ b/openssl-sys/src/handwritten/x509v3.rs @@ -0,0 +1,104 @@ +use super::super::*; +use libc::*; + +pub enum CONF_METHOD {} + +extern "C" { + pub fn GENERAL_NAME_free(name: *mut GENERAL_NAME); +} + +#[repr(C)] +pub struct ACCESS_DESCRIPTION { + pub method: *mut ASN1_OBJECT, + pub location: *mut GENERAL_NAME, +} + +stack!(stack_st_ACCESS_DESCRIPTION); + +extern "C" { + pub fn ACCESS_DESCRIPTION_free(ad: *mut ACCESS_DESCRIPTION); +} + +#[repr(C)] +pub struct AUTHORITY_KEYID { + pub keyid: *mut ASN1_OCTET_STRING, + pub issuer: *mut stack_st_GENERAL_NAME, + pub serial: *mut ASN1_INTEGER, +} + +extern "C" { + pub fn AUTHORITY_KEYID_free(akid: *mut AUTHORITY_KEYID); +} + +const_ptr_api! { + extern "C" { + pub fn X509V3_EXT_nconf_nid( + conf: *mut CONF, + ctx: *mut X509V3_CTX, + ext_nid: c_int, + value: #[const_ptr_if(any(ossl110, libressl280))] c_char, + ) -> *mut X509_EXTENSION; + pub fn X509V3_EXT_nconf( + conf: *mut CONF, + ctx: *mut X509V3_CTX, + name: #[const_ptr_if(any(ossl110, libressl280))] c_char, + value: #[const_ptr_if(any(ossl110, libressl280))] c_char, + ) -> *mut X509_EXTENSION; + } +} + +extern "C" { + pub fn X509_check_issued(issuer: *mut X509, subject: *mut X509) -> c_int; + pub fn X509_verify(req: *mut X509, pkey: *mut EVP_PKEY) -> c_int; + + pub fn X509V3_set_nconf(ctx: *mut X509V3_CTX, conf: *mut CONF); + + pub fn X509V3_set_ctx( + ctx: *mut X509V3_CTX, + issuer: *mut X509, + subject: *mut X509, + req: *mut X509_REQ, + crl: *mut X509_CRL, + flags: c_int, + ); + + pub fn X509_get1_ocsp(x: *mut X509) -> *mut stack_st_OPENSSL_STRING; +} + +const_ptr_api! { + extern "C" { + pub fn X509V3_get_d2i( + x: #[const_ptr_if(any(ossl110, libressl280))] stack_st_X509_EXTENSION, + nid: c_int, + crit: *mut c_int, + idx: *mut c_int, + ) -> *mut c_void; + pub fn X509V3_extensions_print(out: *mut BIO, title: #[const_ptr_if(any(ossl110, libressl280))] c_char, exts: #[const_ptr_if(any(ossl110, libressl280))] stack_st_X509_EXTENSION, flag: c_ulong, indent: c_int) -> c_int; + } +} + +extern "C" { + pub fn X509V3_EXT_add_alias(nid_to: c_int, nid_from: c_int) -> c_int; + pub fn X509V3_EXT_d2i(ext: *mut X509_EXTENSION) -> *mut c_void; + pub fn X509V3_EXT_i2d(ext_nid: c_int, crit: c_int, ext: *mut c_void) -> *mut X509_EXTENSION; + pub fn X509V3_add1_i2d( + x: *mut *mut stack_st_X509_EXTENSION, + nid: c_int, + value: *mut c_void, + crit: c_int, + flags: c_ulong, + ) -> c_int; + pub fn X509V3_EXT_print( + out: *mut BIO, + ext: *mut X509_EXTENSION, + flag: c_ulong, + indent: c_int, + ) -> c_int; + + #[cfg(ossl110)] + pub fn X509_get_extension_flags(x: *mut X509) -> u32; + #[cfg(ossl110)] + pub fn X509_get_key_usage(x: *mut X509) -> u32; + #[cfg(ossl110)] + pub fn X509_get_extended_key_usage(x: *mut X509) -> u32; +} diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index e2f7c83..c308475 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,2679 +1,212 @@ -#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] -#![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://docs.rs/openssl-sys/0.9")] +#![allow( + clippy::missing_safety_doc, + clippy::unreadable_literal, + clippy::uninlined_format_args, + clippy::upper_case_acronyms, + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + overflowing_literals, + unused_imports +)] +#![doc(html_root_url = "https://docs.rs/openssl-sys/0.9")] +#![recursion_limit = "128"] // configure fixed limit across all rust versions extern crate libc; - -use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t, FILE}; -use std::ptr; -use std::mem; - -#[cfg(any(ossl101, ossl102))] -mod ossl10x; -#[cfg(any(ossl101, ossl102))] -pub use ossl10x::*; - -#[cfg(ossl110)] -mod ossl110; -#[cfg(ossl110)] -pub use ossl110::*; - -#[cfg(libressl)] -mod libressl; -#[cfg(libressl)] -pub use libressl::*; - -pub enum ASN1_INTEGER {} -pub enum ASN1_GENERALIZEDTIME {} -pub enum ASN1_STRING {} -pub enum ASN1_BIT_STRING {} -pub enum ASN1_TIME {} -pub enum ASN1_TYPE {} -pub enum ASN1_OBJECT {} -pub enum BN_CTX {} -pub enum BN_GENCB {} -pub enum CMS_ContentInfo {} -pub enum CONF {} -pub enum CONF_METHOD {} -pub enum COMP_METHOD {} -pub enum EC_KEY {} -pub enum EC_GROUP {} -pub enum EC_METHOD {} -pub enum EC_POINT {} -pub enum ENGINE {} -pub enum EVP_CIPHER_CTX {} -pub enum EVP_MD {} -pub enum EVP_PKEY_CTX {} -pub enum OCSP_BASICRESP {} -pub enum OCSP_CERTID {} -pub enum OCSP_RESPONSE {} -pub enum OCSP_REQUEST {} -pub enum OCSP_ONEREQ {} -pub enum SSL_CIPHER {} -pub enum SSL_METHOD {} -pub enum X509_CRL {} -pub enum X509_EXTENSION {} -pub enum X509_NAME {} -pub enum X509_NAME_ENTRY {} -pub enum X509_STORE {} -pub enum X509_STORE_CTX {} -pub enum bio_st {} -pub enum DH_METHOD {} -pub enum RSA_METHOD {} -pub enum BN_MONT_CTX {} -pub enum BN_BLINDING {} -pub enum DSA_METHOD {} -pub enum EVP_PKEY_ASN1_METHOD {} - -pub type bio_info_cb = Option< - unsafe extern "C" fn(*mut BIO, - c_int, - *const c_char, - c_int, - c_long, - c_long), ->; -pub type GEN_SESSION_CB = Option< - unsafe extern "C" fn(*const SSL, *mut c_uchar, *mut c_uint) - -> c_int, ->; -pub type tls_session_ticket_ext_cb_fn = Option< - unsafe extern "C" fn(*mut SSL, - *const c_uchar, - c_int, - *mut c_void) - -> c_int, ->; -pub type tls_session_secret_cb_fn = Option< - unsafe extern "C" fn(*mut SSL, - *mut c_void, - *mut c_int, - *mut stack_st_SSL_CIPHER, - *mut *mut SSL_CIPHER, - *mut c_void) - -> c_int, ->; - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum point_conversion_form_t { - POINT_CONVERSION_COMPRESSED = 2, - POINT_CONVERSION_UNCOMPRESSED = 4, - POINT_CONVERSION_HYBRID = 6, -} - -#[repr(C)] -pub struct AES_KEY { - // There is some business with AES_LONG which is there to ensure the values here are 32 bits - rd_key: [u32; 4 * (AES_MAXNR as usize + 1)], - rounds: c_int, -} - -#[repr(C)] -pub struct GENERAL_NAME { - pub type_: c_int, - pub d: *mut c_void, -} - -#[repr(C)] -pub struct X509V3_CTX { - flags: c_int, - issuer_cert: *mut c_void, - subject_cert: *mut c_void, - subject_req: *mut c_void, - crl: *mut c_void, - db_meth: *mut c_void, - db: *mut c_void, - // I like the last comment line, it is copied from OpenSSL sources: - // Maybe more here -} - -#[repr(C)] -pub struct SHA_CTX { - pub h0: SHA_LONG, - pub h1: SHA_LONG, - pub h2: SHA_LONG, - pub h3: SHA_LONG, - pub h4: SHA_LONG, - pub Nl: SHA_LONG, - pub Nh: SHA_LONG, - pub data: [SHA_LONG; SHA_LBLOCK as usize], - pub num: c_uint, -} - -#[repr(C)] -pub struct SHA256_CTX { - pub h: [SHA_LONG; 8], - pub Nl: SHA_LONG, - pub Nh: SHA_LONG, - pub data: [SHA_LONG; SHA_LBLOCK as usize], - pub num: c_uint, - pub md_len: c_uint, -} - -#[repr(C)] -pub struct SHA512_CTX { - pub h: [SHA_LONG64; 8], - pub Nl: SHA_LONG64, - pub Nh: SHA_LONG64, - // this is a union but we don't want to require 1.19 - u: [SHA_LONG64; SHA_LBLOCK as usize], - pub num: c_uint, - pub md_len: c_uint, -} - -#[cfg(target_pointer_width = "64")] -pub type BN_ULONG = libc::c_ulonglong; -#[cfg(target_pointer_width = "32")] -pub type BN_ULONG = c_uint; - -pub type CRYPTO_EX_new = unsafe extern "C" fn(parent: *mut c_void, - ptr: *mut c_void, - ad: *const CRYPTO_EX_DATA, - idx: c_int, - argl: c_long, - argp: *const c_void) - -> c_int; -pub type CRYPTO_EX_dup = unsafe extern "C" fn(to: *mut CRYPTO_EX_DATA, - from: *mut CRYPTO_EX_DATA, - from_d: *mut c_void, - idx: c_int, - argl: c_long, - argp: *mut c_void) - -> c_int; -pub type CRYPTO_EX_free = unsafe extern "C" fn(parent: *mut c_void, - ptr: *mut c_void, - ad: *mut CRYPTO_EX_DATA, - idx: c_int, - argl: c_long, - argp: *mut c_void); -pub type PasswordCallback = unsafe extern "C" fn(buf: *mut c_char, - size: c_int, - rwflag: c_int, - user_data: *mut c_void) - -> c_int; - -pub type SHA_LONG = c_uint; -pub type SHA_LONG64 = u64; - -pub const AES_ENCRYPT: c_int = 1; -pub const AES_DECRYPT: c_int = 0; - -pub const AES_MAXNR: c_int = 14; -pub const AES_BLOCK_SIZE: c_int = 16; - -pub const BIO_TYPE_NONE: c_int = 0; - -pub const BIO_CTRL_EOF: c_int = 2; -pub const BIO_CTRL_INFO: c_int = 3; -pub const BIO_CTRL_FLUSH: c_int = 11; -pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130; - -pub const BIO_FLAGS_READ: c_int = 0x01; -pub const BIO_FLAGS_WRITE: c_int = 0x02; -pub const BIO_FLAGS_IO_SPECIAL: c_int = 0x04; -pub const BIO_FLAGS_RWS: c_int = BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL; -pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08; - -pub const CRYPTO_LOCK: c_int = 1; - -pub const ERR_TXT_MALLOCED: c_int = 0x01; -pub const ERR_TXT_STRING: c_int = 0x02; - -pub const ERR_LIB_PEM: c_int = 9; -pub const PEM_R_NO_START_LINE: c_int = 108; - -pub const EVP_MAX_MD_SIZE: c_uint = 64; -pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; -pub const EVP_PKEY_HMAC: c_int = NID_hmac; -pub const EVP_PKEY_DSA: c_int = NID_dsa; -pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; -pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; - -pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000; - -pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; - -pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; - -pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9; -pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10; -pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11; - -pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; -pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; -pub const MBSTRING_FLAG: c_int = 0x1000; -pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; -pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; - -pub const NID_undef: c_int = 0; -pub const NID_itu_t: c_int = 645; -pub const NID_ccitt: c_int = 404; -pub const NID_iso: c_int = 181; -pub const NID_joint_iso_itu_t: c_int = 646; -pub const NID_joint_iso_ccitt: c_int = 393; -pub const NID_member_body: c_int = 182; -pub const NID_identified_organization: c_int = 676; -pub const NID_hmac_md5: c_int = 780; -pub const NID_hmac_sha1: c_int = 781; -pub const NID_certicom_arc: c_int = 677; -pub const NID_international_organizations: c_int = 647; -pub const NID_wap: c_int = 678; -pub const NID_wap_wsg: c_int = 679; -pub const NID_selected_attribute_types: c_int = 394; -pub const NID_clearance: c_int = 395; -pub const NID_ISO_US: c_int = 183; -pub const NID_X9_57: c_int = 184; -pub const NID_X9cm: c_int = 185; -pub const NID_dsa: c_int = 116; -pub const NID_dsaWithSHA1: c_int = 113; -pub const NID_ansi_X9_62: c_int = 405; -pub const NID_X9_62_prime_field: c_int = 406; -pub const NID_X9_62_characteristic_two_field: c_int = 407; -pub const NID_X9_62_id_characteristic_two_basis: c_int = 680; -pub const NID_X9_62_onBasis: c_int = 681; -pub const NID_X9_62_tpBasis: c_int = 682; -pub const NID_X9_62_ppBasis: c_int = 683; -pub const NID_X9_62_id_ecPublicKey: c_int = 408; -pub const NID_X9_62_c2pnb163v1: c_int = 684; -pub const NID_X9_62_c2pnb163v2: c_int = 685; -pub const NID_X9_62_c2pnb163v3: c_int = 686; -pub const NID_X9_62_c2pnb176v1: c_int = 687; -pub const NID_X9_62_c2tnb191v1: c_int = 688; -pub const NID_X9_62_c2tnb191v2: c_int = 689; -pub const NID_X9_62_c2tnb191v3: c_int = 690; -pub const NID_X9_62_c2onb191v4: c_int = 691; -pub const NID_X9_62_c2onb191v5: c_int = 692; -pub const NID_X9_62_c2pnb208w1: c_int = 693; -pub const NID_X9_62_c2tnb239v1: c_int = 694; -pub const NID_X9_62_c2tnb239v2: c_int = 695; -pub const NID_X9_62_c2tnb239v3: c_int = 696; -pub const NID_X9_62_c2onb239v4: c_int = 697; -pub const NID_X9_62_c2onb239v5: c_int = 698; -pub const NID_X9_62_c2pnb272w1: c_int = 699; -pub const NID_X9_62_c2pnb304w1: c_int = 700; -pub const NID_X9_62_c2tnb359v1: c_int = 701; -pub const NID_X9_62_c2pnb368w1: c_int = 702; -pub const NID_X9_62_c2tnb431r1: c_int = 703; -pub const NID_X9_62_prime192v1: c_int = 409; -pub const NID_X9_62_prime192v2: c_int = 410; -pub const NID_X9_62_prime192v3: c_int = 411; -pub const NID_X9_62_prime239v1: c_int = 412; -pub const NID_X9_62_prime239v2: c_int = 413; -pub const NID_X9_62_prime239v3: c_int = 414; -pub const NID_X9_62_prime256v1: c_int = 415; -pub const NID_ecdsa_with_SHA1: c_int = 416; -pub const NID_ecdsa_with_Recommended: c_int = 791; -pub const NID_ecdsa_with_Specified: c_int = 792; -pub const NID_ecdsa_with_SHA224: c_int = 793; -pub const NID_ecdsa_with_SHA256: c_int = 794; -pub const NID_ecdsa_with_SHA384: c_int = 795; -pub const NID_ecdsa_with_SHA512: c_int = 796; -pub const NID_secp112r1: c_int = 704; -pub const NID_secp112r2: c_int = 705; -pub const NID_secp128r1: c_int = 706; -pub const NID_secp128r2: c_int = 707; -pub const NID_secp160k1: c_int = 708; -pub const NID_secp160r1: c_int = 709; -pub const NID_secp160r2: c_int = 710; -pub const NID_secp192k1: c_int = 711; -pub const NID_secp224k1: c_int = 712; -pub const NID_secp224r1: c_int = 713; -pub const NID_secp256k1: c_int = 714; -pub const NID_secp384r1: c_int = 715; -pub const NID_secp521r1: c_int = 716; -pub const NID_sect113r1: c_int = 717; -pub const NID_sect113r2: c_int = 718; -pub const NID_sect131r1: c_int = 719; -pub const NID_sect131r2: c_int = 720; -pub const NID_sect163k1: c_int = 721; -pub const NID_sect163r1: c_int = 722; -pub const NID_sect163r2: c_int = 723; -pub const NID_sect193r1: c_int = 724; -pub const NID_sect193r2: c_int = 725; -pub const NID_sect233k1: c_int = 726; -pub const NID_sect233r1: c_int = 727; -pub const NID_sect239k1: c_int = 728; -pub const NID_sect283k1: c_int = 729; -pub const NID_sect283r1: c_int = 730; -pub const NID_sect409k1: c_int = 731; -pub const NID_sect409r1: c_int = 732; -pub const NID_sect571k1: c_int = 733; -pub const NID_sect571r1: c_int = 734; -pub const NID_wap_wsg_idm_ecid_wtls1: c_int = 735; -pub const NID_wap_wsg_idm_ecid_wtls3: c_int = 736; -pub const NID_wap_wsg_idm_ecid_wtls4: c_int = 737; -pub const NID_wap_wsg_idm_ecid_wtls5: c_int = 738; -pub const NID_wap_wsg_idm_ecid_wtls6: c_int = 739; -pub const NID_wap_wsg_idm_ecid_wtls7: c_int = 740; -pub const NID_wap_wsg_idm_ecid_wtls8: c_int = 741; -pub const NID_wap_wsg_idm_ecid_wtls9: c_int = 742; -pub const NID_wap_wsg_idm_ecid_wtls10: c_int = 743; -pub const NID_wap_wsg_idm_ecid_wtls11: c_int = 744; -pub const NID_wap_wsg_idm_ecid_wtls12: c_int = 745; -pub const NID_cast5_cbc: c_int = 108; -pub const NID_cast5_ecb: c_int = 109; -pub const NID_cast5_cfb64: c_int = 110; -pub const NID_cast5_ofb64: c_int = 111; -pub const NID_pbeWithMD5AndCast5_CBC: c_int = 112; -pub const NID_id_PasswordBasedMAC: c_int = 782; -pub const NID_id_DHBasedMac: c_int = 783; -pub const NID_rsadsi: c_int = 1; -pub const NID_pkcs: c_int = 2; -pub const NID_pkcs1: c_int = 186; -pub const NID_rsaEncryption: c_int = 6; -pub const NID_md2WithRSAEncryption: c_int = 7; -pub const NID_md4WithRSAEncryption: c_int = 396; -pub const NID_md5WithRSAEncryption: c_int = 8; -pub const NID_sha1WithRSAEncryption: c_int = 65; -pub const NID_rsaesOaep: c_int = 919; -pub const NID_mgf1: c_int = 911; -pub const NID_rsassaPss: c_int = 912; -pub const NID_sha256WithRSAEncryption: c_int = 668; -pub const NID_sha384WithRSAEncryption: c_int = 669; -pub const NID_sha512WithRSAEncryption: c_int = 670; -pub const NID_sha224WithRSAEncryption: c_int = 671; -pub const NID_pkcs3: c_int = 27; -pub const NID_dhKeyAgreement: c_int = 28; -pub const NID_pkcs5: c_int = 187; -pub const NID_pbeWithMD2AndDES_CBC: c_int = 9; -pub const NID_pbeWithMD5AndDES_CBC: c_int = 10; -pub const NID_pbeWithMD2AndRC2_CBC: c_int = 168; -pub const NID_pbeWithMD5AndRC2_CBC: c_int = 169; -pub const NID_pbeWithSHA1AndDES_CBC: c_int = 170; -pub const NID_pbeWithSHA1AndRC2_CBC: c_int = 68; -pub const NID_id_pbkdf2: c_int = 69; -pub const NID_pbes2: c_int = 161; -pub const NID_pbmac1: c_int = 162; -pub const NID_pkcs7: c_int = 20; -pub const NID_pkcs7_data: c_int = 21; -pub const NID_pkcs7_signed: c_int = 22; -pub const NID_pkcs7_enveloped: c_int = 23; -pub const NID_pkcs7_signedAndEnveloped: c_int = 24; -pub const NID_pkcs7_digest: c_int = 25; -pub const NID_pkcs7_encrypted: c_int = 26; -pub const NID_pkcs9: c_int = 47; -pub const NID_pkcs9_emailAddress: c_int = 48; -pub const NID_pkcs9_unstructuredName: c_int = 49; -pub const NID_pkcs9_contentType: c_int = 50; -pub const NID_pkcs9_messageDigest: c_int = 51; -pub const NID_pkcs9_signingTime: c_int = 52; -pub const NID_pkcs9_countersignature: c_int = 53; -pub const NID_pkcs9_challengePassword: c_int = 54; -pub const NID_pkcs9_unstructuredAddress: c_int = 55; -pub const NID_pkcs9_extCertAttributes: c_int = 56; -pub const NID_ext_req: c_int = 172; -pub const NID_SMIMECapabilities: c_int = 167; -pub const NID_SMIME: c_int = 188; -pub const NID_id_smime_mod: c_int = 189; -pub const NID_id_smime_ct: c_int = 190; -pub const NID_id_smime_aa: c_int = 191; -pub const NID_id_smime_alg: c_int = 192; -pub const NID_id_smime_cd: c_int = 193; -pub const NID_id_smime_spq: c_int = 194; -pub const NID_id_smime_cti: c_int = 195; -pub const NID_id_smime_mod_cms: c_int = 196; -pub const NID_id_smime_mod_ess: c_int = 197; -pub const NID_id_smime_mod_oid: c_int = 198; -pub const NID_id_smime_mod_msg_v3: c_int = 199; -pub const NID_id_smime_mod_ets_eSignature_88: c_int = 200; -pub const NID_id_smime_mod_ets_eSignature_97: c_int = 201; -pub const NID_id_smime_mod_ets_eSigPolicy_88: c_int = 202; -pub const NID_id_smime_mod_ets_eSigPolicy_97: c_int = 203; -pub const NID_id_smime_ct_receipt: c_int = 204; -pub const NID_id_smime_ct_authData: c_int = 205; -pub const NID_id_smime_ct_publishCert: c_int = 206; -pub const NID_id_smime_ct_TSTInfo: c_int = 207; -pub const NID_id_smime_ct_TDTInfo: c_int = 208; -pub const NID_id_smime_ct_contentInfo: c_int = 209; -pub const NID_id_smime_ct_DVCSRequestData: c_int = 210; -pub const NID_id_smime_ct_DVCSResponseData: c_int = 211; -pub const NID_id_smime_ct_compressedData: c_int = 786; -pub const NID_id_ct_asciiTextWithCRLF: c_int = 787; -pub const NID_id_smime_aa_receiptRequest: c_int = 212; -pub const NID_id_smime_aa_securityLabel: c_int = 213; -pub const NID_id_smime_aa_mlExpandHistory: c_int = 214; -pub const NID_id_smime_aa_contentHint: c_int = 215; -pub const NID_id_smime_aa_msgSigDigest: c_int = 216; -pub const NID_id_smime_aa_encapContentType: c_int = 217; -pub const NID_id_smime_aa_contentIdentifier: c_int = 218; -pub const NID_id_smime_aa_macValue: c_int = 219; -pub const NID_id_smime_aa_equivalentLabels: c_int = 220; -pub const NID_id_smime_aa_contentReference: c_int = 221; -pub const NID_id_smime_aa_encrypKeyPref: c_int = 222; -pub const NID_id_smime_aa_signingCertificate: c_int = 223; -pub const NID_id_smime_aa_smimeEncryptCerts: c_int = 224; -pub const NID_id_smime_aa_timeStampToken: c_int = 225; -pub const NID_id_smime_aa_ets_sigPolicyId: c_int = 226; -pub const NID_id_smime_aa_ets_commitmentType: c_int = 227; -pub const NID_id_smime_aa_ets_signerLocation: c_int = 228; -pub const NID_id_smime_aa_ets_signerAttr: c_int = 229; -pub const NID_id_smime_aa_ets_otherSigCert: c_int = 230; -pub const NID_id_smime_aa_ets_contentTimestamp: c_int = 231; -pub const NID_id_smime_aa_ets_CertificateRefs: c_int = 232; -pub const NID_id_smime_aa_ets_RevocationRefs: c_int = 233; -pub const NID_id_smime_aa_ets_certValues: c_int = 234; -pub const NID_id_smime_aa_ets_revocationValues: c_int = 235; -pub const NID_id_smime_aa_ets_escTimeStamp: c_int = 236; -pub const NID_id_smime_aa_ets_certCRLTimestamp: c_int = 237; -pub const NID_id_smime_aa_ets_archiveTimeStamp: c_int = 238; -pub const NID_id_smime_aa_signatureType: c_int = 239; -pub const NID_id_smime_aa_dvcs_dvc: c_int = 240; -pub const NID_id_smime_alg_ESDHwith3DES: c_int = 241; -pub const NID_id_smime_alg_ESDHwithRC2: c_int = 242; -pub const NID_id_smime_alg_3DESwrap: c_int = 243; -pub const NID_id_smime_alg_RC2wrap: c_int = 244; -pub const NID_id_smime_alg_ESDH: c_int = 245; -pub const NID_id_smime_alg_CMS3DESwrap: c_int = 246; -pub const NID_id_smime_alg_CMSRC2wrap: c_int = 247; -pub const NID_id_alg_PWRI_KEK: c_int = 893; -pub const NID_id_smime_cd_ldap: c_int = 248; -pub const NID_id_smime_spq_ets_sqt_uri: c_int = 249; -pub const NID_id_smime_spq_ets_sqt_unotice: c_int = 250; -pub const NID_id_smime_cti_ets_proofOfOrigin: c_int = 251; -pub const NID_id_smime_cti_ets_proofOfReceipt: c_int = 252; -pub const NID_id_smime_cti_ets_proofOfDelivery: c_int = 253; -pub const NID_id_smime_cti_ets_proofOfSender: c_int = 254; -pub const NID_id_smime_cti_ets_proofOfApproval: c_int = 255; -pub const NID_id_smime_cti_ets_proofOfCreation: c_int = 256; -pub const NID_friendlyName: c_int = 156; -pub const NID_localKeyID: c_int = 157; -pub const NID_ms_csp_name: c_int = 417; -pub const NID_LocalKeySet: c_int = 856; -pub const NID_x509Certificate: c_int = 158; -pub const NID_sdsiCertificate: c_int = 159; -pub const NID_x509Crl: c_int = 160; -pub const NID_pbe_WithSHA1And128BitRC4: c_int = 144; -pub const NID_pbe_WithSHA1And40BitRC4: c_int = 145; -pub const NID_pbe_WithSHA1And3_Key_TripleDES_CBC: c_int = 146; -pub const NID_pbe_WithSHA1And2_Key_TripleDES_CBC: c_int = 147; -pub const NID_pbe_WithSHA1And128BitRC2_CBC: c_int = 148; -pub const NID_pbe_WithSHA1And40BitRC2_CBC: c_int = 149; -pub const NID_keyBag: c_int = 150; -pub const NID_pkcs8ShroudedKeyBag: c_int = 151; -pub const NID_certBag: c_int = 152; -pub const NID_crlBag: c_int = 153; -pub const NID_secretBag: c_int = 154; -pub const NID_safeContentsBag: c_int = 155; -pub const NID_md2: c_int = 3; -pub const NID_md4: c_int = 257; -pub const NID_md5: c_int = 4; -pub const NID_md5_sha1: c_int = 114; -pub const NID_hmacWithMD5: c_int = 797; -pub const NID_hmacWithSHA1: c_int = 163; -pub const NID_hmacWithSHA224: c_int = 798; -pub const NID_hmacWithSHA256: c_int = 799; -pub const NID_hmacWithSHA384: c_int = 800; -pub const NID_hmacWithSHA512: c_int = 801; -pub const NID_rc2_cbc: c_int = 37; -pub const NID_rc2_ecb: c_int = 38; -pub const NID_rc2_cfb64: c_int = 39; -pub const NID_rc2_ofb64: c_int = 40; -pub const NID_rc2_40_cbc: c_int = 98; -pub const NID_rc2_64_cbc: c_int = 166; -pub const NID_rc4: c_int = 5; -pub const NID_rc4_40: c_int = 97; -pub const NID_des_ede3_cbc: c_int = 44; -pub const NID_rc5_cbc: c_int = 120; -pub const NID_rc5_ecb: c_int = 121; -pub const NID_rc5_cfb64: c_int = 122; -pub const NID_rc5_ofb64: c_int = 123; -pub const NID_ms_ext_req: c_int = 171; -pub const NID_ms_code_ind: c_int = 134; -pub const NID_ms_code_com: c_int = 135; -pub const NID_ms_ctl_sign: c_int = 136; -pub const NID_ms_sgc: c_int = 137; -pub const NID_ms_efs: c_int = 138; -pub const NID_ms_smartcard_login: c_int = 648; -pub const NID_ms_upn: c_int = 649; -pub const NID_idea_cbc: c_int = 34; -pub const NID_idea_ecb: c_int = 36; -pub const NID_idea_cfb64: c_int = 35; -pub const NID_idea_ofb64: c_int = 46; -pub const NID_bf_cbc: c_int = 91; -pub const NID_bf_ecb: c_int = 92; -pub const NID_bf_cfb64: c_int = 93; -pub const NID_bf_ofb64: c_int = 94; -pub const NID_id_pkix: c_int = 127; -pub const NID_id_pkix_mod: c_int = 258; -pub const NID_id_pe: c_int = 175; -pub const NID_id_qt: c_int = 259; -pub const NID_id_kp: c_int = 128; -pub const NID_id_it: c_int = 260; -pub const NID_id_pkip: c_int = 261; -pub const NID_id_alg: c_int = 262; -pub const NID_id_cmc: c_int = 263; -pub const NID_id_on: c_int = 264; -pub const NID_id_pda: c_int = 265; -pub const NID_id_aca: c_int = 266; -pub const NID_id_qcs: c_int = 267; -pub const NID_id_cct: c_int = 268; -pub const NID_id_ppl: c_int = 662; -pub const NID_id_ad: c_int = 176; -pub const NID_id_pkix1_explicit_88: c_int = 269; -pub const NID_id_pkix1_implicit_88: c_int = 270; -pub const NID_id_pkix1_explicit_93: c_int = 271; -pub const NID_id_pkix1_implicit_93: c_int = 272; -pub const NID_id_mod_crmf: c_int = 273; -pub const NID_id_mod_cmc: c_int = 274; -pub const NID_id_mod_kea_profile_88: c_int = 275; -pub const NID_id_mod_kea_profile_93: c_int = 276; -pub const NID_id_mod_cmp: c_int = 277; -pub const NID_id_mod_qualified_cert_88: c_int = 278; -pub const NID_id_mod_qualified_cert_93: c_int = 279; -pub const NID_id_mod_attribute_cert: c_int = 280; -pub const NID_id_mod_timestamp_protocol: c_int = 281; -pub const NID_id_mod_ocsp: c_int = 282; -pub const NID_id_mod_dvcs: c_int = 283; -pub const NID_id_mod_cmp2000: c_int = 284; -pub const NID_info_access: c_int = 177; -pub const NID_biometricInfo: c_int = 285; -pub const NID_qcStatements: c_int = 286; -pub const NID_ac_auditEntity: c_int = 287; -pub const NID_ac_targeting: c_int = 288; -pub const NID_aaControls: c_int = 289; -pub const NID_sbgp_ipAddrBlock: c_int = 290; -pub const NID_sbgp_autonomousSysNum: c_int = 291; -pub const NID_sbgp_routerIdentifier: c_int = 292; -pub const NID_ac_proxying: c_int = 397; -pub const NID_sinfo_access: c_int = 398; -pub const NID_proxyCertInfo: c_int = 663; -pub const NID_id_qt_cps: c_int = 164; -pub const NID_id_qt_unotice: c_int = 165; -pub const NID_textNotice: c_int = 293; -pub const NID_server_auth: c_int = 129; -pub const NID_client_auth: c_int = 130; -pub const NID_code_sign: c_int = 131; -pub const NID_email_protect: c_int = 132; -pub const NID_ipsecEndSystem: c_int = 294; -pub const NID_ipsecTunnel: c_int = 295; -pub const NID_ipsecUser: c_int = 296; -pub const NID_time_stamp: c_int = 133; -pub const NID_OCSP_sign: c_int = 180; -pub const NID_dvcs: c_int = 297; -pub const NID_id_it_caProtEncCert: c_int = 298; -pub const NID_id_it_signKeyPairTypes: c_int = 299; -pub const NID_id_it_encKeyPairTypes: c_int = 300; -pub const NID_id_it_preferredSymmAlg: c_int = 301; -pub const NID_id_it_caKeyUpdateInfo: c_int = 302; -pub const NID_id_it_currentCRL: c_int = 303; -pub const NID_id_it_unsupportedOIDs: c_int = 304; -pub const NID_id_it_subscriptionRequest: c_int = 305; -pub const NID_id_it_subscriptionResponse: c_int = 306; -pub const NID_id_it_keyPairParamReq: c_int = 307; -pub const NID_id_it_keyPairParamRep: c_int = 308; -pub const NID_id_it_revPassphrase: c_int = 309; -pub const NID_id_it_implicitConfirm: c_int = 310; -pub const NID_id_it_confirmWaitTime: c_int = 311; -pub const NID_id_it_origPKIMessage: c_int = 312; -pub const NID_id_it_suppLangTags: c_int = 784; -pub const NID_id_regCtrl: c_int = 313; -pub const NID_id_regInfo: c_int = 314; -pub const NID_id_regCtrl_regToken: c_int = 315; -pub const NID_id_regCtrl_authenticator: c_int = 316; -pub const NID_id_regCtrl_pkiPublicationInfo: c_int = 317; -pub const NID_id_regCtrl_pkiArchiveOptions: c_int = 318; -pub const NID_id_regCtrl_oldCertID: c_int = 319; -pub const NID_id_regCtrl_protocolEncrKey: c_int = 320; -pub const NID_id_regInfo_utf8Pairs: c_int = 321; -pub const NID_id_regInfo_certReq: c_int = 322; -pub const NID_id_alg_des40: c_int = 323; -pub const NID_id_alg_noSignature: c_int = 324; -pub const NID_id_alg_dh_sig_hmac_sha1: c_int = 325; -pub const NID_id_alg_dh_pop: c_int = 326; -pub const NID_id_cmc_statusInfo: c_int = 327; -pub const NID_id_cmc_identification: c_int = 328; -pub const NID_id_cmc_identityProof: c_int = 329; -pub const NID_id_cmc_dataReturn: c_int = 330; -pub const NID_id_cmc_transactionId: c_int = 331; -pub const NID_id_cmc_senderNonce: c_int = 332; -pub const NID_id_cmc_recipientNonce: c_int = 333; -pub const NID_id_cmc_addExtensions: c_int = 334; -pub const NID_id_cmc_encryptedPOP: c_int = 335; -pub const NID_id_cmc_decryptedPOP: c_int = 336; -pub const NID_id_cmc_lraPOPWitness: c_int = 337; -pub const NID_id_cmc_getCert: c_int = 338; -pub const NID_id_cmc_getCRL: c_int = 339; -pub const NID_id_cmc_revokeRequest: c_int = 340; -pub const NID_id_cmc_regInfo: c_int = 341; -pub const NID_id_cmc_responseInfo: c_int = 342; -pub const NID_id_cmc_queryPending: c_int = 343; -pub const NID_id_cmc_popLinkRandom: c_int = 344; -pub const NID_id_cmc_popLinkWitness: c_int = 345; -pub const NID_id_cmc_confirmCertAcceptance: c_int = 346; -pub const NID_id_on_personalData: c_int = 347; -pub const NID_id_on_permanentIdentifier: c_int = 858; -pub const NID_id_pda_dateOfBirth: c_int = 348; -pub const NID_id_pda_placeOfBirth: c_int = 349; -pub const NID_id_pda_gender: c_int = 351; -pub const NID_id_pda_countryOfCitizenship: c_int = 352; -pub const NID_id_pda_countryOfResidence: c_int = 353; -pub const NID_id_aca_authenticationInfo: c_int = 354; -pub const NID_id_aca_accessIdentity: c_int = 355; -pub const NID_id_aca_chargingIdentity: c_int = 356; -pub const NID_id_aca_group: c_int = 357; -pub const NID_id_aca_role: c_int = 358; -pub const NID_id_aca_encAttrs: c_int = 399; -pub const NID_id_qcs_pkixQCSyntax_v1: c_int = 359; -pub const NID_id_cct_crs: c_int = 360; -pub const NID_id_cct_PKIData: c_int = 361; -pub const NID_id_cct_PKIResponse: c_int = 362; -pub const NID_id_ppl_anyLanguage: c_int = 664; -pub const NID_id_ppl_inheritAll: c_int = 665; -pub const NID_Independent: c_int = 667; -pub const NID_ad_OCSP: c_int = 178; -pub const NID_ad_ca_issuers: c_int = 179; -pub const NID_ad_timeStamping: c_int = 363; -pub const NID_ad_dvcs: c_int = 364; -pub const NID_caRepository: c_int = 785; -pub const NID_id_pkix_OCSP_basic: c_int = 365; -pub const NID_id_pkix_OCSP_Nonce: c_int = 366; -pub const NID_id_pkix_OCSP_CrlID: c_int = 367; -pub const NID_id_pkix_OCSP_acceptableResponses: c_int = 368; -pub const NID_id_pkix_OCSP_noCheck: c_int = 369; -pub const NID_id_pkix_OCSP_archiveCutoff: c_int = 370; -pub const NID_id_pkix_OCSP_serviceLocator: c_int = 371; -pub const NID_id_pkix_OCSP_extendedStatus: c_int = 372; -pub const NID_id_pkix_OCSP_valid: c_int = 373; -pub const NID_id_pkix_OCSP_path: c_int = 374; -pub const NID_id_pkix_OCSP_trustRoot: c_int = 375; -pub const NID_algorithm: c_int = 376; -pub const NID_md5WithRSA: c_int = 104; -pub const NID_des_ecb: c_int = 29; -pub const NID_des_cbc: c_int = 31; -pub const NID_des_ofb64: c_int = 45; -pub const NID_des_cfb64: c_int = 30; -pub const NID_rsaSignature: c_int = 377; -pub const NID_dsa_2: c_int = 67; -pub const NID_dsaWithSHA: c_int = 66; -pub const NID_shaWithRSAEncryption: c_int = 42; -pub const NID_des_ede_ecb: c_int = 32; -pub const NID_des_ede3_ecb: c_int = 33; -pub const NID_des_ede_cbc: c_int = 43; -pub const NID_des_ede_cfb64: c_int = 60; -pub const NID_des_ede3_cfb64: c_int = 61; -pub const NID_des_ede_ofb64: c_int = 62; -pub const NID_des_ede3_ofb64: c_int = 63; -pub const NID_desx_cbc: c_int = 80; -pub const NID_sha: c_int = 41; -pub const NID_sha1: c_int = 64; -pub const NID_dsaWithSHA1_2: c_int = 70; -pub const NID_sha1WithRSA: c_int = 115; -pub const NID_ripemd160: c_int = 117; -pub const NID_ripemd160WithRSA: c_int = 119; -pub const NID_sxnet: c_int = 143; -pub const NID_X500: c_int = 11; -pub const NID_X509: c_int = 12; -pub const NID_commonName: c_int = 13; -pub const NID_surname: c_int = 100; -pub const NID_serialNumber: c_int = 105; -pub const NID_countryName: c_int = 14; -pub const NID_localityName: c_int = 15; -pub const NID_stateOrProvinceName: c_int = 16; -pub const NID_streetAddress: c_int = 660; -pub const NID_organizationName: c_int = 17; -pub const NID_organizationalUnitName: c_int = 18; -pub const NID_title: c_int = 106; -pub const NID_description: c_int = 107; -pub const NID_searchGuide: c_int = 859; -pub const NID_businessCategory: c_int = 860; -pub const NID_postalAddress: c_int = 861; -pub const NID_postalCode: c_int = 661; -pub const NID_postOfficeBox: c_int = 862; -pub const NID_physicalDeliveryOfficeName: c_int = 863; -pub const NID_telephoneNumber: c_int = 864; -pub const NID_telexNumber: c_int = 865; -pub const NID_teletexTerminalIdentifier: c_int = 866; -pub const NID_facsimileTelephoneNumber: c_int = 867; -pub const NID_x121Address: c_int = 868; -pub const NID_internationaliSDNNumber: c_int = 869; -pub const NID_registeredAddress: c_int = 870; -pub const NID_destinationIndicator: c_int = 871; -pub const NID_preferredDeliveryMethod: c_int = 872; -pub const NID_presentationAddress: c_int = 873; -pub const NID_supportedApplicationContext: c_int = 874; -pub const NID_member: c_int = 875; -pub const NID_owner: c_int = 876; -pub const NID_roleOccupant: c_int = 877; -pub const NID_seeAlso: c_int = 878; -pub const NID_userPassword: c_int = 879; -pub const NID_userCertificate: c_int = 880; -pub const NID_cACertificate: c_int = 881; -pub const NID_authorityRevocationList: c_int = 882; -pub const NID_certificateRevocationList: c_int = 883; -pub const NID_crossCertificatePair: c_int = 884; -pub const NID_name: c_int = 173; -pub const NID_givenName: c_int = 99; -pub const NID_initials: c_int = 101; -pub const NID_generationQualifier: c_int = 509; -pub const NID_x500UniqueIdentifier: c_int = 503; -pub const NID_dnQualifier: c_int = 174; -pub const NID_enhancedSearchGuide: c_int = 885; -pub const NID_protocolInformation: c_int = 886; -pub const NID_distinguishedName: c_int = 887; -pub const NID_uniqueMember: c_int = 888; -pub const NID_houseIdentifier: c_int = 889; -pub const NID_supportedAlgorithms: c_int = 890; -pub const NID_deltaRevocationList: c_int = 891; -pub const NID_dmdName: c_int = 892; -pub const NID_pseudonym: c_int = 510; -pub const NID_role: c_int = 400; -pub const NID_X500algorithms: c_int = 378; -pub const NID_rsa: c_int = 19; -pub const NID_mdc2WithRSA: c_int = 96; -pub const NID_mdc2: c_int = 95; -pub const NID_id_ce: c_int = 81; -pub const NID_subject_directory_attributes: c_int = 769; -pub const NID_subject_key_identifier: c_int = 82; -pub const NID_key_usage: c_int = 83; -pub const NID_private_key_usage_period: c_int = 84; -pub const NID_subject_alt_name: c_int = 85; -pub const NID_issuer_alt_name: c_int = 86; -pub const NID_basic_constraints: c_int = 87; -pub const NID_crl_number: c_int = 88; -pub const NID_crl_reason: c_int = 141; -pub const NID_invalidity_date: c_int = 142; -pub const NID_delta_crl: c_int = 140; -pub const NID_issuing_distribution_point: c_int = 770; -pub const NID_certificate_issuer: c_int = 771; -pub const NID_name_constraints: c_int = 666; -pub const NID_crl_distribution_points: c_int = 103; -pub const NID_certificate_policies: c_int = 89; -pub const NID_any_policy: c_int = 746; -pub const NID_policy_mappings: c_int = 747; -pub const NID_authority_key_identifier: c_int = 90; -pub const NID_policy_constraints: c_int = 401; -pub const NID_ext_key_usage: c_int = 126; -pub const NID_freshest_crl: c_int = 857; -pub const NID_inhibit_any_policy: c_int = 748; -pub const NID_target_information: c_int = 402; -pub const NID_no_rev_avail: c_int = 403; -pub const NID_anyExtendedKeyUsage: c_int = 910; -pub const NID_netscape: c_int = 57; -pub const NID_netscape_cert_extension: c_int = 58; -pub const NID_netscape_data_type: c_int = 59; -pub const NID_netscape_cert_type: c_int = 71; -pub const NID_netscape_base_url: c_int = 72; -pub const NID_netscape_revocation_url: c_int = 73; -pub const NID_netscape_ca_revocation_url: c_int = 74; -pub const NID_netscape_renewal_url: c_int = 75; -pub const NID_netscape_ca_policy_url: c_int = 76; -pub const NID_netscape_ssl_server_name: c_int = 77; -pub const NID_netscape_comment: c_int = 78; -pub const NID_netscape_cert_sequence: c_int = 79; -pub const NID_ns_sgc: c_int = 139; -pub const NID_org: c_int = 379; -pub const NID_dod: c_int = 380; -pub const NID_iana: c_int = 381; -pub const NID_Directory: c_int = 382; -pub const NID_Management: c_int = 383; -pub const NID_Experimental: c_int = 384; -pub const NID_Private: c_int = 385; -pub const NID_Security: c_int = 386; -pub const NID_SNMPv2: c_int = 387; -pub const NID_Mail: c_int = 388; -pub const NID_Enterprises: c_int = 389; -pub const NID_dcObject: c_int = 390; -pub const NID_mime_mhs: c_int = 504; -pub const NID_mime_mhs_headings: c_int = 505; -pub const NID_mime_mhs_bodies: c_int = 506; -pub const NID_id_hex_partial_message: c_int = 507; -pub const NID_id_hex_multipart_message: c_int = 508; -pub const NID_zlib_compression: c_int = 125; -pub const NID_aes_128_ecb: c_int = 418; -pub const NID_aes_128_cbc: c_int = 419; -pub const NID_aes_128_ofb128: c_int = 420; -pub const NID_aes_128_cfb128: c_int = 421; -pub const NID_id_aes128_wrap: c_int = 788; -pub const NID_aes_128_gcm: c_int = 895; -pub const NID_aes_128_ccm: c_int = 896; -pub const NID_id_aes128_wrap_pad: c_int = 897; -pub const NID_aes_192_ecb: c_int = 422; -pub const NID_aes_192_cbc: c_int = 423; -pub const NID_aes_192_ofb128: c_int = 424; -pub const NID_aes_192_cfb128: c_int = 425; -pub const NID_id_aes192_wrap: c_int = 789; -pub const NID_aes_192_gcm: c_int = 898; -pub const NID_aes_192_ccm: c_int = 899; -pub const NID_id_aes192_wrap_pad: c_int = 900; -pub const NID_aes_256_ecb: c_int = 426; -pub const NID_aes_256_cbc: c_int = 427; -pub const NID_aes_256_ofb128: c_int = 428; -pub const NID_aes_256_cfb128: c_int = 429; -pub const NID_id_aes256_wrap: c_int = 790; -pub const NID_aes_256_gcm: c_int = 901; -pub const NID_aes_256_ccm: c_int = 902; -pub const NID_id_aes256_wrap_pad: c_int = 903; -pub const NID_aes_128_cfb1: c_int = 650; -pub const NID_aes_192_cfb1: c_int = 651; -pub const NID_aes_256_cfb1: c_int = 652; -pub const NID_aes_128_cfb8: c_int = 653; -pub const NID_aes_192_cfb8: c_int = 654; -pub const NID_aes_256_cfb8: c_int = 655; -pub const NID_aes_128_ctr: c_int = 904; -pub const NID_aes_192_ctr: c_int = 905; -pub const NID_aes_256_ctr: c_int = 906; -pub const NID_aes_128_xts: c_int = 913; -pub const NID_aes_256_xts: c_int = 914; -pub const NID_des_cfb1: c_int = 656; -pub const NID_des_cfb8: c_int = 657; -pub const NID_des_ede3_cfb1: c_int = 658; -pub const NID_des_ede3_cfb8: c_int = 659; -pub const NID_sha256: c_int = 672; -pub const NID_sha384: c_int = 673; -pub const NID_sha512: c_int = 674; -pub const NID_sha224: c_int = 675; -pub const NID_dsa_with_SHA224: c_int = 802; -pub const NID_dsa_with_SHA256: c_int = 803; -pub const NID_hold_instruction_code: c_int = 430; -pub const NID_hold_instruction_none: c_int = 431; -pub const NID_hold_instruction_call_issuer: c_int = 432; -pub const NID_hold_instruction_reject: c_int = 433; -pub const NID_data: c_int = 434; -pub const NID_pss: c_int = 435; -pub const NID_ucl: c_int = 436; -pub const NID_pilot: c_int = 437; -pub const NID_pilotAttributeType: c_int = 438; -pub const NID_pilotAttributeSyntax: c_int = 439; -pub const NID_pilotObjectClass: c_int = 440; -pub const NID_pilotGroups: c_int = 441; -pub const NID_iA5StringSyntax: c_int = 442; -pub const NID_caseIgnoreIA5StringSyntax: c_int = 443; -pub const NID_pilotObject: c_int = 444; -pub const NID_pilotPerson: c_int = 445; -pub const NID_account: c_int = 446; -pub const NID_document: c_int = 447; -pub const NID_room: c_int = 448; -pub const NID_documentSeries: c_int = 449; -pub const NID_Domain: c_int = 392; -pub const NID_rFC822localPart: c_int = 450; -pub const NID_dNSDomain: c_int = 451; -pub const NID_domainRelatedObject: c_int = 452; -pub const NID_friendlyCountry: c_int = 453; -pub const NID_simpleSecurityObject: c_int = 454; -pub const NID_pilotOrganization: c_int = 455; -pub const NID_pilotDSA: c_int = 456; -pub const NID_qualityLabelledData: c_int = 457; -pub const NID_userId: c_int = 458; -pub const NID_textEncodedORAddress: c_int = 459; -pub const NID_rfc822Mailbox: c_int = 460; -pub const NID_info: c_int = 461; -pub const NID_favouriteDrink: c_int = 462; -pub const NID_roomNumber: c_int = 463; -pub const NID_photo: c_int = 464; -pub const NID_userClass: c_int = 465; -pub const NID_host: c_int = 466; -pub const NID_manager: c_int = 467; -pub const NID_documentIdentifier: c_int = 468; -pub const NID_documentTitle: c_int = 469; -pub const NID_documentVersion: c_int = 470; -pub const NID_documentAuthor: c_int = 471; -pub const NID_documentLocation: c_int = 472; -pub const NID_homeTelephoneNumber: c_int = 473; -pub const NID_secretary: c_int = 474; -pub const NID_otherMailbox: c_int = 475; -pub const NID_lastModifiedTime: c_int = 476; -pub const NID_lastModifiedBy: c_int = 477; -pub const NID_domainComponent: c_int = 391; -pub const NID_aRecord: c_int = 478; -pub const NID_pilotAttributeType27: c_int = 479; -pub const NID_mXRecord: c_int = 480; -pub const NID_nSRecord: c_int = 481; -pub const NID_sOARecord: c_int = 482; -pub const NID_cNAMERecord: c_int = 483; -pub const NID_associatedDomain: c_int = 484; -pub const NID_associatedName: c_int = 485; -pub const NID_homePostalAddress: c_int = 486; -pub const NID_personalTitle: c_int = 487; -pub const NID_mobileTelephoneNumber: c_int = 488; -pub const NID_pagerTelephoneNumber: c_int = 489; -pub const NID_friendlyCountryName: c_int = 490; -pub const NID_organizationalStatus: c_int = 491; -pub const NID_janetMailbox: c_int = 492; -pub const NID_mailPreferenceOption: c_int = 493; -pub const NID_buildingName: c_int = 494; -pub const NID_dSAQuality: c_int = 495; -pub const NID_singleLevelQuality: c_int = 496; -pub const NID_subtreeMinimumQuality: c_int = 497; -pub const NID_subtreeMaximumQuality: c_int = 498; -pub const NID_personalSignature: c_int = 499; -pub const NID_dITRedirect: c_int = 500; -pub const NID_audio: c_int = 501; -pub const NID_documentPublisher: c_int = 502; -pub const NID_id_set: c_int = 512; -pub const NID_set_ctype: c_int = 513; -pub const NID_set_msgExt: c_int = 514; -pub const NID_set_attr: c_int = 515; -pub const NID_set_policy: c_int = 516; -pub const NID_set_certExt: c_int = 517; -pub const NID_set_brand: c_int = 518; -pub const NID_setct_PANData: c_int = 519; -pub const NID_setct_PANToken: c_int = 520; -pub const NID_setct_PANOnly: c_int = 521; -pub const NID_setct_OIData: c_int = 522; -pub const NID_setct_PI: c_int = 523; -pub const NID_setct_PIData: c_int = 524; -pub const NID_setct_PIDataUnsigned: c_int = 525; -pub const NID_setct_HODInput: c_int = 526; -pub const NID_setct_AuthResBaggage: c_int = 527; -pub const NID_setct_AuthRevReqBaggage: c_int = 528; -pub const NID_setct_AuthRevResBaggage: c_int = 529; -pub const NID_setct_CapTokenSeq: c_int = 530; -pub const NID_setct_PInitResData: c_int = 531; -pub const NID_setct_PI_TBS: c_int = 532; -pub const NID_setct_PResData: c_int = 533; -pub const NID_setct_AuthReqTBS: c_int = 534; -pub const NID_setct_AuthResTBS: c_int = 535; -pub const NID_setct_AuthResTBSX: c_int = 536; -pub const NID_setct_AuthTokenTBS: c_int = 537; -pub const NID_setct_CapTokenData: c_int = 538; -pub const NID_setct_CapTokenTBS: c_int = 539; -pub const NID_setct_AcqCardCodeMsg: c_int = 540; -pub const NID_setct_AuthRevReqTBS: c_int = 541; -pub const NID_setct_AuthRevResData: c_int = 542; -pub const NID_setct_AuthRevResTBS: c_int = 543; -pub const NID_setct_CapReqTBS: c_int = 544; -pub const NID_setct_CapReqTBSX: c_int = 545; -pub const NID_setct_CapResData: c_int = 546; -pub const NID_setct_CapRevReqTBS: c_int = 547; -pub const NID_setct_CapRevReqTBSX: c_int = 548; -pub const NID_setct_CapRevResData: c_int = 549; -pub const NID_setct_CredReqTBS: c_int = 550; -pub const NID_setct_CredReqTBSX: c_int = 551; -pub const NID_setct_CredResData: c_int = 552; -pub const NID_setct_CredRevReqTBS: c_int = 553; -pub const NID_setct_CredRevReqTBSX: c_int = 554; -pub const NID_setct_CredRevResData: c_int = 555; -pub const NID_setct_PCertReqData: c_int = 556; -pub const NID_setct_PCertResTBS: c_int = 557; -pub const NID_setct_BatchAdminReqData: c_int = 558; -pub const NID_setct_BatchAdminResData: c_int = 559; -pub const NID_setct_CardCInitResTBS: c_int = 560; -pub const NID_setct_MeAqCInitResTBS: c_int = 561; -pub const NID_setct_RegFormResTBS: c_int = 562; -pub const NID_setct_CertReqData: c_int = 563; -pub const NID_setct_CertReqTBS: c_int = 564; -pub const NID_setct_CertResData: c_int = 565; -pub const NID_setct_CertInqReqTBS: c_int = 566; -pub const NID_setct_ErrorTBS: c_int = 567; -pub const NID_setct_PIDualSignedTBE: c_int = 568; -pub const NID_setct_PIUnsignedTBE: c_int = 569; -pub const NID_setct_AuthReqTBE: c_int = 570; -pub const NID_setct_AuthResTBE: c_int = 571; -pub const NID_setct_AuthResTBEX: c_int = 572; -pub const NID_setct_AuthTokenTBE: c_int = 573; -pub const NID_setct_CapTokenTBE: c_int = 574; -pub const NID_setct_CapTokenTBEX: c_int = 575; -pub const NID_setct_AcqCardCodeMsgTBE: c_int = 576; -pub const NID_setct_AuthRevReqTBE: c_int = 577; -pub const NID_setct_AuthRevResTBE: c_int = 578; -pub const NID_setct_AuthRevResTBEB: c_int = 579; -pub const NID_setct_CapReqTBE: c_int = 580; -pub const NID_setct_CapReqTBEX: c_int = 581; -pub const NID_setct_CapResTBE: c_int = 582; -pub const NID_setct_CapRevReqTBE: c_int = 583; -pub const NID_setct_CapRevReqTBEX: c_int = 584; -pub const NID_setct_CapRevResTBE: c_int = 585; -pub const NID_setct_CredReqTBE: c_int = 586; -pub const NID_setct_CredReqTBEX: c_int = 587; -pub const NID_setct_CredResTBE: c_int = 588; -pub const NID_setct_CredRevReqTBE: c_int = 589; -pub const NID_setct_CredRevReqTBEX: c_int = 590; -pub const NID_setct_CredRevResTBE: c_int = 591; -pub const NID_setct_BatchAdminReqTBE: c_int = 592; -pub const NID_setct_BatchAdminResTBE: c_int = 593; -pub const NID_setct_RegFormReqTBE: c_int = 594; -pub const NID_setct_CertReqTBE: c_int = 595; -pub const NID_setct_CertReqTBEX: c_int = 596; -pub const NID_setct_CertResTBE: c_int = 597; -pub const NID_setct_CRLNotificationTBS: c_int = 598; -pub const NID_setct_CRLNotificationResTBS: c_int = 599; -pub const NID_setct_BCIDistributionTBS: c_int = 600; -pub const NID_setext_genCrypt: c_int = 601; -pub const NID_setext_miAuth: c_int = 602; -pub const NID_setext_pinSecure: c_int = 603; -pub const NID_setext_pinAny: c_int = 604; -pub const NID_setext_track2: c_int = 605; -pub const NID_setext_cv: c_int = 606; -pub const NID_set_policy_root: c_int = 607; -pub const NID_setCext_hashedRoot: c_int = 608; -pub const NID_setCext_certType: c_int = 609; -pub const NID_setCext_merchData: c_int = 610; -pub const NID_setCext_cCertRequired: c_int = 611; -pub const NID_setCext_tunneling: c_int = 612; -pub const NID_setCext_setExt: c_int = 613; -pub const NID_setCext_setQualf: c_int = 614; -pub const NID_setCext_PGWYcapabilities: c_int = 615; -pub const NID_setCext_TokenIdentifier: c_int = 616; -pub const NID_setCext_Track2Data: c_int = 617; -pub const NID_setCext_TokenType: c_int = 618; -pub const NID_setCext_IssuerCapabilities: c_int = 619; -pub const NID_setAttr_Cert: c_int = 620; -pub const NID_setAttr_PGWYcap: c_int = 621; -pub const NID_setAttr_TokenType: c_int = 622; -pub const NID_setAttr_IssCap: c_int = 623; -pub const NID_set_rootKeyThumb: c_int = 624; -pub const NID_set_addPolicy: c_int = 625; -pub const NID_setAttr_Token_EMV: c_int = 626; -pub const NID_setAttr_Token_B0Prime: c_int = 627; -pub const NID_setAttr_IssCap_CVM: c_int = 628; -pub const NID_setAttr_IssCap_T2: c_int = 629; -pub const NID_setAttr_IssCap_Sig: c_int = 630; -pub const NID_setAttr_GenCryptgrm: c_int = 631; -pub const NID_setAttr_T2Enc: c_int = 632; -pub const NID_setAttr_T2cleartxt: c_int = 633; -pub const NID_setAttr_TokICCsig: c_int = 634; -pub const NID_setAttr_SecDevSig: c_int = 635; -pub const NID_set_brand_IATA_ATA: c_int = 636; -pub const NID_set_brand_Diners: c_int = 637; -pub const NID_set_brand_AmericanExpress: c_int = 638; -pub const NID_set_brand_JCB: c_int = 639; -pub const NID_set_brand_Visa: c_int = 640; -pub const NID_set_brand_MasterCard: c_int = 641; -pub const NID_set_brand_Novus: c_int = 642; -pub const NID_des_cdmf: c_int = 643; -pub const NID_rsaOAEPEncryptionSET: c_int = 644; -pub const NID_ipsec3: c_int = 749; -pub const NID_ipsec4: c_int = 750; -pub const NID_whirlpool: c_int = 804; -pub const NID_cryptopro: c_int = 805; -pub const NID_cryptocom: c_int = 806; -pub const NID_id_GostR3411_94_with_GostR3410_2001: c_int = 807; -pub const NID_id_GostR3411_94_with_GostR3410_94: c_int = 808; -pub const NID_id_GostR3411_94: c_int = 809; -pub const NID_id_HMACGostR3411_94: c_int = 810; -pub const NID_id_GostR3410_2001: c_int = 811; -pub const NID_id_GostR3410_94: c_int = 812; -pub const NID_id_Gost28147_89: c_int = 813; -pub const NID_gost89_cnt: c_int = 814; -pub const NID_id_Gost28147_89_MAC: c_int = 815; -pub const NID_id_GostR3411_94_prf: c_int = 816; -pub const NID_id_GostR3410_2001DH: c_int = 817; -pub const NID_id_GostR3410_94DH: c_int = 818; -pub const NID_id_Gost28147_89_CryptoPro_KeyMeshing: c_int = 819; -pub const NID_id_Gost28147_89_None_KeyMeshing: c_int = 820; -pub const NID_id_GostR3411_94_TestParamSet: c_int = 821; -pub const NID_id_GostR3411_94_CryptoProParamSet: c_int = 822; -pub const NID_id_Gost28147_89_TestParamSet: c_int = 823; -pub const NID_id_Gost28147_89_CryptoPro_A_ParamSet: c_int = 824; -pub const NID_id_Gost28147_89_CryptoPro_B_ParamSet: c_int = 825; -pub const NID_id_Gost28147_89_CryptoPro_C_ParamSet: c_int = 826; -pub const NID_id_Gost28147_89_CryptoPro_D_ParamSet: c_int = 827; -pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet: c_int = 828; -pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet: c_int = 829; -pub const NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet: c_int = 830; -pub const NID_id_GostR3410_94_TestParamSet: c_int = 831; -pub const NID_id_GostR3410_94_CryptoPro_A_ParamSet: c_int = 832; -pub const NID_id_GostR3410_94_CryptoPro_B_ParamSet: c_int = 833; -pub const NID_id_GostR3410_94_CryptoPro_C_ParamSet: c_int = 834; -pub const NID_id_GostR3410_94_CryptoPro_D_ParamSet: c_int = 835; -pub const NID_id_GostR3410_94_CryptoPro_XchA_ParamSet: c_int = 836; -pub const NID_id_GostR3410_94_CryptoPro_XchB_ParamSet: c_int = 837; -pub const NID_id_GostR3410_94_CryptoPro_XchC_ParamSet: c_int = 838; -pub const NID_id_GostR3410_2001_TestParamSet: c_int = 839; -pub const NID_id_GostR3410_2001_CryptoPro_A_ParamSet: c_int = 840; -pub const NID_id_GostR3410_2001_CryptoPro_B_ParamSet: c_int = 841; -pub const NID_id_GostR3410_2001_CryptoPro_C_ParamSet: c_int = 842; -pub const NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet: c_int = 843; -pub const NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet: c_int = 844; -pub const NID_id_GostR3410_94_a: c_int = 845; -pub const NID_id_GostR3410_94_aBis: c_int = 846; -pub const NID_id_GostR3410_94_b: c_int = 847; -pub const NID_id_GostR3410_94_bBis: c_int = 848; -pub const NID_id_Gost28147_89_cc: c_int = 849; -pub const NID_id_GostR3410_94_cc: c_int = 850; -pub const NID_id_GostR3410_2001_cc: c_int = 851; -pub const NID_id_GostR3411_94_with_GostR3410_94_cc: c_int = 852; -pub const NID_id_GostR3411_94_with_GostR3410_2001_cc: c_int = 853; -pub const NID_id_GostR3410_2001_ParamSet_cc: c_int = 854; -pub const NID_camellia_128_cbc: c_int = 751; -pub const NID_camellia_192_cbc: c_int = 752; -pub const NID_camellia_256_cbc: c_int = 753; -pub const NID_id_camellia128_wrap: c_int = 907; -pub const NID_id_camellia192_wrap: c_int = 908; -pub const NID_id_camellia256_wrap: c_int = 909; -pub const NID_camellia_128_ecb: c_int = 754; -pub const NID_camellia_128_ofb128: c_int = 766; -pub const NID_camellia_128_cfb128: c_int = 757; -pub const NID_camellia_192_ecb: c_int = 755; -pub const NID_camellia_192_ofb128: c_int = 767; -pub const NID_camellia_192_cfb128: c_int = 758; -pub const NID_camellia_256_ecb: c_int = 756; -pub const NID_camellia_256_ofb128: c_int = 768; -pub const NID_camellia_256_cfb128: c_int = 759; -pub const NID_camellia_128_cfb1: c_int = 760; -pub const NID_camellia_192_cfb1: c_int = 761; -pub const NID_camellia_256_cfb1: c_int = 762; -pub const NID_camellia_128_cfb8: c_int = 763; -pub const NID_camellia_192_cfb8: c_int = 764; -pub const NID_camellia_256_cfb8: c_int = 765; -pub const NID_kisa: c_int = 773; -pub const NID_seed_ecb: c_int = 776; -pub const NID_seed_cbc: c_int = 777; -pub const NID_seed_cfb128: c_int = 779; -pub const NID_seed_ofb128: c_int = 778; -pub const NID_hmac: c_int = 855; -pub const NID_cmac: c_int = 894; -pub const NID_rc4_hmac_md5: c_int = 915; -pub const NID_aes_128_cbc_hmac_sha1: c_int = 916; -pub const NID_aes_192_cbc_hmac_sha1: c_int = 917; -pub const NID_aes_256_cbc_hmac_sha1: c_int = 918; - -pub const OCSP_NOCERTS: c_ulong = 0x1; -pub const OCSP_NOINTERN: c_ulong = 0x2; -pub const OCSP_NOSIGS: c_ulong = 0x4; -pub const OCSP_NOCHAIN: c_ulong = 0x8; -pub const OCSP_NOVERIFY: c_ulong = 0x10; -pub const OCSP_NOEXPLICIT: c_ulong = 0x20; -pub const OCSP_NOCASIGN: c_ulong = 0x40; -pub const OCSP_NODELEGATED: c_ulong = 0x80; -pub const OCSP_NOCHECKS: c_ulong = 0x100; -pub const OCSP_TRUSTOTHER: c_ulong = 0x200; -pub const OCSP_RESPID_KEY: c_ulong = 0x400; -pub const OCSP_NOTIME: c_ulong = 0x800; - -pub const V_OCSP_CERTSTATUS_GOOD: c_int = 0; -pub const V_OCSP_CERTSTATUS_REVOKED: c_int = 1; -pub const V_OCSP_CERTSTATUS_UNKNOWN: c_int = 2; - -pub const OCSP_REVOKED_STATUS_NOSTATUS: c_int = -1; -pub const OCSP_REVOKED_STATUS_UNSPECIFIED: c_int = 0; -pub const OCSP_REVOKED_STATUS_KEYCOMPROMISE: c_int = 1; -pub const OCSP_REVOKED_STATUS_CACOMPROMISE: c_int = 2; -pub const OCSP_REVOKED_STATUS_AFFILIATIONCHANGED: c_int = 3; -pub const OCSP_REVOKED_STATUS_SUPERSEDED: c_int = 4; -pub const OCSP_REVOKED_STATUS_CESSATIONOFOPERATION: c_int = 5; -pub const OCSP_REVOKED_STATUS_CERTIFICATEHOLD: c_int = 6; -pub const OCSP_REVOKED_STATUS_REMOVEFROMCRL: c_int = 8; - -pub const OCSP_RESPONSE_STATUS_SUCCESSFUL: c_int = 0; -pub const OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: c_int = 1; -pub const OCSP_RESPONSE_STATUS_INTERNALERROR: c_int = 2; -pub const OCSP_RESPONSE_STATUS_TRYLATER: c_int = 3; -pub const OCSP_RESPONSE_STATUS_SIGREQUIRED: c_int = 5; -pub const OCSP_RESPONSE_STATUS_UNAUTHORIZED: c_int = 6; - -pub const OPENSSL_EC_NAMED_CURVE: c_int = 1; - -pub const PKCS5_SALT_LEN: c_int = 8; -pub const PKCS12_DEFAULT_ITER: c_int = 2048; - -pub const RSA_F4: c_long = 0x10001; - -pub const RSA_PKCS1_PADDING: c_int = 1; -pub const RSA_SSLV23_PADDING: c_int = 2; -pub const RSA_NO_PADDING: c_int = 3; -pub const RSA_PKCS1_OAEP_PADDING: c_int = 4; -pub const RSA_X931_PADDING: c_int = 5; - -pub const SHA_LBLOCK: c_int = 16; - -pub const SSL_CTRL_SET_TMP_DH: c_int = 3; -pub const SSL_CTRL_SET_TMP_ECDH: c_int = 4; -pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; -pub const SSL_CTRL_MODE: c_int = 33; -pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41; -pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53; -pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; -pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; -pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: c_int = 63; -pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: c_int = 64; -pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: c_int = 65; -pub const SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 70; -pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 71; -pub const SSL_CTRL_GET_EXTRA_CHAIN_CERTS: c_int = 82; -#[cfg(not(any(ossl101, libressl)))] -pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106; - -pub const SSL_MODE_ENABLE_PARTIAL_WRITE: c_long = 0x1; -pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 0x2; -pub const SSL_MODE_AUTO_RETRY: c_long = 0x4; -pub const SSL_MODE_NO_AUTO_CHAIN: c_long = 0x8; -pub const SSL_MODE_RELEASE_BUFFERS: c_long = 0x10; -#[cfg(not(libressl))] -pub const SSL_MODE_SEND_CLIENTHELLO_TIME: c_long = 0x20; -#[cfg(not(libressl))] -pub const SSL_MODE_SEND_SERVERHELLO_TIME: c_long = 0x40; -#[cfg(not(libressl))] -pub const SSL_MODE_SEND_FALLBACK_SCSV: c_long = 0x80; - -pub const SSL_ERROR_NONE: c_int = 0; -pub const SSL_ERROR_SSL: c_int = 1; -pub const SSL_ERROR_SYSCALL: c_int = 5; -pub const SSL_ERROR_WANT_ACCEPT: c_int = 8; -pub const SSL_ERROR_WANT_CONNECT: c_int = 7; -pub const SSL_ERROR_WANT_READ: c_int = 2; -pub const SSL_ERROR_WANT_WRITE: c_int = 3; -pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; -pub const SSL_ERROR_ZERO_RETURN: c_int = 6; -pub const SSL_VERIFY_NONE: c_int = 0; -pub const SSL_VERIFY_PEER: c_int = 1; -pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; - -#[cfg(not(any(libressl261, libressl262, libressl26x, ossl101)))] -pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x00000010; -#[cfg(any(libressl261, libressl262, libressl26x))] -pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x0; -pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_ulong = 0x00000800; -#[cfg(not(any(libressl261, libressl262, libressl26x)))] -pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x80000000; -#[cfg(any(libressl261, libressl262, libressl26x))] -pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x0; -pub const SSL_OP_LEGACY_SERVER_CONNECT: c_ulong = 0x00000004; -#[cfg(not(libressl))] -pub const SSL_OP_SAFARI_ECDHE_ECDSA_BUG: c_ulong = 0x00000040; -#[cfg(not(any(libressl, ossl110f)))] -pub const SSL_OP_ALL: c_ulong = 0x80000BFF; -#[cfg(ossl110f)] -pub const SSL_OP_ALL: c_ulong = SSL_OP_CRYPTOPRO_TLSEXT_BUG | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS | - SSL_OP_LEGACY_SERVER_CONNECT | SSL_OP_TLSEXT_PADDING | - SSL_OP_SAFARI_ECDHE_ECDSA_BUG; -pub const SSL_OP_NO_QUERY_MTU: c_ulong = 0x00001000; -pub const SSL_OP_COOKIE_EXCHANGE: c_ulong = 0x00002000; -pub const SSL_OP_NO_TICKET: c_ulong = 0x00004000; -#[cfg(not(libressl))] -pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x00008000; -pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: c_ulong = 0x00010000; -#[cfg(not(libressl))] -pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x00020000; -#[cfg(not(libressl))] -pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x00040000; -pub const SSL_OP_CIPHER_SERVER_PREFERENCE: c_ulong = 0x00400000; -pub const SSL_OP_TLS_ROLLBACK_BUG: c_ulong = 0x00800000; -#[cfg(not(libressl))] -pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; -pub const SSL_OP_NO_TLSv1: c_ulong = 0x04000000; -pub const SSL_OP_NO_TLSv1_2: c_ulong = 0x08000000; -pub const SSL_OP_NO_TLSv1_1: c_ulong = 0x10000000; - -#[cfg(not(any(ossl101, libressl)))] -pub const SSL_OP_NO_DTLSv1: c_ulong = 0x04000000; -#[cfg(not(any(ossl101, libressl)))] -pub const SSL_OP_NO_DTLSv1_2: c_ulong = 0x08000000; -#[cfg(not(any(ossl101, libressl)))] -pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | - SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; - -pub const TLSEXT_NAMETYPE_host_name: c_int = 0; - -pub const TLSEXT_STATUSTYPE_ocsp: c_int = 1; - -pub const SSL_TLSEXT_ERR_OK: c_int = 0; -pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1; -pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2; -pub const SSL_TLSEXT_ERR_NOACK: c_int = 3; - -pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0; -pub const OPENSSL_NPN_NEGOTIATED: c_int = 1; -pub const OPENSSL_NPN_NO_OVERLAP: c_int = 2; - -pub const V_ASN1_GENERALIZEDTIME: c_int = 24; -pub const V_ASN1_UTCTIME: c_int = 23; - -pub const X509_FILETYPE_ASN1: c_int = 2; -pub const X509_FILETYPE_DEFAULT: c_int = 3; -pub const X509_FILETYPE_PEM: c_int = 1; -pub const X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; -pub const X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; -pub const X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; -pub const X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; -pub const X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; -pub const X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; -pub const X509_V_ERR_CERT_REJECTED: c_int = 28; -pub const X509_V_ERR_CERT_REVOKED: c_int = 23; -pub const X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; -pub const X509_V_ERR_CERT_UNTRUSTED: c_int = 27; -pub const X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; -pub const X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; -pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; -pub const X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; -pub const X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; -pub const X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; -pub const X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; -pub const X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; -pub const X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; -pub const X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; -pub const X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; -pub const X509_V_ERR_INVALID_CA: c_int = 24; -pub const X509_V_ERR_INVALID_EXTENSION: c_int = 41; -pub const X509_V_ERR_INVALID_NON_CA: c_int = 37; -pub const X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; -pub const X509_V_ERR_INVALID_PURPOSE: c_int = 26; -pub const X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; -pub const X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; -pub const X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; -pub const X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; -pub const X509_V_ERR_OUT_OF_MEM: c_int = 17; -pub const X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; -pub const X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; -pub const X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; -pub const X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; -pub const X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; -pub const X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; -pub const X509_V_ERR_SUBTREE_MINMAX: c_int = 49; -pub const X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; -pub const X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; -pub const X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; -pub const X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; -pub const X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; -pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; -pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; -pub const X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; -pub const X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; -pub const X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; -pub const X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; -pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; -pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; -pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; -pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; -pub const X509_V_OK: c_int = 0; - -#[cfg(not(any(ossl101, libressl)))] -pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1; -#[cfg(not(any(ossl101, libressl)))] -pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2; -#[cfg(not(any(ossl101, libressl)))] -pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; -#[cfg(not(any(ossl101, libressl)))] -pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8; -#[cfg(not(any(ossl101, libressl)))] -pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10; - -pub const GEN_OTHERNAME: c_int = 0; -pub const GEN_EMAIL: c_int = 1; -pub const GEN_DNS: c_int = 2; -pub const GEN_X400: c_int = 3; -pub const GEN_DIRNAME: c_int = 4; -pub const GEN_EDIPARTY: c_int = 5; -pub const GEN_URI: c_int = 6; -pub const GEN_IPADD: c_int = 7; -pub const GEN_RID: c_int = 8; - -// macros -pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { - BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) -} - -pub unsafe fn BIO_clear_retry_flags(b: *mut BIO) { - BIO_clear_flags(b, BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY) -} - -pub unsafe fn BIO_set_retry_read(b: *mut BIO) { - BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY) -} - -pub unsafe fn BIO_set_retry_write(b: *mut BIO) { - BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY) -} - -// EVP_PKEY_CTX_ctrl macros -pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { - EVP_PKEY_CTX_ctrl( - ctx, - EVP_PKEY_RSA, - -1, - EVP_PKEY_CTRL_RSA_PADDING, - pad, - ptr::null_mut(), - ) -} - -pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { - EVP_PKEY_CTX_ctrl( - ctx, - EVP_PKEY_RSA, - -1, - EVP_PKEY_CTRL_GET_RSA_PADDING, - 0, - ppad as *mut c_void, - ) -} - -pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut()) -} - -pub unsafe fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_SET_READ_AHEAD, m, ptr::null_mut()) -} - -pub unsafe fn SSL_CTX_set_tmp_dh(ctx: *mut SSL_CTX, dh: *mut DH) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) -} - -pub unsafe fn SSL_CTX_set_tmp_ecdh(ctx: *mut SSL_CTX, key: *mut EC_KEY) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) -} - -pub unsafe fn SSL_set_tmp_dh(ssl: *mut SSL, dh: *mut DH) -> c_long { - SSL_ctrl(ssl, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) -} - -pub unsafe fn SSL_set_tmp_ecdh(ssl: *mut SSL, key: *mut EC_KEY) -> c_long { - SSL_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) -} - -pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509 as *mut c_void) -} - -#[cfg(not(any(ossl101, libressl)))] -pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) -} - -pub unsafe fn SSL_CTX_set_tlsext_servername_callback( - ctx: *mut SSL_CTX, - cb: Option, -) -> c_long { - SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cb) -} - -pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long { - SSL_ctrl( - s, - SSL_CTRL_SET_TLSEXT_HOSTNAME, - TLSEXT_NAMETYPE_host_name as c_long, - name as *mut c_void, - ) -} - -pub unsafe fn SSL_set_tlsext_status_type(s: *mut SSL, type_: c_int) -> c_long { - SSL_ctrl( - s, - SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, - type_ as c_long, - ptr::null_mut(), - ) -} - -pub unsafe fn SSL_CTX_set_tlsext_status_cb( - ctx: *mut SSL_CTX, - cb: Option c_int>, -) -> c_long { - SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, mem::transmute(cb)) -} - -pub unsafe fn SSL_CTX_set_tlsext_status_arg(ctx: *mut SSL_CTX, arg: *mut c_void) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG, 0, arg) -} - -pub unsafe fn SSL_CTX_get_extra_chain_certs( - ctx: *mut SSL_CTX, - chain: *mut *mut stack_st_X509, -) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_GET_EXTRA_CHAIN_CERTS, 0, chain as *mut c_void) -} - -pub unsafe fn SSL_get_tlsext_status_ocsp_resp(ssl: *mut SSL, resp: *mut *mut c_uchar) -> c_long { - SSL_ctrl( - ssl, - SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, - 0, - resp as *mut c_void, - ) -} - -pub unsafe fn SSL_set_tlsext_status_ocsp_resp( - ssl: *mut SSL, - resp: *mut c_uchar, - len: c_long, -) -> c_long { - SSL_ctrl( - ssl, - SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, - len, - resp as *mut c_void, - ) -} - -pub fn ERR_GET_LIB(l: c_ulong) -> c_int { - ((l >> 24) & 0x0FF) as c_int -} - -pub fn ERR_GET_FUNC(l: c_ulong) -> c_int { - ((l >> 12) & 0xFFF) as c_int -} - -pub fn ERR_GET_REASON(l: c_ulong) -> c_int { - (l & 0xFFF) as c_int -} - -extern "C" { - pub fn AES_set_encrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; - pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; - pub fn AES_ige_encrypt( - in_: *const c_uchar, - out: *mut c_uchar, - length: size_t, - key: *const AES_KEY, - ivec: *mut c_uchar, - enc: c_int, - ); - - pub fn ASN1_INTEGER_get(dest: *const ASN1_INTEGER) -> c_long; - pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; - pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); - pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; - pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; - pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); - pub fn ASN1_TIME_print(b: *mut BIO, tm: *const ASN1_TIME) -> c_int; - pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); - pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); - - pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn BIO_free_all(b: *mut BIO); - pub fn BIO_new_fp(stream: *mut FILE, close_flag: c_int) -> *mut BIO; - pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *mut BIO; - pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; - pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; - #[cfg(any(ossl101, libressl))] - pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO; - #[cfg(not(any(ossl101, libressl)))] - pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; - pub fn BIO_set_flags(b: *mut BIO, flags: c_int); - pub fn BIO_clear_flags(b: *mut BIO, flags: c_int); - - pub fn BN_CTX_new() -> *mut BN_CTX; - pub fn BN_CTX_free(ctx: *mut BN_CTX); - - pub fn BN_new() -> *mut BIGNUM; - pub fn BN_dup(n: *const BIGNUM) -> *mut BIGNUM; - pub fn BN_clear(bn: *mut BIGNUM); - pub fn BN_free(bn: *mut BIGNUM); - pub fn BN_clear_free(bn: *mut BIGNUM); - pub fn BN_num_bits(bn: *const BIGNUM) -> c_int; - pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); - pub fn BN_set_word(bn: *mut BIGNUM, n: BN_ULONG) -> c_int; - pub fn BN_add(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; - pub fn BN_div( - dv: *mut BIGNUM, - rem: *mut BIGNUM, - a: *const BIGNUM, - b: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn BN_exp(r: *mut BIGNUM, a: *const BIGNUM, p: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_gcd(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_add( - r: *mut BIGNUM, - a: *const BIGNUM, - b: *const BIGNUM, - m: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn BN_mod_exp( - r: *mut BIGNUM, - a: *const BIGNUM, - p: *const BIGNUM, - m: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn BN_mod_inverse( - r: *mut BIGNUM, - a: *const BIGNUM, - n: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> *mut BIGNUM; - pub fn BN_mod_mul( - r: *mut BIGNUM, - a: *const BIGNUM, - b: *const BIGNUM, - m: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn BN_mod_sqr( - r: *mut BIGNUM, - a: *const BIGNUM, - m: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn BN_mod_sub( - r: *mut BIGNUM, - a: *const BIGNUM, - b: *const BIGNUM, - m: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn BN_mul(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_nnmod( - rem: *mut BIGNUM, - a: *const BIGNUM, - m: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn BN_add_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; - pub fn BN_sub_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; - pub fn BN_mul_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; - pub fn BN_div_word(r: *mut BIGNUM, w: BN_ULONG) -> BN_ULONG; - pub fn BN_mod_word(r: *const BIGNUM, w: BN_ULONG) -> BN_ULONG; - pub fn BN_sqr(r: *mut BIGNUM, a: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_sub(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; - pub fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_is_bit_set(a: *const BIGNUM, n: c_int) -> c_int; - pub fn BN_lshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; - pub fn BN_lshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; - pub fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_rshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; - pub fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_rshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; - pub fn BN_cmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; - pub fn BN_ucmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; - pub fn BN_generate_prime_ex( - r: *mut BIGNUM, - bits: c_int, - safe: c_int, - add: *const BIGNUM, - rem: *const BIGNUM, - cb: *mut BN_GENCB, - ) -> c_int; - pub fn BN_is_prime_ex( - p: *const BIGNUM, - checks: c_int, - ctx: *mut BN_CTX, - cb: *mut BN_GENCB, - ) -> c_int; - pub fn BN_is_prime_fasttest_ex( - p: *const BIGNUM, - checks: c_int, - ctx: *mut BN_CTX, - do_trial_division: c_int, - cb: *mut BN_GENCB, - ) -> c_int; - pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; - pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; - pub fn BN_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; - pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; - pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_bn2bin(a: *const BIGNUM, to: *mut u8) -> c_int; - pub fn BN_dec2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; - pub fn BN_bn2dec(a: *const BIGNUM) -> *mut c_char; - pub fn BN_hex2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; - pub fn BN_bn2hex(a: *const BIGNUM) -> *mut c_char; - pub fn BN_to_ASN1_INTEGER(bn: *const BIGNUM, ai: *mut ASN1_INTEGER) -> *mut ASN1_INTEGER; - - pub fn NCONF_default() -> *mut CONF_METHOD; - pub fn NCONF_new(meth: *mut CONF_METHOD) -> *mut CONF; - pub fn NCONF_free(conf: *mut CONF); - - pub fn CRYPTO_memcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; - - pub fn DH_new() -> *mut DH; - pub fn DH_free(dh: *mut DH); - #[cfg(not(any(ossl101, libressl)))] - pub fn DH_get_1024_160() -> *mut DH; - #[cfg(not(any(ossl101, libressl)))] - pub fn DH_get_2048_224() -> *mut DH; - #[cfg(not(any(ossl101, libressl)))] - pub fn DH_get_2048_256() -> *mut DH; - - pub fn EC_KEY_new() -> *mut EC_KEY; - pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY; - pub fn EC_KEY_dup(key: *const EC_KEY) -> *mut EC_KEY; - pub fn EC_KEY_set_group(key: *mut EC_KEY, group: *const EC_GROUP) -> c_int; - pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP; - pub fn EC_KEY_set_public_key(key: *mut EC_KEY, key: *const EC_POINT) -> c_int; - pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT; - pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int; - pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; - pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int; - pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int; - pub fn EC_KEY_free(key: *mut EC_KEY); - pub fn EC_KEY_set_public_key_affine_coordinates( - key: *mut EC_KEY, - x: *mut BIGNUM, - y: *mut BIGNUM, - ) -> c_int; - - #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] - pub fn EC_GF2m_simple_method() -> *const EC_METHOD; - - pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP; - pub fn EC_GROUP_new_curve_GFp( - p: *const BIGNUM, - a: *const BIGNUM, - b: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> *mut EC_GROUP; - #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] - pub fn EC_GROUP_new_curve_GF2m( - p: *const BIGNUM, - a: *const BIGNUM, - b: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> *mut EC_GROUP; - pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP; - pub fn EC_GROUP_get_curve_GFp( - group: *const EC_GROUP, - p: *mut BIGNUM, - a: *mut BIGNUM, - b: *mut BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] - pub fn EC_GROUP_get_curve_GF2m( - group: *const EC_GROUP, - p: *mut BIGNUM, - a: *mut BIGNUM, - b: *mut BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn EC_GROUP_get_degree(group: *const EC_GROUP) -> c_int; - pub fn EC_GROUP_get_order( - group: *const EC_GROUP, - order: *mut BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn EC_GROUP_set_asn1_flag(key: *mut EC_GROUP, flag: c_int); - - pub fn EC_GROUP_free(group: *mut EC_GROUP); - - pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT; - pub fn EC_POINT_add( - group: *const EC_GROUP, - r: *mut EC_POINT, - a: *const EC_POINT, - b: *const EC_POINT, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn EC_POINT_mul( - group: *const EC_GROUP, - r: *mut EC_POINT, - n: *const BIGNUM, - q: *const EC_POINT, - m: *const BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn EC_POINT_invert(group: *const EC_GROUP, r: *mut EC_POINT, ctx: *mut BN_CTX) -> c_int; - pub fn EC_POINT_point2oct( - group: *const EC_GROUP, - p: *const EC_POINT, - form: point_conversion_form_t, - buf: *mut c_uchar, - len: size_t, - ctx: *mut BN_CTX, - ) -> size_t; - pub fn EC_POINT_oct2point( - group: *const EC_GROUP, - p: *mut EC_POINT, - buf: *const c_uchar, - len: size_t, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn EC_POINT_cmp( - group: *const EC_GROUP, - a: *const EC_POINT, - b: *const EC_POINT, - ctx: *mut BN_CTX, - ) -> c_int; - pub fn EC_POINT_free(point: *mut EC_POINT); - pub fn EC_POINT_get_affine_coordinates_GFp( - group: *const EC_GROUP, - p: *const EC_POINT, - x: *mut BIGNUM, - y: *mut BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] - pub fn EC_POINT_get_affine_coordinates_GF2m( - group: *const EC_GROUP, - p: *const EC_POINT, - x: *mut BIGNUM, - y: *mut BIGNUM, - ctx: *mut BN_CTX, - ) -> c_int; - - pub fn ERR_peek_last_error() -> c_ulong; - pub fn ERR_get_error() -> c_ulong; - pub fn ERR_get_error_line_data( - file: *mut *const c_char, - line: *mut c_int, - data: *mut *const c_char, - flags: *mut c_int, - ) -> c_ulong; - pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; - pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; - pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; - pub fn ERR_clear_error(); - - pub fn EVP_md5() -> *const EVP_MD; - pub fn EVP_ripemd160() -> *const EVP_MD; - pub fn EVP_sha1() -> *const EVP_MD; - pub fn EVP_sha224() -> *const EVP_MD; - pub fn EVP_sha256() -> *const EVP_MD; - pub fn EVP_sha384() -> *const EVP_MD; - pub fn EVP_sha512() -> *const EVP_MD; - - pub fn EVP_aes_128_cbc() -> *const EVP_CIPHER; - pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER; - pub fn EVP_aes_128_xts() -> *const EVP_CIPHER; - pub fn EVP_aes_128_ctr() -> *const EVP_CIPHER; - pub fn EVP_aes_128_gcm() -> *const EVP_CIPHER; - pub fn EVP_aes_128_cfb1() -> *const EVP_CIPHER; - pub fn EVP_aes_128_cfb128() -> *const EVP_CIPHER; - pub fn EVP_aes_128_cfb8() -> *const EVP_CIPHER; - pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; - pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; - pub fn EVP_aes_256_xts() -> *const EVP_CIPHER; - pub fn EVP_aes_256_ctr() -> *const EVP_CIPHER; - pub fn EVP_aes_256_gcm() -> *const EVP_CIPHER; - pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER; - pub fn EVP_aes_256_cfb128() -> *const EVP_CIPHER; - pub fn EVP_aes_256_cfb8() -> *const EVP_CIPHER; - pub fn EVP_bf_cbc() -> *const EVP_CIPHER; - pub fn EVP_bf_ecb() -> *const EVP_CIPHER; - pub fn EVP_bf_cfb64() -> *const EVP_CIPHER; - pub fn EVP_bf_ofb() -> *const EVP_CIPHER; - pub fn EVP_rc4() -> *const EVP_CIPHER; - - pub fn EVP_des_cbc() -> *const EVP_CIPHER; - pub fn EVP_des_ecb() -> *const EVP_CIPHER; - - pub fn EVP_BytesToKey( - typ: *const EVP_CIPHER, - md: *const EVP_MD, - salt: *const u8, - data: *const u8, - datalen: c_int, - count: c_int, - key: *mut u8, - iv: *mut u8, - ) -> c_int; - - pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; - pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int; - pub fn EVP_CIPHER_CTX_set_key_length(ctx: *mut EVP_CIPHER_CTX, keylen: c_int) -> c_int; - pub fn EVP_CIPHER_CTX_ctrl( - ctx: *mut EVP_CIPHER_CTX, - type_: c_int, - arg: c_int, - ptr: *mut c_void, - ) -> c_int; - pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX); - - pub fn EVP_CipherInit( - ctx: *mut EVP_CIPHER_CTX, - evp: *const EVP_CIPHER, - key: *const u8, - iv: *const u8, - mode: c_int, - ) -> c_int; - pub fn EVP_CipherInit_ex( - ctx: *mut EVP_CIPHER_CTX, - type_: *const EVP_CIPHER, - impl_: *mut ENGINE, - key: *const c_uchar, - iv: *const c_uchar, - enc: c_int, - ) -> c_int; - pub fn EVP_CipherUpdate( - ctx: *mut EVP_CIPHER_CTX, - outbuf: *mut u8, - outlen: *mut c_int, - inbuf: *const u8, - inlen: c_int, - ) -> c_int; - pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: *mut c_int) -> c_int; - - pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD) -> c_int; - pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *mut ENGINE) - -> c_int; - pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const c_void, n: size_t) -> c_int; - pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; - pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; - - pub fn EVP_DigestSignInit( - ctx: *mut EVP_MD_CTX, - pctx: *mut *mut EVP_PKEY_CTX, - type_: *const EVP_MD, - e: *mut ENGINE, - pkey: *mut EVP_PKEY, - ) -> c_int; - pub fn EVP_DigestSignFinal( - ctx: *mut EVP_MD_CTX, - sig: *mut c_uchar, - siglen: *mut size_t, - ) -> c_int; - pub fn EVP_DigestVerifyInit( - ctx: *mut EVP_MD_CTX, - pctx: *mut *mut EVP_PKEY_CTX, - type_: *const EVP_MD, - e: *mut ENGINE, - pkey: *mut EVP_PKEY, - ) -> c_int; - #[cfg(any(ossl101, libressl))] - pub fn EVP_DigestVerifyFinal( - ctx: *mut EVP_MD_CTX, - sigret: *mut c_uchar, - siglen: size_t, - ) -> c_int; - #[cfg(not(any(ossl101, libressl)))] - pub fn EVP_DigestVerifyFinal( - ctx: *mut EVP_MD_CTX, - sigret: *const c_uchar, - siglen: size_t, - ) -> c_int; - - pub fn EVP_MD_CTX_copy_ex(dst: *mut EVP_MD_CTX, src: *const EVP_MD_CTX) -> c_int; - - pub fn EVP_PKEY_new() -> *mut EVP_PKEY; - pub fn EVP_PKEY_free(k: *mut EVP_PKEY); - pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *mut c_void) -> c_int; - pub fn EVP_PKEY_copy_parameters(to: *mut EVP_PKEY, from: *const EVP_PKEY) -> c_int; - pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; - pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; - pub fn EVP_PKEY_get1_DSA(k: *mut EVP_PKEY) -> *mut DSA; - pub fn EVP_PKEY_get1_DH(k: *mut EVP_PKEY) -> *mut DH; - pub fn EVP_PKEY_get1_EC_KEY(k: *mut EVP_PKEY) -> *mut EC_KEY; - pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int; - pub fn EVP_PKEY_new_mac_key( - type_: c_int, - e: *mut ENGINE, - key: *const c_uchar, - keylen: c_int, - ) -> *mut EVP_PKEY; - pub fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int; - pub fn EVP_PKEY_derive_set_peer(ctx: *mut EVP_PKEY_CTX, peer: *mut EVP_PKEY) -> c_int; - pub fn EVP_PKEY_derive(ctx: *mut EVP_PKEY_CTX, key: *mut c_uchar, size: *mut size_t) -> c_int; - pub fn d2i_PKCS8PrivateKey_bio( - bp: *mut BIO, - x: *mut *mut EVP_PKEY, - cb: Option, - u: *mut c_void, - ) -> *mut EVP_PKEY; - - pub fn EVP_PKEY_CTX_new(k: *mut EVP_PKEY, e: *mut ENGINE) -> *mut EVP_PKEY_CTX; - pub fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX); - pub fn EVP_PKEY_CTX_ctrl( - ctx: *mut EVP_PKEY_CTX, - keytype: c_int, - optype: c_int, - cmd: c_int, - p1: c_int, - p2: *mut c_void, - ) -> c_int; - - pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; - - pub fn OBJ_obj2nid(o: *const ASN1_OBJECT) -> c_int; - pub fn OBJ_obj2txt( - buf: *mut c_char, - buf_len: c_int, - a: *const ASN1_OBJECT, - no_name: c_int, - ) -> c_int; - - pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; - pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP); - pub fn OCSP_basic_verify( - bs: *mut OCSP_BASICRESP, - certs: *mut stack_st_X509, - st: *mut X509_STORE, - flags: c_ulong, - ) -> c_int; - pub fn OCSP_resp_find_status( - bs: *mut OCSP_BASICRESP, - id: *mut OCSP_CERTID, - status: *mut c_int, - reason: *mut c_int, - revtime: *mut *mut ASN1_GENERALIZEDTIME, - thisupd: *mut *mut ASN1_GENERALIZEDTIME, - nextupd: *mut *mut ASN1_GENERALIZEDTIME, - ) -> c_int; - pub fn OCSP_check_validity( - thisupd: *mut ASN1_GENERALIZEDTIME, - nextupd: *mut ASN1_GENERALIZEDTIME, - sec: c_long, - maxsec: c_long, - ) -> c_int; - - pub fn OCSP_CERTID_free(id: *mut OCSP_CERTID); - - pub fn OCSP_RESPONSE_new() -> *mut OCSP_RESPONSE; - pub fn OCSP_RESPONSE_free(r: *mut OCSP_RESPONSE); - pub fn i2d_OCSP_RESPONSE(a: *mut OCSP_RESPONSE, pp: *mut *mut c_uchar) -> c_int; - pub fn d2i_OCSP_RESPONSE( - a: *mut *mut OCSP_RESPONSE, - pp: *mut *const c_uchar, - length: c_long, - ) -> *mut OCSP_RESPONSE; - pub fn OCSP_response_create(status: c_int, bs: *mut OCSP_BASICRESP) -> *mut OCSP_RESPONSE; - pub fn OCSP_response_status(resp: *mut OCSP_RESPONSE) -> c_int; - pub fn OCSP_response_get1_basic(resp: *mut OCSP_RESPONSE) -> *mut OCSP_BASICRESP; - - pub fn OCSP_REQUEST_new() -> *mut OCSP_REQUEST; - pub fn OCSP_REQUEST_free(r: *mut OCSP_REQUEST); - pub fn i2d_OCSP_REQUEST(a: *mut OCSP_REQUEST, pp: *mut *mut c_uchar) -> c_int; - pub fn d2i_OCSP_REQUEST( - a: *mut *mut OCSP_REQUEST, - pp: *mut *const c_uchar, - length: c_long, - ) -> *mut OCSP_REQUEST; - pub fn OCSP_request_add0_id(r: *mut OCSP_REQUEST, id: *mut OCSP_CERTID) -> *mut OCSP_ONEREQ; - - pub fn OCSP_ONEREQ_free(r: *mut OCSP_ONEREQ); - - pub fn PEM_read_bio_DHparams( - bio: *mut BIO, - out: *mut *mut DH, - callback: Option, - user_data: *mut c_void, - ) -> *mut DH; - pub fn PEM_read_bio_X509( - bio: *mut BIO, - out: *mut *mut X509, - callback: Option, - user_data: *mut c_void, - ) -> *mut X509; - pub fn PEM_read_bio_X509_REQ( - bio: *mut BIO, - out: *mut *mut X509_REQ, - callback: Option, - user_data: *mut c_void, - ) -> *mut X509_REQ; - pub fn PEM_read_bio_PrivateKey( - bio: *mut BIO, - out: *mut *mut EVP_PKEY, - callback: Option, - user_data: *mut c_void, - ) -> *mut EVP_PKEY; - pub fn PEM_read_bio_PUBKEY( - bio: *mut BIO, - out: *mut *mut EVP_PKEY, - callback: Option, - user_data: *mut c_void, - ) -> *mut EVP_PKEY; - - pub fn PEM_read_bio_RSAPrivateKey( - bio: *mut BIO, - rsa: *mut *mut RSA, - callback: Option, - user_data: *mut c_void, - ) -> *mut RSA; - pub fn PEM_read_bio_RSA_PUBKEY( - bio: *mut BIO, - rsa: *mut *mut RSA, - callback: Option, - user_data: *mut c_void, - ) -> *mut RSA; - - pub fn PEM_write_bio_DHparams(bio: *mut BIO, x: *const DH) -> c_int; - pub fn PEM_write_bio_PrivateKey( - bio: *mut BIO, - pkey: *mut EVP_PKEY, - cipher: *const EVP_CIPHER, - kstr: *mut c_uchar, - klen: c_int, - callback: Option, - user_data: *mut c_void, - ) -> c_int; - pub fn PEM_write_bio_PKCS8PrivateKey( - bio: *mut BIO, - pkey: *mut EVP_PKEY, - cipher: *const EVP_CIPHER, - kstr: *mut c_char, - klen: c_int, - callback: Option, - user_data: *mut c_void, - ) -> c_int; - pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int; - pub fn PEM_write_bio_RSAPrivateKey( - bp: *mut BIO, - rsa: *mut RSA, - cipher: *const EVP_CIPHER, - kstr: *mut c_uchar, - klen: c_int, - callback: Option, - user_data: *mut c_void, - ) -> c_int; - pub fn PEM_write_bio_RSAPublicKey(bp: *mut BIO, rsa: *const RSA) -> c_int; - pub fn PEM_write_bio_RSA_PUBKEY(bp: *mut BIO, rsa: *mut RSA) -> c_int; - - pub fn PEM_read_bio_DSAPrivateKey( - bp: *mut BIO, - dsa: *mut *mut DSA, - callback: Option, - user_data: *mut c_void, - ) -> *mut DSA; - pub fn PEM_read_bio_DSA_PUBKEY( - bp: *mut BIO, - dsa: *mut *mut DSA, - callback: Option, - user_data: *mut c_void, - ) -> *mut DSA; - pub fn PEM_write_bio_DSAPrivateKey( - bp: *mut BIO, - dsa: *mut DSA, - cipher: *const EVP_CIPHER, - kstr: *mut c_uchar, - klen: c_int, - callback: Option, - user_data: *mut c_void, - ) -> c_int; - pub fn PEM_write_bio_DSA_PUBKEY(bp: *mut BIO, dsa: *mut DSA) -> c_int; - - pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; - pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int; - - pub fn PEM_write_bio_ECPrivateKey( - bio: *mut BIO, - key: *mut EC_KEY, - cipher: *const EVP_CIPHER, - kstr: *mut c_uchar, - klen: c_int, - callback: Option, - user_data: *mut c_void, - ) -> c_int; - pub fn PEM_read_bio_ECPrivateKey( - bio: *mut BIO, - key: *mut *mut EC_KEY, - callback: Option, - user_data: *mut c_void, - ) -> *mut EC_KEY; - - pub fn PKCS5_PBKDF2_HMAC_SHA1( - pass: *const c_char, - passlen: c_int, - salt: *const u8, - saltlen: c_int, - iter: c_int, - keylen: c_int, - out: *mut u8, - ) -> c_int; - pub fn PKCS5_PBKDF2_HMAC( - pass: *const c_char, - passlen: c_int, - salt: *const c_uchar, - saltlen: c_int, - iter: c_int, - digest: *const EVP_MD, - keylen: c_int, - out: *mut u8, - ) -> c_int; - - pub fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int; - pub fn RAND_status() -> c_int; - - pub fn RSA_new() -> *mut RSA; - pub fn RSA_free(rsa: *mut RSA); - pub fn RSA_generate_key_ex( - rsa: *mut RSA, - bits: c_int, - e: *mut BIGNUM, - cb: *mut BN_GENCB, - ) -> c_int; - pub fn RSA_private_decrypt( - flen: c_int, - from: *const u8, - to: *mut u8, - k: *mut RSA, - pad: c_int, - ) -> c_int; - pub fn RSA_public_decrypt( - flen: c_int, - from: *const u8, - to: *mut u8, - k: *mut RSA, - pad: c_int, - ) -> c_int; - pub fn RSA_private_encrypt( - flen: c_int, - from: *const u8, - to: *mut u8, - k: *mut RSA, - pad: c_int, - ) -> c_int; - pub fn RSA_public_encrypt( - flen: c_int, - from: *const u8, - to: *mut u8, - k: *mut RSA, - pad: c_int, - ) -> c_int; - pub fn RSA_sign( - t: c_int, - m: *const u8, - mlen: c_uint, - sig: *mut u8, - siglen: *mut c_uint, - k: *mut RSA, - ) -> c_int; - pub fn RSA_size(k: *const RSA) -> c_int; - pub fn RSA_verify( - t: c_int, - m: *const u8, - mlen: c_uint, - sig: *const u8, - siglen: c_uint, - k: *mut RSA, - ) -> c_int; - - pub fn DSA_new() -> *mut DSA; - pub fn DSA_free(dsa: *mut DSA); - pub fn DSA_size(dsa: *const DSA) -> c_int; - pub fn DSA_generate_parameters_ex( - dsa: *mut DSA, - bits: c_int, - seed: *const c_uchar, - seed_len: c_int, - counter_ref: *mut c_int, - h_ret: *mut c_ulong, - cb: *mut BN_GENCB, - ) -> c_int; - pub fn DSA_generate_key(dsa: *mut DSA) -> c_int; - pub fn DSA_sign( - dummy: c_int, - dgst: *const c_uchar, - len: c_int, - sigret: *mut c_uchar, - siglen: *mut c_uint, - dsa: *mut DSA, - ) -> c_int; - pub fn DSA_verify( - dummy: c_int, - dgst: *const c_uchar, - len: c_int, - sigbuf: *const c_uchar, - siglen: c_int, - dsa: *mut DSA, - ) -> c_int; - - pub fn SHA1(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; - pub fn SHA224(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; - pub fn SHA256(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; - pub fn SHA384(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; - pub fn SHA512(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; - - pub fn SHA1_Init(c: *mut SHA_CTX) -> c_int; - pub fn SHA1_Update(c: *mut SHA_CTX, data: *const c_void, len: size_t) -> c_int; - pub fn SHA1_Final(md: *mut c_uchar, c: *mut SHA_CTX) -> c_int; - pub fn SHA256_Init(c: *mut SHA256_CTX) -> c_int; - pub fn SHA256_Update(c: *mut SHA256_CTX, data: *const c_void, len: size_t) -> c_int; - pub fn SHA256_Final(md: *mut c_uchar, c: *mut SHA256_CTX) -> c_int; - pub fn SHA224_Init(c: *mut SHA256_CTX) -> c_int; - pub fn SHA224_Update(c: *mut SHA256_CTX, data: *const c_void, len: size_t) -> c_int; - pub fn SHA224_Final(md: *mut c_uchar, c: *mut SHA256_CTX) -> c_int; - pub fn SHA384_Init(c: *mut SHA512_CTX) -> c_int; - pub fn SHA384_Update(c: *mut SHA512_CTX, data: *const c_void, len: size_t) -> c_int; - pub fn SHA384_Final(md: *mut c_uchar, c: *mut SHA512_CTX) -> c_int; - pub fn SHA512_Init(c: *mut SHA512_CTX) -> c_int; - pub fn SHA512_Update(c: *mut SHA512_CTX, data: *const c_void, len: size_t) -> c_int; - pub fn SHA512_Final(md: *mut c_uchar, c: *mut SHA512_CTX) -> c_int; - - pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; - pub fn SSL_pending(ssl: *const SSL) -> c_int; - pub fn SSL_free(ssl: *mut SSL); - pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); - pub fn SSL_get_rbio(ssl: *const SSL) -> *mut BIO; - pub fn SSL_get_wbio(ssl: *const SSL) -> *mut BIO; - pub fn SSL_accept(ssl: *mut SSL) -> c_int; - pub fn SSL_connect(ssl: *mut SSL) -> c_int; - pub fn SSL_do_handshake(ssl: *mut SSL) -> c_int; - pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn SSL_get_error(ssl: *const SSL, ret: c_int) -> c_int; - pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; - pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; - pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; - pub fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX; - pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX; - #[cfg(not(any(osslconf = "OPENSSL_NO_COMP", libressl)))] - pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; - #[cfg(libressl)] - pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const libc::c_void; - pub fn SSL_get_peer_certificate(ssl: *const SSL) -> *mut X509; - pub fn SSL_get_peer_cert_chain(ssl: *const SSL) -> *mut stack_st_X509; - pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD; - pub fn SSL_get_version(ssl: *const SSL) -> *const c_char; - pub fn SSL_state_string(ssl: *const SSL) -> *const c_char; - pub fn SSL_state_string_long(ssl: *const SSL) -> *const c_char; - pub fn SSL_set_verify( - ssl: *mut SSL, - mode: c_int, - verify_callback: Option c_int>, - ); - pub fn SSL_set_ex_data(ssl: *mut SSL, idx: c_int, data: *mut c_void) -> c_int; - pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void; - pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; - pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; - #[cfg(not(any(ossl101, libressl)))] - pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; - pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long; - pub fn SSL_shutdown(ssl: *mut SSL) -> c_int; - pub fn SSL_get_certificate(ssl: *const SSL) -> *mut X509; - #[cfg(any(ossl101, libressl))] - pub fn SSL_get_privatekey(ssl: *mut SSL) -> *mut EVP_PKEY; - #[cfg(not(any(ossl101, libressl)))] - pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY; - pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; - pub fn SSL_set_tmp_dh_callback( - ctx: *mut SSL, - dh: unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, - ); - - #[cfg(not(any(osslconf = "OPENSSL_NO_COMP", libressl)))] - pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; - #[cfg(libressl)] - pub fn SSL_COMP_get_name(comp: *const libc::c_void) -> *const c_char; - - pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char; - pub fn SSL_CIPHER_get_bits(cipher: *const SSL_CIPHER, alg_bits: *mut c_int) -> c_int; - pub fn SSL_CIPHER_description( - cipher: *const SSL_CIPHER, +pub use libc::*; + +#[cfg(feature = "unstable_boringssl")] +extern crate bssl_sys; +#[cfg(feature = "unstable_boringssl")] +pub use bssl_sys::*; + +#[cfg(all(boringssl, not(feature = "unstable_boringssl")))] +#[path = "."] +mod boringssl { + include!(concat!(env!("OUT_DIR"), "/bindgen.rs")); + + pub fn init() { + unsafe { + CRYPTO_library_init(); + } + } +} +#[cfg(all(boringssl, not(feature = "unstable_boringssl")))] +pub use boringssl::*; + +#[cfg(openssl)] +#[path = "."] +mod openssl { + use libc::*; + + #[cfg(feature = "bindgen")] + include!(concat!(env!("OUT_DIR"), "/bindgen.rs")); + + pub use self::aes::*; + pub use self::asn1::*; + pub use self::bio::*; + pub use self::bn::*; + pub use self::cms::*; + pub use self::crypto::*; + pub use self::dtls1::*; + pub use self::ec::*; + pub use self::err::*; + pub use self::evp::*; + #[cfg(not(feature = "bindgen"))] + pub use self::handwritten::*; + pub use self::obj_mac::*; + pub use self::ocsp::*; + pub use self::pem::*; + pub use self::pkcs7::*; + pub use self::rsa::*; + pub use self::sha::*; + pub use self::srtp::*; + pub use self::ssl::*; + pub use self::ssl3::*; + pub use self::tls1::*; + pub use self::types::*; + pub use self::x509::*; + pub use self::x509_vfy::*; + pub use self::x509v3::*; + + #[macro_use] + mod macros; + + mod aes; + mod asn1; + mod bio; + mod bn; + mod cms; + mod crypto; + mod dtls1; + mod ec; + mod err; + mod evp; + #[cfg(not(feature = "bindgen"))] + mod handwritten; + mod obj_mac; + mod ocsp; + mod pem; + mod pkcs7; + mod rsa; + mod sha; + mod srtp; + mod ssl; + mod ssl3; + mod tls1; + mod types; + mod x509; + mod x509_vfy; + mod x509v3; + + use std::sync::Once; + // explicitly initialize to work around https://github.com/openssl/openssl/issues/3505 + static INIT: Once = Once::new(); + + // FIXME remove + pub type PasswordCallback = unsafe extern "C" fn( buf: *mut c_char, size: c_int, - ) -> *mut c_char; - - pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; - pub fn SSL_CTX_free(ctx: *mut SSL_CTX); - pub fn SSL_CTX_ctrl(ctx: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn SSL_CTX_callback_ctrl( - ctx: *mut SSL_CTX, - cmd: c_int, - fp: Option, - ) -> c_long; - pub fn SSL_CTX_set_verify( - ctx: *mut SSL_CTX, - mode: c_int, - verify_callback: Option c_int>, - ); - pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int); - pub fn SSL_CTX_load_verify_locations( - ctx: *mut SSL_CTX, - CAfile: *const c_char, - CApath: *const c_char, - ) -> c_int; - pub fn SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int; - pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) -> c_int; - pub fn SSL_CTX_get_ex_data(ctx: *const SSL_CTX, idx: c_int) -> *mut c_void; - pub fn SSL_CTX_set_session_id_context( - ssl: *mut SSL_CTX, - sid_ctx: *const c_uchar, - sid_ctx_len: c_uint, - ) -> c_int; - - pub fn SSL_CTX_use_certificate_file( - ctx: *mut SSL_CTX, - cert_file: *const c_char, - file_type: c_int, - ) -> c_int; - pub fn SSL_CTX_use_certificate_chain_file( - ctx: *mut SSL_CTX, - cert_chain_file: *const c_char, - ) -> c_int; - pub fn SSL_CTX_use_certificate(ctx: *mut SSL_CTX, cert: *mut X509) -> c_int; - - pub fn SSL_CTX_use_PrivateKey_file( - ctx: *mut SSL_CTX, - key_file: *const c_char, - file_type: c_int, - ) -> c_int; - pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int; - pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; - pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME); - pub fn SSL_CTX_get_cert_store(ctx: *const SSL_CTX) -> *mut X509_STORE; - pub fn SSL_CTX_set_tmp_dh_callback( - ctx: *mut SSL_CTX, - dh: unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, - ); - - #[cfg(not(any(ossl101, libressl)))] - pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; - #[cfg(not(any(ossl101, libressl)))] - pub fn SSL_CTX_get0_privatekey(ctx: *const SSL_CTX) -> *mut EVP_PKEY; - - pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; - - pub fn SSL_CTX_set_next_protos_advertised_cb( - ssl: *mut SSL_CTX, - cb: extern "C" fn(ssl: *mut SSL, - out: *mut *const c_uchar, - outlen: *mut c_uint, - arg: *mut c_void) - -> c_int, - arg: *mut c_void, - ); - pub fn SSL_CTX_set_next_proto_select_cb( - ssl: *mut SSL_CTX, - cb: extern "C" fn(ssl: *mut SSL, - out: *mut *mut c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - arg: *mut c_void) - -> c_int, - arg: *mut c_void, - ); - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - pub fn SSL_CTX_set_psk_client_callback( - ssl: *mut SSL_CTX, - psk_client_cb: Option< - extern "C" fn(*mut SSL, - *const c_char, - *mut c_char, - c_uint, - *mut c_uchar, - c_uint) - -> c_uint, - >, - ); - pub fn SSL_select_next_proto( - out: *mut *mut c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - client: *const c_uchar, - client_len: c_uint, - ) -> c_int; - pub fn SSL_get0_next_proto_negotiated( - s: *const SSL, - data: *mut *const c_uchar, - len: *mut c_uint, - ); - pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; - pub fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int; - #[cfg(not(any(ossl101, libressl, ossl110f)))] - pub fn SSL_is_server(s: *mut SSL) -> c_int; - #[cfg(ossl110f)] - pub fn SSL_is_server(s: *const SSL) -> c_int; - - pub fn SSL_SESSION_free(s: *mut SSL_SESSION); - pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar; - - #[cfg(not(ossl101))] - pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; - - #[cfg(not(ossl101))] - pub fn SSL_set_alpn_protos(s: *mut SSL, data: *const c_uchar, len: c_uint) -> c_int; - - #[cfg(not(ossl101))] - pub fn SSL_CTX_set_alpn_select_cb( - ssl: *mut SSL_CTX, - cb: extern "C" fn(ssl: *mut SSL, - out: *mut *const c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - arg: *mut c_void) - -> c_int, - arg: *mut c_void, - ); - #[cfg(not(ossl101))] - pub fn SSL_get0_alpn_selected(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); - - pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; - pub fn X509_digest( - x: *const X509, - digest: *const EVP_MD, - buf: *mut c_uchar, - len: *mut c_uint, - ) -> c_int; - pub fn X509_free(x: *mut X509); - pub fn X509_REQ_free(x: *mut X509_REQ); - pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; - pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; - pub fn X509_new() -> *mut X509; - pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int; - pub fn X509_set_subject_name(x: *mut X509, name: *mut X509_NAME) -> c_int; - pub fn X509_set_serialNumber(x: *mut X509, sn: *mut ASN1_INTEGER) -> c_int; - pub fn X509_set_version(x: *mut X509, version: c_long) -> c_int; - pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; - pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY; - pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; - pub fn X509_verify_cert_error_string(n: c_long) -> *const c_char; - pub fn X509_get1_ocsp(x: *mut X509) -> *mut stack_st_OPENSSL_STRING; - pub fn X509_check_issued(issuer: *mut X509, subject: *mut X509) -> c_int; - - pub fn X509_ALGOR_free(x: *mut X509_ALGOR); - - pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); - - pub fn X509_NAME_new() -> *mut X509_NAME; - pub fn X509_NAME_free(x: *mut X509_NAME); - pub fn X509_NAME_add_entry_by_txt( - x: *mut X509_NAME, - field: *const c_char, - ty: c_int, - bytes: *const c_uchar, - len: c_int, - loc: c_int, - set: c_int, - ) -> c_int; - pub fn X509_NAME_get_index_by_NID(n: *mut X509_NAME, nid: c_int, last_pos: c_int) -> c_int; - - pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); - - pub fn ASN1_STRING_free(x: *mut ASN1_STRING); - pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; - - pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER); - - pub fn X509_STORE_new() -> *mut X509_STORE; - pub fn X509_STORE_free(store: *mut X509_STORE); - pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int; - pub fn X509_STORE_set_default_paths(store: *mut X509_STORE) -> c_int; - - pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX); - pub fn X509_STORE_CTX_get_current_cert(ctx: *mut X509_STORE_CTX) -> *mut X509; - pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; - pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; - pub fn X509_STORE_CTX_get_error_depth(ctx: *mut X509_STORE_CTX) -> c_int; - - pub fn X509V3_set_ctx( - ctx: *mut X509V3_CTX, - issuer: *mut X509, - subject: *mut X509, - req: *mut X509_REQ, - crl: *mut X509_CRL, - flags: c_int, - ); - pub fn X509V3_set_nconf(ctx: *mut X509V3_CTX, conf: *mut CONF); - - pub fn X509_REQ_new() -> *mut X509_REQ; - pub fn X509_REQ_set_version(req: *mut X509_REQ, version: c_long) -> c_int; - pub fn X509_REQ_set_subject_name(req: *mut X509_REQ, name: *mut X509_NAME) -> c_int; - pub fn X509_REQ_set_pubkey(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; - pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) - -> c_int; - pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - - #[cfg(not(ossl101))] - pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); - #[cfg(not(any(ossl101, libressl)))] - pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint); - #[cfg(not(any(ossl101, libressl)))] - pub fn X509_VERIFY_PARAM_set1_host( - param: *mut X509_VERIFY_PARAM, - name: *const c_char, - namelen: size_t, - ) -> c_int; - #[cfg(not(any(ossl101, libressl)))] - pub fn X509_VERIFY_PARAM_set1_ip( - param: *mut X509_VERIFY_PARAM, - ip: *const c_uchar, - iplen: size_t, - ) -> c_int; - - pub fn d2i_DHparams(k: *mut *mut DH, pp: *mut *const c_uchar, length: c_long) -> *mut DH; - pub fn i2d_DHparams(dh: *const DH, pp: *mut *mut c_uchar) -> c_int; - - pub fn d2i_DSAPublicKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; - pub fn i2d_DSAPublicKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; - pub fn d2i_DSAPrivateKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) - -> *mut DSA; - pub fn i2d_DSAPrivateKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; - - pub fn d2i_ECPrivateKey( - k: *mut *mut EC_KEY, - pp: *mut *const c_uchar, - length: c_long, - ) -> *mut EC_KEY; - pub fn i2d_ECPrivateKey(ec_key: *mut EC_KEY, pp: *mut *mut c_uchar) -> c_int; - - pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; - pub fn d2i_X509_REQ( - a: *mut *mut X509_REQ, - pp: *mut *const c_uchar, - length: c_long, - ) -> *mut X509_REQ; - pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int; - pub fn i2d_X509(x: *mut X509, buf: *mut *mut u8) -> c_int; - pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int; - pub fn i2d_X509_REQ(x: *mut X509_REQ, buf: *mut *mut u8) -> c_int; - - pub fn d2i_AutoPrivateKey( - a: *mut *mut EVP_PKEY, - pp: *mut *const c_uchar, - length: c_long, - ) -> *mut EVP_PKEY; - pub fn d2i_PUBKEY(k: *mut *mut EVP_PKEY, buf: *mut *const u8, len: c_long) -> *mut EVP_PKEY; - pub fn i2d_PUBKEY_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; - pub fn i2d_PrivateKey_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; - pub fn i2d_PUBKEY(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int; - pub fn i2d_PrivateKey(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int; - - pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *mut *mut u8) -> c_int; - pub fn d2i_RSA_PUBKEY(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; - pub fn i2d_RSAPublicKey(k: *const RSA, buf: *mut *mut u8) -> c_int; - pub fn d2i_RSAPublicKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; - pub fn i2d_RSAPrivateKey(k: *const RSA, buf: *mut *mut u8) -> c_int; - pub fn d2i_RSAPrivateKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; - - pub fn i2d_PKCS12_bio(b: *mut BIO, a: *mut PKCS12) -> c_int; - pub fn i2d_PKCS12(a: *mut PKCS12, buf: *mut *mut u8) -> c_int; - pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12; - pub fn PKCS12_parse( - p12: *mut PKCS12, - pass: *const c_char, - pkey: *mut *mut EVP_PKEY, - cert: *mut *mut X509, - ca: *mut *mut stack_st_X509, - ) -> c_int; - pub fn PKCS12_free(p12: *mut PKCS12); - - pub fn GENERAL_NAME_free(name: *mut GENERAL_NAME); - - pub fn HMAC_Init_ex( - ctx: *mut HMAC_CTX, - key: *const c_void, - len: c_int, - md: *const EVP_MD, - impl_: *mut ENGINE, + rwflag: c_int, + user_data: *mut c_void, ) -> c_int; - pub fn HMAC_Update(ctx: *mut HMAC_CTX, data: *const c_uchar, len: size_t) -> c_int; - pub fn HMAC_Final(ctx: *mut HMAC_CTX, md: *mut c_uchar, len: *mut c_uint) -> c_int; - #[cfg(not(libressl))] - pub fn CMS_decrypt( - cms: *mut CMS_ContentInfo, - pkey: *mut EVP_PKEY, - cert: *mut X509, - dcont: *mut BIO, - out: *mut BIO, - flags: c_uint, - ) -> c_int; - #[cfg(not(libressl))] - pub fn SMIME_read_CMS(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut CMS_ContentInfo; - #[cfg(not(libressl))] - pub fn CMS_ContentInfo_free(cms: *mut CMS_ContentInfo); -} + #[cfg(ossl110)] + pub fn init() { + use std::ptr; + + #[cfg(not(ossl111b))] + let init_options = OPENSSL_INIT_LOAD_SSL_STRINGS; + #[cfg(ossl111b)] + let init_options = OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_NO_ATEXIT; + + INIT.call_once(|| unsafe { + OPENSSL_init_ssl(init_options, ptr::null_mut()); + }) + } + + #[cfg(not(ossl110))] + pub fn init() { + use std::io::{self, Write}; + use std::mem; + use std::process; + use std::sync::{Mutex, MutexGuard}; + + static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; + static mut GUARDS: *mut Vec>> = + 0 as *mut Vec>>; + + unsafe extern "C" fn locking_function( + mode: c_int, + n: c_int, + _file: *const c_char, + _line: c_int, + ) { + let mutex = &(*MUTEXES)[n as usize]; + + if mode & CRYPTO_LOCK != 0 { + (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); + } else { + if let None = (*GUARDS)[n as usize].take() { + let _ = writeln!( + io::stderr(), + "BUG: rust-openssl lock {} already unlocked, aborting", + n + ); + process::abort(); + } + } + } + + cfg_if! { + if #[cfg(unix)] { + fn set_id_callback() { + unsafe extern "C" fn thread_id() -> c_ulong { + ::libc::pthread_self() as c_ulong + } + + unsafe { + CRYPTO_set_id_callback__fixed_rust(Some(thread_id)); + } + } + } else { + fn set_id_callback() {} + } + } + + INIT.call_once(|| unsafe { + SSL_library_init(); + SSL_load_error_strings(); + OPENSSL_add_all_algorithms_noconf(); + + let num_locks = CRYPTO_num_locks(); + let mut mutexes = Box::new(Vec::new()); + for _ in 0..num_locks { + mutexes.push(Mutex::new(())); + } + MUTEXES = mem::transmute(mutexes); + let guards: Box>>> = + Box::new((0..num_locks).map(|_| None).collect()); + GUARDS = mem::transmute(guards); + + CRYPTO_set_locking_callback__fixed_rust(Some(locking_function)); + set_id_callback(); + }) + } + + /// Disable explicit initialization of the openssl libs. + /// + /// This is only appropriate to use if the openssl crate is being consumed by an application + /// that will be performing the initialization explicitly. + /// + /// # Safety + /// + /// In some versions of openssl, skipping initialization will fall back to the default procedure + /// while other will cause difficult to debug errors so care must be taken when calling this. + pub unsafe fn assume_init() { + INIT.call_once(|| {}); + } +} +#[cfg(openssl)] +pub use openssl::*; diff --git a/openssl-sys/src/libressl/mod.rs b/openssl-sys/src/libressl/mod.rs deleted file mode 100644 index 7eb119c..0000000 --- a/openssl-sys/src/libressl/mod.rs +++ /dev/null @@ -1,600 +0,0 @@ -use std::sync::{Mutex, MutexGuard}; -use std::sync::{Once, ONCE_INIT}; -use std::mem; -use std::ptr; - -#[cfg(libressl250)] -pub use libressl::v250::*; -#[cfg(not(libressl250))] -pub use libressl::v25x::*; - -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; - -#[cfg(libressl250)] -mod v250; -#[cfg(not(libressl250))] -mod v25x; - -#[repr(C)] -pub struct stack_st_ASN1_OBJECT { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509 { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509_NAME { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509_ATTRIBUTE { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509_EXTENSION { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_GENERAL_NAME { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_void { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_SSL_CIPHER { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_OPENSSL_STRING { - pub stack: _STACK, -} - -#[repr(C)] -pub struct _STACK { - pub num: c_int, - pub data: *mut *mut c_char, - pub sorted: c_int, - pub num_alloc: c_int, - pub comp: Option c_int>, -} - -#[repr(C)] -pub struct BIO_METHOD { - pub type_: c_int, - pub name: *const c_char, - pub bwrite: Option c_int>, - pub bread: Option c_int>, - pub bputs: Option c_int>, - pub bgets: Option c_int>, - pub ctrl: Option c_long>, - pub create: Option c_int>, - pub destroy: Option c_int>, - pub callback_ctrl: Option c_long>, -} - -#[repr(C)] -pub struct RSA { - pub pad: c_int, - pub version: c_long, - pub meth: *const ::RSA_METHOD, - - pub engine: *mut ::ENGINE, - pub n: *mut ::BIGNUM, - pub e: *mut ::BIGNUM, - pub d: *mut ::BIGNUM, - pub p: *mut ::BIGNUM, - pub q: *mut ::BIGNUM, - pub dmp1: *mut ::BIGNUM, - pub dmq1: *mut ::BIGNUM, - pub iqmp: *mut ::BIGNUM, - - pub ex_data: ::CRYPTO_EX_DATA, - pub references: c_int, - pub flags: c_int, - - pub _method_mod_n: *mut ::BN_MONT_CTX, - pub _method_mod_p: *mut ::BN_MONT_CTX, - pub _method_mod_q: *mut ::BN_MONT_CTX, - - pub blinding: *mut ::BN_BLINDING, - pub mt_blinding: *mut ::BN_BLINDING, -} - -#[repr(C)] -pub struct DSA { - pub pad: c_int, - pub version: c_long, - pub write_params: c_int, - - pub p: *mut ::BIGNUM, - pub q: *mut ::BIGNUM, - pub g: *mut ::BIGNUM, - pub pub_key: *mut ::BIGNUM, - pub priv_key: *mut ::BIGNUM, - pub kinv: *mut ::BIGNUM, - pub r: *mut ::BIGNUM, - - pub flags: c_int, - pub method_mont_p: *mut ::BN_MONT_CTX, - pub references: c_int, - pub ex_data: ::CRYPTO_EX_DATA, - pub meth: *const ::DSA_METHOD, - pub engine: *mut ::ENGINE, -} - -#[repr(C)] -pub struct EVP_PKEY { - pub type_: c_int, - pub save_type: c_int, - pub references: c_int, - pub ameth: *const ::EVP_PKEY_ASN1_METHOD, - pub engine: *mut ::ENGINE, - pub pkey: *mut c_void, - pub save_parameters: c_int, - pub attributes: *mut stack_st_X509_ATTRIBUTE, -} - -#[repr(C)] -pub struct BIO { - pub method: *mut ::BIO_METHOD, - pub callback: Option< - unsafe extern "C" fn(*mut ::BIO, - c_int, - *const c_char, - c_int, - c_long, - c_long) - -> c_long, - >, - pub cb_arg: *mut c_char, - pub init: c_int, - pub shutdown: c_int, - pub flags: c_int, - pub retry_reason: c_int, - pub num: c_int, - pub ptr: *mut c_void, - pub next_bio: *mut ::BIO, - pub prev_bio: *mut ::BIO, - pub references: c_int, - pub num_read: c_ulong, - pub num_write: c_ulong, - pub ex_data: ::CRYPTO_EX_DATA, -} - -#[repr(C)] -pub struct CRYPTO_EX_DATA { - pub sk: *mut ::stack_st_void, -} - -#[repr(C)] -pub struct EVP_MD_CTX { - digest: *mut ::EVP_MD, - engine: *mut ::ENGINE, - flags: c_ulong, - md_data: *mut c_void, - pctx: *mut ::EVP_PKEY_CTX, - update: *mut c_void, -} - -#[repr(C)] -pub struct EVP_CIPHER { - pub nid: c_int, - pub block_size: c_int, - pub key_len: c_int, - pub iv_len: c_int, - pub flags: c_ulong, - pub init: Option< - unsafe extern "C" fn(*mut ::EVP_CIPHER_CTX, - *const c_uchar, - *const c_uchar, - c_int) - -> c_int, - >, - pub do_cipher: Option< - unsafe extern "C" fn(*mut ::EVP_CIPHER_CTX, - *mut c_uchar, - *const c_uchar, - size_t) - -> c_int, - >, - pub cleanup: Option c_int>, - pub ctx_size: c_int, - pub set_asn1_parameters: - Option c_int>, - pub get_asn1_parameters: - Option c_int>, - pub ctrl: - Option c_int>, - pub app_data: *mut c_void, -} - -#[repr(C)] -pub struct HMAC_CTX { - md: *mut ::EVP_MD, - md_ctx: ::EVP_MD_CTX, - i_ctx: ::EVP_MD_CTX, - o_ctx: ::EVP_MD_CTX, - key_length: c_uint, - key: [c_uchar; 128], -} - -#[repr(C)] -pub struct BIGNUM { - pub d: *mut ::BN_ULONG, - pub top: c_int, - pub dmax: c_int, - pub neg: c_int, - pub flags: c_int, -} - -#[repr(C)] -pub struct DH { - pub pad: c_int, - pub version: c_int, - pub p: *mut ::BIGNUM, - pub g: *mut ::BIGNUM, - pub length: c_long, - pub pub_key: *mut ::BIGNUM, - pub priv_key: *mut ::BIGNUM, - pub flags: c_int, - pub method_mont_p: *mut ::BN_MONT_CTX, - pub q: *mut ::BIGNUM, - pub j: *mut ::BIGNUM, - pub seed: *mut c_uchar, - pub seedlen: c_int, - pub counter: *mut ::BIGNUM, - pub references: c_int, - pub ex_data: ::CRYPTO_EX_DATA, - pub meth: *const ::DH_METHOD, - pub engine: *mut ::ENGINE, -} - -#[repr(C)] -pub struct X509 { - pub cert_info: *mut X509_CINF, - pub sig_alg: *mut ::X509_ALGOR, - pub signature: *mut ::ASN1_BIT_STRING, - pub valid: c_int, - pub references: c_int, - pub name: *mut c_char, - pub ex_data: ::CRYPTO_EX_DATA, - pub ex_pathlen: c_long, - pub ex_pcpathlen: c_long, - pub ex_flags: c_ulong, - pub ex_kusage: c_ulong, - pub ex_xkusage: c_ulong, - pub ex_nscert: c_ulong, - skid: *mut c_void, - akid: *mut c_void, - policy_cache: *mut c_void, - crldp: *mut c_void, - altname: *mut c_void, - nc: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] - sha1_hash: [c_uchar; 20], - aux: *mut c_void, -} - -#[repr(C)] -pub struct X509_CINF { - version: *mut c_void, - serialNumber: *mut c_void, - signature: *mut c_void, - issuer: *mut c_void, - pub validity: *mut X509_VAL, - subject: *mut c_void, - key: *mut c_void, - issuerUID: *mut c_void, - subjectUID: *mut c_void, - pub extensions: *mut stack_st_X509_EXTENSION, - enc: ASN1_ENCODING, -} - -#[repr(C)] -pub struct X509_ALGOR { - pub algorithm: *mut ::ASN1_OBJECT, - parameter: *mut c_void, -} - -#[repr(C)] -pub struct ASN1_ENCODING { - pub enc: *mut c_uchar, - pub len: c_long, - pub modified: c_int, -} - -#[repr(C)] -pub struct X509_VAL { - pub notBefore: *mut ::ASN1_TIME, - pub notAfter: *mut ::ASN1_TIME, -} - -#[repr(C)] -pub struct X509_REQ_INFO { - pub enc: ASN1_ENCODING, - pub version: *mut ::ASN1_INTEGER, - pub subject: *mut ::X509_NAME, - pubkey: *mut c_void, - pub attributes: *mut stack_st_X509_ATTRIBUTE, -} - -#[repr(C)] -pub struct X509_REQ { - pub req_info: *mut X509_REQ_INFO, - sig_alg: *mut c_void, - signature: *mut c_void, - references: c_int, -} - -pub enum X509_VERIFY_PARAM_ID {} -pub enum PKCS12 {} - -pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8; -pub const SSL_CTRL_OPTIONS: c_int = 32; -pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; -pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; - -#[cfg(any(libressl261, libressl262, libressl26x))] -pub const SSL_OP_ALL: c_ulong = 0x4; -#[cfg(not(any(libressl261, libressl262, libressl26x)))] -pub const SSL_OP_ALL: c_ulong = 0x80000014; -pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x0; -pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x0; -pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x0; -pub const SSL_OP_NO_SSLv3: c_ulong = 0x0; -pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x0; -pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x0; -pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x0; -pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x0; -pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x0; -pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x0; -pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x0; -#[cfg(any(libressl261, libressl262, libressl26x))] -pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x0; -#[cfg(not(any(libressl261, libressl262, libressl26x)))] -pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; -pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; -pub const SSL_OP_NO_SSLv2: c_ulong = 0x0; - -pub const SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32; -pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32; -pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48; - -pub const SSLEAY_VERSION: c_int = 0; -pub const SSLEAY_CFLAGS: c_int = 2; -pub const SSLEAY_BUILT_ON: c_int = 3; -pub const SSLEAY_PLATFORM: c_int = 4; -pub const SSLEAY_DIR: c_int = 5; - -pub const CRYPTO_LOCK_X509: c_int = 3; -pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; -pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14; - -static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; -static mut GUARDS: *mut Vec>> = 0 as - *mut Vec>>; - -unsafe extern "C" fn locking_function(mode: c_int, n: c_int, _file: *const c_char, _line: c_int) { - let mutex = &(*MUTEXES)[n as usize]; - - if mode & ::CRYPTO_LOCK != 0 { - (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); - } else { - &(*GUARDS)[n as usize].take().expect("lock already unlocked"); - } -} - -pub fn init() { - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| unsafe { - SSL_library_init(); - SSL_load_error_strings(); - OPENSSL_add_all_algorithms_noconf(); - - let num_locks = ::CRYPTO_num_locks(); - let mut mutexes = Box::new(Vec::new()); - for _ in 0..num_locks { - mutexes.push(Mutex::new(())); - } - MUTEXES = mem::transmute(mutexes); - let guards: Box>>> = - Box::new((0..num_locks).map(|_| None).collect()); - GUARDS = mem::transmute(guards); - - CRYPTO_set_locking_callback(locking_function); - set_id_callback(); - }) -} - -#[cfg(unix)] -fn set_id_callback() { - unsafe extern "C" fn thread_id() -> c_ulong { - ::libc::pthread_self() as c_ulong - } - - unsafe { - CRYPTO_set_id_callback(thread_id); - } -} - -#[cfg(not(unix))] -fn set_id_callback() {} - -// macros - -pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { - ::SSL_CTX_ctrl( - ctx, - SSL_CTRL_SET_ECDH_AUTO, - onoff as c_long, - ptr::null_mut(), - ) as c_int -} - -pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { - ::SSL_ctrl( - ssl, - SSL_CTRL_SET_ECDH_AUTO, - onoff as c_long, - ptr::null_mut(), - ) as c_int -} - -pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { - ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int -} - -extern "C" { - pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; - pub fn BIO_s_file() -> *mut BIO_METHOD; - pub fn BIO_s_mem() -> *mut BIO_METHOD; - - pub fn get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; - - pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void; - pub fn CRYPTO_free(buf: *mut c_void); - pub fn CRYPTO_num_locks() -> c_int; - pub fn CRYPTO_set_locking_callback( - func: unsafe extern "C" fn(mode: c_int, n: c_int, file: *const c_char, line: c_int), - ); - pub fn CRYPTO_set_id_callback(func: unsafe extern "C" fn() -> c_ulong); - - pub fn ERR_load_crypto_strings(); - - pub fn RSA_generate_key( - modsz: c_int, - e: c_ulong, - cb: Option, - cbarg: *mut c_void, - ) -> *mut RSA; - - pub fn OCSP_cert_to_id( - dgst: *const ::EVP_MD, - subject: *mut ::X509, - issuer: *mut ::X509, - ) -> *mut ::OCSP_CERTID; - - pub fn PKCS12_create( - pass: *mut c_char, - friendly_name: *mut c_char, - pkey: *mut EVP_PKEY, - cert: *mut X509, - ca: *mut stack_st_X509, - nid_key: c_int, - nid_cert: c_int, - iter: c_int, - mac_iter: c_int, - keytype: c_int, - ) -> *mut PKCS12; - - pub fn SSL_library_init() -> c_int; - pub fn SSL_load_error_strings(); - pub fn OPENSSL_add_all_algorithms_noconf(); - pub fn HMAC_CTX_init(ctx: *mut ::HMAC_CTX); - pub fn HMAC_CTX_cleanup(ctx: *mut ::HMAC_CTX); - pub fn TLSv1_method() -> *const ::SSL_METHOD; - pub fn SSLv23_method() -> *const ::SSL_METHOD; - pub fn TLSv1_1_method() -> *const ::SSL_METHOD; - pub fn TLSv1_2_method() -> *const ::SSL_METHOD; - pub fn DTLSv1_method() -> *const ::SSL_METHOD; - pub fn SSL_get_ex_new_index( - argl: c_long, - argp: *mut c_void, - new_func: Option<::CRYPTO_EX_new>, - dup_func: Option<::CRYPTO_EX_dup>, - free_func: Option<::CRYPTO_EX_free>, - ) -> c_int; - pub fn SSL_set_tmp_ecdh_callback( - ssl: *mut ::SSL, - ecdh: unsafe extern "C" fn(ssl: *mut ::SSL, is_export: c_int, keylength: c_int) - -> *mut ::EC_KEY, - ); - pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *mut c_char; - pub fn SSL_CTX_get_ex_new_index( - argl: c_long, - argp: *mut c_void, - new_func: Option<::CRYPTO_EX_new>, - dup_func: Option<::CRYPTO_EX_dup>, - free_func: Option<::CRYPTO_EX_free>, - ) -> c_int; - pub fn SSL_CTX_set_tmp_ecdh_callback( - ctx: *mut ::SSL_CTX, - ecdh: unsafe extern "C" fn(ssl: *mut ::SSL, is_export: c_int, keylength: c_int) - -> *mut ::EC_KEY, - ); - pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; - pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_get_ext_d2i( - x: *mut ::X509, - nid: c_int, - crit: *mut c_int, - idx: *mut c_int, - ) -> *mut c_void; - pub fn X509_NAME_add_entry_by_NID( - x: *mut ::X509_NAME, - field: c_int, - ty: c_int, - bytes: *mut c_uchar, - len: c_int, - loc: c_int, - set: c_int, - ) -> c_int; - pub fn X509_NAME_get_entry(n: *mut ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; - pub fn X509_NAME_ENTRY_get_data(ne: *mut ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; - pub fn X509_STORE_CTX_get_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; - pub fn X509V3_EXT_nconf_nid( - conf: *mut ::CONF, - ctx: *mut ::X509V3_CTX, - ext_nid: c_int, - value: *mut c_char, - ) -> *mut ::X509_EXTENSION; - pub fn X509V3_EXT_nconf( - conf: *mut ::CONF, - ctx: *mut ::X509V3_CTX, - name: *mut c_char, - value: *mut c_char, - ) -> *mut ::X509_EXTENSION; - pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ::ASN1_STRING) -> c_int; - pub fn ASN1_STRING_data(x: *mut ::ASN1_STRING) -> *mut c_uchar; - pub fn CRYPTO_add_lock( - pointer: *mut c_int, - amount: c_int, - type_: c_int, - file: *const c_char, - line: c_int, - ) -> c_int; - pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; - pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); - pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int; - - pub fn sk_new_null() -> *mut _STACK; - pub fn sk_num(st: *const _STACK) -> c_int; - pub fn sk_value(st: *const _STACK, n: c_int) -> *mut c_void; - pub fn sk_free(st: *mut _STACK); - pub fn sk_push(st: *mut _STACK, data: *mut c_void) -> c_int; - pub fn sk_pop_free(st: *mut _STACK, free: Option); - pub fn sk_pop(st: *mut _STACK) -> *mut c_void; - - pub fn SSLeay() -> c_ulong; - pub fn SSLeay_version(key: c_int) -> *const c_char; -} diff --git a/openssl-sys/src/libressl/v250.rs b/openssl-sys/src/libressl/v250.rs deleted file mode 100644 index e844ffe..0000000 --- a/openssl-sys/src/libressl/v250.rs +++ /dev/null @@ -1,221 +0,0 @@ -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong, time_t}; - -use super::*; - -#[repr(C)] -pub struct SSL { - version: c_int, - type_: c_int, - method: *const ::SSL_METHOD, - rbio: *mut c_void, - wbio: *mut c_void, - bbio: *mut c_void, - rwstate: c_int, - in_handshake: c_int, - handshake_func: Option c_int>, - pub server: c_int, - new_session: c_int, - quiet_shutdown: c_int, - shutdown: c_int, - state: c_int, - rstate: c_int, - init_buf: *mut c_void, - init_msg: *mut c_void, - init_num: c_int, - init_off: c_int, - packet: *mut c_uchar, - packet_length: c_uint, - s3: *mut c_void, - d1: *mut c_void, - read_ahead: c_int, - msg_callback: Option< - unsafe extern "C" fn(c_int, - c_int, - c_int, - *const c_void, - size_t, - *mut SSL, - *mut c_void), - >, - msg_callback_arg: *mut c_void, - hit: c_int, - param: *mut c_void, - cipher_list: *mut stack_st_SSL_CIPHER, - cipher_list_by_id: *mut stack_st_SSL_CIPHER, - mac_flags: c_int, - aead_read_ctx: *mut c_void, - enc_read_ctx: *mut ::EVP_CIPHER_CTX, - read_hash: *mut ::EVP_MD_CTX, - aead_write_ctx: *mut c_void, - enc_write_ctx: *mut ::EVP_CIPHER_CTX, - write_hash: *mut ::EVP_MD_CTX, - cert: *mut c_void, - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - session: *mut ::SSL_SESSION, - generate_session_id: ::GEN_SESSION_CB, - verify_mode: c_int, - verify_callback: Option c_int>, - info_callback: Option, - error: c_int, - error_code: c_int, - ctx: *mut ::SSL_CTX, - debug: c_int, - verify_result: c_long, - ex_data: ::CRYPTO_EX_DATA, - client_CA: *mut stack_st_X509_NAME, - references: c_int, - options: c_ulong, - mode: c_ulong, - max_cert_list: c_long, - first_packet: c_int, - client_version: c_int, - max_send_fragment: c_uint, - tlsext_debug_cb: - Option, - tlsext_debug_arg: *mut c_void, - tlsext_hostname: *mut c_char, - servername_done: c_int, - tlsext_status_type: c_int, - tlsext_status_expected: c_int, - tlsext_ocsp_ids: *mut c_void, - tlsext_ocsp_exts: *mut c_void, - tlsext_ocsp_resp: *mut c_uchar, - tlsext_ocsp_resplen: c_int, - tlsext_ticket_expected: c_int, - tlsext_ecpointformatlist_length: size_t, - tlsext_ecpointformatlist: *mut c_uchar, - tlsext_ellipticcurvelist_length: size_t, - tlsext_ellipticcurvelist: *mut c_uchar, - tlsext_session_ticket: *mut c_void, - tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, - tls_session_ticket_ext_cb_arg: *mut c_void, - tls_session_secret_cb: ::tls_session_secret_cb_fn, - tls_session_secret_cb_arg: *mut c_void, - initial_ctx: *mut ::SSL_CTX, - next_proto_negotiated: *mut c_uchar, - next_proto_negotiated_len: c_uchar, - srtp_profiles: *mut c_void, - srtp_profile: *mut c_void, - tlsext_heartbeat: c_uint, - tlsext_hb_pending: c_uint, - tlsext_hb_seq: c_uint, - alpn_client_proto_list: *mut c_uchar, - alpn_client_proto_list_len: c_uint, - renegotiate: c_int, -} - -#[repr(C)] -pub struct SSL_CTX { - method: *mut c_void, - cipher_list: *mut c_void, - cipher_list_by_id: *mut c_void, - cert_store: *mut c_void, - sessions: *mut c_void, - session_cache_size: c_ulong, - session_cache_head: *mut c_void, - session_cache_tail: *mut c_void, - session_cache_mode: c_int, - session_timeout: c_long, - new_session_cb: *mut c_void, - remove_session_cb: *mut c_void, - get_session_cb: *mut c_void, - stats: [c_int; 11], - pub references: c_int, - app_verify_callback: *mut c_void, - app_verify_arg: *mut c_void, - default_passwd_callback: *mut c_void, - default_passwd_callback_userdata: *mut c_void, - client_cert_cb: *mut c_void, - app_gen_cookie_cb: *mut c_void, - app_verify_cookie_cb: *mut c_void, - ex_dat: ::CRYPTO_EX_DATA, - rsa_md5: *mut c_void, - md5: *mut c_void, - sha1: *mut c_void, - extra_certs: *mut c_void, - comp_methods: *mut c_void, - info_callback: *mut c_void, - client_CA: *mut c_void, - options: c_ulong, - mode: c_ulong, - max_cert_list: c_long, - cert: *mut c_void, - read_ahead: c_int, - msg_callback: *mut c_void, - msg_callback_arg: *mut c_void, - verify_mode: c_int, - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; 32], - default_verify_callback: *mut c_void, - generate_session_id: *mut c_void, - param: *mut c_void, - quiet_shutdown: c_int, - max_send_fragment: c_uint, - - #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] - client_cert_engine: *mut c_void, - - tlsext_servername_callback: *mut c_void, - tlsect_servername_arg: *mut c_void, - tlsext_tick_key_name: [c_uchar; 16], - tlsext_tick_hmac_key: [c_uchar; 16], - tlsext_tick_aes_key: [c_uchar; 16], - tlsext_ticket_key_cb: *mut c_void, - tlsext_status_cb: *mut c_void, - tlsext_status_arg: *mut c_void, - tlsext_opaque_prf_input_callback: *mut c_void, - tlsext_opaque_prf_input_callback_arg: *mut c_void, - - next_protos_advertised_cb: *mut c_void, - next_protos_advertised_cb_arg: *mut c_void, - next_proto_select_cb: *mut c_void, - next_proto_select_cb_arg: *mut c_void, - - srtp_profiles: *mut c_void, -} - -#[repr(C)] -pub struct SSL_SESSION { - ssl_version: c_int, - pub master_key_length: c_int, - pub master_key: [c_uchar; 48], - session_id_length: c_uint, - session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], - not_resumable: c_int, - sess_cert: *mut c_void, - peer: *mut X509, - verify_result: c_long, - timeout: c_long, - time: time_t, - pub references: c_int, - cipher: *const c_void, - cipher_id: c_ulong, - ciphers: *mut c_void, - ex_data: ::CRYPTO_EX_DATA, - prev: *mut c_void, - next: *mut c_void, - tlsext_hostname: *mut c_char, - tlsext_ecpointformatlist_length: size_t, - tlsext_ecpointformatlist: *mut u8, - tlsext_ellipticcurvelist_length: size_t, - tlsext_ellipticcurvelist: *mut u16, - tlsext_tick: *mut c_uchar, - tlsext_ticklen: size_t, - tlsext_tick_lifetime_hint: c_long, -} - -#[repr(C)] -pub struct X509_VERIFY_PARAM { - pub name: *mut c_char, - pub check_time: time_t, - pub inh_flags: c_ulong, - pub flags: c_ulong, - pub purpose: c_int, - pub trust: c_int, - pub depth: c_int, - pub policies: *mut stack_st_ASN1_OBJECT, - //pub id: *mut X509_VERIFY_PARAM_ID, -} diff --git a/openssl-sys/src/libressl/v25x.rs b/openssl-sys/src/libressl/v25x.rs deleted file mode 100644 index 7e7023e..0000000 --- a/openssl-sys/src/libressl/v25x.rs +++ /dev/null @@ -1,89 +0,0 @@ -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong, time_t}; - -use super::*; - -#[repr(C)] -pub struct SSL { - version: c_int, - method: *const ::SSL_METHOD, - rbio: *mut ::BIO, - wbio: *mut ::BIO, - bbio: *mut ::BIO, - pub server: c_int, - s3: *mut c_void, - d1: *mut c_void, - param: *mut c_void, - cipher_list: *mut stack_st_SSL_CIPHER, - cert: *mut c_void, - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - session: *mut ::SSL_SESSION, - verify_mode: c_int, - error: c_int, - error_code: c_int, - ctx: *mut ::SSL_CTX, - verify_result: c_long, - references: c_int, - client_version: c_int, - max_send_fragment: c_uint, - tlsext_hostname: *mut c_char, - tlsext_status_type: c_int, - initial_ctx: *mut ::SSL_CTX, - enc_read_ctx: *mut ::EVP_CIPHER_CTX, - read_hash: *mut EVP_MD_CTX, - internal: *mut c_void, -} - -#[repr(C)] -pub struct SSL_CTX { - method: *const ::SSL_METHOD, - cipher_list: *mut stack_st_SSL_CIPHER, - cert_store: *mut c_void, - session_timeout: c_long, - pub references: c_int, - extra_certs: *mut stack_st_X509, - verify_mode: c_int, - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - param: *mut ::X509_VERIFY_PARAM, - default_passwd_callback: *mut c_void, - default_passwd_callback_userdata: *mut c_void, - internal: *mut c_void, -} - -#[repr(C)] -pub struct SSL_SESSION { - ssl_version: c_int, - pub master_key_length: c_int, - pub master_key: [c_uchar; 48], - session_id_length: c_uint, - session_id: [c_uchar; ::SSL_MAX_SSL_SESSION_ID_LENGTH as usize], - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - peer: *mut ::X509, - verify_result: c_long, - timeout: c_long, - time: time_t, - pub references: c_int, - cipher: *const ::SSL_CIPHER, - cipher_id: c_long, - ciphers: *mut stack_st_SSL_CIPHER, - tlsext_hostname: *mut c_char, - tlsext_tick: *mut c_uchar, - tlsext_ticklen: size_t, - tlsext_tick_lifetime_int: c_long, - internal: *mut c_void, -} - -#[repr(C)] -pub struct X509_VERIFY_PARAM { - pub name: *mut c_char, - pub check_time: time_t, - pub inh_flags: c_ulong, - pub flags: c_ulong, - pub purpose: c_int, - pub trust: c_int, - pub depth: c_int, - policies: *mut stack_st_ASN1_OBJECT, - id: *mut c_void, -} diff --git a/openssl-sys/src/macros.rs b/openssl-sys/src/macros.rs new file mode 100644 index 0000000..e1b08c4 --- /dev/null +++ b/openssl-sys/src/macros.rs @@ -0,0 +1,298 @@ +#![allow(unused_macros)] + +// vendored from the cfg-if crate to avoid breaking ctest +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +macro_rules! stack { + ($t:ident) => { + cfg_if! { + if #[cfg(ossl110)] { + pub enum $t {} + } else { + #[repr(C)] + pub struct $t { + pub stack: $crate::_STACK, + } + } + } + }; +} + +#[cfg(const_fn)] +macro_rules! const_fn { + ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { + $( + pub const fn $name($($arg: $t),*) -> $ret $b + )* + } +} + +#[cfg(not(const_fn))] +macro_rules! const_fn { + ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { + $( + pub fn $name($($arg: $t),*) -> $ret $b + )* + } +} + +// openssl changes `*mut` to `*const` in certain parameters in certain versions; +// in C this is ABI and (mostly) API compatible. +// +// We need to handle this explicitly, and this macro helps annotate which +// parameter got converted in which version. +// +// Input is: +// extern "C" { +// #[attributes...] +// pub fn name(args) -> rettype; // `-> rettype` optional +// // more functions... +// } +// +// This macro replaces `#[const_ptr_if(...)]` in types with `*const` or `*mut` +// (depending on the inner cfg flags) +// +// Walks through all argument and return types, but only finds inner types of +// `*const` and `*mut`; doesn't walk arrays or generics. +// +// NOTE: can't abstract `pub` as `$fn_vis:vis`, as ctest macro handling doesn't +// support it (old syntax crate). But we really only need `pub` anyway. +// +// NOTE: ctest seams to simply ignore macros it can't expand (whatever the +// reason) +macro_rules! const_ptr_api { + // ---------------------------------------------------------------- + // (partialarg): partial argument, waiting for "final" argument type + // MAGIC PART 1: hande conditional const ptr in argument type + ( (partialarg) + { $(#[$fn_attr:meta])* pub fn $fn_name:ident } + $args_packed:tt + [ $($part_arg:tt)* ] + [ #[const_ptr_if( $($cfg:tt)* )] $($arg_rem:tt)* ] + $ret_packed:tt + ) => { + const_ptr_api!( (partialarg) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed ); + const_ptr_api!( (partialarg) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed ); + }; + // continue partial argument with `*mut` pointer (might need special const handling in inner type) + ( (partialarg) + $def_packed:tt + $args_packed:tt + [ $($part_arg:tt)* ] + [ *mut $($arg_rem:tt)* ] + $ret_packed:tt + ) => { + const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed ); + }; + // continue partial argument with `*const` pointer (might need special const handling in inner type) + ( (partialarg) + $def_packed:tt + $args_packed:tt + [ $($part_arg:tt)* ] + [ *const $($arg_rem:tt)* ] + $ret_packed:tt + ) => { + const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed ); + }; + // finish partial argument with trailing comma + ( (partialarg) + $def_packed:tt + { $($args_tt:tt)* } + [ $($part_arg:tt)* ] + [ $arg_ty:ty, $($arg_rem:tt)* ] + $ret_packed:tt + ) => { + const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ $($arg_rem)* ] $ret_packed ); + }; + // finish final partial argument (no trailing comma) + ( (partialarg) + $def_packed:tt + { $($args_tt:tt)* } + [ $($part_arg:tt)* ] + [ $arg_ty:ty ] + $ret_packed:tt + ) => { + const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ ] $ret_packed ); + }; + + // ---------------------------------------------------------------- + // (parseargs): parsing arguments + // start next argument + ( (parseargs) + $def_packed:tt + $args_packed:tt + [ $arg_name:ident : $($arg_rem:tt)* ] + $ret_packed:tt + ) => { + const_ptr_api!( (partialarg) $def_packed $args_packed [ $arg_name: ] [ $($arg_rem)* ] $ret_packed ); + }; + // end of arguments, there is a return type; start parsing it + ( (parseargs) + $def_packed:tt + $args_packed:tt + [ ] + [ -> $($rem:tt)* ] + ) => { + const_ptr_api!( (partialret) $def_packed $args_packed [] [ $($rem)* ] ); + }; + // end of arguments, no return type + ( (parseargs) + $def_packed:tt + $args_packed:tt + [ ] + [ ] + ) => { + const_ptr_api!( (generate) $def_packed $args_packed { () } ); + }; + + // ---------------------------------------------------------------- + // (partialret): have partial return type, waiting for final return type + // MAGIC PART 2: hande conditional const ptr in return type + ( (partialret) + { $(#[$fn_attr:meta])* pub fn $fn_name:ident } + $args_packed:tt + [ $($part_ret:tt)* ] + [ #[const_ptr_if( $($cfg:tt)* )] $($rem:tt)* ] + ) => { + const_ptr_api!( (partialret) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *const ] [ $($rem)* ] ); + const_ptr_api!( (partialret) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] ); + }; + // `* mut` part in return type; continue parsing to find inner conditional const ptr + ( (partialret) + $def_packed:tt + $args_packed:tt + [ $($part_ret:tt)* ] + [ *mut $($rem:tt)* ] + ) => { + const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] ); + }; + // `* const` part in return type; continue parsing to find inner conditional const ptr + ( (partialret) + $def_packed:tt + $args_packed:tt + [ $($part_ret:tt)* ] + [ *const $($rem:tt)* ] + ) => { + const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *const ] [ $($rem)* ] ); + }; + // final part of return type + ( (partialret) + $def_packed:tt + $args_packed:tt + [ $($part_ret:tt)* ] + [ $ret_ty:ty ] + ) => { + const_ptr_api!( (generate) $def_packed $args_packed { $($part_ret)* $ret_ty } ); + }; + + // ---------------------------------------------------------------- + // generate + ( (generate) + { $(#[$fn_attr:meta])* pub fn $fn_name:ident } + { $({ $arg_name:ident: $($arg_ty:tt)* })* } + { $ret_ty:ty } + ) => { + extern "C" { + $(#[$fn_attr])* + pub fn $fn_name( $( + $arg_name: $($arg_ty)* + ),* ) -> $ret_ty; + } + }; + + // ---------------------------------------------------------------- + // (fn): gather tokens for return type until ";" + // found end; start parsing current function, and parse remaining functions + ( (fn) + $def_packed:tt + $arg_tts_packed:tt + $ret_packed:tt + [ ; $($rem:tt)* ] + ) => { + const_ptr_api!( (parseargs) $def_packed {} $arg_tts_packed $ret_packed ); + const_ptr_api!( (extern) [ $($rem)* ] ); + }; + // not ";" - all other tokens are part of the return type. + // don't expand return type yet; otherwise we'd have to remember in which branch `rem` needs + // to be used to parse further functions. + ( (fn) + $def_packed:tt + $arg_tts_packed:tt + [ $($ret_tt:tt)* ] + [ $tt:tt $($rem:tt)* ] + ) => { + const_ptr_api!( (fn) $def_packed $arg_tts_packed [ $($ret_tt)* $tt ] [ $($rem)* ] ); + }; + + // ---------------------------------------------------------------- + // (extern): in extern block, find next function + // try to split into functions as fast as possible to reduce recursion depth + ( (extern) [ + $(#[$fn_attr:meta])* + pub fn $fn_name:ident( $($arg_rem:tt)* ) $($rem:tt)* + ] ) => { + const_ptr_api!( (fn) + { $(#[$fn_attr])* pub fn $fn_name } [ $($arg_rem)* ] [] [ $($rem)* ] + ); + }; + // end of extern block + ( (extern) [] ) => {}; + + // ---------------------------------------------------------------- + // macro start; find extern block + ( extern "C" { $($rem:tt)* } ) => { + const_ptr_api!( (extern) [ $($rem)* ] ); + }; +} diff --git a/openssl-sys/src/obj_mac.rs b/openssl-sys/src/obj_mac.rs new file mode 100644 index 0000000..1f8e100 --- /dev/null +++ b/openssl-sys/src/obj_mac.rs @@ -0,0 +1,982 @@ +use libc::*; + +pub const NID_undef: c_int = 0; +pub const NID_itu_t: c_int = 645; +pub const NID_ccitt: c_int = 404; +pub const NID_iso: c_int = 181; +pub const NID_joint_iso_itu_t: c_int = 646; +pub const NID_joint_iso_ccitt: c_int = 393; +pub const NID_member_body: c_int = 182; +pub const NID_identified_organization: c_int = 676; +pub const NID_hmac_md5: c_int = 780; +pub const NID_hmac_sha1: c_int = 781; +pub const NID_certicom_arc: c_int = 677; +pub const NID_international_organizations: c_int = 647; +pub const NID_wap: c_int = 678; +pub const NID_wap_wsg: c_int = 679; +pub const NID_selected_attribute_types: c_int = 394; +pub const NID_clearance: c_int = 395; +pub const NID_ISO_US: c_int = 183; +pub const NID_X9_57: c_int = 184; +pub const NID_X9cm: c_int = 185; +pub const NID_dsa: c_int = 116; +pub const NID_dsaWithSHA1: c_int = 113; +pub const NID_ansi_X9_62: c_int = 405; +pub const NID_X9_62_prime_field: c_int = 406; +pub const NID_X9_62_characteristic_two_field: c_int = 407; +pub const NID_X9_62_id_characteristic_two_basis: c_int = 680; +pub const NID_X9_62_onBasis: c_int = 681; +pub const NID_X9_62_tpBasis: c_int = 682; +pub const NID_X9_62_ppBasis: c_int = 683; +pub const NID_X9_62_id_ecPublicKey: c_int = 408; +pub const NID_X9_62_c2pnb163v1: c_int = 684; +pub const NID_X9_62_c2pnb163v2: c_int = 685; +pub const NID_X9_62_c2pnb163v3: c_int = 686; +pub const NID_X9_62_c2pnb176v1: c_int = 687; +pub const NID_X9_62_c2tnb191v1: c_int = 688; +pub const NID_X9_62_c2tnb191v2: c_int = 689; +pub const NID_X9_62_c2tnb191v3: c_int = 690; +pub const NID_X9_62_c2onb191v4: c_int = 691; +pub const NID_X9_62_c2onb191v5: c_int = 692; +pub const NID_X9_62_c2pnb208w1: c_int = 693; +pub const NID_X9_62_c2tnb239v1: c_int = 694; +pub const NID_X9_62_c2tnb239v2: c_int = 695; +pub const NID_X9_62_c2tnb239v3: c_int = 696; +pub const NID_X9_62_c2onb239v4: c_int = 697; +pub const NID_X9_62_c2onb239v5: c_int = 698; +pub const NID_X9_62_c2pnb272w1: c_int = 699; +pub const NID_X9_62_c2pnb304w1: c_int = 700; +pub const NID_X9_62_c2tnb359v1: c_int = 701; +pub const NID_X9_62_c2pnb368w1: c_int = 702; +pub const NID_X9_62_c2tnb431r1: c_int = 703; +pub const NID_X9_62_prime192v1: c_int = 409; +pub const NID_X9_62_prime192v2: c_int = 410; +pub const NID_X9_62_prime192v3: c_int = 411; +pub const NID_X9_62_prime239v1: c_int = 412; +pub const NID_X9_62_prime239v2: c_int = 413; +pub const NID_X9_62_prime239v3: c_int = 414; +pub const NID_X9_62_prime256v1: c_int = 415; +pub const NID_ecdsa_with_SHA1: c_int = 416; +pub const NID_ecdsa_with_Recommended: c_int = 791; +pub const NID_ecdsa_with_Specified: c_int = 792; +pub const NID_ecdsa_with_SHA224: c_int = 793; +pub const NID_ecdsa_with_SHA256: c_int = 794; +pub const NID_ecdsa_with_SHA384: c_int = 795; +pub const NID_ecdsa_with_SHA512: c_int = 796; +pub const NID_secp112r1: c_int = 704; +pub const NID_secp112r2: c_int = 705; +pub const NID_secp128r1: c_int = 706; +pub const NID_secp128r2: c_int = 707; +pub const NID_secp160k1: c_int = 708; +pub const NID_secp160r1: c_int = 709; +pub const NID_secp160r2: c_int = 710; +pub const NID_secp192k1: c_int = 711; +pub const NID_secp224k1: c_int = 712; +pub const NID_secp224r1: c_int = 713; +pub const NID_secp256k1: c_int = 714; +pub const NID_secp384r1: c_int = 715; +pub const NID_secp521r1: c_int = 716; +pub const NID_sect113r1: c_int = 717; +pub const NID_sect113r2: c_int = 718; +pub const NID_sect131r1: c_int = 719; +pub const NID_sect131r2: c_int = 720; +pub const NID_sect163k1: c_int = 721; +pub const NID_sect163r1: c_int = 722; +pub const NID_sect163r2: c_int = 723; +pub const NID_sect193r1: c_int = 724; +pub const NID_sect193r2: c_int = 725; +pub const NID_sect233k1: c_int = 726; +pub const NID_sect233r1: c_int = 727; +pub const NID_sect239k1: c_int = 728; +pub const NID_sect283k1: c_int = 729; +pub const NID_sect283r1: c_int = 730; +pub const NID_sect409k1: c_int = 731; +pub const NID_sect409r1: c_int = 732; +pub const NID_sect571k1: c_int = 733; +pub const NID_sect571r1: c_int = 734; +#[cfg(ossl110)] +pub const NID_brainpoolP256r1: c_int = 927; +#[cfg(ossl110)] +pub const NID_brainpoolP384r1: c_int = 931; +#[cfg(ossl110)] +pub const NID_brainpoolP512r1: c_int = 933; +pub const NID_wap_wsg_idm_ecid_wtls1: c_int = 735; +pub const NID_wap_wsg_idm_ecid_wtls3: c_int = 736; +pub const NID_wap_wsg_idm_ecid_wtls4: c_int = 737; +pub const NID_wap_wsg_idm_ecid_wtls5: c_int = 738; +pub const NID_wap_wsg_idm_ecid_wtls6: c_int = 739; +pub const NID_wap_wsg_idm_ecid_wtls7: c_int = 740; +pub const NID_wap_wsg_idm_ecid_wtls8: c_int = 741; +pub const NID_wap_wsg_idm_ecid_wtls9: c_int = 742; +pub const NID_wap_wsg_idm_ecid_wtls10: c_int = 743; +pub const NID_wap_wsg_idm_ecid_wtls11: c_int = 744; +pub const NID_wap_wsg_idm_ecid_wtls12: c_int = 745; +pub const NID_cast5_cbc: c_int = 108; +pub const NID_cast5_ecb: c_int = 109; +pub const NID_cast5_cfb64: c_int = 110; +pub const NID_cast5_ofb64: c_int = 111; +pub const NID_pbeWithMD5AndCast5_CBC: c_int = 112; +pub const NID_id_PasswordBasedMAC: c_int = 782; +pub const NID_id_DHBasedMac: c_int = 783; +pub const NID_rsadsi: c_int = 1; +pub const NID_pkcs: c_int = 2; +pub const NID_pkcs1: c_int = 186; +pub const NID_rsaEncryption: c_int = 6; +pub const NID_md2WithRSAEncryption: c_int = 7; +pub const NID_md4WithRSAEncryption: c_int = 396; +pub const NID_md5WithRSAEncryption: c_int = 8; +pub const NID_sha1WithRSAEncryption: c_int = 65; +pub const NID_rsaesOaep: c_int = 919; +pub const NID_mgf1: c_int = 911; +pub const NID_rsassaPss: c_int = 912; +pub const NID_sha256WithRSAEncryption: c_int = 668; +pub const NID_sha384WithRSAEncryption: c_int = 669; +pub const NID_sha512WithRSAEncryption: c_int = 670; +pub const NID_sha224WithRSAEncryption: c_int = 671; +pub const NID_pkcs3: c_int = 27; +pub const NID_dhKeyAgreement: c_int = 28; +pub const NID_pkcs5: c_int = 187; +pub const NID_pbeWithMD2AndDES_CBC: c_int = 9; +pub const NID_pbeWithMD5AndDES_CBC: c_int = 10; +pub const NID_pbeWithMD2AndRC2_CBC: c_int = 168; +pub const NID_pbeWithMD5AndRC2_CBC: c_int = 169; +pub const NID_pbeWithSHA1AndDES_CBC: c_int = 170; +pub const NID_pbeWithSHA1AndRC2_CBC: c_int = 68; +pub const NID_id_pbkdf2: c_int = 69; +pub const NID_pbes2: c_int = 161; +pub const NID_pbmac1: c_int = 162; +pub const NID_pkcs7: c_int = 20; +pub const NID_pkcs7_data: c_int = 21; +pub const NID_pkcs7_signed: c_int = 22; +pub const NID_pkcs7_enveloped: c_int = 23; +pub const NID_pkcs7_signedAndEnveloped: c_int = 24; +pub const NID_pkcs7_digest: c_int = 25; +pub const NID_pkcs7_encrypted: c_int = 26; +pub const NID_pkcs9: c_int = 47; +pub const NID_pkcs9_emailAddress: c_int = 48; +pub const NID_pkcs9_unstructuredName: c_int = 49; +pub const NID_pkcs9_contentType: c_int = 50; +pub const NID_pkcs9_messageDigest: c_int = 51; +pub const NID_pkcs9_signingTime: c_int = 52; +pub const NID_pkcs9_countersignature: c_int = 53; +pub const NID_pkcs9_challengePassword: c_int = 54; +pub const NID_pkcs9_unstructuredAddress: c_int = 55; +pub const NID_pkcs9_extCertAttributes: c_int = 56; +pub const NID_ext_req: c_int = 172; +pub const NID_SMIMECapabilities: c_int = 167; +pub const NID_SMIME: c_int = 188; +pub const NID_id_smime_mod: c_int = 189; +pub const NID_id_smime_ct: c_int = 190; +pub const NID_id_smime_aa: c_int = 191; +pub const NID_id_smime_alg: c_int = 192; +pub const NID_id_smime_cd: c_int = 193; +pub const NID_id_smime_spq: c_int = 194; +pub const NID_id_smime_cti: c_int = 195; +pub const NID_id_smime_mod_cms: c_int = 196; +pub const NID_id_smime_mod_ess: c_int = 197; +pub const NID_id_smime_mod_oid: c_int = 198; +pub const NID_id_smime_mod_msg_v3: c_int = 199; +pub const NID_id_smime_mod_ets_eSignature_88: c_int = 200; +pub const NID_id_smime_mod_ets_eSignature_97: c_int = 201; +pub const NID_id_smime_mod_ets_eSigPolicy_88: c_int = 202; +pub const NID_id_smime_mod_ets_eSigPolicy_97: c_int = 203; +pub const NID_id_smime_ct_receipt: c_int = 204; +pub const NID_id_smime_ct_authData: c_int = 205; +pub const NID_id_smime_ct_publishCert: c_int = 206; +pub const NID_id_smime_ct_TSTInfo: c_int = 207; +pub const NID_id_smime_ct_TDTInfo: c_int = 208; +pub const NID_id_smime_ct_contentInfo: c_int = 209; +pub const NID_id_smime_ct_DVCSRequestData: c_int = 210; +pub const NID_id_smime_ct_DVCSResponseData: c_int = 211; +pub const NID_id_smime_ct_compressedData: c_int = 786; +pub const NID_id_ct_asciiTextWithCRLF: c_int = 787; +pub const NID_id_smime_aa_receiptRequest: c_int = 212; +pub const NID_id_smime_aa_securityLabel: c_int = 213; +pub const NID_id_smime_aa_mlExpandHistory: c_int = 214; +pub const NID_id_smime_aa_contentHint: c_int = 215; +pub const NID_id_smime_aa_msgSigDigest: c_int = 216; +pub const NID_id_smime_aa_encapContentType: c_int = 217; +pub const NID_id_smime_aa_contentIdentifier: c_int = 218; +pub const NID_id_smime_aa_macValue: c_int = 219; +pub const NID_id_smime_aa_equivalentLabels: c_int = 220; +pub const NID_id_smime_aa_contentReference: c_int = 221; +pub const NID_id_smime_aa_encrypKeyPref: c_int = 222; +pub const NID_id_smime_aa_signingCertificate: c_int = 223; +pub const NID_id_smime_aa_smimeEncryptCerts: c_int = 224; +pub const NID_id_smime_aa_timeStampToken: c_int = 225; +pub const NID_id_smime_aa_ets_sigPolicyId: c_int = 226; +pub const NID_id_smime_aa_ets_commitmentType: c_int = 227; +pub const NID_id_smime_aa_ets_signerLocation: c_int = 228; +pub const NID_id_smime_aa_ets_signerAttr: c_int = 229; +pub const NID_id_smime_aa_ets_otherSigCert: c_int = 230; +pub const NID_id_smime_aa_ets_contentTimestamp: c_int = 231; +pub const NID_id_smime_aa_ets_CertificateRefs: c_int = 232; +pub const NID_id_smime_aa_ets_RevocationRefs: c_int = 233; +pub const NID_id_smime_aa_ets_certValues: c_int = 234; +pub const NID_id_smime_aa_ets_revocationValues: c_int = 235; +pub const NID_id_smime_aa_ets_escTimeStamp: c_int = 236; +pub const NID_id_smime_aa_ets_certCRLTimestamp: c_int = 237; +pub const NID_id_smime_aa_ets_archiveTimeStamp: c_int = 238; +pub const NID_id_smime_aa_signatureType: c_int = 239; +pub const NID_id_smime_aa_dvcs_dvc: c_int = 240; +pub const NID_id_smime_alg_ESDHwith3DES: c_int = 241; +pub const NID_id_smime_alg_ESDHwithRC2: c_int = 242; +pub const NID_id_smime_alg_3DESwrap: c_int = 243; +pub const NID_id_smime_alg_RC2wrap: c_int = 244; +pub const NID_id_smime_alg_ESDH: c_int = 245; +pub const NID_id_smime_alg_CMS3DESwrap: c_int = 246; +pub const NID_id_smime_alg_CMSRC2wrap: c_int = 247; +pub const NID_id_alg_PWRI_KEK: c_int = 893; +pub const NID_id_smime_cd_ldap: c_int = 248; +pub const NID_id_smime_spq_ets_sqt_uri: c_int = 249; +pub const NID_id_smime_spq_ets_sqt_unotice: c_int = 250; +pub const NID_id_smime_cti_ets_proofOfOrigin: c_int = 251; +pub const NID_id_smime_cti_ets_proofOfReceipt: c_int = 252; +pub const NID_id_smime_cti_ets_proofOfDelivery: c_int = 253; +pub const NID_id_smime_cti_ets_proofOfSender: c_int = 254; +pub const NID_id_smime_cti_ets_proofOfApproval: c_int = 255; +pub const NID_id_smime_cti_ets_proofOfCreation: c_int = 256; +pub const NID_friendlyName: c_int = 156; +pub const NID_localKeyID: c_int = 157; +pub const NID_ms_csp_name: c_int = 417; +pub const NID_LocalKeySet: c_int = 856; +pub const NID_x509Certificate: c_int = 158; +pub const NID_sdsiCertificate: c_int = 159; +pub const NID_x509Crl: c_int = 160; +pub const NID_pbe_WithSHA1And128BitRC4: c_int = 144; +pub const NID_pbe_WithSHA1And40BitRC4: c_int = 145; +pub const NID_pbe_WithSHA1And3_Key_TripleDES_CBC: c_int = 146; +pub const NID_pbe_WithSHA1And2_Key_TripleDES_CBC: c_int = 147; +pub const NID_pbe_WithSHA1And128BitRC2_CBC: c_int = 148; +pub const NID_pbe_WithSHA1And40BitRC2_CBC: c_int = 149; +pub const NID_keyBag: c_int = 150; +pub const NID_pkcs8ShroudedKeyBag: c_int = 151; +pub const NID_certBag: c_int = 152; +pub const NID_crlBag: c_int = 153; +pub const NID_secretBag: c_int = 154; +pub const NID_safeContentsBag: c_int = 155; +pub const NID_md2: c_int = 3; +pub const NID_md4: c_int = 257; +pub const NID_md5: c_int = 4; +pub const NID_md5_sha1: c_int = 114; +pub const NID_hmacWithMD5: c_int = 797; +pub const NID_hmacWithSHA1: c_int = 163; +pub const NID_hmacWithSHA224: c_int = 798; +pub const NID_hmacWithSHA256: c_int = 799; +pub const NID_hmacWithSHA384: c_int = 800; +pub const NID_hmacWithSHA512: c_int = 801; +pub const NID_rc2_cbc: c_int = 37; +pub const NID_rc2_ecb: c_int = 38; +pub const NID_rc2_cfb64: c_int = 39; +pub const NID_rc2_ofb64: c_int = 40; +pub const NID_rc2_40_cbc: c_int = 98; +pub const NID_rc2_64_cbc: c_int = 166; +pub const NID_rc4: c_int = 5; +pub const NID_rc4_40: c_int = 97; +pub const NID_des_ede3_cbc: c_int = 44; +pub const NID_rc5_cbc: c_int = 120; +pub const NID_rc5_ecb: c_int = 121; +pub const NID_rc5_cfb64: c_int = 122; +pub const NID_rc5_ofb64: c_int = 123; +pub const NID_ms_ext_req: c_int = 171; +pub const NID_ms_code_ind: c_int = 134; +pub const NID_ms_code_com: c_int = 135; +pub const NID_ms_ctl_sign: c_int = 136; +pub const NID_ms_sgc: c_int = 137; +pub const NID_ms_efs: c_int = 138; +pub const NID_ms_smartcard_login: c_int = 648; +pub const NID_ms_upn: c_int = 649; +pub const NID_idea_cbc: c_int = 34; +pub const NID_idea_ecb: c_int = 36; +pub const NID_idea_cfb64: c_int = 35; +pub const NID_idea_ofb64: c_int = 46; +pub const NID_bf_cbc: c_int = 91; +pub const NID_bf_ecb: c_int = 92; +pub const NID_bf_cfb64: c_int = 93; +pub const NID_bf_ofb64: c_int = 94; +pub const NID_id_pkix: c_int = 127; +pub const NID_id_pkix_mod: c_int = 258; +pub const NID_id_pe: c_int = 175; +pub const NID_id_qt: c_int = 259; +pub const NID_id_kp: c_int = 128; +pub const NID_id_it: c_int = 260; +pub const NID_id_pkip: c_int = 261; +pub const NID_id_alg: c_int = 262; +pub const NID_id_cmc: c_int = 263; +pub const NID_id_on: c_int = 264; +pub const NID_id_pda: c_int = 265; +pub const NID_id_aca: c_int = 266; +pub const NID_id_qcs: c_int = 267; +pub const NID_id_cct: c_int = 268; +pub const NID_id_ppl: c_int = 662; +pub const NID_id_ad: c_int = 176; +pub const NID_id_pkix1_explicit_88: c_int = 269; +pub const NID_id_pkix1_implicit_88: c_int = 270; +pub const NID_id_pkix1_explicit_93: c_int = 271; +pub const NID_id_pkix1_implicit_93: c_int = 272; +pub const NID_id_mod_crmf: c_int = 273; +pub const NID_id_mod_cmc: c_int = 274; +pub const NID_id_mod_kea_profile_88: c_int = 275; +pub const NID_id_mod_kea_profile_93: c_int = 276; +pub const NID_id_mod_cmp: c_int = 277; +pub const NID_id_mod_qualified_cert_88: c_int = 278; +pub const NID_id_mod_qualified_cert_93: c_int = 279; +pub const NID_id_mod_attribute_cert: c_int = 280; +pub const NID_id_mod_timestamp_protocol: c_int = 281; +pub const NID_id_mod_ocsp: c_int = 282; +pub const NID_id_mod_dvcs: c_int = 283; +pub const NID_id_mod_cmp2000: c_int = 284; +pub const NID_info_access: c_int = 177; +pub const NID_biometricInfo: c_int = 285; +pub const NID_qcStatements: c_int = 286; +pub const NID_ac_auditEntity: c_int = 287; +pub const NID_ac_targeting: c_int = 288; +pub const NID_aaControls: c_int = 289; +pub const NID_sbgp_ipAddrBlock: c_int = 290; +pub const NID_sbgp_autonomousSysNum: c_int = 291; +pub const NID_sbgp_routerIdentifier: c_int = 292; +pub const NID_ac_proxying: c_int = 397; +pub const NID_sinfo_access: c_int = 398; +pub const NID_proxyCertInfo: c_int = 663; +pub const NID_id_qt_cps: c_int = 164; +pub const NID_id_qt_unotice: c_int = 165; +pub const NID_textNotice: c_int = 293; +pub const NID_server_auth: c_int = 129; +pub const NID_client_auth: c_int = 130; +pub const NID_code_sign: c_int = 131; +pub const NID_email_protect: c_int = 132; +pub const NID_ipsecEndSystem: c_int = 294; +pub const NID_ipsecTunnel: c_int = 295; +pub const NID_ipsecUser: c_int = 296; +pub const NID_time_stamp: c_int = 133; +pub const NID_OCSP_sign: c_int = 180; +pub const NID_dvcs: c_int = 297; +pub const NID_id_it_caProtEncCert: c_int = 298; +pub const NID_id_it_signKeyPairTypes: c_int = 299; +pub const NID_id_it_encKeyPairTypes: c_int = 300; +pub const NID_id_it_preferredSymmAlg: c_int = 301; +pub const NID_id_it_caKeyUpdateInfo: c_int = 302; +pub const NID_id_it_currentCRL: c_int = 303; +pub const NID_id_it_unsupportedOIDs: c_int = 304; +pub const NID_id_it_subscriptionRequest: c_int = 305; +pub const NID_id_it_subscriptionResponse: c_int = 306; +pub const NID_id_it_keyPairParamReq: c_int = 307; +pub const NID_id_it_keyPairParamRep: c_int = 308; +pub const NID_id_it_revPassphrase: c_int = 309; +pub const NID_id_it_implicitConfirm: c_int = 310; +pub const NID_id_it_confirmWaitTime: c_int = 311; +pub const NID_id_it_origPKIMessage: c_int = 312; +pub const NID_id_it_suppLangTags: c_int = 784; +pub const NID_id_regCtrl: c_int = 313; +pub const NID_id_regInfo: c_int = 314; +pub const NID_id_regCtrl_regToken: c_int = 315; +pub const NID_id_regCtrl_authenticator: c_int = 316; +pub const NID_id_regCtrl_pkiPublicationInfo: c_int = 317; +pub const NID_id_regCtrl_pkiArchiveOptions: c_int = 318; +pub const NID_id_regCtrl_oldCertID: c_int = 319; +pub const NID_id_regCtrl_protocolEncrKey: c_int = 320; +pub const NID_id_regInfo_utf8Pairs: c_int = 321; +pub const NID_id_regInfo_certReq: c_int = 322; +pub const NID_id_alg_des40: c_int = 323; +pub const NID_id_alg_noSignature: c_int = 324; +pub const NID_id_alg_dh_sig_hmac_sha1: c_int = 325; +pub const NID_id_alg_dh_pop: c_int = 326; +pub const NID_id_cmc_statusInfo: c_int = 327; +pub const NID_id_cmc_identification: c_int = 328; +pub const NID_id_cmc_identityProof: c_int = 329; +pub const NID_id_cmc_dataReturn: c_int = 330; +pub const NID_id_cmc_transactionId: c_int = 331; +pub const NID_id_cmc_senderNonce: c_int = 332; +pub const NID_id_cmc_recipientNonce: c_int = 333; +pub const NID_id_cmc_addExtensions: c_int = 334; +pub const NID_id_cmc_encryptedPOP: c_int = 335; +pub const NID_id_cmc_decryptedPOP: c_int = 336; +pub const NID_id_cmc_lraPOPWitness: c_int = 337; +pub const NID_id_cmc_getCert: c_int = 338; +pub const NID_id_cmc_getCRL: c_int = 339; +pub const NID_id_cmc_revokeRequest: c_int = 340; +pub const NID_id_cmc_regInfo: c_int = 341; +pub const NID_id_cmc_responseInfo: c_int = 342; +pub const NID_id_cmc_queryPending: c_int = 343; +pub const NID_id_cmc_popLinkRandom: c_int = 344; +pub const NID_id_cmc_popLinkWitness: c_int = 345; +pub const NID_id_cmc_confirmCertAcceptance: c_int = 346; +pub const NID_id_on_personalData: c_int = 347; +pub const NID_id_on_permanentIdentifier: c_int = 858; +pub const NID_id_pda_dateOfBirth: c_int = 348; +pub const NID_id_pda_placeOfBirth: c_int = 349; +pub const NID_id_pda_gender: c_int = 351; +pub const NID_id_pda_countryOfCitizenship: c_int = 352; +pub const NID_id_pda_countryOfResidence: c_int = 353; +pub const NID_id_aca_authenticationInfo: c_int = 354; +pub const NID_id_aca_accessIdentity: c_int = 355; +pub const NID_id_aca_chargingIdentity: c_int = 356; +pub const NID_id_aca_group: c_int = 357; +pub const NID_id_aca_role: c_int = 358; +pub const NID_id_aca_encAttrs: c_int = 399; +pub const NID_id_qcs_pkixQCSyntax_v1: c_int = 359; +pub const NID_id_cct_crs: c_int = 360; +pub const NID_id_cct_PKIData: c_int = 361; +pub const NID_id_cct_PKIResponse: c_int = 362; +pub const NID_id_ppl_anyLanguage: c_int = 664; +pub const NID_id_ppl_inheritAll: c_int = 665; +pub const NID_Independent: c_int = 667; +pub const NID_ad_OCSP: c_int = 178; +pub const NID_ad_ca_issuers: c_int = 179; +pub const NID_ad_timeStamping: c_int = 363; +pub const NID_ad_dvcs: c_int = 364; +pub const NID_caRepository: c_int = 785; +pub const NID_id_pkix_OCSP_basic: c_int = 365; +pub const NID_id_pkix_OCSP_Nonce: c_int = 366; +pub const NID_id_pkix_OCSP_CrlID: c_int = 367; +pub const NID_id_pkix_OCSP_acceptableResponses: c_int = 368; +pub const NID_id_pkix_OCSP_noCheck: c_int = 369; +pub const NID_id_pkix_OCSP_archiveCutoff: c_int = 370; +pub const NID_id_pkix_OCSP_serviceLocator: c_int = 371; +pub const NID_id_pkix_OCSP_extendedStatus: c_int = 372; +pub const NID_id_pkix_OCSP_valid: c_int = 373; +pub const NID_id_pkix_OCSP_path: c_int = 374; +pub const NID_id_pkix_OCSP_trustRoot: c_int = 375; +pub const NID_algorithm: c_int = 376; +pub const NID_md5WithRSA: c_int = 104; +pub const NID_des_ecb: c_int = 29; +pub const NID_des_cbc: c_int = 31; +pub const NID_des_ofb64: c_int = 45; +pub const NID_des_cfb64: c_int = 30; +pub const NID_rsaSignature: c_int = 377; +pub const NID_dsa_2: c_int = 67; +pub const NID_dsaWithSHA: c_int = 66; +pub const NID_shaWithRSAEncryption: c_int = 42; +pub const NID_des_ede_ecb: c_int = 32; +pub const NID_des_ede3_ecb: c_int = 33; +pub const NID_des_ede_cbc: c_int = 43; +pub const NID_des_ede_cfb64: c_int = 60; +pub const NID_des_ede3_cfb64: c_int = 61; +pub const NID_des_ede_ofb64: c_int = 62; +pub const NID_des_ede3_ofb64: c_int = 63; +pub const NID_desx_cbc: c_int = 80; +pub const NID_sha: c_int = 41; +pub const NID_sha1: c_int = 64; +pub const NID_dsaWithSHA1_2: c_int = 70; +pub const NID_sha1WithRSA: c_int = 115; +pub const NID_ripemd160: c_int = 117; +pub const NID_ripemd160WithRSA: c_int = 119; +pub const NID_sxnet: c_int = 143; +pub const NID_X500: c_int = 11; +pub const NID_X509: c_int = 12; +pub const NID_commonName: c_int = 13; +pub const NID_surname: c_int = 100; +pub const NID_serialNumber: c_int = 105; +pub const NID_countryName: c_int = 14; +pub const NID_localityName: c_int = 15; +pub const NID_stateOrProvinceName: c_int = 16; +pub const NID_streetAddress: c_int = 660; +pub const NID_organizationName: c_int = 17; +pub const NID_organizationalUnitName: c_int = 18; +pub const NID_title: c_int = 106; +pub const NID_description: c_int = 107; +pub const NID_searchGuide: c_int = 859; +pub const NID_businessCategory: c_int = 860; +pub const NID_postalAddress: c_int = 861; +pub const NID_postalCode: c_int = 661; +pub const NID_postOfficeBox: c_int = 862; +pub const NID_physicalDeliveryOfficeName: c_int = 863; +pub const NID_telephoneNumber: c_int = 864; +pub const NID_telexNumber: c_int = 865; +pub const NID_teletexTerminalIdentifier: c_int = 866; +pub const NID_facsimileTelephoneNumber: c_int = 867; +pub const NID_x121Address: c_int = 868; +pub const NID_internationaliSDNNumber: c_int = 869; +pub const NID_registeredAddress: c_int = 870; +pub const NID_destinationIndicator: c_int = 871; +pub const NID_preferredDeliveryMethod: c_int = 872; +pub const NID_presentationAddress: c_int = 873; +pub const NID_supportedApplicationContext: c_int = 874; +pub const NID_member: c_int = 875; +pub const NID_owner: c_int = 876; +pub const NID_roleOccupant: c_int = 877; +pub const NID_seeAlso: c_int = 878; +pub const NID_userPassword: c_int = 879; +pub const NID_userCertificate: c_int = 880; +pub const NID_cACertificate: c_int = 881; +pub const NID_authorityRevocationList: c_int = 882; +pub const NID_certificateRevocationList: c_int = 883; +pub const NID_crossCertificatePair: c_int = 884; +pub const NID_name: c_int = 173; +pub const NID_givenName: c_int = 99; +pub const NID_initials: c_int = 101; +pub const NID_generationQualifier: c_int = 509; +pub const NID_x500UniqueIdentifier: c_int = 503; +pub const NID_dnQualifier: c_int = 174; +pub const NID_enhancedSearchGuide: c_int = 885; +pub const NID_protocolInformation: c_int = 886; +pub const NID_distinguishedName: c_int = 887; +pub const NID_uniqueMember: c_int = 888; +pub const NID_houseIdentifier: c_int = 889; +pub const NID_supportedAlgorithms: c_int = 890; +pub const NID_deltaRevocationList: c_int = 891; +pub const NID_dmdName: c_int = 892; +pub const NID_pseudonym: c_int = 510; +pub const NID_role: c_int = 400; +pub const NID_X500algorithms: c_int = 378; +pub const NID_rsa: c_int = 19; +pub const NID_mdc2WithRSA: c_int = 96; +pub const NID_mdc2: c_int = 95; +pub const NID_id_ce: c_int = 81; +pub const NID_subject_directory_attributes: c_int = 769; +pub const NID_subject_key_identifier: c_int = 82; +pub const NID_key_usage: c_int = 83; +pub const NID_private_key_usage_period: c_int = 84; +pub const NID_subject_alt_name: c_int = 85; +pub const NID_issuer_alt_name: c_int = 86; +pub const NID_basic_constraints: c_int = 87; +pub const NID_crl_number: c_int = 88; +pub const NID_crl_reason: c_int = 141; +pub const NID_invalidity_date: c_int = 142; +pub const NID_delta_crl: c_int = 140; +pub const NID_issuing_distribution_point: c_int = 770; +pub const NID_certificate_issuer: c_int = 771; +pub const NID_name_constraints: c_int = 666; +pub const NID_crl_distribution_points: c_int = 103; +pub const NID_certificate_policies: c_int = 89; +pub const NID_any_policy: c_int = 746; +pub const NID_policy_mappings: c_int = 747; +pub const NID_authority_key_identifier: c_int = 90; +pub const NID_policy_constraints: c_int = 401; +pub const NID_ext_key_usage: c_int = 126; +pub const NID_freshest_crl: c_int = 857; +pub const NID_inhibit_any_policy: c_int = 748; +pub const NID_target_information: c_int = 402; +pub const NID_no_rev_avail: c_int = 403; +pub const NID_anyExtendedKeyUsage: c_int = 910; +pub const NID_netscape: c_int = 57; +pub const NID_netscape_cert_extension: c_int = 58; +pub const NID_netscape_data_type: c_int = 59; +pub const NID_netscape_cert_type: c_int = 71; +pub const NID_netscape_base_url: c_int = 72; +pub const NID_netscape_revocation_url: c_int = 73; +pub const NID_netscape_ca_revocation_url: c_int = 74; +pub const NID_netscape_renewal_url: c_int = 75; +pub const NID_netscape_ca_policy_url: c_int = 76; +pub const NID_netscape_ssl_server_name: c_int = 77; +pub const NID_netscape_comment: c_int = 78; +pub const NID_netscape_cert_sequence: c_int = 79; +pub const NID_ns_sgc: c_int = 139; +pub const NID_org: c_int = 379; +pub const NID_dod: c_int = 380; +pub const NID_iana: c_int = 381; +pub const NID_Directory: c_int = 382; +pub const NID_Management: c_int = 383; +pub const NID_Experimental: c_int = 384; +pub const NID_Private: c_int = 385; +pub const NID_Security: c_int = 386; +pub const NID_SNMPv2: c_int = 387; +pub const NID_Mail: c_int = 388; +pub const NID_Enterprises: c_int = 389; +pub const NID_dcObject: c_int = 390; +pub const NID_mime_mhs: c_int = 504; +pub const NID_mime_mhs_headings: c_int = 505; +pub const NID_mime_mhs_bodies: c_int = 506; +pub const NID_id_hex_partial_message: c_int = 507; +pub const NID_id_hex_multipart_message: c_int = 508; +pub const NID_zlib_compression: c_int = 125; +pub const NID_aes_128_ecb: c_int = 418; +pub const NID_aes_128_cbc: c_int = 419; +pub const NID_aes_128_ofb128: c_int = 420; +pub const NID_aes_128_cfb128: c_int = 421; +pub const NID_id_aes128_wrap: c_int = 788; +pub const NID_aes_128_gcm: c_int = 895; +pub const NID_aes_128_ccm: c_int = 896; +pub const NID_id_aes128_wrap_pad: c_int = 897; +pub const NID_aes_192_ecb: c_int = 422; +pub const NID_aes_192_cbc: c_int = 423; +pub const NID_aes_192_ofb128: c_int = 424; +pub const NID_aes_192_cfb128: c_int = 425; +pub const NID_id_aes192_wrap: c_int = 789; +pub const NID_aes_192_gcm: c_int = 898; +pub const NID_aes_192_ccm: c_int = 899; +pub const NID_id_aes192_wrap_pad: c_int = 900; +pub const NID_aes_256_ecb: c_int = 426; +pub const NID_aes_256_cbc: c_int = 427; +pub const NID_aes_256_ofb128: c_int = 428; +pub const NID_aes_256_cfb128: c_int = 429; +pub const NID_id_aes256_wrap: c_int = 790; +pub const NID_aes_256_gcm: c_int = 901; +pub const NID_aes_256_ccm: c_int = 902; +pub const NID_id_aes256_wrap_pad: c_int = 903; +pub const NID_aes_128_cfb1: c_int = 650; +pub const NID_aes_192_cfb1: c_int = 651; +pub const NID_aes_256_cfb1: c_int = 652; +pub const NID_aes_128_cfb8: c_int = 653; +pub const NID_aes_192_cfb8: c_int = 654; +pub const NID_aes_256_cfb8: c_int = 655; +pub const NID_aes_128_ctr: c_int = 904; +pub const NID_aes_192_ctr: c_int = 905; +pub const NID_aes_256_ctr: c_int = 906; +pub const NID_aes_128_xts: c_int = 913; +pub const NID_aes_256_xts: c_int = 914; +pub const NID_des_cfb1: c_int = 656; +pub const NID_des_cfb8: c_int = 657; +pub const NID_des_ede3_cfb1: c_int = 658; +pub const NID_des_ede3_cfb8: c_int = 659; +pub const NID_sha256: c_int = 672; +pub const NID_sha384: c_int = 673; +pub const NID_sha512: c_int = 674; +pub const NID_sha224: c_int = 675; +pub const NID_dsa_with_SHA224: c_int = 802; +pub const NID_dsa_with_SHA256: c_int = 803; +pub const NID_hold_instruction_code: c_int = 430; +pub const NID_hold_instruction_none: c_int = 431; +pub const NID_hold_instruction_call_issuer: c_int = 432; +pub const NID_hold_instruction_reject: c_int = 433; +pub const NID_data: c_int = 434; +pub const NID_pss: c_int = 435; +pub const NID_ucl: c_int = 436; +pub const NID_pilot: c_int = 437; +pub const NID_pilotAttributeType: c_int = 438; +pub const NID_pilotAttributeSyntax: c_int = 439; +pub const NID_pilotObjectClass: c_int = 440; +pub const NID_pilotGroups: c_int = 441; +pub const NID_iA5StringSyntax: c_int = 442; +pub const NID_caseIgnoreIA5StringSyntax: c_int = 443; +pub const NID_pilotObject: c_int = 444; +pub const NID_pilotPerson: c_int = 445; +pub const NID_account: c_int = 446; +pub const NID_document: c_int = 447; +pub const NID_room: c_int = 448; +pub const NID_documentSeries: c_int = 449; +pub const NID_Domain: c_int = 392; +pub const NID_rFC822localPart: c_int = 450; +pub const NID_dNSDomain: c_int = 451; +pub const NID_domainRelatedObject: c_int = 452; +pub const NID_friendlyCountry: c_int = 453; +pub const NID_simpleSecurityObject: c_int = 454; +pub const NID_pilotOrganization: c_int = 455; +pub const NID_pilotDSA: c_int = 456; +pub const NID_qualityLabelledData: c_int = 457; +pub const NID_userId: c_int = 458; +pub const NID_textEncodedORAddress: c_int = 459; +pub const NID_rfc822Mailbox: c_int = 460; +pub const NID_info: c_int = 461; +pub const NID_favouriteDrink: c_int = 462; +pub const NID_roomNumber: c_int = 463; +pub const NID_photo: c_int = 464; +pub const NID_userClass: c_int = 465; +pub const NID_host: c_int = 466; +pub const NID_manager: c_int = 467; +pub const NID_documentIdentifier: c_int = 468; +pub const NID_documentTitle: c_int = 469; +pub const NID_documentVersion: c_int = 470; +pub const NID_documentAuthor: c_int = 471; +pub const NID_documentLocation: c_int = 472; +pub const NID_homeTelephoneNumber: c_int = 473; +pub const NID_secretary: c_int = 474; +pub const NID_otherMailbox: c_int = 475; +pub const NID_lastModifiedTime: c_int = 476; +pub const NID_lastModifiedBy: c_int = 477; +pub const NID_domainComponent: c_int = 391; +pub const NID_aRecord: c_int = 478; +pub const NID_pilotAttributeType27: c_int = 479; +pub const NID_mXRecord: c_int = 480; +pub const NID_nSRecord: c_int = 481; +pub const NID_sOARecord: c_int = 482; +pub const NID_cNAMERecord: c_int = 483; +pub const NID_associatedDomain: c_int = 484; +pub const NID_associatedName: c_int = 485; +pub const NID_homePostalAddress: c_int = 486; +pub const NID_personalTitle: c_int = 487; +pub const NID_mobileTelephoneNumber: c_int = 488; +pub const NID_pagerTelephoneNumber: c_int = 489; +pub const NID_friendlyCountryName: c_int = 490; +pub const NID_organizationalStatus: c_int = 491; +pub const NID_janetMailbox: c_int = 492; +pub const NID_mailPreferenceOption: c_int = 493; +pub const NID_buildingName: c_int = 494; +pub const NID_dSAQuality: c_int = 495; +pub const NID_singleLevelQuality: c_int = 496; +pub const NID_subtreeMinimumQuality: c_int = 497; +pub const NID_subtreeMaximumQuality: c_int = 498; +pub const NID_personalSignature: c_int = 499; +pub const NID_dITRedirect: c_int = 500; +pub const NID_audio: c_int = 501; +pub const NID_documentPublisher: c_int = 502; +pub const NID_id_set: c_int = 512; +pub const NID_set_ctype: c_int = 513; +pub const NID_set_msgExt: c_int = 514; +pub const NID_set_attr: c_int = 515; +pub const NID_set_policy: c_int = 516; +pub const NID_set_certExt: c_int = 517; +pub const NID_set_brand: c_int = 518; +pub const NID_setct_PANData: c_int = 519; +pub const NID_setct_PANToken: c_int = 520; +pub const NID_setct_PANOnly: c_int = 521; +pub const NID_setct_OIData: c_int = 522; +pub const NID_setct_PI: c_int = 523; +pub const NID_setct_PIData: c_int = 524; +pub const NID_setct_PIDataUnsigned: c_int = 525; +pub const NID_setct_HODInput: c_int = 526; +pub const NID_setct_AuthResBaggage: c_int = 527; +pub const NID_setct_AuthRevReqBaggage: c_int = 528; +pub const NID_setct_AuthRevResBaggage: c_int = 529; +pub const NID_setct_CapTokenSeq: c_int = 530; +pub const NID_setct_PInitResData: c_int = 531; +pub const NID_setct_PI_TBS: c_int = 532; +pub const NID_setct_PResData: c_int = 533; +pub const NID_setct_AuthReqTBS: c_int = 534; +pub const NID_setct_AuthResTBS: c_int = 535; +pub const NID_setct_AuthResTBSX: c_int = 536; +pub const NID_setct_AuthTokenTBS: c_int = 537; +pub const NID_setct_CapTokenData: c_int = 538; +pub const NID_setct_CapTokenTBS: c_int = 539; +pub const NID_setct_AcqCardCodeMsg: c_int = 540; +pub const NID_setct_AuthRevReqTBS: c_int = 541; +pub const NID_setct_AuthRevResData: c_int = 542; +pub const NID_setct_AuthRevResTBS: c_int = 543; +pub const NID_setct_CapReqTBS: c_int = 544; +pub const NID_setct_CapReqTBSX: c_int = 545; +pub const NID_setct_CapResData: c_int = 546; +pub const NID_setct_CapRevReqTBS: c_int = 547; +pub const NID_setct_CapRevReqTBSX: c_int = 548; +pub const NID_setct_CapRevResData: c_int = 549; +pub const NID_setct_CredReqTBS: c_int = 550; +pub const NID_setct_CredReqTBSX: c_int = 551; +pub const NID_setct_CredResData: c_int = 552; +pub const NID_setct_CredRevReqTBS: c_int = 553; +pub const NID_setct_CredRevReqTBSX: c_int = 554; +pub const NID_setct_CredRevResData: c_int = 555; +pub const NID_setct_PCertReqData: c_int = 556; +pub const NID_setct_PCertResTBS: c_int = 557; +pub const NID_setct_BatchAdminReqData: c_int = 558; +pub const NID_setct_BatchAdminResData: c_int = 559; +pub const NID_setct_CardCInitResTBS: c_int = 560; +pub const NID_setct_MeAqCInitResTBS: c_int = 561; +pub const NID_setct_RegFormResTBS: c_int = 562; +pub const NID_setct_CertReqData: c_int = 563; +pub const NID_setct_CertReqTBS: c_int = 564; +pub const NID_setct_CertResData: c_int = 565; +pub const NID_setct_CertInqReqTBS: c_int = 566; +pub const NID_setct_ErrorTBS: c_int = 567; +pub const NID_setct_PIDualSignedTBE: c_int = 568; +pub const NID_setct_PIUnsignedTBE: c_int = 569; +pub const NID_setct_AuthReqTBE: c_int = 570; +pub const NID_setct_AuthResTBE: c_int = 571; +pub const NID_setct_AuthResTBEX: c_int = 572; +pub const NID_setct_AuthTokenTBE: c_int = 573; +pub const NID_setct_CapTokenTBE: c_int = 574; +pub const NID_setct_CapTokenTBEX: c_int = 575; +pub const NID_setct_AcqCardCodeMsgTBE: c_int = 576; +pub const NID_setct_AuthRevReqTBE: c_int = 577; +pub const NID_setct_AuthRevResTBE: c_int = 578; +pub const NID_setct_AuthRevResTBEB: c_int = 579; +pub const NID_setct_CapReqTBE: c_int = 580; +pub const NID_setct_CapReqTBEX: c_int = 581; +pub const NID_setct_CapResTBE: c_int = 582; +pub const NID_setct_CapRevReqTBE: c_int = 583; +pub const NID_setct_CapRevReqTBEX: c_int = 584; +pub const NID_setct_CapRevResTBE: c_int = 585; +pub const NID_setct_CredReqTBE: c_int = 586; +pub const NID_setct_CredReqTBEX: c_int = 587; +pub const NID_setct_CredResTBE: c_int = 588; +pub const NID_setct_CredRevReqTBE: c_int = 589; +pub const NID_setct_CredRevReqTBEX: c_int = 590; +pub const NID_setct_CredRevResTBE: c_int = 591; +pub const NID_setct_BatchAdminReqTBE: c_int = 592; +pub const NID_setct_BatchAdminResTBE: c_int = 593; +pub const NID_setct_RegFormReqTBE: c_int = 594; +pub const NID_setct_CertReqTBE: c_int = 595; +pub const NID_setct_CertReqTBEX: c_int = 596; +pub const NID_setct_CertResTBE: c_int = 597; +pub const NID_setct_CRLNotificationTBS: c_int = 598; +pub const NID_setct_CRLNotificationResTBS: c_int = 599; +pub const NID_setct_BCIDistributionTBS: c_int = 600; +pub const NID_setext_genCrypt: c_int = 601; +pub const NID_setext_miAuth: c_int = 602; +pub const NID_setext_pinSecure: c_int = 603; +pub const NID_setext_pinAny: c_int = 604; +pub const NID_setext_track2: c_int = 605; +pub const NID_setext_cv: c_int = 606; +pub const NID_set_policy_root: c_int = 607; +pub const NID_setCext_hashedRoot: c_int = 608; +pub const NID_setCext_certType: c_int = 609; +pub const NID_setCext_merchData: c_int = 610; +pub const NID_setCext_cCertRequired: c_int = 611; +pub const NID_setCext_tunneling: c_int = 612; +pub const NID_setCext_setExt: c_int = 613; +pub const NID_setCext_setQualf: c_int = 614; +pub const NID_setCext_PGWYcapabilities: c_int = 615; +pub const NID_setCext_TokenIdentifier: c_int = 616; +pub const NID_setCext_Track2Data: c_int = 617; +pub const NID_setCext_TokenType: c_int = 618; +pub const NID_setCext_IssuerCapabilities: c_int = 619; +pub const NID_setAttr_Cert: c_int = 620; +pub const NID_setAttr_PGWYcap: c_int = 621; +pub const NID_setAttr_TokenType: c_int = 622; +pub const NID_setAttr_IssCap: c_int = 623; +pub const NID_set_rootKeyThumb: c_int = 624; +pub const NID_set_addPolicy: c_int = 625; +pub const NID_setAttr_Token_EMV: c_int = 626; +pub const NID_setAttr_Token_B0Prime: c_int = 627; +pub const NID_setAttr_IssCap_CVM: c_int = 628; +pub const NID_setAttr_IssCap_T2: c_int = 629; +pub const NID_setAttr_IssCap_Sig: c_int = 630; +pub const NID_setAttr_GenCryptgrm: c_int = 631; +pub const NID_setAttr_T2Enc: c_int = 632; +pub const NID_setAttr_T2cleartxt: c_int = 633; +pub const NID_setAttr_TokICCsig: c_int = 634; +pub const NID_setAttr_SecDevSig: c_int = 635; +pub const NID_set_brand_IATA_ATA: c_int = 636; +pub const NID_set_brand_Diners: c_int = 637; +pub const NID_set_brand_AmericanExpress: c_int = 638; +pub const NID_set_brand_JCB: c_int = 639; +pub const NID_set_brand_Visa: c_int = 640; +pub const NID_set_brand_MasterCard: c_int = 641; +pub const NID_set_brand_Novus: c_int = 642; +pub const NID_des_cdmf: c_int = 643; +pub const NID_rsaOAEPEncryptionSET: c_int = 644; +pub const NID_ipsec3: c_int = 749; +pub const NID_ipsec4: c_int = 750; +pub const NID_whirlpool: c_int = 804; +pub const NID_cryptopro: c_int = 805; +pub const NID_cryptocom: c_int = 806; +pub const NID_id_GostR3411_94_with_GostR3410_2001: c_int = 807; +pub const NID_id_GostR3411_94_with_GostR3410_94: c_int = 808; +pub const NID_id_GostR3411_94: c_int = 809; +pub const NID_id_HMACGostR3411_94: c_int = 810; +pub const NID_id_GostR3410_2001: c_int = 811; +pub const NID_id_GostR3410_94: c_int = 812; +pub const NID_id_Gost28147_89: c_int = 813; +pub const NID_gost89_cnt: c_int = 814; +pub const NID_id_Gost28147_89_MAC: c_int = 815; +pub const NID_id_GostR3411_94_prf: c_int = 816; +pub const NID_id_GostR3410_2001DH: c_int = 817; +pub const NID_id_GostR3410_94DH: c_int = 818; +pub const NID_id_Gost28147_89_CryptoPro_KeyMeshing: c_int = 819; +pub const NID_id_Gost28147_89_None_KeyMeshing: c_int = 820; +pub const NID_id_GostR3411_94_TestParamSet: c_int = 821; +pub const NID_id_GostR3411_94_CryptoProParamSet: c_int = 822; +pub const NID_id_Gost28147_89_TestParamSet: c_int = 823; +pub const NID_id_Gost28147_89_CryptoPro_A_ParamSet: c_int = 824; +pub const NID_id_Gost28147_89_CryptoPro_B_ParamSet: c_int = 825; +pub const NID_id_Gost28147_89_CryptoPro_C_ParamSet: c_int = 826; +pub const NID_id_Gost28147_89_CryptoPro_D_ParamSet: c_int = 827; +pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet: c_int = 828; +pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet: c_int = 829; +pub const NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet: c_int = 830; +pub const NID_id_GostR3410_94_TestParamSet: c_int = 831; +pub const NID_id_GostR3410_94_CryptoPro_A_ParamSet: c_int = 832; +pub const NID_id_GostR3410_94_CryptoPro_B_ParamSet: c_int = 833; +pub const NID_id_GostR3410_94_CryptoPro_C_ParamSet: c_int = 834; +pub const NID_id_GostR3410_94_CryptoPro_D_ParamSet: c_int = 835; +pub const NID_id_GostR3410_94_CryptoPro_XchA_ParamSet: c_int = 836; +pub const NID_id_GostR3410_94_CryptoPro_XchB_ParamSet: c_int = 837; +pub const NID_id_GostR3410_94_CryptoPro_XchC_ParamSet: c_int = 838; +pub const NID_id_GostR3410_2001_TestParamSet: c_int = 839; +pub const NID_id_GostR3410_2001_CryptoPro_A_ParamSet: c_int = 840; +pub const NID_id_GostR3410_2001_CryptoPro_B_ParamSet: c_int = 841; +pub const NID_id_GostR3410_2001_CryptoPro_C_ParamSet: c_int = 842; +pub const NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet: c_int = 843; +pub const NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet: c_int = 844; +pub const NID_id_GostR3410_94_a: c_int = 845; +pub const NID_id_GostR3410_94_aBis: c_int = 846; +pub const NID_id_GostR3410_94_b: c_int = 847; +pub const NID_id_GostR3410_94_bBis: c_int = 848; +pub const NID_id_Gost28147_89_cc: c_int = 849; +pub const NID_id_GostR3410_94_cc: c_int = 850; +pub const NID_id_GostR3410_2001_cc: c_int = 851; +pub const NID_id_GostR3411_94_with_GostR3410_94_cc: c_int = 852; +pub const NID_id_GostR3411_94_with_GostR3410_2001_cc: c_int = 853; +pub const NID_id_GostR3410_2001_ParamSet_cc: c_int = 854; +pub const NID_camellia_128_cbc: c_int = 751; +pub const NID_camellia_192_cbc: c_int = 752; +pub const NID_camellia_256_cbc: c_int = 753; +pub const NID_id_camellia128_wrap: c_int = 907; +pub const NID_id_camellia192_wrap: c_int = 908; +pub const NID_id_camellia256_wrap: c_int = 909; +pub const NID_camellia_128_ecb: c_int = 754; +pub const NID_camellia_128_ofb128: c_int = 766; +pub const NID_camellia_128_cfb128: c_int = 757; +pub const NID_camellia_192_ecb: c_int = 755; +pub const NID_camellia_192_ofb128: c_int = 767; +pub const NID_camellia_192_cfb128: c_int = 758; +pub const NID_camellia_256_ecb: c_int = 756; +pub const NID_camellia_256_ofb128: c_int = 768; +pub const NID_camellia_256_cfb128: c_int = 759; +pub const NID_camellia_128_cfb1: c_int = 760; +pub const NID_camellia_192_cfb1: c_int = 761; +pub const NID_camellia_256_cfb1: c_int = 762; +pub const NID_camellia_128_cfb8: c_int = 763; +pub const NID_camellia_192_cfb8: c_int = 764; +pub const NID_camellia_256_cfb8: c_int = 765; +pub const NID_kisa: c_int = 773; +pub const NID_seed_ecb: c_int = 776; +pub const NID_seed_cbc: c_int = 777; +pub const NID_seed_cfb128: c_int = 779; +pub const NID_seed_ofb128: c_int = 778; +pub const NID_hmac: c_int = 855; +pub const NID_cmac: c_int = 894; +pub const NID_rc4_hmac_md5: c_int = 915; +pub const NID_aes_128_cbc_hmac_sha1: c_int = 916; +pub const NID_aes_192_cbc_hmac_sha1: c_int = 917; +pub const NID_aes_256_cbc_hmac_sha1: c_int = 918; +#[cfg(ossl111)] +pub const NID_X25519: c_int = 1034; +#[cfg(libressl370)] +pub const NID_X25519: c_int = 950; +#[cfg(ossl111)] +pub const NID_X448: c_int = 1035; +#[cfg(ossl110)] +pub const NID_hkdf: c_int = 1036; +#[cfg(ossl111)] +pub const NID_ED25519: c_int = 1087; +#[cfg(libressl370)] +pub const NID_ED25519: c_int = 952; +#[cfg(ossl111)] +pub const NID_ED448: c_int = 1088; +#[cfg(ossl111)] +pub const NID_sm3: c_int = 1143; +#[cfg(libressl291)] +pub const NID_sm3: c_int = 968; +#[cfg(ossl111)] +pub const NID_sm3WithRSAEncryption: c_int = 1144; +#[cfg(libressl291)] +pub const NID_sm3WithRSAEncryption: c_int = 969; +#[cfg(ossl111)] +pub const NID_sm4_ecb: c_int = 1133; +#[cfg(libressl291)] +pub const NID_sm4_ecb: c_int = 973; +#[cfg(ossl111)] +pub const NID_sm4_cbc: c_int = 1134; +#[cfg(libressl291)] +pub const NID_sm4_cbc: c_int = 974; +#[cfg(ossl111)] +pub const NID_sm4_ofb128: c_int = 1135; +#[cfg(libressl291)] +pub const NID_sm4_ofb128: c_int = 975; +#[cfg(ossl111)] +pub const NID_sm4_cfb128: c_int = 1137; +#[cfg(libressl291)] +pub const NID_sm4_cfb128: c_int = 976; +#[cfg(ossl111)] +pub const NID_sm4_cfb1: c_int = 1136; +#[cfg(libressl291)] +pub const NID_sm4_cfb1: c_int = 977; +#[cfg(ossl111)] +pub const NID_sm4_cfb8: c_int = 1138; +#[cfg(libressl291)] +pub const NID_sm4_cfb8: c_int = 978; +#[cfg(ossl111)] +pub const NID_sm4_ctr: c_int = 1139; +#[cfg(libressl291)] +pub const NID_sm4_ctr: c_int = 979; +#[cfg(ossl111)] +pub const NID_sha3_224: c_int = 1096; +#[cfg(ossl111)] +pub const NID_sha3_256: c_int = 1097; +#[cfg(ossl111)] +pub const NID_sha3_384: c_int = 1098; +#[cfg(ossl111)] +pub const NID_sha3_512: c_int = 1099; +#[cfg(ossl111)] +pub const NID_shake128: c_int = 1100; +#[cfg(ossl111)] +pub const NID_shake256: c_int = 1101; diff --git a/openssl-sys/src/ocsp.rs b/openssl-sys/src/ocsp.rs new file mode 100644 index 0000000..fc0db39 --- /dev/null +++ b/openssl-sys/src/ocsp.rs @@ -0,0 +1,35 @@ +use libc::*; + +pub const OCSP_REVOKED_STATUS_NOSTATUS: c_int = -1; +pub const OCSP_REVOKED_STATUS_UNSPECIFIED: c_int = 0; +pub const OCSP_REVOKED_STATUS_KEYCOMPROMISE: c_int = 1; +pub const OCSP_REVOKED_STATUS_CACOMPROMISE: c_int = 2; +pub const OCSP_REVOKED_STATUS_AFFILIATIONCHANGED: c_int = 3; +pub const OCSP_REVOKED_STATUS_SUPERSEDED: c_int = 4; +pub const OCSP_REVOKED_STATUS_CESSATIONOFOPERATION: c_int = 5; +pub const OCSP_REVOKED_STATUS_CERTIFICATEHOLD: c_int = 6; +pub const OCSP_REVOKED_STATUS_REMOVEFROMCRL: c_int = 8; + +pub const OCSP_NOCERTS: c_ulong = 0x1; +pub const OCSP_NOINTERN: c_ulong = 0x2; +pub const OCSP_NOSIGS: c_ulong = 0x4; +pub const OCSP_NOCHAIN: c_ulong = 0x8; +pub const OCSP_NOVERIFY: c_ulong = 0x10; +pub const OCSP_NOEXPLICIT: c_ulong = 0x20; +pub const OCSP_NOCASIGN: c_ulong = 0x40; +pub const OCSP_NODELEGATED: c_ulong = 0x80; +pub const OCSP_NOCHECKS: c_ulong = 0x100; +pub const OCSP_TRUSTOTHER: c_ulong = 0x200; +pub const OCSP_RESPID_KEY: c_ulong = 0x400; +pub const OCSP_NOTIME: c_ulong = 0x800; + +pub const OCSP_RESPONSE_STATUS_SUCCESSFUL: c_int = 0; +pub const OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: c_int = 1; +pub const OCSP_RESPONSE_STATUS_INTERNALERROR: c_int = 2; +pub const OCSP_RESPONSE_STATUS_TRYLATER: c_int = 3; +pub const OCSP_RESPONSE_STATUS_SIGREQUIRED: c_int = 5; +pub const OCSP_RESPONSE_STATUS_UNAUTHORIZED: c_int = 6; + +pub const V_OCSP_CERTSTATUS_GOOD: c_int = 0; +pub const V_OCSP_CERTSTATUS_REVOKED: c_int = 1; +pub const V_OCSP_CERTSTATUS_UNKNOWN: c_int = 2; diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs deleted file mode 100644 index b5adb82..0000000 --- a/openssl-sys/src/ossl10x.rs +++ /dev/null @@ -1,985 +0,0 @@ -use std::sync::{Mutex, MutexGuard}; -use std::sync::{Once, ONCE_INIT}; -use std::mem; -use std::ptr; -use std::process; -use std::io::{self, Write}; - -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; -#[cfg(not(ossl101))] -use libc::time_t; - -#[repr(C)] -pub struct stack_st_ASN1_OBJECT { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509 { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509_NAME { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509_ATTRIBUTE { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_X509_EXTENSION { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_GENERAL_NAME { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_void { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_SSL_CIPHER { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_OPENSSL_STRING { - pub stack: _STACK, -} - -#[repr(C)] -pub struct _STACK { - pub num: c_int, - pub data: *mut *mut c_char, - pub sorted: c_int, - pub num_alloc: c_int, - pub comp: Option c_int>, -} - -#[repr(C)] -pub struct BIO_METHOD { - pub type_: c_int, - pub name: *const c_char, - pub bwrite: Option c_int>, - pub bread: Option c_int>, - pub bputs: Option c_int>, - pub bgets: Option c_int>, - pub ctrl: Option c_long>, - pub create: Option c_int>, - pub destroy: Option c_int>, - pub callback_ctrl: Option c_long>, -} - -#[repr(C)] -pub struct RSA { - pub pad: c_int, - pub version: c_long, - pub meth: *const ::RSA_METHOD, - - pub engine: *mut ::ENGINE, - pub n: *mut ::BIGNUM, - pub e: *mut ::BIGNUM, - pub d: *mut ::BIGNUM, - pub p: *mut ::BIGNUM, - pub q: *mut ::BIGNUM, - pub dmp1: *mut ::BIGNUM, - pub dmq1: *mut ::BIGNUM, - pub iqmp: *mut ::BIGNUM, - - pub ex_data: ::CRYPTO_EX_DATA, - pub references: c_int, - pub flags: c_int, - - pub _method_mod_n: *mut ::BN_MONT_CTX, - pub _method_mod_p: *mut ::BN_MONT_CTX, - pub _method_mod_q: *mut ::BN_MONT_CTX, - - pub bignum_data: *mut c_char, - pub blinding: *mut ::BN_BLINDING, - pub mt_blinding: *mut ::BN_BLINDING, -} - -#[repr(C)] -pub struct DSA { - pub pad: c_int, - pub version: c_long, - pub write_params: c_int, - - pub p: *mut ::BIGNUM, - pub q: *mut ::BIGNUM, - pub g: *mut ::BIGNUM, - pub pub_key: *mut ::BIGNUM, - pub priv_key: *mut ::BIGNUM, - pub kinv: *mut ::BIGNUM, - pub r: *mut ::BIGNUM, - - pub flags: c_int, - pub method_mont_p: *mut ::BN_MONT_CTX, - pub references: c_int, - pub ex_data: ::CRYPTO_EX_DATA, - pub meth: *const ::DSA_METHOD, - pub engine: *mut ::ENGINE, -} - -#[repr(C)] -pub struct EVP_PKEY { - pub type_: c_int, - pub save_type: c_int, - pub references: c_int, - pub ameth: *const ::EVP_PKEY_ASN1_METHOD, - pub engine: *mut ::ENGINE, - pub pkey: *mut c_void, - pub save_parameters: c_int, - pub attributes: *mut stack_st_X509_ATTRIBUTE, -} - -#[repr(C)] -pub struct BIO { - pub method: *mut ::BIO_METHOD, - pub callback: Option< - unsafe extern "C" fn(*mut ::BIO, - c_int, - *const c_char, - c_int, - c_long, - c_long) - -> c_long, - >, - pub cb_arg: *mut c_char, - pub init: c_int, - pub shutdown: c_int, - pub flags: c_int, - pub retry_reason: c_int, - pub num: c_int, - pub ptr: *mut c_void, - pub next_bio: *mut ::BIO, - pub prev_bio: *mut ::BIO, - pub references: c_int, - pub num_read: c_ulong, - pub num_write: c_ulong, - pub ex_data: ::CRYPTO_EX_DATA, -} - -#[repr(C)] -pub struct CRYPTO_EX_DATA { - pub sk: *mut ::stack_st_void, - pub dummy: c_int, -} - -#[repr(C)] -pub struct EVP_MD_CTX { - digest: *mut ::EVP_MD, - engine: *mut ::ENGINE, - flags: c_ulong, - md_data: *mut c_void, - pctx: *mut ::EVP_PKEY_CTX, - update: *mut c_void, -} - -#[repr(C)] -pub struct EVP_CIPHER { - pub nid: c_int, - pub block_size: c_int, - pub key_len: c_int, - pub iv_len: c_int, - pub flags: c_ulong, - pub init: Option< - unsafe extern "C" fn(*mut ::EVP_CIPHER_CTX, - *const c_uchar, - *const c_uchar, - c_int) - -> c_int, - >, - pub do_cipher: Option< - unsafe extern "C" fn(*mut ::EVP_CIPHER_CTX, - *mut c_uchar, - *const c_uchar, - size_t) - -> c_int, - >, - pub cleanup: Option c_int>, - pub ctx_size: c_int, - pub set_asn1_parameters: - Option c_int>, - pub get_asn1_parameters: - Option c_int>, - pub ctrl: - Option c_int>, - pub app_data: *mut c_void, -} - -#[repr(C)] -pub struct HMAC_CTX { - md: *mut ::EVP_MD, - md_ctx: ::EVP_MD_CTX, - i_ctx: ::EVP_MD_CTX, - o_ctx: ::EVP_MD_CTX, - key_length: c_uint, - key: [c_uchar; 128], -} - -#[repr(C)] -pub struct BIGNUM { - pub d: *mut ::BN_ULONG, - pub top: c_int, - pub dmax: c_int, - pub neg: c_int, - pub flags: c_int, -} - -#[repr(C)] -pub struct DH { - pub pad: c_int, - pub version: c_int, - pub p: *mut ::BIGNUM, - pub g: *mut ::BIGNUM, - pub length: c_long, - pub pub_key: *mut ::BIGNUM, - pub priv_key: *mut ::BIGNUM, - pub flags: c_int, - pub method_mont_p: *mut ::BN_MONT_CTX, - pub q: *mut ::BIGNUM, - pub j: *mut ::BIGNUM, - pub seed: *mut c_uchar, - pub seedlen: c_int, - pub counter: *mut ::BIGNUM, - pub references: c_int, - pub ex_data: ::CRYPTO_EX_DATA, - pub meth: *const ::DH_METHOD, - pub engine: *mut ::ENGINE, -} - -#[repr(C)] -pub struct X509 { - pub cert_info: *mut X509_CINF, - pub sig_alg: *mut ::X509_ALGOR, - pub signature: *mut ::ASN1_BIT_STRING, - pub valid: c_int, - pub references: c_int, - pub name: *mut c_char, - pub ex_data: ::CRYPTO_EX_DATA, - pub ex_pathlen: c_long, - pub ex_pcpathlen: c_long, - pub ex_flags: c_ulong, - pub ex_kusage: c_ulong, - pub ex_xkusage: c_ulong, - pub ex_nscert: c_ulong, - skid: *mut c_void, - akid: *mut c_void, - policy_cache: *mut c_void, - crldp: *mut c_void, - altname: *mut c_void, - nc: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] - rfc3779_addr: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] - rfc3779_asid: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] - sha1_hash: [c_uchar; 20], - aux: *mut c_void, -} - -#[repr(C)] -pub struct X509_CINF { - version: *mut c_void, - serialNumber: *mut c_void, - signature: *mut c_void, - issuer: *mut c_void, - pub validity: *mut X509_VAL, - subject: *mut c_void, - key: *mut c_void, - issuerUID: *mut c_void, - subjectUID: *mut c_void, - pub extensions: *mut stack_st_X509_EXTENSION, - enc: ASN1_ENCODING, -} - -#[repr(C)] -pub struct X509_ALGOR { - pub algorithm: *mut ::ASN1_OBJECT, - parameter: *mut c_void, -} - -#[repr(C)] -pub struct ASN1_ENCODING { - pub enc: *mut c_uchar, - pub len: c_long, - pub modified: c_int, -} - -#[repr(C)] -pub struct X509_VAL { - pub notBefore: *mut ::ASN1_TIME, - pub notAfter: *mut ::ASN1_TIME, -} - -#[repr(C)] -pub struct X509_REQ_INFO { - pub enc: ASN1_ENCODING, - pub version: *mut ::ASN1_INTEGER, - pub subject: *mut ::X509_NAME, - pubkey: *mut c_void, - pub attributes: *mut stack_st_X509_ATTRIBUTE, -} - -#[repr(C)] -pub struct X509_REQ { - pub req_info: *mut X509_REQ_INFO, - sig_alg: *mut c_void, - signature: *mut c_void, - references: c_int, -} - -#[repr(C)] -pub struct SSL { - version: c_int, - type_: c_int, - method: *const ::SSL_METHOD, - rbio: *mut c_void, - wbio: *mut c_void, - bbio: *mut c_void, - rwstate: c_int, - in_handshake: c_int, - handshake_func: Option c_int>, - pub server: c_int, - new_session: c_int, - quiet_session: c_int, - shutdown: c_int, - state: c_int, - rstate: c_int, - init_buf: *mut c_void, - init_msg: *mut c_void, - init_num: c_int, - init_off: c_int, - packet: *mut c_uchar, - packet_length: c_uint, - s2: *mut c_void, - s3: *mut c_void, - d1: *mut c_void, - read_ahead: c_int, - msg_callback: Option< - unsafe extern "C" fn(c_int, - c_int, - c_int, - *const c_void, - size_t, - *mut SSL, - *mut c_void), - >, - msg_callback_arg: *mut c_void, - hit: c_int, - param: *mut c_void, - cipher_list: *mut stack_st_SSL_CIPHER, - cipher_list_by_id: *mut stack_st_SSL_CIPHER, - mac_flags: c_int, - enc_read_ctx: *mut ::EVP_CIPHER_CTX, - read_hash: *mut ::EVP_MD_CTX, - expand: *mut c_void, - enc_write_ctx: *mut ::EVP_CIPHER_CTX, - write_hash: *mut ::EVP_MD_CTX, - compress: *mut c_void, - cert: *mut c_void, - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - session: *mut ::SSL_SESSION, - generate_session_id: ::GEN_SESSION_CB, - verify_mode: c_int, - verify_callback: Option c_int>, - info_callback: Option, - error: c_int, - error_code: c_int, - #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] - kssl_ctx: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_client_callback: Option< - unsafe extern "C" fn(*mut SSL, - *const c_char, - *mut c_char, - c_uint, - *mut c_uchar, - c_uint) - -> c_uint, - >, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_server_callback: - Option c_uint>, - ctx: *mut ::SSL_CTX, - debug: c_int, - verify_result: c_long, - ex_data: ::CRYPTO_EX_DATA, - client_CA: *mut stack_st_X509_NAME, - references: c_int, - options: c_ulong, - mode: c_ulong, - max_cert_list: c_long, - first_packet: c_int, - client_version: c_int, - max_send_fragment: c_uint, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_debug_cb: - Option, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_debug_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_hostname: *mut c_char, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - servername_done: c_int, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_status_type: c_int, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_status_expected: c_int, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_ocsp_ids: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_ocsp_exts: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_ocsp_resp: *mut c_uchar, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_ocsp_resplen: c_int, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_ticket_expected: c_int, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ecpointformatlist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ecpointformatlist: *mut c_uchar, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ellipticcurvelist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ellipticcurvelist: *mut c_uchar, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_opaque_prf_input: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_opaque_prf_input_len: size_t, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_session_ticket: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tls_session_ticket_ext_cb_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tls_session_secret_cb: ::tls_session_secret_cb_fn, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tls_session_secret_cb_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - initial_ctx: *mut ::SSL_CTX, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] - next_proto_negotiated: *mut c_uchar, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] - next_proto_negotiated_len: c_uchar, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - srtp_profiles: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - srtp_profile: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_heartbeat: c_uint, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_hb_pending: c_uint, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_hb_seq: c_uint, - renegotiate: c_int, - #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] - srp_ctx: ::SRP_CTX, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_client_proto_list: *mut c_uchar, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_client_proto_list_len: c_uint, -} - -#[repr(C)] -pub struct SSL_CTX { - method: *mut c_void, - cipher_list: *mut c_void, - cipher_list_by_id: *mut c_void, - cert_store: *mut c_void, - sessions: *mut c_void, - session_cache_size: c_ulong, - session_cache_head: *mut c_void, - session_cache_tail: *mut c_void, - session_cache_mode: c_int, - session_timeout: c_long, - new_session_cb: *mut c_void, - remove_session_cb: *mut c_void, - get_session_cb: *mut c_void, - stats: [c_int; 11], - pub references: c_int, - app_verify_callback: *mut c_void, - app_verify_arg: *mut c_void, - default_passwd_callback: *mut c_void, - default_passwd_callback_userdata: *mut c_void, - client_cert_cb: *mut c_void, - app_gen_cookie_cb: *mut c_void, - app_verify_cookie_cb: *mut c_void, - ex_dat: ::CRYPTO_EX_DATA, - rsa_md5: *mut c_void, - md5: *mut c_void, - sha1: *mut c_void, - extra_certs: *mut c_void, - comp_methods: *mut c_void, - info_callback: *mut c_void, - client_CA: *mut c_void, - options: c_ulong, - mode: c_ulong, - max_cert_list: c_long, - cert: *mut c_void, - read_ahead: c_int, - msg_callback: *mut c_void, - msg_callback_arg: *mut c_void, - verify_mode: c_int, - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; 32], - default_verify_callback: *mut c_void, - generate_session_id: *mut c_void, - param: *mut c_void, - quiet_shutdown: c_int, - max_send_fragment: c_uint, - - #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] - client_cert_engine: *mut c_void, - - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_servername_callback: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsect_servername_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_tick_key_name: [c_uchar; 16], - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_tick_hmac_key: [c_uchar; 16], - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_tick_aes_key: [c_uchar; 16], - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_ticket_key_cb: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_status_cb: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_status_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_opaque_prf_input_callback: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_opaque_prf_input_callback_arg: *mut c_void, - - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_identity_hint: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_client_callback: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_server_callback: *mut c_void, - - #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] - freelist_max_len: c_uint, - #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] - wbuf_freelist: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] - rbuf_freelist: *mut c_void, - - #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] - srp_ctx: SRP_CTX, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] - next_protos_advertised_cb: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] - next_protos_advertised_cb_arg: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] - next_proto_select_cb: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] - next_proto_select_cb_arg: *mut c_void, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl101))] - srtp_profiles: *mut c_void, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - srtp_profiles: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_select_cb: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_select_cb_arg: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_client_proto_list: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_client_proto_list_len: c_uint, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ecpointformatlist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ecpointformatlist: *mut c_uchar, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ellipticcurvelist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ellipticcurvelist: *mut c_uchar, -} - -#[repr(C)] -pub struct SSL_SESSION { - ssl_version: c_int, - key_arg_length: c_uint, - key_arg: [c_uchar; SSL_MAX_KEY_ARG_LENGTH as usize], - pub master_key_length: c_int, - pub master_key: [c_uchar; 48], - session_id_length: c_uint, - session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], - sid_ctx_length: c_uint, - sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], - #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] - krb5_client_princ_len: c_uint, - #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] - krb5_client_princ: [c_uchar; SSL_MAX_KRB5_PRINCIPAL_LENGTH as usize], - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_identity_hint: *mut c_char, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_identity: *mut c_char, - not_resumable: c_int, - sess_cert: *mut c_void, - peer: *mut X509, - verify_result: c_long, - pub references: c_int, - timeout: c_long, - time: c_long, - compress_meth: c_uint, - cipher: *const c_void, - cipher_id: c_ulong, - ciphers: *mut c_void, - ex_data: ::CRYPTO_EX_DATA, - prev: *mut c_void, - next: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_hostname: *mut c_char, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ecpointformatlist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ecpointformatlist: *mut c_uchar, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ellipticcurvelist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] - tlsext_ellipticcurvelist: *mut c_uchar, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_tick: *mut c_uchar, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_ticklen: size_t, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_tick_lifetime_hint: c_long, - #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] - srp_username: *mut c_char, -} - -#[repr(C)] -pub struct SRP_CTX { - SRP_cb_arg: *mut c_void, - TLS_ext_srp_username_callback: *mut c_void, - SRP_verify_param_callback: *mut c_void, - SRP_give_srp_client_pwd_callback: *mut c_void, - login: *mut c_void, - N: *mut c_void, - g: *mut c_void, - s: *mut c_void, - B: *mut c_void, - A: *mut c_void, - a: *mut c_void, - b: *mut c_void, - v: *mut c_void, - info: *mut c_void, - stringth: c_int, - srp_Mask: c_ulong, -} - -#[repr(C)] -#[cfg(not(ossl101))] -pub struct X509_VERIFY_PARAM { - pub name: *mut c_char, - pub check_time: time_t, - pub inh_flags: c_ulong, - pub flags: c_ulong, - pub purpose: c_int, - pub trust: c_int, - pub depth: c_int, - pub policies: *mut stack_st_ASN1_OBJECT, - pub id: *mut X509_VERIFY_PARAM_ID, -} - -#[cfg(not(ossl101))] -pub enum X509_VERIFY_PARAM_ID {} -pub enum PKCS12 {} - -pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8; -pub const SSL_CTRL_OPTIONS: c_int = 32; -pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; -#[cfg(ossl102)] -pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; - -pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000001; -pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000002; -pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000008; -pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000020; -pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000080; -pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000100; -pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000200; -pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; -pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; -pub const SSL_OP_NO_SSLv2: c_ulong = 0x01000000; - -pub const SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32; -pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32; -pub const SSL_MAX_KEY_ARG_LENGTH: c_int = 8; -pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48; -pub const SSL_MAX_KRB5_PRINCIPAL_LENGTH: c_int = 256; - -pub const SSLEAY_VERSION: c_int = 0; -pub const SSLEAY_CFLAGS: c_int = 2; -pub const SSLEAY_BUILT_ON: c_int = 3; -pub const SSLEAY_PLATFORM: c_int = 4; -pub const SSLEAY_DIR: c_int = 5; - -pub const CRYPTO_LOCK_X509: c_int = 3; -pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; -pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14; - -static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; -static mut GUARDS: *mut Vec>> = 0 as - *mut Vec>>; - -unsafe extern "C" fn locking_function(mode: c_int, n: c_int, _file: *const c_char, _line: c_int) { - let mutex = &(*MUTEXES)[n as usize]; - - if mode & ::CRYPTO_LOCK != 0 { - (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); - } else { - if let None = (*GUARDS)[n as usize].take() { - let _ = writeln!( - io::stderr(), - "BUG: rust-openssl lock {} already unlocked, aborting", - n - ); - process::abort(); - } - } -} - -pub fn init() { - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| unsafe { - SSL_library_init(); - SSL_load_error_strings(); - OPENSSL_add_all_algorithms_noconf(); - - let num_locks = ::CRYPTO_num_locks(); - let mut mutexes = Box::new(Vec::new()); - for _ in 0..num_locks { - mutexes.push(Mutex::new(())); - } - MUTEXES = mem::transmute(mutexes); - let guards: Box>>> = - Box::new((0..num_locks).map(|_| None).collect()); - GUARDS = mem::transmute(guards); - - CRYPTO_set_locking_callback(locking_function); - set_id_callback(); - }) -} - -#[cfg(unix)] -fn set_id_callback() { - unsafe extern "C" fn thread_id() -> c_ulong { - ::libc::pthread_self() as c_ulong - } - - unsafe { - CRYPTO_set_id_callback(thread_id); - } -} - -#[cfg(not(unix))] -fn set_id_callback() {} - -// macros - -#[cfg(ossl102)] -pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { - ::SSL_CTX_ctrl( - ctx, - SSL_CTRL_SET_ECDH_AUTO, - onoff as c_long, - ptr::null_mut(), - ) as c_int -} - -#[cfg(ossl102)] -pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { - ::SSL_ctrl( - ssl, - SSL_CTRL_SET_ECDH_AUTO, - onoff as c_long, - ptr::null_mut(), - ) as c_int -} - -pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { - ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int -} - -extern "C" { - pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; - pub fn BIO_s_file() -> *mut BIO_METHOD; - pub fn BIO_s_mem() -> *mut BIO_METHOD; - - pub fn get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; - - pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void; - pub fn CRYPTO_free(buf: *mut c_void); - pub fn CRYPTO_num_locks() -> c_int; - pub fn CRYPTO_set_locking_callback( - func: unsafe extern "C" fn(mode: c_int, n: c_int, file: *const c_char, line: c_int), - ); - pub fn CRYPTO_set_id_callback(func: unsafe extern "C" fn() -> c_ulong); - - pub fn ERR_load_crypto_strings(); - - pub fn RSA_generate_key( - modsz: c_int, - e: c_ulong, - cb: Option, - cbarg: *mut c_void, - ) -> *mut RSA; - - pub fn OCSP_cert_to_id( - dgst: *const ::EVP_MD, - subject: *mut ::X509, - issuer: *mut ::X509, - ) -> *mut ::OCSP_CERTID; - - pub fn PKCS12_create( - pass: *mut c_char, - friendly_name: *mut c_char, - pkey: *mut EVP_PKEY, - cert: *mut X509, - ca: *mut stack_st_X509, - nid_key: c_int, - nid_cert: c_int, - iter: c_int, - mac_iter: c_int, - keytype: c_int, - ) -> *mut PKCS12; - - pub fn SSL_library_init() -> c_int; - pub fn SSL_load_error_strings(); - pub fn OPENSSL_add_all_algorithms_noconf(); - pub fn HMAC_CTX_init(ctx: *mut ::HMAC_CTX); - pub fn HMAC_CTX_cleanup(ctx: *mut ::HMAC_CTX); - #[cfg(not(osslconf = "OPENSSL_NO_SSL3_METHOD"))] - pub fn SSLv3_method() -> *const ::SSL_METHOD; - pub fn TLSv1_method() -> *const ::SSL_METHOD; - pub fn SSLv23_method() -> *const ::SSL_METHOD; - pub fn TLSv1_1_method() -> *const ::SSL_METHOD; - pub fn TLSv1_2_method() -> *const ::SSL_METHOD; - pub fn DTLSv1_method() -> *const ::SSL_METHOD; - #[cfg(ossl102)] - pub fn DTLSv1_2_method() -> *const ::SSL_METHOD; - pub fn SSL_get_ex_new_index( - argl: c_long, - argp: *mut c_void, - new_func: Option<::CRYPTO_EX_new>, - dup_func: Option<::CRYPTO_EX_dup>, - free_func: Option<::CRYPTO_EX_free>, - ) -> c_int; - pub fn SSL_set_tmp_ecdh_callback( - ssl: *mut ::SSL, - ecdh: unsafe extern "C" fn(ssl: *mut ::SSL, is_export: c_int, keylength: c_int) - -> *mut ::EC_KEY, - ); - pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *mut c_char; - pub fn SSL_CTX_get_ex_new_index( - argl: c_long, - argp: *mut c_void, - new_func: Option<::CRYPTO_EX_new>, - dup_func: Option<::CRYPTO_EX_dup>, - free_func: Option<::CRYPTO_EX_free>, - ) -> c_int; - pub fn SSL_CTX_set_tmp_ecdh_callback( - ctx: *mut ::SSL_CTX, - ecdh: unsafe extern "C" fn(ssl: *mut ::SSL, is_export: c_int, keylength: c_int) - -> *mut ::EC_KEY, - ); - pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; - pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_get_ext_d2i( - x: *mut ::X509, - nid: c_int, - crit: *mut c_int, - idx: *mut c_int, - ) -> *mut c_void; - pub fn X509_NAME_add_entry_by_NID( - x: *mut ::X509_NAME, - field: c_int, - ty: c_int, - bytes: *mut c_uchar, - len: c_int, - loc: c_int, - set: c_int, - ) -> c_int; - #[cfg(not(ossl101))] - pub fn X509_get0_signature( - psig: *mut *mut ::ASN1_BIT_STRING, - palg: *mut *mut ::X509_ALGOR, - x: *const ::X509, - ); - #[cfg(not(ossl101))] - pub fn X509_get_signature_nid(x: *const X509) -> c_int; - #[cfg(not(ossl101))] - pub fn X509_ALGOR_get0( - paobj: *mut *mut ::ASN1_OBJECT, - pptype: *mut c_int, - ppval: *mut *mut c_void, - alg: *mut ::X509_ALGOR, - ); - pub fn X509_NAME_get_entry(n: *mut ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; - pub fn X509_NAME_ENTRY_get_data(ne: *mut ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; - pub fn X509_STORE_CTX_get_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; - pub fn X509V3_EXT_nconf_nid( - conf: *mut ::CONF, - ctx: *mut ::X509V3_CTX, - ext_nid: c_int, - value: *mut c_char, - ) -> *mut ::X509_EXTENSION; - pub fn X509V3_EXT_nconf( - conf: *mut ::CONF, - ctx: *mut ::X509V3_CTX, - name: *mut c_char, - value: *mut c_char, - ) -> *mut ::X509_EXTENSION; - pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ::ASN1_STRING) -> c_int; - pub fn ASN1_STRING_data(x: *mut ::ASN1_STRING) -> *mut c_uchar; - pub fn CRYPTO_add_lock( - pointer: *mut c_int, - amount: c_int, - type_: c_int, - file: *const c_char, - line: c_int, - ) -> c_int; - pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; - pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); - pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int; - - pub fn sk_new_null() -> *mut _STACK; - pub fn sk_num(st: *const _STACK) -> c_int; - pub fn sk_value(st: *const _STACK, n: c_int) -> *mut c_void; - pub fn sk_free(st: *mut _STACK); - pub fn sk_push(st: *mut _STACK, data: *mut c_void) -> c_int; - pub fn sk_pop_free(st: *mut _STACK, free: Option); - pub fn sk_pop(st: *mut _STACK) -> *mut c_void; - - pub fn SSLeay() -> c_ulong; - pub fn SSLeay_version(key: c_int) -> *const c_char; -} diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs deleted file mode 100644 index fabfb2b..0000000 --- a/openssl-sys/src/ossl110.rs +++ /dev/null @@ -1,291 +0,0 @@ -use libc::{c_int, c_void, c_char, c_uchar, c_ulong, c_long, c_uint, size_t}; -use std::sync::{Once, ONCE_INIT}; -use std::ptr; - -pub enum BIGNUM {} -pub enum BIO {} -pub enum BIO_METHOD {} -pub enum CRYPTO_EX_DATA {} -pub enum DH {} -pub enum DSA {} -pub enum EVP_CIPHER {} -pub enum EVP_MD_CTX {} -pub enum EVP_PKEY {} -pub enum HMAC_CTX {} -pub enum OPENSSL_STACK {} -pub enum PKCS12 {} -pub enum RSA {} -pub enum SSL {} -pub enum SSL_CTX {} -pub enum SSL_SESSION {} -pub enum stack_st_ASN1_OBJECT {} -pub enum stack_st_GENERAL_NAME {} -pub enum stack_st_OPENSSL_STRING {} -pub enum stack_st_void {} -pub enum stack_st_X509 {} -pub enum stack_st_X509_NAME {} -pub enum stack_st_X509_ATTRIBUTE {} -pub enum stack_st_X509_EXTENSION {} -pub enum stack_st_SSL_CIPHER {} -pub enum OPENSSL_INIT_SETTINGS {} -pub enum X509 {} -pub enum X509_ALGOR {} -pub enum X509_VERIFY_PARAM {} -pub enum X509_REQ {} - -pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000000; -pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000000; -pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000000; -pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000000; -pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000000; -pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000000; -pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000000; -pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00000000; -pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00000000; -pub const SSL_OP_NO_SSLv2: c_ulong = 0x00000000; - -pub const OPENSSL_VERSION: c_int = 0; -pub const OPENSSL_CFLAGS: c_int = 1; -pub const OPENSSL_BUILT_ON: c_int = 2; -pub const OPENSSL_PLATFORM: c_int = 3; -pub const OPENSSL_DIR: c_int = 4; - -pub const CRYPTO_EX_INDEX_SSL: c_int = 0; -pub const CRYPTO_EX_INDEX_SSL_CTX: c_int = 1; - -pub const OPENSSL_INIT_LOAD_SSL_STRINGS: u64 = 0x00200000; - -pub const X509_CHECK_FLAG_NEVER_CHECK_SUBJECT: c_uint = 0x20; - -pub fn init() { - // explicitly initialize to work around https://github.com/openssl/openssl/issues/3505 - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| unsafe { - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, ptr::null_mut()); - }) -} - -extern "C" { - pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; - pub fn BIO_s_file() -> *const BIO_METHOD; - pub fn BIO_s_mem() -> *const BIO_METHOD; - - pub fn BN_get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; - - pub fn CRYPTO_malloc(num: size_t, file: *const c_char, line: c_int) -> *mut c_void; - pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int); - - pub fn EVP_chacha20() -> *const ::EVP_CIPHER; - pub fn EVP_chacha20_poly1305() -> *const ::EVP_CIPHER; - - pub fn HMAC_CTX_new() -> *mut HMAC_CTX; - pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); - - pub fn OCSP_cert_to_id( - dgst: *const ::EVP_MD, - subject: *const ::X509, - issuer: *const ::X509, - ) -> *mut ::OCSP_CERTID; - - pub fn TLS_method() -> *const ::SSL_METHOD; - pub fn DTLS_method() -> *const ::SSL_METHOD; - pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *const c_char; - pub fn X509_get_subject_name(x: *const ::X509) -> *mut ::X509_NAME; - pub fn X509_set1_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_set1_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_get_ext_d2i( - x: *const ::X509, - nid: c_int, - crit: *mut c_int, - idx: *mut c_int, - ) -> *mut c_void; - pub fn X509_NAME_add_entry_by_NID( - x: *mut ::X509_NAME, - field: c_int, - ty: c_int, - bytes: *const c_uchar, - len: c_int, - loc: c_int, - set: c_int, - ) -> c_int; - pub fn X509_get_signature_nid(x: *const X509) -> c_int; - pub fn X509_ALGOR_get0( - paobj: *mut *const ::ASN1_OBJECT, - pptype: *mut c_int, - ppval: *mut *const c_void, - alg: *const ::X509_ALGOR, - ); - pub fn X509_NAME_get_entry(n: *const ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; - pub fn X509_NAME_ENTRY_get_data(ne: *const ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; - pub fn X509V3_EXT_nconf_nid( - conf: *mut ::CONF, - ctx: *mut ::X509V3_CTX, - ext_nid: c_int, - value: *const c_char, - ) -> *mut ::X509_EXTENSION; - pub fn X509V3_EXT_nconf( - conf: *mut ::CONF, - ctx: *mut ::X509V3_CTX, - name: *const c_char, - value: *const c_char, - ) -> *mut ::X509_EXTENSION; - pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *const ::ASN1_STRING) -> c_int; - pub fn BN_is_negative(b: *const ::BIGNUM) -> c_int; - pub fn EVP_CIPHER_key_length(cipher: *const EVP_CIPHER) -> c_int; - pub fn EVP_CIPHER_block_size(cipher: *const EVP_CIPHER) -> c_int; - pub fn EVP_CIPHER_iv_length(cipher: *const EVP_CIPHER) -> c_int; - pub fn EVP_PBE_scrypt( - pass: *const c_char, - passlen: size_t, - salt: *const c_uchar, - saltlen: size_t, - N: u64, - r: u64, - p: u64, - maxmem: u64, - key: *mut c_uchar, - keylen: size_t, - ) -> c_int; - pub fn DSA_get0_pqg( - d: *const ::DSA, - p: *mut *const ::BIGNUM, - q: *mut *const ::BIGNUM, - q: *mut *const ::BIGNUM, - ); - pub fn DSA_get0_key( - d: *const ::DSA, - pub_key: *mut *const ::BIGNUM, - priv_key: *mut *const ::BIGNUM, - ); - pub fn RSA_get0_key( - r: *const ::RSA, - n: *mut *const ::BIGNUM, - e: *mut *const ::BIGNUM, - d: *mut *const ::BIGNUM, - ); - pub fn RSA_get0_factors(r: *const ::RSA, p: *mut *const ::BIGNUM, q: *mut *const ::BIGNUM); - pub fn RSA_get0_crt_params( - r: *const ::RSA, - dmp1: *mut *const ::BIGNUM, - dmq1: *mut *const ::BIGNUM, - iqmp: *mut *const ::BIGNUM, - ); - pub fn RSA_set0_key( - r: *mut ::RSA, - n: *mut ::BIGNUM, - e: *mut ::BIGNUM, - d: *mut ::BIGNUM, - ) -> c_int; - pub fn RSA_set0_factors(r: *mut ::RSA, p: *mut ::BIGNUM, q: *mut ::BIGNUM) -> c_int; - pub fn RSA_set0_crt_params( - r: *mut ::RSA, - dmp1: *mut ::BIGNUM, - dmq1: *mut ::BIGNUM, - iqmp: *mut ::BIGNUM, - ) -> c_int; - pub fn ASN1_STRING_get0_data(x: *const ::ASN1_STRING) -> *const c_uchar; - pub fn OPENSSL_sk_num(stack: *const ::OPENSSL_STACK) -> c_int; - pub fn OPENSSL_sk_value(stack: *const ::OPENSSL_STACK, idx: c_int) -> *mut c_void; - pub fn SSL_CTX_get_options(ctx: *const ::SSL_CTX) -> c_ulong; - pub fn SSL_CTX_set_options(ctx: *mut ::SSL_CTX, op: c_ulong) -> c_ulong; - pub fn SSL_CTX_clear_options(ctx: *mut ::SSL_CTX, op: c_ulong) -> c_ulong; - pub fn X509_getm_notAfter(x: *const ::X509) -> *mut ::ASN1_TIME; - pub fn X509_getm_notBefore(x: *const ::X509) -> *mut ::ASN1_TIME; - pub fn X509_get0_signature( - psig: *mut *const ::ASN1_BIT_STRING, - palg: *mut *const ::X509_ALGOR, - x: *const ::X509, - ); - pub fn DH_set0_pqg( - dh: *mut ::DH, - p: *mut ::BIGNUM, - q: *mut ::BIGNUM, - g: *mut ::BIGNUM, - ) -> c_int; - pub fn BIO_set_init(a: *mut ::BIO, init: c_int); - pub fn BIO_set_data(a: *mut ::BIO, data: *mut c_void); - pub fn BIO_get_data(a: *mut ::BIO) -> *mut c_void; - pub fn BIO_meth_new(type_: c_int, name: *const c_char) -> *mut ::BIO_METHOD; - pub fn BIO_meth_free(biom: *mut ::BIO_METHOD); - pub fn BIO_meth_set_write( - biom: *mut ::BIO_METHOD, - write: unsafe extern "C" fn(*mut ::BIO, *const c_char, c_int) -> c_int, - ) -> c_int; - pub fn BIO_meth_set_read( - biom: *mut ::BIO_METHOD, - read: unsafe extern "C" fn(*mut ::BIO, *mut c_char, c_int) -> c_int, - ) -> c_int; - pub fn BIO_meth_set_puts( - biom: *mut ::BIO_METHOD, - read: unsafe extern "C" fn(*mut ::BIO, *const c_char) -> c_int, - ) -> c_int; - pub fn BIO_meth_set_ctrl( - biom: *mut ::BIO_METHOD, - read: unsafe extern "C" fn(*mut ::BIO, c_int, c_long, *mut c_void) -> c_long, - ) -> c_int; - pub fn BIO_meth_set_create( - biom: *mut ::BIO_METHOD, - create: unsafe extern "C" fn(*mut ::BIO) -> c_int, - ) -> c_int; - pub fn BIO_meth_set_destroy( - biom: *mut ::BIO_METHOD, - destroy: unsafe extern "C" fn(*mut ::BIO) -> c_int, - ) -> c_int; - pub fn CRYPTO_get_ex_new_index( - class_index: c_int, - argl: c_long, - argp: *mut c_void, - new_func: Option<::CRYPTO_EX_new>, - dup_func: Option<::CRYPTO_EX_dup>, - free_func: Option<::CRYPTO_EX_free>, - ) -> c_int; - pub fn X509_up_ref(x: *mut X509) -> c_int; - pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int; - pub fn SSL_session_reused(ssl: *mut SSL) -> c_int; - pub fn SSL_SESSION_get_master_key( - session: *const SSL_SESSION, - out: *mut c_uchar, - outlen: size_t, - ) -> size_t; - pub fn SSL_SESSION_up_ref(ses: *mut SSL_SESSION) -> c_int; - pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION; - pub fn X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; - pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX; - pub fn EVP_MD_CTX_free(ctx: *mut EVP_MD_CTX); - pub fn EVP_PKEY_bits(key: *const EVP_PKEY) -> c_int; - - pub fn OpenSSL_version_num() -> c_ulong; - pub fn OpenSSL_version(key: c_int) -> *const c_char; - pub fn OPENSSL_init_ssl(opts: u64, settings: *const OPENSSL_INIT_SETTINGS) -> c_int; - pub fn OPENSSL_sk_new_null() -> *mut ::OPENSSL_STACK; - pub fn OPENSSL_sk_free(st: *mut ::OPENSSL_STACK); - pub fn OPENSSL_sk_pop_free( - st: *mut ::OPENSSL_STACK, - free: Option, - ); - pub fn OPENSSL_sk_push(st: *mut ::OPENSSL_STACK, data: *const c_void) -> c_int; - pub fn OPENSSL_sk_pop(st: *mut ::OPENSSL_STACK) -> *mut c_void; - - pub fn PKCS12_create( - pass: *const c_char, - friendly_name: *const c_char, - pkey: *mut EVP_PKEY, - cert: *mut X509, - ca: *mut stack_st_X509, - nid_key: c_int, - nid_cert: c_int, - iter: c_int, - mac_iter: c_int, - keytype: c_int, - ) -> *mut PKCS12; - pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long; - pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut ::X509_NAME; -} diff --git a/openssl-sys/src/pem.rs b/openssl-sys/src/pem.rs new file mode 100644 index 0000000..f7dd8ac --- /dev/null +++ b/openssl-sys/src/pem.rs @@ -0,0 +1,3 @@ +use libc::*; + +pub const PEM_R_NO_START_LINE: c_int = 108; diff --git a/openssl-sys/src/pkcs7.rs b/openssl-sys/src/pkcs7.rs new file mode 100644 index 0000000..0a56225 --- /dev/null +++ b/openssl-sys/src/pkcs7.rs @@ -0,0 +1,20 @@ +use libc::*; + +pub const PKCS7_TEXT: c_int = 0x1; +pub const PKCS7_NOCERTS: c_int = 0x2; +pub const PKCS7_NOSIGS: c_int = 0x4; +pub const PKCS7_NOCHAIN: c_int = 0x8; +pub const PKCS7_NOINTERN: c_int = 0x10; +pub const PKCS7_NOVERIFY: c_int = 0x20; +pub const PKCS7_DETACHED: c_int = 0x40; +pub const PKCS7_BINARY: c_int = 0x80; +pub const PKCS7_NOATTR: c_int = 0x100; +pub const PKCS7_NOSMIMECAP: c_int = 0x200; +pub const PKCS7_NOOLDMIMETYPE: c_int = 0x400; +pub const PKCS7_CRLFEOL: c_int = 0x800; +pub const PKCS7_STREAM: c_int = 0x1000; +pub const PKCS7_NOCRL: c_int = 0x2000; +pub const PKCS7_PARTIAL: c_int = 0x4000; +pub const PKCS7_REUSE_DIGEST: c_int = 0x8000; +#[cfg(not(any(ossl101, ossl102, libressl)))] +pub const PKCS7_NO_DUAL_CONTENT: c_int = 0x10000; diff --git a/openssl-sys/src/rsa.rs b/openssl-sys/src/rsa.rs new file mode 100644 index 0000000..ff30cf1 --- /dev/null +++ b/openssl-sys/src/rsa.rs @@ -0,0 +1,101 @@ +use libc::*; +use std::ptr; + +use super::super::*; + +pub const RSA_F4: c_long = 0x10001; + +cfg_if! { + if #[cfg(not(ossl300))] { + pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + -1, + EVP_PKEY_CTRL_RSA_PADDING, + pad, + ptr::null_mut(), + ) + } + pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + -1, + EVP_PKEY_CTRL_GET_RSA_PADDING, + 0, + ppad as *mut c_void, + ) + } + + pub unsafe fn EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx: *mut EVP_PKEY_CTX, len: c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY, + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, + len, + ptr::null_mut(), + ) + } + + pub unsafe fn EVP_PKEY_CTX_set_rsa_mgf1_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_MD) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_MGF1_MD, + 0, + md as *mut c_void, + ) + } + } +} + +#[cfg(any(ossl102, libressl310))] +pub unsafe fn EVP_PKEY_CTX_set_rsa_oaep_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_MD) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_MD, + 0, + md as *mut c_void, + ) +} + +#[cfg(any(ossl102, libressl310))] +pub unsafe fn EVP_PKEY_CTX_set0_rsa_oaep_label( + ctx: *mut EVP_PKEY_CTX, + label: *mut c_void, + len: c_int, +) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_LABEL, + len, + label as *mut c_void, + ) +} + +pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; +pub const EVP_PKEY_CTRL_RSA_PSS_SALTLEN: c_int = EVP_PKEY_ALG_CTRL + 2; + +pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5; + +pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; + +#[cfg(any(ossl102, libressl310))] +pub const EVP_PKEY_CTRL_RSA_OAEP_MD: c_int = EVP_PKEY_ALG_CTRL + 9; +#[cfg(any(ossl102, libressl310))] +pub const EVP_PKEY_CTRL_RSA_OAEP_LABEL: c_int = EVP_PKEY_ALG_CTRL + 10; + +pub const RSA_PKCS1_PADDING: c_int = 1; +#[cfg(not(ossl300))] +pub const RSA_SSLV23_PADDING: c_int = 2; +pub const RSA_NO_PADDING: c_int = 3; +pub const RSA_PKCS1_OAEP_PADDING: c_int = 4; +pub const RSA_X931_PADDING: c_int = 5; +pub const RSA_PKCS1_PSS_PADDING: c_int = 6; diff --git a/openssl-sys/src/sha.rs b/openssl-sys/src/sha.rs new file mode 100644 index 0000000..4ad0c17 --- /dev/null +++ b/openssl-sys/src/sha.rs @@ -0,0 +1,103 @@ +use super::*; +use libc::*; +use std::ptr; + +#[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] +pub const SHA_LBLOCK: c_int = 16; + +#[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] +pub type SHA_LONG = c_uint; + +cfg_if! { + if #[cfg(ossl300)] { + #[cfg(ossl300)] + // Ideally we'd macro define these, but that crashes ctest :( + pub unsafe fn SHA1(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar { + if EVP_Q_digest( + ptr::null_mut(), + "SHA1\0".as_ptr() as *const c_char, + ptr::null(), + d as *const c_void, + n, + md, + ptr::null_mut(), + ) != 0 + { + md + } else { + ptr::null_mut() + } + } + + pub unsafe fn SHA224(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar { + if EVP_Q_digest( + ptr::null_mut(), + "SHA224\0".as_ptr() as *const c_char, + ptr::null(), + d as *const c_void, + n, + md, + ptr::null_mut(), + ) != 0 { + md + } else { + ptr::null_mut() + } + } + + pub unsafe fn SHA256(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar { + if EVP_Q_digest( + ptr::null_mut(), + "SHA256\0".as_ptr() as *const c_char, + ptr::null(), + d as *const c_void, + n, + md, + ptr::null_mut(), + ) != 0 { + md + } else { + ptr::null_mut() + } + } + } +} + +#[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] +pub type SHA_LONG64 = u64; + +cfg_if! { + if #[cfg(ossl300)] { + pub unsafe fn SHA384(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar { + if EVP_Q_digest( + ptr::null_mut(), + "SHA384\0".as_ptr() as *const c_char, + ptr::null(), + d as *const c_void, + n, + md, + ptr::null_mut(), + ) != 0 { + md + } else { + ptr::null_mut() + } + } + + pub unsafe fn SHA512(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar { + if EVP_Q_digest( + ptr::null_mut(), + "SHA512\0".as_ptr() as *const c_char, + ptr::null(), + d as *const c_void, + n, + md, + ptr::null_mut(), + ) != 0 { + md + } else { + ptr::null_mut() + } + } + } +} diff --git a/openssl-sys/src/srtp.rs b/openssl-sys/src/srtp.rs new file mode 100644 index 0000000..93c7797 --- /dev/null +++ b/openssl-sys/src/srtp.rs @@ -0,0 +1,14 @@ +use libc::*; + +pub const SRTP_AES128_CM_SHA1_80: c_ulong = 0x0001; +pub const SRTP_AES128_CM_SHA1_32: c_ulong = 0x0002; +pub const SRTP_AES128_F8_SHA1_80: c_ulong = 0x0003; +pub const SRTP_AES128_F8_SHA1_32: c_ulong = 0x0004; +pub const SRTP_NULL_SHA1_80: c_ulong = 0x0005; +pub const SRTP_NULL_SHA1_32: c_ulong = 0x0006; + +/* AEAD SRTP protection profiles from RFC 7714 */ +#[cfg(ossl110)] +pub const SRTP_AEAD_AES_128_GCM: c_ulong = 0x0007; +#[cfg(ossl110)] +pub const SRTP_AEAD_AES_256_GCM: c_ulong = 0x0008; diff --git a/openssl-sys/src/ssl.rs b/openssl-sys/src/ssl.rs new file mode 100644 index 0000000..e812673 --- /dev/null +++ b/openssl-sys/src/ssl.rs @@ -0,0 +1,631 @@ +use libc::*; +use std::ptr; + +use super::*; + +#[cfg(not(ossl110))] +pub const SSL_MAX_KRB5_PRINCIPAL_LENGTH: c_int = 256; + +#[cfg(not(ossl110))] +pub const SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32; +#[cfg(not(ossl110))] +pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32; + +#[cfg(not(ossl110))] +pub const SSL_MAX_KEY_ARG_LENGTH: c_int = 8; +#[cfg(not(ossl110))] +pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48; + +pub const SSL_SENT_SHUTDOWN: c_int = 1; +pub const SSL_RECEIVED_SHUTDOWN: c_int = 2; + +pub const SSL_FILETYPE_PEM: c_int = X509_FILETYPE_PEM; +pub const SSL_FILETYPE_ASN1: c_int = X509_FILETYPE_ASN1; + +#[cfg(ossl111)] +pub const SSL_EXT_TLS_ONLY: c_uint = 0x0001; +/* This extension is only allowed in DTLS */ +#[cfg(ossl111)] +pub const SSL_EXT_DTLS_ONLY: c_uint = 0x0002; +/* Some extensions may be allowed in DTLS but we don't implement them for it */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS_IMPLEMENTATION_ONLY: c_uint = 0x0004; +/* Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is */ +#[cfg(ossl111)] +pub const SSL_EXT_SSL3_ALLOWED: c_uint = 0x0008; +/* Extension is only defined for TLS1.2 and below */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_2_AND_BELOW_ONLY: c_uint = 0x0010; +/* Extension is only defined for TLS1.3 and above */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_ONLY: c_uint = 0x0020; +/* Ignore this extension during parsing if we are resuming */ +#[cfg(ossl111)] +pub const SSL_EXT_IGNORE_ON_RESUMPTION: c_uint = 0x0040; +#[cfg(ossl111)] +pub const SSL_EXT_CLIENT_HELLO: c_uint = 0x0080; +/* Really means TLS1.2 or below */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_2_SERVER_HELLO: c_uint = 0x0100; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_SERVER_HELLO: c_uint = 0x0200; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS: c_uint = 0x0400; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST: c_uint = 0x0800; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_CERTIFICATE: c_uint = 0x1000; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_NEW_SESSION_TICKET: c_uint = 0x2000; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_CERTIFICATE_REQUEST: c_uint = 0x4000; + +cfg_if! { + if #[cfg(ossl300)] { + macro_rules! ssl_op_type { + () => {u64}; + } + } else { + macro_rules! ssl_op_type { + () => {c_ulong}; + } + } +} + +pub const SSL_OP_LEGACY_SERVER_CONNECT: ssl_op_type!() = 0x00000004; +cfg_if! { + if #[cfg(libressl261)] { + pub const SSL_OP_TLSEXT_PADDING: ssl_op_type!() = 0x0; + } else if #[cfg(any(ossl102, libressl))] { + pub const SSL_OP_TLSEXT_PADDING: ssl_op_type!() = 0x10; + } +} +#[cfg(ossl101)] +pub const SSL_OP_SAFARI_ECDHE_ECDSA_BUG: ssl_op_type!() = 0x00000040; + +pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: ssl_op_type!() = 0x00000800; + +pub const SSL_OP_NO_QUERY_MTU: ssl_op_type!() = 0x00001000; +pub const SSL_OP_COOKIE_EXCHANGE: ssl_op_type!() = 0x00002000; +pub const SSL_OP_NO_TICKET: ssl_op_type!() = 0x00004000; +cfg_if! { + if #[cfg(ossl101)] { + pub const SSL_OP_CISCO_ANYCONNECT: ssl_op_type!() = 0x00008000; + } else { + pub const SSL_OP_CISCO_ANYCONNECT: ssl_op_type!() = 0x0; + } +} + +pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: ssl_op_type!() = 0x00010000; +cfg_if! { + if #[cfg(ossl101)] { + pub const SSL_OP_NO_COMPRESSION: ssl_op_type!() = 0x00020000; + pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: ssl_op_type!() = 0x00040000; + } else { + pub const SSL_OP_NO_COMPRESSION: ssl_op_type!() = 0x0; + pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: ssl_op_type!() = 0x0; + } +} + +#[cfg(ossl111)] +pub const SSL_OP_ENABLE_MIDDLEBOX_COMPAT: ssl_op_type!() = 0x00100000; +#[cfg(ossl111)] +pub const SSL_OP_PRIORITIZE_CHACHA: ssl_op_type!() = 0x00200000; + +pub const SSL_OP_CIPHER_SERVER_PREFERENCE: ssl_op_type!() = 0x00400000; +cfg_if! { + if #[cfg(libressl280)] { + pub const SSL_OP_TLS_ROLLBACK_BUG: ssl_op_type!() = 0; + } else { + pub const SSL_OP_TLS_ROLLBACK_BUG: ssl_op_type!() = 0x00800000; + } +} + +cfg_if! { + if #[cfg(ossl101)] { + pub const SSL_OP_NO_SSLv3: ssl_op_type!() = 0x02000000; + } else { + pub const SSL_OP_NO_SSLv3: ssl_op_type!() = 0x0; + } +} +pub const SSL_OP_NO_TLSv1_1: ssl_op_type!() = 0x10000000; +pub const SSL_OP_NO_TLSv1_2: ssl_op_type!() = 0x08000000; + +pub const SSL_OP_NO_TLSv1: ssl_op_type!() = 0x04000000; +cfg_if! { + if #[cfg(ossl102)] { + pub const SSL_OP_NO_DTLSv1: ssl_op_type!() = 0x04000000; + pub const SSL_OP_NO_DTLSv1_2: ssl_op_type!() = 0x08000000; + } else if #[cfg(libressl332)] { + pub const SSL_OP_NO_DTLSv1: ssl_op_type!() = 0x40000000; + pub const SSL_OP_NO_DTLSv1_2: ssl_op_type!() = 0x80000000; + } +} +#[cfg(any(ossl111, libressl340))] +pub const SSL_OP_NO_TLSv1_3: ssl_op_type!() = 0x20000000; + +#[cfg(ossl110h)] +pub const SSL_OP_NO_RENEGOTIATION: ssl_op_type!() = 0x40000000; + +cfg_if! { + if #[cfg(ossl111)] { + pub const SSL_OP_NO_SSL_MASK: ssl_op_type!() = SSL_OP_NO_SSLv2 + | SSL_OP_NO_SSLv3 + | SSL_OP_NO_TLSv1 + | SSL_OP_NO_TLSv1_1 + | SSL_OP_NO_TLSv1_2 + | SSL_OP_NO_TLSv1_3; + } else if #[cfg(ossl102)] { + pub const SSL_OP_NO_SSL_MASK: ssl_op_type!() = + SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; + } +} + +cfg_if! { + if #[cfg(libressl261)] { + pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: ssl_op_type!() = 0x0; + } else { + pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: ssl_op_type!() = 0x80000000; + } +} + +cfg_if! { + if #[cfg(ossl300)] { + pub const SSL_OP_ALL: ssl_op_type!() = SSL_OP_CRYPTOPRO_TLSEXT_BUG + | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + | SSL_OP_TLSEXT_PADDING + | SSL_OP_SAFARI_ECDHE_ECDSA_BUG; + } else if #[cfg(ossl110f)] { + pub const SSL_OP_ALL: ssl_op_type!() = SSL_OP_CRYPTOPRO_TLSEXT_BUG + | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + | SSL_OP_LEGACY_SERVER_CONNECT + | SSL_OP_TLSEXT_PADDING + | SSL_OP_SAFARI_ECDHE_ECDSA_BUG; + } else if #[cfg(libressl261)] { + pub const SSL_OP_ALL: ssl_op_type!() = 0x4; + } else if #[cfg(libressl)] { + pub const SSL_OP_ALL: ssl_op_type!() = 0x80000014; + } else { + pub const SSL_OP_ALL: ssl_op_type!() = 0x80000BFF; + } +} + +cfg_if! { + if #[cfg(ossl110)] { + pub const SSL_OP_MICROSOFT_SESS_ID_BUG: ssl_op_type!() = 0x00000000; + pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: ssl_op_type!() = 0x00000000; + pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: ssl_op_type!() = 0x00000000; + pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: ssl_op_type!() = 0x00000000; + pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: ssl_op_type!() = 0x00000000; + pub const SSL_OP_TLS_D5_BUG: ssl_op_type!() = 0x00000000; + pub const SSL_OP_TLS_BLOCK_PADDING_BUG: ssl_op_type!() = 0x00000000; + pub const SSL_OP_SINGLE_ECDH_USE: ssl_op_type!() = 0x00000000; + pub const SSL_OP_SINGLE_DH_USE: ssl_op_type!() = 0x00000000; + pub const SSL_OP_NO_SSLv2: ssl_op_type!() = 0x00000000; + } else if #[cfg(ossl101)] { + pub const SSL_OP_MICROSOFT_SESS_ID_BUG: ssl_op_type!() = 0x00000001; + pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: ssl_op_type!() = 0x00000002; + pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: ssl_op_type!() = 0x00000008; + pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: ssl_op_type!() = 0x00000020; + pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: ssl_op_type!() = 0x00000080; + pub const SSL_OP_TLS_D5_BUG: ssl_op_type!() = 0x00000100; + pub const SSL_OP_TLS_BLOCK_PADDING_BUG: ssl_op_type!() = 0x00000200; + pub const SSL_OP_SINGLE_ECDH_USE: ssl_op_type!() = 0x00080000; + pub const SSL_OP_SINGLE_DH_USE: ssl_op_type!() = 0x00100000; + pub const SSL_OP_NO_SSLv2: ssl_op_type!() = 0x01000000; + } else { + pub const SSL_OP_MICROSOFT_SESS_ID_BUG: ssl_op_type!() = 0x0; + pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: ssl_op_type!() = 0x0; + pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: ssl_op_type!() = 0x0; + pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: ssl_op_type!() = 0x0; + pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: ssl_op_type!() = 0x0; + pub const SSL_OP_TLS_D5_BUG: ssl_op_type!() = 0x0; + pub const SSL_OP_TLS_BLOCK_PADDING_BUG: ssl_op_type!() = 0x0; + #[cfg(libressl261)] + pub const SSL_OP_SINGLE_ECDH_USE: ssl_op_type!() = 0x0; + #[cfg(not(libressl261))] + pub const SSL_OP_SINGLE_ECDH_USE: ssl_op_type!() = 0x00080000; + pub const SSL_OP_SINGLE_DH_USE: ssl_op_type!() = 0x00100000; + pub const SSL_OP_NO_SSLv2: ssl_op_type!() = 0x0; + } +} + +pub const SSL_MODE_ENABLE_PARTIAL_WRITE: c_long = 0x1; +pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 0x2; +pub const SSL_MODE_AUTO_RETRY: c_long = 0x4; +pub const SSL_MODE_NO_AUTO_CHAIN: c_long = 0x8; +pub const SSL_MODE_RELEASE_BUFFERS: c_long = 0x10; +#[cfg(ossl101)] +pub const SSL_MODE_SEND_CLIENTHELLO_TIME: c_long = 0x20; +#[cfg(ossl101)] +pub const SSL_MODE_SEND_SERVERHELLO_TIME: c_long = 0x40; +#[cfg(ossl101)] +pub const SSL_MODE_SEND_FALLBACK_SCSV: c_long = 0x80; + +pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut()) +} + +#[cfg(ossl111)] +pub const SSL_COOKIE_LENGTH: c_int = 4096; + +cfg_if! { + if #[cfg(not(ossl110))] { + pub unsafe fn SSL_CTX_get_options(ctx: *const SSL_CTX) -> c_ulong { + SSL_CTX_ctrl(ctx as *mut _, SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong + } + + pub unsafe fn SSL_CTX_set_options(ctx: *const SSL_CTX, op: c_ulong) -> c_ulong { + SSL_CTX_ctrl( + ctx as *mut _, + SSL_CTRL_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong + } + + pub unsafe fn SSL_CTX_clear_options(ctx: *const SSL_CTX, op: c_ulong) -> c_ulong { + SSL_CTX_ctrl( + ctx as *mut _, + SSL_CTRL_CLEAR_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong + } + } +} + +pub unsafe fn SSL_set_mtu(ssl: *mut SSL, mtu: c_long) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_MTU, mtu, ptr::null_mut()) +} + +#[cfg(ossl110)] +pub unsafe fn SSL_get_extms_support(ssl: *mut SSL) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_GET_EXTMS_SUPPORT, 0, ptr::null_mut()) +} + +pub const SSL_SESS_CACHE_OFF: c_long = 0x0; +pub const SSL_SESS_CACHE_CLIENT: c_long = 0x1; +pub const SSL_SESS_CACHE_SERVER: c_long = 0x2; +pub const SSL_SESS_CACHE_BOTH: c_long = SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_SERVER; +pub const SSL_SESS_CACHE_NO_AUTO_CLEAR: c_long = 0x80; +pub const SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: c_long = 0x100; +pub const SSL_SESS_CACHE_NO_INTERNAL_STORE: c_long = 0x200; +pub const SSL_SESS_CACHE_NO_INTERNAL: c_long = + SSL_SESS_CACHE_NO_INTERNAL_LOOKUP | SSL_SESS_CACHE_NO_INTERNAL_STORE; + +pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0; +pub const OPENSSL_NPN_NEGOTIATED: c_int = 1; +pub const OPENSSL_NPN_NO_OVERLAP: c_int = 2; + +pub const SSL_AD_ILLEGAL_PARAMETER: c_int = SSL3_AD_ILLEGAL_PARAMETER; +pub const SSL_AD_DECODE_ERROR: c_int = TLS1_AD_DECODE_ERROR; +pub const SSL_AD_UNRECOGNIZED_NAME: c_int = TLS1_AD_UNRECOGNIZED_NAME; +pub const SSL_ERROR_NONE: c_int = 0; +pub const SSL_ERROR_SSL: c_int = 1; +pub const SSL_ERROR_SYSCALL: c_int = 5; +pub const SSL_ERROR_WANT_ACCEPT: c_int = 8; +pub const SSL_ERROR_WANT_CONNECT: c_int = 7; +pub const SSL_ERROR_WANT_READ: c_int = 2; +pub const SSL_ERROR_WANT_WRITE: c_int = 3; +pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; +pub const SSL_ERROR_ZERO_RETURN: c_int = 6; +#[cfg(ossl111)] +pub const SSL_ERROR_WANT_CLIENT_HELLO_CB: c_int = 11; +pub const SSL_VERIFY_NONE: c_int = 0; +pub const SSL_VERIFY_PEER: c_int = 1; +pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; +pub const SSL_CTRL_SET_TMP_DH: c_int = 3; +pub const SSL_CTRL_SET_TMP_ECDH: c_int = 4; +#[cfg(any(libressl, all(ossl101, not(ossl110))))] +pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8; +pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; +pub const SSL_CTRL_SET_MTU: c_int = 17; +#[cfg(any(libressl, all(ossl101, not(ossl110))))] +pub const SSL_CTRL_OPTIONS: c_int = 32; +pub const SSL_CTRL_MODE: c_int = 33; +pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41; +pub const SSL_CTRL_SET_SESS_CACHE_SIZE: c_int = 42; +pub const SSL_CTRL_GET_SESS_CACHE_SIZE: c_int = 43; +pub const SSL_CTRL_SET_SESS_CACHE_MODE: c_int = 44; +pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53; +pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; +pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: c_int = 63; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: c_int = 64; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: c_int = 65; +pub const SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 70; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 71; +#[cfg(any(libressl, all(ossl101, not(ossl110))))] +pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; +pub const SSL_CTRL_GET_EXTRA_CHAIN_CERTS: c_int = 82; +#[cfg(ossl102)] +pub const SSL_CTRL_CHAIN_CERT: c_int = 89; +#[cfg(any(ossl111, libressl252))] +pub const SSL_CTRL_SET_GROUPS_LIST: c_int = 92; +#[cfg(any(libressl, all(ossl102, not(ossl110))))] +pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; +#[cfg(ossl102)] +pub const SSL_CTRL_SET_SIGALGS_LIST: c_int = 98; +#[cfg(ossl102)] +pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106; +#[cfg(ossl110)] +pub const SSL_CTRL_GET_EXTMS_SUPPORT: c_int = 122; +#[cfg(any(ossl110, libressl261))] +pub const SSL_CTRL_SET_MIN_PROTO_VERSION: c_int = 123; +#[cfg(any(ossl110, libressl261))] +pub const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124; +#[cfg(any(ossl110g, libressl270))] +pub const SSL_CTRL_GET_MIN_PROTO_VERSION: c_int = 130; +#[cfg(any(ossl110g, libressl270))] +pub const SSL_CTRL_GET_MAX_PROTO_VERSION: c_int = 131; + +pub unsafe fn SSL_CTX_set_tmp_dh(ctx: *mut SSL_CTX, dh: *mut DH) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) +} + +pub unsafe fn SSL_CTX_set_tmp_ecdh(ctx: *mut SSL_CTX, key: *mut EC_KEY) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) +} + +pub unsafe fn SSL_set_tmp_dh(ssl: *mut SSL, dh: *mut DH) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) +} + +pub unsafe fn SSL_set_tmp_ecdh(ssl: *mut SSL, key: *mut EC_KEY) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) +} + +pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509 as *mut c_void) +} + +pub unsafe fn SSL_CTX_get_extra_chain_certs( + ctx: *mut SSL_CTX, + chain: *mut *mut stack_st_X509, +) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_EXTRA_CHAIN_CERTS, 0, chain as *mut c_void) +} + +#[cfg(ossl102)] +pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) +} + +#[cfg(ossl102)] +pub unsafe fn SSL_set0_verify_cert_store(ssl: *mut SSL, st: *mut X509_STORE) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) +} + +cfg_if! { + if #[cfg(ossl111)] { + pub unsafe fn SSL_CTX_set1_groups_list(ctx: *mut SSL_CTX, s: *const c_char) -> c_long { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_GROUPS_LIST, + 0, + s as *const c_void as *mut c_void, + ) + } + } else if #[cfg(libressl251)] { + extern "C" { + pub fn SSL_CTX_set1_groups_list(ctx: *mut SSL_CTX, s: *const c_char) -> c_int; + } + } +} + +#[cfg(ossl102)] +pub unsafe fn SSL_add0_chain_cert(ssl: *mut SSL, ptr: *mut X509) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_CHAIN_CERT, 0, ptr as *mut c_void) +} + +#[cfg(ossl102)] +pub unsafe fn SSL_CTX_set1_sigalgs_list(ctx: *mut SSL_CTX, s: *const c_char) -> c_long { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_SIGALGS_LIST, + 0, + s as *const c_void as *mut c_void, + ) +} + +#[cfg(any(libressl, all(ossl102, not(ossl110))))] +pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_ECDH_AUTO, + onoff as c_long, + ptr::null_mut(), + ) as c_int +} + +#[cfg(any(libressl, all(ossl102, not(ossl110))))] +pub unsafe fn SSL_set_ecdh_auto(ssl: *mut SSL, onoff: c_int) -> c_int { + SSL_ctrl( + ssl, + SSL_CTRL_SET_ECDH_AUTO, + onoff as c_long, + ptr::null_mut(), + ) as c_int +} + +cfg_if! { + if #[cfg(ossl110)] { + pub unsafe fn SSL_CTX_set_min_proto_version(ctx: *mut SSL_CTX, version: c_int) -> c_int { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_MIN_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int + } + + pub unsafe fn SSL_CTX_set_max_proto_version(ctx: *mut SSL_CTX, version: c_int) -> c_int { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_MAX_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int + } + + pub unsafe fn SSL_set_min_proto_version(s: *mut SSL, version: c_int) -> c_int { + SSL_ctrl( + s, + SSL_CTRL_SET_MIN_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int + } + + pub unsafe fn SSL_set_max_proto_version(s: *mut SSL, version: c_int) -> c_int { + SSL_ctrl( + s, + SSL_CTRL_SET_MAX_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int + } + } +} + +cfg_if! { + if #[cfg(ossl110g)] { + pub unsafe fn SSL_CTX_get_min_proto_version(ctx: *mut SSL_CTX) -> c_int { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_MIN_PROTO_VERSION, 0, ptr::null_mut()) as c_int + } + + pub unsafe fn SSL_CTX_get_max_proto_version(ctx: *mut SSL_CTX) -> c_int { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_MAX_PROTO_VERSION, 0, ptr::null_mut()) as c_int + } + pub unsafe fn SSL_get_min_proto_version(s: *mut SSL) -> c_int { + SSL_ctrl(s, SSL_CTRL_GET_MIN_PROTO_VERSION, 0, ptr::null_mut()) as c_int + } + pub unsafe fn SSL_get_max_proto_version(s: *mut SSL) -> c_int { + SSL_ctrl(s, SSL_CTRL_GET_MAX_PROTO_VERSION, 0, ptr::null_mut()) as c_int + } + } +} + +#[cfg(ossl111)] +pub const SSL_CLIENT_HELLO_SUCCESS: c_int = 1; +#[cfg(ossl111)] +pub const SSL_CLIENT_HELLO_ERROR: c_int = 0; +#[cfg(ossl111)] +pub const SSL_CLIENT_HELLO_RETRY: c_int = -1; + +#[cfg(any(ossl111, libressl340))] +pub const SSL_READ_EARLY_DATA_ERROR: c_int = 0; +#[cfg(any(ossl111, libressl340))] +pub const SSL_READ_EARLY_DATA_SUCCESS: c_int = 1; +#[cfg(any(ossl111, libressl340))] +pub const SSL_READ_EARLY_DATA_FINISH: c_int = 2; + +cfg_if! { + if #[cfg(ossl110)] { + pub unsafe fn SSL_get_ex_new_index( + l: c_long, + p: *mut c_void, + newf: Option, + dupf: Option, + freef: Option, + ) -> c_int { + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, l, p, newf, dupf, freef) + } + } +} +cfg_if! { + if #[cfg(ossl110)] { + pub unsafe fn SSL_CTX_get_ex_new_index( + l: c_long, + p: *mut c_void, + newf: Option, + dupf: Option, + freef: Option, + ) -> c_int { + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, l, p, newf, dupf, freef) + } + } +} + +pub unsafe fn SSL_CTX_sess_set_cache_size(ctx: *mut SSL_CTX, t: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SESS_CACHE_SIZE, t, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_sess_get_cache_size(ctx: *mut SSL_CTX) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_SESS_CACHE_SIZE, 0, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_set_session_cache_mode(ctx: *mut SSL_CTX, m: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SESS_CACHE_MODE, m, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_READ_AHEAD, m, ptr::null_mut()) +} + +#[allow(clashing_extern_declarations)] +extern "C" { + #[deprecated(note = "use SSL_CTX_set_tmp_dh_callback__fixed_rust instead")] + pub fn SSL_CTX_set_tmp_dh_callback( + ctx: *mut SSL_CTX, + dh: unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, + ); + #[deprecated(note = "use SSL_set_tmp_dh_callback__fixed_rust instead")] + pub fn SSL_set_tmp_dh_callback( + ctx: *mut SSL, + dh: unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, + ); + #[deprecated(note = "use SSL_CTX_set_tmp_ecdh_callback__fixed_rust instead")] + #[cfg(not(ossl110))] + pub fn SSL_CTX_set_tmp_ecdh_callback( + ctx: *mut SSL_CTX, + ecdh: unsafe extern "C" fn( + ssl: *mut SSL, + is_export: c_int, + keylength: c_int, + ) -> *mut EC_KEY, + ); + #[deprecated(note = "use SSL_set_tmp_ecdh_callback__fixed_rust instead")] + #[cfg(not(ossl110))] + pub fn SSL_set_tmp_ecdh_callback( + ssl: *mut SSL, + ecdh: unsafe extern "C" fn( + ssl: *mut SSL, + is_export: c_int, + keylength: c_int, + ) -> *mut EC_KEY, + ); + + #[deprecated(note = "use SSL_CTX_callback_ctrl__fixed_rust instead")] + pub fn SSL_CTX_callback_ctrl( + ctx: *mut SSL_CTX, + cmd: c_int, + fp: Option, + ) -> c_long; + + #[deprecated(note = "use SSL_CTX_set_alpn_select_cb__fixed_rust instead")] + #[cfg(any(ossl102, libressl261))] + pub fn SSL_CTX_set_alpn_select_cb( + ssl: *mut SSL_CTX, + cb: extern "C" fn( + ssl: *mut SSL, + out: *mut *const c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + arg: *mut c_void, + ) -> c_int, + arg: *mut c_void, + ); +} + +#[cfg(not(ossl110))] +pub unsafe fn SSL_session_reused(ssl: *mut SSL) -> c_int { + SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int +} + +#[cfg(ossl110)] +pub const OPENSSL_INIT_LOAD_SSL_STRINGS: u64 = 0x00200000; +#[cfg(ossl111b)] +pub const OPENSSL_INIT_NO_ATEXIT: u64 = 0x00080000; diff --git a/openssl-sys/src/ssl3.rs b/openssl-sys/src/ssl3.rs new file mode 100644 index 0000000..822613e --- /dev/null +++ b/openssl-sys/src/ssl3.rs @@ -0,0 +1,5 @@ +use libc::*; + +pub const SSL3_VERSION: c_int = 0x300; + +pub const SSL3_AD_ILLEGAL_PARAMETER: c_int = 47; diff --git a/openssl-sys/src/tls1.rs b/openssl-sys/src/tls1.rs new file mode 100644 index 0000000..f7ae302 --- /dev/null +++ b/openssl-sys/src/tls1.rs @@ -0,0 +1,94 @@ +use libc::*; +use std::mem; +use std::ptr; + +use super::*; + +pub const TLS1_VERSION: c_int = 0x301; +pub const TLS1_1_VERSION: c_int = 0x302; +pub const TLS1_2_VERSION: c_int = 0x303; +#[cfg(any(ossl111, libressl340))] +pub const TLS1_3_VERSION: c_int = 0x304; + +pub const TLS1_AD_DECODE_ERROR: c_int = 50; +pub const TLS1_AD_UNRECOGNIZED_NAME: c_int = 112; + +pub const TLSEXT_NAMETYPE_host_name: c_int = 0; +pub const TLSEXT_STATUSTYPE_ocsp: c_int = 1; + +pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long { + SSL_ctrl( + s, + SSL_CTRL_SET_TLSEXT_HOSTNAME, + TLSEXT_NAMETYPE_host_name as c_long, + name as *mut c_void, + ) +} + +pub unsafe fn SSL_set_tlsext_status_type(s: *mut SSL, type_: c_int) -> c_long { + SSL_ctrl( + s, + SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, + type_ as c_long, + ptr::null_mut(), + ) +} + +pub unsafe fn SSL_get_tlsext_status_ocsp_resp(ssl: *mut SSL, resp: *mut *mut c_uchar) -> c_long { + SSL_ctrl( + ssl, + SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, + 0, + resp as *mut c_void, + ) +} + +pub unsafe fn SSL_set_tlsext_status_ocsp_resp( + ssl: *mut SSL, + resp: *mut c_uchar, + len: c_long, +) -> c_long { + SSL_ctrl( + ssl, + SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, + len, + resp as *mut c_void, + ) +} + +#[deprecated(note = "use SSL_CTX_set_tlsext_servername_callback__fixed_rust instead")] +#[allow(deprecated)] +pub unsafe fn SSL_CTX_set_tlsext_servername_callback( + ctx: *mut SSL_CTX, + // FIXME should have the right signature + cb: Option, +) -> c_long { + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cb) +} + +pub unsafe fn SSL_CTX_set_tlsext_servername_callback__fixed_rust( + ctx: *mut SSL_CTX, + cb: Option c_int>, +) -> c_long { + SSL_CTX_callback_ctrl__fixed_rust(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, mem::transmute(cb)) +} + +pub const SSL_TLSEXT_ERR_OK: c_int = 0; +pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1; +pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2; +pub const SSL_TLSEXT_ERR_NOACK: c_int = 3; + +pub unsafe fn SSL_CTX_set_tlsext_servername_arg(ctx: *mut SSL_CTX, arg: *mut c_void) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg) +} + +pub unsafe fn SSL_CTX_set_tlsext_status_cb( + ctx: *mut SSL_CTX, + cb: Option c_int>, +) -> c_long { + SSL_CTX_callback_ctrl__fixed_rust(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, mem::transmute(cb)) +} + +pub unsafe fn SSL_CTX_set_tlsext_status_arg(ctx: *mut SSL_CTX, arg: *mut c_void) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG, 0, arg) +} diff --git a/openssl-sys/src/types.rs b/openssl-sys/src/types.rs new file mode 100644 index 0000000..10c8f67 --- /dev/null +++ b/openssl-sys/src/types.rs @@ -0,0 +1,21 @@ +use libc::*; + +use super::*; + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum EVP_PKEY {} + } else { + #[repr(C)] + pub struct EVP_PKEY { + pub type_: c_int, + pub save_type: c_int, + pub references: c_int, + pub ameth: *const EVP_PKEY_ASN1_METHOD, + pub engine: *mut ENGINE, + pub pkey: *mut c_void, + pub save_parameters: c_int, + pub attributes: *mut stack_st_X509_ATTRIBUTE, + } + } +} diff --git a/openssl-sys/src/x509.rs b/openssl-sys/src/x509.rs new file mode 100644 index 0000000..714b06c --- /dev/null +++ b/openssl-sys/src/x509.rs @@ -0,0 +1,15 @@ +use libc::*; + +pub const X509_FILETYPE_PEM: c_int = 1; +pub const X509_FILETYPE_ASN1: c_int = 2; +pub const X509_FILETYPE_DEFAULT: c_int = 3; + +pub const ASN1_R_HEADER_TOO_LONG: c_int = 123; + +cfg_if! { + if #[cfg(not(any(ossl110, libressl350)))] { + pub const X509_LU_FAIL: c_int = 0; + pub const X509_LU_X509: c_int = 1; + pub const X509_LU_CRL: c_int = 2; + } +} diff --git a/openssl-sys/src/x509_vfy.rs b/openssl-sys/src/x509_vfy.rs new file mode 100644 index 0000000..2fa176f --- /dev/null +++ b/openssl-sys/src/x509_vfy.rs @@ -0,0 +1,149 @@ +use libc::*; + +use super::*; + +pub const X509_V_OK: c_int = 0; +#[cfg(ossl102f)] +pub const X509_V_ERR_UNSPECIFIED: c_int = 1; +pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; +pub const X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; +pub const X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; +pub const X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; +pub const X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; +pub const X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; +pub const X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; +pub const X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; +pub const X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; +pub const X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; +pub const X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; +pub const X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; +pub const X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; +pub const X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; +pub const X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; +pub const X509_V_ERR_OUT_OF_MEM: c_int = 17; +pub const X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; +pub const X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; +pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; +pub const X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; +pub const X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; +pub const X509_V_ERR_CERT_REVOKED: c_int = 23; +cfg_if! { + if #[cfg(ossl300)] { + pub const X509_V_ERR_NO_ISSUER_PUBLIC_KEY: c_int = 24; + } else { + pub const X509_V_ERR_INVALID_CA: c_int = 24; + } +} +pub const X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; +pub const X509_V_ERR_INVALID_PURPOSE: c_int = 26; +pub const X509_V_ERR_CERT_UNTRUSTED: c_int = 27; +pub const X509_V_ERR_CERT_REJECTED: c_int = 28; +pub const X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; +pub const X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; +pub const X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; +pub const X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; +pub const X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; +pub const X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; +pub const X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; +pub const X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; +pub const X509_V_ERR_INVALID_NON_CA: c_int = 37; +pub const X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; +pub const X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; +pub const X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; +pub const X509_V_ERR_INVALID_EXTENSION: c_int = 41; +pub const X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; +pub const X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; +pub const X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; +pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; +pub const X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; +pub const X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; +pub const X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; +pub const X509_V_ERR_SUBTREE_MINMAX: c_int = 49; +pub const X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; +pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; +pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; +pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; +pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_VERSION: c_int = 56; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_ALGORITHM: c_int = 57; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_CURVE: c_int = 58; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: c_int = 59; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: c_int = 60; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: c_int = 61; +#[cfg(ossl102)] +pub const X509_V_ERR_HOSTNAME_MISMATCH: c_int = 62; +#[cfg(ossl102)] +pub const X509_V_ERR_EMAIL_MISMATCH: c_int = 63; +#[cfg(ossl102)] +pub const X509_V_ERR_IP_ADDRESS_MISMATCH: c_int = 64; +cfg_if! { + if #[cfg(ossl110)] { + pub const X509_V_ERR_DANE_NO_MATCH: c_int = 65; + pub const X509_V_ERR_EE_KEY_TOO_SMALL: c_int = 66; + pub const X509_V_ERR_CA_KEY_TOO_SMALL: c_int = 67; + pub const X509_V_ERR_CA_MD_TOO_WEAK: c_int = 68; + pub const X509_V_ERR_INVALID_CALL: c_int = 69; + pub const X509_V_ERR_STORE_LOOKUP: c_int = 70; + pub const X509_V_ERR_NO_VALID_SCTS: c_int = 71; + } else if #[cfg(ossl102h)] { + pub const X509_V_ERR_INVALID_CALL: c_int = 65; + pub const X509_V_ERR_STORE_LOOKUP: c_int = 66; + pub const X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION: c_int = 67; + } +} +#[cfg(ossl300)] +pub const X509_V_ERR_INVALID_CA: c_int = 79; + +#[cfg(not(any(ossl110, libressl370)))] +pub const X509_V_FLAG_CB_ISSUER_CHECK: c_ulong = 0x1; +#[cfg(any(ossl110, libressl370))] +pub const X509_V_FLAG_CB_ISSUER_CHECK: c_ulong = 0x0; +pub const X509_V_FLAG_USE_CHECK_TIME: c_ulong = 0x2; +pub const X509_V_FLAG_CRL_CHECK: c_ulong = 0x4; +pub const X509_V_FLAG_CRL_CHECK_ALL: c_ulong = 0x8; +pub const X509_V_FLAG_IGNORE_CRITICAL: c_ulong = 0x10; +pub const X509_V_FLAG_X509_STRICT: c_ulong = 0x20; +pub const X509_V_FLAG_ALLOW_PROXY_CERTS: c_ulong = 0x40; +pub const X509_V_FLAG_POLICY_CHECK: c_ulong = 0x80; +pub const X509_V_FLAG_EXPLICIT_POLICY: c_ulong = 0x100; +pub const X509_V_FLAG_INHIBIT_ANY: c_ulong = 0x200; +pub const X509_V_FLAG_INHIBIT_MAP: c_ulong = 0x400; +pub const X509_V_FLAG_NOTIFY_POLICY: c_ulong = 0x800; +pub const X509_V_FLAG_EXTENDED_CRL_SUPPORT: c_ulong = 0x1000; +pub const X509_V_FLAG_USE_DELTAS: c_ulong = 0x2000; +pub const X509_V_FLAG_CHECK_SS_SIGNATURE: c_ulong = 0x4000; +#[cfg(ossl102)] +pub const X509_V_FLAG_TRUSTED_FIRST: c_ulong = 0x8000; +#[cfg(ossl102)] +pub const X509_V_FLAG_SUITEB_128_LOS_ONLY: c_ulong = 0x10000; +#[cfg(ossl102)] +pub const X509_V_FLAG_SUITEB_192_LOS: c_ulong = 0x20000; +#[cfg(ossl102)] +pub const X509_V_FLAG_SUITEB_128_LOS: c_ulong = 0x30000; +#[cfg(ossl102)] +pub const X509_V_FLAG_PARTIAL_CHAIN: c_ulong = 0x80000; +#[cfg(ossl110)] +pub const X509_V_FLAG_NO_ALT_CHAINS: c_ulong = 0x100000; +#[cfg(ossl110)] +pub const X509_V_FLAG_NO_CHECK_TIME: c_ulong = 0x200000; + +pub unsafe fn X509_LOOKUP_add_dir( + ctx: *mut X509_LOOKUP, + name: *const c_char, + _type: c_int, +) -> c_int { + const X509_L_ADD_DIR: c_int = 2; + X509_LOOKUP_ctrl( + ctx, + X509_L_ADD_DIR, + name, + _type as c_long, + std::ptr::null_mut(), + ) +} diff --git a/openssl-sys/src/x509v3.rs b/openssl-sys/src/x509v3.rs new file mode 100644 index 0000000..5ae4439 --- /dev/null +++ b/openssl-sys/src/x509v3.rs @@ -0,0 +1,93 @@ +use libc::*; + +use super::*; + +#[repr(C)] +pub struct GENERAL_NAME { + pub type_: c_int, + // FIXME should be a union + pub d: *mut c_void, +} + +stack!(stack_st_GENERAL_NAME); + +pub const GEN_OTHERNAME: c_int = 0; +pub const GEN_EMAIL: c_int = 1; +pub const GEN_DNS: c_int = 2; +pub const GEN_X400: c_int = 3; +pub const GEN_DIRNAME: c_int = 4; +pub const GEN_EDIPARTY: c_int = 5; +pub const GEN_URI: c_int = 6; +pub const GEN_IPADD: c_int = 7; +pub const GEN_RID: c_int = 8; + +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10; +#[cfg(ossl110)] +pub const X509_CHECK_FLAG_NEVER_CHECK_SUBJECT: c_uint = 0x20; + +pub const X509V3_ADD_DEFAULT: c_ulong = 0; +pub const X509V3_ADD_APPEND: c_ulong = 1; +pub const X509V3_ADD_REPLACE: c_ulong = 2; +pub const X509V3_ADD_REPLACE_EXISTING: c_ulong = 3; +pub const X509V3_ADD_KEEP_EXISTING: c_ulong = 4; +pub const X509V3_ADD_DELETE: c_ulong = 5; +pub const X509V3_ADD_SILENT: c_ulong = 0x10; + +pub const EXFLAG_BCONS: u32 = 0x1; +pub const EXFLAG_KUSAGE: u32 = 0x2; +pub const EXFLAG_XKUSAGE: u32 = 0x4; +pub const EXFLAG_NSCERT: u32 = 0x8; +pub const EXFLAG_CA: u32 = 0x10; +pub const EXFLAG_SI: u32 = 0x20; +pub const EXFLAG_V1: u32 = 0x40; +pub const EXFLAG_INVALID: u32 = 0x80; +pub const EXFLAG_SET: u32 = 0x100; +pub const EXFLAG_CRITICAL: u32 = 0x200; +pub const EXFLAG_PROXY: u32 = 0x400; +pub const EXFLAG_INVALID_POLICY: u32 = 0x800; +pub const EXFLAG_FRESHEST: u32 = 0x1000; +#[cfg(any(ossl102, libressl261))] +pub const EXFLAG_SS: u32 = 0x2000; + +pub const X509v3_KU_DIGITAL_SIGNATURE: u32 = 0x0080; +pub const X509v3_KU_NON_REPUDIATION: u32 = 0x0040; +pub const X509v3_KU_KEY_ENCIPHERMENT: u32 = 0x0020; +pub const X509v3_KU_DATA_ENCIPHERMENT: u32 = 0x0010; +pub const X509v3_KU_KEY_AGREEMENT: u32 = 0x0008; +pub const X509v3_KU_KEY_CERT_SIGN: u32 = 0x0004; +pub const X509v3_KU_CRL_SIGN: u32 = 0x0002; +pub const X509v3_KU_ENCIPHER_ONLY: u32 = 0x0001; +pub const X509v3_KU_DECIPHER_ONLY: u32 = 0x8000; +pub const X509v3_KU_UNDEF: u32 = 0xffff; + +pub const XKU_SSL_SERVER: u32 = 0x1; +pub const XKU_SSL_CLIENT: u32 = 0x2; +pub const XKU_SMIME: u32 = 0x4; +pub const XKU_CODE_SIGN: u32 = 0x8; +pub const XKU_SGC: u32 = 0x10; +pub const XKU_OCSP_SIGN: u32 = 0x20; +pub const XKU_TIMESTAMP: u32 = 0x40; +pub const XKU_DVCS: u32 = 0x80; +#[cfg(ossl110)] +pub const XKU_ANYEKU: u32 = 0x100; + +pub const X509_PURPOSE_SSL_CLIENT: c_int = 1; +pub const X509_PURPOSE_SSL_SERVER: c_int = 2; +pub const X509_PURPOSE_NS_SSL_SERVER: c_int = 3; +pub const X509_PURPOSE_SMIME_SIGN: c_int = 4; +pub const X509_PURPOSE_SMIME_ENCRYPT: c_int = 5; +pub const X509_PURPOSE_CRL_SIGN: c_int = 6; +pub const X509_PURPOSE_ANY: c_int = 7; +pub const X509_PURPOSE_OCSP_HELPER: c_int = 8; +pub const X509_PURPOSE_TIMESTAMP_SIGN: c_int = 9; +pub const X509_PURPOSE_MIN: c_int = 1; +pub const X509_PURPOSE_MAX: c_int = 9; diff --git a/openssl/CHANGELOG.md b/openssl/CHANGELOG.md new file mode 100644 index 0000000..7de74b8 --- /dev/null +++ b/openssl/CHANGELOG.md @@ -0,0 +1,749 @@ +# Change Log + +## [Unreleased] + +## [v0.10.47] - 2023-03-19 + +### Added + +* Added support for X25519 and Ed25519 on LibreSSL and BoringSSL. +* Added `Error::library_code` and `Error::reason_code`. + +## [v0.10.46] - 2023-03-14 + +### Fixed + +* Fixed a potential null-pointer deref when parsing a PKCS#12 archive with no identity. +* Fixed builds against OpenSSL built with `no-cast`. +* Fixed debug formatting of `GeneralName`. + +### Deprecated + +* Deprecated `PKcs12Ref::parse` in favor of `Pkcs12Ref::parse2`. +* Deprecated `ParsedPkcs12` in favor of `ParsedPkcs12_2`. +* Deprecated `Pkcs12Builder::build` in favor of `Pkcs12Builder::build2`. + +### Added + +* Added `X509VerifyParamRef::set_auth_level`, `X509VerifyParamRef::auth_level`, and `X509VerifyParamRef::set_purpose`. +* Added `X509PurposeId` and `X509Purpose`. +* Added `X509NameBuilder::append_entry`. +* Added `PKeyRef::private_key_to_pkcs8`. +* Added `X509LookupRef::load_crl_file`. +* Added `Pkcs12Builder::name`, `Pkcs12Builder::pkey`, and `Pkcs12Builder::cert`. +* Added `SslRef::set_method`, `SslRef::set_private_key_file`, `SslRef::set_private_key`, `SslRef::set_certificate`, `SslRef::set_certificate_chain_file`, `SslRef::add_client_ca`, `SslRef::set_client_ca_list`, `SslRef::set_min_proto_version`, `SslREf::set_max_proto_version`, `SslRef::set_ciphersuites`, `SslRef::set_cipher_list`, `SslRef::set_verify_cert_store`. +* Added `X509NameRef::to_owned`. +* Added `SslContextBuilder::set_num_tickets`, `SslContextRef::num_tickets`, `SslRef::set_num_tickets`, and `SslRef::num_tickets`. +* Added `CmsContentInfo::verify`. + +## [v0.10.45] - 2022-12-20 + +### Fixed + +* Removed the newly added `CipherCtxRef::minimal_output_size` method, which did not work properly. +* Added `NO_DEPRECATED_3_0` cfg checks for more APIs. + +### Added + +* Added `SslRef::add_chain_cert`. +* Added `PKeyRef::security_bits`. +* Added `Provider::set_default_search_path`. +* Added `CipherCtxRef::cipher_final_unchecked`. + +## [v0.10.44] - 2022-12-06 + +### Added + +* Added `CipherCtxRef::num`, `CipherCtxRef::minimal_output_size`, and `CipherCtxRef::cipher_update_unchecked`. +* Improved output buffer size checks in `CipherCtxRef::cipher_update`. +* Added `X509Lookup::file` and `X509LookupRef::load_cert_file`. + +## [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 + +* Added `Pkey::ec_gen`. + +## [v0.10.37] - 2021-10-27 + +### Fixed + +* Fixed linkage against OpenSSL distributions built with `no-chacha`. + +### Added + +* Added `BigNumRef::to_vec_padded`. +* Added `X509Name::from_der` and `X509NameRef::to_der`. +* Added `BigNum::new_secure`, `BigNumReef::set_const_time`, `BigNumref::is_const_time`, and `BigNumRef::is_secure`. + +## [v0.10.36] - 2021-08-17 + +### Added + +* Added `Asn1Object::as_slice`. +* Added `PKeyRef::{raw_public_key, raw_private_key, private_key_to_pkcs8_passphrase}` and + `PKey::{private_key_from_raw_bytes, public_key_from_raw_bytes}`. +* Added `Cipher::{seed_cbc, seed_cfb128, seed_ecb, seed_ofb}`. + +## [v0.10.35] - 2021-06-18 + +### Fixed + +* Fixed a memory leak in `Deriver`. + +### Added + +* Added support for OpenSSL 3.x.x. +* Added `SslStream::peek`. + +## [v0.10.34] - 2021-04-28 + +### Added + +* Added `Dh::set_private_key` and `DhRef::private_key`. +* Added `EcPointRef::affine_coordinates`. +* Added `TryFrom` implementations to convert between `PKey` and specific key types. +* Added `X509StoreBuilderRef::set_flags`. + +## [v0.10.33] - 2021-03-13 + +### Fixed + +* `Dh::generate_params` now uses `DH_generate_params_ex` rather than the deprecated `DH_generated_params` function. + +### Added + +* Added `Asn1Type`. +* Added `CmsContentInfoRef::decrypt_without_cert_check`. +* Added `EcPointRef::{is_infinity, is_on_curve}`. +* Added `Encrypter::set_rsa_oaep_label`. +* Added `MessageDigest::sm3`. +* Added `Pkcs7Ref::signers`. +* Added `Cipher::nid`. +* Added `X509Ref::authority_info` and `AccessDescription::{method, location}`. +* Added `X509NameBuilder::{append_entry_by_text_with_type, append_entry_by_nid_with_type}`. + +## [v0.10.32] - 2020-12-24 + +### Fixed + +* Fixed `Ssl::new` to take a `&SslContextRef` rather than `&SslContext`. + +### Added + +* Added the `encrypt` module to support asymmetric encryption and decryption with `PKey`s. +* Added `MessageDigest::from_name`. +* Added `ConnectConfiguration::into_ssl`. +* Added the ability to create unconnected `SslStream`s directly from an `Ssl` and transport stream + without performing any part of the handshake with `SslStream::new`. +* Added `SslStream::{read_early_data, write_early_data, connect, accept, do_handshake, stateless}`. +* Implemented `ToOwned` for `SslContextRef`. +* Added `SslRef::{set_connect_state, set_accept_state}`. + +### Deprecated + +* Deprecated `SslStream::from_raw_parts` in favor of `Ssl::from_ptr` and `SslStream::new`. +* Deprecated `SslStreamBuilder` in favor of methods on `Ssl` and `SslStream`. + +## [v0.10.31] - 2020-12-09 + +### Added + +* Added `Asn1Object::from_str`. +* Added `Dh::from_pgq`, `DhRef::prime_p`, `DhRef::prime_q`, `DhRef::generator`, `DhRef::generate_params`, + `DhRef::generate_key`, `DhRef::public_key`, and `DhRef::compute_key`. +* Added `Pkcs7::from_der` and `Pkcs7Ref::to_der`. +* Added `Id::X25519`, `Id::X448`, `PKey::generate_x25519`, and `PKey::generate_x448`. +* Added `SrtpProfileId::SRTP_AEAD_AES_128_GCM` and `SrtpProfileId::SRTP_AEAD_AES_256_GCM`. +* Added `SslContextBuilder::verify_param` and `SslContextBuilder::verify_param_mut`. +* Added `X509Ref::subject_name_hash` and `X509Ref::version`. +* Added `X509StoreBuilderRef::add_lookup`, and the `X509Lookup` type. +* Added `X509VerifyFlags`, `X509VerifyParamRef::set_flags`, `X509VerifyParamRef::clear_flags` + `X509VerifyParamRef::get_flags`. + +## [v0.10.30] - 2020-06-25 + +### Fixed + +* `DsaRef::private_key_to_pem` can no longer be called without a private key. + +### Changed + +* Improved the `Debug` implementations of many types. + +### Added + +* Added `is_empty` implementations for `Asn1StringRef` and `Asn1BitStringRef`. +* Added `EcPointRef::{to_pem, to_dir}` and `EcKeyRef::{public_key_from_pem, public_key_from_der}`. +* Added `Default` implementations for many types. +* Added `Debug` implementations for many types. +* Added `SslStream::from_raw_parts`. +* Added `SslRef::set_mtu`. +* Added `Cipher::{aes_128_ocb, aes_192_ocb, aes_256_ocb}`. + +### Deprecated + +* Deprecated `SslStreamBuilder::set_dtls_mtu_size` in favor of `SslRef::set_mtu`. + +## [v0.10.29] - 2020-04-07 + +### Fixed + +* Fixed a memory leak in `X509Builder::append_extension`. + +### Added + +* Added `SslConnector::into_context` and `SslConnector::context`. +* Added `SslAcceptor::into_context` and `SslAcceptor::context`. +* Added `SslMethod::tls_client` and `SslMethod::tls_server`. +* Added `SslContextBuilder::set_cert_store`. +* Added `SslContextRef::verify_mode` and `SslRef::verify_mode`. +* Added `SslRef::is_init_finished`. +* Added `X509Object`. +* Added `X509StoreRef::objects`. + +## [v0.10.28] - 2020-02-04 + +### Fixed + +* Fixed the mutability of `Signer::sign_oneshot` and `Verifier::verify_oneshot`. This is unfortunately a breaking + change, but a necessary soundness fix. + +## [v0.10.27] - 2020-01-29 + +### Added + +* Added `MessageDigest::null`. +* Added `PKey::private_key_from_pkcs8`. +* Added `SslOptions::NO_RENEGOTIATION`. +* Added `SslStreamBuilder::set_dtls_mtu_size`. + +## [v0.10.26] - 2019-11-22 + +### Fixed + +* Fixed improper handling of the IV buffer in `envelope::{Seal, Unseal}`. + +### Added + +* Added `Asn1TimeRef::{diff, compare}`. +* Added `Asn1Time::from_unix`. +* Added `PartialEq` and `PartialOrd` implementations for `Asn1Time` and `Asn1TimeRef`. +* Added `base64::{encode_block, decode_block}`. +* Added `EcGroupRef::order_bits`. +* Added `Clone` implementations for `Sha1`, `Sha224`, `Sha256`, `Sha384`, and `Sha512`. +* Added `SslContextBuilder::{set_sigalgs_list, set_groups_list}`. + +## [v0.10.25] - 2019-10-02 + +### Fixed + +* Fixed a memory leak in `EcdsaSig::from_private_components` when using OpenSSL 1.0.x. + +### Added + +* Added support for Ed25519 and Ed448 keys. +* Implemented `ToOwned` for `PKeyRef` and `Clone` for `PKey`. + +## [v0.10.24] - 2019-07-19 + +### Fixed + +* Worked around an OpenSSL 1.0.x bug triggered by code calling `SSL_set_app_data`. + +### Added + +* Added `aes::{wrap_key, unwrap_key}`. +* Added `CmsContentInfoRef::to_pem` and `CmsContentInfo::from_pem`. +* Added `DsaRef::private_key_to_pem`. +* Added `EcGroupRef::{cofactor, generator}`. +* Added `EcPointRef::to_owned`. +* Added a `Debug` implementation for `EcKey`. +* Added `SslAcceptor::{mozilla_intermediate_v5, mozilla_modern_v5}`. +* Added `Cipher::{aes_128_ofb, aes_192_ecb, aes_192_cbc, aes_192_ctr, aes_192_cfb1, aes_192_cfb128, aes_192_cfb8, + aes_192_gcm, aes_192_ccm, aes_192_ofb, aes_256_ofb}`. + +## [v0.10.23] - 2019-05-18 + +### Fixed + +* Fixed session callbacks when an `Ssl`'s context is replaced. + +### Added + +* Added `SslContextBuilder::add_client_ca`. + +## [v0.10.22] - 2019-05-08 + +### Added + +* Added support for the LibreSSL 2.9.x series. + +## [v0.10.21] - 2019-04-30 + +### Fixed + +* Fixed overly conservatifve buffer size checks in `Crypter` when using stream ciphers. + +### Added + +* Added bindings to envelope encryption APIs. +* Added `PkeyRef::size`. + +## [v0.10.20] - 2019-03-20 + +### Added + +* Added `CmsContentInfo::from_der` and `CmsContentInfo::encrypt`. +* Added `X509Ref::verify` and `X509ReqRef::verify`. +* Implemented `PartialEq` and `Eq` for `MessageDigest`. +* Added `MessageDigest::type_` and `EcGroupRef::curve_name`. + +## [v0.10.19] - 2019-03-01 + +### Added + +* The openssl-sys build script now logs the values of environment variables. +* Added `ERR_PACK` to openssl-sys. +* The `ERR_*` functions in openssl-sys are const functions when building against newer Rust versions. +* Implemented `Clone` for `Dsa`. +* Added `SslContextRef::add_session` and `SslContextRef::remove_session`. +* Added `SslSessionRef::time`, `SslSessionRef::timeout`, and `SslSessionRef::protocol_version`. +* Added `SslContextBuilder::set_session_cache_size` and `SslContextRef::session_cache_size`. + +## [v0.10.18] - 2019-02-22 + +### Fixed + +* Fixed the return type of `ssl::cipher_name`. + +## [v0.10.17] - 2019-02-22 + +### Added + +* Implemented `AsRef` and `AsRef<[u8]>` for `OpenSslString`. +* Added `Asn1Integer::from_bn`. +* Added `RsaRef::check_key`. +* Added `Asn1Time::from_str` and `Asn1Time::from_str_x509`. +* Added `Rsa::generate_with_e`. +* Added `Cipher::des_ede3_cfb64`. +* Added `SslCipherRef::standard_name` and `ssl::cipher_name`. + +## [v0.10.16] - 2018-12-16 + +### Added + +* Added SHA3 and SHAKE to `MessageDigest`. +* Added `rand::keep_random_devices_open`. +* Added support for LibreSSL 2.9.0. + +## [v0.10.15] - 2018-10-22 + +### Added + +* Implemented `DoubleEndedIterator` for stack iterators. + +## [v0.10.14] - 2018-10-18 + +### Fixed + +* Made some accidentally exposed internal functions private. + +### Added + +* Added support for LibreSSL 2.8. + +### Changed + +* The OpenSSL version used with the `vendored` feature has been upgraded from 1.1.0 to 1.1.1. + +## [v0.10.13] - 2018-10-14 + +### Fixed + +* Fixed a double-free in the `SslContextBuilder::set_get_session_callback` API. + +### Added + +* Added `SslContextBuilder::set_client_hello_callback`. +* Added support for LibreSSL 2.8.1. +* Added `EcdsaSig::from_der` and `EcdsaSig::to_der`. +* Added PKCS#7 support. + +## [v0.10.12] - 2018-09-13 + +### Fixed + +* Fixed handling of SNI callbacks during renegotiation. + +### Added + +* Added `SslRef::get_shutdown` and `SslRef::set_shutdown`. +* Added support for SRTP in DTLS sessions. +* Added support for LibreSSL 2.8.0. + +## [v0.10.11] - 2018-08-04 + +### Added + +* The new `vendored` cargo feature will cause openssl-sys to compile and statically link to a + vendored copy of OpenSSL. +* Added `SslContextBuilder::set_psk_server_callback`. +* Added `DsaRef::pub_key` and `DsaRef::priv_key`. +* Added `Dsa::from_private_components` and `Dsa::from_public_components`. +* Added `X509NameRef::entries`. + +### Deprecated + +* `SslContextBuilder::set_psk_callback` has been renamed to + `SslContextBuilder::set_psk_client_callback` and deprecated. + +## [v0.10.10] - 2018-06-06 + +### Added + +* Added `SslRef::set_alpn_protos`. +* Added `SslContextBuilder::set_ciphersuites`. + +## [v0.10.9] - 2018-06-01 + +### Fixed + +* Fixed a use-after-free in `CmsContentInfo::sign`. +* `SslRef::servername` now returns `None` rather than panicking on a non-UTF8 name. + +### Added + +* Added `MessageDigest::from_nid`. +* Added `Nid::signature_algorithms`, `Nid::long_name`, and `Nid::short_name`. +* Added early data and early keying material export support for TLS 1.3. +* Added `SslRef::verified_chain`. +* Added `SslRef::servername_raw` which returns a `&[u8]` rather than `&str`. +* Added `SslRef::finished` and `SslRef::peer_finished`. +* Added `X509Ref::digest` to replace `X509Ref::fingerprint`. +* `X509StoreBuilder` and `X509Store` now implement `Sync` and `Send`. + +### Deprecated + +* `X509Ref::fingerprint` has been deprecated in favor of `X509Ref::digest`. + +## [v0.10.8] - 2018-05-20 + +### Fixed + +* `openssl-sys` will now detect Homebrew-installed OpenSSL when installed to a non-default + directory. +* The `X509_V_ERR_INVALID_CALL`, `X509_V_ERR_STORE_LOOKUP`, and + `X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION` constants in `openssl-sys` are now only present when + building against 1.1.0g and up rather than 1.1.0. +* `SslContextBuilder::max_proto_version` and `SslContextBuilder::min_proto_version` are only present + when building against 1.1.0g and up rather than 1.1.0. + +### Added + +* Added `CmsContentInfo::sign`. +* Added `Clone` and `ToOwned` implementations to `Rsa` and `RsaRef` respectively. +* The `min_proto_version` and `max_proto_version` methods are available when linking against + LibreSSL 2.6.1 and up in addition to OpenSSL. +* `X509VerifyParam` is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* ALPN support is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* `Stack` and `StackRef` are now `Sync` and `Send`. + +## [v0.10.7] - 2018-04-30 + +### Added + +* Added `X509Req::public_key` and `X509Req::extensions`. +* Added `RsaPrivateKeyBuilder` to allow control over initialization of optional components of an RSA + private key. +* Added DER encode/decode support to `SslSession`. +* openssl-sys now provides the `DEP_OPENSSL_VERSION_NUMBER` and + `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER` environment variables to downstream build scripts which + contains the hex-encoded version number of the OpenSSL or LibreSSL distribution being built + against. The other variables are deprecated. + +## [v0.10.6] - 2018-03-05 + +### Added + +* Added `SslOptions::ENABLE_MIDDLEBOX_COMPAT`. +* Added more `Sync` and `Send` implementations. +* Added `PKeyRef::id`. +* Added `Padding::PKCS1_PSS`. +* Added `Signer::set_rsa_pss_saltlen`, `Signer::set_rsa_mgf1_md`, `Signer::set_rsa_pss_saltlen`, and + `Signer::set_rsa_mgf1_md` +* Added `X509StoreContextRef::verify` to directly verify certificates. +* Added low level ECDSA support. +* Added support for TLSv1.3 custom extensions. (OpenSSL 1.1.1 only) +* Added AES-CCM support. +* Added `EcKey::from_private_components`. +* Added CMAC support. +* Added support for LibreSSL 2.7. +* Added `X509Ref::serial_number`. +* Added `Asn1IntegerRef::to_bn`. +* Added support for TLSv1.3 stateless handshakes. (OpenSSL 1.1.1 only) + +### Changed + +* The Cargo features previously used to gate access to version-specific OpenSSL APIs have been + removed. Those APIs will be available automatically when building against an appropriate OpenSSL + version. +* Fixed `PKey::private_key_from_der` to return a `PKey` rather than a `PKey`. This + is technically a breaking change but the function was pretty useless previously. + +### Deprecated + +* `X509CheckFlags::FLAG_NO_WILDCARDS` has been renamed to `X509CheckFlags::NO_WILDCARDS` and the old + name deprecated. + +## [v0.10.5] - 2018-02-28 + +### Fixed + +* `ErrorStack`'s `Display` implementation no longer writes an empty string if it contains no errors. + +### Added + +* Added `SslRef::version2`. +* Added `Cipher::des_ede3_cbc`. +* Added `SslRef::export_keying_material`. +* Added the ability to push an `Error` or `ErrorStack` back onto OpenSSL's error stack. Various + callback bindings use this to propagate errors properly. +* Added `SslContextBuilder::set_cookie_generate_cb` and `SslContextBuilder::set_cookie_verify_cb`. +* Added `SslContextBuilder::set_max_proto_version`, `SslContextBuilder::set_min_proto_version`, + `SslContextBuilder::max_proto_version`, and `SslContextBuilder::min_proto_version`. + +### Changed + +* Updated `SslConnector`'s default cipher list to match Python's. + +### Deprecated + +* `SslRef::version` has been deprecated. Use `SslRef::version_str` instead. + +## [v0.10.4] - 2018-02-18 + +### Added + +* Added OpenSSL 1.1.1 support. +* Added `Rsa::public_key_from_pem_pkcs1`. +* Added `SslOptions::NO_TLSV1_3`. (OpenSSL 1.1.1 only) +* Added `SslVersion`. +* Added `SslSessionCacheMode` and `SslContextBuilder::set_session_cache_mode`. +* Added `SslContextBuilder::set_new_session_callback`, + `SslContextBuilder::set_remove_session_callback`, and + `SslContextBuilder::set_get_session_callback`. +* Added `SslContextBuilder::set_keylog_callback`. (OpenSSL 1.1.1 only) +* Added `SslRef::client_random` and `SslRef::server_random`. (OpenSSL 1.1.0+ only) + +### Fixed + +* The `SslAcceptorBuilder::mozilla_modern` constructor now disables TLSv1.0 and TLSv1.1 in + accordance with Mozilla's recommendations. + +## [v0.10.3] - 2018-02-12 + +### Added + +* OpenSSL is now automatically detected on FreeBSD systems. +* Added `GeneralName` accessors for `rfc822Name` and `uri` variants. +* Added DES-EDE3 support. + +### Fixed + +* Fixed a memory leak in `X509StoreBuilder::add_cert`. + +## [v0.10.2] - 2018-01-11 + +### Added + +* Added `ConnectConfiguration::set_use_server_name_indication` and + `ConnectConfiguration::set_verify_hostname` for use in contexts where you don't have ownership + of the `ConnectConfiguration`. + +## [v0.10.1] - 2018-01-10 + +### Added + +* Added a `From for ssl::Error` implementation. + +## [v0.10.0] - 2018-01-10 + +### Compatibility + +* openssl 0.10 still uses openssl-sys 0.9, so openssl 0.9 and 0.10 can coexist without issue. + +### Added + +* The `ssl::select_next_proto` function can be used to easily implement the ALPN selection callback + in a "standard" way. +* FIPS mode support is available in the `fips` module. +* Accessors for the Issuer and Issuer Alternative Name fields of X509 certificates have been added. +* The `X509VerifyResult` can now be set in the certificate verification callback via + `X509StoreContextRef::set_error`. + +### Changed + +* All constants have been moved to associated constants of their type. For example, `bn::MSB_ONE` + is now `bn::MsbOption::ONE`. +* Asymmetric key types are now parameterized over what they contain. In OpenSSL, the same type is + used for key parameters, public keys, and private keys. Unfortunately, some APIs simply assume + that certain components are present and will segfault trying to use things that aren't there. + + The `pkey` module contains new tag types named `Params`, `Public`, and `Private`, and the + `Dh`, `Dsa`, `EcKey`, `Rsa`, and `PKey` have a type parameter set to one of those values. This + allows the `Signer` constructor to indicate that it requires a private key at compile time for + example. Previously, `Signer` would simply segfault if provided a key without private + components. +* ALPN support has been changed to more directly model OpenSSL's own APIs. Instead of a single + method used for both the server and client sides which performed everything automatically, the + `SslContextBuilder::set_alpn_protos` and `SslContextBuilder::set_alpn_select_callback` handle + the client and server sides respectively. +* `SslConnector::danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication` + has been removed in favor of new methods which provide more control. The + `ConnectConfiguration::use_server_name_indication` method controls the use of Server Name + Indication (SNI), and the `ConnectConfiguration::verify_hostname` method controls the use of + hostname verification. These can be controlled independently, and if both are disabled, the + domain argument to `ConnectConfiguration::connect` is ignored. +* Shared secret derivation is now handled by the new `derive::Deriver` type rather than + `pkey::PKeyContext`, which has been removed. +* `ssl::Error` is now no longer an enum, and provides more direct access to the relevant state. +* `SslConnectorBuilder::new` has been moved and renamed to `SslConnector::builder`. +* `SslAcceptorBuilder::mozilla_intermediate` and `SslAcceptorBuilder::mozilla_modern` have been + moved to `SslAcceptor` and no longer take the private key and certificate chain. Install those + manually after creating the builder. +* `X509VerifyError` is now `X509VerifyResult` and can now have the "ok" value in addition to error + values. +* `x509::X509FileType` is now `ssl::SslFiletype`. +* Asymmetric key serialization and deserialization methods now document the formats that they + correspond to, and some have been renamed to better indicate that. + +### Removed + +* All deprecated APIs have been removed. +* NPN support has been removed. It has been supersceded by ALPN, and is hopefully no longer being + used in practice. If you still depend on it, please file an issue! +* `SslRef::compression` has been removed. +* Some `ssl::SslOptions` flags have been removed as they no longer do anything. + +## Older + +Look at the [release tags] for information about older releases. + +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.47...master +[v0.10.47]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.46...openssl-v0.10.47 +[v0.10.46]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.45...openssl-v0.10.46 +[v0.10.45]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.44...openssl-v0.10.45 +[v0.10.44]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.43...openssl-v0.10.44 +[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 +[v0.10.35]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.34...openssl-v0.10.35 +[v0.10.34]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.33...openssl-v0.10.34 +[v0.10.33]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.32...openssl-v0.10.33 +[v0.10.32]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.31...openssl-v0.10.32 +[v0.10.31]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.30...openssl-v0.10.31 +[v0.10.30]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.29...openssl-v0.10.30 +[v0.10.29]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.28...openssl-v0.10.29 +[v0.10.28]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.27...openssl-v0.10.28 +[v0.10.27]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.26...openssl-v0.10.27 +[v0.10.26]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.25...openssl-v0.10.26 +[v0.10.25]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.24...openssl-v0.10.25 +[v0.10.24]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.23...openssl-v0.10.24 +[v0.10.23]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.22...openssl-v0.10.23 +[v0.10.22]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.21...openssl-v0.10.22 +[v0.10.21]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.20...openssl-v0.10.21 +[v0.10.20]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.19...openssl-v0.10.20 +[v0.10.19]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.18...openssl-v0.10.19 +[v0.10.18]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.17...openssl-v0.10.18 +[v0.10.17]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.16...openssl-v0.10.17 +[v0.10.16]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.15...openssl-v0.10.16 +[v0.10.15]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.14...openssl-v0.10.15 +[v0.10.14]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.13...openssl-v0.10.14 +[v0.10.13]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.12...openssl-v0.10.13 +[v0.10.12]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.11...openssl-v0.10.12 +[v0.10.11]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.10...openssl-v0.10.11 +[v0.10.10]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.9...openssl-v0.10.10 +[v0.10.9]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...openssl-v0.10.9 +[v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...openssl-v0.10.8 +[v0.10.7]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.6...openssl-v0.10.7 +[v0.10.6]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.5...openssl-v0.10.6 +[v0.10.5]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.4...openssl-v0.10.5 +[v0.10.4]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.3...openssl-v0.10.4 +[v0.10.3]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.2...openssl-v0.10.3 +[v0.10.2]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.1...openssl-v0.10.2 +[v0.10.1]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.0...openssl-v0.10.1 +[v0.10.0]: https://github.com/sfackler/rust-openssl/compare/v0.9.23...openssl-v0.10.0 +[release tags]: https://github.com/sfackler/rust-openssl/releases diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 07f03bc..158acff 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.9.23" +version = "0.10.47" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" @@ -8,26 +8,29 @@ repository = "https://github.com/sfackler/rust-openssl" readme = "README.md" keywords = ["crypto", "tls", "ssl", "dtls"] categories = ["cryptography", "api-bindings"] -build = "build.rs" - -[package.metadata.docs.rs] -all-features = true +edition = "2018" +# these are deprecated and don't do anything anymore [features] v101 = [] v102 = [] v110 = [] +v111 = [] + +vendored = ['ffi/vendored'] +bindgen = ['ffi/bindgen'] +unstable_boringssl = ["ffi/unstable_boringssl"] +default = [] [dependencies] -bitflags = "0.9" +bitflags = "1.0" +cfg-if = "1.0" foreign-types = "0.3.1" -lazy_static = "1" libc = "0.2" -openssl-sys = { version = "0.9.23", path = "../openssl-sys" } +once_cell = "1.5.2" + +openssl-macros = { version = "0.1.0", path = "../openssl-macros" } +ffi = { package = "openssl-sys", version = "0.9.82", path = "../openssl-sys" } [dev-dependencies] -tempdir = "0.3" -winapi = "0.2" -ws2_32-sys = "0.2" -hex = "0.2" -data-encoding = "2.0" +hex = "0.3" 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/README.md b/openssl/README.md new file mode 100644 index 0000000..32d46ee --- /dev/null +++ b/openssl/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/openssl/build.rs b/openssl/build.rs index eb8894f..5cddce9 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -1,23 +1,19 @@ +#![allow( + clippy::inconsistent_digit_grouping, + clippy::uninlined_format_args, + clippy::unusual_byte_groupings +)] + use std::env; fn main() { - match env::var("DEP_OPENSSL_VERSION") { - Ok(ref v) if v == "101" => { - println!("cargo:rustc-cfg=ossl101"); - println!("cargo:rustc-cfg=ossl10x"); - } - Ok(ref v) if v == "102" => { - println!("cargo:rustc-cfg=ossl102"); - println!("cargo:rustc-cfg=ossl10x"); - } - Ok(ref v) if v == "110" => { - println!("cargo:rustc-cfg=ossl110"); - } - _ => panic!("Unable to detect OpenSSL version"), + if env::var("DEP_OPENSSL_LIBRESSL").is_ok() { + println!("cargo:rustc-cfg=libressl"); } - if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { - println!("cargo:rustc-cfg=libressl"); + if env::var("DEP_OPENSSL_BORINGSSL").is_ok() { + println!("cargo:rustc-cfg=boringssl"); + return; } if let Ok(v) = env::var("DEP_OPENSSL_LIBRESSL_VERSION") { @@ -25,8 +21,90 @@ fn main() { } if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { - for var in vars.split(",") { + for var in vars.split(',') { println!("cargo:rustc-cfg=osslconf=\"{}\"", var); } } + + if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&version, 16).unwrap(); + + if version >= 0x1_00_01_00_0 { + println!("cargo:rustc-cfg=ossl101"); + } + if version >= 0x1_00_02_00_0 { + println!("cargo:rustc-cfg=ossl102"); + } + if version >= 0x1_01_00_00_0 { + println!("cargo:rustc-cfg=ossl110"); + } + if version >= 0x1_01_00_07_0 { + println!("cargo:rustc-cfg=ossl110g"); + } + if version >= 0x1_01_00_08_0 { + println!("cargo:rustc-cfg=ossl110h"); + } + if version >= 0x1_01_01_00_0 { + println!("cargo:rustc-cfg=ossl111"); + } + if version >= 0x3_00_00_00_0 { + println!("cargo:rustc-cfg=ossl300"); + } + } + + 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"); + } + + if version >= 0x2_07_00_00_0 { + println!("cargo:rustc-cfg=libressl270"); + } + + if version >= 0x2_07_01_00_0 { + println!("cargo:rustc-cfg=libressl271"); + } + + if version >= 0x2_07_03_00_0 { + println!("cargo:rustc-cfg=libressl273"); + } + + if version >= 0x2_08_00_00_0 { + println!("cargo:rustc-cfg=libressl280"); + } + + if version >= 0x2_09_01_00_0 { + println!("cargo:rustc-cfg=libressl291"); + } + + if version >= 0x3_02_01_00_0 { + println!("cargo:rustc-cfg=libressl321"); + } + + if version >= 0x3_03_02_00_0 { + println!("cargo:rustc-cfg=libressl332"); + } + + 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/openssl/examples/mk_certs.rs b/openssl/examples/mk_certs.rs index c64dc00..48538c7 100644 --- a/openssl/examples/mk_certs.rs +++ b/openssl/examples/mk_certs.rs @@ -1,23 +1,24 @@ +#![allow(clippy::uninlined_format_args)] + //! A program that generates ca certs, certs verified by the ca, and public //! and private keys. -extern crate openssl; - use openssl::asn1::Asn1Time; -use openssl::bn::{BigNum, MSB_MAYBE_ZERO}; +use openssl::bn::{BigNum, MsbOption}; use openssl::error::ErrorStack; use openssl::hash::MessageDigest; -use openssl::pkey::{PKey, PKeyRef}; +use openssl::pkey::{PKey, PKeyRef, Private}; use openssl::rsa::Rsa; -use openssl::x509::{X509, X509Ref}; -use openssl::x509::{X509NameBuilder, X509Req, X509ReqBuilder}; -use openssl::x509::extension::{AuthorityKeyIdentifier, BasicConstraints, KeyUsage, - SubjectAlternativeName, SubjectKeyIdentifier}; +use openssl::x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; +use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509}; /// Make a CA certificate and private key -fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> { +fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> { let rsa = Rsa::generate(2048)?; - let privkey = PKey::from_rsa(rsa)?; + let key_pair = PKey::from_rsa(rsa)?; let mut x509_name = X509NameBuilder::new()?; x509_name.append_entry_by_text("C", "US")?; @@ -30,39 +31,41 @@ fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> { cert_builder.set_version(2)?; let serial_number = { let mut serial = BigNum::new()?; - serial.rand(159, MSB_MAYBE_ZERO, false)?; + serial.rand(159, MsbOption::MAYBE_ZERO, false)?; serial.to_asn1_integer()? }; cert_builder.set_serial_number(&serial_number)?; cert_builder.set_subject_name(&x509_name)?; cert_builder.set_issuer_name(&x509_name)?; - cert_builder.set_pubkey(&privkey)?; + cert_builder.set_pubkey(&key_pair)?; let not_before = Asn1Time::days_from_now(0)?; cert_builder.set_not_before(¬_before)?; let not_after = Asn1Time::days_from_now(365)?; cert_builder.set_not_after(¬_after)?; cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?; - cert_builder.append_extension(KeyUsage::new() - .critical() - .key_cert_sign() - .crl_sign() - .build()?)?; + cert_builder.append_extension( + KeyUsage::new() + .critical() + .key_cert_sign() + .crl_sign() + .build()?, + )?; let subject_key_identifier = SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?; cert_builder.append_extension(subject_key_identifier)?; - cert_builder.sign(&privkey, MessageDigest::sha256())?; + cert_builder.sign(&key_pair, MessageDigest::sha256())?; let cert = cert_builder.build(); - Ok((cert, privkey)) + Ok((cert, key_pair)) } /// Make a X509 request with the given private key -fn mk_request(privkey: &PKey) -> Result<(X509Req), ErrorStack> { +fn mk_request(key_pair: &PKey) -> Result { let mut req_builder = X509ReqBuilder::new()?; - req_builder.set_pubkey(&privkey)?; + req_builder.set_pubkey(key_pair)?; let mut x509_name = X509NameBuilder::new()?; x509_name.append_entry_by_text("C", "US")?; @@ -72,29 +75,32 @@ fn mk_request(privkey: &PKey) -> Result<(X509Req), ErrorStack> { let x509_name = x509_name.build(); req_builder.set_subject_name(&x509_name)?; - req_builder.sign(&privkey, MessageDigest::sha256())?; + req_builder.sign(key_pair, MessageDigest::sha256())?; let req = req_builder.build(); Ok(req) } /// Make a certificate and private key signed by the given CA cert and private key -fn mk_ca_signed_cert(ca_cert: &X509Ref, ca_privkey: &PKeyRef) -> Result<(X509, PKey), ErrorStack> { +fn mk_ca_signed_cert( + ca_cert: &X509Ref, + ca_key_pair: &PKeyRef, +) -> Result<(X509, PKey), ErrorStack> { let rsa = Rsa::generate(2048)?; - let privkey = PKey::from_rsa(rsa)?; + let key_pair = PKey::from_rsa(rsa)?; - let req = mk_request(&privkey)?; + let req = mk_request(&key_pair)?; let mut cert_builder = X509::builder()?; cert_builder.set_version(2)?; let serial_number = { let mut serial = BigNum::new()?; - serial.rand(159, MSB_MAYBE_ZERO, false)?; + serial.rand(159, MsbOption::MAYBE_ZERO, false)?; serial.to_asn1_integer()? }; cert_builder.set_serial_number(&serial_number)?; cert_builder.set_subject_name(req.subject_name())?; cert_builder.set_issuer_name(ca_cert.subject_name())?; - cert_builder.set_pubkey(&privkey)?; + cert_builder.set_pubkey(&key_pair)?; let not_before = Asn1Time::days_from_now(0)?; cert_builder.set_not_before(¬_before)?; let not_after = Asn1Time::days_from_now(365)?; @@ -102,15 +108,17 @@ fn mk_ca_signed_cert(ca_cert: &X509Ref, ca_privkey: &PKeyRef) -> Result<(X509, P cert_builder.append_extension(BasicConstraints::new().build()?)?; - cert_builder.append_extension(KeyUsage::new() - .critical() - .non_repudiation() - .digital_signature() - .key_encipherment() - .build()?)?; + cert_builder.append_extension( + KeyUsage::new() + .critical() + .non_repudiation() + .digital_signature() + .key_encipherment() + .build()?, + )?; - let subject_key_identifier = SubjectKeyIdentifier::new() - .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; + let subject_key_identifier = + SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?; cert_builder.append_extension(subject_key_identifier)?; let auth_key_identifier = AuthorityKeyIdentifier::new() @@ -125,20 +133,20 @@ fn mk_ca_signed_cert(ca_cert: &X509Ref, ca_privkey: &PKeyRef) -> Result<(X509, P .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; cert_builder.append_extension(subject_alt_name)?; - cert_builder.sign(&ca_privkey, MessageDigest::sha256())?; + cert_builder.sign(ca_key_pair, MessageDigest::sha256())?; let cert = cert_builder.build(); - Ok((cert, privkey)) + Ok((cert, key_pair)) } fn real_main() -> Result<(), ErrorStack> { - let (ca_cert, ca_privkey) = mk_ca_cert()?; - let (cert, _privkey) = mk_ca_signed_cert(&ca_cert, &ca_privkey)?; + let (ca_cert, ca_key_pair) = mk_ca_cert()?; + let (cert, _key_pair) = mk_ca_signed_cert(&ca_cert, &ca_key_pair)?; // Verify that this cert was issued by this ca match ca_cert.issued(&cert) { - Err(ver_err) => println!("Failed to verify certificate: {}", ver_err), - Ok(()) => println!("Certificate verified!"), + X509VerifyResult::OK => println!("Certificate verified!"), + ver_err => println!("Failed to verify certificate: {}", ver_err), }; Ok(()) diff --git a/openssl/src/aes.rs b/openssl/src/aes.rs index 5be9943..cbc4999 100644 --- a/openssl/src/aes.rs +++ b/openssl/src/aes.rs @@ -1,7 +1,7 @@ -//! Low level AES IGE functionality +//! Low level AES IGE and key wrapping functionality //! //! AES ECB, CBC, XTS, CTR, CFB, GCM and other conventional symmetric encryption -//! modes are found in [`symm`]. This is the implementation of AES IGE. +//! modes are found in [`symm`]. This is the implementation of AES IGE and key wrapping //! //! Advanced Encryption Standard (AES) provides symmetric key cipher that //! the same key is used to encrypt and decrypt data. This implementation @@ -13,7 +13,7 @@ //! [`aes_ige`]: fn.aes_ige.html //! //! The [`symm`] module should be used in preference to this module in most cases. -//! The IGE block cypher is a non-traditional cipher mode. More traditional AES +//! The IGE block cipher is a non-traditional cipher mode. More traditional AES //! encryption methods are found in the [`Crypter`] and [`Cipher`] structs. //! //! [`symm`]: ../symm/index.html @@ -21,36 +21,53 @@ //! [`Cipher`]: ../symm/struct.Cipher.html //! //! # Examples + +#![cfg_attr( + all(not(boringssl), not(osslconf = "OPENSSL_NO_DEPRECATED_3_0")), + 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 -//! # extern crate openssl; -//! extern crate hex; -//! use openssl::aes::{AesKey, KeyError, aes_ige}; -//! use openssl::symm::Mode; -//! use hex::{FromHex, ToHex}; +//! use openssl::aes::{AesKey, unwrap_key, wrap_key}; +//! +//! let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +//! let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"; +//! +//! let enc_key = AesKey::new_encrypt(kek).unwrap(); +//! let mut ciphertext = [0u8; 24]; +//! wrap_key(&enc_key, None, &mut ciphertext, &key_to_wrap[..]).unwrap(); +//! let dec_key = AesKey::new_decrypt(kek).unwrap(); +//! let mut orig_key = [0u8; 16]; +//! unwrap_key(&dec_key, None, &mut orig_key, &ciphertext[..]).unwrap(); //! -//! fn decrypt() -> Result<(), KeyError> { -//! let raw_key = "000102030405060708090A0B0C0D0E0F"; -//! let hex_cipher = "12345678901234561234567890123456"; -//! let randomness = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; -//! if let (Ok(key_as_u8), Ok(cipher_as_u8), Ok(mut iv_as_u8)) = -//! (Vec::from_hex(raw_key), Vec::from_hex(hex_cipher), Vec::from_hex(randomness)) { -//! let key = AesKey::new_encrypt(&key_as_u8)?; -//! let mut output = vec![0u8; cipher_as_u8.len()]; -//! aes_ige(&cipher_as_u8, &mut output, &key, &mut iv_as_u8, Mode::Encrypt); -//! assert_eq!(output.to_hex(), "a6ad974d5cea1d36d2f367980907ed32"); -//! } -//! Ok(()) -//! } +//! assert_eq!(&orig_key[..], &key_to_wrap[..]); +//! ``` //! -//! # fn main() { -//! # decrypt(); -//! # } -use ffi; -use std::mem; -use libc::c_int; +use cfg_if::cfg_if; +use libc::{c_int, c_uint}; +use std::mem::MaybeUninit; +use std::ptr; -use symm::Mode; +#[cfg(not(boringssl))] +use crate::symm::Mode; +use openssl_macros::corresponds; /// Provides Error handling for parsing keys. #[derive(Debug)] @@ -59,24 +76,35 @@ pub struct KeyError(()); /// The key used to encrypt or decrypt cipher blocks. pub struct AesKey(ffi::AES_KEY); +cfg_if! { + if #[cfg(boringssl)] { + type AesBitType = c_uint; + type AesSizeType = usize; + } else { + type AesBitType = c_int; + type AesSizeType = c_uint; + } +} + impl AesKey { /// Prepares a key for encryption. /// /// # Failure /// /// Returns an error if the key is not 128, 192, or 256 bits. + #[corresponds(AES_set_encrypt_key)] pub fn new_encrypt(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize / 8); - let mut aes_key = mem::uninitialized(); + let mut aes_key = MaybeUninit::uninit(); let r = ffi::AES_set_encrypt_key( key.as_ptr() as *const _, - key.len() as c_int * 8, - &mut aes_key, + key.len() as AesBitType * 8, + aes_key.as_mut_ptr(), ); if r == 0 { - Ok(AesKey(aes_key)) + Ok(AesKey(aes_key.assume_init())) } else { Err(KeyError(())) } @@ -88,19 +116,20 @@ impl AesKey { /// # Failure /// /// Returns an error if the key is not 128, 192, or 256 bits. + #[corresponds(AES_set_decrypt_key)] pub fn new_decrypt(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize / 8); - let mut aes_key = mem::uninitialized(); + let mut aes_key = MaybeUninit::uninit(); let r = ffi::AES_set_decrypt_key( key.as_ptr() as *const _, - key.len() as c_int * 8, - &mut aes_key, + key.len() as AesBitType * 8, + aes_key.as_mut_ptr(), ); if r == 0 { - Ok(AesKey(aes_key)) + Ok(AesKey(aes_key.assume_init())) } else { Err(KeyError(())) } @@ -111,14 +140,14 @@ impl AesKey { /// Performs AES IGE encryption or decryption /// /// AES IGE (Infinite Garble Extension) is a form of AES block cipher utilized in -/// OpenSSL. Infinite Garble referes to propogating forward errors. IGE, like other -/// block ciphers implemented for AES requires an initalization vector. The IGE mode +/// OpenSSL. Infinite Garble refers to propagating forward errors. IGE, like other +/// block ciphers implemented for AES requires an initialization vector. The IGE mode /// allows a stream of blocks to be encrypted or decrypted without having the entire /// plaintext available. For more information, visit [AES IGE Encryption]. /// -/// This block cipher uses 16 byte blocks. The rust implmentation will panic -/// if the input or output does not meet this 16-byte boundry. Attention must -/// be made in this low level implementation to pad the value to the 128-bit boundry. +/// This block cipher uses 16 byte blocks. The rust implementation will panic +/// if the input or output does not meet this 16-byte boundary. Attention must +/// be made in this low level implementation to pad the value to the 128-bit boundary. /// /// [AES IGE Encryption]: http://www.links.org/files/openssl-ige.pdf /// @@ -126,6 +155,9 @@ impl AesKey { /// /// Panics if `in_` is not the same length as `out`, if that length is not a multiple of 16, or if /// `iv` is not at least 32 bytes. +#[cfg(not(boringssl))] +#[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] +#[corresponds(AES_ige_encrypt)] pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mode) { unsafe { assert!(in_.len() == out.len()); @@ -147,15 +179,97 @@ pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mo } } +/// Wrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394) +/// +/// * `key`: The key-encrypting-key to use. Must be a encrypting key +/// * `iv`: The IV to use. You must use the same IV for both wrapping and unwrapping +/// * `out`: The output buffer to store the ciphertext +/// * `in_`: The input buffer, storing the key to be wrapped +/// +/// Returns the number of bytes written into `out` +/// +/// # Panics +/// +/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or if +/// `out` is not 8 bytes longer than `in_` +#[corresponds(AES_wrap_key)] +pub fn wrap_key( + key: &AesKey, + iv: Option<[u8; 8]>, + out: &mut [u8], + in_: &[u8], +) -> Result { + unsafe { + assert!(out.len() >= in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1) + + let written = ffi::AES_wrap_key( + &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. + iv.as_ref() + .map_or(ptr::null(), |iv| iv.as_ptr() as *const _), + out.as_ptr() as *mut _, + in_.as_ptr() as *const _, + in_.len() as AesSizeType, + ); + if written <= 0 { + Err(KeyError(())) + } else { + Ok(written as usize) + } + } +} + +/// Unwrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394) +/// +/// * `key`: The key-encrypting-key to decrypt the wrapped key. Must be a decrypting key +/// * `iv`: The same IV used for wrapping the key +/// * `out`: The buffer to write the unwrapped key to +/// * `in_`: The input ciphertext +/// +/// Returns the number of bytes written into `out` +/// +/// # Panics +/// +/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or +/// if `in_` is not 8 bytes longer than `out` +#[corresponds(AES_unwrap_key)] +pub fn unwrap_key( + key: &AesKey, + iv: Option<[u8; 8]>, + out: &mut [u8], + in_: &[u8], +) -> Result { + unsafe { + assert!(out.len() + 8 <= in_.len()); + + let written = ffi::AES_unwrap_key( + &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. + iv.as_ref() + .map_or(ptr::null(), |iv| iv.as_ptr() as *const _), + out.as_ptr() as *mut _, + in_.as_ptr() as *const _, + in_.len() as AesSizeType, + ); + + if written <= 0 { + Err(KeyError(())) + } else { + Ok(written as usize) + } + } +} + #[cfg(test)] mod test { use hex::FromHex; - use symm::Mode; use super::*; + #[cfg(not(boringssl))] + use crate::symm::Mode; // From https://www.mgp25.com/AESIGE/ #[test] + #[cfg(not(boringssl))] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn ige_vector_1() { let raw_key = "000102030405060708090A0B0C0D0E0F"; let raw_iv = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; @@ -177,4 +291,29 @@ mod test { aes_ige(&ct, &mut pt_actual, &key, &mut iv, Mode::Decrypt); assert_eq!(pt_actual, pt); } + + // from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3 + #[test] + fn test_wrap_unwrap() { + let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap(); + let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap(); + let expected_ciphertext = + Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap(); + + let enc_key = AesKey::new_encrypt(&raw_key).unwrap(); + let mut wrapped = [0; 24]; + assert_eq!( + wrap_key(&enc_key, None, &mut wrapped, &key_data).unwrap(), + 24 + ); + assert_eq!(&wrapped[..], &expected_ciphertext[..]); + + let dec_key = AesKey::new_decrypt(&raw_key).unwrap(); + let mut unwrapped = [0; 16]; + assert_eq!( + unwrap_key(&dec_key, None, &mut unwrapped, &wrapped).unwrap(), + 16 + ); + assert_eq!(&unwrapped[..], &key_data[..]); + } } diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index d129235..55de049 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1,6 +1,6 @@ #![deny(missing_docs)] -//! Defines the format of certificiates +//! Defines the format of certificates //! //! This module is used by [`x509`] and other certificate building functions //! to describe time, strings, and objects. @@ -24,19 +24,24 @@ //! use openssl::asn1::Asn1Time; //! let tomorrow = Asn1Time::days_from_now(1); //! ``` -use ffi; +use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; -use libc::{c_long, c_char, c_int}; +use libc::{c_char, c_int, c_long, time_t}; +#[cfg(ossl102)] +use std::cmp::Ordering; +use std::ffi::CString; use std::fmt; use std::ptr; use std::slice; use std::str; -use {cvt, cvt_p}; -use bio::MemBio; -use error::ErrorStack; -use nid::Nid; -use string::OpensslString; +use crate::bio::MemBio; +use crate::bn::{BigNum, BigNumRef}; +use crate::error::ErrorStack; +use crate::nid::Nid; +use crate::string::OpensslString; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_GENERALIZEDTIME; @@ -49,7 +54,7 @@ foreign_type_and_impl_send_sync! { /// example outside the year range of 1950-2049. /// /// [ASN1_GENERALIZEDTIME_set] documentation from OpenSSL provides - /// further details of implmentation. Note: these docs are from the master + /// further details of implementation. Note: these docs are from the master /// branch as documentation on the 1.1.0 branch did not include this page. /// /// [ASN1_GENERALIZEDTIME_set]: https://www.openssl.org/docs/manmaster/man3/ASN1_GENERALIZEDTIME_set.html @@ -61,18 +66,115 @@ foreign_type_and_impl_send_sync! { } impl fmt::Display for Asn1GeneralizedTimeRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { unsafe { - let mem_bio = MemBio::new()?; - cvt(ffi::ASN1_GENERALIZEDTIME_print( + let mem_bio = match MemBio::new() { + Err(_) => return f.write_str("error"), + Ok(m) => m, + }; + let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print( mem_bio.as_ptr(), self.as_ptr(), - ))?; - write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) + )); + match print_result { + Err(_) => f.write_str("error"), + Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())), + } } } } +/// The type of an ASN.1 value. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Asn1Type(c_int); + +#[allow(missing_docs)] // no need to document the constants +impl Asn1Type { + pub const EOC: Asn1Type = Asn1Type(ffi::V_ASN1_EOC); + + pub const BOOLEAN: Asn1Type = Asn1Type(ffi::V_ASN1_BOOLEAN); + + pub const INTEGER: Asn1Type = Asn1Type(ffi::V_ASN1_INTEGER); + + pub const BIT_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_BIT_STRING); + + pub const OCTET_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_OCTET_STRING); + + pub const NULL: Asn1Type = Asn1Type(ffi::V_ASN1_NULL); + + pub const OBJECT: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT); + + pub const OBJECT_DESCRIPTOR: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT_DESCRIPTOR); + + pub const EXTERNAL: Asn1Type = Asn1Type(ffi::V_ASN1_EXTERNAL); + + pub const REAL: Asn1Type = Asn1Type(ffi::V_ASN1_REAL); + + pub const ENUMERATED: Asn1Type = Asn1Type(ffi::V_ASN1_ENUMERATED); + + pub const UTF8STRING: Asn1Type = Asn1Type(ffi::V_ASN1_UTF8STRING); + + pub const SEQUENCE: Asn1Type = Asn1Type(ffi::V_ASN1_SEQUENCE); + + pub const SET: Asn1Type = Asn1Type(ffi::V_ASN1_SET); + + pub const NUMERICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_NUMERICSTRING); + + pub const PRINTABLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_PRINTABLESTRING); + + pub const T61STRING: Asn1Type = Asn1Type(ffi::V_ASN1_T61STRING); + + pub const TELETEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_TELETEXSTRING); + + pub const VIDEOTEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VIDEOTEXSTRING); + + pub const IA5STRING: Asn1Type = Asn1Type(ffi::V_ASN1_IA5STRING); + + pub const UTCTIME: Asn1Type = Asn1Type(ffi::V_ASN1_UTCTIME); + + pub const GENERALIZEDTIME: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALIZEDTIME); + + pub const GRAPHICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GRAPHICSTRING); + + pub const ISO64STRING: Asn1Type = Asn1Type(ffi::V_ASN1_ISO64STRING); + + pub const VISIBLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VISIBLESTRING); + + pub const GENERALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALSTRING); + + pub const UNIVERSALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_UNIVERSALSTRING); + + pub const BMPSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_BMPSTRING); + + /// Constructs an `Asn1Type` from a raw OpenSSL value. + pub fn from_raw(value: c_int) -> Self { + Asn1Type(value) + } + + /// Returns the raw OpenSSL value represented by this type. + pub fn as_raw(&self) -> c_int { + self.0 + } +} + +/// Difference between two ASN1 times. +/// +/// This `struct` is created by the [`diff`] method on [`Asn1TimeRef`]. See its +/// documentation for more. +/// +/// [`diff`]: struct.Asn1TimeRef.html#method.diff +/// [`Asn1TimeRef`]: struct.Asn1TimeRef.html +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg(ossl102)] +pub struct TimeDiff { + /// Difference in days + pub days: c_int, + /// Difference in seconds. + /// + /// This is always less than the number of seconds in a day. + pub secs: c_int, +} + foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_TIME; fn drop = ffi::ASN1_TIME_free; @@ -82,10 +184,10 @@ foreign_type_and_impl_send_sync! { /// using certificates. If Asn1Time is set using a string, it must /// be in either YYMMDDHHMMSSZ, YYYYMMDDHHMMSSZ, or another ASN.1 format. /// - /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementaiton + /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementation /// used by OpenSSL. /// - /// [ASN_TIME_set]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_set.html + /// [ASN_TIME_set]: https://www.openssl.org/docs/manmaster/crypto/ASN1_TIME_set.html pub struct Asn1Time; /// Reference to an [`Asn1Time`] /// @@ -93,17 +195,121 @@ foreign_type_and_impl_send_sync! { pub struct Asn1TimeRef; } +impl Asn1TimeRef { + /// Find difference between two times + #[corresponds(ASN1_TIME_diff)] + #[cfg(ossl102)] + pub fn diff(&self, compare: &Self) -> Result { + let mut days = 0; + let mut secs = 0; + let other = compare.as_ptr(); + + let err = unsafe { ffi::ASN1_TIME_diff(&mut days, &mut secs, self.as_ptr(), other) }; + + match err { + 0 => Err(ErrorStack::get()), + _ => Ok(TimeDiff { days, secs }), + } + } + + /// Compare two times + #[corresponds(ASN1_TIME_compare)] + #[cfg(ossl102)] + pub fn compare(&self, other: &Self) -> Result { + let d = self.diff(other)?; + if d.days > 0 || d.secs > 0 { + return Ok(Ordering::Less); + } + if d.days < 0 || d.secs < 0 { + return Ok(Ordering::Greater); + } + + Ok(Ordering::Equal) + } +} + +#[cfg(ossl102)] +impl PartialEq for Asn1TimeRef { + fn eq(&self, other: &Asn1TimeRef) -> bool { + self.diff(other) + .map(|t| t.days == 0 && t.secs == 0) + .unwrap_or(false) + } +} + +#[cfg(ossl102)] +impl PartialEq for Asn1TimeRef { + fn eq(&self, other: &Asn1Time) -> bool { + self.diff(other) + .map(|t| t.days == 0 && t.secs == 0) + .unwrap_or(false) + } +} + +#[cfg(ossl102)] +impl<'a> PartialEq for &'a Asn1TimeRef { + fn eq(&self, other: &Asn1Time) -> bool { + self.diff(other) + .map(|t| t.days == 0 && t.secs == 0) + .unwrap_or(false) + } +} + +#[cfg(ossl102)] +impl PartialOrd for Asn1TimeRef { + fn partial_cmp(&self, other: &Asn1TimeRef) -> Option { + self.compare(other).ok() + } +} + +#[cfg(ossl102)] +impl PartialOrd for Asn1TimeRef { + fn partial_cmp(&self, other: &Asn1Time) -> Option { + self.compare(other).ok() + } +} + +#[cfg(ossl102)] +impl<'a> PartialOrd for &'a Asn1TimeRef { + fn partial_cmp(&self, other: &Asn1Time) -> Option { + self.compare(other).ok() + } +} + impl fmt::Display for Asn1TimeRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { unsafe { - let mem_bio = MemBio::new()?; - cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()))?; - write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) + let mem_bio = match MemBio::new() { + Err(_) => return f.write_str("error"), + Ok(m) => m, + }; + let print_result = cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr())); + match print_result { + Err(_) => f.write_str("error"), + Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())), + } } } } +impl fmt::Debug for Asn1TimeRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.to_string()) + } +} + impl Asn1Time { + #[corresponds(ASN1_TIME_new)] + fn new() -> Result { + ffi::init(); + + unsafe { + let handle = cvt_p(ffi::ASN1_TIME_new())?; + Ok(Asn1Time::from_ptr(handle)) + } + } + + #[corresponds(X509_gmtime_adj)] fn from_period(period: c_long) -> Result { ffi::init(); @@ -117,6 +323,95 @@ impl Asn1Time { pub fn days_from_now(days: u32) -> Result { Asn1Time::from_period(days as c_long * 60 * 60 * 24) } + + /// Creates a new time from the specified `time_t` value + #[corresponds(ASN1_TIME_set)] + pub fn from_unix(time: time_t) -> Result { + ffi::init(); + + unsafe { + let handle = cvt_p(ffi::ASN1_TIME_set(ptr::null_mut(), time))?; + Ok(Asn1Time::from_ptr(handle)) + } + } + + /// Creates a new time corresponding to the specified ASN1 time string. + #[corresponds(ASN1_TIME_set_string)] + #[allow(clippy::should_implement_trait)] + pub fn from_str(s: &str) -> Result { + unsafe { + let s = CString::new(s).unwrap(); + + let time = Asn1Time::new()?; + cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?; + + Ok(time) + } + } + + /// Creates a new time corresponding to the specified X509 time string. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(ASN1_TIME_set_string_X509)] + #[cfg(ossl111)] + pub fn from_str_x509(s: &str) -> Result { + unsafe { + let s = CString::new(s).unwrap(); + + let time = Asn1Time::new()?; + cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?; + + Ok(time) + } + } +} + +#[cfg(ossl102)] +impl PartialEq for Asn1Time { + fn eq(&self, other: &Asn1Time) -> bool { + self.diff(other) + .map(|t| t.days == 0 && t.secs == 0) + .unwrap_or(false) + } +} + +#[cfg(ossl102)] +impl PartialEq for Asn1Time { + fn eq(&self, other: &Asn1TimeRef) -> bool { + self.diff(other) + .map(|t| t.days == 0 && t.secs == 0) + .unwrap_or(false) + } +} + +#[cfg(ossl102)] +impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time { + fn eq(&self, other: &&'a Asn1TimeRef) -> bool { + self.diff(other) + .map(|t| t.days == 0 && t.secs == 0) + .unwrap_or(false) + } +} + +#[cfg(ossl102)] +impl PartialOrd for Asn1Time { + fn partial_cmp(&self, other: &Asn1Time) -> Option { + self.compare(other).ok() + } +} + +#[cfg(ossl102)] +impl PartialOrd for Asn1Time { + fn partial_cmp(&self, other: &Asn1TimeRef) -> Option { + self.compare(other).ok() + } +} + +#[cfg(ossl102)] +impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time { + fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option { + self.compare(other).ok() + } } foreign_type_and_impl_send_sync! { @@ -128,11 +423,9 @@ foreign_type_and_impl_send_sync! { /// structures. This implementation uses [ASN1_STRING-to_UTF8] to preserve /// compatibility with Rust's String. /// - /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_STRING_to_UTF8.html + /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/manmaster/crypto/ASN1_STRING_to_UTF8.html pub struct Asn1String; - /// Reference to [`Asn1String`] - /// - /// [`Asn1String`]: struct.Asn1String.html + /// A reference to an [`Asn1String`]. pub struct Asn1StringRef; } @@ -142,6 +435,7 @@ impl Asn1StringRef { /// ASN.1 strings may utilize UTF-16, ASCII, BMP, or UTF8. This is important to /// consume the string in a meaningful way without knowing the underlying /// format. + #[corresponds(ASN1_STRING_to_UTF8)] pub fn as_utf8(&self) -> Result { unsafe { let mut ptr = ptr::null_mut(); @@ -154,20 +448,36 @@ impl Asn1StringRef { } } - /// Return the string as an array of bytes + /// Return the string as an array of bytes. /// - /// The bytes do not directly corespond to UTF-8 encoding. To interact with + /// The bytes do not directly correspond to UTF-8 encoding. To interact with /// strings in rust, it is preferable to use [`as_utf8`] /// /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8 + #[corresponds(ASN1_STRING_get0_data)] pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr()), self.len()) } + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } } - /// Return the length of the Asn1String (number of bytes) + /// Returns the number of bytes in the string. + #[corresponds(ASN1_STRING_length)] pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize } } + + /// Determines if the string is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl fmt::Debug for Asn1StringRef { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.as_utf8() { + Ok(openssl_string) => openssl_string.fmt(fmt), + Err(_) => fmt.write_str("error"), + } + } } foreign_type_and_impl_send_sync! { @@ -182,32 +492,48 @@ foreign_type_and_impl_send_sync! { /// OpenSSL documentation includes [`ASN1_INTEGER_set`]. /// /// [`bn`]: ../bn/index.html - /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html + /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/manmaster/crypto/ASN1_INTEGER_set.html pub struct Asn1Integer; - /// Reference to [`Asn1Integer`] - /// - /// [`Asn1Integer`]: struct.Asn1Integer.html + /// A reference to an [`Asn1Integer`]. pub struct Asn1IntegerRef; } -impl Asn1IntegerRef { - /// Returns value of ASN.1 integer, or -1 if there is an error, and 0 if the integer is Null. +impl Asn1Integer { + /// Converts a bignum to an `Asn1Integer`. /// - /// OpenSSL documentation at [`ASN1_INTEGER_get`]. + /// Corresponds to [`BN_to_ASN1_INTEGER`]. Also see + /// [`BigNumRef::to_asn1_integer`]. /// - /// [`ASN1_INTEGER_get`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_get.html + /// [`BN_to_ASN1_INTEGER`]: https://www.openssl.org/docs/manmaster/crypto/BN_to_ASN1_INTEGER.html + /// [`BigNumRef::to_asn1_integer`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer + pub fn from_bn(bn: &BigNumRef) -> Result { + bn.to_asn1_integer() + } +} + +impl Asn1IntegerRef { + #[allow(missing_docs, clippy::unnecessary_cast)] + #[deprecated(since = "0.10.6", note = "use to_bn instead")] pub fn get(&self) -> i64 { - unsafe { ::ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 } + unsafe { ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 } } + + /// Converts the integer to a `BigNum`. + #[corresponds(ASN1_INTEGER_to_BN)] + pub fn to_bn(&self) -> Result { + unsafe { + cvt_p(ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut())) + .map(|p| BigNum::from_ptr(p)) + } + } + /// Sets the ASN.1 value to the value of a signed 32-bit integer, for larger numbers /// see [`bn`]. /// - /// OpenSSL documentation at [`ASN1_INTEGER_set`] - /// /// [`bn`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer - /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html + #[corresponds(ASN1_INTEGER_set)] pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { - unsafe { cvt(::ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } + unsafe { cvt(ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } } } @@ -221,20 +547,26 @@ foreign_type_and_impl_send_sync! { /// /// [`x509`]: ../x509/struct.X509.html#method.signature pub struct Asn1BitString; - /// Reference to [`Asn1BitString`] - /// - /// [`Asn1BitString`]: struct.Asn1BitString.html + /// A reference to an [`Asn1BitString`]. pub struct Asn1BitStringRef; } impl Asn1BitStringRef { - /// Returns the Asn1BitString as a slice + /// Returns the Asn1BitString as a slice. + #[corresponds(ASN1_STRING_get0_data)] pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr() as *mut _), self.len()) } + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } } - /// Length of Asn1BitString in number of bytes. + + /// Returns the number of bytes in the string. + #[corresponds(ASN1_STRING_length)] pub fn len(&self) -> usize { - unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *mut _) as usize } + unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } + } + + /// Determines if the string is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 } } @@ -254,14 +586,39 @@ foreign_type_and_impl_send_sync! { /// /// [`Nid`]: ../nid/index.html /// [`nid::COMMONNAME`]: ../nid/constant.COMMONNAME.html - /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_obj2nid.html + /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/manmaster/crypto/OBJ_obj2nid.html pub struct Asn1Object; - /// Reference to [`Asn1Object`] - /// - /// [`Asn1Object`]: struct.Asn1Object.html + /// A reference to an [`Asn1Object`]. pub struct Asn1ObjectRef; } +impl Asn1Object { + /// Constructs an ASN.1 Object Identifier from a string representation of the OID. + #[corresponds(OBJ_txt2obj)] + #[allow(clippy::should_implement_trait)] + pub fn from_str(txt: &str) -> Result { + unsafe { + ffi::init(); + let txt = CString::new(txt).unwrap(); + let obj: *mut ffi::ASN1_OBJECT = cvt_p(ffi::OBJ_txt2obj(txt.as_ptr() as *const _, 0))?; + Ok(Asn1Object::from_ptr(obj)) + } + } + + /// Return the OID as an DER encoded array of bytes. This is the ASN.1 + /// value, not including tag or length. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(OBJ_get0_data)] + #[cfg(ossl111)] + pub fn as_slice(&self) -> &[u8] { + unsafe { + let len = ffi::OBJ_length(self.as_ptr()); + slice::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len) + } + } +} + impl Asn1ObjectRef { /// Returns the NID associated with this OID. pub fn nid(&self) -> Nid { @@ -270,7 +627,7 @@ impl Asn1ObjectRef { } impl fmt::Display for Asn1ObjectRef { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { unsafe { let mut buf = [0; 80]; let len = ffi::OBJ_obj2txt( @@ -279,17 +636,134 @@ impl fmt::Display for Asn1ObjectRef { self.as_ptr(), 0, ); - let s = str::from_utf8(&buf[..len as usize]).map_err(|_| fmt::Error)?; - fmt.write_str(s) + match str::from_utf8(&buf[..len as usize]) { + Err(_) => fmt.write_str("error"), + Ok(s) => fmt.write_str(s), + } } } } -#[cfg(any(ossl101, ossl102))] -use ffi::ASN1_STRING_data; +impl fmt::Debug for Asn1ObjectRef { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(self.to_string().as_str()) + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::ASN1_STRING_get0_data; + } else { + #[allow(bad_style)] + unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar { + ffi::ASN1_STRING_data(s) + } + } +} -#[cfg(ossl110)] -#[allow(bad_style)] -unsafe fn ASN1_STRING_data(s: *mut ffi::ASN1_STRING) -> *mut ::libc::c_uchar { - ffi::ASN1_STRING_get0_data(s) as *mut _ +#[cfg(test)] +mod tests { + use super::*; + + use crate::bn::BigNum; + use crate::nid::Nid; + + /// Tests conversion between BigNum and Asn1Integer. + #[test] + fn bn_cvt() { + fn roundtrip(bn: BigNum) { + let large = Asn1Integer::from_bn(&bn).unwrap(); + assert_eq!(large.to_bn().unwrap(), bn); + } + + roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); + roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); + roundtrip(BigNum::from_u32(1234).unwrap()); + roundtrip(-BigNum::from_u32(1234).unwrap()); + } + + #[test] + fn time_from_str() { + Asn1Time::from_str("99991231235959Z").unwrap(); + #[cfg(ossl111)] + Asn1Time::from_str_x509("99991231235959Z").unwrap(); + } + + #[test] + fn time_from_unix() { + let t = Asn1Time::from_unix(0).unwrap(); + assert_eq!("Jan 1 00:00:00 1970 GMT", t.to_string()); + } + + #[test] + #[cfg(ossl102)] + fn time_eq() { + let a = Asn1Time::from_str("99991231235959Z").unwrap(); + let b = Asn1Time::from_str("99991231235959Z").unwrap(); + let c = Asn1Time::from_str("99991231235958Z").unwrap(); + let a_ref = a.as_ref(); + let b_ref = b.as_ref(); + let c_ref = c.as_ref(); + assert!(a == b); + assert!(a != c); + assert!(a == b_ref); + assert!(a != c_ref); + assert!(b_ref == a); + assert!(c_ref != a); + assert!(a_ref == b_ref); + assert!(a_ref != c_ref); + } + + #[test] + #[cfg(ossl102)] + fn time_ord() { + let a = Asn1Time::from_str("99991231235959Z").unwrap(); + let b = Asn1Time::from_str("99991231235959Z").unwrap(); + let c = Asn1Time::from_str("99991231235958Z").unwrap(); + let a_ref = a.as_ref(); + let b_ref = b.as_ref(); + let c_ref = c.as_ref(); + assert!(a >= b); + assert!(a > c); + assert!(b <= a); + assert!(c < a); + + assert!(a_ref >= b); + assert!(a_ref > c); + assert!(b_ref <= a); + assert!(c_ref < a); + + assert!(a >= b_ref); + assert!(a > c_ref); + assert!(b <= a_ref); + assert!(c < a_ref); + + assert!(a_ref >= b_ref); + assert!(a_ref > c_ref); + assert!(b_ref <= a_ref); + assert!(c_ref < a_ref); + } + + #[test] + fn object_from_str() { + let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap(); + assert_eq!(object.nid(), Nid::SHA256); + } + + #[test] + fn object_from_str_with_invalid_input() { + Asn1Object::from_str("NOT AN OID") + .map(|object| object.to_string()) + .expect_err("parsing invalid OID should fail"); + } + + #[test] + #[cfg(ossl111)] + fn object_to_slice() { + let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap(); + assert_eq!( + object.as_slice(), + &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01], + ); + } } diff --git a/openssl/src/base64.rs b/openssl/src/base64.rs new file mode 100644 index 0000000..bfa8cbc --- /dev/null +++ b/openssl/src/base64.rs @@ -0,0 +1,128 @@ +//! Base64 encoding support. +use crate::error::ErrorStack; +use crate::{cvt_n, LenType}; +use libc::c_int; +use openssl_macros::corresponds; + +/// Encodes a slice of bytes to a base64 string. +/// +/// # Panics +/// +/// Panics if the input length or computed output length overflow a signed C integer. +#[corresponds(EVP_EncodeBlock)] +pub fn encode_block(src: &[u8]) -> String { + assert!(src.len() <= c_int::max_value() as usize); + let src_len = src.len() as LenType; + + let len = encoded_len(src_len).unwrap(); + let mut out = Vec::with_capacity(len as usize); + + // SAFETY: `encoded_len` ensures space for 4 output characters + // for every 3 input bytes including padding and nul terminator. + // `EVP_EncodeBlock` will write only single byte ASCII characters. + // `EVP_EncodeBlock` will only write to not read from `out`. + unsafe { + let out_len = ffi::EVP_EncodeBlock(out.as_mut_ptr(), src.as_ptr(), src_len); + out.set_len(out_len as usize); + String::from_utf8_unchecked(out) + } +} + +/// Decodes a base64-encoded string to bytes. +/// +/// # Panics +/// +/// Panics if the input length or computed output length overflow a signed C integer. +#[corresponds(EVP_DecodeBlock)] +pub fn decode_block(src: &str) -> Result, ErrorStack> { + let src = src.trim(); + + // https://github.com/openssl/openssl/issues/12143 + if src.is_empty() { + return Ok(vec![]); + } + + assert!(src.len() <= c_int::max_value() as usize); + let src_len = src.len() as LenType; + + let len = decoded_len(src_len).unwrap(); + let mut out = Vec::with_capacity(len as usize); + + // SAFETY: `decoded_len` ensures space for 3 output bytes + // for every 4 input characters including padding. + // `EVP_DecodeBlock` can write fewer bytes after stripping + // leading and trailing whitespace, but never more. + // `EVP_DecodeBlock` will only write to not read from `out`. + unsafe { + let out_len = cvt_n(ffi::EVP_DecodeBlock( + out.as_mut_ptr(), + src.as_ptr(), + src_len, + ))?; + out.set_len(out_len as usize); + } + + if src.ends_with('=') { + out.pop(); + if src.ends_with("==") { + out.pop(); + } + } + + Ok(out) +} + +fn encoded_len(src_len: LenType) -> Option { + let mut len = (src_len / 3).checked_mul(4)?; + + if src_len % 3 != 0 { + len = len.checked_add(4)?; + } + + len = len.checked_add(1)?; + + Some(len) +} + +fn decoded_len(src_len: LenType) -> Option { + let mut len = (src_len / 4).checked_mul(3)?; + + if src_len % 4 != 0 { + len = len.checked_add(3)?; + } + + Some(len) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_encode_block() { + assert_eq!("".to_string(), encode_block(b"")); + assert_eq!("Zg==".to_string(), encode_block(b"f")); + assert_eq!("Zm8=".to_string(), encode_block(b"fo")); + assert_eq!("Zm9v".to_string(), encode_block(b"foo")); + assert_eq!("Zm9vYg==".to_string(), encode_block(b"foob")); + assert_eq!("Zm9vYmE=".to_string(), encode_block(b"fooba")); + assert_eq!("Zm9vYmFy".to_string(), encode_block(b"foobar")); + } + + #[test] + fn test_decode_block() { + assert_eq!(b"".to_vec(), decode_block("").unwrap()); + assert_eq!(b"f".to_vec(), decode_block("Zg==").unwrap()); + assert_eq!(b"fo".to_vec(), decode_block("Zm8=").unwrap()); + assert_eq!(b"foo".to_vec(), decode_block("Zm9v").unwrap()); + assert_eq!(b"foob".to_vec(), decode_block("Zm9vYg==").unwrap()); + assert_eq!(b"fooba".to_vec(), decode_block("Zm9vYmE=").unwrap()); + assert_eq!(b"foobar".to_vec(), decode_block("Zm9vYmFy").unwrap()); + } + + #[test] + fn test_strip_whitespace() { + assert_eq!(b"foobar".to_vec(), decode_block(" Zm9vYmFy\n").unwrap()); + assert_eq!(b"foob".to_vec(), decode_block(" Zm9vYg==\n").unwrap()); + } +} diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 56ba1f3..0f54935 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -1,11 +1,11 @@ +use cfg_if::cfg_if; +use libc::c_int; use std::marker::PhantomData; use std::ptr; use std::slice; -use libc::c_int; -use ffi; -use cvt_p; -use error::ErrorStack; +use crate::cvt_p; +use crate::error::ErrorStack; pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>); @@ -25,7 +25,7 @@ impl<'a> MemBioSlice<'a> { let bio = unsafe { cvt_p(BIO_new_mem_buf( buf.as_ptr() as *const _, - buf.len() as c_int, + buf.len() as crate::SLenType, ))? }; @@ -66,13 +66,20 @@ impl MemBio { slice::from_raw_parts(ptr as *const _ as *const _, len as usize) } } -} -#[cfg(not(ossl101))] -use ffi::BIO_new_mem_buf; + #[cfg(not(boringssl))] + pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBio { + MemBio(bio) + } +} -#[cfg(ossl101)] -#[allow(bad_style)] -unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { - ffi::BIO_new_mem_buf(buf as *mut _, len) +cfg_if! { + if #[cfg(any(ossl102, boringssl))] { + use ffi::BIO_new_mem_buf; + } else { + #[allow(bad_style)] + unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { + ffi::BIO_new_mem_buf(buf as *mut _, len) + } + } } diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index 82ec38b..0328730 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -12,60 +12,74 @@ //! use openssl::bn::BigNum; //! use openssl::error::ErrorStack; //! -//! fn bignums() -> Result< (), ErrorStack > { +//! fn main() -> Result<(), ErrorStack> { //! let a = BigNum::new()?; // a = 0 //! let b = BigNum::from_dec_str("1234567890123456789012345")?; //! let c = &a * &b; -//! assert_eq!(a,c); +//! assert_eq!(a, c); //! Ok(()) //! } -//! # fn main() { -//! # bignums(); -//! # } +//! ``` //! //! [`BIGNUM`]: https://wiki.openssl.org/index.php/Manual:Bn_internal(3) -use ffi; +use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::cmp::Ordering; use std::ffi::CString; +use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub}; use std::{fmt, ptr}; -use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref}; - -use {cvt, cvt_p, cvt_n}; -use asn1::Asn1Integer; -use error::ErrorStack; -use string::OpensslString; - -#[cfg(ossl10x)] -use ffi::{get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, - get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, - get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, - get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, - get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, - get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, - get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, - get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192}; - -#[cfg(ossl110)] -use ffi::{BN_get_rfc2409_prime_768, BN_get_rfc2409_prime_1024, BN_get_rfc3526_prime_1536, - BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, - BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192}; + +use crate::asn1::Asn1Integer; +use crate::error::ErrorStack; +use crate::string::OpensslString; +use crate::{cvt, cvt_n, cvt_p, LenType}; +use openssl_macros::corresponds; + +cfg_if! { + 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, + BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192, BN_is_negative, + }; + } else if #[cfg(boringssl)] { + use ffi::BN_is_negative; + } else { + use ffi::{ + get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, + get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, + get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, + get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, + get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, + get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, + get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, + get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192, + }; + + #[allow(bad_style)] + unsafe fn BN_is_negative(bn: *const ffi::BIGNUM) -> c_int { + (*bn).neg + } + } +} /// Options for the most significant bits of a randomly generated `BigNum`. pub struct MsbOption(c_int); -/// The most significant bit of the number may be 0. -pub const MSB_MAYBE_ZERO: MsbOption = MsbOption(-1); +impl MsbOption { + /// The most significant bit of the number may be 0. + pub const MAYBE_ZERO: MsbOption = MsbOption(-1); -/// The most significant bit of the number must be 1. -pub const MSB_ONE: MsbOption = MsbOption(0); + /// The most significant bit of the number must be 1. + pub const ONE: MsbOption = MsbOption(0); -/// The most significant two bits of the number must be 1. -/// -/// The number of bits in the product of two such numbers will always be exactly twice the number -/// of bits in the original numbers. -pub const TWO_MSB_ONE: MsbOption = MsbOption(1); + /// The most significant two bits of the number must be 1. + /// + /// The number of bits in the product of two such numbers will always be exactly twice the + /// number of bits in the original numbers. + pub const TWO_ONES: MsbOption = MsbOption(1); +} foreign_type_and_impl_send_sync! { type CType = ffi::BN_CTX; @@ -77,7 +91,7 @@ foreign_type_and_impl_send_sync! { /// to allocate. BigNumContext and the OpenSSL [`BN_CTX`] structure are used /// internally when passing BigNum values between subroutines. /// - /// [`BN_CTX`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_new.html + /// [`BN_CTX`]: https://www.openssl.org/docs/manmaster/crypto/BN_CTX_new.html pub struct BigNumContext; /// Reference to [`BigNumContext`] /// @@ -87,33 +101,40 @@ foreign_type_and_impl_send_sync! { impl BigNumContext { /// Returns a new `BigNumContext`. - /// - /// See OpenSSL documentation at [`BN_CTX_new`]. - /// - /// [`BN_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_new.html + #[corresponds(BN_CTX_new)] pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::BN_CTX_new()).map(BigNumContext) } } + + /// Returns a new secure `BigNumContext`. + #[corresponds(BN_CTX_secure_new)] + #[cfg(ossl110)] + pub fn new_secure() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::BN_CTX_secure_new()).map(BigNumContext) + } + } } foreign_type_and_impl_send_sync! { type CType = ffi::BIGNUM; fn drop = ffi::BN_free; - /// Dynamically sized large number impelementation + /// Dynamically sized large number implementation /// /// Perform large number mathematics. Create a new BigNum - /// with [`new`]. Perform stanard mathematics on large numbers using + /// with [`new`]. Perform standard mathematics on large numbers using /// methods from [`Dref`] /// - /// OpenSSL documenation at [`BN_new`]. + /// OpenSSL documentation at [`BN_new`]. /// /// [`new`]: struct.BigNum.html#method.new /// [`Dref`]: struct.BigNum.html#deref-methods - /// [`BN_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_new.html + /// [`BN_new`]: https://www.openssl.org/docs/manmaster/crypto/BN_new.html /// /// # Examples /// ``` @@ -137,46 +158,32 @@ impl BigNumRef { /// Erases the memory used by this `BigNum`, resetting its value to 0. /// /// This can be used to destroy sensitive data such as keys when they are no longer needed. - /// - /// OpenSSL documentation at [`BN_clear`] - /// - /// [`BN_clear`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_clear.html + #[corresponds(BN_clear)] pub fn clear(&mut self) { unsafe { ffi::BN_clear(self.as_ptr()) } } /// Adds a `u32` to `self`. - /// - /// OpenSSL documentation at [`BN_add_word`] - /// - /// [`BN_add_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_add_word.html + #[corresponds(BN_add_word)] pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } } /// Subtracts a `u32` from `self`. - /// - /// OpenSSL documentation at [`BN_sub_word`] - /// - /// [`BN_sub_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sub_word.html + #[corresponds(BN_sub_word)] pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } } /// Multiplies a `u32` by `self`. - /// - /// OpenSSL documentation at [`BN_mul_word`] - /// - /// [`BN_mul_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mul_word.html + #[corresponds(BN_mul_word)] pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } } /// Divides `self` by a `u32`, returning the remainder. - /// - /// OpenSSL documentation at [`BN_div_word`] - /// - /// [`BN_div_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div_word.html + #[corresponds(BN_div_word)] + #[allow(clippy::useless_conversion)] pub fn div_word(&mut self, w: u32) -> Result { unsafe { let r = ffi::BN_div_word(self.as_ptr(), w.into()); @@ -189,10 +196,8 @@ impl BigNumRef { } /// Returns the result of `self` modulo `w`. - /// - /// OpenSSL documentation at [`BN_mod_word`] - /// - /// [`BN_mod_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_word.html + #[corresponds(BN_mod_word)] + #[allow(clippy::useless_conversion)] pub fn mod_word(&self, w: u32) -> Result { unsafe { let r = ffi::BN_mod_word(self.as_ptr(), w.into()); @@ -206,19 +211,14 @@ impl BigNumRef { /// Places a cryptographically-secure pseudo-random nonnegative /// number less than `self` in `rnd`. - /// - /// OpenSSL documentation at [`BN_rand_range`] - /// - /// [`BN_rand_range`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rand_range.html + #[corresponds(BN_rand_range)] pub fn rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) } } /// The cryptographically weak counterpart to `rand_in_range`. - /// - /// OpenSSL documentation at [`BN_pseudo_rand_range`] - /// - /// [`BN_pseudo_rand_range`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_pseudo_rand_range.html + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + #[corresponds(BN_pseudo_rand_range)] pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_pseudo_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) } } @@ -226,10 +226,8 @@ impl BigNumRef { /// Sets bit `n`. Equivalent to `self |= (1 << n)`. /// /// When setting a bit outside of `self`, it is expanded. - /// - /// OpenSSL documentation at [`BN_set_bit`] - /// - /// [`BN_set_bit`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_set_bit.html + #[corresponds(BN_set_bit)] + #[allow(clippy::useless_conversion)] pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_set_bit(self.as_ptr(), n.into())).map(|_| ()) } } @@ -237,19 +235,15 @@ impl BigNumRef { /// Clears bit `n`, setting it to 0. Equivalent to `self &= ~(1 << n)`. /// /// When clearing a bit outside of `self`, an error is returned. - /// - /// OpenSSL documentation at [`BN_clear_bit`] - /// - /// [`BN_clear_bit`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_clear_bit.html + #[corresponds(BN_clear_bit)] + #[allow(clippy::useless_conversion)] pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())).map(|_| ()) } } /// Returns `true` if the `n`th bit of `self` is set to 1, `false` otherwise. - /// - /// OpenSSL documentation at [`BN_is_bit_set`] - /// - /// [`BN_is_bit_set`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_bit_set.html + #[corresponds(BN_is_bit_set)] + #[allow(clippy::useless_conversion)] pub fn is_bit_set(&self, n: i32) -> bool { unsafe { ffi::BN_is_bit_set(self.as_ptr(), n.into()) == 1 } } @@ -257,91 +251,69 @@ impl BigNumRef { /// Truncates `self` to the lowest `n` bits. /// /// An error occurs if `self` is already shorter than `n` bits. - /// - /// OpenSSL documentation at [`BN_mask_bits`] - /// - /// [`BN_mask_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mask_bits.html + #[corresponds(BN_mask_bits)] + #[allow(clippy::useless_conversion)] pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mask_bits(self.as_ptr(), n.into())).map(|_| ()) } } /// Places `a << 1` in `self`. Equivalent to `self * 2`. - /// - /// OpenSSL documentation at [`BN_lshift1`] - /// - /// [`BN_lshift1`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_lshift1.html + #[corresponds(BN_lshift1)] pub fn lshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_lshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) } } /// Places `a >> 1` in `self`. Equivalent to `self / 2`. - /// - /// OpenSSL documentation at [`BN_rshift1`] - /// - /// [`BN_rshift1`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rshift1.html + #[corresponds(BN_rshift1)] pub fn rshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) } } /// Places `a + b` in `self`. [`core::ops::Add`] is also implemented for `BigNumRef`. /// - /// OpenSSL documentation at [`BN_add`] - /// /// [`core::ops::Add`]: struct.BigNumRef.html#method.add - /// [`BN_add`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_add.html + #[corresponds(BN_add)] pub fn checked_add(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_add(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) } } /// Places `a - b` in `self`. [`core::ops::Sub`] is also implemented for `BigNumRef`. /// - /// OpenSSL documentation at [`BN_sub`] - /// /// [`core::ops::Sub`]: struct.BigNumRef.html#method.sub - /// [`BN_sub`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sub.html + #[corresponds(BN_sub)] pub fn checked_sub(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_sub(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) } } /// Places `a << n` in `self`. Equivalent to `a * 2 ^ n`. - /// - /// OpenSSL documentation at [`BN_lshift`] - /// - /// [`BN_lshift`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_lshift.html + #[corresponds(BN_lshift)] + #[allow(clippy::useless_conversion)] pub fn lshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_lshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) } } /// Places `a >> n` in `self`. Equivalent to `a / 2 ^ n`. - /// - /// OpenSSL documentation at [`BN_rshift`] - /// - /// [`BN_rshift`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rshift.html + #[corresponds(BN_rshift)] + #[allow(clippy::useless_conversion)] pub fn rshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) } } /// Creates a new BigNum with the same value. - /// - /// OpenSSL documentation at [`BN_dup`] - /// - /// [`BN_dup`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_dup.html + #[corresponds(BN_dup)] pub fn to_owned(&self) -> Result { unsafe { cvt_p(ffi::BN_dup(self.as_ptr())).map(|b| BigNum::from_ptr(b)) } } /// Sets the sign of `self`. Pass true to set `self` to a negative. False sets /// `self` positive. + #[corresponds(BN_set_negative)] pub fn set_negative(&mut self, negative: bool) { unsafe { ffi::BN_set_negative(self.as_ptr(), negative as c_int) } } /// Compare the absolute values of `self` and `oth`. /// - /// OpenSSL documentation at [`BN_ucmp`] - /// - /// [`BN_ucmp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_ucmp.html - /// /// # Examples /// /// ``` @@ -352,30 +324,20 @@ impl BigNumRef { /// /// assert_eq!(s.ucmp(&o), Ordering::Equal); /// ``` + #[corresponds(BN_ucmp)] pub fn ucmp(&self, oth: &BigNumRef) -> Ordering { unsafe { ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()).cmp(&0) } } /// Returns `true` if `self` is negative. + #[corresponds(BN_is_negative)] pub fn is_negative(&self) -> bool { - self._is_negative() - } - - #[cfg(ossl10x)] - fn _is_negative(&self) -> bool { - unsafe { (*self.as_ptr()).neg == 1 } - } - - #[cfg(ossl110)] - fn _is_negative(&self) -> bool { - unsafe { ffi::BN_is_negative(self.as_ptr()) == 1 } + unsafe { BN_is_negative(self.as_ptr()) == 1 } } /// Returns the number of significant bits in `self`. - /// - /// OpenSSL documentation at [`BN_num_bits`] - /// - /// [`BN_num_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_num_bits.html + #[corresponds(BN_num_bits)] + #[allow(clippy::unnecessary_cast)] pub fn num_bits(&self) -> i32 { unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 } } @@ -396,22 +358,21 @@ impl BigNumRef { /// # Examples /// /// ``` - /// use openssl::bn::{BigNum,MSB_MAYBE_ZERO}; + /// use openssl::bn::{BigNum, MsbOption}; /// use openssl::error::ErrorStack; /// /// fn generate_random() -> Result< BigNum, ErrorStack > { /// let mut big = BigNum::new()?; /// /// // Generates a 128-bit odd random number - /// big.rand(128, MSB_MAYBE_ZERO, true); + /// big.rand(128, MsbOption::MAYBE_ZERO, true); /// Ok((big)) /// } /// ``` /// - /// OpenSSL documentation at [`BN_rand`] - /// /// [`constants`]: index.html#constants - /// [`BN_rand`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rand.html + #[corresponds(BN_rand)] + #[allow(clippy::useless_conversion)] pub fn rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rand( @@ -419,15 +380,15 @@ impl BigNumRef { bits.into(), msb.0, odd as c_int, - )).map(|_| ()) + )) + .map(|_| ()) } } /// The cryptographically weak counterpart to `rand`. Not suitable for key generation. - /// - /// OpenSSL documentation at [`BN_psuedo_rand`] - /// - /// [`BN_psuedo_rand`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_pseudo_rand.html + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + #[corresponds(BN_pseudo_rand)] + #[allow(clippy::useless_conversion)] pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_pseudo_rand( @@ -435,7 +396,8 @@ impl BigNumRef { bits.into(), msb.0, odd as c_int, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -462,10 +424,7 @@ impl BigNumRef { /// Ok((big)) /// } /// ``` - /// - /// OpenSSL documentation at [`BN_generate_prime_ex`] - /// - /// [`BN_generate_prime_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_generate_prime_ex.html + #[corresponds(BN_generate_prime_ex)] pub fn generate_prime( &mut self, bits: i32, @@ -481,17 +440,16 @@ impl BigNumRef { add.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()), rem.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()), ptr::null_mut(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a * b` in `self`. /// [`core::ops::Mul`] is also implemented for `BigNumRef`. /// - /// OpenSSL documentation at [`BN_mul`] - /// /// [`core::ops::Mul`]: struct.BigNumRef.html#method.mul - /// [`BN_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mul.html + #[corresponds(BN_mul)] pub fn checked_mul( &mut self, a: &BigNumRef, @@ -504,17 +462,16 @@ impl BigNumRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a / b` in `self`. The remainder is discarded. /// [`core::ops::Div`] is also implemented for `BigNumRef`. /// - /// OpenSSL documentation at [`BN_div`] - /// /// [`core::ops::Div`]: struct.BigNumRef.html#method.div - /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html + #[corresponds(BN_div)] pub fn checked_div( &mut self, a: &BigNumRef, @@ -528,15 +485,13 @@ impl BigNumRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a % b` in `self`. - /// - /// OpenSSL documentation at [`BN_div`] - /// - /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html + #[corresponds(BN_div)] pub fn checked_rem( &mut self, a: &BigNumRef, @@ -550,15 +505,13 @@ impl BigNumRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a / b` in `self` and `a % b` in `rem`. - /// - /// OpenSSL documentation at [`BN_div`] - /// - /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html + #[corresponds(BN_div)] pub fn div_rem( &mut self, rem: &mut BigNumRef, @@ -573,25 +526,20 @@ impl BigNumRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a²` in `self`. - /// - /// OpenSSL documentation at [`BN_sqr`] - /// - /// [`BN_sqr`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sqr.html + #[corresponds(BN_sqr)] pub fn sqr(&mut self, a: &BigNumRef, ctx: &mut BigNumContextRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_sqr(self.as_ptr(), a.as_ptr(), ctx.as_ptr())).map(|_| ()) } } /// Places the result of `a mod m` in `self`. As opposed to `div_rem` /// the result is non-negative. - /// - /// OpenSSL documentation at [`BN_nnmod`] - /// - /// [`BN_nnmod`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_nnmod.html + #[corresponds(BN_nnmod)] pub fn nnmod( &mut self, a: &BigNumRef, @@ -604,15 +552,13 @@ impl BigNumRef { a.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `(a + b) mod m` in `self`. - /// - /// OpenSSL documentation at [`BN_mod_add`] - /// - /// [`BN_mod_add`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_add.html + #[corresponds(BN_mod_add)] pub fn mod_add( &mut self, a: &BigNumRef, @@ -627,15 +573,13 @@ impl BigNumRef { b.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `(a - b) mod m` in `self`. - /// - /// OpenSSL documentation at [`BN_mod_sub`] - /// - /// [`BN_mod_sub`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_sub.html + #[corresponds(BN_mod_sub)] pub fn mod_sub( &mut self, a: &BigNumRef, @@ -650,15 +594,13 @@ impl BigNumRef { b.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `(a * b) mod m` in `self`. - /// - /// OpenSSL documentation at [`BN_mod_mul`] - /// - /// [`BN_mod_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_mul.html + #[corresponds(BN_mod_mul)] pub fn mod_mul( &mut self, a: &BigNumRef, @@ -673,15 +615,13 @@ impl BigNumRef { b.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a² mod m` in `self`. - /// - /// OpenSSL documentation at [`BN_mod_sqr`] - /// - /// [`BN_mod_sqr`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_sqr.html + #[corresponds(BN_mod_sqr)] pub fn mod_sqr( &mut self, a: &BigNumRef, @@ -694,15 +634,13 @@ impl BigNumRef { a.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a^p` in `self`. - /// - /// OpenSSL documentation at [`BN_exp`] - /// - /// [`BN_exp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_exp.html + #[corresponds(BN_exp)] pub fn exp( &mut self, a: &BigNumRef, @@ -715,15 +653,13 @@ impl BigNumRef { a.as_ptr(), p.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the result of `a^p mod m` in `self`. - /// - /// OpenSSL documentation at [`BN_mod_exp`] - /// - /// [`BN_mod_exp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_exp.html + #[corresponds(BN_mod_exp)] pub fn mod_exp( &mut self, a: &BigNumRef, @@ -738,11 +674,13 @@ impl BigNumRef { p.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the inverse of `a` modulo `n` in `self`. + #[corresponds(BN_mod_inverse)] pub fn mod_inverse( &mut self, a: &BigNumRef, @@ -755,15 +693,13 @@ impl BigNumRef { a.as_ptr(), n.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Places the greatest common denominator of `a` and `b` in `self`. - /// - /// OpenSSL documentation at [`BN_gcd`] - /// - /// [`BN_gcd`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_gcd.html + #[corresponds(BN_gcd)] pub fn gcd( &mut self, a: &BigNumRef, @@ -776,7 +712,8 @@ impl BigNumRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -784,14 +721,12 @@ impl BigNumRef { /// /// Performs a Miller-Rabin probabilistic primality test with `checks` iterations. /// - /// OpenSSL documentation at [`BN_is_prime_ex`] - /// - /// [`BN_is_prime_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_prime_ex.html - /// /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. - + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + #[corresponds(BN_is_prime_ex)] + #[allow(clippy::useless_conversion)] pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result { unsafe { cvt_n(ffi::BN_is_prime_ex( @@ -799,7 +734,8 @@ impl BigNumRef { checks.into(), ctx.as_ptr(), ptr::null_mut(), - )).map(|r| r != 0) + )) + .map(|r| r != 0) } } @@ -809,13 +745,12 @@ impl BigNumRef { /// Then, like `is_prime`, performs a Miller-Rabin probabilistic primality test with `checks` /// iterations. /// - /// OpenSSL documentation at [`BN_is_prime_fasttest_ex`] - /// - /// [`BN_is_prime_fasttest_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_prime_fasttest_ex.html - /// /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + #[corresponds(BN_is_prime_fasttest_ex)] + #[allow(clippy::useless_conversion)] pub fn is_prime_fasttest( &self, checks: i32, @@ -829,7 +764,8 @@ impl BigNumRef { ctx.as_ptr(), do_trial_division as c_int, ptr::null_mut(), - )).map(|r| r != 0) + )) + .map(|r| r != 0) } } @@ -845,6 +781,7 @@ impl BigNumRef { /// let s_vec = s.to_vec(); /// assert_eq!(BigNum::from_slice(&s_vec).unwrap(), r); /// ``` + #[corresponds(BN_bn2bin)] pub fn to_vec(&self) -> Vec { let size = self.num_bytes() as usize; let mut v = Vec::with_capacity(size); @@ -855,6 +792,38 @@ impl BigNumRef { v } + /// Returns a big-endian byte vector representation of the absolute value of `self` padded + /// to `pad_to` bytes. + /// + /// If `pad_to` is less than `self.num_bytes()` then an error is returned. + /// + /// `self` can be recreated by using `from_slice`. + /// + /// ``` + /// # use openssl::bn::BigNum; + /// let bn = BigNum::from_u32(0x4543).unwrap(); + /// + /// let bn_vec = bn.to_vec_padded(4).unwrap(); + /// assert_eq!(&bn_vec, &[0, 0, 0x45, 0x43]); + /// + /// let r = bn.to_vec_padded(1); + /// assert!(r.is_err()); + /// + /// let bn = -BigNum::from_u32(0x4543).unwrap(); + /// let bn_vec = bn.to_vec_padded(4).unwrap(); + /// assert_eq!(&bn_vec, &[0, 0, 0x45, 0x43]); + /// ``` + #[corresponds(BN_bn2binpad)] + #[cfg(ossl110)] + pub fn to_vec_padded(&self, pad_to: i32) -> Result, ErrorStack> { + let mut v = Vec::with_capacity(pad_to as usize); + unsafe { + cvt(ffi::BN_bn2binpad(self.as_ptr(), v.as_mut_ptr(), pad_to))?; + v.set_len(pad_to as usize); + } + Ok(v) + } + /// Returns a decimal string representation of `self`. /// /// ``` @@ -863,6 +832,7 @@ impl BigNumRef { /// /// assert_eq!(&**s.to_dec_str().unwrap(), "-12345"); /// ``` + #[corresponds(BN_bn2dec)] pub fn to_dec_str(&self) -> Result { unsafe { let buf = cvt_p(ffi::BN_bn2dec(self.as_ptr()))?; @@ -876,8 +846,9 @@ impl BigNumRef { /// # 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 { unsafe { let buf = cvt_p(ffi::BN_bn2hex(self.as_ptr()))?; @@ -886,16 +857,45 @@ impl BigNumRef { } /// Returns an `Asn1Integer` containing the value of `self`. + #[corresponds(BN_to_ASN1_INTEGER)] pub fn to_asn1_integer(&self) -> Result { unsafe { cvt_p(ffi::BN_to_ASN1_INTEGER(self.as_ptr(), ptr::null_mut())) .map(|p| Asn1Integer::from_ptr(p)) } } + + /// Force constant time computation on this value. + #[corresponds(BN_set_flags)] + #[cfg(ossl110)] + pub fn set_const_time(&mut self) { + unsafe { ffi::BN_set_flags(self.as_ptr(), ffi::BN_FLG_CONSTTIME) } + } + + /// Returns true if `self` is in const time mode. + #[corresponds(BN_get_flags)] + #[cfg(ossl110)] + pub fn is_const_time(&self) -> bool { + unsafe { + let ret = ffi::BN_get_flags(self.as_ptr(), ffi::BN_FLG_CONSTTIME); + ret == ffi::BN_FLG_CONSTTIME + } + } + + /// Returns true if `self` was created with [`BigNum::new_secure`]. + #[corresponds(BN_get_flags)] + #[cfg(ossl110)] + pub fn is_secure(&self) -> bool { + unsafe { + let ret = ffi::BN_get_flags(self.as_ptr(), ffi::BN_FLG_SECURE); + ret == ffi::BN_FLG_SECURE + } + } } impl BigNum { /// Creates a new `BigNum` with the value 0. + #[corresponds(BN_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -904,11 +904,19 @@ impl BigNum { } } + /// Returns a new secure `BigNum`. + #[corresponds(BN_secure_new)] + #[cfg(ossl110)] + pub fn new_secure() -> Result { + unsafe { + ffi::init(); + let v = cvt_p(ffi::BN_secure_new())?; + Ok(BigNum::from_ptr(v)) + } + } + /// Creates a new `BigNum` with the given value. - /// - /// OpenSSL documentation at [`BN_set_word`] - /// - /// [`BN_set_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_set_word.html + #[corresponds(BN_set_word)] pub fn from_u32(n: u32) -> Result { BigNum::new().and_then(|v| unsafe { cvt(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)).map(|_| v) @@ -916,10 +924,7 @@ impl BigNum { } /// Creates a `BigNum` from a decimal string. - /// - /// OpenSSL documentation at [`BN_dec2bn`] - /// - /// [`BN_dec2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_dec2bn.html + #[corresponds(BN_dec2bn)] pub fn from_dec_str(s: &str) -> Result { unsafe { ffi::init(); @@ -931,10 +936,7 @@ impl BigNum { } /// Creates a `BigNum` from a hexadecimal string. - /// - /// OpenSSL documentation at [`BN_hex2bn`] - /// - /// [`BN_hex2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_hex2bn.html + #[corresponds(BN_hex2bn)] pub fn from_hex_str(s: &str) -> Result { unsafe { ffi::init(); @@ -949,10 +951,9 @@ impl BigNum { /// the order of magnitude of `2 ^ 768`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled Oakley group id 1. /// - /// OpenSSL documentation at [`BN_get_rfc2409_prime_768`] - /// /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 - /// [`BN_get_rfc2409_prime_768`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc2409_prime_768.html + #[corresponds(BN_get_rfc2409_prime_768)] + #[cfg(not(boringssl))] pub fn get_rfc2409_prime_768() -> Result { unsafe { ffi::init(); @@ -964,10 +965,9 @@ impl BigNum { /// the order of magnitude of `2 ^ 1024`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled Oakly group 2. /// - /// OpenSSL documentation at [`BN_get_rfc2409_prime_1024`] - /// /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 - /// [`BN_get_rfc2409_prime_1024`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc2409_prime_1024.html + #[corresponds(BN_get_rfc2409_prime_1024)] + #[cfg(not(boringssl))] pub fn get_rfc2409_prime_1024() -> Result { unsafe { ffi::init(); @@ -979,10 +979,9 @@ impl BigNum { /// of magnitude of `2 ^ 1536`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 5. /// - /// OpenSSL documentation at [`BN_get_rfc3526_prime_1536`] - /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 - /// [`BN_get_rfc3526_prime_1536`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_1536.html + #[corresponds(BN_get_rfc3526_prime_1536)] + #[cfg(not(boringssl))] pub fn get_rfc3526_prime_1536() -> Result { unsafe { ffi::init(); @@ -994,10 +993,9 @@ impl BigNum { /// of magnitude of `2 ^ 2048`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 14. /// - /// OpenSSL documentation at [`BN_get_rfc3526_prime_2048`] - /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 - /// [`BN_get_rfc3526_prime_2048`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_2048.html + #[corresponds(BN_get_rfc3526_prime_2048)] + #[cfg(not(boringssl))] pub fn get_rfc3526_prime_2048() -> Result { unsafe { ffi::init(); @@ -1009,10 +1007,9 @@ impl BigNum { /// of magnitude of `2 ^ 3072`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 15. /// - /// OpenSSL documentation at [`BN_get_rfc3526_prime_3072`] - /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 - /// [`BN_get_rfc3526_prime_3072`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_3072.html + #[corresponds(BN_get_rfc3526_prime_3072)] + #[cfg(not(boringssl))] pub fn get_rfc3526_prime_3072() -> Result { unsafe { ffi::init(); @@ -1024,10 +1021,9 @@ impl BigNum { /// of magnitude of `2 ^ 4096`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 16. /// - /// OpenSSL documentation at [`BN_get_rfc3526_prime_4096`] - /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 - /// [`BN_get_rfc3526_prime_4096`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_4096.html + #[corresponds(BN_get_rfc3526_prime_4096)] + #[cfg(not(boringssl))] pub fn get_rfc3526_prime_4096() -> Result { unsafe { ffi::init(); @@ -1039,10 +1035,9 @@ impl BigNum { /// of magnitude of `2 ^ 6144`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 17. /// - /// OpenSSL documentation at [`BN_get_rfc3526_prime_6144`] - /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 - /// [`BN_get_rfc3526_prime_6144`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_6144.html + #[corresponds(BN_get_rfc3526_prime_6114)] + #[cfg(not(boringssl))] pub fn get_rfc3526_prime_6144() -> Result { unsafe { ffi::init(); @@ -1054,10 +1049,9 @@ impl BigNum { /// of magnitude of `2 ^ 8192`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 18. /// - /// OpenSSL documentation at [`BN_get_rfc3526_prime_8192`] - /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 - /// [`BN_get_rfc3526_prime_8192`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_8192.html + #[corresponds(BN_get_rfc3526_prime_8192)] + #[cfg(not(boringssl))] pub fn get_rfc3526_prime_8192() -> Result { unsafe { ffi::init(); @@ -1069,7 +1063,7 @@ impl BigNum { /// /// OpenSSL documentation at [`BN_bin2bn`] /// - /// [`BN_bin2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_bin2bn.html + /// [`BN_bin2bn`]: https://www.openssl.org/docs/manmaster/crypto/BN_bin2bn.html /// /// ``` /// # use openssl::bn::BigNum; @@ -1077,21 +1071,48 @@ impl BigNum { /// /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap()); /// ``` + #[corresponds(BN_bin2bn)] pub fn from_slice(n: &[u8]) -> Result { unsafe { ffi::init(); - assert!(n.len() <= c_int::max_value() as usize); + assert!(n.len() <= LenType::max_value() as usize); + cvt_p(ffi::BN_bin2bn( n.as_ptr(), - n.len() as c_int, + n.len() as LenType, ptr::null_mut(), - )).map(|p| BigNum::from_ptr(p)) + )) + .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(()) } } } impl fmt::Debug for BigNumRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), @@ -1100,7 +1121,7 @@ impl fmt::Debug for BigNumRef { } impl fmt::Debug for BigNum { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), @@ -1109,7 +1130,7 @@ impl fmt::Debug for BigNum { } impl fmt::Display for BigNumRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), @@ -1118,7 +1139,7 @@ impl fmt::Display for BigNumRef { } impl fmt::Display for BigNum { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), @@ -1215,7 +1236,7 @@ macro_rules! delegate { $t::$m(self.deref(), oth.deref()) } } - } + }; } impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef { @@ -1345,20 +1366,20 @@ impl Neg for BigNum { #[cfg(test)] mod tests { - use bn::{BigNumContext, BigNum}; + use crate::bn::{BigNum, BigNumContext}; #[test] fn test_to_from_slice() { - let v0 = BigNum::from_u32(10203004).unwrap(); + let v0 = BigNum::from_u32(10_203_004).unwrap(); let vec = v0.to_vec(); let v1 = BigNum::from_slice(&vec).unwrap(); - assert!(v0 == v1); + assert_eq!(v0, v1); } #[test] fn test_negation() { - let a = BigNum::from_u32(909829283).unwrap(); + let a = BigNum::from_u32(909_829_283).unwrap(); assert!(!a.is_negative()); assert!((-a).is_negative()); @@ -1366,31 +1387,33 @@ mod tests { #[test] fn test_shift() { - let a = BigNum::from_u32(909829283).unwrap(); - use std::ops::{Shl, Shr}; + let a = BigNum::from_u32(909_829_283).unwrap(); - assert!(a == a.shl(1).shr(1)); + assert_eq!(a, &(&a << 1) >> 1); } + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[test] fn test_rand_range() { - let range = BigNum::from_u32(909829283).unwrap(); + let range = BigNum::from_u32(909_829_283).unwrap(); let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap(); range.rand_range(&mut result).unwrap(); assert!(result >= BigNum::from_u32(0).unwrap() && result < range); } + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[test] fn test_pseudo_rand_range() { - let range = BigNum::from_u32(909829283).unwrap(); + let range = BigNum::from_u32(909_829_283).unwrap(); let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap(); range.pseudo_rand_range(&mut result).unwrap(); assert!(result >= BigNum::from_u32(0).unwrap() && result < range); } + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[test] fn test_prime_numbers() { - let a = BigNum::from_u32(19029017).unwrap(); + let a = BigNum::from_u32(19_029_017).unwrap(); let mut p = BigNum::new().unwrap(); p.generate_prime(128, true, None, Some(&a)).unwrap(); @@ -1398,4 +1421,38 @@ mod tests { assert!(p.is_prime(100, &mut ctx).unwrap()); assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap()); } + + #[cfg(ossl110)] + #[test] + fn test_secure_bn_ctx() { + let mut cxt = BigNumContext::new_secure().unwrap(); + let a = BigNum::from_u32(8).unwrap(); + let b = BigNum::from_u32(3).unwrap(); + + let mut remainder = BigNum::new().unwrap(); + remainder.nnmod(&a, &b, &mut cxt).unwrap(); + + assert!(remainder.eq(&BigNum::from_u32(2).unwrap())); + } + + #[cfg(ossl110)] + #[test] + fn test_secure_bn() { + let a = BigNum::new().unwrap(); + assert!(!a.is_secure()); + + let b = BigNum::new_secure().unwrap(); + assert!(b.is_secure()) + } + + #[cfg(ossl110)] + #[test] + fn test_const_time_bn() { + let a = BigNum::new().unwrap(); + assert!(!a.is_const_time()); + + let mut b = BigNum::new().unwrap(); + b.set_const_time(); + assert!(b.is_const_time()) + } } diff --git a/openssl/src/cipher.rs b/openssl/src/cipher.rs new file mode 100644 index 0000000..aeedf45 --- /dev/null +++ b/openssl/src/cipher.rs @@ -0,0 +1,484 @@ +//! Symmetric ciphers. + +#[cfg(ossl300)] +use crate::cvt_p; +#[cfg(ossl300)] +use crate::error::ErrorStack; +#[cfg(ossl300)] +use crate::lib_ctx::LibCtxRef; +use crate::nid::Nid; +use cfg_if::cfg_if; +use foreign_types::{ForeignTypeRef, Opaque}; +use openssl_macros::corresponds; +#[cfg(ossl300)] +use std::ffi::CString; +#[cfg(ossl300)] +use std::ptr; + +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; + + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).iv_len + } + + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).block_size + } + + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).key_len + } + } +} + +cfg_if! { + if #[cfg(ossl300)] { + use foreign_types::ForeignType; + use std::ops::{Deref, DerefMut}; + + type Inner = *mut ffi::EVP_CIPHER; + + impl Drop for Cipher { + #[inline] + fn drop(&mut self) { + unsafe { + ffi::EVP_CIPHER_free(self.as_ptr()); + } + } + } + + impl ForeignType for Cipher { + type CType = ffi::EVP_CIPHER; + type Ref = CipherRef; + + #[inline] + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { + Cipher(ptr) + } + + #[inline] + fn as_ptr(&self) -> *mut Self::CType { + self.0 + } + } + + impl Deref for Cipher { + type Target = CipherRef; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + CipherRef::from_ptr(self.as_ptr()) + } + } + } + + impl DerefMut for Cipher { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + CipherRef::from_ptr_mut(self.as_ptr()) + } + } + } + } else { + enum Inner {} + } +} + +/// A symmetric cipher. +pub struct Cipher(Inner); + +unsafe impl Sync for Cipher {} +unsafe impl Send for Cipher {} + +impl Cipher { + /// Looks up the cipher for a certain nid. + #[corresponds(EVP_get_cipherbynid)] + pub fn from_nid(nid: Nid) -> Option<&'static CipherRef> { + unsafe { + let ptr = ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())); + if ptr.is_null() { + None + } else { + Some(CipherRef::from_ptr(ptr as *mut _)) + } + } + } + + /// Fetches a cipher object corresponding to the specified algorithm name and properties. + /// + /// Requires OpenSSL 3.0.0 or newer. + #[corresponds(EVP_CIPHER_fetch)] + #[cfg(ossl300)] + pub fn fetch( + ctx: Option<&LibCtxRef>, + algorithm: &str, + properties: Option<&str>, + ) -> Result { + let algorithm = CString::new(algorithm).unwrap(); + let properties = properties.map(|s| CString::new(s).unwrap()); + + unsafe { + let ptr = cvt_p(ffi::EVP_CIPHER_fetch( + ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + algorithm.as_ptr(), + properties.map_or(ptr::null_mut(), |s| s.as_ptr()), + ))?; + + Ok(Cipher::from_ptr(ptr)) + } + } + + pub fn aes_128_ecb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ecb() as *mut _) } + } + + pub fn aes_128_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cbc() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_xts() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_xts() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_ctr() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ctr() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_cfb1() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb1() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_cfb128() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb128() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_cfb8() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb8() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_gcm() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_gcm() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_ccm() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ccm() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_128_ofb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ofb() as *mut _) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_128_ocb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ocb() as *mut _) } + } + + pub fn aes_192_ecb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ecb() as *mut _) } + } + + pub fn aes_192_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cbc() as *mut _) } + } + + pub fn aes_192_ctr() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ctr() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_192_cfb1() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb1() as *mut _) } + } + + pub fn aes_192_cfb128() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb128() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_192_cfb8() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb8() as *mut _) } + } + + pub fn aes_192_gcm() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_gcm() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_192_ccm() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ccm() as *mut _) } + } + + pub fn aes_192_ofb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ofb() as *mut _) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_192_ocb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ocb() as *mut _) } + } + + pub fn aes_256_ecb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ecb() as *mut _) } + } + + pub fn aes_256_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cbc() as *mut _) } + } + + pub fn aes_256_ctr() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ctr() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_256_cfb1() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb1() as *mut _) } + } + + pub fn aes_256_cfb128() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb128() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_256_cfb8() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb8() as *mut _) } + } + + pub fn aes_256_gcm() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_gcm() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn aes_256_ccm() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ccm() as *mut _) } + } + + pub fn aes_256_ofb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ofb() as *mut _) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_256_ocb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ocb() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_BF"))] + pub fn bf_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_BF"))] + pub fn bf_ecb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_bf_ecb() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_BF"))] + #[cfg(not(boringssl))] + pub fn bf_cfb64() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_bf_cfb64() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_BF"))] + #[cfg(not(boringssl))] + pub fn bf_ofb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_bf_ofb() as *mut _) } + } + + pub fn des_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_des_cbc() as *mut _) } + } + + pub fn des_ecb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_des_ecb() as *mut _) } + } + + pub fn des_ede3() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3() as *mut _) } + } + + pub fn des_ede3_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cbc() as *mut _) } + } + + #[cfg(not(boringssl))] + pub fn des_ede3_cfb64() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cfb64() as *mut _) } + } + + pub fn rc4() -> &'static CipherRef { + 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(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] + pub fn cast5_cfb64() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cfb64() as *mut _) } + } + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] + 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 _) } + } + + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] + pub fn chacha20_poly1305() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_chacha20_poly1305() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + #[cfg(not(boringssl))] + pub fn seed_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_seed_cbc() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + #[cfg(not(boringssl))] + pub fn seed_cfb128() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_seed_cfb128() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + #[cfg(not(boringssl))] + pub fn seed_ecb() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_seed_ecb() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] + #[cfg(not(boringssl))] + 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`]. +pub struct CipherRef(Opaque); + +impl ForeignTypeRef for CipherRef { + type CType = ffi::EVP_CIPHER; +} + +unsafe impl Sync for CipherRef {} +unsafe impl Send for CipherRef {} + +impl CipherRef { + /// Returns the cipher's Nid. + #[corresponds(EVP_CIPHER_nid)] + pub fn nid(&self) -> Nid { + let nid = unsafe { ffi::EVP_CIPHER_nid(self.as_ptr()) }; + Nid::from_raw(nid) + } + + /// Returns the length of keys used with this cipher. + #[corresponds(EVP_CIPHER_key_length)] + pub fn key_length(&self) -> usize { + unsafe { EVP_CIPHER_key_length(self.as_ptr()) as usize } + } + + /// Returns the length of the IV used with this cipher. + /// + /// # Note + /// + /// Ciphers that do not use an IV have an IV length of 0. + #[corresponds(EVP_CIPHER_iv_length)] + pub fn iv_length(&self) -> usize { + unsafe { EVP_CIPHER_iv_length(self.as_ptr()) as usize } + } + + /// Returns the block size of the cipher. + /// + /// # Note + /// + /// Stream ciphers have a block size of 1. + #[corresponds(EVP_CIPHER_block_size)] + pub fn block_size(&self) -> usize { + unsafe { EVP_CIPHER_block_size(self.as_ptr()) as usize } + } +} diff --git a/openssl/src/cipher_ctx.rs b/openssl/src/cipher_ctx.rs new file mode 100644 index 0000000..211c58b --- /dev/null +++ b/openssl/src/cipher_ctx.rs @@ -0,0 +1,841 @@ +//! The symmetric encryption context. +//! +//! # Examples +//! +//! Encrypt data with AES128 CBC +//! +//! ``` +//! use openssl::cipher::Cipher; +//! use openssl::cipher_ctx::CipherCtx; +//! +//! let cipher = Cipher::aes_128_cbc(); +//! let data = b"Some Crypto Text"; +//! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +//! let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; +//! +//! let mut ctx = CipherCtx::new().unwrap(); +//! ctx.encrypt_init(Some(cipher), Some(key), Some(iv)).unwrap(); +//! +//! let mut ciphertext = vec![]; +//! ctx.cipher_update_vec(data, &mut ciphertext).unwrap(); +//! ctx.cipher_final_vec(&mut ciphertext).unwrap(); +//! +//! assert_eq!( +//! b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\ +//! \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1", +//! &ciphertext[..], +//! ); +//! ``` +//! +//! Decrypt data with AES128 CBC +//! +//! ``` +//! use openssl::cipher::Cipher; +//! use openssl::cipher_ctx::CipherCtx; +//! +//! let cipher = Cipher::aes_128_cbc(); +//! let data = b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\ +//! \x87\x4D\xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1"; +//! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +//! let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; +//! +//! let mut ctx = CipherCtx::new().unwrap(); +//! ctx.decrypt_init(Some(cipher), Some(key), Some(iv)).unwrap(); +//! +//! let mut plaintext = vec![]; +//! ctx.cipher_update_vec(data, &mut plaintext).unwrap(); +//! ctx.cipher_final_vec(&mut plaintext).unwrap(); +//! +//! assert_eq!(b"Some Crypto Text", &plaintext[..]); +//! ``` +#![warn(missing_docs)] + +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 libc::{c_int, c_uchar}; +use openssl_macros::corresponds; +use std::convert::{TryFrom, TryInto}; +use std::ptr; + +cfg_if! { + if #[cfg(ossl300)] { + use ffi::EVP_CIPHER_CTX_get0_cipher; + } else { + use ffi::EVP_CIPHER_CTX_cipher as EVP_CIPHER_CTX_get0_cipher; + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::EVP_CIPHER_CTX; + fn drop = ffi::EVP_CIPHER_CTX_free; + + /// A context object used to perform symmetric encryption operations. + pub struct CipherCtx; + /// A reference to a [`CipherCtx`]. + pub struct CipherCtxRef; +} + +impl CipherCtx { + /// Creates a new context. + #[corresponds(EVP_CIPHER_CTX_new)] + pub fn new() -> Result { + ffi::init(); + + unsafe { + let ptr = cvt_p(ffi::EVP_CIPHER_CTX_new())?; + Ok(CipherCtx::from_ptr(ptr)) + } + } +} + +impl CipherCtxRef { + /// Initializes the context for encryption. + /// + /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up + /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used + /// to, for example, use a nonstandard IV size. + /// + /// # Panics + /// + /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size + /// of the cipher, or if a key or IV is provided before a cipher. + #[corresponds(EVP_EncryptInit_ex)] + pub fn encrypt_init( + &mut self, + type_: Option<&CipherRef>, + key: Option<&[u8]>, + iv: Option<&[u8]>, + ) -> Result<(), ErrorStack> { + self.cipher_init(type_, key, iv, ffi::EVP_EncryptInit_ex) + } + + /// Initializes the context for decryption. + /// + /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up + /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used + /// to, for example, use a nonstandard IV size. + /// + /// # Panics + /// + /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size + /// of the cipher, or if a key or IV is provided before a cipher. + #[corresponds(EVP_DecryptInit_ex)] + pub fn decrypt_init( + &mut self, + type_: Option<&CipherRef>, + key: Option<&[u8]>, + iv: Option<&[u8]>, + ) -> Result<(), ErrorStack> { + self.cipher_init(type_, key, iv, ffi::EVP_DecryptInit_ex) + } + + fn cipher_init( + &mut self, + type_: Option<&CipherRef>, + key: Option<&[u8]>, + iv: Option<&[u8]>, + f: unsafe extern "C" fn( + *mut ffi::EVP_CIPHER_CTX, + *const ffi::EVP_CIPHER, + *mut ffi::ENGINE, + *const c_uchar, + *const c_uchar, + ) -> c_int, + ) -> Result<(), ErrorStack> { + if let Some(key) = key { + let key_len = type_.map_or_else(|| self.key_length(), |c| c.key_length()); + assert!(key_len <= key.len()); + } + + if let Some(iv) = iv { + let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); + assert!(iv_len <= iv.len()); + } + + unsafe { + cvt(f( + self.as_ptr(), + type_.map_or(ptr::null(), |p| p.as_ptr()), + ptr::null_mut(), + key.map_or(ptr::null(), |k| k.as_ptr()), + iv.map_or(ptr::null(), |iv| iv.as_ptr()), + ))?; + } + + Ok(()) + } + + /// Initializes the context to perform envelope encryption. + /// + /// Normally this is called once to set both the cipher and public keys. However, this process may be split up by + /// first providing the cipher with no public keys and then setting the public keys with no cipher. + /// + /// `encrypted_keys` will contain the generated symmetric key encrypted with each corresponding asymmetric private + /// key. The generated IV will be written to `iv`. + /// + /// # Panics + /// + /// Panics if `pub_keys` is not the same size as `encrypted_keys`, the IV buffer is smaller than the cipher's IV + /// size, or if an IV is provided before the cipher. + #[corresponds(EVP_SealInit)] + #[cfg(not(boringssl))] + pub fn seal_init( + &mut self, + type_: Option<&CipherRef>, + pub_keys: &[PKey], + encrypted_keys: &mut [Vec], + iv: Option<&mut [u8]>, + ) -> Result<(), ErrorStack> + where + T: HasPublic, + { + assert_eq!(pub_keys.len(), encrypted_keys.len()); + if !pub_keys.is_empty() { + let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); + assert!(iv.as_ref().map_or(0, |b| b.len()) >= iv_len); + } + + for (pub_key, buf) in pub_keys.iter().zip(&mut *encrypted_keys) { + buf.resize(pub_key.size(), 0); + } + + let mut keys = encrypted_keys + .iter_mut() + .map(|b| b.as_mut_ptr()) + .collect::>(); + let mut key_lengths = vec![0; pub_keys.len()]; + let pub_keys_len = i32::try_from(pub_keys.len()).unwrap(); + + unsafe { + cvt(ffi::EVP_SealInit( + self.as_ptr(), + type_.map_or(ptr::null(), |p| p.as_ptr()), + keys.as_mut_ptr(), + key_lengths.as_mut_ptr(), + iv.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + pub_keys.as_ptr() as *mut _, + pub_keys_len, + ))?; + } + + for (buf, len) in encrypted_keys.iter_mut().zip(key_lengths) { + buf.truncate(len as usize); + } + + Ok(()) + } + + /// Initializes the context to perform envelope decryption. + /// + /// Normally this is called once with all of the arguments present. However, this process may be split up by first + /// providing the cipher alone and then after providing the rest of the arguments in a second call. + /// + /// # Panics + /// + /// Panics if the IV buffer is smaller than the cipher's required IV size or if the IV is provided before the + /// cipher. + #[corresponds(EVP_OpenInit)] + #[cfg(not(boringssl))] + pub fn open_init( + &mut self, + type_: Option<&CipherRef>, + encrypted_key: &[u8], + iv: Option<&[u8]>, + priv_key: Option<&PKeyRef>, + ) -> Result<(), ErrorStack> + where + T: HasPrivate, + { + if priv_key.is_some() { + let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); + assert!(iv.map_or(0, |b| b.len()) >= iv_len); + } + + let len = c_int::try_from(encrypted_key.len()).unwrap(); + unsafe { + cvt(ffi::EVP_OpenInit( + self.as_ptr(), + type_.map_or(ptr::null(), |p| p.as_ptr()), + encrypted_key.as_ptr(), + len, + iv.map_or(ptr::null(), |b| b.as_ptr()), + priv_key.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + ))?; + } + + Ok(()) + } + + fn assert_cipher(&self) { + unsafe { + assert!(!EVP_CIPHER_CTX_get0_cipher(self.as_ptr()).is_null()); + } + } + + /// Returns the block size of the context's cipher. + /// + /// Stream ciphers will report a block size of 1. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher. + #[corresponds(EVP_CIPHER_CTX_block_size)] + pub fn block_size(&self) -> usize { + self.assert_cipher(); + + unsafe { ffi::EVP_CIPHER_CTX_block_size(self.as_ptr()) as usize } + } + + /// Returns the key length of the context's cipher. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher. + #[corresponds(EVP_CIPHER_CTX_key_length)] + pub fn key_length(&self) -> usize { + self.assert_cipher(); + + unsafe { ffi::EVP_CIPHER_CTX_key_length(self.as_ptr()) as usize } + } + + /// Generates a random key based on the configured cipher. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher or if the buffer is smaller than the cipher's key + /// length. + /// + /// This corresponds to [`EVP_CIPHER_CTX_rand_key`]. + /// + /// [`EVP_CIPHER_CTX_rand_key`]: https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_CTX_rand_key.html + #[corresponds(EVP_CIPHER_CTX_rand_key)] + #[cfg(not(boringssl))] + pub fn rand_key(&self, buf: &mut [u8]) -> Result<(), ErrorStack> { + assert!(buf.len() >= self.key_length()); + + unsafe { + cvt(ffi::EVP_CIPHER_CTX_rand_key( + self.as_ptr(), + buf.as_mut_ptr(), + ))?; + } + + Ok(()) + } + + /// Sets the length of the key expected by the context. + /// + /// Only some ciphers support configurable key lengths. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher. + #[corresponds(EVP_CIPHER_CTX_set_key_length)] + pub fn set_key_length(&mut self, len: usize) -> Result<(), ErrorStack> { + self.assert_cipher(); + + unsafe { + cvt(ffi::EVP_CIPHER_CTX_set_key_length( + self.as_ptr(), + len.try_into().unwrap(), + ))?; + } + + Ok(()) + } + + /// Returns the length of the IV expected by this context. + /// + /// Returns 0 if the cipher does not use an IV. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher. + #[corresponds(EVP_CIPHER_CTX_iv_length)] + pub fn iv_length(&self) -> usize { + self.assert_cipher(); + + unsafe { ffi::EVP_CIPHER_CTX_iv_length(self.as_ptr()) as usize } + } + + /// Returns the `num` parameter of the cipher. + /// + /// Built-in ciphers typically use this to track how much of the + /// current underlying block has been "used" already. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher. + #[corresponds(EVP_CIPHER_CTX_num)] + #[cfg(ossl110)] + pub fn num(&self) -> usize { + self.assert_cipher(); + + unsafe { ffi::EVP_CIPHER_CTX_num(self.as_ptr()) as usize } + } + + /// Sets the length of the IV expected by this context. + /// + /// Only some ciphers support configurable IV lengths. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher. + #[corresponds(EVP_CIPHER_CTX_ctrl)] + pub fn set_iv_length(&mut self, len: usize) -> Result<(), ErrorStack> { + self.assert_cipher(); + + let len = c_int::try_from(len).unwrap(); + + unsafe { + cvt(ffi::EVP_CIPHER_CTX_ctrl( + self.as_ptr(), + ffi::EVP_CTRL_GCM_SET_IVLEN, + len, + ptr::null_mut(), + ))?; + } + + Ok(()) + } + + /// Returns the length of the authentication tag expected by this context. + /// + /// Returns 0 if the cipher is not authenticated. + /// + /// # Panics + /// + /// Panics if the context has not been initialized with a cipher. + /// + /// Requires OpenSSL 3.0.0 or newer. + #[corresponds(EVP_CIPHER_CTX_get_tag_length)] + #[cfg(ossl300)] + pub fn tag_length(&self) -> usize { + self.assert_cipher(); + + unsafe { ffi::EVP_CIPHER_CTX_get_tag_length(self.as_ptr()) as usize } + } + + /// Retrieves the calculated authentication tag from the context. + /// + /// 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. + #[corresponds(EVP_CIPHER_CTX_ctrl)] + pub fn tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { + let len = c_int::try_from(tag.len()).unwrap(); + + unsafe { + cvt(ffi::EVP_CIPHER_CTX_ctrl( + self.as_ptr(), + ffi::EVP_CTRL_GCM_GET_TAG, + len, + tag.as_mut_ptr() as *mut _, + ))?; + } + + Ok(()) + } + + /// Sets the length of the generated authentication tag. + /// + /// This must be called when encrypting with a cipher in CCM mode to use a tag size other than the default. + #[corresponds(EVP_CIPHER_CTX_ctrl)] + pub fn set_tag_length(&mut self, len: usize) -> Result<(), ErrorStack> { + let len = c_int::try_from(len).unwrap(); + + unsafe { + cvt(ffi::EVP_CIPHER_CTX_ctrl( + self.as_ptr(), + ffi::EVP_CTRL_GCM_SET_TAG, + len, + ptr::null_mut(), + ))?; + } + + Ok(()) + } + + /// Sets the authentication tag for verification during decryption. + #[corresponds(EVP_CIPHER_CTX_ctrl)] + pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> { + let len = c_int::try_from(tag.len()).unwrap(); + + unsafe { + cvt(ffi::EVP_CIPHER_CTX_ctrl( + self.as_ptr(), + ffi::EVP_CTRL_GCM_SET_TAG, + len, + tag.as_ptr() as *mut _, + ))?; + } + + Ok(()) + } + + /// Enables or disables padding. + /// + /// If padding is disabled, the plaintext must be an exact multiple of the cipher's block size. + #[corresponds(EVP_CIPHER_CTX_set_padding)] + pub fn set_padding(&mut self, padding: bool) { + unsafe { + ffi::EVP_CIPHER_CTX_set_padding(self.as_ptr(), padding as c_int); + } + } + + /// Sets the total length of plaintext data. + /// + /// This is required for ciphers operating in CCM mode. + #[corresponds(EVP_CipherUpdate)] + pub fn set_data_len(&mut self, len: usize) -> Result<(), ErrorStack> { + let len = c_int::try_from(len).unwrap(); + + unsafe { + cvt(ffi::EVP_CipherUpdate( + self.as_ptr(), + ptr::null_mut(), + &mut 0, + ptr::null(), + len, + ))?; + } + + Ok(()) + } + + /// Writes data into the context. + /// + /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD). + /// + /// Returns the number of bytes written to `output`. + /// + /// # Panics + /// + /// Panics if `output` doesn't contain enough space for data to be + /// written as specified by [`Self::minimal_output_size`]. + #[corresponds(EVP_CipherUpdate)] + pub fn cipher_update( + &mut self, + input: &[u8], + output: Option<&mut [u8]>, + ) -> Result { + if let Some(output) = &output { + let mut block_size = self.block_size(); + if block_size == 1 { + block_size = 0; + } + let min_output_size = input.len() + block_size; + assert!( + output.len() >= min_output_size, + "Output buffer size should be at least {} bytes.", + min_output_size + ); + } + + unsafe { self.cipher_update_unchecked(input, output) } + } + + /// Writes data into the context. + /// + /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD). + /// + /// Returns the number of bytes written to `output`. + /// + /// This function is the same as [`Self::cipher_update`] but with the + /// output size check removed. It can be used when the exact + /// buffer size control is maintained by the caller. + /// + /// SAFETY: The caller is expected to provide `output` buffer + /// large enough to contain correct number of bytes. For streaming + /// ciphers the output buffer size should be at least as big as + /// the input buffer. For block ciphers the size of the output + /// buffer depends on the state of partially updated blocks. + #[corresponds(EVP_CipherUpdate)] + pub unsafe fn cipher_update_unchecked( + &mut self, + input: &[u8], + output: Option<&mut [u8]>, + ) -> Result { + let inlen = c_int::try_from(input.len()).unwrap(); + + let mut outlen = 0; + + cvt(ffi::EVP_CipherUpdate( + self.as_ptr(), + output.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut outlen, + input.as_ptr(), + inlen, + ))?; + + Ok(outlen as usize) + } + + /// Like [`Self::cipher_update`] except that it appends output to a [`Vec`]. + pub fn cipher_update_vec( + &mut self, + input: &[u8], + output: &mut Vec, + ) -> Result { + let base = output.len(); + output.resize(base + input.len() + self.block_size(), 0); + let len = self.cipher_update(input, Some(&mut output[base..]))?; + output.truncate(base + len); + + Ok(len) + } + + /// Finalizes the encryption or decryption process. + /// + /// Any remaining data will be written to the output buffer. + /// + /// Returns the number of bytes written to `output`. + /// + /// # Panics + /// + /// Panics if `output` is smaller than the cipher's block size. + #[corresponds(EVP_CipherFinal)] + pub fn cipher_final(&mut self, output: &mut [u8]) -> Result { + let block_size = self.block_size(); + if block_size > 1 { + assert!(output.len() >= block_size); + } + + unsafe { self.cipher_final_unchecked(output) } + } + + /// Finalizes the encryption or decryption process. + /// + /// Any remaining data will be written to the output buffer. + /// + /// Returns the number of bytes written to `output`. + /// + /// This function is the same as [`Self::cipher_final`] but with + /// the output buffer size check removed. + /// + /// SAFETY: The caller is expected to provide `output` buffer + /// large enough to contain correct number of bytes. For streaming + /// ciphers the output buffer can be empty, for block ciphers the + /// output buffer should be at least as big as the block. + #[corresponds(EVP_CipherFinal)] + pub unsafe fn cipher_final_unchecked( + &mut self, + output: &mut [u8], + ) -> Result { + let mut outl = 0; + + cvt(ffi::EVP_CipherFinal( + self.as_ptr(), + output.as_mut_ptr(), + &mut outl, + ))?; + + Ok(outl as usize) + } + + /// Like [`Self::cipher_final`] except that it appends output to a [`Vec`]. + pub fn cipher_final_vec(&mut self, output: &mut Vec) -> Result { + let base = output.len(); + output.resize(base + self.block_size(), 0); + let len = self.cipher_final(&mut output[base..])?; + output.truncate(base + len); + + Ok(len) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::{cipher::Cipher, rand::rand_bytes}; + #[cfg(not(boringssl))] + use std::slice; + + #[test] + #[cfg(not(boringssl))] + fn seal_open() { + let private_pem = include_bytes!("../test/rsa.pem"); + let public_pem = include_bytes!("../test/rsa.pem.pub"); + let private_key = PKey::private_key_from_pem(private_pem).unwrap(); + let public_key = PKey::public_key_from_pem(public_pem).unwrap(); + let cipher = Cipher::aes_256_cbc(); + let secret = b"My secret message"; + + let mut ctx = CipherCtx::new().unwrap(); + let mut encrypted_key = vec![]; + let mut iv = vec![0; cipher.iv_length()]; + let mut encrypted = vec![]; + ctx.seal_init( + Some(cipher), + &[public_key], + slice::from_mut(&mut encrypted_key), + Some(&mut iv), + ) + .unwrap(); + ctx.cipher_update_vec(secret, &mut encrypted).unwrap(); + ctx.cipher_final_vec(&mut encrypted).unwrap(); + + let mut decrypted = vec![]; + ctx.open_init(Some(cipher), &encrypted_key, Some(&iv), Some(&private_key)) + .unwrap(); + ctx.cipher_update_vec(&encrypted, &mut decrypted).unwrap(); + ctx.cipher_final_vec(&mut decrypted).unwrap(); + + assert_eq!(secret, &decrypted[..]); + } + + fn aes_128_cbc(cipher: &CipherRef) { + // from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf + let key = hex::decode("2b7e151628aed2a6abf7158809cf4f3c").unwrap(); + let iv = hex::decode("000102030405060708090a0b0c0d0e0f").unwrap(); + let pt = hex::decode("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51") + .unwrap(); + let ct = hex::decode("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2") + .unwrap(); + + let mut ctx = CipherCtx::new().unwrap(); + + ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) + .unwrap(); + ctx.set_padding(false); + + let mut buf = vec![]; + ctx.cipher_update_vec(&pt, &mut buf).unwrap(); + ctx.cipher_final_vec(&mut buf).unwrap(); + + assert_eq!(buf, ct); + + ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) + .unwrap(); + ctx.set_padding(false); + + let mut buf = vec![]; + ctx.cipher_update_vec(&ct, &mut buf).unwrap(); + ctx.cipher_final_vec(&mut buf).unwrap(); + + assert_eq!(buf, pt); + } + + #[test] + #[cfg(ossl300)] + fn fetched_aes_128_cbc() { + let cipher = Cipher::fetch(None, "AES-128-CBC", None).unwrap(); + aes_128_cbc(&cipher); + } + + #[test] + fn default_aes_128_cbc() { + let cipher = Cipher::aes_128_cbc(); + aes_128_cbc(cipher); + } + + #[test] + fn test_stream_ciphers() { + test_stream_cipher(Cipher::aes_192_ctr()); + test_stream_cipher(Cipher::aes_256_ctr()); + } + + fn test_stream_cipher(cipher: &'static CipherRef) { + let mut key = vec![0; cipher.key_length()]; + rand_bytes(&mut key).unwrap(); + let mut iv = vec![0; cipher.iv_length()]; + rand_bytes(&mut iv).unwrap(); + + let mut ctx = CipherCtx::new().unwrap(); + + ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) + .unwrap(); + ctx.set_padding(false); + + assert_eq!( + 1, + cipher.block_size(), + "Need a stream cipher, not a block cipher" + ); + + // update cipher with non-full block + // this is a streaming cipher so the number of output bytes + // will be the same as the number of input bytes + let mut output = vec![0; 32]; + let outlen = ctx + .cipher_update(&[1; 15], Some(&mut output[0..15])) + .unwrap(); + assert_eq!(15, outlen); + + // update cipher with missing bytes from the previous block + // as previously it will output the same number of bytes as + // the input + let outlen = ctx + .cipher_update(&[1; 17], Some(&mut output[15..])) + .unwrap(); + assert_eq!(17, outlen); + + ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); + + // try to decrypt + ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) + .unwrap(); + ctx.set_padding(false); + + // update cipher with non-full block + // expect that the output for stream cipher will contain + // the same number of bytes as the input + let mut output_decrypted = vec![0; 32]; + let outlen = ctx + .cipher_update(&output[0..15], Some(&mut output_decrypted[0..15])) + .unwrap(); + assert_eq!(15, outlen); + + let outlen = ctx + .cipher_update(&output[15..], Some(&mut output_decrypted[15..])) + .unwrap(); + assert_eq!(17, outlen); + + ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); + // check if the decrypted blocks are the same as input (all ones) + assert_eq!(output_decrypted, vec![1; 32]); + } + + #[test] + #[should_panic(expected = "Output buffer size should be at least 33 bytes.")] + fn full_block_updates_aes_128() { + output_buffer_too_small(Cipher::aes_128_cbc()); + } + + #[test] + #[should_panic(expected = "Output buffer size should be at least 33 bytes.")] + fn full_block_updates_aes_256() { + output_buffer_too_small(Cipher::aes_256_cbc()); + } + + #[test] + #[should_panic(expected = "Output buffer size should be at least 17 bytes.")] + fn full_block_updates_3des() { + output_buffer_too_small(Cipher::des_ede3_cbc()); + } + + fn output_buffer_too_small(cipher: &'static CipherRef) { + let mut key = vec![0; cipher.key_length()]; + rand_bytes(&mut key).unwrap(); + let mut iv = vec![0; cipher.iv_length()]; + rand_bytes(&mut iv).unwrap(); + + let mut ctx = CipherCtx::new().unwrap(); + + ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) + .unwrap(); + ctx.set_padding(false); + + let block_size = cipher.block_size(); + assert!(block_size > 1, "Need a block cipher, not a stream cipher"); + + ctx.cipher_update(&vec![0; block_size + 1], Some(&mut vec![0; block_size - 1])) + .unwrap(); + } +} diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 160d2da..6b6aa9f 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -1,22 +1,52 @@ //! SMIME implementation using CMS //! -//! CMS (PKCS#7) is an encyption standard. It allows signing and ecrypting data using +//! CMS (PKCS#7) is an encryption standard. It allows signing and encrypting data using //! X.509 certificates. The OpenSSL implementation of CMS is used in email encryption //! generated from a `Vec` of bytes. This `Vec` follows the smime protocol standards. //! Data accepted by this module will be smime type `enveloped-data`. -use ffi; +use bitflags::bitflags; use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_uint; use std::ptr; -use error::ErrorStack; -use bio::{MemBio, MemBioSlice}; +use crate::bio::{MemBio, MemBioSlice}; +use crate::error::ErrorStack; +use crate::pkey::{HasPrivate, PKeyRef}; +use crate::stack::StackRef; +use crate::symm::Cipher; +use crate::x509::{store::X509StoreRef, X509Ref, X509}; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; -use x509::X509; -use pkey::PKeyRef; - -use cvt; -use cvt_p; +bitflags! { + pub struct CMSOptions : c_uint { + const TEXT = ffi::CMS_TEXT; + const CMS_NOCERTS = ffi::CMS_NOCERTS; + const NO_CONTENT_VERIFY = ffi::CMS_NO_CONTENT_VERIFY; + const NO_ATTR_VERIFY = ffi::CMS_NO_ATTR_VERIFY; + const NOSIGS = ffi::CMS_NOSIGS; + const NOINTERN = ffi::CMS_NOINTERN; + const NO_SIGNER_CERT_VERIFY = ffi::CMS_NO_SIGNER_CERT_VERIFY; + const NOVERIFY = ffi::CMS_NOVERIFY; + const DETACHED = ffi::CMS_DETACHED; + const BINARY = ffi::CMS_BINARY; + const NOATTR = ffi::CMS_NOATTR; + const NOSMIMECAP = ffi::CMS_NOSMIMECAP; + const NOOLDMIMETYPE = ffi::CMS_NOOLDMIMETYPE; + const CRLFEOL = ffi::CMS_CRLFEOL; + const STREAM = ffi::CMS_STREAM; + const NOCRL = ffi::CMS_NOCRL; + const PARTIAL = ffi::CMS_PARTIAL; + const REUSE_DIGEST = ffi::CMS_REUSE_DIGEST; + const USE_KEYID = ffi::CMS_USE_KEYID; + const DEBUG_DECRYPT = ffi::CMS_DEBUG_DECRYPT; + #[cfg(all(not(libressl), not(ossl101)))] + const KEY_PARAM = ffi::CMS_KEY_PARAM; + #[cfg(all(not(libressl), not(ossl101), not(ossl102)))] + const ASCIICRLF = ffi::CMS_ASCIICRLF; + } +} foreign_type_and_impl_send_sync! { type CType = ffi::CMS_ContentInfo; @@ -27,7 +57,7 @@ foreign_type_and_impl_send_sync! { /// CMS supports nesting various types of data, including signatures, certificates, /// encrypted data, smime messages (encrypted email), and data digest. The ContentInfo /// content type is the encapsulation of all those content types. [`RFC 5652`] describes - /// CMS and OpenSSL follows this RFC's implmentation. + /// CMS and OpenSSL follows this RFC's implementation. /// /// [`RFC 5652`]: https://tools.ietf.org/html/rfc5652#page-6 pub struct CmsContentInfo; @@ -38,18 +68,17 @@ foreign_type_and_impl_send_sync! { } impl CmsContentInfoRef { - /// Given the sender's private key, `pkey` and the recipient's certificiate, `cert`, + /// Given the sender's private key, `pkey` and the recipient's certificate, `cert`, /// decrypt the data in `self`. - /// - /// OpenSSL documentation at [`CMS_decrypt`] - /// - /// [`CMS_decrypt`]: https://www.openssl.org/docs/man1.1.0/crypto/CMS_decrypt.html - pub fn decrypt(&self, pkey: &PKeyRef, cert: &X509) -> Result, ErrorStack> { + #[corresponds(CMS_decrypt)] + pub fn decrypt(&self, pkey: &PKeyRef, cert: &X509) -> Result, ErrorStack> + where + T: HasPrivate, + { unsafe { let pkey = pkey.as_ptr(); let cert = cert.as_ptr(); let out = MemBio::new()?; - let flags: u32 = 0; cvt(ffi::CMS_decrypt( self.as_ptr(), @@ -57,31 +86,401 @@ impl CmsContentInfoRef { cert, ptr::null_mut(), out.as_ptr(), - flags.into(), + 0, + ))?; + + Ok(out.get_buf().to_owned()) + } + } + + /// Given the sender's private key, `pkey`, + /// decrypt the data in `self` without validating the recipient certificate. + /// + /// *Warning*: Not checking the recipient certificate may leave you vulnerable to Bleichenbacher's attack on PKCS#1 v1.5 RSA padding. + #[corresponds(CMS_decrypt)] + // FIXME merge into decrypt + pub fn decrypt_without_cert_check(&self, pkey: &PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + unsafe { + let pkey = pkey.as_ptr(); + let out = MemBio::new()?; + + cvt(ffi::CMS_decrypt( + self.as_ptr(), + pkey, + ptr::null_mut(), + ptr::null_mut(), + out.as_ptr(), + 0, ))?; Ok(out.get_buf().to_owned()) } } + to_der! { + /// Serializes this CmsContentInfo using DER. + #[corresponds(i2d_CMS_ContentInfo)] + to_der, + ffi::i2d_CMS_ContentInfo + } + + to_pem! { + /// Serializes this CmsContentInfo using DER. + #[corresponds(PEM_write_bio_CMS)] + to_pem, + ffi::PEM_write_bio_CMS + } } impl CmsContentInfo { /// Parses a smime formatted `vec` of bytes into a `CmsContentInfo`. - /// - /// OpenSSL documentation at [`SMIME_read_CMS`] - /// - /// [`SMIME_read_CMS`]: https://www.openssl.org/docs/man1.0.2/crypto/SMIME_read_CMS.html + #[corresponds(SMIME_read_CMS)] pub fn smime_read_cms(smime: &[u8]) -> Result { unsafe { let bio = MemBioSlice::new(smime)?; - let cms = cvt_p(ffi::SMIME_read_CMS( - bio.as_ptr(), - ptr::null_mut(), + let cms = cvt_p(ffi::SMIME_read_CMS(bio.as_ptr(), ptr::null_mut()))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } + + from_der! { + /// Deserializes a DER-encoded ContentInfo structure. + #[corresponds(d2i_CMS_ContentInfo)] + from_der, + CmsContentInfo, + ffi::d2i_CMS_ContentInfo + } + + from_pem! { + /// Deserializes a PEM-encoded ContentInfo structure. + #[corresponds(PEM_read_bio_CMS)] + from_pem, + CmsContentInfo, + ffi::PEM_read_bio_CMS + } + + /// Given a signing cert `signcert`, private key `pkey`, a certificate stack `certs`, + /// data `data` and flags `flags`, create a CmsContentInfo struct. + /// + /// All arguments are optional. + #[corresponds(CMS_sign)] + pub fn sign( + signcert: Option<&X509Ref>, + pkey: Option<&PKeyRef>, + certs: Option<&StackRef>, + data: Option<&[u8]>, + flags: CMSOptions, + ) -> Result + where + T: HasPrivate, + { + unsafe { + let signcert = signcert.map_or(ptr::null_mut(), |p| p.as_ptr()); + let pkey = pkey.map_or(ptr::null_mut(), |p| p.as_ptr()); + let data_bio = match data { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, + }; + let data_bio_ptr = data_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); + let certs = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); + + let cms = cvt_p(ffi::CMS_sign( + signcert, + pkey, + certs, + data_bio_ptr, + flags.bits(), ))?; Ok(CmsContentInfo::from_ptr(cms)) } } + + /// Given a certificate stack `certs`, data `data`, cipher `cipher` and flags `flags`, + /// create a CmsContentInfo struct. + /// + /// OpenSSL documentation at [`CMS_encrypt`] + /// + /// [`CMS_encrypt`]: https://www.openssl.org/docs/manmaster/man3/CMS_encrypt.html + #[corresponds(CMS_encrypt)] + pub fn encrypt( + certs: &StackRef, + data: &[u8], + cipher: Cipher, + flags: CMSOptions, + ) -> Result { + unsafe { + let data_bio = MemBioSlice::new(data)?; + + let cms = cvt_p(ffi::CMS_encrypt( + certs.as_ptr(), + data_bio.as_ptr(), + cipher.as_ptr(), + flags.bits(), + ))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } + + /// Verify this CmsContentInfo's signature, + /// This will search the 'certs' list for the signing certificate. + /// Additional certificates, needed for building the certificate chain, may be + /// given in 'store' as well as additional CRLs. + /// A detached signature may be passed in `detached_data`. The signed content + /// without signature, will be copied into output_data if it is present. + /// + #[corresponds(CMS_verify)] + pub fn verify( + &mut self, + certs: Option<&StackRef>, + store: Option<&X509StoreRef>, + detached_data: Option<&[u8]>, + output_data: Option<&mut Vec>, + flags: CMSOptions, + ) -> Result<(), ErrorStack> { + unsafe { + let certs_ptr = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); + let store_ptr = store.map_or(ptr::null_mut(), |p| p.as_ptr()); + let detached_data_bio = match detached_data { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, + }; + let detached_data_bio_ptr = detached_data_bio + .as_ref() + .map_or(ptr::null_mut(), |p| p.as_ptr()); + let out_bio = MemBio::new()?; + + cvt(ffi::CMS_verify( + self.as_ptr(), + certs_ptr, + store_ptr, + detached_data_bio_ptr, + out_bio.as_ptr(), + flags.bits(), + ))?; + + if let Some(data) = output_data { + data.clear(); + data.extend_from_slice(out_bio.get_buf()); + }; + + Ok(()) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + use crate::pkcs12::Pkcs12; + use crate::pkey::PKey; + use crate::stack::Stack; + use crate::x509::{ + store::{X509Store, X509StoreBuilder}, + X509, + }; + + #[test] + fn cms_encrypt_decrypt() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + + // load cert with public key only + let pub_cert_bytes = include_bytes!("../test/cms_pubkey.der"); + let pub_cert = X509::from_der(pub_cert_bytes).expect("failed to load pub cert"); + + // load cert with private key + let priv_cert_bytes = include_bytes!("../test/cms.p12"); + let priv_cert = Pkcs12::from_der(priv_cert_bytes).expect("failed to load priv cert"); + let priv_cert = priv_cert + .parse2("mypass") + .expect("failed to parse priv cert"); + + // encrypt cms message using public key cert + let input = String::from("My Message"); + let mut cert_stack = Stack::new().expect("failed to create stack"); + cert_stack + .push(pub_cert) + .expect("failed to add pub cert to stack"); + + let encrypt = CmsContentInfo::encrypt( + &cert_stack, + input.as_bytes(), + Cipher::des_ede3_cbc(), + CMSOptions::empty(), + ) + .expect("failed create encrypted cms"); + + // decrypt cms message using private key cert (DER) + { + let encrypted_der = encrypt.to_der().expect("failed to create der from cms"); + let decrypt = + CmsContentInfo::from_der(&encrypted_der).expect("failed read cms from der"); + + let decrypt_with_cert_check = decrypt + .decrypt( + priv_cert.pkey.as_ref().unwrap(), + priv_cert.cert.as_ref().unwrap(), + ) + .expect("failed to decrypt cms"); + let decrypt_with_cert_check = String::from_utf8(decrypt_with_cert_check) + .expect("failed to create string from cms content"); + + let decrypt_without_cert_check = decrypt + .decrypt_without_cert_check(priv_cert.pkey.as_ref().unwrap()) + .expect("failed to decrypt cms"); + let decrypt_without_cert_check = String::from_utf8(decrypt_without_cert_check) + .expect("failed to create string from cms content"); + + assert_eq!(input, decrypt_with_cert_check); + assert_eq!(input, decrypt_without_cert_check); + } + + // decrypt cms message using private key cert (PEM) + { + let encrypted_pem = encrypt.to_pem().expect("failed to create pem from cms"); + let decrypt = + CmsContentInfo::from_pem(&encrypted_pem).expect("failed read cms from pem"); + + let decrypt_with_cert_check = decrypt + .decrypt( + priv_cert.pkey.as_ref().unwrap(), + priv_cert.cert.as_ref().unwrap(), + ) + .expect("failed to decrypt cms"); + let decrypt_with_cert_check = String::from_utf8(decrypt_with_cert_check) + .expect("failed to create string from cms content"); + + let decrypt_without_cert_check = decrypt + .decrypt_without_cert_check(priv_cert.pkey.as_ref().unwrap()) + .expect("failed to decrypt cms"); + let decrypt_without_cert_check = String::from_utf8(decrypt_without_cert_check) + .expect("failed to create string from cms content"); + + assert_eq!(input, decrypt_with_cert_check); + assert_eq!(input, decrypt_without_cert_check); + } + } + + fn cms_sign_verify_generic_helper(is_detached: bool) { + // load cert with private key + let cert_bytes = include_bytes!("../test/cert.pem"); + let cert = X509::from_pem(cert_bytes).expect("failed to load cert.pem"); + + let key_bytes = include_bytes!("../test/key.pem"); + let key = PKey::private_key_from_pem(key_bytes).expect("failed to load key.pem"); + + let root_bytes = include_bytes!("../test/root-ca.pem"); + let root = X509::from_pem(root_bytes).expect("failed to load root-ca.pem"); + + // sign cms message using public key cert + let data = b"Hello world!"; + + let (opt, ext_data): (CMSOptions, Option<&[u8]>) = if is_detached { + (CMSOptions::DETACHED | CMSOptions::BINARY, Some(data)) + } else { + (CMSOptions::empty(), None) + }; + + let mut cms = CmsContentInfo::sign(Some(&cert), Some(&key), None, Some(data), opt) + .expect("failed to CMS sign a message"); + + // check CMS signature length + let pem_cms = cms + .to_pem() + .expect("failed to pack CmsContentInfo into PEM"); + assert!(!pem_cms.is_empty()); + + // verify CMS signature + let mut builder = X509StoreBuilder::new().expect("failed to create X509StoreBuilder"); + builder + .add_cert(root) + .expect("failed to add root-ca into X509StoreBuilder"); + let store: X509Store = builder.build(); + let mut out_data: Vec = Vec::new(); + let res = cms.verify( + None, + Some(&store), + ext_data, + Some(&mut out_data), + CMSOptions::empty(), + ); + + // check verification result - valid signature + res.unwrap(); + assert_eq!(data.to_vec(), out_data); + } + + #[test] + fn cms_sign_verify_ok() { + cms_sign_verify_generic_helper(false); + } + + #[test] + fn cms_sign_verify_detached_ok() { + cms_sign_verify_generic_helper(true); + } + + #[test] + fn cms_sign_verify_error() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + + // load cert with private key + let priv_cert_bytes = include_bytes!("../test/cms.p12"); + let priv_cert = Pkcs12::from_der(priv_cert_bytes).expect("failed to load priv cert"); + let priv_cert = priv_cert + .parse2("mypass") + .expect("failed to parse priv cert"); + + // sign cms message using public key cert + let data = b"Hello world!"; + let mut cms = CmsContentInfo::sign( + Some(&priv_cert.cert.unwrap()), + Some(&priv_cert.pkey.unwrap()), + None, + Some(data), + CMSOptions::empty(), + ) + .expect("failed to CMS sign a message"); + + // check CMS signature length + let pem_cms = cms + .to_pem() + .expect("failed to pack CmsContentInfo into PEM"); + assert!(!pem_cms.is_empty()); + + let empty_store = X509StoreBuilder::new() + .expect("failed to create X509StoreBuilder") + .build(); + + // verify CMS signature + let res = cms.verify( + None, + Some(&empty_store), + Some(data), + None, + CMSOptions::empty(), + ); + + // check verification result - this is an invalid signature + // defined in openssl crypto/cms/cms.h + const CMS_R_CERTIFICATE_VERIFY_ERROR: i32 = 100; + match res { + Err(es) => { + let error_array = es.errors(); + assert_eq!(1, error_array.len()); + let code = error_array[0].code(); + assert_eq!(ffi::ERR_GET_REASON(code), CMS_R_CERTIFICATE_VERIFY_ERROR); + } + _ => panic!("expected CMS verification error, got Ok()"), + } + } } diff --git a/openssl/src/conf.rs b/openssl/src/conf.rs index fb5d4f3..715519c 100644 --- a/openssl/src/conf.rs +++ b/openssl/src/conf.rs @@ -1,32 +1,4 @@ //! Interface for processing OpenSSL configuration files. -use ffi; - -use cvt_p; -use error::ErrorStack; - -pub struct ConfMethod(*mut ffi::CONF_METHOD); - -impl ConfMethod { - /// Retrieve handle to the default OpenSSL configuration file processing function. - 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. - 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; @@ -36,17 +8,58 @@ foreign_type_and_impl_send_sync! { pub struct ConfRef; } -impl Conf { - /// Create a configuration parser. - /// - /// # Examples - /// - /// ``` - /// use openssl::conf::{Conf, ConfMethod}; - /// - /// let conf = Conf::new(ConfMethod::default()); - /// ``` - pub fn new(method: ConfMethod) -> Result { - unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) } +#[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)] + #[allow(clippy::should_implement_trait)] + 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 { + unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) } + } } } +#[cfg(not(boringssl))] +pub use methods::*; diff --git a/openssl/src/crypto.rs b/openssl/src/crypto.rs deleted file mode 100644 index 519135c..0000000 --- a/openssl/src/crypto.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![doc(hidden)] -#![deprecated(since = "0.9.20")] -use string::OpensslString; - -#[deprecated(note = "renamed to OpensslString", since = "0.9.7")] -pub type CryptoString = OpensslString; diff --git a/openssl/src/derive.rs b/openssl/src/derive.rs new file mode 100644 index 0000000..5d422f6 --- /dev/null +++ b/openssl/src/derive.rs @@ -0,0 +1,182 @@ +//! Shared secret derivation. +//! +//! # Example +//! +//! The following example implements [ECDH] using `NIST P-384` keys: +//! +//! ``` +//! # fn main() -> Result<(), Box> { +//! # use std::convert::TryInto; +//! use openssl::bn::BigNumContext; +//! use openssl::pkey::PKey; +//! use openssl::derive::Deriver; +//! use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm}; +//! use openssl::nid::Nid; +//! +//! let group = EcGroup::from_curve_name(Nid::SECP384R1)?; +//! +//! let first: PKey<_> = EcKey::generate(&group)?.try_into()?; +//! +//! // second party generates an ephemeral key and derives +//! // a shared secret using first party's public key +//! let shared_key = EcKey::generate(&group)?; +//! // shared_public is sent to first party +//! let mut ctx = BigNumContext::new()?; +//! let shared_public = shared_key.public_key().to_bytes( +//! &group, +//! PointConversionForm::COMPRESSED, +//! &mut ctx, +//! )?; +//! +//! let shared_key: PKey<_> = shared_key.try_into()?; +//! let mut deriver = Deriver::new(&shared_key)?; +//! deriver.set_peer(&first)?; +//! // secret can be used e.g. as a symmetric encryption key +//! let secret = deriver.derive_to_vec()?; +//! # drop(deriver); +//! +//! // first party derives the same shared secret using +//! // shared_public +//! let point = EcPoint::from_bytes(&group, &shared_public, &mut ctx)?; +//! let recipient_key: PKey<_> = EcKey::from_public_key(&group, &point)?.try_into()?; +//! let mut deriver = Deriver::new(&first)?; +//! deriver.set_peer(&recipient_key)?; +//! let first_secret = deriver.derive_to_vec()?; +//! +//! assert_eq!(secret, first_secret); +//! # Ok(()) } +//! ``` +//! +//! [ECDH]: https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman + +use foreign_types::ForeignTypeRef; +use std::marker::PhantomData; +use std::ptr; + +use crate::error::ErrorStack; +use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; +use crate::{cvt, cvt_p}; + +/// A type used to derive a shared secret between two keys. +pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>); + +unsafe impl<'a> Sync for Deriver<'a> {} +unsafe impl<'a> Send for Deriver<'a> {} + +#[allow(clippy::len_without_is_empty)] +impl<'a> Deriver<'a> { + /// Creates a new `Deriver` using the provided private key. + /// + /// This corresponds to [`EVP_PKEY_derive_init`]. + /// + /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html + pub fn new(key: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + unsafe { + cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut())) + .map(|p| Deriver(p, PhantomData)) + .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx)) + } + } + + /// Sets the peer key used for secret derivation. + /// + /// This corresponds to [`EVP_PKEY_derive_set_peer`]: + /// + /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html + pub fn set_peer(&mut self, key: &'a PKeyRef) -> Result<(), ErrorStack> + where + T: HasPublic, + { + unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) } + } + + /// Returns the size of the shared secret. + /// + /// It can be used to size the buffer passed to [`Deriver::derive`]. + /// + /// This corresponds to [`EVP_PKEY_derive`]. + /// + /// [`Deriver::derive`]: #method.derive + /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html + pub fn len(&mut self) -> Result { + unsafe { + let mut len = 0; + cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len) + } + } + + /// Derives a shared secret between the two keys, writing it into the buffer. + /// + /// Returns the number of bytes written. + /// + /// This corresponds to [`EVP_PKEY_derive`]. + /// + /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html + pub fn derive(&mut self, buf: &mut [u8]) -> Result { + let mut len = buf.len(); + unsafe { + cvt(ffi::EVP_PKEY_derive( + self.0, + buf.as_mut_ptr() as *mut _, + &mut len, + )) + .map(|_| len) + } + } + + /// A convenience function which derives a shared secret and returns it in a new buffer. + /// + /// This simply wraps [`Deriver::len`] and [`Deriver::derive`]. + /// + /// [`Deriver::len`]: #method.len + /// [`Deriver::derive`]: #method.derive + pub fn derive_to_vec(&mut self) -> Result, ErrorStack> { + let len = self.len()?; + let mut buf = vec![0; len]; + let len = self.derive(&mut buf)?; + buf.truncate(len); + Ok(buf) + } +} + +impl<'a> Drop for Deriver<'a> { + fn drop(&mut self) { + unsafe { + ffi::EVP_PKEY_CTX_free(self.0); + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + use crate::ec::{EcGroup, EcKey}; + use crate::nid::Nid; + use crate::pkey::PKey; + + #[test] + fn derive_without_peer() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + let mut deriver = Deriver::new(&pkey).unwrap(); + deriver.derive_to_vec().unwrap_err(); + } + + #[test] + fn test_ec_key_derive() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let ec_key2 = EcKey::generate(&group).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); + let mut deriver = Deriver::new(&pkey).unwrap(); + deriver.set_peer(&pkey2).unwrap(); + let shared = deriver.derive_to_vec().unwrap(); + assert!(!shared.is_empty()); + } +} diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 50d9da7..e781543 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -1,108 +1,315 @@ -use error::ErrorStack; -use ffi; -use foreign_types::ForeignTypeRef; +//! Diffie-Hellman key agreement. + +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef}; use std::mem; use std::ptr; -use {cvt, cvt_p}; -use bn::BigNum; +use crate::bn::{BigNum, BigNumRef}; +use crate::error::ErrorStack; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private}; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; -foreign_type_and_impl_send_sync! { +generic_foreign_type_and_impl_send_sync! { type CType = ffi::DH; fn drop = ffi::DH_free; - pub struct Dh; + pub struct Dh; - pub struct DhRef; + pub struct DhRef; } -impl DhRef { - to_pem!(ffi::PEM_write_bio_DHparams); - to_der!(ffi::i2d_DHparams); +impl DhRef +where + T: HasParams, +{ + to_pem! { + /// Serializes the parameters into a PEM-encoded PKCS#3 DHparameter structure. + /// + /// The output will have a header of `-----BEGIN DH PARAMETERS-----`. + #[corresponds(PEM_write_bio_DHparams)] + params_to_pem, + ffi::PEM_write_bio_DHparams + } + + to_der! { + /// Serializes the parameters into a DER-encoded PKCS#3 DHparameter structure. + #[corresponds(i2d_DHparams)] + params_to_der, + ffi::i2d_DHparams + } } -impl Dh { - pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result { +impl Dh { + pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result, ErrorStack> { + Self::from_pqg(p, Some(q), g) + } + + /// Creates a DH instance based upon the given primes and generator params. + #[corresponds(DH_set0_pqg)] + pub fn from_pqg( + prime_p: BigNum, + prime_q: Option, + generator: BigNum, + ) -> Result, ErrorStack> { unsafe { - let dh = Dh(cvt_p(ffi::DH_new())?); - cvt(compat::DH_set0_pqg( + let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); + cvt(DH_set0_pqg( dh.0, - p.as_ptr(), - q.as_ptr(), - g.as_ptr(), + prime_p.as_ptr(), + prime_q.as_ref().map_or(ptr::null_mut(), |q| q.as_ptr()), + generator.as_ptr(), ))?; - mem::forget((p, g, q)); + mem::forget((prime_p, prime_q, generator)); Ok(dh) } } - from_pem!(Dh, ffi::PEM_read_bio_DHparams); - from_der!(Dh, ffi::d2i_DHparams); + /// Sets the private key on the DH object and recomputes the public key. + pub fn set_private_key(self, priv_key: BigNum) -> Result, ErrorStack> { + unsafe { + let dh_ptr = self.0; + cvt(DH_set0_key(dh_ptr, ptr::null_mut(), priv_key.as_ptr()))?; + mem::forget(priv_key); + + cvt(ffi::DH_generate_key(dh_ptr))?; + mem::forget(self); + Ok(Dh::from_ptr(dh_ptr)) + } + } + + /// Generates DH params based on the given `prime_len` and a fixed `generator` value. + #[corresponds(DH_generate_parameters_ex)] + pub fn generate_params(prime_len: u32, generator: u32) -> Result, ErrorStack> { + unsafe { + let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); + cvt(ffi::DH_generate_parameters_ex( + dh.0, + prime_len as i32, + generator as i32, + ptr::null_mut(), + ))?; + Ok(dh) + } + } + + /// Generates a public and a private key based on the DH params. + #[corresponds(DH_generate_key)] + pub fn generate_key(self) -> Result, ErrorStack> { + unsafe { + let dh_ptr = self.0; + cvt(ffi::DH_generate_key(dh_ptr))?; + mem::forget(self); + Ok(Dh::from_ptr(dh_ptr)) + } + } + + from_pem! { + /// Deserializes a PEM-encoded PKCS#3 DHpararameters structure. + /// + /// The input should have a header of `-----BEGIN DH PARAMETERS-----`. + #[corresponds(PEM_read_bio_DHparams)] + params_from_pem, + Dh, + ffi::PEM_read_bio_DHparams + } + + from_der! { + /// Deserializes a DER-encoded PKCS#3 DHparameters structure. + #[corresponds(d2i_DHparams)] + params_from_der, + Dh, + ffi::d2i_DHparams + } - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - pub fn get_1024_160() -> Result { + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(DH_get_1024_160)] + #[cfg(any(ossl102, ossl110))] + pub fn get_1024_160() -> Result, ErrorStack> { unsafe { ffi::init(); - cvt_p(ffi::DH_get_1024_160()).map(Dh) + cvt_p(ffi::DH_get_1024_160()).map(|p| Dh::from_ptr(p)) } } - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - pub fn get_2048_224() -> Result { + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(DH_get_2048_224)] + #[cfg(any(ossl102, ossl110))] + pub fn get_2048_224() -> Result, ErrorStack> { unsafe { ffi::init(); - cvt_p(ffi::DH_get_2048_224()).map(Dh) + cvt_p(ffi::DH_get_2048_224()).map(|p| Dh::from_ptr(p)) } } - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - pub fn get_2048_256() -> Result { + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(DH_get_2048_256)] + #[cfg(any(ossl102, ossl110))] + pub fn get_2048_256() -> Result, ErrorStack> { unsafe { ffi::init(); - cvt_p(ffi::DH_get_2048_256()).map(Dh) + cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) + } + } +} + +impl Dh +where + T: HasParams, +{ + /// Returns the prime `p` from the DH instance. + #[corresponds(DH_get0_pqg)] + pub fn prime_p(&self) -> &BigNumRef { + let mut p = ptr::null(); + unsafe { + DH_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); + BigNumRef::from_ptr(p as *mut _) + } + } + + /// Returns the prime `q` from the DH instance. + #[corresponds(DH_get0_pqg)] + pub fn prime_q(&self) -> Option<&BigNumRef> { + let mut q = ptr::null(); + unsafe { + DH_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); + if q.is_null() { + None + } else { + Some(BigNumRef::from_ptr(q as *mut _)) + } + } + } + + /// Returns the generator from the DH instance. + #[corresponds(DH_get0_pqg)] + pub fn generator(&self) -> &BigNumRef { + let mut g = ptr::null(); + unsafe { + DH_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); + BigNumRef::from_ptr(g as *mut _) } } } -#[cfg(ossl110)] -mod compat { - pub use ffi::DH_set0_pqg; +impl DhRef +where + T: HasPublic, +{ + /// Returns the public key from the DH instance. + #[corresponds(DH_get0_key)] + pub fn public_key(&self) -> &BigNumRef { + let mut pub_key = ptr::null(); + unsafe { + DH_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); + BigNumRef::from_ptr(pub_key as *mut _) + } + } } -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use ffi; - use libc::c_int; - - pub unsafe fn DH_set0_pqg( - dh: *mut ffi::DH, - p: *mut ffi::BIGNUM, - q: *mut ffi::BIGNUM, - g: *mut ffi::BIGNUM, - ) -> c_int { - (*dh).p = p; - (*dh).q = q; - (*dh).g = g; - 1 +impl DhRef +where + T: HasPrivate, +{ + /// Computes a shared secret from the own private key and the given `public_key`. + #[corresponds(DH_compute_key)] + pub fn compute_key(&self, public_key: &BigNumRef) -> Result, ErrorStack> { + unsafe { + let key_len = ffi::DH_size(self.as_ptr()); + let mut key = vec![0u8; key_len as usize]; + cvt(ffi::DH_compute_key( + key.as_mut_ptr(), + public_key.as_ptr(), + self.as_ptr(), + ))?; + Ok(key) + } + } + + /// Returns the private key from the DH instance. + #[corresponds(DH_get0_key)] + pub fn private_key(&self) -> &BigNumRef { + let mut priv_key = ptr::null(); + unsafe { + DH_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); + BigNumRef::from_ptr(priv_key as *mut _) + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl270, boringssl))] { + use ffi::{DH_set0_pqg, DH_get0_pqg, DH_get0_key, DH_set0_key}; + } else { + #[allow(bad_style)] + unsafe fn DH_set0_pqg( + dh: *mut ffi::DH, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM, + ) -> ::libc::c_int { + (*dh).p = p; + (*dh).q = q; + (*dh).g = g; + 1 + } + + #[allow(bad_style)] + unsafe fn DH_get0_pqg( + dh: *mut ffi::DH, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + g: *mut *const ffi::BIGNUM, + ) { + if !p.is_null() { + *p = (*dh).p; + } + if !q.is_null() { + *q = (*dh).q; + } + if !g.is_null() { + *g = (*dh).g; + } + } + + #[allow(bad_style)] + unsafe fn DH_set0_key( + dh: *mut ffi::DH, + pub_key: *mut ffi::BIGNUM, + priv_key: *mut ffi::BIGNUM, + ) -> ::libc::c_int { + (*dh).pub_key = pub_key; + (*dh).priv_key = priv_key; + 1 + } + + #[allow(bad_style)] + unsafe fn DH_get0_key( + dh: *mut ffi::DH, + pub_key: *mut *const ffi::BIGNUM, + priv_key: *mut *const ffi::BIGNUM, + ) { + if !pub_key.is_null() { + *pub_key = (*dh).pub_key; + } + if !priv_key.is_null() { + *priv_key = (*dh).priv_key; + } + } } } #[cfg(test)] mod tests { - use dh::Dh; - use bn::BigNum; - use ssl::{SslMethod, SslContext}; + use crate::bn::BigNum; + use crate::dh::Dh; + use crate::ssl::{SslContext, SslMethod}; #[test] - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] + #[cfg(ossl102)] fn test_dh_rfc5114() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let dh1 = Dh::get_1024_160().unwrap(); - ctx.set_tmp_dh(&dh1).unwrap(); let dh2 = Dh::get_2048_224().unwrap(); ctx.set_tmp_dh(&dh2).unwrap(); let dh3 = Dh::get_2048_256().unwrap(); @@ -110,51 +317,100 @@ mod tests { } #[test] - fn test_dh() { + fn test_dh_params() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let p = BigNum::from_hex_str( - "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\ - E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\ - 6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\ - 2E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF1230\ - 7F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9\ - A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251C\ - CACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE\ - 621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D227\ - 6E11715F693877FAD7EF09CADB094AE91E1A1597", - ).unwrap(); - let g = BigNum::from_hex_str( - "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0\ - BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773\ - BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2D\ - DF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428E\ - BC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BF\ - FE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7\ - D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92\ - B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148\ - D47954515E2327CFEF98C582664B4C0F6CC41659", + let prime_p = BigNum::from_hex_str( + "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\ + 4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\ + 58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\ + 3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\ + 140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\ + C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", ).unwrap(); - let q = BigNum::from_hex_str( - "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F\ - 5FBD3", + let prime_q = BigNum::from_hex_str( + "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\ + 4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\ + 57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\ + 045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\ + 052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\ + B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", ).unwrap(); - let dh = Dh::from_params(p, g, q).unwrap(); + let generator = BigNum::from_hex_str( + "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", + ) + .unwrap(); + let dh = Dh::from_params( + prime_p.to_owned().unwrap(), + generator.to_owned().unwrap(), + prime_q.to_owned().unwrap(), + ) + .unwrap(); ctx.set_tmp_dh(&dh).unwrap(); + + assert_eq!(dh.prime_p(), &prime_p); + assert_eq!(dh.prime_q().unwrap(), &prime_q); + assert_eq!(dh.generator(), &generator); + } + + #[test] + #[cfg(ossl102)] + fn test_dh_stored_restored() { + let dh1 = Dh::get_2048_256().unwrap(); + let key1 = dh1.generate_key().unwrap(); + + let dh2 = Dh::get_2048_256().unwrap(); + let key2 = dh2 + .set_private_key(key1.private_key().to_owned().unwrap()) + .unwrap(); + + assert_eq!(key1.public_key(), key2.public_key()); + assert_eq!(key1.private_key(), key2.private_key()); } #[test] fn test_dh_from_pem() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); let params = include_bytes!("../test/dhparams.pem"); - let dh = Dh::from_pem(params).unwrap(); + let dh = Dh::params_from_pem(params).unwrap(); ctx.set_tmp_dh(&dh).unwrap(); } #[test] fn test_dh_from_der() { let params = include_bytes!("../test/dhparams.pem"); - let dh = Dh::from_pem(params).unwrap(); - let der = dh.to_der().unwrap(); - Dh::from_der(&der).unwrap(); + let dh = Dh::params_from_pem(params).unwrap(); + let der = dh.params_to_der().unwrap(); + Dh::params_from_der(&der).unwrap(); + } + + #[test] + #[cfg(ossl102)] + fn test_dh_generate_key_compute_key() { + let dh1 = Dh::get_2048_224().unwrap().generate_key().unwrap(); + let dh2 = Dh::get_2048_224().unwrap().generate_key().unwrap(); + + let shared_a = dh1.compute_key(dh2.public_key()).unwrap(); + let shared_b = dh2.compute_key(dh1.public_key()).unwrap(); + + assert_eq!(shared_a, shared_b); + } + + #[test] + fn test_dh_generate_params_generate_key_compute_key() { + let dh_params1 = Dh::generate_params(512, 2).unwrap(); + let dh_params2 = Dh::from_pqg( + dh_params1.prime_p().to_owned().unwrap(), + None, + dh_params1.generator().to_owned().unwrap(), + ) + .unwrap(); + + let dh1 = dh_params1.generate_key().unwrap(); + let dh2 = dh_params2.generate_key().unwrap(); + + let shared_a = dh1.compute_key(dh2.public_key()).unwrap(); + let shared_b = dh2.compute_key(dh1.public_key()).unwrap(); + + assert_eq!(shared_a, shared_b); } } diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index c687531..c550f65 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -1,23 +1,25 @@ //! Digital Signatures //! //! DSA ensures a message originated from a known sender, and was not modified. -//! DSA uses asymetrical keys and an algorithm to output a signature of the message +//! DSA uses asymmetrical keys and an algorithm to output a signature of the message //! using the private key that can be validated with the public key but not be generated //! without the private key. -use ffi; -use foreign_types::ForeignTypeRef; -use libc::{c_int, c_char, c_void}; +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; use std::fmt; +use std::mem; use std::ptr; -use {cvt, cvt_p}; -use bio::MemBioSlice; -use bn::BigNumRef; -use error::ErrorStack; -use util::{CallbackState, invoke_passwd_cb_old}; +use crate::bn::{BigNum, BigNumRef}; +use crate::error::ErrorStack; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; +use crate::util::ForeignTypeRefExt; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; -foreign_type_and_impl_send_sync! { +generic_foreign_type_and_impl_send_sync! { type CType = ffi::DSA; fn drop = ffi::DSA_free; @@ -30,19 +32,21 @@ foreign_type_and_impl_send_sync! { /// * `q`: DSA sub-prime parameter /// * `g`: DSA base parameter /// - /// These values are used to calculate a pair of asymetrical keys used for + /// These values are used to calculate a pair of asymmetrical keys used for /// signing. /// /// OpenSSL documentation at [`DSA_new`] /// - /// [`DSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_new.html + /// [`DSA_new`]: https://www.openssl.org/docs/manmaster/crypto/DSA_new.html /// /// # Examples /// /// ``` /// use openssl::dsa::Dsa; /// use openssl::error::ErrorStack; - /// fn create_dsa() -> Result< Dsa, ErrorStack > { + /// use openssl::pkey::Private; + /// + /// fn create_dsa() -> Result, ErrorStack> { /// let sign = Dsa::generate(2048)?; /// Ok(sign) /// } @@ -50,101 +54,152 @@ foreign_type_and_impl_send_sync! { /// # create_dsa(); /// # } /// ``` - pub struct Dsa; + pub struct Dsa; /// Reference to [`Dsa`]. /// /// [`Dsa`]: struct.Dsa.html - pub struct DsaRef; + pub struct DsaRef; } -impl DsaRef { - private_key_to_pem!(ffi::PEM_write_bio_DSAPrivateKey); - public_key_to_pem!(ffi::PEM_write_bio_DSA_PUBKEY); +impl Clone for Dsa { + fn clone(&self) -> Dsa { + (**self).to_owned() + } +} - private_key_to_der!(ffi::i2d_DSAPrivateKey); - public_key_to_der!(ffi::i2d_DSAPublicKey); +impl ToOwned for DsaRef { + type Owned = Dsa; - /// Returns the maximum size of the signature output by `self` in bytes. Returns - /// None if the keys are uninitialized. - /// - /// OpenSSL documentation at [`DSA_size`] - /// - /// [`DSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_size.html - // FIXME should return u32 - pub fn size(&self) -> Option { - if self.q().is_some() { - unsafe { Some(ffi::DSA_size(self.as_ptr()) as u32) } - } else { - None + fn to_owned(&self) -> Dsa { + unsafe { + ffi::DSA_up_ref(self.as_ptr()); + Dsa::from_ptr(self.as_ptr()) } } +} - /// Returns the DSA prime parameter of `self`. - pub fn p(&self) -> Option<&BigNumRef> { +impl DsaRef +where + T: HasPublic, +{ + to_pem! { + /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_write_bio_DSA_PUBKEY)] + public_key_to_pem, + ffi::PEM_write_bio_DSA_PUBKEY + } + + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + #[corresponds(i2d_DSA_PUBKEY)] + public_key_to_der, + ffi::i2d_DSA_PUBKEY + } + + /// Returns a reference to the public key component of `self`. + #[corresponds(DSA_get0_key)] + pub fn pub_key(&self) -> &BigNumRef { unsafe { - let p = compat::pqg(self.as_ptr())[0]; - if p.is_null() { - None - } else { - Some(BigNumRef::from_ptr(p as *mut _)) - } + let mut pub_key = ptr::null(); + DSA_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); + BigNumRef::from_const_ptr(pub_key) } } +} - /// Returns the DSA sub-prime parameter of `self`. - pub fn q(&self) -> Option<&BigNumRef> { +impl DsaRef +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded DSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_DSAPrivateKey)] + private_key_to_pem, + /// Serializes the private key to a PEM-encoded encrypted DSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_DSAPrivateKey)] + private_key_to_pem_passphrase, + ffi::PEM_write_bio_DSAPrivateKey + } + + /// Returns a reference to the private key component of `self`. + #[corresponds(DSA_get0_key)] + pub fn priv_key(&self) -> &BigNumRef { unsafe { - let q = compat::pqg(self.as_ptr())[1]; - if q.is_null() { - None - } else { - Some(BigNumRef::from_ptr(q as *mut _)) - } + let mut priv_key = ptr::null(); + DSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); + BigNumRef::from_const_ptr(priv_key) } } +} - /// Returns the DSA base parameter of `self`. - pub fn g(&self) -> Option<&BigNumRef> { +impl DsaRef +where + T: HasParams, +{ + /// Returns the maximum size of the signature output by `self` in bytes. + #[corresponds(DSA_size)] + pub fn size(&self) -> u32 { + unsafe { ffi::DSA_size(self.as_ptr()) as u32 } + } + + /// Returns the DSA prime parameter of `self`. + #[corresponds(DSA_get0_pqg)] + pub fn p(&self) -> &BigNumRef { unsafe { - let g = compat::pqg(self.as_ptr())[2]; - if g.is_null() { - None - } else { - Some(BigNumRef::from_ptr(g as *mut _)) - } + let mut p = ptr::null(); + DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); + BigNumRef::from_const_ptr(p) } } - /// Returns whether the DSA includes a public key, used to confirm the authenticity - /// of the message. - pub fn has_public_key(&self) -> bool { - unsafe { !compat::keys(self.as_ptr())[0].is_null() } + /// Returns the DSA sub-prime parameter of `self`. + #[corresponds(DSA_get0_pqg)] + pub fn q(&self) -> &BigNumRef { + unsafe { + let mut q = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); + BigNumRef::from_const_ptr(q) + } } - /// Returns whether the DSA includes a private key, used to prove the authenticity - /// of a message. - pub fn has_private_key(&self) -> bool { - unsafe { !compat::keys(self.as_ptr())[1].is_null() } + /// Returns the DSA base parameter of `self`. + #[corresponds(DSA_get0_pqg)] + pub fn g(&self) -> &BigNumRef { + unsafe { + let mut g = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); + BigNumRef::from_const_ptr(g) + } } } +#[cfg(boringssl)] +type BitType = libc::c_uint; +#[cfg(not(boringssl))] +type BitType = c_int; -impl Dsa { +impl Dsa { /// Generate a DSA key pair. /// /// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values. /// These values are used to generate the key pair with [`DSA_generate_key`]. /// - /// The `bits` parameter coresponds to the length of the prime `p`. + /// The `bits` parameter corresponds to the length of the prime `p`. /// - /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_parameters_ex.html - /// [`DSA_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_key.html - pub fn generate(bits: u32) -> Result { + /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/manmaster/crypto/DSA_generate_parameters_ex.html + /// [`DSA_generate_key`]: https://www.openssl.org/docs/manmaster/crypto/DSA_generate_key.html + pub fn generate(bits: u32) -> Result, ErrorStack> { ffi::init(); unsafe { - let dsa = Dsa(cvt_p(ffi::DSA_new())?); + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); cvt(ffi::DSA_generate_parameters_ex( dsa.0, - bits as c_int, + bits as BitType, ptr::null(), 0, ptr::null_mut(), @@ -156,75 +211,302 @@ impl Dsa { } } - private_key_from_pem!(Dsa, ffi::PEM_read_bio_DSAPrivateKey); - private_key_from_der!(Dsa, ffi::d2i_DSAPrivateKey); - public_key_from_pem!(Dsa, ffi::PEM_read_bio_DSA_PUBKEY); - public_key_from_der!(Dsa, ffi::d2i_DSAPublicKey); - - #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] - pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result - where - F: FnOnce(&mut [c_char]) -> usize, - { + /// Create a DSA key pair with the given parameters + /// + /// `p`, `q` and `g` are the common parameters. + /// `priv_key` is the private component of the key pair. + /// `pub_key` is the public component of the key. Can be computed via `g^(priv_key) mod p` + pub fn from_private_components( + p: BigNum, + q: BigNum, + g: BigNum, + priv_key: BigNum, + pub_key: BigNum, + ) -> Result, ErrorStack> { ffi::init(); - let mut cb = CallbackState::new(pass_cb); - let mem_bio = MemBioSlice::new(buf)?; + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), priv_key.as_ptr()))?; + mem::forget((pub_key, priv_key)); + Ok(dsa) + } + } +} + +impl Dsa { + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_read_bio_DSA_PUBKEY)] + public_key_from_pem, + Dsa, + ffi::PEM_read_bio_DSA_PUBKEY + } + + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key. + #[corresponds(d2i_DSA_PUBKEY)] + public_key_from_der, + Dsa, + ffi::d2i_DSA_PUBKEY + } + /// Create a new DSA key with only public components. + /// + /// `p`, `q` and `g` are the common parameters. + /// `pub_key` is the public component of the key. + pub fn from_public_components( + p: BigNum, + q: BigNum, + g: BigNum, + pub_key: BigNum, + ) -> Result, ErrorStack> { + ffi::init(); unsafe { - let cb_ptr = &mut cb as *mut _ as *mut c_void; - let dsa = cvt_p(ffi::PEM_read_bio_DSAPrivateKey( - mem_bio.as_ptr(), - ptr::null_mut(), - Some(invoke_passwd_cb_old::), - cb_ptr, - ))?; - Ok(Dsa(dsa)) + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), ptr::null_mut()))?; + mem::forget(pub_key); + Ok(dsa) } } } -impl fmt::Debug for Dsa { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Dsa { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "DSA") } } -#[cfg(ossl110)] -mod compat { - use std::ptr; - use ffi::{self, BIGNUM, DSA}; +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; + } else { + #[allow(bad_style)] + unsafe fn DSA_get0_pqg( + d: *mut ffi::DSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + g: *mut *const ffi::BIGNUM) + { + if !p.is_null() { + *p = (*d).p; + } + if !q.is_null() { + *q = (*d).q; + } + if !g.is_null() { + *g = (*d).g; + } + } + + #[allow(bad_style)] + unsafe fn DSA_get0_key( + d: *mut ffi::DSA, + pub_key: *mut *const ffi::BIGNUM, + priv_key: *mut *const ffi::BIGNUM) + { + if !pub_key.is_null() { + *pub_key = (*d).pub_key; + } + if !priv_key.is_null() { + *priv_key = (*d).priv_key; + } + } + + #[allow(bad_style)] + unsafe fn DSA_set0_key( + d: *mut ffi::DSA, + pub_key: *mut ffi::BIGNUM, + priv_key: *mut ffi::BIGNUM) -> c_int + { + (*d).pub_key = pub_key; + (*d).priv_key = priv_key; + 1 + } - pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] { - let (mut p, mut q, mut g) = (ptr::null(), ptr::null(), ptr::null()); - ffi::DSA_get0_pqg(d, &mut p, &mut q, &mut g); - [p, q, g] + #[allow(bad_style)] + unsafe fn DSA_set0_pqg( + d: *mut ffi::DSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM) -> c_int + { + (*d).p = p; + (*d).q = q; + (*d).g = g; + 1 + } } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::DSA_SIG; + fn drop = ffi::DSA_SIG_free; - pub unsafe fn keys(d: *const DSA) -> [*const BIGNUM; 2] { - let (mut pub_key, mut priv_key) = (ptr::null(), ptr::null()); - ffi::DSA_get0_key(d, &mut pub_key, &mut priv_key); - [pub_key, priv_key] + /// 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 { + 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() } } -#[cfg(ossl10x)] -mod compat { - use ffi::{BIGNUM, DSA}; +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) + } + } - pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] { - [(*d).p, (*d).q, (*d).g] + /// 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 + } - pub unsafe fn keys(d: *const DSA) -> [*const BIGNUM; 2] { - [(*d).pub_key, (*d).priv_key] + #[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 symm::Cipher; - 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] pub fn test_generate() { @@ -232,30 +514,134 @@ mod test { } #[test] - pub fn test_password() { - let key = include_bytes!("../test/dsa-encrypted.pem"); - Dsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); + fn test_pubkey_generation() { + let dsa = Dsa::generate(1024).unwrap(); + let p = dsa.p(); + let g = dsa.g(); + let priv_key = dsa.priv_key(); + let pub_key = dsa.pub_key(); + let mut ctx = BigNumContext::new().unwrap(); + let mut calc = BigNum::new().unwrap(); + calc.mod_exp(g, priv_key, p, &mut ctx).unwrap(); + assert_eq!(&calc, pub_key) + } + + #[test] + fn test_priv_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let priv_key = BigNum::from_u32(15).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); + + let dsa = Dsa::from_private_components(p, q, g, priv_key, pub_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.priv_key(), &BigNum::from_u32(15).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); + } + + #[test] + fn test_pub_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); + + let dsa = Dsa::from_public_components(p, q, g, pub_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); + } + + #[test] + #[cfg(not(boringssl))] + fn test_signature() { + const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let dsa_ref = Dsa::generate(1024).unwrap(); + + let p = dsa_ref.p(); + let q = dsa_ref.q(); + let g = dsa_ref.g(); + + let pub_key = dsa_ref.pub_key(); + let priv_key = dsa_ref.priv_key(); + + let priv_key = Dsa::from_private_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(priv_key).unwrap(), + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); + let priv_key = PKey::from_dsa(priv_key).unwrap(); + + let pub_key = Dsa::from_public_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); + let pub_key = PKey::from_dsa(pub_key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); + signer.update(TEST_DATA).unwrap(); + + let signature = signer.sign_to_vec().unwrap(); + let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); + verifier.update(TEST_DATA).unwrap(); + assert!(verifier.verify(&signature[..]).unwrap()); + } + + #[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] - fn test_to_password() { + #[allow(clippy::redundant_clone)] + fn clone() { let key = Dsa::generate(2048).unwrap(); - let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") - .unwrap(); - Dsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); - assert!(Dsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); + drop(key.clone()); } #[test] - pub fn test_password_callback() { - let mut password_queried = false; - let key = include_bytes!("../test/dsa-encrypted.pem"); - Dsa::private_key_from_pem_callback(key, |password| { - password_queried = true; - password[..6].copy_from_slice(b"mypass"); - Ok(6) - }).unwrap(); - - assert!(password_queried); + 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/openssl/src/ec.rs index 97b095d..248ced3 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -1,83 +1,32 @@ //! Elliptic Curve //! -//! Cryptology relies on the difficulty of solving mathematical problems, such as the factor +//! Cryptography relies on the difficulty of solving mathematical problems, such as the factor //! of large integers composed of two large prime numbers and the discrete logarithm of a -//! random eliptic curve. This module provides low-level features of the latter. +//! random elliptic curve. This module provides low-level features of the latter. //! Elliptic Curve protocols can provide the same security with smaller keys. //! //! There are 2 forms of elliptic curves, `Fp` and `F2^m`. These curves use irreducible -//! trinomial or pentanomial . Being a generic interface to a wide range of algorithms, -//! the cuves are generally referenced by [`EcGroup`]. There are many built in groups +//! trinomial or pentanomial. Being a generic interface to a wide range of algorithms, +//! the curves are generally referenced by [`EcGroup`]. There are many built-in groups //! found in [`Nid`]. //! -//! OpenSSL Wiki explains the fields and curves in detail at [Eliptic Curve Cryptography]. +//! OpenSSL Wiki explains the fields and curves in detail at [Elliptic Curve Cryptography]. //! //! [`EcGroup`]: struct.EcGroup.html //! [`Nid`]: ../nid/struct.Nid.html -//! [Eliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography -//! -//! # Examples -//! -//! ``` -//! use openssl::ec::{EcGroup, EcPoint}; -//! use openssl::nid; -//! use openssl::error::ErrorStack; -//! fn get_ec_point() -> Result< EcPoint, ErrorStack > { -//! let group = EcGroup::from_curve_name(nid::SECP224R1)?; -//! let point = EcPoint::new(&group)?; -//! Ok(point) -//! } -//! # fn main() { -//! # let _ = get_ec_point(); -//! # } -//! ``` -use ffi; +//! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography use foreign_types::{ForeignType, ForeignTypeRef}; -use std::ptr; -use std::mem; use libc::c_int; +use std::fmt; +use std::ptr; -use {cvt, cvt_n, cvt_p, init}; -use bn::{BigNumRef, BigNumContextRef}; -use error::ErrorStack; -use nid::Nid; - -/// Compressed conversion from point value (Default) -pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); - -/// Uncompressed conversion from point value (Binary curve default) -pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); - -/// Performs both compressed and uncompressed conversions -pub const POINT_CONVERSION_HYBRID: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); - -/// Curve defined using polynomial parameters -/// -/// Most applications use a named EC_GROUP curve, however, support -/// is included to explicitly define the curve used to calculate keys -/// This information would need to be known by both endpoint to make communication -/// effective. -/// -/// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1. -/// Man page documents that 0 can be used in older versions. -/// -/// OpenSSL documentation at [`EC_GROUP`] -/// -/// [`EC_GROUP`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_seed_len.html -pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); - -/// Standard Curves -/// -/// Curves that make up the typical encryption use cases. The collection of curves -/// are well known but extensible. -/// -/// OpenSSL documentation at [`EC_GROUP`] -/// -/// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html -pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); +use crate::bn::{BigNum, BigNumContextRef, BigNumRef}; +use crate::error::ErrorStack; +use crate::nid::Nid; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; +use crate::util::ForeignTypeRefExt; +use crate::{cvt, cvt_n, cvt_p, init}; +use openssl_macros::corresponds; /// Compressed or Uncompressed conversion /// @@ -91,13 +40,53 @@ pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); #[derive(Copy, Clone)] pub struct PointConversionForm(ffi::point_conversion_form_t); +impl PointConversionForm { + /// Compressed conversion from point value. + pub const COMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); + + /// Uncompressed conversion from point value. + pub const UNCOMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); + + /// Performs both compressed and uncompressed conversions. + pub const HYBRID: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); +} + /// Named Curve or Explicit /// -/// This type acts as a boolean as to whether the EC_Group is named or -/// explicit. +/// This type acts as a boolean as to whether the `EcGroup` is named or explicit. #[derive(Copy, Clone)] pub struct Asn1Flag(c_int); +impl Asn1Flag { + /// Curve defined using polynomial parameters + /// + /// Most applications use a named EC_GROUP curve, however, support + /// is included to explicitly define the curve used to calculate keys + /// This information would need to be known by both endpoint to make communication + /// effective. + /// + /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1. + /// Man page documents that 0 can be used in older versions. + /// + /// OpenSSL documentation at [`EC_GROUP`] + /// + /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/crypto/EC_GROUP_get_seed_len.html + pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); + + /// Standard Curves + /// + /// Curves that make up the typical encryption use cases. The collection of curves + /// are well known but extensible. + /// + /// OpenSSL documentation at [`EC_GROUP`] + /// + /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html + pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); +} + foreign_type_and_impl_send_sync! { type CType = ffi::EC_GROUP; fn drop = ffi::EC_GROUP_free; @@ -114,7 +103,7 @@ foreign_type_and_impl_send_sync! { /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`. Binary /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`. Named curves have /// assured security. To prevent accidental vulnerabilities, they should - /// be prefered. + /// be preferred. /// /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations /// [`Nid`]: ../nid/index.html @@ -128,24 +117,50 @@ foreign_type_and_impl_send_sync! { impl EcGroup { /// Returns the group of a standard named curve. /// - /// OpenSSL documentation at [`EC_GROUP_new`]. + /// # Examples /// - /// [`EC_GROUP_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_new.html + /// ``` + /// # fn main() -> Result<(), Box> { + /// use openssl::nid::Nid; + /// use openssl::ec::{EcGroup, EcKey}; + /// + /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve + /// let group = EcGroup::from_curve_name(nid)?; + /// let key = EcKey::generate(&group)?; + /// # Ok(()) } + /// ``` + #[corresponds(EC_GROUP_new_by_curve_name)] pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); 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 { + 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 { /// Places the components of a curve over a prime field in the provided `BigNum`s. /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`. - /// - /// OpenSSL documentation available at [`EC_GROUP_get_curve_GFp`] - /// - /// [`EC_GROUP_get_curve_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GFp.html + #[corresponds(EC_GROUP_get_curve_GFp)] pub fn components_gfp( &self, p: &mut BigNumRef, @@ -160,7 +175,8 @@ impl EcGroupRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -170,11 +186,8 @@ impl EcGroupRef { /// In this form `p` relates to the irreducible polynomial. Each bit represents /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on /// using a trinomial or pentanomial. - /// - /// OpenSSL documentation at [`EC_GROUP_get_curve_GF2m`]. - /// - /// [`EC_GROUP_get_curve_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GF2m.html - #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + #[corresponds(EC_GROUP_get_curve_GF2m)] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))] pub fn components_gf2m( &self, p: &mut BigNumRef, @@ -189,24 +202,71 @@ impl EcGroupRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) + } + } + + /// Places the cofactor of the group in the provided `BigNum`. + #[corresponds(EC_GROUP_get_cofactor)] + pub fn cofactor( + &self, + cofactor: &mut BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_cofactor( + self.as_ptr(), + cofactor.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) } } /// Returns the degree of the curve. - /// - /// OpenSSL documentation at [`EC_GROUP_get_degree`] - /// - /// [`EC_GROUP_get_degree`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_degree.html + #[corresponds(EC_GROUP_get_degree)] pub fn degree(&self) -> u32 { unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } } + /// Returns the number of bits in the group order. + #[corresponds(EC_GROUP_order_bits)] + #[cfg(ossl110)] + pub fn order_bits(&self) -> u32 { + unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 } + } + + /// Returns the generator for the given curve as an [`EcPoint`]. + #[corresponds(EC_GROUP_get0_generator)] + pub fn generator(&self) -> &EcPointRef { + unsafe { + let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr()); + EcPointRef::from_const_ptr(ptr) + } + } + + /// 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`. - /// - /// OpenSSL documentation at [`EC_GROUP_get_order`] - /// - /// [`EC_GROUP_get_order`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_order.html + #[corresponds(EC_GROUP_get_order)] pub fn order( &self, order: &mut BigNumRef, @@ -217,7 +277,8 @@ impl EcGroupRef { self.as_ptr(), order.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -226,11 +287,23 @@ impl EcGroupRef { /// /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL /// 1.1.0. + #[corresponds(EC_GROUP_set_asn1_flag)] pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { unsafe { ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); } } + + /// Returns the name of the curve, if a name is associated. + #[corresponds(EC_GROUP_get_curve_name)] + pub fn curve_name(&self) -> Option { + let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }; + if nid > 0 { + Some(Nid::from_raw(nid)) + } else { + None + } + } } foreign_type_and_impl_send_sync! { @@ -238,23 +311,14 @@ foreign_type_and_impl_send_sync! { fn drop = ffi::EC_POINT_free; /// Represents a point on the curve - /// - /// OpenSSL documentation at [`EC_POINT_new`] - /// - /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html pub struct EcPoint; - /// Reference to [`EcPoint`] - /// - /// [`EcPoint`]: struct.EcPoint.html + /// A reference a borrowed [`EcPoint`]. pub struct EcPointRef; } impl EcPointRef { /// Computes `a + b`, storing the result in `self`. - /// - /// OpenSSL documentation at [`EC_POINT_add`] - /// - /// [`EC_POINT_add`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_add.html + #[corresponds(EC_POINT_add)] pub fn add( &mut self, group: &EcGroupRef, @@ -269,20 +333,19 @@ impl EcPointRef { a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Computes `q * m`, storing the result in `self`. - /// - /// OpenSSL documentation at [`EC_POINT_mul`] - /// - /// [`EC_POINT_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_mul.html + #[corresponds(EC_POINT_mul)] pub fn mul( &mut self, group: &EcGroupRef, q: &EcPointRef, m: &BigNumRef, + // FIXME should be &mut ctx: &BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { @@ -293,15 +356,18 @@ impl EcPointRef { q.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } - /// Computes `generator * n`, storing the result ing `self`. + /// Computes `generator * n`, storing the result in `self`. + #[corresponds(EC_POINT_mul)] pub fn mul_generator( &mut self, group: &EcGroupRef, n: &BigNumRef, + // FIXME should be &mut ctx: &BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { @@ -312,11 +378,13 @@ impl EcPointRef { ptr::null(), ptr::null(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Computes `generator * n + q * m`, storing the result in `self`. + #[corresponds(EC_POINT_mul)] pub fn mul_full( &mut self, group: &EcGroupRef, @@ -333,30 +401,27 @@ impl EcPointRef { q.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Inverts `self`. - /// - /// OpenSSL documentation at [`EC_POINT_invert`] - /// - /// [`EC_POINT_invert`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_invert.html + #[corresponds(EC_POINT_invert)] + // FIXME should be mutable pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_invert( group.as_ptr(), self.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Serializes the point to a binary representation. - /// - /// OpenSSL documentation at [`EC_POINT_point2oct`] - /// - /// [`EC_POINT_point2oct`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_point2oct.html + #[corresponds(EC_POINT_point2oct)] pub fn to_bytes( &self, group: &EcGroupRef, @@ -392,11 +457,14 @@ impl EcPointRef { } } + /// Creates a new point on the specified curve with the same value. + #[corresponds(EC_POINT_dup)] + pub fn to_owned(&self, group: &EcGroupRef) -> Result { + unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) } + } + /// Determines if this point is equal to another. - /// - /// OpenSSL doucmentation at [`EC_POINT_cmp`] - /// - /// [`EC_POINT_cmp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_cmp.html + #[corresponds(EC_POINT_cmp)] pub fn eq( &self, group: &EcGroupRef, @@ -414,12 +482,32 @@ impl EcPointRef { } } - /// Place affine coordinates of a curve over a prime field in the provided + /// Places affine coordinates of a curve over a prime field in the provided + /// `x` and `y` `BigNum`s. + #[corresponds(EC_POINT_get_affine_coordinates)] + #[cfg(ossl111)] + pub fn affine_coordinates( + &self, + group: &EcGroupRef, + x: &mut BigNumRef, + y: &mut BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_get_affine_coordinates( + group.as_ptr(), + self.as_ptr(), + x.as_ptr(), + y.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places affine coordinates of a curve over a prime field in the provided /// `x` and `y` `BigNum`s - /// - /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GFp`] - /// - /// [`EC_POINT_get_affine_coordinates_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GFp.html + #[corresponds(EC_POINT_get_affine_coordinates_GFp)] pub fn affine_coordinates_gfp( &self, group: &EcGroupRef, @@ -434,17 +522,37 @@ impl EcPointRef { x.as_ptr(), y.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } - /// Place affine coordinates of a curve over a binary field in the provided + /// Sets affine coordinates of a curve over a prime field using the provided /// `x` and `y` `BigNum`s - /// - /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GF2m`] - /// - /// [`EC_POINT_get_affine_coordinates_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GF2m.html - #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + #[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)] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))] pub fn affine_coordinates_gf2m( &self, group: &EcGroupRef, @@ -459,26 +567,47 @@ impl EcPointRef { x.as_ptr(), y.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) + } + } + + /// Checks if point is infinity + #[corresponds(EC_POINT_is_at_infinity)] + pub fn is_infinity(&self, group: &EcGroupRef) -> bool { + unsafe { + let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr()); + res == 1 + } + } + + /// Checks if point is on a given curve + #[corresponds(EC_POINT_is_on_curve)] + pub fn is_on_curve( + &self, + group: &EcGroupRef, + ctx: &mut BigNumContextRef, + ) -> Result { + unsafe { + let res = cvt_n(ffi::EC_POINT_is_on_curve( + group.as_ptr(), + self.as_ptr(), + ctx.as_ptr(), + ))?; + Ok(res == 1) } } } impl EcPoint { /// Creates a new point on the specified curve. - /// - /// OpenSSL documentation at [`EC_POINT_new`] - /// - /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html + #[corresponds(EC_POINT_new)] pub fn new(group: &EcGroupRef) -> Result { unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } } /// Creates point from a binary representation - /// - /// OpenSSL documentation at [`EC_POINT_oct2point`] - /// - /// [`EC_POINT_oct2point`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_oct2point.html + #[corresponds(EC_POINT_oct2point)] pub fn from_bytes( group: &EcGroupRef, buf: &[u8], @@ -498,386 +627,642 @@ impl EcPoint { } } -foreign_type_and_impl_send_sync! { +generic_foreign_type_and_impl_send_sync! { type CType = ffi::EC_KEY; fn drop = ffi::EC_KEY_free; - /// Public and optional Private key on the given curve - /// - /// OpenSSL documentation at [`EC_KEY_new`] - /// - /// [`EC_KEY_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html - pub struct EcKey; - /// Reference to [`EcKey`] - /// - /// [`EcKey`]: struct.EcKey.html - pub struct EcKeyRef; + /// Public and optional private key on the given curve. + pub struct EcKey; + /// A reference to an [`EcKey`]. + pub struct EcKeyRef; } -impl EcKeyRef { - private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); - private_key_to_der!(ffi::i2d_ECPrivateKey); +impl EcKeyRef +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded ECPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_ECPrivateKey)] + private_key_to_pem, + /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_ECPrivateKey)] + private_key_to_pem_passphrase, + ffi::PEM_write_bio_ECPrivateKey + } - /// Return [`EcGroup`] of the `EcKey` - /// - /// OpenSSL documentation at [`EC_KEY_get0_group`] - /// - /// [`EC_KEY_get0_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_group.html - pub fn group(&self) -> Option<&EcGroupRef> { + to_der! { + /// Serializes the private key into a DER-encoded ECPrivateKey structure. + #[corresponds(i2d_ECPrivateKey)] + private_key_to_der, + ffi::i2d_ECPrivateKey + } + + /// Returns the private key value. + #[corresponds(EC_KEY_get0_private_key)] + pub fn private_key(&self) -> &BigNumRef { unsafe { - let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(EcGroupRef::from_ptr(ptr as *mut _)) - } + let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); + BigNumRef::from_const_ptr(ptr) } } +} - /// Return [`EcPoint`] associated with the public key - /// - /// OpenSSL documentation at [`EC_KEY_get0_pubic_key`] - /// - /// [`EC_KEY_get0_pubic_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_public_key.html - pub fn public_key(&self) -> Option<&EcPointRef> { +impl EcKeyRef +where + T: HasPublic, +{ + /// Returns the public key. + #[corresponds(EC_KEY_get0_public_key)] + pub fn public_key(&self) -> &EcPointRef { unsafe { let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(EcPointRef::from_ptr(ptr as *mut _)) - } + EcPointRef::from_const_ptr(ptr) } } - /// Return [`EcPoint`] associated with the private key - /// - /// OpenSSL documentation at [`EC_KEY_get0_private_key`] - /// - /// [`EC_KEY_get0_private_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_private_key.html - pub fn private_key(&self) -> Option<&BigNumRef> { + to_pem! { + /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_write_bio_EC_PUBKEY)] + public_key_to_pem, + ffi::PEM_write_bio_EC_PUBKEY + } + + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + #[corresponds(i2d_EC_PUBKEY)] + public_key_to_der, + ffi::i2d_EC_PUBKEY + } +} + +impl EcKeyRef +where + T: HasParams, +{ + /// Returns the key's group. + #[corresponds(EC_KEY_get0_group)] + pub fn group(&self) -> &EcGroupRef { unsafe { - let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(BigNumRef::from_ptr(ptr as *mut _)) - } + let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); + EcGroupRef::from_const_ptr(ptr) } } /// Checks the key for validity. - /// - /// OpenSSL documenation at [`EC_KEY_check_key`] - /// - /// [`EC_KEY_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_check_key.html + #[corresponds(EC_KEY_check_key)] pub fn check_key(&self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } } +} + +impl ToOwned for EcKeyRef { + type Owned = EcKey; - /// Create a copy of the `EcKey` to allow modification - pub fn to_owned(&self) -> Result { - unsafe { cvt_p(ffi::EC_KEY_dup(self.as_ptr())).map(EcKey) } + fn to_owned(&self) -> EcKey { + unsafe { + let r = ffi::EC_KEY_up_ref(self.as_ptr()); + assert!(r == 1); + EcKey::from_ptr(self.as_ptr()) + } } } -impl EcKey { +impl EcKey { /// Constructs an `EcKey` corresponding to a known curve. /// /// It will not have an associated public or private key. This kind of key is primarily useful /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. - /// - /// OpenSSL documenation at [`EC_KEY_new_by_curve_name`] - /// - /// [`EC_KEY_new_by_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new_by_curve_name.html - pub fn from_curve_name(nid: Nid) -> Result { + #[corresponds(EC_KEY_new_by_curve_name)] + pub fn from_curve_name(nid: Nid) -> Result, ErrorStack> { unsafe { init(); - cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) + cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p)) } } - /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key. + /// Constructs an `EcKey` corresponding to a curve. + #[corresponds(EC_KEY_set_group)] + pub fn from_group(group: &EcGroupRef) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + } + } +} + +impl EcKey { + /// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`. /// - /// This will only have the associated public_key. + /// This will only have the associated `public_key`. /// /// # Example /// - /// ```no_run + /// ``` + /// # fn main() -> Result<(), Box> { /// use openssl::bn::BigNumContext; /// use openssl::ec::*; - /// use openssl::nid; + /// use openssl::nid::Nid; /// use openssl::pkey::PKey; /// - /// // get bytes from somewhere, i.e. this will not produce a valid key - /// let public_key: Vec = vec![]; + /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?; + /// let mut ctx = BigNumContext::new()?; + /// + /// // get bytes from somewhere + /// let public_key = // ... + /// # EcKey::generate(&group)?.public_key().to_bytes(&group, + /// # PointConversionForm::COMPRESSED, &mut ctx)?; /// /// // create an EcKey from the binary form of a EcPoint - /// let group = EcGroup::from_curve_name(nid::SECP256K1).unwrap(); - /// let mut ctx = BigNumContext::new().unwrap(); - /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap(); - /// let key = EcKey::from_public_key(&group, &point); + /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?; + /// let key = EcKey::from_public_key(&group, &point)?; + /// key.check_key()?; + /// # Ok(()) } /// ``` + #[corresponds(EC_KEY_set_public_key)] pub fn from_public_key( group: &EcGroupRef, public_key: &EcPointRef, - ) -> Result { - let mut builder = EcKeyBuilder::new()?; - builder.set_group(group)?; - builder.set_public_key(public_key)?; - Ok(builder.build()) + ) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_public_key( + key.as_ptr(), + public_key.as_ptr(), + )) + .map(|_| key) + }) + } } - /// Generates a new public/private key pair on the specified curve. - pub fn generate(group: &EcGroupRef) -> Result { - let mut builder = EcKeyBuilder::new()?; - builder.set_group(group)?; - builder.generate_key()?; - Ok(builder.build()) + /// Constructs a public key from its affine coordinates. + #[corresponds(EC_KEY_set_public_key_affine_coordinates)] + pub fn from_public_key_affine_coordinates( + group: &EcGroupRef, + x: &BigNumRef, + y: &BigNumRef, + ) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_public_key_affine_coordinates( + key.as_ptr(), + x.as_ptr(), + y.as_ptr(), + )) + .map(|_| key) + }) + } } - #[deprecated(since = "0.9.2", note = "use from_curve_name")] - pub fn new_by_curve_name(nid: Nid) -> Result { - EcKey::from_curve_name(nid) + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_read_bio_EC_PUBKEY)] + public_key_from_pem, + EcKey, + ffi::PEM_read_bio_EC_PUBKEY } - private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); - private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. + #[corresponds(d2i_EC_PUBKEY)] + public_key_from_der, + EcKey, + ffi::d2i_EC_PUBKEY + } } - -foreign_type_and_impl_send_sync! { - type CType = ffi::EC_KEY; - fn drop = ffi::EC_KEY_free; - - /// Builder pattern for key generation +impl EcKey { + /// Generates a new public/private key pair on the specified curve. /// - /// Returns a `EcKeyBuilder` to be consumed by `build` - pub struct EcKeyBuilder; - /// Reference to [`EcKeyBuilder`] + /// # Examples /// - /// [`EcKeyBuilder`]: struct.EcKeyBuilder.html - pub struct EcKeyBuilderRef; -} - -impl EcKeyBuilder { - /// Creates an empty `EcKeyBuilder` to be chained with additonal methods - pub fn new() -> Result { - unsafe { - init(); - cvt_p(ffi::EC_KEY_new()).map(EcKeyBuilder) - } - } - - /// Consume the `EcKeyBuilder` and return [`EcKey`] + /// ``` + /// # fn main() -> Result<(), Box> { + /// use openssl::bn::BigNumContext; + /// use openssl::nid::Nid; + /// use openssl::ec::{EcGroup, EcKey, PointConversionForm}; + /// + /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve + /// let group = EcGroup::from_curve_name(nid)?; + /// let key = EcKey::generate(&group)?; + /// + /// let mut ctx = BigNumContext::new()?; + /// + /// let public_key = &key.public_key().to_bytes( + /// &group, + /// PointConversionForm::COMPRESSED, + /// &mut ctx, + /// )?; + /// assert_eq!(public_key.len(), 33); + /// assert_ne!(public_key[0], 0x04); /// - /// [`EcKey`]: struct.EcKey.html - pub fn build(self) -> EcKey { + /// let private_key = key.private_key().to_vec(); + /// assert!(private_key.len() >= 31); + /// # Ok(()) } + /// ``` + #[corresponds(EC_KEY_generate_key)] + pub fn generate(group: &EcGroupRef) -> Result, ErrorStack> { unsafe { - let key = EcKey::from_ptr(self.as_ptr()); - mem::forget(self); - key + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key)) } } -} -impl EcKeyBuilderRef { - /// Set the [`EcGroup`] explicitly - /// - /// [`EcGroup`]: struct.EcGroup.html - pub fn set_group(&mut self, group: &EcGroupRef) -> Result<&mut EcKeyBuilderRef, ErrorStack> { - unsafe { cvt(ffi::EC_KEY_set_group(self.as_ptr(), group.as_ptr())).map(|_| self) } - } - - /// Set public key to given `EcPoint` - pub fn set_public_key( - &mut self, + /// Constructs an public/private key pair given a curve, a private key and a public key point. + #[corresponds(EC_KEY_set_private_key)] + pub fn from_private_components( + group: &EcGroupRef, + private_number: &BigNumRef, public_key: &EcPointRef, - ) -> Result<&mut EcKeyBuilderRef, ErrorStack> { + ) -> Result, ErrorStack> { unsafe { - cvt(ffi::EC_KEY_set_public_key( - self.as_ptr(), - public_key.as_ptr(), - )).map(|_| self) + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_private_key( + key.as_ptr(), + private_number.as_ptr(), + )) + .map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_public_key( + key.as_ptr(), + public_key.as_ptr(), + )) + .map(|_| key) + }) } } - /// Generate public and private keys. - pub fn generate_key(&mut self) -> Result<&mut EcKeyBuilderRef, ErrorStack> { - unsafe { cvt(ffi::EC_KEY_generate_key(self.as_ptr())).map(|_| self) } + private_key_from_pem! { + /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. + /// + /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. + #[corresponds(PEM_read_bio_ECPrivateKey)] + private_key_from_pem, + + /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. + /// + /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. + #[corresponds(PEM_read_bio_ECPrivateKey)] + private_key_from_pem_passphrase, + + /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. + /// + /// The callback should fill the password into the provided buffer and return its length. + /// + /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. + #[corresponds(PEM_read_bio_ECPrivateKey)] + private_key_from_pem_callback, + EcKey, + ffi::PEM_read_bio_ECPrivateKey } - /// Sets the public key based on affine coordinates. - pub fn set_public_key_affine_coordinates( - &mut self, - x: &BigNumRef, - y: &BigNumRef, - ) -> Result<&mut EcKeyBuilderRef, ErrorStack> { - unsafe { - cvt(ffi::EC_KEY_set_public_key_affine_coordinates( - self.as_ptr(), - x.as_ptr(), - y.as_ptr(), - )).map(|_| self) - } + from_der! { + /// Decodes a DER-encoded elliptic curve private key structure. + #[corresponds(d2i_ECPrivateKey)] + private_key_from_der, + EcKey, + ffi::d2i_ECPrivateKey + } +} + +impl Clone for EcKey { + fn clone(&self) -> EcKey { + (**self).to_owned() } +} - /// Sets the private key. - pub fn set_private_key(&mut self, key: &BigNumRef) -> Result<&mut EcKeyBuilderRef, ErrorStack> { - unsafe { cvt(ffi::EC_KEY_set_private_key(self.as_ptr(), key.as_ptr())).map(|_| self) } +impl fmt::Debug for EcKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "EcKey") } } #[cfg(test)] mod test { - use bn::{BigNum, BigNumContext}; - use nid; - use data_encoding::BASE64URL_NOPAD; + use hex::FromHex; + use super::*; + use crate::bn::{BigNum, BigNumContext}; + use crate::nid::Nid; #[test] fn key_new_by_curve_name() { - EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); } #[test] fn generate() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let key = EcKey::generate(&group).unwrap(); - key.public_key().unwrap(); - key.private_key().unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + EcKey::generate(&group).unwrap(); + } + + #[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(); + let mut cofactor = BigNum::new().unwrap(); + group.cofactor(&mut cofactor, &mut ctx).unwrap(); + let one = BigNum::from_u32(1).unwrap(); + assert_eq!(cofactor, one); + } + + #[test] + #[allow(clippy::redundant_clone)] fn dup() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); - key.to_owned().unwrap(); + drop(key.clone()); } #[test] fn point_new() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); EcPoint::new(&group).unwrap(); } #[test] fn point_bytes() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); - let point = key.public_key().unwrap(); + let point = key.public_key(); let mut ctx = BigNumContext::new().unwrap(); let bytes = point - .to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx) + .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) .unwrap(); let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); assert!(point.eq(&group, &point2, &mut ctx).unwrap()); } + #[test] + fn point_owned() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let point = key.public_key(); + let owned = point.to_owned(&group).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + assert!(owned.eq(&group, point, &mut ctx).unwrap()); + } + #[test] fn mul_generator() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let mut public_key = EcPoint::new(&group).unwrap(); public_key - .mul_generator(&group, key.private_key().unwrap(), &mut ctx) + .mul_generator(&group, key.private_key(), &ctx) .unwrap(); - assert!( - public_key - .eq(&group, key.public_key().unwrap(), &mut ctx) - .unwrap() - ); + assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); + } + + #[test] + fn generator() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let gen = group.generator(); + let one = BigNum::from_u32(1).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let mut ecp = EcPoint::new(&group).unwrap(); + ecp.mul_generator(&group, &one, &ctx).unwrap(); + assert!(ecp.eq(&group, gen, &mut ctx).unwrap()); } #[test] fn key_from_public_key() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let mut ctx = BigNumContext::new().unwrap(); - let bytes = key.public_key() - .unwrap() - .to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx) + let bytes = key + .public_key() + .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) .unwrap(); drop(key); let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); assert!(ec_key.check_key().is_ok()); - assert!(ec_key.public_key().is_some()); - assert!(ec_key.private_key().is_none()); + } + + #[test] + fn key_from_private_components() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + + let dup_key = + EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); + dup_key.check_key().unwrap(); + + assert!(key.private_key() == dup_key.private_key()); } #[test] fn key_from_affine_coordinates() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let x = BASE64URL_NOPAD.decode( - "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4".as_bytes(), - ).unwrap(); - let y = BASE64URL_NOPAD.decode( - "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM".as_bytes(), - ).unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") + .unwrap(); + let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") + .unwrap(); let xbn = BigNum::from_slice(&x).unwrap(); let ybn = BigNum::from_slice(&y).unwrap(); - let mut builder = EcKeyBuilder::new().unwrap(); - builder.set_group(&group).unwrap(); - builder - .set_public_key_affine_coordinates(&xbn, &ybn) - .unwrap(); - - let ec_key = builder.build(); + let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); assert!(ec_key.check_key().is_ok()); - assert!(ec_key.public_key().is_some()); } + #[cfg(ossl111)] #[test] - fn set_private_key() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let d = BASE64URL_NOPAD.decode( - "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE".as_bytes(), - ).unwrap(); + fn get_affine_coordinates() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") + .unwrap(); + let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") + .unwrap(); - let dbn = BigNum::from_slice(&d).unwrap(); + let xbn = BigNum::from_slice(&x).unwrap(); + let ybn = BigNum::from_slice(&y).unwrap(); - let mut builder = EcKeyBuilder::new().unwrap(); - builder.set_group(&group).unwrap(); - builder.set_private_key(&dbn).unwrap(); + let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); - let ec_key = builder.build(); - assert!(ec_key.private_key().is_some()); + let mut xbn2 = BigNum::new().unwrap(); + let mut ybn2 = BigNum::new().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let ec_key_pk = ec_key.public_key(); + ec_key_pk + .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx) + .unwrap(); + assert_eq!(xbn2, xbn); + assert_eq!(ybn2, ybn); } #[test] - fn get_affine_coordinates() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let x = BASE64URL_NOPAD.decode( - "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4".as_bytes(), - ).unwrap(); - let y = BASE64URL_NOPAD.decode( - "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM".as_bytes(), - ).unwrap(); + fn get_affine_coordinates_gfp() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") + .unwrap(); + let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") + .unwrap(); let xbn = BigNum::from_slice(&x).unwrap(); let ybn = BigNum::from_slice(&y).unwrap(); - let mut builder = EcKeyBuilder::new().unwrap(); - builder.set_group(&group).unwrap(); - builder - .set_public_key_affine_coordinates(&xbn, &ybn) - .unwrap(); - - let ec_key = builder.build(); + let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); let mut xbn2 = BigNum::new().unwrap(); let mut ybn2 = BigNum::new().unwrap(); let mut ctx = BigNumContext::new().unwrap(); - let ec_key_pk = ec_key.public_key().unwrap(); + let ec_key_pk = ec_key.public_key(); ec_key_pk .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx) .unwrap(); assert_eq!(xbn2, xbn); assert_eq!(ybn2, ybn); } + + #[test] + fn is_infinity() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let g = group.generator(); + assert!(!g.is_infinity(&group)); + + let mut order = BigNum::new().unwrap(); + group.order(&mut order, &mut ctx).unwrap(); + let mut inf = EcPoint::new(&group).unwrap(); + inf.mul_generator(&group, &order, &ctx).unwrap(); + assert!(inf.is_infinity(&group)); + } + + #[test] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_EC2M")))] + fn is_on_curve() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let g = group.generator(); + assert!(g.is_on_curve(&group, &mut ctx).unwrap()); + + let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); + assert!(!g.is_on_curve(&group2, &mut ctx).unwrap()); + } } diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs deleted file mode 100644 index f983aaf..0000000 --- a/openssl/src/ec_key.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![doc(hidden)] -#![deprecated(since = "0.9.2", note = "renamed to `ec`")] - -pub use ec::{EcKey, EcKeyRef}; diff --git a/openssl/src/ecdsa.rs b/openssl/src/ecdsa.rs new file mode 100644 index 0000000..0a960e7 --- /dev/null +++ b/openssl/src/ecdsa.rs @@ -0,0 +1,224 @@ +//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions. + +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::mem; +use std::ptr; + +use crate::bn::{BigNum, BigNumRef}; +use crate::ec::EcKeyRef; +use crate::error::ErrorStack; +use crate::pkey::{HasPrivate, HasPublic}; +use crate::util::ForeignTypeRefExt; +use crate::{cvt_n, cvt_p, LenType}; +use openssl_macros::corresponds; + +foreign_type_and_impl_send_sync! { + type CType = ffi::ECDSA_SIG; + fn drop = ffi::ECDSA_SIG_free; + + /// A low level interface to ECDSA. + pub struct EcdsaSig; + /// A reference to an [`EcdsaSig`]. + pub struct EcdsaSigRef; +} + +impl EcdsaSig { + /// Computes a digital signature of the hash value `data` using the private EC key eckey. + #[corresponds(ECDSA_do_sign)] + pub fn sign(data: &[u8], eckey: &EcKeyRef) -> Result + where + T: HasPrivate, + { + unsafe { + assert!(data.len() <= c_int::max_value() as usize); + let sig = cvt_p(ffi::ECDSA_do_sign( + data.as_ptr(), + data.len() as LenType, + eckey.as_ptr(), + ))?; + Ok(EcdsaSig::from_ptr(sig)) + } + } + + /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with an ECDSA signature. + #[corresponds(ECDSA_SIG_set0)] + pub fn from_private_components(r: BigNum, s: BigNum) -> Result { + unsafe { + let sig = cvt_p(ffi::ECDSA_SIG_new())?; + ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); + mem::forget((r, s)); + Ok(EcdsaSig::from_ptr(sig)) + } + } + + from_der! { + /// Decodes a DER-encoded ECDSA signature. + #[corresponds(d2i_ECDSA_SIG)] + from_der, + EcdsaSig, + ffi::d2i_ECDSA_SIG + } +} + +impl EcdsaSigRef { + to_der! { + /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure. + #[corresponds(i2d_ECDSA_SIG)] + to_der, + ffi::i2d_ECDSA_SIG + } + + /// Verifies if the signature is a valid ECDSA signature using the given public key. + #[corresponds(ECDSA_do_verify)] + pub fn verify(&self, data: &[u8], eckey: &EcKeyRef) -> Result + where + T: HasPublic, + { + unsafe { + assert!(data.len() <= c_int::max_value() as usize); + cvt_n(ffi::ECDSA_do_verify( + data.as_ptr(), + data.len() as LenType, + self.as_ptr(), + eckey.as_ptr(), + )) + .map(|x| x == 1) + } + } + + /// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) + #[corresponds(ECDSA_SIG_get0)] + pub fn r(&self) -> &BigNumRef { + unsafe { + let mut r = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); + BigNumRef::from_const_ptr(r) + } + } + + /// Returns internal components: `s` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) + #[corresponds(ECDSA_SIG_get0)] + pub fn s(&self) -> &BigNumRef { + unsafe { + let mut s = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); + BigNumRef::from_const_ptr(s) + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; + } else { + #[allow(bad_style)] + unsafe fn ECDSA_SIG_set0( + sig: *mut ffi::ECDSA_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 ECDSA_SIG_get0( + sig: *const ffi::ECDSA_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::ec::EcGroup; + use crate::ec::EcKey; + use crate::nid::Nid; + use crate::pkey::{Private, Public}; + + fn get_public_key(group: &EcGroup, x: &EcKey) -> Result, ErrorStack> { + EcKey::from_public_key(group, x.public_key()) + } + + #[test] + #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] + fn sign_and_verify() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let private_key = EcKey::generate(&group).unwrap(); + let public_key = get_public_key(&group, &private_key).unwrap(); + + let private_key2 = EcKey::generate(&group).unwrap(); + let public_key2 = get_public_key(&group, &private_key2).unwrap(); + + let data = String::from("hello"); + let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); + + // Signature can be verified using the correct data & correct public key + let verification = res.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification); + + // Signature will not be verified using the incorrect data but the correct public key + let verification2 = res + .verify(String::from("hello2").as_bytes(), &public_key) + .unwrap(); + assert!(!verification2); + + // Signature will not be verified using the correct data but the incorrect public key + let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap(); + assert!(!verification3); + } + + #[test] + #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] + fn check_private_components() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let private_key = EcKey::generate(&group).unwrap(); + let public_key = get_public_key(&group, &private_key).unwrap(); + let data = String::from("hello"); + let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); + + let verification = res.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification); + + let r = res.r().to_owned().unwrap(); + let s = res.s().to_owned().unwrap(); + + let res2 = EcdsaSig::from_private_components(r, s).unwrap(); + let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification2); + } + + #[test] + #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] + fn serialize_deserialize() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let private_key = EcKey::generate(&group).unwrap(); + let public_key = get_public_key(&group, &private_key).unwrap(); + + let data = String::from("hello"); + let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); + + let der = res.to_der().unwrap(); + let sig = EcdsaSig::from_der(&der).unwrap(); + + let verification = sig.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification); + } +} diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs new file mode 100644 index 0000000..d3db0fd --- /dev/null +++ b/openssl/src/encrypt.rs @@ -0,0 +1,578 @@ +//! Message encryption. +//! +//! The [`Encrypter`] allows for encryption of data given a public key. The [`Decrypter`] can be +//! used with the corresponding private key to decrypt the data. +//! +//! # Examples +//! +//! Encrypt and decrypt data given an RSA keypair: +//! +//! ```rust +//! use openssl::encrypt::{Encrypter, Decrypter}; +//! use openssl::rsa::{Rsa, Padding}; +//! use openssl::pkey::PKey; +//! +//! // Generate a keypair +//! let keypair = Rsa::generate(2048).unwrap(); +//! let keypair = PKey::from_rsa(keypair).unwrap(); +//! +//! let data = b"hello, world!"; +//! +//! // Encrypt the data with RSA PKCS1 +//! let mut encrypter = Encrypter::new(&keypair).unwrap(); +//! encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); +//! // Create an output buffer +//! let buffer_len = encrypter.encrypt_len(data).unwrap(); +//! let mut encrypted = vec![0; buffer_len]; +//! // Encrypt and truncate the buffer +//! let encrypted_len = encrypter.encrypt(data, &mut encrypted).unwrap(); +//! encrypted.truncate(encrypted_len); +//! +//! // Decrypt the data +//! let mut decrypter = Decrypter::new(&keypair).unwrap(); +//! decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); +//! // Create an output buffer +//! let buffer_len = decrypter.decrypt_len(&encrypted).unwrap(); +//! let mut decrypted = vec![0; buffer_len]; +//! // Encrypt and truncate the buffer +//! let decrypted_len = decrypter.decrypt(&encrypted, &mut decrypted).unwrap(); +//! decrypted.truncate(decrypted_len); +//! assert_eq!(&*decrypted, data); +//! ``` +#[cfg(any(ossl102, libressl310))] +use libc::{c_int, c_void}; +use std::{marker::PhantomData, ptr}; + +use crate::error::ErrorStack; +use crate::hash::MessageDigest; +use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; +use crate::rsa::Padding; +use crate::{cvt, cvt_p}; +use foreign_types::ForeignTypeRef; + +/// A type which encrypts data. +pub struct Encrypter<'a> { + pctx: *mut ffi::EVP_PKEY_CTX, + _p: PhantomData<&'a ()>, +} + +unsafe impl<'a> Sync for Encrypter<'a> {} +unsafe impl<'a> Send for Encrypter<'a> {} + +impl<'a> Drop for Encrypter<'a> { + fn drop(&mut self) { + unsafe { + ffi::EVP_PKEY_CTX_free(self.pctx); + } + } +} + +impl<'a> Encrypter<'a> { + /// Creates a new `Encrypter`. + /// + /// OpenSSL documentation at [`EVP_PKEY_encrypt_init`]. + /// + /// [`EVP_PKEY_encrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt_init.html + pub fn new(pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPublic, + { + unsafe { + ffi::init(); + + let pctx = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; + let r = ffi::EVP_PKEY_encrypt_init(pctx); + if r != 1 { + ffi::EVP_PKEY_CTX_free(pctx); + return Err(ErrorStack::get()); + } + + Ok(Encrypter { + pctx, + _p: PhantomData, + }) + } + } + + /// Returns the RSA padding mode in use. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + pub fn rsa_padding(&self) -> Result { + unsafe { + let mut pad = 0; + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) + .map(|_| Padding::from_raw(pad)) + } + } + + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.pctx, + padding.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } + } + + /// Sets the RSA OAEP algorithm. + /// + /// This is only useful for RSA keys. + /// + /// 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))] + pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } + } + + /// Sets the RSA OAEP label. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set0_rsa_oaep_label`]. + /// + /// [`EVP_PKEY_CTX_set0_rsa_oaep_label`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set0_rsa_oaep_label.html + #[cfg(any(ossl102, libressl310))] + pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { + unsafe { + let p = cvt_p(ffi::OPENSSL_malloc(label.len() as _))?; + ptr::copy_nonoverlapping(label.as_ptr(), p as *mut u8, label.len()); + + cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( + self.pctx, + p as *mut c_void, + label.len() as c_int, + )) + .map(|_| ()) + .map_err(|e| { + ffi::OPENSSL_free(p); + e + }) + } + } + + /// Performs public key encryption. + /// + /// In order to know the size needed for the output buffer, use [`encrypt_len`](Encrypter::encrypt_len). + /// Note that the length of the output buffer can be greater of the length of the encoded data. + /// ``` + /// # use openssl::{ + /// # encrypt::Encrypter, + /// # pkey::PKey, + /// # rsa::{Rsa, Padding}, + /// # }; + /// # + /// # let key = include_bytes!("../test/rsa.pem"); + /// # let private_key = Rsa::private_key_from_pem(key).unwrap(); + /// # let pkey = PKey::from_rsa(private_key).unwrap(); + /// # let input = b"hello world".to_vec(); + /// # + /// let mut encrypter = Encrypter::new(&pkey).unwrap(); + /// encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); + /// + /// // Get the length of the output buffer + /// let buffer_len = encrypter.encrypt_len(&input).unwrap(); + /// let mut encoded = vec![0u8; buffer_len]; + /// + /// // Encode the data and get its length + /// let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); + /// + /// // Use only the part of the buffer with the encoded data + /// let encoded = &encoded[..encoded_len]; + /// ``` + /// + /// This corresponds to [`EVP_PKEY_encrypt`]. + /// + /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html + pub fn encrypt(&self, from: &[u8], to: &mut [u8]) -> Result { + let mut written = to.len(); + unsafe { + cvt(ffi::EVP_PKEY_encrypt( + self.pctx, + to.as_mut_ptr(), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } + + /// Gets the size of the buffer needed to encrypt the input data. + /// + /// This corresponds to [`EVP_PKEY_encrypt`] called with a null pointer as output argument. + /// + /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html + pub fn encrypt_len(&self, from: &[u8]) -> Result { + let mut written = 0; + unsafe { + cvt(ffi::EVP_PKEY_encrypt( + self.pctx, + ptr::null_mut(), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } +} + +/// A type which decrypts data. +pub struct Decrypter<'a> { + pctx: *mut ffi::EVP_PKEY_CTX, + _p: PhantomData<&'a ()>, +} + +unsafe impl<'a> Sync for Decrypter<'a> {} +unsafe impl<'a> Send for Decrypter<'a> {} + +impl<'a> Drop for Decrypter<'a> { + fn drop(&mut self) { + unsafe { + ffi::EVP_PKEY_CTX_free(self.pctx); + } + } +} + +impl<'a> Decrypter<'a> { + /// Creates a new `Decrypter`. + /// + /// OpenSSL documentation at [`EVP_PKEY_decrypt_init`]. + /// + /// [`EVP_PKEY_decrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt_init.html + pub fn new(pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + unsafe { + ffi::init(); + + let pctx = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; + let r = ffi::EVP_PKEY_decrypt_init(pctx); + if r != 1 { + ffi::EVP_PKEY_CTX_free(pctx); + return Err(ErrorStack::get()); + } + + Ok(Decrypter { + pctx, + _p: PhantomData, + }) + } + } + + /// Returns the RSA padding mode in use. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + pub fn rsa_padding(&self) -> Result { + unsafe { + let mut pad = 0; + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) + .map(|_| Padding::from_raw(pad)) + } + } + + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.pctx, + padding.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } + } + + /// Sets the RSA OAEP algorithm. + /// + /// This is only useful for RSA keys. + /// + /// 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))] + pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } + } + + /// Sets the RSA OAEP label. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set0_rsa_oaep_label`]. + /// + /// [`EVP_PKEY_CTX_set0_rsa_oaep_label`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set0_rsa_oaep_label.html + #[cfg(any(ossl102, libressl310))] + pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { + unsafe { + let p = cvt_p(ffi::OPENSSL_malloc(label.len() as _))?; + ptr::copy_nonoverlapping(label.as_ptr(), p as *mut u8, label.len()); + + cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( + self.pctx, + p as *mut c_void, + label.len() as c_int, + )) + .map(|_| ()) + .map_err(|e| { + ffi::OPENSSL_free(p); + e + }) + } + } + + /// Performs public key decryption. + /// + /// In order to know the size needed for the output buffer, use [`decrypt_len`](Decrypter::decrypt_len). + /// Note that the length of the output buffer can be greater of the length of the decoded data. + /// ``` + /// # use openssl::{ + /// # encrypt::Decrypter, + /// # pkey::PKey, + /// # rsa::{Rsa, Padding}, + /// # }; + /// # + /// # const INPUT: &[u8] = b"\ + /// # \x26\xa1\xc1\x13\xc5\x7f\xb4\x9f\xa0\xb4\xde\x61\x5e\x2e\xc6\xfb\x76\x5c\xd1\x2b\x5f\ + /// # \x1d\x36\x60\xfa\xf8\xe8\xb3\x21\xf4\x9c\x70\xbc\x03\xea\xea\xac\xce\x4b\xb3\xf6\x45\ + /// # \xcc\xb3\x80\x9e\xa8\xf7\xc3\x5d\x06\x12\x7a\xa3\x0c\x30\x67\xf1\xe7\x94\x6c\xf6\x26\ + /// # \xac\x28\x17\x59\x69\xe1\xdc\xed\x7e\xc0\xe9\x62\x57\x49\xce\xdd\x13\x07\xde\x18\x03\ + /// # \x0f\x9d\x61\x65\xb9\x23\x8c\x78\x4b\xad\x23\x49\x75\x47\x64\xa0\xa0\xa2\x90\xc1\x49\ + /// # \x1b\x05\x24\xc2\xe9\x2c\x0d\x49\x78\x72\x61\x72\xed\x8b\x6f\x8a\xe8\xca\x05\x5c\x58\ + /// # \xd6\x95\xd6\x7b\xe3\x2d\x0d\xaa\x3e\x6d\x3c\x9a\x1c\x1d\xb4\x6c\x42\x9d\x9a\x82\x55\ + /// # \xd9\xde\xc8\x08\x7b\x17\xac\xd7\xaf\x86\x7b\x69\x9e\x3c\xf4\x5e\x1c\x39\x52\x6d\x62\ + /// # \x50\x51\xbd\xa6\xc8\x4e\xe9\x34\xf0\x37\x0d\xa9\xa9\x77\xe6\xf5\xc2\x47\x2d\xa8\xee\ + /// # \x3f\x69\x78\xff\xa9\xdc\x70\x22\x20\x9a\x5c\x9b\x70\x15\x90\xd3\xb4\x0e\x54\x9e\x48\ + /// # \xed\xb6\x2c\x88\xfc\xb4\xa9\x37\x10\xfa\x71\xb2\xec\x75\xe7\xe7\x0e\xf4\x60\x2c\x7b\ + /// # \x58\xaf\xa0\x53\xbd\x24\xf1\x12\xe3\x2e\x99\x25\x0a\x54\x54\x9d\xa1\xdb\xca\x41\x85\ + /// # \xf4\x62\x78\x64"; + /// # + /// # let key = include_bytes!("../test/rsa.pem"); + /// # let private_key = Rsa::private_key_from_pem(key).unwrap(); + /// # let pkey = PKey::from_rsa(private_key).unwrap(); + /// # let input = INPUT.to_vec(); + /// # + /// let mut decrypter = Decrypter::new(&pkey).unwrap(); + /// decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); + /// + /// // Get the length of the output buffer + /// let buffer_len = decrypter.decrypt_len(&input).unwrap(); + /// let mut decoded = vec![0u8; buffer_len]; + /// + /// // Decrypt the data and get its length + /// let decoded_len = decrypter.decrypt(&input, &mut decoded).unwrap(); + /// + /// // Use only the part of the buffer with the decrypted data + /// let decoded = &decoded[..decoded_len]; + /// ``` + /// + /// This corresponds to [`EVP_PKEY_decrypt`]. + /// + /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt.html + pub fn decrypt(&self, from: &[u8], to: &mut [u8]) -> Result { + let mut written = to.len(); + unsafe { + cvt(ffi::EVP_PKEY_decrypt( + self.pctx, + to.as_mut_ptr(), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } + + /// Gets the size of the buffer needed to decrypt the input data. + /// + /// This corresponds to [`EVP_PKEY_decrypt`] called with a null pointer as output argument. + /// + /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt.html + pub fn decrypt_len(&self, from: &[u8]) -> Result { + let mut written = 0; + unsafe { + cvt(ffi::EVP_PKEY_decrypt( + self.pctx, + ptr::null_mut(), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } +} + +#[cfg(test)] +mod test { + use hex::FromHex; + + use crate::encrypt::{Decrypter, Encrypter}; + #[cfg(any(ossl102, libressl310))] + use crate::hash::MessageDigest; + use crate::pkey::PKey; + use crate::rsa::{Padding, Rsa}; + + const INPUT: &str = + "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ + 654841694f6a457a4d4441344d546b7a4f44417344516f67496d6830644841364c79396c654746746347786c4c\ + 6d4e76625339706331397962323930496a7030636e566c6651"; + + #[test] + fn rsa_encrypt_decrypt() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let mut encrypter = Encrypter::new(&pkey).unwrap(); + encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); + let input = Vec::from_hex(INPUT).unwrap(); + let buffer_len = encrypter.encrypt_len(&input).unwrap(); + let mut encoded = vec![0u8; buffer_len]; + let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); + let encoded = &encoded[..encoded_len]; + + let mut decrypter = Decrypter::new(&pkey).unwrap(); + decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); + let buffer_len = decrypter.decrypt_len(encoded).unwrap(); + let mut decoded = vec![0u8; buffer_len]; + let decoded_len = decrypter.decrypt(encoded, &mut decoded).unwrap(); + let decoded = &decoded[..decoded_len]; + + assert_eq!(decoded, &*input); + } + + #[test] + #[cfg(any(ossl102, libressl310))] + fn rsa_encrypt_decrypt_with_sha256() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let md = MessageDigest::sha256(); + + let mut encrypter = Encrypter::new(&pkey).unwrap(); + encrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + encrypter.set_rsa_oaep_md(md).unwrap(); + encrypter.set_rsa_mgf1_md(md).unwrap(); + let input = Vec::from_hex(INPUT).unwrap(); + let buffer_len = encrypter.encrypt_len(&input).unwrap(); + let mut encoded = vec![0u8; buffer_len]; + let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); + let encoded = &encoded[..encoded_len]; + + let mut decrypter = Decrypter::new(&pkey).unwrap(); + decrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + decrypter.set_rsa_oaep_md(md).unwrap(); + decrypter.set_rsa_mgf1_md(md).unwrap(); + let buffer_len = decrypter.decrypt_len(encoded).unwrap(); + let mut decoded = vec![0u8; buffer_len]; + let decoded_len = decrypter.decrypt(encoded, &mut decoded).unwrap(); + let decoded = &decoded[..decoded_len]; + + assert_eq!(decoded, &*input); + } + + #[test] + #[cfg(any(ossl102, libressl310))] + fn rsa_encrypt_decrypt_oaep_label() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let mut encrypter = Encrypter::new(&pkey).unwrap(); + encrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + encrypter.set_rsa_oaep_label(b"test_oaep_label").unwrap(); + let input = Vec::from_hex(INPUT).unwrap(); + let buffer_len = encrypter.encrypt_len(&input).unwrap(); + let mut encoded = vec![0u8; buffer_len]; + let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); + let encoded = &encoded[..encoded_len]; + + let mut decrypter = Decrypter::new(&pkey).unwrap(); + decrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + decrypter.set_rsa_oaep_label(b"test_oaep_label").unwrap(); + let buffer_len = decrypter.decrypt_len(encoded).unwrap(); + let mut decoded = vec![0u8; buffer_len]; + let decoded_len = decrypter.decrypt(encoded, &mut decoded).unwrap(); + let decoded = &decoded[..decoded_len]; + + assert_eq!(decoded, &*input); + + decrypter.set_rsa_oaep_label(b"wrong_oaep_label").unwrap(); + let buffer_len = decrypter.decrypt_len(encoded).unwrap(); + let mut decoded = vec![0u8; buffer_len]; + + assert!(decrypter.decrypt(encoded, &mut decoded).is_err()); + } +} diff --git a/openssl/src/envelope.rs b/openssl/src/envelope.rs new file mode 100644 index 0000000..25055ac --- /dev/null +++ b/openssl/src/envelope.rs @@ -0,0 +1,181 @@ +//! Envelope encryption. +//! +//! # Example +//! +//! ```rust +//! use openssl::rsa::Rsa; +//! use openssl::envelope::Seal; +//! use openssl::pkey::PKey; +//! use openssl::symm::Cipher; +//! +//! let rsa = Rsa::generate(2048).unwrap(); +//! let key = PKey::from_rsa(rsa).unwrap(); +//! +//! let cipher = Cipher::aes_256_cbc(); +//! let mut seal = Seal::new(cipher, &[key]).unwrap(); +//! +//! let secret = b"My secret message"; +//! let mut encrypted = vec![0; secret.len() + cipher.block_size()]; +//! +//! let mut enc_len = seal.update(secret, &mut encrypted).unwrap(); +//! enc_len += seal.finalize(&mut encrypted[enc_len..]).unwrap(); +//! encrypted.truncate(enc_len); +//! ``` +use crate::cipher::CipherRef; +use crate::cipher_ctx::CipherCtx; +use crate::error::ErrorStack; +use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; +use crate::symm::Cipher; +use foreign_types::ForeignTypeRef; + +/// Represents an EVP_Seal context. +pub struct Seal { + ctx: CipherCtx, + iv: Option>, + enc_keys: Vec>, +} + +impl Seal { + /// Creates a new `Seal`. + pub fn new(cipher: Cipher, pub_keys: &[PKey]) -> Result + where + T: HasPublic, + { + let mut iv = cipher.iv_len().map(|len| vec![0; len]); + let mut enc_keys = vec![vec![]; pub_keys.len()]; + + let mut ctx = CipherCtx::new()?; + ctx.seal_init( + Some(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) }), + pub_keys, + &mut enc_keys, + iv.as_deref_mut(), + )?; + + Ok(Seal { ctx, iv, enc_keys }) + } + + /// Returns the initialization vector, if the cipher uses one. + #[allow(clippy::option_as_ref_deref)] + pub fn iv(&self) -> Option<&[u8]> { + self.iv.as_ref().map(|v| &**v) + } + + /// Returns the encrypted keys. + pub fn encrypted_keys(&self) -> &[Vec] { + &self.enc_keys + } + + /// Feeds data from `input` through the cipher, writing encrypted bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Panics + /// + /// Panics if `output.len() < input.len() + block_size` where `block_size` is + /// the block size of the cipher (see `Cipher::block_size`), or if + /// `output.len() > c_int::max_value()`. + pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { + self.ctx.cipher_update(input, Some(output)) + } + + /// Finishes the encryption process, writing any remaining data to `output`. + /// + /// The number of bytes written to `output` is returned. + /// + /// `update` should not be called after this method. + /// + /// # Panics + /// + /// Panics if `output` is less than the cipher's block size. + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + self.ctx.cipher_final(output) + } +} + +/// Represents an EVP_Open context. +pub struct Open { + ctx: CipherCtx, +} + +impl Open { + /// Creates a new `Open`. + pub fn new( + cipher: Cipher, + priv_key: &PKeyRef, + iv: Option<&[u8]>, + encrypted_key: &[u8], + ) -> Result + where + T: HasPrivate, + { + let mut ctx = CipherCtx::new()?; + ctx.open_init( + Some(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) }), + encrypted_key, + iv, + Some(priv_key), + )?; + + Ok(Open { ctx }) + } + + /// Feeds data from `input` through the cipher, writing decrypted bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Panics + /// + /// Panics if `output.len() < input.len() + block_size` where + /// `block_size` is the block size of the cipher (see `Cipher::block_size`), + /// or if `output.len() > c_int::max_value()`. + pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { + self.ctx.cipher_update(input, Some(output)) + } + + /// Finishes the decryption process, writing any remaining data to `output`. + /// + /// The number of bytes written to `output` is returned. + /// + /// `update` should not be called after this method. + /// + /// # Panics + /// + /// Panics if `output` is less than the cipher's block size. + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + self.ctx.cipher_final(output) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::pkey::PKey; + use crate::symm::Cipher; + + #[test] + fn public_encrypt_private_decrypt() { + let private_pem = include_bytes!("../test/rsa.pem"); + let public_pem = include_bytes!("../test/rsa.pem.pub"); + let private_key = PKey::private_key_from_pem(private_pem).unwrap(); + let public_key = PKey::public_key_from_pem(public_pem).unwrap(); + let cipher = Cipher::aes_256_cbc(); + let secret = b"My secret message"; + + let mut seal = Seal::new(cipher, &[public_key]).unwrap(); + let mut encrypted = vec![0; secret.len() + cipher.block_size()]; + let mut enc_len = seal.update(secret, &mut encrypted).unwrap(); + enc_len += seal.finalize(&mut encrypted[enc_len..]).unwrap(); + let iv = seal.iv(); + let encrypted_key = &seal.encrypted_keys()[0]; + + let mut open = Open::new(cipher, &private_key, iv, encrypted_key).unwrap(); + let mut decrypted = vec![0; enc_len + cipher.block_size()]; + let mut dec_len = open.update(&encrypted[..enc_len], &mut decrypted).unwrap(); + dec_len += open.finalize(&mut decrypted[dec_len..]).unwrap(); + + assert_eq!(&secret[..], &decrypted[..dec_len]); + } +} diff --git a/openssl/src/error.rs b/openssl/src/error.rs index 5f3e217..064d635 100644 --- a/openssl/src/error.rs +++ b/openssl/src/error.rs @@ -15,16 +15,22 @@ //! Err(e) => println!("Parsing Error: {:?}", e), //! } //! ``` -use libc::{c_ulong, c_char, c_int}; -use std::fmt; +use cfg_if::cfg_if; +use libc::{c_char, c_int}; +use std::borrow::Cow; +#[cfg(boringssl)] +use std::convert::TryInto; use std::error; use std::ffi::CStr; +use std::fmt; use std::io; -use std::str; use std::ptr; -use std::borrow::Cow; +use std::str; -use ffi; +#[cfg(not(boringssl))] +type ErrType = libc::c_ulong; +#[cfg(boringssl)] +type ErrType = libc::c_uint; /// Collection of [`Error`]s from OpenSSL. /// @@ -41,6 +47,13 @@ impl ErrorStack { } ErrorStack(vec) } + + /// Pushes the errors back onto the OpenSSL error stack. + pub fn put(&self) { + for error in self.errors() { + error.put(); + } + } } impl ErrorStack { @@ -51,7 +64,11 @@ impl ErrorStack { } impl fmt::Display for ErrorStack { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.0.is_empty() { + return fmt.write_str("OpenSSL error"); + } + let mut first = true; for err in &self.0 { if !first { @@ -64,11 +81,7 @@ impl fmt::Display for ErrorStack { } } -impl error::Error for ErrorStack { - fn description(&self) -> &str { - "An OpenSSL error stack" - } -} +impl error::Error for ErrorStack {} impl From for io::Error { fn from(e: ErrorStack) -> io::Error { @@ -85,9 +98,10 @@ impl From for fmt::Error { /// An error reported from OpenSSL. #[derive(Clone)] pub struct Error { - code: c_ulong, - file: *const c_char, + code: ErrType, + file: ShimStr, line: c_int, + func: Option, data: Option>, } @@ -102,9 +116,10 @@ impl Error { let mut file = ptr::null(); let mut line = 0; + let mut func = ptr::null(); let mut data = ptr::null(); let mut flags = 0; - match ffi::ERR_get_error_line_data(&mut file, &mut line, &mut data, &mut flags) { + match ERR_get_error_all(&mut file, &mut line, &mut func, &mut data, &mut flags) { 0 => None, code => { // The memory referenced by data is only valid until that slot is overwritten @@ -112,28 +127,100 @@ impl Error { let data = if flags & ffi::ERR_TXT_STRING != 0 { let bytes = CStr::from_ptr(data as *const _).to_bytes(); let data = str::from_utf8(bytes).unwrap(); + #[cfg(not(boringssl))] let data = if flags & ffi::ERR_TXT_MALLOCED != 0 { Cow::Owned(data.to_string()) } else { Cow::Borrowed(data) }; + #[cfg(boringssl)] + let data = Cow::Borrowed(data); Some(data) } else { None }; + + let file = ShimStr::new(file); + + let func = if func.is_null() { + None + } else { + Some(ShimStr::new(func)) + }; + Some(Error { - code: code, - file: file, - line: line, - data: data, + code, + file, + line, + func, + data, }) } } } } + /// Pushes the error back onto the OpenSSL error stack. + pub fn put(&self) { + self.put_error(); + + unsafe { + let data = match self.data { + Some(Cow::Borrowed(data)) => Some((data.as_ptr() as *mut c_char, 0)), + Some(Cow::Owned(ref data)) => { + let ptr = ffi::CRYPTO_malloc( + (data.len() + 1) as _, + concat!(file!(), "\0").as_ptr() as _, + line!() as _, + ) as *mut c_char; + if ptr.is_null() { + None + } else { + ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len()); + *ptr.add(data.len()) = 0; + Some((ptr, ffi::ERR_TXT_MALLOCED)) + } + } + None => None, + }; + if let Some((ptr, flags)) = data { + ffi::ERR_set_error_data(ptr, flags | ffi::ERR_TXT_STRING); + } + } + } + + #[cfg(ossl300)] + fn put_error(&self) { + unsafe { + ffi::ERR_new(); + 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(self.library_code(), self.reason_code(), ptr::null()); + } + } + + #[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( + self.library_code(), + ffi::ERR_GET_FUNC(self.code), + self.reason_code(), + self.file.as_ptr(), + line, + ); + } + } + /// Returns the raw OpenSSL error code for this error. - pub fn code(&self) -> c_ulong { + pub fn code(&self) -> ErrType { self.code } @@ -149,16 +236,18 @@ impl Error { } } + /// Returns the raw OpenSSL error constant for the library reporting the + /// error. + // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on + // OpenSSL/LibreSSL they're safe. + #[allow(unused_unsafe)] + pub fn library_code(&self) -> libc::c_int { + unsafe { ffi::ERR_GET_LIB(self.code) } + } + /// Returns the name of the function reporting the error. - pub fn function(&self) -> Option<&'static str> { - unsafe { - let cstr = ffi::ERR_func_error_string(self.code); - if cstr.is_null() { - return None; - } - let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); - Some(str::from_utf8(bytes).unwrap()) - } + pub fn function(&self) -> Option> { + self.func.as_ref().map(|s| s.as_str()) } /// Returns the reason for the error. @@ -173,28 +262,33 @@ impl Error { } } + /// Returns the raw OpenSSL error constant for the reason for the error. + // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on + // OpenSSL/LibreSSL they're safe. + #[allow(unused_unsafe)] + pub fn reason_code(&self) -> libc::c_int { + unsafe { ffi::ERR_GET_REASON(self.code) } + } + /// 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. - pub fn line(&self) -> c_int { - self.line + pub fn line(&self) -> u32 { + self.line as u32 } /// Returns additional data describing the error. + #[allow(clippy::option_as_ref_deref)] pub fn data(&self) -> Option<&str> { self.data.as_ref().map(|s| &**s) } } impl fmt::Debug for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("Error"); builder.field("code", &self.code()); if let Some(library) = self.library() { @@ -216,19 +310,22 @@ impl fmt::Debug for Error { } impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on + // OpenSSL/LibreSSL they're safe. + #[allow(unused_unsafe)] + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "error:{:08X}", self.code())?; match self.library() { Some(l) => write!(fmt, ":{}", l)?, - None => write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))?, + None => write!(fmt, ":lib({})", self.library_code())?, } match self.function() { Some(f) => write!(fmt, ":{}", f)?, - None => write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))?, + None => write!(fmt, ":func({})", unsafe { ffi::ERR_GET_FUNC(self.code()) })?, } match self.reason() { Some(r) => write!(fmt, ":{}", r)?, - None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.code()))?, + None => write!(fmt, ":reason({})", self.reason_code())?, } write!( fmt, @@ -240,8 +337,79 @@ impl fmt::Display for Error { } } -impl error::Error for Error { - fn description(&self) -> &str { - "an OpenSSL error" +impl error::Error for Error {} + +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( + file: *mut *const c_char, + line: *mut c_int, + func: *mut *const c_char, + data: *mut *const c_char, + flags: *mut c_int, + ) -> ErrType { + let code = ffi::ERR_get_error_line_data(file, line, data, flags); + *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() + } + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::nid::Nid; + + #[test] + fn test_error_library_code() { + let stack = Nid::create("not-an-oid", "invalid", "invalid").unwrap_err(); + let errors = stack.errors(); + #[cfg(not(boringssl))] + assert_eq!(errors[0].library_code(), ffi::ERR_LIB_ASN1); + #[cfg(boringssl)] + assert_eq!(errors[0].library_code(), ffi::ERR_LIB_OBJ as libc::c_int); } } diff --git a/openssl/src/ex_data.rs b/openssl/src/ex_data.rs index 450dd11..d4f0021 100644 --- a/openssl/src/ex_data.rs +++ b/openssl/src/ex_data.rs @@ -16,10 +16,16 @@ impl Clone for Index { } impl Index { + /// Creates an `Index` from a raw integer index. + /// + /// # Safety + /// + /// The caller must ensure that the index correctly maps to a `U` value stored in a `T`. pub unsafe fn from_raw(idx: c_int) -> Index { Index(idx, PhantomData) } + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } diff --git a/openssl/src/fips.rs b/openssl/src/fips.rs new file mode 100644 index 0000000..2a8a2fe --- /dev/null +++ b/openssl/src/fips.rs @@ -0,0 +1,21 @@ +//! FIPS 140-2 support. +//! +//! See [OpenSSL's documentation] for details. +//! +//! [OpenSSL's documentation]: https://www.openssl.org/docs/fips/UserGuide-2.0.pdf +use crate::cvt; +use crate::error::ErrorStack; +use openssl_macros::corresponds; + +/// Moves the library into or out of the FIPS 140-2 mode of operation. +#[corresponds(FIPS_mode_set)] +pub fn enable(enabled: bool) -> Result<(), ErrorStack> { + ffi::init(); + unsafe { cvt(ffi::FIPS_mode_set(enabled as _)).map(|_| ()) } +} + +/// Determines if the library is running in the FIPS 140-2 mode of operation. +#[corresponds(FIPS_mode)] +pub fn enabled() -> bool { + unsafe { ffi::FIPS_mode() != 0 } +} diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index bb60ed3..37442fb 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -1,21 +1,108 @@ -use std::io::prelude::*; +//! Message digest (hash) computation support. +//! +//! # Examples +//! +//! Calculate a hash in one go: +//! +//! ``` +//! # fn main() -> Result<(), Box> { +//! use openssl::hash::{hash, MessageDigest}; +//! +//! let data = b"\x42\xF4\x97\xE0"; +//! let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; +//! let res = hash(MessageDigest::md5(), data)?; +//! assert_eq!(&*res, spec); +//! # Ok(()) } +//! ``` +//! +//! Supply the input in chunks: +//! +//! ``` +//! use openssl::hash::{Hasher, MessageDigest}; +//! +//! # fn main() -> Result<(), Box> { +//! let mut hasher = Hasher::new(MessageDigest::sha256())?; +//! hasher.update(b"test")?; +//! hasher.update(b"this")?; +//! let digest: &[u8] = &hasher.finish()?; +//! +//! let expected = hex::decode("9740e652ab5b4acd997a7cca13d6696702ccb2d441cca59fc6e285127f28cfe6")?; +//! assert_eq!(digest, expected); +//! # Ok(()) } +//! ``` +use cfg_if::cfg_if; +use std::ffi::CString; +use std::fmt; use std::io; +use std::io::prelude::*; use std::ops::{Deref, DerefMut}; -use std::fmt; -use ffi; +use std::ptr; -#[cfg(ossl110)] -use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free}; -#[cfg(any(ossl101, ossl102))] -use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; +use crate::error::ErrorStack; +use crate::nid::Nid; +use crate::{cvt, cvt_p}; -use {cvt, cvt_p}; -use error::ErrorStack; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} -#[derive(Copy, Clone)] +/// A message digest algorithm. +#[derive(Copy, Clone, PartialEq, Eq)] pub struct MessageDigest(*const ffi::EVP_MD); impl MessageDigest { + /// Creates a `MessageDigest` from a raw OpenSSL pointer. + /// + /// # Safety + /// + /// The caller must ensure the pointer is valid. + pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self { + MessageDigest(x) + } + + /// Returns the `MessageDigest` corresponding to an `Nid`. + /// + /// This corresponds to [`EVP_get_digestbynid`]. + /// + /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html + pub fn from_nid(type_: Nid) -> Option { + unsafe { + let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); + if ptr.is_null() { + None + } else { + Some(MessageDigest(ptr)) + } + } + } + + /// Returns the `MessageDigest` corresponding to an algorithm name. + /// + /// This corresponds to [`EVP_get_digestbyname`]. + /// + /// [`EVP_get_digestbyname`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html + pub fn from_name(name: &str) -> Option { + ffi::init(); + let name = CString::new(name).ok()?; + unsafe { + let ptr = ffi::EVP_get_digestbyname(name.as_ptr()); + if ptr.is_null() { + None + } else { + Some(MessageDigest(ptr)) + } + } + } + + #[cfg(not(boringssl))] + pub fn null() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_md_null()) } + } + pub fn md5() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_md5()) } } @@ -40,15 +127,73 @@ impl MessageDigest { unsafe { MessageDigest(ffi::EVP_sha512()) } } + #[cfg(ossl111)] + pub fn sha3_224() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_224()) } + } + + #[cfg(ossl111)] + pub fn sha3_256() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_256()) } + } + + #[cfg(ossl111)] + pub fn sha3_384() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_384()) } + } + + #[cfg(ossl111)] + pub fn sha3_512() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_512()) } + } + + #[cfg(ossl111)] + pub fn shake_128() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_shake128()) } + } + + #[cfg(ossl111)] + pub fn shake_256() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_shake256()) } + } + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_RMD160")))] pub fn ripemd160() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_ripemd160()) } } + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))] + pub fn sm3() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sm3()) } + } + + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_ptr(&self) -> *const ffi::EVP_MD { self.0 } + + /// The block size of the digest in bytes. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn block_size(&self) -> usize { + unsafe { ffi::EVP_MD_block_size(self.0) as usize } + } + + /// The size of the digest in bytes. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn size(&self) -> usize { + unsafe { ffi::EVP_MD_size(self.0) as usize } + } + + /// The name of the digest. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn type_(&self) -> Nid { + Nid::from_raw(unsafe { ffi::EVP_MD_type(self.0) }) + } } +unsafe impl Sync for MessageDigest {} +unsafe impl Send for MessageDigest {} + #[derive(PartialEq, Copy, Clone)] enum State { Reset, @@ -62,29 +207,18 @@ use self::State::*; /// /// # Examples /// -/// Calculate a hash in one go: -/// -/// ``` -/// use openssl::hash::{hash, MessageDigest}; -/// -/// let data = b"\x42\xF4\x97\xE0"; -/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; -/// let res = hash(MessageDigest::md5(), data).unwrap(); -/// assert_eq!(res, spec); -/// ``` -/// -/// Supply the input in chunks: -/// /// ``` /// use openssl::hash::{Hasher, MessageDigest}; /// +/// # fn main() -> Result<(), Box> { /// let data = [b"\x42\xF4", b"\x97\xE0"]; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; -/// let mut h = Hasher::new(MessageDigest::md5()).unwrap(); -/// h.update(data[0]).unwrap(); -/// h.update(data[1]).unwrap(); -/// let res = h.finish().unwrap(); -/// assert_eq!(res, spec); +/// let mut h = Hasher::new(MessageDigest::md5())?; +/// h.update(data[0])?; +/// h.update(data[1])?; +/// let res = h.finish()?; +/// assert_eq!(&*res, spec); +/// # Ok(()) } /// ``` /// /// # Warning @@ -92,6 +226,11 @@ use self::State::*; /// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore. /// /// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead. +/// +/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256), +/// you must use [`Hasher::finish_xof`] instead of [`Hasher::finish`] +/// and provide a `buf` to store the hash. The hash will be as long as +/// the `buf`. pub struct Hasher { ctx: *mut ffi::EVP_MD_CTX, md: *const ffi::EVP_MD, @@ -99,6 +238,9 @@ pub struct Hasher { state: State, } +unsafe impl Sync for Hasher {} +unsafe impl Send for Hasher {} + impl Hasher { /// Creates a new `Hasher` with the specified hash type. pub fn new(ty: MessageDigest) -> Result { @@ -107,7 +249,7 @@ impl Hasher { let ctx = unsafe { cvt_p(EVP_MD_CTX_new())? }; let mut h = Hasher { - ctx: ctx, + ctx, md: ty.as_ptr(), type_: ty, state: Finalized, @@ -120,12 +262,12 @@ impl Hasher { match self.state { Reset => return Ok(()), Updated => { - self.finish2()?; + self.finish()?; } Finalized => (), } unsafe { - cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _))?; + cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, ptr::null_mut()))?; } self.state = Reset; Ok(()) @@ -147,20 +289,16 @@ impl Hasher { Ok(()) } - #[deprecated(note = "use finish2 instead", since = "0.9.11")] - pub fn finish(&mut self) -> Result, ErrorStack> { - self.finish2().map(|b| b.to_vec()) - } - - /// Returns the hash of the data written and resets the hasher. - /// - /// Unlike `finish`, this method does not allocate. - pub fn finish2(&mut self) -> Result { + /// Returns the hash of the data written and resets the non-XOF hasher. + pub fn finish(&mut self) -> Result { if self.state == Finalized { self.init()?; } unsafe { + #[cfg(not(boringssl))] let mut len = ffi::EVP_MAX_MD_SIZE; + #[cfg(boringssl)] + let mut len = ffi::EVP_MAX_MD_SIZE as u32; let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize]; cvt(ffi::EVP_DigestFinal_ex( self.ctx, @@ -169,11 +307,29 @@ impl Hasher { ))?; self.state = Finalized; Ok(DigestBytes { - buf: buf, + buf, len: len as usize, }) } } + + /// Writes the hash of the data into the supplied buf and resets the XOF hasher. + /// The hash will be as long as the buf. + #[cfg(ossl111)] + pub fn finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> { + if self.state == Finalized { + self.init()?; + } + unsafe { + cvt(ffi::EVP_DigestFinalXOF( + self.ctx, + buf.as_mut_ptr(), + buf.len(), + ))?; + self.state = Finalized; + Ok(()) + } + } } impl Write for Hasher { @@ -198,7 +354,7 @@ impl Clone for Hasher { ctx }; Hasher { - ctx: ctx, + ctx, md: self.md, type_: self.type_, state: self.state, @@ -210,7 +366,7 @@ impl Drop for Hasher { fn drop(&mut self) { unsafe { if self.state != Finalized { - drop(self.finish2()); + drop(self.finish()); } EVP_MD_CTX_free(self.ctx); } @@ -223,8 +379,8 @@ impl Drop for Hasher { /// store the digest data. #[derive(Copy)] pub struct DigestBytes { - buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], - len: usize, + pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], + pub(crate) len: usize, } impl Clone for DigestBytes { @@ -258,76 +414,118 @@ impl AsRef<[u8]> for DigestBytes { } impl fmt::Debug for DigestBytes { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, fmt) } } -#[deprecated(note = "use hash2 instead", since = "0.9.11")] -pub fn hash(t: MessageDigest, data: &[u8]) -> Result, ErrorStack> { - hash2(t, data).map(|b| b.to_vec()) +/// Computes the hash of the `data` with the non-XOF hasher `t`. +/// +/// # Examples +/// +/// ``` +/// # fn main() -> Result<(), Box> { +/// use openssl::hash::{hash, MessageDigest}; +/// +/// let data = b"\x42\xF4\x97\xE0"; +/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; +/// let res = hash(MessageDigest::md5(), data)?; +/// assert_eq!(&*res, spec); +/// # Ok(()) } +/// ``` +pub fn hash(t: MessageDigest, data: &[u8]) -> Result { + let mut h = Hasher::new(t)?; + h.update(data)?; + h.finish() } -/// Computes the hash of the `data` with the hash `t`. +/// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`. +/// +/// # Examples +/// +/// ``` +/// use openssl::hash::{hash_xof, MessageDigest}; +/// +/// let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73"; +/// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35"; +/// let mut buf = vec![0; 16]; +/// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap(); +/// assert_eq!(buf, spec); +/// ``` /// -/// Unlike `hash`, this function does not allocate the return value. -pub fn hash2(t: MessageDigest, data: &[u8]) -> Result { +#[cfg(ossl111)] +pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> { let mut h = Hasher::new(t)?; h.update(data)?; - h.finish2() + h.finish_xof(buf) } #[cfg(test)] mod tests { - use hex::{FromHex, ToHex}; + use hex::{self, FromHex}; use std::io::prelude::*; use super::*; fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) { - let res = hash2(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap(); - assert_eq!(res.to_hex(), hashtest.1); + let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap(); + assert_eq!(hex::encode(res), hashtest.1); + } + + #[cfg(ossl111)] + fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) { + let expected = Vec::from_hex(hashtest.1).unwrap(); + let mut buf = vec![0; expected.len()]; + hash_xof( + hashtype, + &Vec::from_hex(hashtest.0).unwrap(), + buf.as_mut_slice(), + ) + .unwrap(); + assert_eq!(buf, expected); } fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { - let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap(); - let res = h.finish2().unwrap(); - assert_eq!(res.to_hex(), hashtest.1); + h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap(); + let res = h.finish().unwrap(); + assert_eq!(hex::encode(res), hashtest.1); } // Test vectors from http://www.nsrl.nist.gov/testdata/ - #[allow(non_upper_case_globals)] - const md5_tests: [(&'static str, &'static str); 13] = - [ - ("", "d41d8cd98f00b204e9800998ecf8427e"), - ("7F", "83acb6e67e50e31db6ed341dd2de1595"), - ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), - ("FEE57A", "e0d583171eb06d56198fc0ef22173907"), - ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), - ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), - ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), - ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), - ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), - ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), - ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), - ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), - ( - "AAED18DBE8938C19ED734A8D", - "6f80fb775f27e0a4ce5c2f42fc72c5f1", - ), - ]; + const MD5_TESTS: [(&str, &str); 13] = [ + ("", "d41d8cd98f00b204e9800998ecf8427e"), + ("7F", "83acb6e67e50e31db6ed341dd2de1595"), + ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), + ("FEE57A", "e0d583171eb06d56198fc0ef22173907"), + ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), + ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), + ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), + ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), + ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), + ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), + ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), + ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), + ( + "AAED18DBE8938C19ED734A8D", + "6f80fb775f27e0a4ce5c2f42fc72c5f1", + ), + ]; #[test] fn test_md5() { - for test in md5_tests.iter() { + for test in MD5_TESTS.iter() { hash_test(MessageDigest::md5(), test); } + + 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] fn test_md5_recycle() { let mut h = Hasher::new(MessageDigest::md5()).unwrap(); - for test in md5_tests.iter() { + for test in MD5_TESTS.iter() { hash_recycle_test(&mut h, test); } } @@ -335,18 +533,19 @@ mod tests { #[test] fn test_finish_twice() { let mut h = Hasher::new(MessageDigest::md5()).unwrap(); - h.write_all(&Vec::from_hex(md5_tests[6].0).unwrap()) + h.write_all(&Vec::from_hex(MD5_TESTS[6].0).unwrap()) .unwrap(); - h.finish2().unwrap(); - let res = h.finish2().unwrap(); - let null = hash2(MessageDigest::md5(), &[]).unwrap(); + h.finish().unwrap(); + let res = h.finish().unwrap(); + let null = hash(MessageDigest::md5(), &[]).unwrap(); assert_eq!(&*res, &*null); } #[test] + #[allow(clippy::redundant_clone)] fn test_clone() { let i = 7; - let inp = Vec::from_hex(md5_tests[i].0).unwrap(); + let inp = Vec::from_hex(MD5_TESTS[i].0).unwrap(); assert!(inp.len() > 2); let p = inp.len() / 2; let h0 = Hasher::new(MessageDigest::md5()).unwrap(); @@ -358,19 +557,19 @@ mod tests { println!("Clone an updated hasher"); let mut h2 = h1.clone(); h2.write_all(&inp[p..]).unwrap(); - let res = h2.finish2().unwrap(); - assert_eq!(res.to_hex(), md5_tests[i].1); + let res = h2.finish().unwrap(); + assert_eq!(hex::encode(res), MD5_TESTS[i].1); } h1.write_all(&inp[p..]).unwrap(); - let res = h1.finish2().unwrap(); - assert_eq!(res.to_hex(), md5_tests[i].1); + let res = h1.finish().unwrap(); + assert_eq!(hex::encode(res), MD5_TESTS[i].1); println!("Clone a finished hasher"); let mut h3 = h1.clone(); - h3.write_all(&Vec::from_hex(md5_tests[i + 1].0).unwrap()) + h3.write_all(&Vec::from_hex(MD5_TESTS[i + 1].0).unwrap()) .unwrap(); - let res = h3.finish2().unwrap(); - assert_eq!(res.to_hex(), md5_tests[i + 1].1); + let res = h3.finish().unwrap(); + assert_eq!(hex::encode(res), MD5_TESTS[i + 1].1); } #[test] @@ -380,28 +579,222 @@ mod tests { for test in tests.iter() { hash_test(MessageDigest::sha1(), test); } + + 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] fn test_sha256() { - let tests = [ - ( - "616263", - "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - ), - ]; + let tests = [( + "616263", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + )]; for test in tests.iter() { hash_test(MessageDigest::sha256(), test); } + + 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)] + #[test] + fn test_sha3_224() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913", + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_224(), test); + } + + 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)] + #[test] + fn test_sha3_256() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61", + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_256(), test); + } + + 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)] #[test] + fn test_sha3_384() { + let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\ + ef2008ff16" + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_384(), test); + } + + 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)] + #[test] + fn test_sha3_512() { + let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\ + 807caee3a79f8eb02dcd61589fbbdf5f40c8787a72" + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_512(), test); + } + + 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)] + #[test] + fn test_shake_128() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "49d0697ff508111d8b84f15e46daf135", + )]; + + for test in tests.iter() { + hash_xof_test(MessageDigest::shake_128(), test); + } + + 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)] + #[test] + fn test_shake_256() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697", + )]; + + for test in tests.iter() { + hash_xof_test(MessageDigest::shake_256(), test); + } + + 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] + #[cfg(not(boringssl))] + #[cfg_attr(ossl300, ignore)] fn test_ripemd160() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")]; for test in tests.iter() { hash_test(MessageDigest::ripemd160(), test); } + + 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")))] + #[test] + fn test_sm3() { + let tests = [( + "616263", + "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sm3(), test); + } + + 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] + fn from_nid() { + assert_eq!( + MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(), + MessageDigest::sha256().as_ptr() + ); + } + + #[test] + fn from_name() { + assert_eq!( + MessageDigest::from_name("SHA256").unwrap().as_ptr(), + MessageDigest::sha256().as_ptr() + ) } } diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 5c3e7cc..5678298 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,27 +1,132 @@ -#![doc(html_root_url="https://docs.rs/openssl/0.9")] - -#[macro_use] -extern crate bitflags; -#[macro_use] -extern crate foreign_types; -extern crate libc; -#[macro_use] -extern crate lazy_static; -extern crate openssl_sys as ffi; - -#[cfg(test)] -extern crate hex; -#[cfg(test)] -extern crate tempdir; -#[cfg(test)] -extern crate data_encoding; +//! Bindings to OpenSSL +//! +//! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through +//! 3.x.x and LibreSSL versions 2.5 through 3.4.1 are supported. +//! +//! # Building +//! +//! Both OpenSSL libraries and headers are required to build this crate. There are multiple options available to locate +//! OpenSSL. +//! +//! ## Vendored +//! +//! If the `vendored` Cargo feature is enabled, the `openssl-src` crate will be used to compile and statically link to +//! a copy of OpenSSL. The build process requires a C compiler, perl (and perl-core), and make. The OpenSSL version will generally track +//! the newest OpenSSL release, and changes to the version are *not* considered breaking changes. +//! +//! ```toml +//! [dependencies] +//! openssl = { version = "0.10", features = ["vendored"] } +//! ``` +//! +//! The vendored copy will not be configured to automatically find the system's root certificates, but the +//! `openssl-probe` crate can be used to do that instead. +//! +//! ## Automatic +//! +//! The `openssl-sys` crate will automatically detect OpenSSL installations via Homebrew on macOS and vcpkg on Windows. +//! Additionally, it will use `pkg-config` on Unix-like systems to find the system installation. +//! +//! ```not_rust +//! # macOS (Homebrew) +//! $ brew install openssl@3 +//! +//! # macOS (MacPorts) +//! $ sudo port install openssl +//! +//! # macOS (pkgsrc) +//! $ sudo pkgin install openssl +//! +//! # Arch Linux +//! $ sudo pacman -S pkg-config openssl +//! +//! # Debian and Ubuntu +//! $ sudo apt-get install pkg-config libssl-dev +//! +//! # Fedora +//! $ sudo dnf install pkg-config openssl-devel +//! +//! # Alpine Linux +//! $ apk add pkgconfig openssl-dev +//! ``` +//! +//! ## Manual +//! +//! A set of environment variables can be used to point `openssl-sys` towards an OpenSSL installation. They will +//! override the automatic detection logic. +//! +//! * `OPENSSL_DIR` - If specified, the directory of an OpenSSL installation. The directory should contain `lib` and +//! `include` subdirectories containing the libraries and headers respectively. +//! * `OPENSSL_LIB_DIR` and `OPENSSL_INCLUDE_DIR` - If specified, the directories containing the OpenSSL libraries and +//! headers respectively. This can be used if the OpenSSL installation is split in a nonstandard directory layout. +//! * `OPENSSL_STATIC` - If set, the crate will statically link to OpenSSL rather than dynamically link. +//! * `OPENSSL_LIBS` - If set, a `:`-separated list of library names to link to (e.g. `ssl:crypto`). This can be used +//! if nonstandard library names were used for whatever reason. +//! * `OPENSSL_NO_VENDOR` - If set, always find OpenSSL in the system, even if the `vendored` feature is enabled. +//! +//! Additionally, these variables can be prefixed with the upper-cased target architecture (e.g. +//! `X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR`), which can be useful when cross compiling. +//! +//! # Feature Detection +//! +//! APIs have been added to and removed from the various supported OpenSSL versions, and this library exposes the +//! functionality available in the version being linked against. This means that methods, constants, and even modules +//! will be present when building against one version of OpenSSL but not when building against another! APIs will +//! document any version-specific availability restrictions. +//! +//! A build script can be used to detect the OpenSSL or LibreSSL version at compile time if needed. The `openssl-sys` +//! crate propagates the version via the `DEP_OPENSSL_VERSION_NUMBER` and `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER` +//! environment variables to build scripts. The version format is a hex-encoding of the OpenSSL release version: +//! `0xMNNFFPPS`. For example, version 1.0.2g's encoding is `0x1_00_02_07_0`. +//! +//! For example, let's say we want to adjust the TLSv1.3 cipher suites used by a client, but also want to compile +//! against OpenSSL versions that don't support TLSv1.3: +//! +//! Cargo.toml: +//! +//! ```toml +//! [dependencies] +//! openssl-sys = "0.9" +//! openssl = "0.10" +//! ``` +//! +//! build.rs: +//! +//! ``` +//! use std::env; +//! +//! fn main() { +//! if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") { +//! let version = u64::from_str_radix(&v, 16).unwrap(); +//! +//! if version >= 0x1_01_01_00_0 { +//! println!("cargo:rustc-cfg=openssl111"); +//! } +//! } +//! } +//! ``` +//! +//! lib.rs: +//! +//! ``` +//! use openssl::ssl::{SslConnector, SslMethod}; +//! +//! let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap(); +//! +//! // set_ciphersuites was added in OpenSSL 1.1.1, so we can only call it when linking against that version +//! #[cfg(openssl111)] +//! ctx.set_ciphersuites("TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256").unwrap(); +//! ``` +#![doc(html_root_url = "https://docs.rs/openssl/0.10")] +#![warn(rust_2018_idioms)] +#![allow(clippy::uninlined_format_args)] #[doc(inline)] pub use ffi::init; use libc::c_int; -use error::ErrorStack; +use crate::error::ErrorStack; #[macro_use] mod macros; @@ -31,38 +136,66 @@ mod bio; mod util; pub mod aes; pub mod asn1; +pub mod base64; pub mod bn; -#[cfg(not(libressl))] +pub mod cipher; +pub mod cipher_ctx; +#[cfg(all(not(boringssl), not(libressl), not(osslconf = "OPENSSL_NO_CMS")))] pub mod cms; pub mod conf; -pub mod crypto; +pub mod derive; pub mod dh; pub mod dsa; pub mod ec; -pub mod ec_key; +pub mod ecdsa; +pub mod encrypt; +#[cfg(not(boringssl))] +pub mod envelope; pub mod error; pub mod ex_data; +#[cfg(not(any(libressl, ossl300)))] +pub mod fips; pub mod hash; +#[cfg(ossl300)] +pub mod lib_ctx; +pub mod md; +pub mod md_ctx; pub mod memcmp; pub mod nid; +#[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_OCSP")))] pub mod ocsp; pub mod pkcs12; +#[cfg(not(boringssl))] pub mod pkcs5; +#[cfg(not(boringssl))] +pub mod pkcs7; pub mod pkey; +pub mod pkey_ctx; +#[cfg(ossl300)] +pub mod provider; pub mod rand; pub mod rsa; -pub mod sign; pub mod sha; +pub mod sign; +pub mod srtp; pub mod ssl; pub mod stack; pub mod string; pub mod symm; -pub mod types; pub mod version; pub mod x509; -#[cfg(any(ossl102, ossl110))] -mod verify; +#[cfg(boringssl)] +type LenType = libc::size_t; +#[cfg(not(boringssl))] +type LenType = libc::c_int; + +#[cfg(boringssl)] +type SLenType = libc::ssize_t; +#[cfg(not(boringssl))] +type SLenType = libc::c_int; + +#[inline] fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Err(ErrorStack::get()) @@ -71,6 +204,7 @@ fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { } } +#[inline] fn cvt(r: c_int) -> Result { if r <= 0 { Err(ErrorStack::get()) @@ -79,6 +213,11 @@ fn cvt(r: c_int) -> Result { } } +#[inline] fn cvt_n(r: c_int) -> Result { - if r < 0 { Err(ErrorStack::get()) } else { Ok(r) } + if r < 0 { + Err(ErrorStack::get()) + } else { + Ok(r) + } } diff --git a/openssl/src/lib_ctx.rs b/openssl/src/lib_ctx.rs new file mode 100644 index 0000000..1fcdc65 --- /dev/null +++ b/openssl/src/lib_ctx.rs @@ -0,0 +1,22 @@ +use crate::cvt_p; +use crate::error::ErrorStack; +use foreign_types::ForeignType; +use openssl_macros::corresponds; + +foreign_type_and_impl_send_sync! { + type CType = ffi::OSSL_LIB_CTX; + fn drop = ffi::OSSL_LIB_CTX_free; + + pub struct LibCtx; + pub struct LibCtxRef; +} + +impl LibCtx { + #[corresponds(OSSL_LIB_CTX_new)] + pub fn new() -> Result { + unsafe { + let ptr = cvt_p(ffi::OSSL_LIB_CTX_new())?; + Ok(LibCtx::from_ptr(ptr)) + } + } +} diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 721f4b0..671a11b 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -1,221 +1,136 @@ - macro_rules! private_key_from_pem { - ($t:ident, $f:path) => { - from_pem_inner!(/// Deserializes a PEM-formatted private key. - private_key_from_pem, $t, $f); - - /// Deserializes a PEM-formatted private key, using the supplied password if the key is - /// encrypted. - /// - /// # Panics - /// - /// Panics if `passphrase` contains an embedded null. - pub fn private_key_from_pem_passphrase(pem: &[u8], - passphrase: &[u8]) - -> Result<$t, ::error::ErrorStack> { + ($(#[$m:meta])* $n:ident, $(#[$m2:meta])* $n2:ident, $(#[$m3:meta])* $n3:ident, $t:ty, $f:path) => { + from_pem!($(#[$m])* $n, $t, $f); + + $(#[$m2])* + pub fn $n2(pem: &[u8], passphrase: &[u8]) -> Result<$t, crate::error::ErrorStack> { unsafe { ffi::init(); - let bio = try!(::bio::MemBioSlice::new(pem)); + let bio = crate::bio::MemBioSlice::new(pem)?; let passphrase = ::std::ffi::CString::new(passphrase).unwrap(); cvt_p($f(bio.as_ptr(), ptr::null_mut(), None, passphrase.as_ptr() as *const _ as *mut _)) - .map($t) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } - /// Deserializes a PEM-formatted private key, using a callback to retrieve a password if the - /// key is encrypted. - /// - /// The callback should copy the password into the provided buffer and return the number of - /// bytes written. - pub fn private_key_from_pem_callback(pem: &[u8], - callback: F) - -> Result<$t, ::error::ErrorStack> - where F: FnOnce(&mut [u8]) -> Result + $(#[$m3])* + pub fn $n3(pem: &[u8], callback: F) -> Result<$t, crate::error::ErrorStack> + where F: FnOnce(&mut [u8]) -> Result { unsafe { ffi::init(); - let mut cb = ::util::CallbackState::new(callback); - let bio = try!(::bio::MemBioSlice::new(pem)); + let mut cb = crate::util::CallbackState::new(callback); + let bio = crate::bio::MemBioSlice::new(pem)?; cvt_p($f(bio.as_ptr(), ptr::null_mut(), - Some(::util::invoke_passwd_cb::), + Some(crate::util::invoke_passwd_cb::), &mut cb as *mut _ as *mut _)) - .map($t) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } } } macro_rules! private_key_to_pem { - ($f:path) => { - /// Serializes the private key to PEM. - pub fn private_key_to_pem(&self) -> Result, ::error::ErrorStack> { + ($(#[$m:meta])* $n:ident, $(#[$m2:meta])* $n2:ident, $f:path) => { + $(#[$m])* + pub fn $n(&self) -> Result, crate::error::ErrorStack> { unsafe { - let bio = try!(::bio::MemBio::new()); - try!(cvt($f(bio.as_ptr(), - self.as_ptr(), - ptr::null(), - ptr::null_mut(), - -1, - None, - ptr::null_mut()))); + let bio = crate::bio::MemBio::new()?; + cvt($f(bio.as_ptr(), + self.as_ptr(), + ptr::null(), + ptr::null_mut(), + -1, + None, + ptr::null_mut()))?; Ok(bio.get_buf().to_owned()) } } - /// Serializes the private key to PEM, encrypting it with the specified symmetric cipher and - /// passphrase. - pub fn private_key_to_pem_passphrase(&self, - cipher: ::symm::Cipher, - passphrase: &[u8]) - -> Result, ::error::ErrorStack> { + $(#[$m2])* + pub fn $n2( + &self, + cipher: crate::symm::Cipher, + passphrase: &[u8] + ) -> Result, crate::error::ErrorStack> { unsafe { - let bio = try!(::bio::MemBio::new()); + let bio = crate::bio::MemBio::new()?; assert!(passphrase.len() <= ::libc::c_int::max_value() as usize); - try!(cvt($f(bio.as_ptr(), - self.as_ptr(), - cipher.as_ptr(), - passphrase.as_ptr() as *const _ as *mut _, - passphrase.len() as ::libc::c_int, - None, - ptr::null_mut()))); + cvt($f(bio.as_ptr(), + self.as_ptr(), + cipher.as_ptr(), + passphrase.as_ptr() as *const _ as *mut _, + passphrase.len() as ::libc::c_int, + None, + ptr::null_mut()))?; Ok(bio.get_buf().to_owned()) } } } } -macro_rules! to_pem_inner { - (#[$m:meta] $n:ident, $f:path) => { - #[$m] - pub fn $n(&self) -> Result, ::error::ErrorStack> { +macro_rules! to_pem { + ($(#[$m:meta])* $n:ident, $f:path) => { + $(#[$m])* + pub fn $n(&self) -> Result, crate::error::ErrorStack> { unsafe { - let bio = try!(::bio::MemBio::new()); - try!(cvt($f(bio.as_ptr(), self.as_ptr()))); + let bio = crate::bio::MemBio::new()?; + cvt($f(bio.as_ptr(), self.as_ptr()))?; Ok(bio.get_buf().to_owned()) } } } } -macro_rules! public_key_to_pem { - ($f:path) => { - to_pem_inner!(/// Serializes a public key to PEM. - public_key_to_pem, $f); - } -} - -macro_rules! to_pem { - ($f:path) => { - to_pem_inner!(/// Serializes this value to PEM. - to_pem, $f); - } -} - -macro_rules! to_der_inner { - (#[$m:meta] $n:ident, $f:path) => { - #[$m] - pub fn $n(&self) -> Result, ::error::ErrorStack> { +macro_rules! to_der { + ($(#[$m:meta])* $n:ident, $f:path) => { + $(#[$m])* + pub fn $n(&self) -> Result, crate::error::ErrorStack> { unsafe { - let len = try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), - ptr::null_mut()))); + let len = crate::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), + ptr::null_mut()))?; let mut buf = vec![0; len as usize]; - try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), - &mut buf.as_mut_ptr()))); + crate::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), + &mut buf.as_mut_ptr()))?; Ok(buf) } } }; } -macro_rules! to_der { - ($f:path) => { - to_der_inner!(/// Serializes this value to DER. - to_der, $f); - } -} - -macro_rules! private_key_to_der { - ($f:path) => { - to_der_inner!(/// Serializes the private key to DER. - private_key_to_der, $f); - } -} - -macro_rules! public_key_to_der { - ($f:path) => { - to_der_inner!(/// Serializes the public key to DER. - public_key_to_der, $f); - } -} - -macro_rules! from_der_inner { - (#[$m:meta] $n:ident, $t:ident, $f:path) => { - #[$m] - pub fn $n(der: &[u8]) -> Result<$t, ::error::ErrorStack> { +macro_rules! from_der { + ($(#[$m:meta])* $n:ident, $t:ty, $f:path) => { + $(#[$m])* + pub fn $n(der: &[u8]) -> Result<$t, crate::error::ErrorStack> { + use std::convert::TryInto; unsafe { - ::ffi::init(); + ffi::init(); let len = ::std::cmp::min(der.len(), ::libc::c_long::max_value() as usize) as ::libc::c_long; - ::cvt_p($f(::std::ptr::null_mut(), &mut der.as_ptr(), len)) - .map($t) + crate::cvt_p($f(::std::ptr::null_mut(), &mut der.as_ptr(), len.try_into().unwrap())) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } } } -macro_rules! from_der { - ($t:ident, $f:path) => { - from_der_inner!(/// Deserializes a value from DER-formatted data. - from_der, $t, $f); - } -} - -macro_rules! private_key_from_der { - ($t:ident, $f:path) => { - from_der_inner!(/// Deserializes a private key from DER-formatted data. - private_key_from_der, $t, $f); - } -} - -macro_rules! public_key_from_der { - ($t:ident, $f:path) => { - from_der_inner!(/// Deserializes a public key from DER-formatted data. - public_key_from_der, $t, $f); - } -} - -macro_rules! from_pem_inner { - (#[$m:meta] $n:ident, $t:ident, $f:path) => { - #[$m] - pub fn $n(pem: &[u8]) -> Result<$t, ::error::ErrorStack> { +macro_rules! from_pem { + ($(#[$m:meta])* $n:ident, $t:ty, $f:path) => { + $(#[$m])* + pub fn $n(pem: &[u8]) -> Result<$t, crate::error::ErrorStack> { unsafe { - ::init(); - let bio = try!(::bio::MemBioSlice::new(pem)); + crate::init(); + let bio = crate::bio::MemBioSlice::new(pem)?; cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut())) - .map($t) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } } } -macro_rules! public_key_from_pem { - ($t:ident, $f:path) => { - from_pem_inner!(/// Deserializes a public key from PEM-formatted data. - public_key_from_pem, $t, $f); - } -} - -macro_rules! from_pem { - ($t:ident, $f:path) => { - from_pem_inner!(/// Deserializes a value from PEM-formatted data. - from_pem, $t, $f); - } -} - - macro_rules! foreign_type_and_impl_send_sync { ( $(#[$impl_attr:meta])* @@ -229,7 +144,7 @@ macro_rules! foreign_type_and_impl_send_sync { pub struct $borrowed:ident; ) => { - foreign_type! { + ::foreign_types::foreign_type! { $(#[$impl_attr])* type CType = $ctype; fn drop = $drop; @@ -246,3 +161,110 @@ macro_rules! foreign_type_and_impl_send_sync { unsafe impl Sync for $borrowed{} }; } + +macro_rules! generic_foreign_type_and_impl_send_sync { + ( + $(#[$impl_attr:meta])* + type CType = $ctype:ty; + fn drop = $drop:expr; + $(fn clone = $clone:expr;)* + + $(#[$owned_attr:meta])* + pub struct $owned:ident; + $(#[$borrowed_attr:meta])* + pub struct $borrowed:ident; + ) => { + $(#[$owned_attr])* + pub struct $owned(*mut $ctype, ::std::marker::PhantomData); + + $(#[$impl_attr])* + impl ::foreign_types::ForeignType for $owned { + type CType = $ctype; + type Ref = $borrowed; + + #[inline] + unsafe fn from_ptr(ptr: *mut $ctype) -> $owned { + $owned(ptr, ::std::marker::PhantomData) + } + + #[inline] + fn as_ptr(&self) -> *mut $ctype { + self.0 + } + } + + impl Drop for $owned { + #[inline] + fn drop(&mut self) { + unsafe { $drop(self.0) } + } + } + + $( + impl Clone for $owned { + #[inline] + fn clone(&self) -> $owned { + unsafe { + let handle: *mut $ctype = $clone(self.0); + ::foreign_types::ForeignType::from_ptr(handle) + } + } + } + + impl ::std::borrow::ToOwned for $borrowed { + type Owned = $owned; + #[inline] + fn to_owned(&self) -> $owned { + unsafe { + let handle: *mut $ctype = + $clone(::foreign_types::ForeignTypeRef::as_ptr(self)); + $crate::ForeignType::from_ptr(handle) + } + } + } + )* + + impl ::std::ops::Deref for $owned { + type Target = $borrowed; + + #[inline] + fn deref(&self) -> &$borrowed { + unsafe { ::foreign_types::ForeignTypeRef::from_ptr(self.0) } + } + } + + impl ::std::ops::DerefMut for $owned { + #[inline] + fn deref_mut(&mut self) -> &mut $borrowed { + unsafe { ::foreign_types::ForeignTypeRef::from_ptr_mut(self.0) } + } + } + + impl ::std::borrow::Borrow<$borrowed> for $owned { + #[inline] + fn borrow(&self) -> &$borrowed { + &**self + } + } + + impl ::std::convert::AsRef<$borrowed> for $owned { + #[inline] + fn as_ref(&self) -> &$borrowed { + &**self + } + } + + $(#[$borrowed_attr])* + pub struct $borrowed(::foreign_types::Opaque, ::std::marker::PhantomData); + + $(#[$impl_attr])* + impl ::foreign_types::ForeignTypeRef for $borrowed { + type CType = $ctype; + } + + unsafe impl Send for $owned{} + unsafe impl Send for $borrowed{} + unsafe impl Sync for $owned{} + unsafe impl Sync for $borrowed{} + }; +} diff --git a/openssl/src/md.rs b/openssl/src/md.rs new file mode 100644 index 0000000..4ade8e8 --- /dev/null +++ b/openssl/src/md.rs @@ -0,0 +1,235 @@ +//! Message digest algorithms. + +#[cfg(ossl300)] +use crate::cvt_p; +#[cfg(ossl300)] +use crate::error::ErrorStack; +#[cfg(ossl300)] +use crate::lib_ctx::LibCtxRef; +use crate::nid::Nid; +use cfg_if::cfg_if; +use foreign_types::{ForeignTypeRef, Opaque}; +use openssl_macros::corresponds; +#[cfg(ossl300)] +use std::ffi::CString; +#[cfg(ossl300)] +use std::ptr; + +cfg_if! { + if #[cfg(ossl300)] { + use foreign_types::ForeignType; + use std::ops::{Deref, DerefMut}; + + type Inner = *mut ffi::EVP_MD; + + impl Drop for Md { + #[inline] + fn drop(&mut self) { + unsafe { + ffi::EVP_MD_free(self.as_ptr()); + } + } + } + + impl ForeignType for Md { + type CType = ffi::EVP_MD; + type Ref = MdRef; + + #[inline] + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { + Md(ptr) + } + + #[inline] + fn as_ptr(&self) -> *mut Self::CType { + self.0 + } + } + + impl Deref for Md { + type Target = MdRef; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + MdRef::from_ptr(self.as_ptr()) + } + } + } + + impl DerefMut for Md { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + MdRef::from_ptr_mut(self.as_ptr()) + } + } + } + } else { + enum Inner {} + } +} + +/// A message digest algorithm. +pub struct Md(Inner); + +unsafe impl Sync for Md {} +unsafe impl Send for Md {} + +impl Md { + /// Returns the `Md` corresponding to an [`Nid`]. + #[corresponds(EVP_get_digestbynid)] + pub fn from_nid(type_: Nid) -> Option<&'static MdRef> { + unsafe { + let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); + if ptr.is_null() { + None + } else { + Some(MdRef::from_ptr(ptr as *mut _)) + } + } + } + + /// Fetches an `Md` object corresponding to the specified algorithm name and properties. + /// + /// Requires OpenSSL 3.0.0 or newer. + #[corresponds(EVP_MD_fetch)] + #[cfg(ossl300)] + pub fn fetch( + ctx: Option<&LibCtxRef>, + algorithm: &str, + properties: Option<&str>, + ) -> Result { + let algorithm = CString::new(algorithm).unwrap(); + let properties = properties.map(|s| CString::new(s).unwrap()); + + unsafe { + let ptr = cvt_p(ffi::EVP_MD_fetch( + ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + algorithm.as_ptr(), + properties.map_or(ptr::null_mut(), |s| s.as_ptr()), + ))?; + + Ok(Md::from_ptr(ptr)) + } + } + + #[inline] + #[cfg(not(boringssl))] + pub fn null() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_md_null() as *mut _) } + } + + #[inline] + pub fn md5() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_md5() as *mut _) } + } + + #[inline] + pub fn sha1() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha1() as *mut _) } + } + + #[inline] + pub fn sha224() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha224() as *mut _) } + } + + #[inline] + pub fn sha256() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha256() as *mut _) } + } + + #[inline] + pub fn sha384() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha384() as *mut _) } + } + + #[inline] + pub fn sha512() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha512() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_224() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_224() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_256() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_256() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_384() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_384() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_512() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_512() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn shake128() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_shake128() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn shake256() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_shake256() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))] + #[inline] + #[cfg(not(boringssl))] + pub fn ripemd160() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_ripemd160() as *mut _) } + } + + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))] + #[inline] + #[cfg(not(boringssl))] + pub fn sm3() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sm3() as *mut _) } + } +} + +/// A reference to an [`Md`]. +pub struct MdRef(Opaque); + +impl ForeignTypeRef for MdRef { + type CType = ffi::EVP_MD; +} + +unsafe impl Sync for MdRef {} +unsafe impl Send for MdRef {} + +impl MdRef { + /// Returns the block size of the digest in bytes. + #[corresponds(EVP_MD_block_size)] + #[inline] + pub fn block_size(&self) -> usize { + unsafe { ffi::EVP_MD_block_size(self.as_ptr()) as usize } + } + + /// Returns the size of the digest in bytes. + #[corresponds(EVP_MD_size)] + #[inline] + pub fn size(&self) -> usize { + unsafe { ffi::EVP_MD_size(self.as_ptr()) as usize } + } + + /// Returns the [`Nid`] of the digest. + #[corresponds(EVP_MD_type)] + #[inline] + pub fn type_(&self) -> Nid { + unsafe { Nid::from_raw(ffi::EVP_MD_type(self.as_ptr())) } + } +} diff --git a/openssl/src/md_ctx.rs b/openssl/src/md_ctx.rs new file mode 100644 index 0000000..c4d3f06 --- /dev/null +++ b/openssl/src/md_ctx.rs @@ -0,0 +1,540 @@ +//! The message digest context. +//! +//! # Examples +//! +//! Compute the SHA256 checksum of data +//! +//! ``` +//! use openssl::md::Md; +//! use openssl::md_ctx::MdCtx; +//! +//! let mut ctx = MdCtx::new().unwrap(); +//! ctx.digest_init(Md::sha256()).unwrap(); +//! ctx.digest_update(b"Some Crypto Text").unwrap(); +//! let mut digest = [0; 32]; +//! ctx.digest_final(&mut digest).unwrap(); +//! +//! assert_eq!( +//! digest, +//! *b"\x60\x78\x56\x38\x8a\xca\x5c\x51\x83\xc4\xd1\x4d\xc8\xf9\xcc\xf2\ +//! \xa5\x21\xb3\x10\x93\x72\xfa\xd6\x7c\x55\xf5\xc9\xe3\xd1\x83\x19", +//! ); +//! ``` +//! +//! Sign and verify data with RSA and SHA256 +//! +//! ``` +//! use openssl::md::Md; +//! use openssl::md_ctx::MdCtx; +//! use openssl::pkey::PKey; +//! use openssl::rsa::Rsa; +//! +//! // Generate a random RSA key. +//! let key = Rsa::generate(4096).unwrap(); +//! let key = PKey::from_rsa(key).unwrap(); +//! +//! let text = b"Some Crypto Text"; +//! +//! // Create the signature. +//! let mut ctx = MdCtx::new().unwrap(); +//! ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap(); +//! ctx.digest_sign_update(text).unwrap(); +//! let mut signature = vec![]; +//! ctx.digest_sign_final_to_vec(&mut signature).unwrap(); +//! +//! // Verify the signature. +//! let mut ctx = MdCtx::new().unwrap(); +//! ctx.digest_verify_init(Some(Md::sha256()), &key).unwrap(); +//! ctx.digest_verify_update(text).unwrap(); +//! let valid = ctx.digest_verify_final(&signature).unwrap(); +//! 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, HasPublic, PKeyRef}; +use crate::pkey_ctx::PkeyCtxRef; +use crate::{cvt, cvt_n, cvt_p}; +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef}; +use openssl_macros::corresponds; +use std::convert::TryFrom; +use std::ptr; + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::EVP_MD_CTX; + fn drop = EVP_MD_CTX_free; + + pub struct MdCtx; + /// A reference to an [`MdCtx`]. + pub struct MdCtxRef; +} + +impl MdCtx { + /// Creates a new context. + #[corresponds(EVP_MD_CTX_new)] + #[inline] + pub fn new() -> Result { + ffi::init(); + + unsafe { + let ptr = cvt_p(EVP_MD_CTX_new())?; + Ok(MdCtx::from_ptr(ptr)) + } + } +} + +impl MdCtxRef { + /// Initializes the context to compute the digest of data. + #[corresponds(EVP_DigestInit_ex)] + #[inline] + pub fn digest_init(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_DigestInit_ex( + self.as_ptr(), + digest.as_ptr(), + ptr::null_mut(), + ))?; + } + + Ok(()) + } + + /// Initializes the context to compute the signature of data. + /// + /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured. + #[corresponds(EVP_DigestSignInit)] + #[inline] + pub fn digest_sign_init<'a, T>( + &'a mut self, + digest: Option<&MdRef>, + pkey: &PKeyRef, + ) -> Result<&'a mut PkeyCtxRef, ErrorStack> + where + T: HasPrivate, + { + unsafe { + let mut p = ptr::null_mut(); + cvt(ffi::EVP_DigestSignInit( + self.as_ptr(), + &mut p, + digest.map_or(ptr::null(), |p| p.as_ptr()), + ptr::null_mut(), + pkey.as_ptr(), + ))?; + Ok(PkeyCtxRef::from_ptr_mut(p)) + } + } + + /// Initializes the context to verify the signature of data. + /// + /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured. + #[corresponds(EVP_DigestVerifyInit)] + #[inline] + pub fn digest_verify_init<'a, T>( + &'a mut self, + digest: Option<&MdRef>, + pkey: &PKeyRef, + ) -> Result<&'a mut PkeyCtxRef, ErrorStack> + where + T: HasPublic, + { + unsafe { + let mut p = ptr::null_mut(); + cvt(ffi::EVP_DigestVerifyInit( + self.as_ptr(), + &mut p, + digest.map_or(ptr::null(), |p| p.as_ptr()), + ptr::null_mut(), + pkey.as_ptr(), + ))?; + Ok(PkeyCtxRef::from_ptr_mut(p)) + } + } + + /// Updates the context with more data. + #[corresponds(EVP_DigestUpdate)] + #[inline] + pub fn digest_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_DigestUpdate( + self.as_ptr(), + data.as_ptr() as *const _, + data.len(), + ))?; + } + + Ok(()) + } + + /// Updates the context with more data. + #[corresponds(EVP_DigestSignUpdate)] + #[inline] + pub fn digest_sign_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_DigestSignUpdate( + self.as_ptr(), + data.as_ptr() as *const _, + data.len(), + ))?; + } + + Ok(()) + } + + /// Updates the context with more data. + #[corresponds(EVP_DigestVerifyUpdate)] + #[inline] + pub fn digest_verify_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_DigestVerifyUpdate( + self.as_ptr(), + data.as_ptr() as *const _, + data.len(), + ))?; + } + + Ok(()) + } + + /// Copies the computed digest into the buffer, returning the number of bytes written. + #[corresponds(EVP_DigestFinal)] + #[inline] + pub fn digest_final(&mut self, out: &mut [u8]) -> Result { + let mut len = u32::try_from(out.len()).unwrap_or(u32::MAX); + + unsafe { + cvt(ffi::EVP_DigestFinal( + self.as_ptr(), + out.as_mut_ptr(), + &mut len, + ))?; + } + + Ok(len as usize) + } + + /// Copies the computed digest into the buffer. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(EVP_DigestFinalXOF)] + #[inline] + #[cfg(ossl111)] + pub fn digest_final_xof(&mut self, out: &mut [u8]) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_DigestFinalXOF( + self.as_ptr(), + out.as_mut_ptr(), + out.len(), + ))?; + } + + Ok(()) + } + + /// Signs the computed digest. + /// + /// If `out` is set to `None`, an upper bound on the number of bytes required for the output buffer will be + /// returned. + #[corresponds(EVP_DigestSignFinal)] + #[inline] + pub fn digest_sign_final(&mut self, out: Option<&mut [u8]>) -> Result { + let mut len = out.as_ref().map_or(0, |b| b.len()); + + unsafe { + cvt(ffi::EVP_DigestSignFinal( + self.as_ptr(), + out.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut len, + ))?; + } + + Ok(len) + } + + /// Like [`Self::digest_sign_final`] but appends the signature to a [`Vec`]. + pub fn digest_sign_final_to_vec(&mut self, out: &mut Vec) -> Result { + let base = out.len(); + let len = self.digest_sign_final(None)?; + out.resize(base + len, 0); + let len = self.digest_sign_final(Some(&mut out[base..]))?; + out.truncate(base + len); + Ok(len) + } + + /// Verifies the provided signature. + /// + /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error + /// occurred. + #[corresponds(EVP_DigestVerifyFinal)] + #[inline] + pub fn digest_verify_final(&mut self, signature: &[u8]) -> Result { + unsafe { + let r = cvt_n(ffi::EVP_DigestVerifyFinal( + self.as_ptr(), + signature.as_ptr() as *mut _, + signature.len(), + ))?; + Ok(r == 1) + } + } + + /// Computes the signature of the data in `from`. + /// + /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be + /// returned. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(EVP_DigestSign)] + #[cfg(ossl111)] + #[inline] + pub fn digest_sign(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { + let mut len = to.as_ref().map_or(0, |b| b.len()); + + unsafe { + cvt(ffi::EVP_DigestSign( + self.as_ptr(), + to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut len, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(len) + } + + /// Like [`Self::digest_sign`] but appends the signature to a [`Vec`]. + #[cfg(ossl111)] + pub fn digest_sign_to_vec( + &mut self, + from: &[u8], + to: &mut Vec, + ) -> Result { + let base = to.len(); + let len = self.digest_sign(from, None)?; + to.resize(base + len, 0); + let len = self.digest_sign(from, Some(&mut to[base..]))?; + to.truncate(base + len); + Ok(len) + } + + /// Verifies the signature of the data in `data`. + /// + /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error + /// occurred. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(EVP_DigestVerify)] + #[cfg(ossl111)] + #[inline] + pub fn digest_verify(&mut self, data: &[u8], signature: &[u8]) -> Result { + unsafe { + let r = cvt(ffi::EVP_DigestVerify( + self.as_ptr(), + signature.as_ptr(), + signature.len(), + data.as_ptr(), + data.len(), + ))?; + 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)] +mod test { + use super::*; + use crate::md::Md; + use crate::pkey::PKey; + use crate::rsa::Rsa; + + #[test] + fn verify_fail() { + let key1 = Rsa::generate(4096).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 bad_data = b"Some Crypto text"; + + ctx.digest_verify_init(Some(md), &key1).unwrap(); + ctx.digest_verify_update(bad_data).unwrap(); + 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/openssl/src/memcmp.rs index 3b831e6..91281b9 100644 --- a/openssl/src/memcmp.rs +++ b/openssl/src/memcmp.rs @@ -12,7 +12,7 @@ //! //! # Examples //! -//! To perform a constant-time comparision of two arrays of the same length but different +//! To perform a constant-time comparison of two arrays of the same length but different //! values: //! //! ``` @@ -30,7 +30,7 @@ //! assert!(!eq(&a, &c)); //! ``` use libc::size_t; -use ffi; +use openssl_macros::corresponds; /// Returns `true` iff `a` and `b` contain the same bytes. /// @@ -44,7 +44,7 @@ use ffi; /// /// # Examples /// -/// To perform a constant-time comparision of two arrays of the same length but different +/// To perform a constant-time comparison of two arrays of the same length but different /// values: /// /// ``` @@ -61,6 +61,7 @@ use ffi; /// assert!(!eq(&a, &b)); /// assert!(!eq(&a, &c)); /// ``` +#[corresponds(CRYPTO_memcmp)] pub fn eq(a: &[u8], b: &[u8]) -> bool { assert!(a.len() == b.len()); let ret = unsafe { diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index df1090c..e4562a1 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -1,6 +1,24 @@ //! A collection of numerical identifiers for OpenSSL objects. -use ffi; -use libc::c_int; +use libc::{c_char, c_int}; + +use std::ffi::CStr; +use std::ffi::CString; +use std::str; + +use crate::cvt_p; +use crate::error::ErrorStack; +use openssl_macros::corresponds; + +/// The digest and public-key algorithms associated with a signature. +pub struct SignatureAlgorithms { + /// The signature's digest. + /// + /// If the signature does not specify a digest, this will be `NID::UNDEF`. + pub digest: Nid, + + /// The signature's public-key. + pub pkey: Nid, +} /// A numerical identifier for an OpenSSL object. /// @@ -16,9 +34,9 @@ use libc::c_int; /// To view the integer representation of a `Nid`: /// /// ``` -/// use openssl::nid; +/// use openssl::nid::Nid; /// -/// assert!(nid::AES_256_GCM.as_raw() == 901); +/// assert!(Nid::AES_256_GCM.as_raw() == 901); /// ``` /// /// # External Documentation @@ -26,7 +44,7 @@ use libc::c_int; /// The following documentation provides context about `Nid`s and their usage /// in OpenSSL. /// -/// - [Obj_nid2obj](https://www.openssl.org/docs/man1.1.0/crypto/OBJ_create.html) +/// - [Obj_nid2obj](https://www.openssl.org/docs/manmaster/crypto/OBJ_create.html) #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Nid(c_int); @@ -38,945 +56,1119 @@ impl Nid { } /// Return the integer representation of a `Nid`. + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } + + /// Creates a new `Nid` for the `oid` with short name `sn` and long name `ln`. + #[corresponds(OBJ_create)] + pub fn create(oid: &str, sn: &str, ln: &str) -> Result { + unsafe { + ffi::init(); + let oid = CString::new(oid).unwrap(); + let sn = CString::new(sn).unwrap(); + let ln = CString::new(ln).unwrap(); + let raw = ffi::OBJ_create(oid.as_ptr(), sn.as_ptr(), ln.as_ptr()); + if raw == ffi::NID_undef { + Err(ErrorStack::get()) + } else { + Ok(Nid(raw)) + } + } + } + + /// Returns the `Nid`s of the digest and public key algorithms associated with a signature ID. + /// + /// This corresponds to `OBJ_find_sigid_algs`. + #[corresponds(OBJ_find_sigid_algs)] + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn signature_algorithms(&self) -> Option { + unsafe { + let mut digest = 0; + let mut pkey = 0; + if ffi::OBJ_find_sigid_algs(self.0, &mut digest, &mut pkey) == 1 { + Some(SignatureAlgorithms { + digest: Nid(digest), + pkey: Nid(pkey), + }) + } else { + None + } + } + } + + /// Returns the string representation of a `Nid` (long). + #[corresponds(OBJ_nid2ln)] + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn long_name(&self) -> Result<&'static str, ErrorStack> { + unsafe { + cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) + } + } + + /// Returns the string representation of a `Nid` (short). + #[corresponds(OBJ_nid2sn)] + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn short_name(&self) -> Result<&'static str, ErrorStack> { + unsafe { + cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) + } + } + + pub const UNDEF: Nid = Nid(ffi::NID_undef); + pub const ITU_T: Nid = Nid(ffi::NID_itu_t); + #[cfg(not(boringssl))] + pub const CCITT: Nid = Nid(ffi::NID_ccitt); + pub const ISO: Nid = Nid(ffi::NID_iso); + pub const JOINT_ISO_ITU_T: Nid = Nid(ffi::NID_joint_iso_itu_t); + #[cfg(not(boringssl))] + pub const JOINT_ISO_CCITT: Nid = Nid(ffi::NID_joint_iso_ccitt); + pub const MEMBER_BODY: Nid = Nid(ffi::NID_member_body); + pub const IDENTIFIED_ORGANIZATION: Nid = Nid(ffi::NID_identified_organization); + pub const HMAC_MD5: Nid = Nid(ffi::NID_hmac_md5); + pub const HMAC_SHA1: Nid = Nid(ffi::NID_hmac_sha1); + pub const CERTICOM_ARC: Nid = Nid(ffi::NID_certicom_arc); + pub const INTERNATIONAL_ORGANIZATIONS: Nid = Nid(ffi::NID_international_organizations); + pub const WAP: Nid = Nid(ffi::NID_wap); + pub const WAP_WSG: Nid = Nid(ffi::NID_wap_wsg); + pub const SELECTED_ATTRIBUTE_TYPES: Nid = Nid(ffi::NID_selected_attribute_types); + pub const CLEARANCE: Nid = Nid(ffi::NID_clearance); + pub const ISO_US: Nid = Nid(ffi::NID_ISO_US); + pub const X9_57: Nid = Nid(ffi::NID_X9_57); + pub const X9CM: Nid = Nid(ffi::NID_X9cm); + pub const DSA: Nid = Nid(ffi::NID_dsa); + pub const DSAWITHSHA1: Nid = Nid(ffi::NID_dsaWithSHA1); + pub const ANSI_X9_62: Nid = Nid(ffi::NID_ansi_X9_62); + pub const X9_62_PRIME_FIELD: Nid = Nid(ffi::NID_X9_62_prime_field); + pub const X9_62_CHARACTERISTIC_TWO_FIELD: Nid = Nid(ffi::NID_X9_62_characteristic_two_field); + pub const X9_62_ID_CHARACTERISTIC_TWO_BASIS: Nid = + Nid(ffi::NID_X9_62_id_characteristic_two_basis); + pub const X9_62_ONBASIS: Nid = Nid(ffi::NID_X9_62_onBasis); + pub const X9_62_TPBASIS: Nid = Nid(ffi::NID_X9_62_tpBasis); + pub const X9_62_PPBASIS: Nid = Nid(ffi::NID_X9_62_ppBasis); + pub const X9_62_ID_ECPUBLICKEY: Nid = Nid(ffi::NID_X9_62_id_ecPublicKey); + pub const X9_62_C2PNB163V1: Nid = Nid(ffi::NID_X9_62_c2pnb163v1); + pub const X9_62_C2PNB163V2: Nid = Nid(ffi::NID_X9_62_c2pnb163v2); + pub const X9_62_C2PNB163V3: Nid = Nid(ffi::NID_X9_62_c2pnb163v3); + pub const X9_62_C2PNB176V1: Nid = Nid(ffi::NID_X9_62_c2pnb176v1); + pub const X9_62_C2TNB191V1: Nid = Nid(ffi::NID_X9_62_c2tnb191v1); + pub const X9_62_C2TNB191V2: Nid = Nid(ffi::NID_X9_62_c2tnb191v2); + pub const X9_62_C2TNB191V3: Nid = Nid(ffi::NID_X9_62_c2tnb191v3); + pub const X9_62_C2ONB191V4: Nid = Nid(ffi::NID_X9_62_c2onb191v4); + pub const X9_62_C2ONB191V5: Nid = Nid(ffi::NID_X9_62_c2onb191v5); + pub const X9_62_C2PNB208W1: Nid = Nid(ffi::NID_X9_62_c2pnb208w1); + pub const X9_62_C2TNB239V1: Nid = Nid(ffi::NID_X9_62_c2tnb239v1); + pub const X9_62_C2TNB239V2: Nid = Nid(ffi::NID_X9_62_c2tnb239v2); + pub const X9_62_C2TNB239V3: Nid = Nid(ffi::NID_X9_62_c2tnb239v3); + pub const X9_62_C2ONB239V4: Nid = Nid(ffi::NID_X9_62_c2onb239v4); + pub const X9_62_C2ONB239V5: Nid = Nid(ffi::NID_X9_62_c2onb239v5); + pub const X9_62_C2PNB272W1: Nid = Nid(ffi::NID_X9_62_c2pnb272w1); + pub const X9_62_C2PNB304W1: Nid = Nid(ffi::NID_X9_62_c2pnb304w1); + pub const X9_62_C2TNB359V1: Nid = Nid(ffi::NID_X9_62_c2tnb359v1); + pub const X9_62_C2PNB368W1: Nid = Nid(ffi::NID_X9_62_c2pnb368w1); + pub const X9_62_C2TNB431R1: Nid = Nid(ffi::NID_X9_62_c2tnb431r1); + pub const X9_62_PRIME192V1: Nid = Nid(ffi::NID_X9_62_prime192v1); + pub const X9_62_PRIME192V2: Nid = Nid(ffi::NID_X9_62_prime192v2); + pub const X9_62_PRIME192V3: Nid = Nid(ffi::NID_X9_62_prime192v3); + pub const X9_62_PRIME239V1: Nid = Nid(ffi::NID_X9_62_prime239v1); + pub const X9_62_PRIME239V2: Nid = Nid(ffi::NID_X9_62_prime239v2); + pub const X9_62_PRIME239V3: Nid = Nid(ffi::NID_X9_62_prime239v3); + pub const X9_62_PRIME256V1: Nid = Nid(ffi::NID_X9_62_prime256v1); + pub const ECDSA_WITH_SHA1: Nid = Nid(ffi::NID_ecdsa_with_SHA1); + pub const ECDSA_WITH_RECOMMENDED: Nid = Nid(ffi::NID_ecdsa_with_Recommended); + pub const ECDSA_WITH_SPECIFIED: Nid = Nid(ffi::NID_ecdsa_with_Specified); + pub const ECDSA_WITH_SHA224: Nid = Nid(ffi::NID_ecdsa_with_SHA224); + pub const ECDSA_WITH_SHA256: Nid = Nid(ffi::NID_ecdsa_with_SHA256); + pub const ECDSA_WITH_SHA384: Nid = Nid(ffi::NID_ecdsa_with_SHA384); + pub const ECDSA_WITH_SHA512: Nid = Nid(ffi::NID_ecdsa_with_SHA512); + pub const SECP112R1: Nid = Nid(ffi::NID_secp112r1); + pub const SECP112R2: Nid = Nid(ffi::NID_secp112r2); + pub const SECP128R1: Nid = Nid(ffi::NID_secp128r1); + pub const SECP128R2: Nid = Nid(ffi::NID_secp128r2); + pub const SECP160K1: Nid = Nid(ffi::NID_secp160k1); + pub const SECP160R1: Nid = Nid(ffi::NID_secp160r1); + pub const SECP160R2: Nid = Nid(ffi::NID_secp160r2); + pub const SECP192K1: Nid = Nid(ffi::NID_secp192k1); + pub const SECP224K1: Nid = Nid(ffi::NID_secp224k1); + pub const SECP224R1: Nid = Nid(ffi::NID_secp224r1); + pub const SECP256K1: Nid = Nid(ffi::NID_secp256k1); + pub const SECP384R1: Nid = Nid(ffi::NID_secp384r1); + pub const SECP521R1: Nid = Nid(ffi::NID_secp521r1); + pub const SECT113R1: Nid = Nid(ffi::NID_sect113r1); + pub const SECT113R2: Nid = Nid(ffi::NID_sect113r2); + pub const SECT131R1: Nid = Nid(ffi::NID_sect131r1); + pub const SECT131R2: Nid = Nid(ffi::NID_sect131r2); + pub const SECT163K1: Nid = Nid(ffi::NID_sect163k1); + pub const SECT163R1: Nid = Nid(ffi::NID_sect163r1); + pub const SECT163R2: Nid = Nid(ffi::NID_sect163r2); + pub const SECT193R1: Nid = Nid(ffi::NID_sect193r1); + pub const SECT193R2: Nid = Nid(ffi::NID_sect193r2); + pub const SECT233K1: Nid = Nid(ffi::NID_sect233k1); + pub const SECT233R1: Nid = Nid(ffi::NID_sect233r1); + pub const SECT239K1: Nid = Nid(ffi::NID_sect239k1); + pub const SECT283K1: Nid = Nid(ffi::NID_sect283k1); + pub const SECT283R1: Nid = Nid(ffi::NID_sect283r1); + pub const SECT409K1: Nid = Nid(ffi::NID_sect409k1); + 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); + pub const WAP_WSG_IDM_ECID_WTLS5: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls5); + pub const WAP_WSG_IDM_ECID_WTLS6: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls6); + pub const WAP_WSG_IDM_ECID_WTLS7: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls7); + pub const WAP_WSG_IDM_ECID_WTLS8: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls8); + pub const WAP_WSG_IDM_ECID_WTLS9: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls9); + pub const WAP_WSG_IDM_ECID_WTLS10: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls10); + pub const WAP_WSG_IDM_ECID_WTLS11: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls11); + pub const WAP_WSG_IDM_ECID_WTLS12: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls12); + pub const CAST5_CBC: Nid = Nid(ffi::NID_cast5_cbc); + pub const CAST5_ECB: Nid = Nid(ffi::NID_cast5_ecb); + pub const CAST5_CFB64: Nid = Nid(ffi::NID_cast5_cfb64); + pub const CAST5_OFB64: Nid = Nid(ffi::NID_cast5_ofb64); + pub const PBEWITHMD5ANDCAST5_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndCast5_CBC); + pub const ID_PASSWORDBASEDMAC: Nid = Nid(ffi::NID_id_PasswordBasedMAC); + pub const ID_DHBASEDMAC: Nid = Nid(ffi::NID_id_DHBasedMac); + pub const RSADSI: Nid = Nid(ffi::NID_rsadsi); + pub const PKCS: Nid = Nid(ffi::NID_pkcs); + pub const PKCS1: Nid = Nid(ffi::NID_pkcs1); + pub const RSAENCRYPTION: Nid = Nid(ffi::NID_rsaEncryption); + pub const MD2WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md2WithRSAEncryption); + pub const MD4WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md4WithRSAEncryption); + pub const MD5WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md5WithRSAEncryption); + pub const SHA1WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha1WithRSAEncryption); + pub const RSAESOAEP: Nid = Nid(ffi::NID_rsaesOaep); + pub const MGF1: Nid = Nid(ffi::NID_mgf1); + pub const RSASSAPSS: Nid = Nid(ffi::NID_rsassaPss); + pub const SHA256WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha256WithRSAEncryption); + pub const SHA384WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha384WithRSAEncryption); + pub const SHA512WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha512WithRSAEncryption); + pub const SHA224WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha224WithRSAEncryption); + pub const PKCS3: Nid = Nid(ffi::NID_pkcs3); + pub const DHKEYAGREEMENT: Nid = Nid(ffi::NID_dhKeyAgreement); + pub const PKCS5: Nid = Nid(ffi::NID_pkcs5); + pub const PBEWITHMD2ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndDES_CBC); + pub const PBEWITHMD5ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndDES_CBC); + pub const PBEWITHMD2ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndRC2_CBC); + pub const PBEWITHMD5ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndRC2_CBC); + pub const PBEWITHSHA1ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndDES_CBC); + pub const PBEWITHSHA1ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndRC2_CBC); + pub const ID_PBKDF2: Nid = Nid(ffi::NID_id_pbkdf2); + pub const PBES2: Nid = Nid(ffi::NID_pbes2); + pub const PBMAC1: Nid = Nid(ffi::NID_pbmac1); + pub const PKCS7: Nid = Nid(ffi::NID_pkcs7); + pub const PKCS7_DATA: Nid = Nid(ffi::NID_pkcs7_data); + pub const PKCS7_SIGNED: Nid = Nid(ffi::NID_pkcs7_signed); + pub const PKCS7_ENVELOPED: Nid = Nid(ffi::NID_pkcs7_enveloped); + pub const PKCS7_SIGNEDANDENVELOPED: Nid = Nid(ffi::NID_pkcs7_signedAndEnveloped); + pub const PKCS7_DIGEST: Nid = Nid(ffi::NID_pkcs7_digest); + pub const PKCS7_ENCRYPTED: Nid = Nid(ffi::NID_pkcs7_encrypted); + pub const PKCS9: Nid = Nid(ffi::NID_pkcs9); + pub const PKCS9_EMAILADDRESS: Nid = Nid(ffi::NID_pkcs9_emailAddress); + pub const PKCS9_UNSTRUCTUREDNAME: Nid = Nid(ffi::NID_pkcs9_unstructuredName); + pub const PKCS9_CONTENTTYPE: Nid = Nid(ffi::NID_pkcs9_contentType); + pub const PKCS9_MESSAGEDIGEST: Nid = Nid(ffi::NID_pkcs9_messageDigest); + pub const PKCS9_SIGNINGTIME: Nid = Nid(ffi::NID_pkcs9_signingTime); + pub const PKCS9_COUNTERSIGNATURE: Nid = Nid(ffi::NID_pkcs9_countersignature); + pub const PKCS9_CHALLENGEPASSWORD: Nid = Nid(ffi::NID_pkcs9_challengePassword); + pub const PKCS9_UNSTRUCTUREDADDRESS: Nid = Nid(ffi::NID_pkcs9_unstructuredAddress); + pub const PKCS9_EXTCERTATTRIBUTES: Nid = Nid(ffi::NID_pkcs9_extCertAttributes); + pub const EXT_REQ: Nid = Nid(ffi::NID_ext_req); + pub const SMIMECAPABILITIES: Nid = Nid(ffi::NID_SMIMECapabilities); + pub const SMIME: Nid = Nid(ffi::NID_SMIME); + pub const ID_SMIME_MOD: Nid = Nid(ffi::NID_id_smime_mod); + pub const ID_SMIME_CT: Nid = Nid(ffi::NID_id_smime_ct); + pub const ID_SMIME_AA: Nid = Nid(ffi::NID_id_smime_aa); + pub const ID_SMIME_ALG: Nid = Nid(ffi::NID_id_smime_alg); + pub const ID_SMIME_CD: Nid = Nid(ffi::NID_id_smime_cd); + pub const ID_SMIME_SPQ: Nid = Nid(ffi::NID_id_smime_spq); + pub const ID_SMIME_CTI: Nid = Nid(ffi::NID_id_smime_cti); + pub const ID_SMIME_MOD_CMS: Nid = Nid(ffi::NID_id_smime_mod_cms); + pub const ID_SMIME_MOD_ESS: Nid = Nid(ffi::NID_id_smime_mod_ess); + pub const ID_SMIME_MOD_OID: Nid = Nid(ffi::NID_id_smime_mod_oid); + pub const ID_SMIME_MOD_MSG_V3: Nid = Nid(ffi::NID_id_smime_mod_msg_v3); + pub const ID_SMIME_MOD_ETS_ESIGNATURE_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_88); + pub const ID_SMIME_MOD_ETS_ESIGNATURE_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_97); + pub const ID_SMIME_MOD_ETS_ESIGPOLICY_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_88); + pub const ID_SMIME_MOD_ETS_ESIGPOLICY_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_97); + pub const ID_SMIME_CT_RECEIPT: Nid = Nid(ffi::NID_id_smime_ct_receipt); + pub const ID_SMIME_CT_AUTHDATA: Nid = Nid(ffi::NID_id_smime_ct_authData); + pub const ID_SMIME_CT_PUBLISHCERT: Nid = Nid(ffi::NID_id_smime_ct_publishCert); + pub const ID_SMIME_CT_TSTINFO: Nid = Nid(ffi::NID_id_smime_ct_TSTInfo); + pub const ID_SMIME_CT_TDTINFO: Nid = Nid(ffi::NID_id_smime_ct_TDTInfo); + pub const ID_SMIME_CT_CONTENTINFO: Nid = Nid(ffi::NID_id_smime_ct_contentInfo); + pub const ID_SMIME_CT_DVCSREQUESTDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSRequestData); + pub const ID_SMIME_CT_DVCSRESPONSEDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSResponseData); + pub const ID_SMIME_CT_COMPRESSEDDATA: Nid = Nid(ffi::NID_id_smime_ct_compressedData); + pub const ID_CT_ASCIITEXTWITHCRLF: Nid = Nid(ffi::NID_id_ct_asciiTextWithCRLF); + pub const ID_SMIME_AA_RECEIPTREQUEST: Nid = Nid(ffi::NID_id_smime_aa_receiptRequest); + pub const ID_SMIME_AA_SECURITYLABEL: Nid = Nid(ffi::NID_id_smime_aa_securityLabel); + pub const ID_SMIME_AA_MLEXPANDHISTORY: Nid = Nid(ffi::NID_id_smime_aa_mlExpandHistory); + pub const ID_SMIME_AA_CONTENTHINT: Nid = Nid(ffi::NID_id_smime_aa_contentHint); + pub const ID_SMIME_AA_MSGSIGDIGEST: Nid = Nid(ffi::NID_id_smime_aa_msgSigDigest); + pub const ID_SMIME_AA_ENCAPCONTENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_encapContentType); + pub const ID_SMIME_AA_CONTENTIDENTIFIER: Nid = Nid(ffi::NID_id_smime_aa_contentIdentifier); + pub const ID_SMIME_AA_MACVALUE: Nid = Nid(ffi::NID_id_smime_aa_macValue); + pub const ID_SMIME_AA_EQUIVALENTLABELS: Nid = Nid(ffi::NID_id_smime_aa_equivalentLabels); + pub const ID_SMIME_AA_CONTENTREFERENCE: Nid = Nid(ffi::NID_id_smime_aa_contentReference); + pub const ID_SMIME_AA_ENCRYPKEYPREF: Nid = Nid(ffi::NID_id_smime_aa_encrypKeyPref); + pub const ID_SMIME_AA_SIGNINGCERTIFICATE: Nid = Nid(ffi::NID_id_smime_aa_signingCertificate); + pub const ID_SMIME_AA_SMIMEENCRYPTCERTS: Nid = Nid(ffi::NID_id_smime_aa_smimeEncryptCerts); + pub const ID_SMIME_AA_TIMESTAMPTOKEN: Nid = Nid(ffi::NID_id_smime_aa_timeStampToken); + pub const ID_SMIME_AA_ETS_SIGPOLICYID: Nid = Nid(ffi::NID_id_smime_aa_ets_sigPolicyId); + pub const ID_SMIME_AA_ETS_COMMITMENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_ets_commitmentType); + pub const ID_SMIME_AA_ETS_SIGNERLOCATION: Nid = Nid(ffi::NID_id_smime_aa_ets_signerLocation); + pub const ID_SMIME_AA_ETS_SIGNERATTR: Nid = Nid(ffi::NID_id_smime_aa_ets_signerAttr); + pub const ID_SMIME_AA_ETS_OTHERSIGCERT: Nid = Nid(ffi::NID_id_smime_aa_ets_otherSigCert); + pub const ID_SMIME_AA_ETS_CONTENTTIMESTAMP: Nid = + Nid(ffi::NID_id_smime_aa_ets_contentTimestamp); + pub const ID_SMIME_AA_ETS_CERTIFICATEREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_CertificateRefs); + pub const ID_SMIME_AA_ETS_REVOCATIONREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_RevocationRefs); + pub const ID_SMIME_AA_ETS_CERTVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_certValues); + pub const ID_SMIME_AA_ETS_REVOCATIONVALUES: Nid = + Nid(ffi::NID_id_smime_aa_ets_revocationValues); + pub const ID_SMIME_AA_ETS_ESCTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_escTimeStamp); + pub const ID_SMIME_AA_ETS_CERTCRLTIMESTAMP: Nid = + Nid(ffi::NID_id_smime_aa_ets_certCRLTimestamp); + pub const ID_SMIME_AA_ETS_ARCHIVETIMESTAMP: Nid = + Nid(ffi::NID_id_smime_aa_ets_archiveTimeStamp); + pub const ID_SMIME_AA_SIGNATURETYPE: Nid = Nid(ffi::NID_id_smime_aa_signatureType); + pub const ID_SMIME_AA_DVCS_DVC: Nid = Nid(ffi::NID_id_smime_aa_dvcs_dvc); + pub const ID_SMIME_ALG_ESDHWITH3DES: Nid = Nid(ffi::NID_id_smime_alg_ESDHwith3DES); + pub const ID_SMIME_ALG_ESDHWITHRC2: Nid = Nid(ffi::NID_id_smime_alg_ESDHwithRC2); + pub const ID_SMIME_ALG_3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_3DESwrap); + pub const ID_SMIME_ALG_RC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_RC2wrap); + pub const ID_SMIME_ALG_ESDH: Nid = Nid(ffi::NID_id_smime_alg_ESDH); + pub const ID_SMIME_ALG_CMS3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_CMS3DESwrap); + pub const ID_SMIME_ALG_CMSRC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_CMSRC2wrap); + pub const ID_ALG_PWRI_KEK: Nid = Nid(ffi::NID_id_alg_PWRI_KEK); + pub const ID_SMIME_CD_LDAP: Nid = Nid(ffi::NID_id_smime_cd_ldap); + pub const ID_SMIME_SPQ_ETS_SQT_URI: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_uri); + pub const ID_SMIME_SPQ_ETS_SQT_UNOTICE: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_unotice); + pub const ID_SMIME_CTI_ETS_PROOFOFORIGIN: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfOrigin); + pub const ID_SMIME_CTI_ETS_PROOFOFRECEIPT: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfReceipt); + pub const ID_SMIME_CTI_ETS_PROOFOFDELIVERY: Nid = + Nid(ffi::NID_id_smime_cti_ets_proofOfDelivery); + pub const ID_SMIME_CTI_ETS_PROOFOFSENDER: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfSender); + pub const ID_SMIME_CTI_ETS_PROOFOFAPPROVAL: Nid = + Nid(ffi::NID_id_smime_cti_ets_proofOfApproval); + pub const ID_SMIME_CTI_ETS_PROOFOFCREATION: Nid = + Nid(ffi::NID_id_smime_cti_ets_proofOfCreation); + pub const FRIENDLYNAME: Nid = Nid(ffi::NID_friendlyName); + pub const LOCALKEYID: Nid = Nid(ffi::NID_localKeyID); + pub const MS_CSP_NAME: Nid = Nid(ffi::NID_ms_csp_name); + pub const LOCALKEYSET: Nid = Nid(ffi::NID_LocalKeySet); + pub const X509CERTIFICATE: Nid = Nid(ffi::NID_x509Certificate); + pub const SDSICERTIFICATE: Nid = Nid(ffi::NID_sdsiCertificate); + pub const X509CRL: Nid = Nid(ffi::NID_x509Crl); + pub const PBE_WITHSHA1AND128BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC4); + pub const PBE_WITHSHA1AND40BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC4); + pub const PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC: Nid = + Nid(ffi::NID_pbe_WithSHA1And3_Key_TripleDES_CBC); + pub const PBE_WITHSHA1AND2_KEY_TRIPLEDES_CBC: Nid = + Nid(ffi::NID_pbe_WithSHA1And2_Key_TripleDES_CBC); + pub const PBE_WITHSHA1AND128BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC2_CBC); + pub const PBE_WITHSHA1AND40BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC2_CBC); + pub const KEYBAG: Nid = Nid(ffi::NID_keyBag); + pub const PKCS8SHROUDEDKEYBAG: Nid = Nid(ffi::NID_pkcs8ShroudedKeyBag); + pub const CERTBAG: Nid = Nid(ffi::NID_certBag); + pub const CRLBAG: Nid = Nid(ffi::NID_crlBag); + pub const SECRETBAG: Nid = Nid(ffi::NID_secretBag); + pub const SAFECONTENTSBAG: Nid = Nid(ffi::NID_safeContentsBag); + pub const MD2: Nid = Nid(ffi::NID_md2); + pub const MD4: Nid = Nid(ffi::NID_md4); + pub const MD5: Nid = Nid(ffi::NID_md5); + pub const MD5_SHA1: Nid = Nid(ffi::NID_md5_sha1); + pub const HMACWITHMD5: Nid = Nid(ffi::NID_hmacWithMD5); + pub const HMACWITHSHA1: Nid = Nid(ffi::NID_hmacWithSHA1); + pub const HMACWITHSHA224: Nid = Nid(ffi::NID_hmacWithSHA224); + pub const HMACWITHSHA256: Nid = Nid(ffi::NID_hmacWithSHA256); + pub const HMACWITHSHA384: Nid = Nid(ffi::NID_hmacWithSHA384); + pub const HMACWITHSHA512: Nid = Nid(ffi::NID_hmacWithSHA512); + pub const RC2_CBC: Nid = Nid(ffi::NID_rc2_cbc); + pub const RC2_ECB: Nid = Nid(ffi::NID_rc2_ecb); + pub const RC2_CFB64: Nid = Nid(ffi::NID_rc2_cfb64); + pub const RC2_OFB64: Nid = Nid(ffi::NID_rc2_ofb64); + pub const RC2_40_CBC: Nid = Nid(ffi::NID_rc2_40_cbc); + pub const RC2_64_CBC: Nid = Nid(ffi::NID_rc2_64_cbc); + pub const RC4: Nid = Nid(ffi::NID_rc4); + pub const RC4_40: Nid = Nid(ffi::NID_rc4_40); + pub const DES_EDE3_CBC: Nid = Nid(ffi::NID_des_ede3_cbc); + pub const RC5_CBC: Nid = Nid(ffi::NID_rc5_cbc); + pub const RC5_ECB: Nid = Nid(ffi::NID_rc5_ecb); + pub const RC5_CFB64: Nid = Nid(ffi::NID_rc5_cfb64); + pub const RC5_OFB64: Nid = Nid(ffi::NID_rc5_ofb64); + pub const MS_EXT_REQ: Nid = Nid(ffi::NID_ms_ext_req); + pub const MS_CODE_IND: Nid = Nid(ffi::NID_ms_code_ind); + pub const MS_CODE_COM: Nid = Nid(ffi::NID_ms_code_com); + pub const MS_CTL_SIGN: Nid = Nid(ffi::NID_ms_ctl_sign); + pub const MS_SGC: Nid = Nid(ffi::NID_ms_sgc); + pub const MS_EFS: Nid = Nid(ffi::NID_ms_efs); + pub const MS_SMARTCARD_LOGIN: Nid = Nid(ffi::NID_ms_smartcard_login); + pub const MS_UPN: Nid = Nid(ffi::NID_ms_upn); + pub const IDEA_CBC: Nid = Nid(ffi::NID_idea_cbc); + pub const IDEA_ECB: Nid = Nid(ffi::NID_idea_ecb); + pub const IDEA_CFB64: Nid = Nid(ffi::NID_idea_cfb64); + pub const IDEA_OFB64: Nid = Nid(ffi::NID_idea_ofb64); + pub const BF_CBC: Nid = Nid(ffi::NID_bf_cbc); + pub const BF_ECB: Nid = Nid(ffi::NID_bf_ecb); + pub const BF_CFB64: Nid = Nid(ffi::NID_bf_cfb64); + pub const BF_OFB64: Nid = Nid(ffi::NID_bf_ofb64); + pub const ID_PKIX: Nid = Nid(ffi::NID_id_pkix); + pub const ID_PKIX_MOD: Nid = Nid(ffi::NID_id_pkix_mod); + pub const ID_PE: Nid = Nid(ffi::NID_id_pe); + pub const ID_QT: Nid = Nid(ffi::NID_id_qt); + pub const ID_KP: Nid = Nid(ffi::NID_id_kp); + pub const ID_IT: Nid = Nid(ffi::NID_id_it); + pub const ID_PKIP: Nid = Nid(ffi::NID_id_pkip); + pub const ID_ALG: Nid = Nid(ffi::NID_id_alg); + pub const ID_CMC: Nid = Nid(ffi::NID_id_cmc); + pub const ID_ON: Nid = Nid(ffi::NID_id_on); + pub const ID_PDA: Nid = Nid(ffi::NID_id_pda); + pub const ID_ACA: Nid = Nid(ffi::NID_id_aca); + pub const ID_QCS: Nid = Nid(ffi::NID_id_qcs); + pub const ID_CCT: Nid = Nid(ffi::NID_id_cct); + pub const ID_PPL: Nid = Nid(ffi::NID_id_ppl); + pub const ID_AD: Nid = Nid(ffi::NID_id_ad); + pub const ID_PKIX1_EXPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_explicit_88); + pub const ID_PKIX1_IMPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_implicit_88); + pub const ID_PKIX1_EXPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_explicit_93); + pub const ID_PKIX1_IMPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_implicit_93); + pub const ID_MOD_CRMF: Nid = Nid(ffi::NID_id_mod_crmf); + pub const ID_MOD_CMC: Nid = Nid(ffi::NID_id_mod_cmc); + pub const ID_MOD_KEA_PROFILE_88: Nid = Nid(ffi::NID_id_mod_kea_profile_88); + pub const ID_MOD_KEA_PROFILE_93: Nid = Nid(ffi::NID_id_mod_kea_profile_93); + pub const ID_MOD_CMP: Nid = Nid(ffi::NID_id_mod_cmp); + pub const ID_MOD_QUALIFIED_CERT_88: Nid = Nid(ffi::NID_id_mod_qualified_cert_88); + pub const ID_MOD_QUALIFIED_CERT_93: Nid = Nid(ffi::NID_id_mod_qualified_cert_93); + pub const ID_MOD_ATTRIBUTE_CERT: Nid = Nid(ffi::NID_id_mod_attribute_cert); + pub const ID_MOD_TIMESTAMP_PROTOCOL: Nid = Nid(ffi::NID_id_mod_timestamp_protocol); + pub const ID_MOD_OCSP: Nid = Nid(ffi::NID_id_mod_ocsp); + pub const ID_MOD_DVCS: Nid = Nid(ffi::NID_id_mod_dvcs); + pub const ID_MOD_CMP2000: Nid = Nid(ffi::NID_id_mod_cmp2000); + pub const INFO_ACCESS: Nid = Nid(ffi::NID_info_access); + pub const BIOMETRICINFO: Nid = Nid(ffi::NID_biometricInfo); + pub const QCSTATEMENTS: Nid = Nid(ffi::NID_qcStatements); + pub const AC_AUDITENTITY: Nid = Nid(ffi::NID_ac_auditEntity); + pub const AC_TARGETING: Nid = Nid(ffi::NID_ac_targeting); + pub const AACONTROLS: Nid = Nid(ffi::NID_aaControls); + pub const SBGP_IPADDRBLOCK: Nid = Nid(ffi::NID_sbgp_ipAddrBlock); + pub const SBGP_AUTONOMOUSSYSNUM: Nid = Nid(ffi::NID_sbgp_autonomousSysNum); + pub const SBGP_ROUTERIDENTIFIER: Nid = Nid(ffi::NID_sbgp_routerIdentifier); + pub const AC_PROXYING: Nid = Nid(ffi::NID_ac_proxying); + pub const SINFO_ACCESS: Nid = Nid(ffi::NID_sinfo_access); + pub const PROXYCERTINFO: Nid = Nid(ffi::NID_proxyCertInfo); + pub const ID_QT_CPS: Nid = Nid(ffi::NID_id_qt_cps); + pub const ID_QT_UNOTICE: Nid = Nid(ffi::NID_id_qt_unotice); + pub const TEXTNOTICE: Nid = Nid(ffi::NID_textNotice); + pub const SERVER_AUTH: Nid = Nid(ffi::NID_server_auth); + pub const CLIENT_AUTH: Nid = Nid(ffi::NID_client_auth); + pub const CODE_SIGN: Nid = Nid(ffi::NID_code_sign); + pub const EMAIL_PROTECT: Nid = Nid(ffi::NID_email_protect); + pub const IPSECENDSYSTEM: Nid = Nid(ffi::NID_ipsecEndSystem); + pub const IPSECTUNNEL: Nid = Nid(ffi::NID_ipsecTunnel); + pub const IPSECUSER: Nid = Nid(ffi::NID_ipsecUser); + pub const TIME_STAMP: Nid = Nid(ffi::NID_time_stamp); + pub const OCSP_SIGN: Nid = Nid(ffi::NID_OCSP_sign); + pub const DVCS: Nid = Nid(ffi::NID_dvcs); + pub const ID_IT_CAPROTENCCERT: Nid = Nid(ffi::NID_id_it_caProtEncCert); + pub const ID_IT_SIGNKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_signKeyPairTypes); + pub const ID_IT_ENCKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_encKeyPairTypes); + pub const ID_IT_PREFERREDSYMMALG: Nid = Nid(ffi::NID_id_it_preferredSymmAlg); + pub const ID_IT_CAKEYUPDATEINFO: Nid = Nid(ffi::NID_id_it_caKeyUpdateInfo); + pub const ID_IT_CURRENTCRL: Nid = Nid(ffi::NID_id_it_currentCRL); + pub const ID_IT_UNSUPPORTEDOIDS: Nid = Nid(ffi::NID_id_it_unsupportedOIDs); + pub const ID_IT_SUBSCRIPTIONREQUEST: Nid = Nid(ffi::NID_id_it_subscriptionRequest); + pub const ID_IT_SUBSCRIPTIONRESPONSE: Nid = Nid(ffi::NID_id_it_subscriptionResponse); + pub const ID_IT_KEYPAIRPARAMREQ: Nid = Nid(ffi::NID_id_it_keyPairParamReq); + pub const ID_IT_KEYPAIRPARAMREP: Nid = Nid(ffi::NID_id_it_keyPairParamRep); + pub const ID_IT_REVPASSPHRASE: Nid = Nid(ffi::NID_id_it_revPassphrase); + pub const ID_IT_IMPLICITCONFIRM: Nid = Nid(ffi::NID_id_it_implicitConfirm); + pub const ID_IT_CONFIRMWAITTIME: Nid = Nid(ffi::NID_id_it_confirmWaitTime); + pub const ID_IT_ORIGPKIMESSAGE: Nid = Nid(ffi::NID_id_it_origPKIMessage); + pub const ID_IT_SUPPLANGTAGS: Nid = Nid(ffi::NID_id_it_suppLangTags); + pub const ID_REGCTRL: Nid = Nid(ffi::NID_id_regCtrl); + pub const ID_REGINFO: Nid = Nid(ffi::NID_id_regInfo); + pub const ID_REGCTRL_REGTOKEN: Nid = Nid(ffi::NID_id_regCtrl_regToken); + pub const ID_REGCTRL_AUTHENTICATOR: Nid = Nid(ffi::NID_id_regCtrl_authenticator); + pub const ID_REGCTRL_PKIPUBLICATIONINFO: Nid = Nid(ffi::NID_id_regCtrl_pkiPublicationInfo); + pub const ID_REGCTRL_PKIARCHIVEOPTIONS: Nid = Nid(ffi::NID_id_regCtrl_pkiArchiveOptions); + pub const ID_REGCTRL_OLDCERTID: Nid = Nid(ffi::NID_id_regCtrl_oldCertID); + pub const ID_REGCTRL_PROTOCOLENCRKEY: Nid = Nid(ffi::NID_id_regCtrl_protocolEncrKey); + pub const ID_REGINFO_UTF8PAIRS: Nid = Nid(ffi::NID_id_regInfo_utf8Pairs); + pub const ID_REGINFO_CERTREQ: Nid = Nid(ffi::NID_id_regInfo_certReq); + pub const ID_ALG_DES40: Nid = Nid(ffi::NID_id_alg_des40); + pub const ID_ALG_NOSIGNATURE: Nid = Nid(ffi::NID_id_alg_noSignature); + pub const ID_ALG_DH_SIG_HMAC_SHA1: Nid = Nid(ffi::NID_id_alg_dh_sig_hmac_sha1); + pub const ID_ALG_DH_POP: Nid = Nid(ffi::NID_id_alg_dh_pop); + pub const ID_CMC_STATUSINFO: Nid = Nid(ffi::NID_id_cmc_statusInfo); + pub const ID_CMC_IDENTIFICATION: Nid = Nid(ffi::NID_id_cmc_identification); + pub const ID_CMC_IDENTITYPROOF: Nid = Nid(ffi::NID_id_cmc_identityProof); + pub const ID_CMC_DATARETURN: Nid = Nid(ffi::NID_id_cmc_dataReturn); + pub const ID_CMC_TRANSACTIONID: Nid = Nid(ffi::NID_id_cmc_transactionId); + pub const ID_CMC_SENDERNONCE: Nid = Nid(ffi::NID_id_cmc_senderNonce); + pub const ID_CMC_RECIPIENTNONCE: Nid = Nid(ffi::NID_id_cmc_recipientNonce); + pub const ID_CMC_ADDEXTENSIONS: Nid = Nid(ffi::NID_id_cmc_addExtensions); + pub const ID_CMC_ENCRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_encryptedPOP); + pub const ID_CMC_DECRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_decryptedPOP); + pub const ID_CMC_LRAPOPWITNESS: Nid = Nid(ffi::NID_id_cmc_lraPOPWitness); + pub const ID_CMC_GETCERT: Nid = Nid(ffi::NID_id_cmc_getCert); + pub const ID_CMC_GETCRL: Nid = Nid(ffi::NID_id_cmc_getCRL); + pub const ID_CMC_REVOKEREQUEST: Nid = Nid(ffi::NID_id_cmc_revokeRequest); + pub const ID_CMC_REGINFO: Nid = Nid(ffi::NID_id_cmc_regInfo); + pub const ID_CMC_RESPONSEINFO: Nid = Nid(ffi::NID_id_cmc_responseInfo); + pub const ID_CMC_QUERYPENDING: Nid = Nid(ffi::NID_id_cmc_queryPending); + pub const ID_CMC_POPLINKRANDOM: Nid = Nid(ffi::NID_id_cmc_popLinkRandom); + pub const ID_CMC_POPLINKWITNESS: Nid = Nid(ffi::NID_id_cmc_popLinkWitness); + pub const ID_CMC_CONFIRMCERTACCEPTANCE: Nid = Nid(ffi::NID_id_cmc_confirmCertAcceptance); + pub const ID_ON_PERSONALDATA: Nid = Nid(ffi::NID_id_on_personalData); + pub const ID_ON_PERMANENTIDENTIFIER: Nid = Nid(ffi::NID_id_on_permanentIdentifier); + pub const ID_PDA_DATEOFBIRTH: Nid = Nid(ffi::NID_id_pda_dateOfBirth); + pub const ID_PDA_PLACEOFBIRTH: Nid = Nid(ffi::NID_id_pda_placeOfBirth); + pub const ID_PDA_GENDER: Nid = Nid(ffi::NID_id_pda_gender); + pub const ID_PDA_COUNTRYOFCITIZENSHIP: Nid = Nid(ffi::NID_id_pda_countryOfCitizenship); + pub const ID_PDA_COUNTRYOFRESIDENCE: Nid = Nid(ffi::NID_id_pda_countryOfResidence); + pub const ID_ACA_AUTHENTICATIONINFO: Nid = Nid(ffi::NID_id_aca_authenticationInfo); + pub const ID_ACA_ACCESSIDENTITY: Nid = Nid(ffi::NID_id_aca_accessIdentity); + pub const ID_ACA_CHARGINGIDENTITY: Nid = Nid(ffi::NID_id_aca_chargingIdentity); + pub const ID_ACA_GROUP: Nid = Nid(ffi::NID_id_aca_group); + pub const ID_ACA_ROLE: Nid = Nid(ffi::NID_id_aca_role); + pub const ID_ACA_ENCATTRS: Nid = Nid(ffi::NID_id_aca_encAttrs); + pub const ID_QCS_PKIXQCSYNTAX_V1: Nid = Nid(ffi::NID_id_qcs_pkixQCSyntax_v1); + pub const ID_CCT_CRS: Nid = Nid(ffi::NID_id_cct_crs); + pub const ID_CCT_PKIDATA: Nid = Nid(ffi::NID_id_cct_PKIData); + pub const ID_CCT_PKIRESPONSE: Nid = Nid(ffi::NID_id_cct_PKIResponse); + pub const ID_PPL_ANYLANGUAGE: Nid = Nid(ffi::NID_id_ppl_anyLanguage); + pub const ID_PPL_INHERITALL: Nid = Nid(ffi::NID_id_ppl_inheritAll); + pub const INDEPENDENT: Nid = Nid(ffi::NID_Independent); + pub const AD_OCSP: Nid = Nid(ffi::NID_ad_OCSP); + pub const AD_CA_ISSUERS: Nid = Nid(ffi::NID_ad_ca_issuers); + pub const AD_TIMESTAMPING: Nid = Nid(ffi::NID_ad_timeStamping); + pub const AD_DVCS: Nid = Nid(ffi::NID_ad_dvcs); + pub const CAREPOSITORY: Nid = Nid(ffi::NID_caRepository); + pub const ID_PKIX_OCSP_BASIC: Nid = Nid(ffi::NID_id_pkix_OCSP_basic); + pub const ID_PKIX_OCSP_NONCE: Nid = Nid(ffi::NID_id_pkix_OCSP_Nonce); + pub const ID_PKIX_OCSP_CRLID: Nid = Nid(ffi::NID_id_pkix_OCSP_CrlID); + pub const ID_PKIX_OCSP_ACCEPTABLERESPONSES: Nid = + Nid(ffi::NID_id_pkix_OCSP_acceptableResponses); + pub const ID_PKIX_OCSP_NOCHECK: Nid = Nid(ffi::NID_id_pkix_OCSP_noCheck); + pub const ID_PKIX_OCSP_ARCHIVECUTOFF: Nid = Nid(ffi::NID_id_pkix_OCSP_archiveCutoff); + pub const ID_PKIX_OCSP_SERVICELOCATOR: Nid = Nid(ffi::NID_id_pkix_OCSP_serviceLocator); + pub const ID_PKIX_OCSP_EXTENDEDSTATUS: Nid = Nid(ffi::NID_id_pkix_OCSP_extendedStatus); + pub const ID_PKIX_OCSP_VALID: Nid = Nid(ffi::NID_id_pkix_OCSP_valid); + pub const ID_PKIX_OCSP_PATH: Nid = Nid(ffi::NID_id_pkix_OCSP_path); + pub const ID_PKIX_OCSP_TRUSTROOT: Nid = Nid(ffi::NID_id_pkix_OCSP_trustRoot); + pub const ALGORITHM: Nid = Nid(ffi::NID_algorithm); + pub const MD5WITHRSA: Nid = Nid(ffi::NID_md5WithRSA); + pub const DES_ECB: Nid = Nid(ffi::NID_des_ecb); + pub const DES_CBC: Nid = Nid(ffi::NID_des_cbc); + pub const DES_OFB64: Nid = Nid(ffi::NID_des_ofb64); + pub const DES_CFB64: Nid = Nid(ffi::NID_des_cfb64); + pub const RSASIGNATURE: Nid = Nid(ffi::NID_rsaSignature); + pub const DSA_2: Nid = Nid(ffi::NID_dsa_2); + pub const DSAWITHSHA: Nid = Nid(ffi::NID_dsaWithSHA); + pub const SHAWITHRSAENCRYPTION: Nid = Nid(ffi::NID_shaWithRSAEncryption); + pub const DES_EDE_ECB: Nid = Nid(ffi::NID_des_ede_ecb); + pub const DES_EDE3_ECB: Nid = Nid(ffi::NID_des_ede3_ecb); + pub const DES_EDE_CBC: Nid = Nid(ffi::NID_des_ede_cbc); + pub const DES_EDE_CFB64: Nid = Nid(ffi::NID_des_ede_cfb64); + pub const DES_EDE3_CFB64: Nid = Nid(ffi::NID_des_ede3_cfb64); + pub const DES_EDE_OFB64: Nid = Nid(ffi::NID_des_ede_ofb64); + pub const DES_EDE3_OFB64: Nid = Nid(ffi::NID_des_ede3_ofb64); + pub const DESX_CBC: Nid = Nid(ffi::NID_desx_cbc); + pub const SHA: Nid = Nid(ffi::NID_sha); + pub const SHA1: Nid = Nid(ffi::NID_sha1); + pub const DSAWITHSHA1_2: Nid = Nid(ffi::NID_dsaWithSHA1_2); + pub const SHA1WITHRSA: Nid = Nid(ffi::NID_sha1WithRSA); + pub const RIPEMD160: Nid = Nid(ffi::NID_ripemd160); + pub const RIPEMD160WITHRSA: Nid = Nid(ffi::NID_ripemd160WithRSA); + pub const SXNET: Nid = Nid(ffi::NID_sxnet); + pub const X500: Nid = Nid(ffi::NID_X500); + pub const X509: Nid = Nid(ffi::NID_X509); + pub const COMMONNAME: Nid = Nid(ffi::NID_commonName); + pub const SURNAME: Nid = Nid(ffi::NID_surname); + pub const SERIALNUMBER: Nid = Nid(ffi::NID_serialNumber); + pub const COUNTRYNAME: Nid = Nid(ffi::NID_countryName); + pub const LOCALITYNAME: Nid = Nid(ffi::NID_localityName); + pub const STATEORPROVINCENAME: Nid = Nid(ffi::NID_stateOrProvinceName); + pub const STREETADDRESS: Nid = Nid(ffi::NID_streetAddress); + pub const ORGANIZATIONNAME: Nid = Nid(ffi::NID_organizationName); + pub const ORGANIZATIONALUNITNAME: Nid = Nid(ffi::NID_organizationalUnitName); + pub const TITLE: Nid = Nid(ffi::NID_title); + pub const DESCRIPTION: Nid = Nid(ffi::NID_description); + pub const SEARCHGUIDE: Nid = Nid(ffi::NID_searchGuide); + pub const BUSINESSCATEGORY: Nid = Nid(ffi::NID_businessCategory); + pub const POSTALADDRESS: Nid = Nid(ffi::NID_postalAddress); + pub const POSTALCODE: Nid = Nid(ffi::NID_postalCode); + pub const POSTOFFICEBOX: Nid = Nid(ffi::NID_postOfficeBox); + pub const PHYSICALDELIVERYOFFICENAME: Nid = Nid(ffi::NID_physicalDeliveryOfficeName); + pub const TELEPHONENUMBER: Nid = Nid(ffi::NID_telephoneNumber); + pub const TELEXNUMBER: Nid = Nid(ffi::NID_telexNumber); + pub const TELETEXTERMINALIDENTIFIER: Nid = Nid(ffi::NID_teletexTerminalIdentifier); + pub const FACSIMILETELEPHONENUMBER: Nid = Nid(ffi::NID_facsimileTelephoneNumber); + pub const X121ADDRESS: Nid = Nid(ffi::NID_x121Address); + pub const INTERNATIONALISDNNUMBER: Nid = Nid(ffi::NID_internationaliSDNNumber); + pub const REGISTEREDADDRESS: Nid = Nid(ffi::NID_registeredAddress); + pub const DESTINATIONINDICATOR: Nid = Nid(ffi::NID_destinationIndicator); + pub const PREFERREDDELIVERYMETHOD: Nid = Nid(ffi::NID_preferredDeliveryMethod); + pub const PRESENTATIONADDRESS: Nid = Nid(ffi::NID_presentationAddress); + pub const SUPPORTEDAPPLICATIONCONTEXT: Nid = Nid(ffi::NID_supportedApplicationContext); + pub const MEMBER: Nid = Nid(ffi::NID_member); + pub const OWNER: Nid = Nid(ffi::NID_owner); + pub const ROLEOCCUPANT: Nid = Nid(ffi::NID_roleOccupant); + pub const SEEALSO: Nid = Nid(ffi::NID_seeAlso); + pub const USERPASSWORD: Nid = Nid(ffi::NID_userPassword); + pub const USERCERTIFICATE: Nid = Nid(ffi::NID_userCertificate); + pub const CACERTIFICATE: Nid = Nid(ffi::NID_cACertificate); + pub const AUTHORITYREVOCATIONLIST: Nid = Nid(ffi::NID_authorityRevocationList); + pub const CERTIFICATEREVOCATIONLIST: Nid = Nid(ffi::NID_certificateRevocationList); + pub const CROSSCERTIFICATEPAIR: Nid = Nid(ffi::NID_crossCertificatePair); + pub const NAME: Nid = Nid(ffi::NID_name); + pub const GIVENNAME: Nid = Nid(ffi::NID_givenName); + pub const INITIALS: Nid = Nid(ffi::NID_initials); + pub const GENERATIONQUALIFIER: Nid = Nid(ffi::NID_generationQualifier); + pub const X500UNIQUEIDENTIFIER: Nid = Nid(ffi::NID_x500UniqueIdentifier); + pub const DNQUALIFIER: Nid = Nid(ffi::NID_dnQualifier); + pub const ENHANCEDSEARCHGUIDE: Nid = Nid(ffi::NID_enhancedSearchGuide); + pub const PROTOCOLINFORMATION: Nid = Nid(ffi::NID_protocolInformation); + pub const DISTINGUISHEDNAME: Nid = Nid(ffi::NID_distinguishedName); + pub const UNIQUEMEMBER: Nid = Nid(ffi::NID_uniqueMember); + pub const HOUSEIDENTIFIER: Nid = Nid(ffi::NID_houseIdentifier); + pub const SUPPORTEDALGORITHMS: Nid = Nid(ffi::NID_supportedAlgorithms); + pub const DELTAREVOCATIONLIST: Nid = Nid(ffi::NID_deltaRevocationList); + pub const DMDNAME: Nid = Nid(ffi::NID_dmdName); + pub const PSEUDONYM: Nid = Nid(ffi::NID_pseudonym); + pub const ROLE: Nid = Nid(ffi::NID_role); + pub const X500ALGORITHMS: Nid = Nid(ffi::NID_X500algorithms); + pub const RSA: Nid = Nid(ffi::NID_rsa); + pub const MDC2WITHRSA: Nid = Nid(ffi::NID_mdc2WithRSA); + pub const MDC2: Nid = Nid(ffi::NID_mdc2); + pub const ID_CE: Nid = Nid(ffi::NID_id_ce); + pub const SUBJECT_DIRECTORY_ATTRIBUTES: Nid = Nid(ffi::NID_subject_directory_attributes); + pub const SUBJECT_KEY_IDENTIFIER: Nid = Nid(ffi::NID_subject_key_identifier); + pub const KEY_USAGE: Nid = Nid(ffi::NID_key_usage); + pub const PRIVATE_KEY_USAGE_PERIOD: Nid = Nid(ffi::NID_private_key_usage_period); + pub const SUBJECT_ALT_NAME: Nid = Nid(ffi::NID_subject_alt_name); + pub const ISSUER_ALT_NAME: Nid = Nid(ffi::NID_issuer_alt_name); + pub const BASIC_CONSTRAINTS: Nid = Nid(ffi::NID_basic_constraints); + pub const CRL_NUMBER: Nid = Nid(ffi::NID_crl_number); + pub const CRL_REASON: Nid = Nid(ffi::NID_crl_reason); + pub const INVALIDITY_DATE: Nid = Nid(ffi::NID_invalidity_date); + pub const DELTA_CRL: Nid = Nid(ffi::NID_delta_crl); + pub const ISSUING_DISTRIBUTION_POINT: Nid = Nid(ffi::NID_issuing_distribution_point); + pub const CERTIFICATE_ISSUER: Nid = Nid(ffi::NID_certificate_issuer); + pub const NAME_CONSTRAINTS: Nid = Nid(ffi::NID_name_constraints); + pub const CRL_DISTRIBUTION_POINTS: Nid = Nid(ffi::NID_crl_distribution_points); + pub const CERTIFICATE_POLICIES: Nid = Nid(ffi::NID_certificate_policies); + pub const ANY_POLICY: Nid = Nid(ffi::NID_any_policy); + pub const POLICY_MAPPINGS: Nid = Nid(ffi::NID_policy_mappings); + pub const AUTHORITY_KEY_IDENTIFIER: Nid = Nid(ffi::NID_authority_key_identifier); + pub const POLICY_CONSTRAINTS: Nid = Nid(ffi::NID_policy_constraints); + pub const EXT_KEY_USAGE: Nid = Nid(ffi::NID_ext_key_usage); + pub const FRESHEST_CRL: Nid = Nid(ffi::NID_freshest_crl); + pub const INHIBIT_ANY_POLICY: Nid = Nid(ffi::NID_inhibit_any_policy); + pub const TARGET_INFORMATION: Nid = Nid(ffi::NID_target_information); + pub const NO_REV_AVAIL: Nid = Nid(ffi::NID_no_rev_avail); + pub const ANYEXTENDEDKEYUSAGE: Nid = Nid(ffi::NID_anyExtendedKeyUsage); + pub const NETSCAPE: Nid = Nid(ffi::NID_netscape); + pub const NETSCAPE_CERT_EXTENSION: Nid = Nid(ffi::NID_netscape_cert_extension); + pub const NETSCAPE_DATA_TYPE: Nid = Nid(ffi::NID_netscape_data_type); + pub const NETSCAPE_CERT_TYPE: Nid = Nid(ffi::NID_netscape_cert_type); + pub const NETSCAPE_BASE_URL: Nid = Nid(ffi::NID_netscape_base_url); + pub const NETSCAPE_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_revocation_url); + pub const NETSCAPE_CA_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_ca_revocation_url); + pub const NETSCAPE_RENEWAL_URL: Nid = Nid(ffi::NID_netscape_renewal_url); + pub const NETSCAPE_CA_POLICY_URL: Nid = Nid(ffi::NID_netscape_ca_policy_url); + pub const NETSCAPE_SSL_SERVER_NAME: Nid = Nid(ffi::NID_netscape_ssl_server_name); + pub const NETSCAPE_COMMENT: Nid = Nid(ffi::NID_netscape_comment); + pub const NETSCAPE_CERT_SEQUENCE: Nid = Nid(ffi::NID_netscape_cert_sequence); + pub const NS_SGC: Nid = Nid(ffi::NID_ns_sgc); + pub const ORG: Nid = Nid(ffi::NID_org); + pub const DOD: Nid = Nid(ffi::NID_dod); + pub const IANA: Nid = Nid(ffi::NID_iana); + pub const DIRECTORY: Nid = Nid(ffi::NID_Directory); + pub const MANAGEMENT: Nid = Nid(ffi::NID_Management); + pub const EXPERIMENTAL: Nid = Nid(ffi::NID_Experimental); + pub const PRIVATE: Nid = Nid(ffi::NID_Private); + pub const SECURITY: Nid = Nid(ffi::NID_Security); + pub const SNMPV2: Nid = Nid(ffi::NID_SNMPv2); + pub const MAIL: Nid = Nid(ffi::NID_Mail); + pub const ENTERPRISES: Nid = Nid(ffi::NID_Enterprises); + pub const DCOBJECT: Nid = Nid(ffi::NID_dcObject); + pub const MIME_MHS: Nid = Nid(ffi::NID_mime_mhs); + pub const MIME_MHS_HEADINGS: Nid = Nid(ffi::NID_mime_mhs_headings); + pub const MIME_MHS_BODIES: Nid = Nid(ffi::NID_mime_mhs_bodies); + pub const ID_HEX_PARTIAL_MESSAGE: Nid = Nid(ffi::NID_id_hex_partial_message); + pub const ID_HEX_MULTIPART_MESSAGE: Nid = Nid(ffi::NID_id_hex_multipart_message); + pub const ZLIB_COMPRESSION: Nid = Nid(ffi::NID_zlib_compression); + pub const AES_128_ECB: Nid = Nid(ffi::NID_aes_128_ecb); + pub const AES_128_CBC: Nid = Nid(ffi::NID_aes_128_cbc); + pub const AES_128_OFB128: Nid = Nid(ffi::NID_aes_128_ofb128); + pub const AES_128_CFB128: Nid = Nid(ffi::NID_aes_128_cfb128); + pub const ID_AES128_WRAP: Nid = Nid(ffi::NID_id_aes128_wrap); + pub const AES_128_GCM: Nid = Nid(ffi::NID_aes_128_gcm); + pub const AES_128_CCM: Nid = Nid(ffi::NID_aes_128_ccm); + pub const ID_AES128_WRAP_PAD: Nid = Nid(ffi::NID_id_aes128_wrap_pad); + pub const AES_192_ECB: Nid = Nid(ffi::NID_aes_192_ecb); + pub const AES_192_CBC: Nid = Nid(ffi::NID_aes_192_cbc); + pub const AES_192_OFB128: Nid = Nid(ffi::NID_aes_192_ofb128); + pub const AES_192_CFB128: Nid = Nid(ffi::NID_aes_192_cfb128); + pub const ID_AES192_WRAP: Nid = Nid(ffi::NID_id_aes192_wrap); + pub const AES_192_GCM: Nid = Nid(ffi::NID_aes_192_gcm); + pub const AES_192_CCM: Nid = Nid(ffi::NID_aes_192_ccm); + pub const ID_AES192_WRAP_PAD: Nid = Nid(ffi::NID_id_aes192_wrap_pad); + pub const AES_256_ECB: Nid = Nid(ffi::NID_aes_256_ecb); + pub const AES_256_CBC: Nid = Nid(ffi::NID_aes_256_cbc); + pub const AES_256_OFB128: Nid = Nid(ffi::NID_aes_256_ofb128); + pub const AES_256_CFB128: Nid = Nid(ffi::NID_aes_256_cfb128); + pub const ID_AES256_WRAP: Nid = Nid(ffi::NID_id_aes256_wrap); + pub const AES_256_GCM: Nid = Nid(ffi::NID_aes_256_gcm); + pub const AES_256_CCM: Nid = Nid(ffi::NID_aes_256_ccm); + pub const ID_AES256_WRAP_PAD: Nid = Nid(ffi::NID_id_aes256_wrap_pad); + pub const AES_128_CFB1: Nid = Nid(ffi::NID_aes_128_cfb1); + pub const AES_192_CFB1: Nid = Nid(ffi::NID_aes_192_cfb1); + pub const AES_256_CFB1: Nid = Nid(ffi::NID_aes_256_cfb1); + pub const AES_128_CFB8: Nid = Nid(ffi::NID_aes_128_cfb8); + pub const AES_192_CFB8: Nid = Nid(ffi::NID_aes_192_cfb8); + pub const AES_256_CFB8: Nid = Nid(ffi::NID_aes_256_cfb8); + pub const AES_128_CTR: Nid = Nid(ffi::NID_aes_128_ctr); + pub const AES_192_CTR: Nid = Nid(ffi::NID_aes_192_ctr); + pub const AES_256_CTR: Nid = Nid(ffi::NID_aes_256_ctr); + pub const AES_128_XTS: Nid = Nid(ffi::NID_aes_128_xts); + pub const AES_256_XTS: Nid = Nid(ffi::NID_aes_256_xts); + pub const DES_CFB1: Nid = Nid(ffi::NID_des_cfb1); + pub const DES_CFB8: Nid = Nid(ffi::NID_des_cfb8); + pub const DES_EDE3_CFB1: Nid = Nid(ffi::NID_des_ede3_cfb1); + pub const DES_EDE3_CFB8: Nid = Nid(ffi::NID_des_ede3_cfb8); + pub const SHA256: Nid = Nid(ffi::NID_sha256); + pub const SHA384: Nid = Nid(ffi::NID_sha384); + pub const SHA512: Nid = Nid(ffi::NID_sha512); + pub const SHA224: Nid = Nid(ffi::NID_sha224); + pub const DSA_WITH_SHA224: Nid = Nid(ffi::NID_dsa_with_SHA224); + pub const DSA_WITH_SHA256: Nid = Nid(ffi::NID_dsa_with_SHA256); + pub const HOLD_INSTRUCTION_CODE: Nid = Nid(ffi::NID_hold_instruction_code); + pub const HOLD_INSTRUCTION_NONE: Nid = Nid(ffi::NID_hold_instruction_none); + pub const HOLD_INSTRUCTION_CALL_ISSUER: Nid = Nid(ffi::NID_hold_instruction_call_issuer); + pub const HOLD_INSTRUCTION_REJECT: Nid = Nid(ffi::NID_hold_instruction_reject); + pub const DATA: Nid = Nid(ffi::NID_data); + pub const PSS: Nid = Nid(ffi::NID_pss); + pub const UCL: Nid = Nid(ffi::NID_ucl); + pub const PILOT: Nid = Nid(ffi::NID_pilot); + pub const PILOTATTRIBUTETYPE: Nid = Nid(ffi::NID_pilotAttributeType); + pub const PILOTATTRIBUTESYNTAX: Nid = Nid(ffi::NID_pilotAttributeSyntax); + pub const PILOTOBJECTCLASS: Nid = Nid(ffi::NID_pilotObjectClass); + pub const PILOTGROUPS: Nid = Nid(ffi::NID_pilotGroups); + pub const IA5STRINGSYNTAX: Nid = Nid(ffi::NID_iA5StringSyntax); + pub const CASEIGNOREIA5STRINGSYNTAX: Nid = Nid(ffi::NID_caseIgnoreIA5StringSyntax); + pub const PILOTOBJECT: Nid = Nid(ffi::NID_pilotObject); + pub const PILOTPERSON: Nid = Nid(ffi::NID_pilotPerson); + pub const ACCOUNT: Nid = Nid(ffi::NID_account); + pub const DOCUMENT: Nid = Nid(ffi::NID_document); + pub const ROOM: Nid = Nid(ffi::NID_room); + pub const DOCUMENTSERIES: Nid = Nid(ffi::NID_documentSeries); + pub const DOMAIN: Nid = Nid(ffi::NID_Domain); + pub const RFC822LOCALPART: Nid = Nid(ffi::NID_rFC822localPart); + pub const DNSDOMAIN: Nid = Nid(ffi::NID_dNSDomain); + pub const DOMAINRELATEDOBJECT: Nid = Nid(ffi::NID_domainRelatedObject); + pub const FRIENDLYCOUNTRY: Nid = Nid(ffi::NID_friendlyCountry); + pub const SIMPLESECURITYOBJECT: Nid = Nid(ffi::NID_simpleSecurityObject); + pub const PILOTORGANIZATION: Nid = Nid(ffi::NID_pilotOrganization); + pub const PILOTDSA: Nid = Nid(ffi::NID_pilotDSA); + pub const QUALITYLABELLEDDATA: Nid = Nid(ffi::NID_qualityLabelledData); + pub const USERID: Nid = Nid(ffi::NID_userId); + pub const TEXTENCODEDORADDRESS: Nid = Nid(ffi::NID_textEncodedORAddress); + pub const RFC822MAILBOX: Nid = Nid(ffi::NID_rfc822Mailbox); + pub const INFO: Nid = Nid(ffi::NID_info); + pub const FAVOURITEDRINK: Nid = Nid(ffi::NID_favouriteDrink); + pub const ROOMNUMBER: Nid = Nid(ffi::NID_roomNumber); + pub const PHOTO: Nid = Nid(ffi::NID_photo); + pub const USERCLASS: Nid = Nid(ffi::NID_userClass); + pub const HOST: Nid = Nid(ffi::NID_host); + pub const MANAGER: Nid = Nid(ffi::NID_manager); + pub const DOCUMENTIDENTIFIER: Nid = Nid(ffi::NID_documentIdentifier); + pub const DOCUMENTTITLE: Nid = Nid(ffi::NID_documentTitle); + pub const DOCUMENTVERSION: Nid = Nid(ffi::NID_documentVersion); + pub const DOCUMENTAUTHOR: Nid = Nid(ffi::NID_documentAuthor); + pub const DOCUMENTLOCATION: Nid = Nid(ffi::NID_documentLocation); + pub const HOMETELEPHONENUMBER: Nid = Nid(ffi::NID_homeTelephoneNumber); + pub const SECRETARY: Nid = Nid(ffi::NID_secretary); + pub const OTHERMAILBOX: Nid = Nid(ffi::NID_otherMailbox); + pub const LASTMODIFIEDTIME: Nid = Nid(ffi::NID_lastModifiedTime); + pub const LASTMODIFIEDBY: Nid = Nid(ffi::NID_lastModifiedBy); + pub const DOMAINCOMPONENT: Nid = Nid(ffi::NID_domainComponent); + pub const ARECORD: Nid = Nid(ffi::NID_aRecord); + pub const PILOTATTRIBUTETYPE27: Nid = Nid(ffi::NID_pilotAttributeType27); + pub const MXRECORD: Nid = Nid(ffi::NID_mXRecord); + pub const NSRECORD: Nid = Nid(ffi::NID_nSRecord); + pub const SOARECORD: Nid = Nid(ffi::NID_sOARecord); + pub const CNAMERECORD: Nid = Nid(ffi::NID_cNAMERecord); + pub const ASSOCIATEDDOMAIN: Nid = Nid(ffi::NID_associatedDomain); + pub const ASSOCIATEDNAME: Nid = Nid(ffi::NID_associatedName); + pub const HOMEPOSTALADDRESS: Nid = Nid(ffi::NID_homePostalAddress); + pub const PERSONALTITLE: Nid = Nid(ffi::NID_personalTitle); + pub const MOBILETELEPHONENUMBER: Nid = Nid(ffi::NID_mobileTelephoneNumber); + pub const PAGERTELEPHONENUMBER: Nid = Nid(ffi::NID_pagerTelephoneNumber); + pub const FRIENDLYCOUNTRYNAME: Nid = Nid(ffi::NID_friendlyCountryName); + pub const ORGANIZATIONALSTATUS: Nid = Nid(ffi::NID_organizationalStatus); + pub const JANETMAILBOX: Nid = Nid(ffi::NID_janetMailbox); + pub const MAILPREFERENCEOPTION: Nid = Nid(ffi::NID_mailPreferenceOption); + pub const BUILDINGNAME: Nid = Nid(ffi::NID_buildingName); + pub const DSAQUALITY: Nid = Nid(ffi::NID_dSAQuality); + pub const SINGLELEVELQUALITY: Nid = Nid(ffi::NID_singleLevelQuality); + pub const SUBTREEMINIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMinimumQuality); + pub const SUBTREEMAXIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMaximumQuality); + pub const PERSONALSIGNATURE: Nid = Nid(ffi::NID_personalSignature); + pub const DITREDIRECT: Nid = Nid(ffi::NID_dITRedirect); + pub const AUDIO: Nid = Nid(ffi::NID_audio); + pub const DOCUMENTPUBLISHER: Nid = Nid(ffi::NID_documentPublisher); + pub const ID_SET: Nid = Nid(ffi::NID_id_set); + pub const SET_CTYPE: Nid = Nid(ffi::NID_set_ctype); + pub const SET_MSGEXT: Nid = Nid(ffi::NID_set_msgExt); + pub const SET_ATTR: Nid = Nid(ffi::NID_set_attr); + pub const SET_POLICY: Nid = Nid(ffi::NID_set_policy); + pub const SET_CERTEXT: Nid = Nid(ffi::NID_set_certExt); + pub const SET_BRAND: Nid = Nid(ffi::NID_set_brand); + pub const SETCT_PANDATA: Nid = Nid(ffi::NID_setct_PANData); + pub const SETCT_PANTOKEN: Nid = Nid(ffi::NID_setct_PANToken); + pub const SETCT_PANONLY: Nid = Nid(ffi::NID_setct_PANOnly); + pub const SETCT_OIDATA: Nid = Nid(ffi::NID_setct_OIData); + pub const SETCT_PI: Nid = Nid(ffi::NID_setct_PI); + pub const SETCT_PIDATA: Nid = Nid(ffi::NID_setct_PIData); + pub const SETCT_PIDATAUNSIGNED: Nid = Nid(ffi::NID_setct_PIDataUnsigned); + pub const SETCT_HODINPUT: Nid = Nid(ffi::NID_setct_HODInput); + pub const SETCT_AUTHRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthResBaggage); + pub const SETCT_AUTHREVREQBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevReqBaggage); + pub const SETCT_AUTHREVRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevResBaggage); + pub const SETCT_CAPTOKENSEQ: Nid = Nid(ffi::NID_setct_CapTokenSeq); + pub const SETCT_PINITRESDATA: Nid = Nid(ffi::NID_setct_PInitResData); + pub const SETCT_PI_TBS: Nid = Nid(ffi::NID_setct_PI_TBS); + pub const SETCT_PRESDATA: Nid = Nid(ffi::NID_setct_PResData); + pub const SETCT_AUTHREQTBS: Nid = Nid(ffi::NID_setct_AuthReqTBS); + pub const SETCT_AUTHRESTBS: Nid = Nid(ffi::NID_setct_AuthResTBS); + pub const SETCT_AUTHRESTBSX: Nid = Nid(ffi::NID_setct_AuthResTBSX); + pub const SETCT_AUTHTOKENTBS: Nid = Nid(ffi::NID_setct_AuthTokenTBS); + pub const SETCT_CAPTOKENDATA: Nid = Nid(ffi::NID_setct_CapTokenData); + pub const SETCT_CAPTOKENTBS: Nid = Nid(ffi::NID_setct_CapTokenTBS); + pub const SETCT_ACQCARDCODEMSG: Nid = Nid(ffi::NID_setct_AcqCardCodeMsg); + pub const SETCT_AUTHREVREQTBS: Nid = Nid(ffi::NID_setct_AuthRevReqTBS); + pub const SETCT_AUTHREVRESDATA: Nid = Nid(ffi::NID_setct_AuthRevResData); + pub const SETCT_AUTHREVRESTBS: Nid = Nid(ffi::NID_setct_AuthRevResTBS); + pub const SETCT_CAPREQTBS: Nid = Nid(ffi::NID_setct_CapReqTBS); + pub const SETCT_CAPREQTBSX: Nid = Nid(ffi::NID_setct_CapReqTBSX); + pub const SETCT_CAPRESDATA: Nid = Nid(ffi::NID_setct_CapResData); + pub const SETCT_CAPREVREQTBS: Nid = Nid(ffi::NID_setct_CapRevReqTBS); + pub const SETCT_CAPREVREQTBSX: Nid = Nid(ffi::NID_setct_CapRevReqTBSX); + pub const SETCT_CAPREVRESDATA: Nid = Nid(ffi::NID_setct_CapRevResData); + pub const SETCT_CREDREQTBS: Nid = Nid(ffi::NID_setct_CredReqTBS); + pub const SETCT_CREDREQTBSX: Nid = Nid(ffi::NID_setct_CredReqTBSX); + pub const SETCT_CREDRESDATA: Nid = Nid(ffi::NID_setct_CredResData); + pub const SETCT_CREDREVREQTBS: Nid = Nid(ffi::NID_setct_CredRevReqTBS); + pub const SETCT_CREDREVREQTBSX: Nid = Nid(ffi::NID_setct_CredRevReqTBSX); + pub const SETCT_CREDREVRESDATA: Nid = Nid(ffi::NID_setct_CredRevResData); + pub const SETCT_PCERTREQDATA: Nid = Nid(ffi::NID_setct_PCertReqData); + pub const SETCT_PCERTRESTBS: Nid = Nid(ffi::NID_setct_PCertResTBS); + pub const SETCT_BATCHADMINREQDATA: Nid = Nid(ffi::NID_setct_BatchAdminReqData); + pub const SETCT_BATCHADMINRESDATA: Nid = Nid(ffi::NID_setct_BatchAdminResData); + pub const SETCT_CARDCINITRESTBS: Nid = Nid(ffi::NID_setct_CardCInitResTBS); + pub const SETCT_MEAQCINITRESTBS: Nid = Nid(ffi::NID_setct_MeAqCInitResTBS); + pub const SETCT_REGFORMRESTBS: Nid = Nid(ffi::NID_setct_RegFormResTBS); + pub const SETCT_CERTREQDATA: Nid = Nid(ffi::NID_setct_CertReqData); + pub const SETCT_CERTREQTBS: Nid = Nid(ffi::NID_setct_CertReqTBS); + pub const SETCT_CERTRESDATA: Nid = Nid(ffi::NID_setct_CertResData); + pub const SETCT_CERTINQREQTBS: Nid = Nid(ffi::NID_setct_CertInqReqTBS); + pub const SETCT_ERRORTBS: Nid = Nid(ffi::NID_setct_ErrorTBS); + pub const SETCT_PIDUALSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIDualSignedTBE); + pub const SETCT_PIUNSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIUnsignedTBE); + pub const SETCT_AUTHREQTBE: Nid = Nid(ffi::NID_setct_AuthReqTBE); + pub const SETCT_AUTHRESTBE: Nid = Nid(ffi::NID_setct_AuthResTBE); + pub const SETCT_AUTHRESTBEX: Nid = Nid(ffi::NID_setct_AuthResTBEX); + pub const SETCT_AUTHTOKENTBE: Nid = Nid(ffi::NID_setct_AuthTokenTBE); + pub const SETCT_CAPTOKENTBE: Nid = Nid(ffi::NID_setct_CapTokenTBE); + pub const SETCT_CAPTOKENTBEX: Nid = Nid(ffi::NID_setct_CapTokenTBEX); + pub const SETCT_ACQCARDCODEMSGTBE: Nid = Nid(ffi::NID_setct_AcqCardCodeMsgTBE); + pub const SETCT_AUTHREVREQTBE: Nid = Nid(ffi::NID_setct_AuthRevReqTBE); + pub const SETCT_AUTHREVRESTBE: Nid = Nid(ffi::NID_setct_AuthRevResTBE); + pub const SETCT_AUTHREVRESTBEB: Nid = Nid(ffi::NID_setct_AuthRevResTBEB); + pub const SETCT_CAPREQTBE: Nid = Nid(ffi::NID_setct_CapReqTBE); + pub const SETCT_CAPREQTBEX: Nid = Nid(ffi::NID_setct_CapReqTBEX); + pub const SETCT_CAPRESTBE: Nid = Nid(ffi::NID_setct_CapResTBE); + pub const SETCT_CAPREVREQTBE: Nid = Nid(ffi::NID_setct_CapRevReqTBE); + pub const SETCT_CAPREVREQTBEX: Nid = Nid(ffi::NID_setct_CapRevReqTBEX); + pub const SETCT_CAPREVRESTBE: Nid = Nid(ffi::NID_setct_CapRevResTBE); + pub const SETCT_CREDREQTBE: Nid = Nid(ffi::NID_setct_CredReqTBE); + pub const SETCT_CREDREQTBEX: Nid = Nid(ffi::NID_setct_CredReqTBEX); + pub const SETCT_CREDRESTBE: Nid = Nid(ffi::NID_setct_CredResTBE); + pub const SETCT_CREDREVREQTBE: Nid = Nid(ffi::NID_setct_CredRevReqTBE); + pub const SETCT_CREDREVREQTBEX: Nid = Nid(ffi::NID_setct_CredRevReqTBEX); + pub const SETCT_CREDREVRESTBE: Nid = Nid(ffi::NID_setct_CredRevResTBE); + pub const SETCT_BATCHADMINREQTBE: Nid = Nid(ffi::NID_setct_BatchAdminReqTBE); + pub const SETCT_BATCHADMINRESTBE: Nid = Nid(ffi::NID_setct_BatchAdminResTBE); + pub const SETCT_REGFORMREQTBE: Nid = Nid(ffi::NID_setct_RegFormReqTBE); + pub const SETCT_CERTREQTBE: Nid = Nid(ffi::NID_setct_CertReqTBE); + pub const SETCT_CERTREQTBEX: Nid = Nid(ffi::NID_setct_CertReqTBEX); + pub const SETCT_CERTRESTBE: Nid = Nid(ffi::NID_setct_CertResTBE); + pub const SETCT_CRLNOTIFICATIONTBS: Nid = Nid(ffi::NID_setct_CRLNotificationTBS); + pub const SETCT_CRLNOTIFICATIONRESTBS: Nid = Nid(ffi::NID_setct_CRLNotificationResTBS); + pub const SETCT_BCIDISTRIBUTIONTBS: Nid = Nid(ffi::NID_setct_BCIDistributionTBS); + pub const SETEXT_GENCRYPT: Nid = Nid(ffi::NID_setext_genCrypt); + pub const SETEXT_MIAUTH: Nid = Nid(ffi::NID_setext_miAuth); + pub const SETEXT_PINSECURE: Nid = Nid(ffi::NID_setext_pinSecure); + pub const SETEXT_PINANY: Nid = Nid(ffi::NID_setext_pinAny); + pub const SETEXT_TRACK2: Nid = Nid(ffi::NID_setext_track2); + pub const SETEXT_CV: Nid = Nid(ffi::NID_setext_cv); + pub const SET_POLICY_ROOT: Nid = Nid(ffi::NID_set_policy_root); + pub const SETCEXT_HASHEDROOT: Nid = Nid(ffi::NID_setCext_hashedRoot); + pub const SETCEXT_CERTTYPE: Nid = Nid(ffi::NID_setCext_certType); + pub const SETCEXT_MERCHDATA: Nid = Nid(ffi::NID_setCext_merchData); + pub const SETCEXT_CCERTREQUIRED: Nid = Nid(ffi::NID_setCext_cCertRequired); + pub const SETCEXT_TUNNELING: Nid = Nid(ffi::NID_setCext_tunneling); + pub const SETCEXT_SETEXT: Nid = Nid(ffi::NID_setCext_setExt); + pub const SETCEXT_SETQUALF: Nid = Nid(ffi::NID_setCext_setQualf); + pub const SETCEXT_PGWYCAPABILITIES: Nid = Nid(ffi::NID_setCext_PGWYcapabilities); + pub const SETCEXT_TOKENIDENTIFIER: Nid = Nid(ffi::NID_setCext_TokenIdentifier); + pub const SETCEXT_TRACK2DATA: Nid = Nid(ffi::NID_setCext_Track2Data); + pub const SETCEXT_TOKENTYPE: Nid = Nid(ffi::NID_setCext_TokenType); + pub const SETCEXT_ISSUERCAPABILITIES: Nid = Nid(ffi::NID_setCext_IssuerCapabilities); + pub const SETATTR_CERT: Nid = Nid(ffi::NID_setAttr_Cert); + pub const SETATTR_PGWYCAP: Nid = Nid(ffi::NID_setAttr_PGWYcap); + pub const SETATTR_TOKENTYPE: Nid = Nid(ffi::NID_setAttr_TokenType); + pub const SETATTR_ISSCAP: Nid = Nid(ffi::NID_setAttr_IssCap); + pub const SET_ROOTKEYTHUMB: Nid = Nid(ffi::NID_set_rootKeyThumb); + pub const SET_ADDPOLICY: Nid = Nid(ffi::NID_set_addPolicy); + pub const SETATTR_TOKEN_EMV: Nid = Nid(ffi::NID_setAttr_Token_EMV); + pub const SETATTR_TOKEN_B0PRIME: Nid = Nid(ffi::NID_setAttr_Token_B0Prime); + pub const SETATTR_ISSCAP_CVM: Nid = Nid(ffi::NID_setAttr_IssCap_CVM); + pub const SETATTR_ISSCAP_T2: Nid = Nid(ffi::NID_setAttr_IssCap_T2); + pub const SETATTR_ISSCAP_SIG: Nid = Nid(ffi::NID_setAttr_IssCap_Sig); + pub const SETATTR_GENCRYPTGRM: Nid = Nid(ffi::NID_setAttr_GenCryptgrm); + pub const SETATTR_T2ENC: Nid = Nid(ffi::NID_setAttr_T2Enc); + pub const SETATTR_T2CLEARTXT: Nid = Nid(ffi::NID_setAttr_T2cleartxt); + pub const SETATTR_TOKICCSIG: Nid = Nid(ffi::NID_setAttr_TokICCsig); + pub const SETATTR_SECDEVSIG: Nid = Nid(ffi::NID_setAttr_SecDevSig); + pub const SET_BRAND_IATA_ATA: Nid = Nid(ffi::NID_set_brand_IATA_ATA); + pub const SET_BRAND_DINERS: Nid = Nid(ffi::NID_set_brand_Diners); + pub const SET_BRAND_AMERICANEXPRESS: Nid = Nid(ffi::NID_set_brand_AmericanExpress); + pub const SET_BRAND_JCB: Nid = Nid(ffi::NID_set_brand_JCB); + pub const SET_BRAND_VISA: Nid = Nid(ffi::NID_set_brand_Visa); + pub const SET_BRAND_MASTERCARD: Nid = Nid(ffi::NID_set_brand_MasterCard); + pub const SET_BRAND_NOVUS: Nid = Nid(ffi::NID_set_brand_Novus); + pub const DES_CDMF: Nid = Nid(ffi::NID_des_cdmf); + pub const RSAOAEPENCRYPTIONSET: Nid = Nid(ffi::NID_rsaOAEPEncryptionSET); + pub const IPSEC3: Nid = Nid(ffi::NID_ipsec3); + pub const IPSEC4: Nid = Nid(ffi::NID_ipsec4); + pub const WHIRLPOOL: Nid = Nid(ffi::NID_whirlpool); + pub const CRYPTOPRO: Nid = Nid(ffi::NID_cryptopro); + pub const CRYPTOCOM: Nid = Nid(ffi::NID_cryptocom); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_94: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94); + pub const ID_GOSTR3411_94: Nid = Nid(ffi::NID_id_GostR3411_94); + pub const ID_HMACGOSTR3411_94: Nid = Nid(ffi::NID_id_HMACGostR3411_94); + pub const ID_GOSTR3410_2001: Nid = Nid(ffi::NID_id_GostR3410_2001); + pub const ID_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3410_94); + pub const ID_GOST28147_89: Nid = Nid(ffi::NID_id_Gost28147_89); + pub const GOST89_CNT: Nid = Nid(ffi::NID_gost89_cnt); + pub const ID_GOST28147_89_MAC: Nid = Nid(ffi::NID_id_Gost28147_89_MAC); + pub const ID_GOSTR3411_94_PRF: Nid = Nid(ffi::NID_id_GostR3411_94_prf); + pub const ID_GOSTR3410_2001DH: Nid = Nid(ffi::NID_id_GostR3410_2001DH); + pub const ID_GOSTR3410_94DH: Nid = Nid(ffi::NID_id_GostR3410_94DH); + pub const ID_GOST28147_89_CRYPTOPRO_KEYMESHING: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_KeyMeshing); + pub const ID_GOST28147_89_NONE_KEYMESHING: Nid = Nid(ffi::NID_id_Gost28147_89_None_KeyMeshing); + pub const ID_GOSTR3411_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_TestParamSet); + pub const ID_GOSTR3411_94_CRYPTOPROPARAMSET: Nid = + Nid(ffi::NID_id_GostR3411_94_CryptoProParamSet); + pub const ID_GOST28147_89_TESTPARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_TestParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_A_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_A_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_B_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_B_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_C_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_C_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_D_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_D_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_1_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_0_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_RIC_1_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet); + pub const ID_GOSTR3410_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_TestParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_A_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_A_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_B_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_B_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_C_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_C_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_D_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_D_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_XCHA_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchA_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_XCHB_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchB_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_XCHC_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchC_ParamSet); + pub const ID_GOSTR3410_2001_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_TestParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_A_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_A_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_B_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_B_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_C_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_C_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHA_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHB_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet); + pub const ID_GOSTR3410_94_A: Nid = Nid(ffi::NID_id_GostR3410_94_a); + pub const ID_GOSTR3410_94_ABIS: Nid = Nid(ffi::NID_id_GostR3410_94_aBis); + pub const ID_GOSTR3410_94_B: Nid = Nid(ffi::NID_id_GostR3410_94_b); + pub const ID_GOSTR3410_94_BBIS: Nid = Nid(ffi::NID_id_GostR3410_94_bBis); + pub const ID_GOST28147_89_CC: Nid = Nid(ffi::NID_id_Gost28147_89_cc); + pub const ID_GOSTR3410_94_CC: Nid = Nid(ffi::NID_id_GostR3410_94_cc); + pub const ID_GOSTR3410_2001_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_cc); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_94_CC: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94_cc); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001_CC: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001_cc); + pub const ID_GOSTR3410_2001_PARAMSET_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_ParamSet_cc); + pub const CAMELLIA_128_CBC: Nid = Nid(ffi::NID_camellia_128_cbc); + pub const CAMELLIA_192_CBC: Nid = Nid(ffi::NID_camellia_192_cbc); + pub const CAMELLIA_256_CBC: Nid = Nid(ffi::NID_camellia_256_cbc); + pub const ID_CAMELLIA128_WRAP: Nid = Nid(ffi::NID_id_camellia128_wrap); + pub const ID_CAMELLIA192_WRAP: Nid = Nid(ffi::NID_id_camellia192_wrap); + pub const ID_CAMELLIA256_WRAP: Nid = Nid(ffi::NID_id_camellia256_wrap); + pub const CAMELLIA_128_ECB: Nid = Nid(ffi::NID_camellia_128_ecb); + pub const CAMELLIA_128_OFB128: Nid = Nid(ffi::NID_camellia_128_ofb128); + pub const CAMELLIA_128_CFB128: Nid = Nid(ffi::NID_camellia_128_cfb128); + pub const CAMELLIA_192_ECB: Nid = Nid(ffi::NID_camellia_192_ecb); + pub const CAMELLIA_192_OFB128: Nid = Nid(ffi::NID_camellia_192_ofb128); + pub const CAMELLIA_192_CFB128: Nid = Nid(ffi::NID_camellia_192_cfb128); + pub const CAMELLIA_256_ECB: Nid = Nid(ffi::NID_camellia_256_ecb); + pub const CAMELLIA_256_OFB128: Nid = Nid(ffi::NID_camellia_256_ofb128); + pub const CAMELLIA_256_CFB128: Nid = Nid(ffi::NID_camellia_256_cfb128); + pub const CAMELLIA_128_CFB1: Nid = Nid(ffi::NID_camellia_128_cfb1); + pub const CAMELLIA_192_CFB1: Nid = Nid(ffi::NID_camellia_192_cfb1); + pub const CAMELLIA_256_CFB1: Nid = Nid(ffi::NID_camellia_256_cfb1); + pub const CAMELLIA_128_CFB8: Nid = Nid(ffi::NID_camellia_128_cfb8); + pub const CAMELLIA_192_CFB8: Nid = Nid(ffi::NID_camellia_192_cfb8); + pub const CAMELLIA_256_CFB8: Nid = Nid(ffi::NID_camellia_256_cfb8); + pub const KISA: Nid = Nid(ffi::NID_kisa); + pub const SEED_ECB: Nid = Nid(ffi::NID_seed_ecb); + pub const SEED_CBC: Nid = Nid(ffi::NID_seed_cbc); + pub const SEED_CFB128: Nid = Nid(ffi::NID_seed_cfb128); + pub const SEED_OFB128: Nid = Nid(ffi::NID_seed_ofb128); + pub const HMAC: Nid = Nid(ffi::NID_hmac); + pub const CMAC: Nid = Nid(ffi::NID_cmac); + pub const RC4_HMAC_MD5: Nid = Nid(ffi::NID_rc4_hmac_md5); + 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); } -pub const UNDEF: Nid = Nid(ffi::NID_undef); -pub const ITU_T: Nid = Nid(ffi::NID_itu_t); -pub const CCITT: Nid = Nid(ffi::NID_ccitt); -pub const ISO: Nid = Nid(ffi::NID_iso); -pub const JOINT_ISO_ITU_T: Nid = Nid(ffi::NID_joint_iso_itu_t); -pub const JOINT_ISO_CCITT: Nid = Nid(ffi::NID_joint_iso_ccitt); -pub const MEMBER_BODY: Nid = Nid(ffi::NID_member_body); -pub const IDENTIFIED_ORGANIZATION: Nid = Nid(ffi::NID_identified_organization); -pub const HMAC_MD5: Nid = Nid(ffi::NID_hmac_md5); -pub const HMAC_SHA1: Nid = Nid(ffi::NID_hmac_sha1); -pub const CERTICOM_ARC: Nid = Nid(ffi::NID_certicom_arc); -pub const INTERNATIONAL_ORGANIZATIONS: Nid = Nid(ffi::NID_international_organizations); -pub const WAP: Nid = Nid(ffi::NID_wap); -pub const WAP_WSG: Nid = Nid(ffi::NID_wap_wsg); -pub const SELECTED_ATTRIBUTE_TYPES: Nid = Nid(ffi::NID_selected_attribute_types); -pub const CLEARANCE: Nid = Nid(ffi::NID_clearance); -pub const ISO_US: Nid = Nid(ffi::NID_ISO_US); -pub const X9_57: Nid = Nid(ffi::NID_X9_57); -pub const X9CM: Nid = Nid(ffi::NID_X9cm); -pub const DSA: Nid = Nid(ffi::NID_dsa); -pub const DSAWITHSHA1: Nid = Nid(ffi::NID_dsaWithSHA1); -pub const ANSI_X9_62: Nid = Nid(ffi::NID_ansi_X9_62); -pub const X9_62_PRIME_FIELD: Nid = Nid(ffi::NID_X9_62_prime_field); -pub const X9_62_CHARACTERISTIC_TWO_FIELD: Nid = Nid(ffi::NID_X9_62_characteristic_two_field); -pub const X9_62_ID_CHARACTERISTIC_TWO_BASIS: Nid = Nid(ffi::NID_X9_62_id_characteristic_two_basis); -pub const X9_62_ONBASIS: Nid = Nid(ffi::NID_X9_62_onBasis); -pub const X9_62_TPBASIS: Nid = Nid(ffi::NID_X9_62_tpBasis); -pub const X9_62_PPBASIS: Nid = Nid(ffi::NID_X9_62_ppBasis); -pub const X9_62_ID_ECPUBLICKEY: Nid = Nid(ffi::NID_X9_62_id_ecPublicKey); -pub const X9_62_C2PNB163V1: Nid = Nid(ffi::NID_X9_62_c2pnb163v1); -pub const X9_62_C2PNB163V2: Nid = Nid(ffi::NID_X9_62_c2pnb163v2); -pub const X9_62_C2PNB163V3: Nid = Nid(ffi::NID_X9_62_c2pnb163v3); -pub const X9_62_C2PNB176V1: Nid = Nid(ffi::NID_X9_62_c2pnb176v1); -pub const X9_62_C2TNB191V1: Nid = Nid(ffi::NID_X9_62_c2tnb191v1); -pub const X9_62_C2TNB191V2: Nid = Nid(ffi::NID_X9_62_c2tnb191v2); -pub const X9_62_C2TNB191V3: Nid = Nid(ffi::NID_X9_62_c2tnb191v3); -pub const X9_62_C2ONB191V4: Nid = Nid(ffi::NID_X9_62_c2onb191v4); -pub const X9_62_C2ONB191V5: Nid = Nid(ffi::NID_X9_62_c2onb191v5); -pub const X9_62_C2PNB208W1: Nid = Nid(ffi::NID_X9_62_c2pnb208w1); -pub const X9_62_C2TNB239V1: Nid = Nid(ffi::NID_X9_62_c2tnb239v1); -pub const X9_62_C2TNB239V2: Nid = Nid(ffi::NID_X9_62_c2tnb239v2); -pub const X9_62_C2TNB239V3: Nid = Nid(ffi::NID_X9_62_c2tnb239v3); -pub const X9_62_C2ONB239V4: Nid = Nid(ffi::NID_X9_62_c2onb239v4); -pub const X9_62_C2ONB239V5: Nid = Nid(ffi::NID_X9_62_c2onb239v5); -pub const X9_62_C2PNB272W1: Nid = Nid(ffi::NID_X9_62_c2pnb272w1); -pub const X9_62_C2PNB304W1: Nid = Nid(ffi::NID_X9_62_c2pnb304w1); -pub const X9_62_C2TNB359V1: Nid = Nid(ffi::NID_X9_62_c2tnb359v1); -pub const X9_62_C2PNB368W1: Nid = Nid(ffi::NID_X9_62_c2pnb368w1); -pub const X9_62_C2TNB431R1: Nid = Nid(ffi::NID_X9_62_c2tnb431r1); -pub const X9_62_PRIME192V1: Nid = Nid(ffi::NID_X9_62_prime192v1); -pub const X9_62_PRIME192V2: Nid = Nid(ffi::NID_X9_62_prime192v2); -pub const X9_62_PRIME192V3: Nid = Nid(ffi::NID_X9_62_prime192v3); -pub const X9_62_PRIME239V1: Nid = Nid(ffi::NID_X9_62_prime239v1); -pub const X9_62_PRIME239V2: Nid = Nid(ffi::NID_X9_62_prime239v2); -pub const X9_62_PRIME239V3: Nid = Nid(ffi::NID_X9_62_prime239v3); -pub const X9_62_PRIME256V1: Nid = Nid(ffi::NID_X9_62_prime256v1); -pub const ECDSA_WITH_SHA1: Nid = Nid(ffi::NID_ecdsa_with_SHA1); -pub const ECDSA_WITH_RECOMMENDED: Nid = Nid(ffi::NID_ecdsa_with_Recommended); -pub const ECDSA_WITH_SPECIFIED: Nid = Nid(ffi::NID_ecdsa_with_Specified); -pub const ECDSA_WITH_SHA224: Nid = Nid(ffi::NID_ecdsa_with_SHA224); -pub const ECDSA_WITH_SHA256: Nid = Nid(ffi::NID_ecdsa_with_SHA256); -pub const ECDSA_WITH_SHA384: Nid = Nid(ffi::NID_ecdsa_with_SHA384); -pub const ECDSA_WITH_SHA512: Nid = Nid(ffi::NID_ecdsa_with_SHA512); -pub const SECP112R1: Nid = Nid(ffi::NID_secp112r1); -pub const SECP112R2: Nid = Nid(ffi::NID_secp112r2); -pub const SECP128R1: Nid = Nid(ffi::NID_secp128r1); -pub const SECP128R2: Nid = Nid(ffi::NID_secp128r2); -pub const SECP160K1: Nid = Nid(ffi::NID_secp160k1); -pub const SECP160R1: Nid = Nid(ffi::NID_secp160r1); -pub const SECP160R2: Nid = Nid(ffi::NID_secp160r2); -pub const SECP192K1: Nid = Nid(ffi::NID_secp192k1); -pub const SECP224K1: Nid = Nid(ffi::NID_secp224k1); -pub const SECP224R1: Nid = Nid(ffi::NID_secp224r1); -pub const SECP256K1: Nid = Nid(ffi::NID_secp256k1); -pub const SECP384R1: Nid = Nid(ffi::NID_secp384r1); -pub const SECP521R1: Nid = Nid(ffi::NID_secp521r1); -pub const SECT113R1: Nid = Nid(ffi::NID_sect113r1); -pub const SECT113R2: Nid = Nid(ffi::NID_sect113r2); -pub const SECT131R1: Nid = Nid(ffi::NID_sect131r1); -pub const SECT131R2: Nid = Nid(ffi::NID_sect131r2); -pub const SECT163K1: Nid = Nid(ffi::NID_sect163k1); -pub const SECT163R1: Nid = Nid(ffi::NID_sect163r1); -pub const SECT163R2: Nid = Nid(ffi::NID_sect163r2); -pub const SECT193R1: Nid = Nid(ffi::NID_sect193r1); -pub const SECT193R2: Nid = Nid(ffi::NID_sect193r2); -pub const SECT233K1: Nid = Nid(ffi::NID_sect233k1); -pub const SECT233R1: Nid = Nid(ffi::NID_sect233r1); -pub const SECT239K1: Nid = Nid(ffi::NID_sect239k1); -pub const SECT283K1: Nid = Nid(ffi::NID_sect283k1); -pub const SECT283R1: Nid = Nid(ffi::NID_sect283r1); -pub const SECT409K1: Nid = Nid(ffi::NID_sect409k1); -pub const SECT409R1: Nid = Nid(ffi::NID_sect409r1); -pub const SECT571K1: Nid = Nid(ffi::NID_sect571k1); -pub const SECT571R1: Nid = Nid(ffi::NID_sect571r1); -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); -pub const WAP_WSG_IDM_ECID_WTLS5: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls5); -pub const WAP_WSG_IDM_ECID_WTLS6: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls6); -pub const WAP_WSG_IDM_ECID_WTLS7: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls7); -pub const WAP_WSG_IDM_ECID_WTLS8: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls8); -pub const WAP_WSG_IDM_ECID_WTLS9: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls9); -pub const WAP_WSG_IDM_ECID_WTLS10: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls10); -pub const WAP_WSG_IDM_ECID_WTLS11: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls11); -pub const WAP_WSG_IDM_ECID_WTLS12: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls12); -pub const CAST5_CBC: Nid = Nid(ffi::NID_cast5_cbc); -pub const CAST5_ECB: Nid = Nid(ffi::NID_cast5_ecb); -pub const CAST5_CFB64: Nid = Nid(ffi::NID_cast5_cfb64); -pub const CAST5_OFB64: Nid = Nid(ffi::NID_cast5_ofb64); -pub const PBEWITHMD5ANDCAST5_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndCast5_CBC); -pub const ID_PASSWORDBASEDMAC: Nid = Nid(ffi::NID_id_PasswordBasedMAC); -pub const ID_DHBASEDMAC: Nid = Nid(ffi::NID_id_DHBasedMac); -pub const RSADSI: Nid = Nid(ffi::NID_rsadsi); -pub const PKCS: Nid = Nid(ffi::NID_pkcs); -pub const PKCS1: Nid = Nid(ffi::NID_pkcs1); -pub const RSAENCRYPTION: Nid = Nid(ffi::NID_rsaEncryption); -pub const MD2WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md2WithRSAEncryption); -pub const MD4WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md4WithRSAEncryption); -pub const MD5WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md5WithRSAEncryption); -pub const SHA1WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha1WithRSAEncryption); -pub const RSAESOAEP: Nid = Nid(ffi::NID_rsaesOaep); -pub const MGF1: Nid = Nid(ffi::NID_mgf1); -pub const RSASSAPSS: Nid = Nid(ffi::NID_rsassaPss); -pub const SHA256WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha256WithRSAEncryption); -pub const SHA384WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha384WithRSAEncryption); -pub const SHA512WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha512WithRSAEncryption); -pub const SHA224WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha224WithRSAEncryption); -pub const PKCS3: Nid = Nid(ffi::NID_pkcs3); -pub const DHKEYAGREEMENT: Nid = Nid(ffi::NID_dhKeyAgreement); -pub const PKCS5: Nid = Nid(ffi::NID_pkcs5); -pub const PBEWITHMD2ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndDES_CBC); -pub const PBEWITHMD5ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndDES_CBC); -pub const PBEWITHMD2ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndRC2_CBC); -pub const PBEWITHMD5ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndRC2_CBC); -pub const PBEWITHSHA1ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndDES_CBC); -pub const PBEWITHSHA1ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndRC2_CBC); -pub const ID_PBKDF2: Nid = Nid(ffi::NID_id_pbkdf2); -pub const PBES2: Nid = Nid(ffi::NID_pbes2); -pub const PBMAC1: Nid = Nid(ffi::NID_pbmac1); -pub const PKCS7: Nid = Nid(ffi::NID_pkcs7); -pub const PKCS7_DATA: Nid = Nid(ffi::NID_pkcs7_data); -pub const PKCS7_SIGNED: Nid = Nid(ffi::NID_pkcs7_signed); -pub const PKCS7_ENVELOPED: Nid = Nid(ffi::NID_pkcs7_enveloped); -pub const PKCS7_SIGNEDANDENVELOPED: Nid = Nid(ffi::NID_pkcs7_signedAndEnveloped); -pub const PKCS7_DIGEST: Nid = Nid(ffi::NID_pkcs7_digest); -pub const PKCS7_ENCRYPTED: Nid = Nid(ffi::NID_pkcs7_encrypted); -pub const PKCS9: Nid = Nid(ffi::NID_pkcs9); -pub const PKCS9_EMAILADDRESS: Nid = Nid(ffi::NID_pkcs9_emailAddress); -pub const PKCS9_UNSTRUCTUREDNAME: Nid = Nid(ffi::NID_pkcs9_unstructuredName); -pub const PKCS9_CONTENTTYPE: Nid = Nid(ffi::NID_pkcs9_contentType); -pub const PKCS9_MESSAGEDIGEST: Nid = Nid(ffi::NID_pkcs9_messageDigest); -pub const PKCS9_SIGNINGTIME: Nid = Nid(ffi::NID_pkcs9_signingTime); -pub const PKCS9_COUNTERSIGNATURE: Nid = Nid(ffi::NID_pkcs9_countersignature); -pub const PKCS9_CHALLENGEPASSWORD: Nid = Nid(ffi::NID_pkcs9_challengePassword); -pub const PKCS9_UNSTRUCTUREDADDRESS: Nid = Nid(ffi::NID_pkcs9_unstructuredAddress); -pub const PKCS9_EXTCERTATTRIBUTES: Nid = Nid(ffi::NID_pkcs9_extCertAttributes); -pub const EXT_REQ: Nid = Nid(ffi::NID_ext_req); -pub const SMIMECAPABILITIES: Nid = Nid(ffi::NID_SMIMECapabilities); -pub const SMIME: Nid = Nid(ffi::NID_SMIME); -pub const ID_SMIME_MOD: Nid = Nid(ffi::NID_id_smime_mod); -pub const ID_SMIME_CT: Nid = Nid(ffi::NID_id_smime_ct); -pub const ID_SMIME_AA: Nid = Nid(ffi::NID_id_smime_aa); -pub const ID_SMIME_ALG: Nid = Nid(ffi::NID_id_smime_alg); -pub const ID_SMIME_CD: Nid = Nid(ffi::NID_id_smime_cd); -pub const ID_SMIME_SPQ: Nid = Nid(ffi::NID_id_smime_spq); -pub const ID_SMIME_CTI: Nid = Nid(ffi::NID_id_smime_cti); -pub const ID_SMIME_MOD_CMS: Nid = Nid(ffi::NID_id_smime_mod_cms); -pub const ID_SMIME_MOD_ESS: Nid = Nid(ffi::NID_id_smime_mod_ess); -pub const ID_SMIME_MOD_OID: Nid = Nid(ffi::NID_id_smime_mod_oid); -pub const ID_SMIME_MOD_MSG_V3: Nid = Nid(ffi::NID_id_smime_mod_msg_v3); -pub const ID_SMIME_MOD_ETS_ESIGNATURE_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_88); -pub const ID_SMIME_MOD_ETS_ESIGNATURE_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_97); -pub const ID_SMIME_MOD_ETS_ESIGPOLICY_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_88); -pub const ID_SMIME_MOD_ETS_ESIGPOLICY_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_97); -pub const ID_SMIME_CT_RECEIPT: Nid = Nid(ffi::NID_id_smime_ct_receipt); -pub const ID_SMIME_CT_AUTHDATA: Nid = Nid(ffi::NID_id_smime_ct_authData); -pub const ID_SMIME_CT_PUBLISHCERT: Nid = Nid(ffi::NID_id_smime_ct_publishCert); -pub const ID_SMIME_CT_TSTINFO: Nid = Nid(ffi::NID_id_smime_ct_TSTInfo); -pub const ID_SMIME_CT_TDTINFO: Nid = Nid(ffi::NID_id_smime_ct_TDTInfo); -pub const ID_SMIME_CT_CONTENTINFO: Nid = Nid(ffi::NID_id_smime_ct_contentInfo); -pub const ID_SMIME_CT_DVCSREQUESTDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSRequestData); -pub const ID_SMIME_CT_DVCSRESPONSEDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSResponseData); -pub const ID_SMIME_CT_COMPRESSEDDATA: Nid = Nid(ffi::NID_id_smime_ct_compressedData); -pub const ID_CT_ASCIITEXTWITHCRLF: Nid = Nid(ffi::NID_id_ct_asciiTextWithCRLF); -pub const ID_SMIME_AA_RECEIPTREQUEST: Nid = Nid(ffi::NID_id_smime_aa_receiptRequest); -pub const ID_SMIME_AA_SECURITYLABEL: Nid = Nid(ffi::NID_id_smime_aa_securityLabel); -pub const ID_SMIME_AA_MLEXPANDHISTORY: Nid = Nid(ffi::NID_id_smime_aa_mlExpandHistory); -pub const ID_SMIME_AA_CONTENTHINT: Nid = Nid(ffi::NID_id_smime_aa_contentHint); -pub const ID_SMIME_AA_MSGSIGDIGEST: Nid = Nid(ffi::NID_id_smime_aa_msgSigDigest); -pub const ID_SMIME_AA_ENCAPCONTENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_encapContentType); -pub const ID_SMIME_AA_CONTENTIDENTIFIER: Nid = Nid(ffi::NID_id_smime_aa_contentIdentifier); -pub const ID_SMIME_AA_MACVALUE: Nid = Nid(ffi::NID_id_smime_aa_macValue); -pub const ID_SMIME_AA_EQUIVALENTLABELS: Nid = Nid(ffi::NID_id_smime_aa_equivalentLabels); -pub const ID_SMIME_AA_CONTENTREFERENCE: Nid = Nid(ffi::NID_id_smime_aa_contentReference); -pub const ID_SMIME_AA_ENCRYPKEYPREF: Nid = Nid(ffi::NID_id_smime_aa_encrypKeyPref); -pub const ID_SMIME_AA_SIGNINGCERTIFICATE: Nid = Nid(ffi::NID_id_smime_aa_signingCertificate); -pub const ID_SMIME_AA_SMIMEENCRYPTCERTS: Nid = Nid(ffi::NID_id_smime_aa_smimeEncryptCerts); -pub const ID_SMIME_AA_TIMESTAMPTOKEN: Nid = Nid(ffi::NID_id_smime_aa_timeStampToken); -pub const ID_SMIME_AA_ETS_SIGPOLICYID: Nid = Nid(ffi::NID_id_smime_aa_ets_sigPolicyId); -pub const ID_SMIME_AA_ETS_COMMITMENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_ets_commitmentType); -pub const ID_SMIME_AA_ETS_SIGNERLOCATION: Nid = Nid(ffi::NID_id_smime_aa_ets_signerLocation); -pub const ID_SMIME_AA_ETS_SIGNERATTR: Nid = Nid(ffi::NID_id_smime_aa_ets_signerAttr); -pub const ID_SMIME_AA_ETS_OTHERSIGCERT: Nid = Nid(ffi::NID_id_smime_aa_ets_otherSigCert); -pub const ID_SMIME_AA_ETS_CONTENTTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_contentTimestamp); -pub const ID_SMIME_AA_ETS_CERTIFICATEREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_CertificateRefs); -pub const ID_SMIME_AA_ETS_REVOCATIONREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_RevocationRefs); -pub const ID_SMIME_AA_ETS_CERTVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_certValues); -pub const ID_SMIME_AA_ETS_REVOCATIONVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_revocationValues); -pub const ID_SMIME_AA_ETS_ESCTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_escTimeStamp); -pub const ID_SMIME_AA_ETS_CERTCRLTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_certCRLTimestamp); -pub const ID_SMIME_AA_ETS_ARCHIVETIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_archiveTimeStamp); -pub const ID_SMIME_AA_SIGNATURETYPE: Nid = Nid(ffi::NID_id_smime_aa_signatureType); -pub const ID_SMIME_AA_DVCS_DVC: Nid = Nid(ffi::NID_id_smime_aa_dvcs_dvc); -pub const ID_SMIME_ALG_ESDHWITH3DES: Nid = Nid(ffi::NID_id_smime_alg_ESDHwith3DES); -pub const ID_SMIME_ALG_ESDHWITHRC2: Nid = Nid(ffi::NID_id_smime_alg_ESDHwithRC2); -pub const ID_SMIME_ALG_3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_3DESwrap); -pub const ID_SMIME_ALG_RC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_RC2wrap); -pub const ID_SMIME_ALG_ESDH: Nid = Nid(ffi::NID_id_smime_alg_ESDH); -pub const ID_SMIME_ALG_CMS3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_CMS3DESwrap); -pub const ID_SMIME_ALG_CMSRC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_CMSRC2wrap); -pub const ID_ALG_PWRI_KEK: Nid = Nid(ffi::NID_id_alg_PWRI_KEK); -pub const ID_SMIME_CD_LDAP: Nid = Nid(ffi::NID_id_smime_cd_ldap); -pub const ID_SMIME_SPQ_ETS_SQT_URI: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_uri); -pub const ID_SMIME_SPQ_ETS_SQT_UNOTICE: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_unotice); -pub const ID_SMIME_CTI_ETS_PROOFOFORIGIN: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfOrigin); -pub const ID_SMIME_CTI_ETS_PROOFOFRECEIPT: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfReceipt); -pub const ID_SMIME_CTI_ETS_PROOFOFDELIVERY: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfDelivery); -pub const ID_SMIME_CTI_ETS_PROOFOFSENDER: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfSender); -pub const ID_SMIME_CTI_ETS_PROOFOFAPPROVAL: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfApproval); -pub const ID_SMIME_CTI_ETS_PROOFOFCREATION: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfCreation); -pub const FRIENDLYNAME: Nid = Nid(ffi::NID_friendlyName); -pub const LOCALKEYID: Nid = Nid(ffi::NID_localKeyID); -pub const MS_CSP_NAME: Nid = Nid(ffi::NID_ms_csp_name); -pub const LOCALKEYSET: Nid = Nid(ffi::NID_LocalKeySet); -pub const X509CERTIFICATE: Nid = Nid(ffi::NID_x509Certificate); -pub const SDSICERTIFICATE: Nid = Nid(ffi::NID_sdsiCertificate); -pub const X509CRL: Nid = Nid(ffi::NID_x509Crl); -pub const PBE_WITHSHA1AND128BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC4); -pub const PBE_WITHSHA1AND40BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC4); -pub const PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC: Nid = - Nid(ffi::NID_pbe_WithSHA1And3_Key_TripleDES_CBC); -pub const PBE_WITHSHA1AND2_KEY_TRIPLEDES_CBC: Nid = - Nid(ffi::NID_pbe_WithSHA1And2_Key_TripleDES_CBC); -pub const PBE_WITHSHA1AND128BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC2_CBC); -pub const PBE_WITHSHA1AND40BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC2_CBC); -pub const KEYBAG: Nid = Nid(ffi::NID_keyBag); -pub const PKCS8SHROUDEDKEYBAG: Nid = Nid(ffi::NID_pkcs8ShroudedKeyBag); -pub const CERTBAG: Nid = Nid(ffi::NID_certBag); -pub const CRLBAG: Nid = Nid(ffi::NID_crlBag); -pub const SECRETBAG: Nid = Nid(ffi::NID_secretBag); -pub const SAFECONTENTSBAG: Nid = Nid(ffi::NID_safeContentsBag); -pub const MD2: Nid = Nid(ffi::NID_md2); -pub const MD4: Nid = Nid(ffi::NID_md4); -pub const MD5: Nid = Nid(ffi::NID_md5); -pub const MD5_SHA1: Nid = Nid(ffi::NID_md5_sha1); -pub const HMACWITHMD5: Nid = Nid(ffi::NID_hmacWithMD5); -pub const HMACWITHSHA1: Nid = Nid(ffi::NID_hmacWithSHA1); -pub const HMACWITHSHA224: Nid = Nid(ffi::NID_hmacWithSHA224); -pub const HMACWITHSHA256: Nid = Nid(ffi::NID_hmacWithSHA256); -pub const HMACWITHSHA384: Nid = Nid(ffi::NID_hmacWithSHA384); -pub const HMACWITHSHA512: Nid = Nid(ffi::NID_hmacWithSHA512); -pub const RC2_CBC: Nid = Nid(ffi::NID_rc2_cbc); -pub const RC2_ECB: Nid = Nid(ffi::NID_rc2_ecb); -pub const RC2_CFB64: Nid = Nid(ffi::NID_rc2_cfb64); -pub const RC2_OFB64: Nid = Nid(ffi::NID_rc2_ofb64); -pub const RC2_40_CBC: Nid = Nid(ffi::NID_rc2_40_cbc); -pub const RC2_64_CBC: Nid = Nid(ffi::NID_rc2_64_cbc); -pub const RC4: Nid = Nid(ffi::NID_rc4); -pub const RC4_40: Nid = Nid(ffi::NID_rc4_40); -pub const DES_EDE3_CBC: Nid = Nid(ffi::NID_des_ede3_cbc); -pub const RC5_CBC: Nid = Nid(ffi::NID_rc5_cbc); -pub const RC5_ECB: Nid = Nid(ffi::NID_rc5_ecb); -pub const RC5_CFB64: Nid = Nid(ffi::NID_rc5_cfb64); -pub const RC5_OFB64: Nid = Nid(ffi::NID_rc5_ofb64); -pub const MS_EXT_REQ: Nid = Nid(ffi::NID_ms_ext_req); -pub const MS_CODE_IND: Nid = Nid(ffi::NID_ms_code_ind); -pub const MS_CODE_COM: Nid = Nid(ffi::NID_ms_code_com); -pub const MS_CTL_SIGN: Nid = Nid(ffi::NID_ms_ctl_sign); -pub const MS_SGC: Nid = Nid(ffi::NID_ms_sgc); -pub const MS_EFS: Nid = Nid(ffi::NID_ms_efs); -pub const MS_SMARTCARD_LOGIN: Nid = Nid(ffi::NID_ms_smartcard_login); -pub const MS_UPN: Nid = Nid(ffi::NID_ms_upn); -pub const IDEA_CBC: Nid = Nid(ffi::NID_idea_cbc); -pub const IDEA_ECB: Nid = Nid(ffi::NID_idea_ecb); -pub const IDEA_CFB64: Nid = Nid(ffi::NID_idea_cfb64); -pub const IDEA_OFB64: Nid = Nid(ffi::NID_idea_ofb64); -pub const BF_CBC: Nid = Nid(ffi::NID_bf_cbc); -pub const BF_ECB: Nid = Nid(ffi::NID_bf_ecb); -pub const BF_CFB64: Nid = Nid(ffi::NID_bf_cfb64); -pub const BF_OFB64: Nid = Nid(ffi::NID_bf_ofb64); -pub const ID_PKIX: Nid = Nid(ffi::NID_id_pkix); -pub const ID_PKIX_MOD: Nid = Nid(ffi::NID_id_pkix_mod); -pub const ID_PE: Nid = Nid(ffi::NID_id_pe); -pub const ID_QT: Nid = Nid(ffi::NID_id_qt); -pub const ID_KP: Nid = Nid(ffi::NID_id_kp); -pub const ID_IT: Nid = Nid(ffi::NID_id_it); -pub const ID_PKIP: Nid = Nid(ffi::NID_id_pkip); -pub const ID_ALG: Nid = Nid(ffi::NID_id_alg); -pub const ID_CMC: Nid = Nid(ffi::NID_id_cmc); -pub const ID_ON: Nid = Nid(ffi::NID_id_on); -pub const ID_PDA: Nid = Nid(ffi::NID_id_pda); -pub const ID_ACA: Nid = Nid(ffi::NID_id_aca); -pub const ID_QCS: Nid = Nid(ffi::NID_id_qcs); -pub const ID_CCT: Nid = Nid(ffi::NID_id_cct); -pub const ID_PPL: Nid = Nid(ffi::NID_id_ppl); -pub const ID_AD: Nid = Nid(ffi::NID_id_ad); -pub const ID_PKIX1_EXPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_explicit_88); -pub const ID_PKIX1_IMPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_implicit_88); -pub const ID_PKIX1_EXPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_explicit_93); -pub const ID_PKIX1_IMPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_implicit_93); -pub const ID_MOD_CRMF: Nid = Nid(ffi::NID_id_mod_crmf); -pub const ID_MOD_CMC: Nid = Nid(ffi::NID_id_mod_cmc); -pub const ID_MOD_KEA_PROFILE_88: Nid = Nid(ffi::NID_id_mod_kea_profile_88); -pub const ID_MOD_KEA_PROFILE_93: Nid = Nid(ffi::NID_id_mod_kea_profile_93); -pub const ID_MOD_CMP: Nid = Nid(ffi::NID_id_mod_cmp); -pub const ID_MOD_QUALIFIED_CERT_88: Nid = Nid(ffi::NID_id_mod_qualified_cert_88); -pub const ID_MOD_QUALIFIED_CERT_93: Nid = Nid(ffi::NID_id_mod_qualified_cert_93); -pub const ID_MOD_ATTRIBUTE_CERT: Nid = Nid(ffi::NID_id_mod_attribute_cert); -pub const ID_MOD_TIMESTAMP_PROTOCOL: Nid = Nid(ffi::NID_id_mod_timestamp_protocol); -pub const ID_MOD_OCSP: Nid = Nid(ffi::NID_id_mod_ocsp); -pub const ID_MOD_DVCS: Nid = Nid(ffi::NID_id_mod_dvcs); -pub const ID_MOD_CMP2000: Nid = Nid(ffi::NID_id_mod_cmp2000); -pub const INFO_ACCESS: Nid = Nid(ffi::NID_info_access); -pub const BIOMETRICINFO: Nid = Nid(ffi::NID_biometricInfo); -pub const QCSTATEMENTS: Nid = Nid(ffi::NID_qcStatements); -pub const AC_AUDITENTITY: Nid = Nid(ffi::NID_ac_auditEntity); -pub const AC_TARGETING: Nid = Nid(ffi::NID_ac_targeting); -pub const AACONTROLS: Nid = Nid(ffi::NID_aaControls); -pub const SBGP_IPADDRBLOCK: Nid = Nid(ffi::NID_sbgp_ipAddrBlock); -pub const SBGP_AUTONOMOUSSYSNUM: Nid = Nid(ffi::NID_sbgp_autonomousSysNum); -pub const SBGP_ROUTERIDENTIFIER: Nid = Nid(ffi::NID_sbgp_routerIdentifier); -pub const AC_PROXYING: Nid = Nid(ffi::NID_ac_proxying); -pub const SINFO_ACCESS: Nid = Nid(ffi::NID_sinfo_access); -pub const PROXYCERTINFO: Nid = Nid(ffi::NID_proxyCertInfo); -pub const ID_QT_CPS: Nid = Nid(ffi::NID_id_qt_cps); -pub const ID_QT_UNOTICE: Nid = Nid(ffi::NID_id_qt_unotice); -pub const TEXTNOTICE: Nid = Nid(ffi::NID_textNotice); -pub const SERVER_AUTH: Nid = Nid(ffi::NID_server_auth); -pub const CLIENT_AUTH: Nid = Nid(ffi::NID_client_auth); -pub const CODE_SIGN: Nid = Nid(ffi::NID_code_sign); -pub const EMAIL_PROTECT: Nid = Nid(ffi::NID_email_protect); -pub const IPSECENDSYSTEM: Nid = Nid(ffi::NID_ipsecEndSystem); -pub const IPSECTUNNEL: Nid = Nid(ffi::NID_ipsecTunnel); -pub const IPSECUSER: Nid = Nid(ffi::NID_ipsecUser); -pub const TIME_STAMP: Nid = Nid(ffi::NID_time_stamp); -pub const OCSP_SIGN: Nid = Nid(ffi::NID_OCSP_sign); -pub const DVCS: Nid = Nid(ffi::NID_dvcs); -pub const ID_IT_CAPROTENCCERT: Nid = Nid(ffi::NID_id_it_caProtEncCert); -pub const ID_IT_SIGNKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_signKeyPairTypes); -pub const ID_IT_ENCKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_encKeyPairTypes); -pub const ID_IT_PREFERREDSYMMALG: Nid = Nid(ffi::NID_id_it_preferredSymmAlg); -pub const ID_IT_CAKEYUPDATEINFO: Nid = Nid(ffi::NID_id_it_caKeyUpdateInfo); -pub const ID_IT_CURRENTCRL: Nid = Nid(ffi::NID_id_it_currentCRL); -pub const ID_IT_UNSUPPORTEDOIDS: Nid = Nid(ffi::NID_id_it_unsupportedOIDs); -pub const ID_IT_SUBSCRIPTIONREQUEST: Nid = Nid(ffi::NID_id_it_subscriptionRequest); -pub const ID_IT_SUBSCRIPTIONRESPONSE: Nid = Nid(ffi::NID_id_it_subscriptionResponse); -pub const ID_IT_KEYPAIRPARAMREQ: Nid = Nid(ffi::NID_id_it_keyPairParamReq); -pub const ID_IT_KEYPAIRPARAMREP: Nid = Nid(ffi::NID_id_it_keyPairParamRep); -pub const ID_IT_REVPASSPHRASE: Nid = Nid(ffi::NID_id_it_revPassphrase); -pub const ID_IT_IMPLICITCONFIRM: Nid = Nid(ffi::NID_id_it_implicitConfirm); -pub const ID_IT_CONFIRMWAITTIME: Nid = Nid(ffi::NID_id_it_confirmWaitTime); -pub const ID_IT_ORIGPKIMESSAGE: Nid = Nid(ffi::NID_id_it_origPKIMessage); -pub const ID_IT_SUPPLANGTAGS: Nid = Nid(ffi::NID_id_it_suppLangTags); -pub const ID_REGCTRL: Nid = Nid(ffi::NID_id_regCtrl); -pub const ID_REGINFO: Nid = Nid(ffi::NID_id_regInfo); -pub const ID_REGCTRL_REGTOKEN: Nid = Nid(ffi::NID_id_regCtrl_regToken); -pub const ID_REGCTRL_AUTHENTICATOR: Nid = Nid(ffi::NID_id_regCtrl_authenticator); -pub const ID_REGCTRL_PKIPUBLICATIONINFO: Nid = Nid(ffi::NID_id_regCtrl_pkiPublicationInfo); -pub const ID_REGCTRL_PKIARCHIVEOPTIONS: Nid = Nid(ffi::NID_id_regCtrl_pkiArchiveOptions); -pub const ID_REGCTRL_OLDCERTID: Nid = Nid(ffi::NID_id_regCtrl_oldCertID); -pub const ID_REGCTRL_PROTOCOLENCRKEY: Nid = Nid(ffi::NID_id_regCtrl_protocolEncrKey); -pub const ID_REGINFO_UTF8PAIRS: Nid = Nid(ffi::NID_id_regInfo_utf8Pairs); -pub const ID_REGINFO_CERTREQ: Nid = Nid(ffi::NID_id_regInfo_certReq); -pub const ID_ALG_DES40: Nid = Nid(ffi::NID_id_alg_des40); -pub const ID_ALG_NOSIGNATURE: Nid = Nid(ffi::NID_id_alg_noSignature); -pub const ID_ALG_DH_SIG_HMAC_SHA1: Nid = Nid(ffi::NID_id_alg_dh_sig_hmac_sha1); -pub const ID_ALG_DH_POP: Nid = Nid(ffi::NID_id_alg_dh_pop); -pub const ID_CMC_STATUSINFO: Nid = Nid(ffi::NID_id_cmc_statusInfo); -pub const ID_CMC_IDENTIFICATION: Nid = Nid(ffi::NID_id_cmc_identification); -pub const ID_CMC_IDENTITYPROOF: Nid = Nid(ffi::NID_id_cmc_identityProof); -pub const ID_CMC_DATARETURN: Nid = Nid(ffi::NID_id_cmc_dataReturn); -pub const ID_CMC_TRANSACTIONID: Nid = Nid(ffi::NID_id_cmc_transactionId); -pub const ID_CMC_SENDERNONCE: Nid = Nid(ffi::NID_id_cmc_senderNonce); -pub const ID_CMC_RECIPIENTNONCE: Nid = Nid(ffi::NID_id_cmc_recipientNonce); -pub const ID_CMC_ADDEXTENSIONS: Nid = Nid(ffi::NID_id_cmc_addExtensions); -pub const ID_CMC_ENCRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_encryptedPOP); -pub const ID_CMC_DECRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_decryptedPOP); -pub const ID_CMC_LRAPOPWITNESS: Nid = Nid(ffi::NID_id_cmc_lraPOPWitness); -pub const ID_CMC_GETCERT: Nid = Nid(ffi::NID_id_cmc_getCert); -pub const ID_CMC_GETCRL: Nid = Nid(ffi::NID_id_cmc_getCRL); -pub const ID_CMC_REVOKEREQUEST: Nid = Nid(ffi::NID_id_cmc_revokeRequest); -pub const ID_CMC_REGINFO: Nid = Nid(ffi::NID_id_cmc_regInfo); -pub const ID_CMC_RESPONSEINFO: Nid = Nid(ffi::NID_id_cmc_responseInfo); -pub const ID_CMC_QUERYPENDING: Nid = Nid(ffi::NID_id_cmc_queryPending); -pub const ID_CMC_POPLINKRANDOM: Nid = Nid(ffi::NID_id_cmc_popLinkRandom); -pub const ID_CMC_POPLINKWITNESS: Nid = Nid(ffi::NID_id_cmc_popLinkWitness); -pub const ID_CMC_CONFIRMCERTACCEPTANCE: Nid = Nid(ffi::NID_id_cmc_confirmCertAcceptance); -pub const ID_ON_PERSONALDATA: Nid = Nid(ffi::NID_id_on_personalData); -pub const ID_ON_PERMANENTIDENTIFIER: Nid = Nid(ffi::NID_id_on_permanentIdentifier); -pub const ID_PDA_DATEOFBIRTH: Nid = Nid(ffi::NID_id_pda_dateOfBirth); -pub const ID_PDA_PLACEOFBIRTH: Nid = Nid(ffi::NID_id_pda_placeOfBirth); -pub const ID_PDA_GENDER: Nid = Nid(ffi::NID_id_pda_gender); -pub const ID_PDA_COUNTRYOFCITIZENSHIP: Nid = Nid(ffi::NID_id_pda_countryOfCitizenship); -pub const ID_PDA_COUNTRYOFRESIDENCE: Nid = Nid(ffi::NID_id_pda_countryOfResidence); -pub const ID_ACA_AUTHENTICATIONINFO: Nid = Nid(ffi::NID_id_aca_authenticationInfo); -pub const ID_ACA_ACCESSIDENTITY: Nid = Nid(ffi::NID_id_aca_accessIdentity); -pub const ID_ACA_CHARGINGIDENTITY: Nid = Nid(ffi::NID_id_aca_chargingIdentity); -pub const ID_ACA_GROUP: Nid = Nid(ffi::NID_id_aca_group); -pub const ID_ACA_ROLE: Nid = Nid(ffi::NID_id_aca_role); -pub const ID_ACA_ENCATTRS: Nid = Nid(ffi::NID_id_aca_encAttrs); -pub const ID_QCS_PKIXQCSYNTAX_V1: Nid = Nid(ffi::NID_id_qcs_pkixQCSyntax_v1); -pub const ID_CCT_CRS: Nid = Nid(ffi::NID_id_cct_crs); -pub const ID_CCT_PKIDATA: Nid = Nid(ffi::NID_id_cct_PKIData); -pub const ID_CCT_PKIRESPONSE: Nid = Nid(ffi::NID_id_cct_PKIResponse); -pub const ID_PPL_ANYLANGUAGE: Nid = Nid(ffi::NID_id_ppl_anyLanguage); -pub const ID_PPL_INHERITALL: Nid = Nid(ffi::NID_id_ppl_inheritAll); -pub const INDEPENDENT: Nid = Nid(ffi::NID_Independent); -pub const AD_OCSP: Nid = Nid(ffi::NID_ad_OCSP); -pub const AD_CA_ISSUERS: Nid = Nid(ffi::NID_ad_ca_issuers); -pub const AD_TIMESTAMPING: Nid = Nid(ffi::NID_ad_timeStamping); -pub const AD_DVCS: Nid = Nid(ffi::NID_ad_dvcs); -pub const CAREPOSITORY: Nid = Nid(ffi::NID_caRepository); -pub const ID_PKIX_OCSP_BASIC: Nid = Nid(ffi::NID_id_pkix_OCSP_basic); -pub const ID_PKIX_OCSP_NONCE: Nid = Nid(ffi::NID_id_pkix_OCSP_Nonce); -pub const ID_PKIX_OCSP_CRLID: Nid = Nid(ffi::NID_id_pkix_OCSP_CrlID); -pub const ID_PKIX_OCSP_ACCEPTABLERESPONSES: Nid = Nid(ffi::NID_id_pkix_OCSP_acceptableResponses); -pub const ID_PKIX_OCSP_NOCHECK: Nid = Nid(ffi::NID_id_pkix_OCSP_noCheck); -pub const ID_PKIX_OCSP_ARCHIVECUTOFF: Nid = Nid(ffi::NID_id_pkix_OCSP_archiveCutoff); -pub const ID_PKIX_OCSP_SERVICELOCATOR: Nid = Nid(ffi::NID_id_pkix_OCSP_serviceLocator); -pub const ID_PKIX_OCSP_EXTENDEDSTATUS: Nid = Nid(ffi::NID_id_pkix_OCSP_extendedStatus); -pub const ID_PKIX_OCSP_VALID: Nid = Nid(ffi::NID_id_pkix_OCSP_valid); -pub const ID_PKIX_OCSP_PATH: Nid = Nid(ffi::NID_id_pkix_OCSP_path); -pub const ID_PKIX_OCSP_TRUSTROOT: Nid = Nid(ffi::NID_id_pkix_OCSP_trustRoot); -pub const ALGORITHM: Nid = Nid(ffi::NID_algorithm); -pub const MD5WITHRSA: Nid = Nid(ffi::NID_md5WithRSA); -pub const DES_ECB: Nid = Nid(ffi::NID_des_ecb); -pub const DES_CBC: Nid = Nid(ffi::NID_des_cbc); -pub const DES_OFB64: Nid = Nid(ffi::NID_des_ofb64); -pub const DES_CFB64: Nid = Nid(ffi::NID_des_cfb64); -pub const RSASIGNATURE: Nid = Nid(ffi::NID_rsaSignature); -pub const DSA_2: Nid = Nid(ffi::NID_dsa_2); -pub const DSAWITHSHA: Nid = Nid(ffi::NID_dsaWithSHA); -pub const SHAWITHRSAENCRYPTION: Nid = Nid(ffi::NID_shaWithRSAEncryption); -pub const DES_EDE_ECB: Nid = Nid(ffi::NID_des_ede_ecb); -pub const DES_EDE3_ECB: Nid = Nid(ffi::NID_des_ede3_ecb); -pub const DES_EDE_CBC: Nid = Nid(ffi::NID_des_ede_cbc); -pub const DES_EDE_CFB64: Nid = Nid(ffi::NID_des_ede_cfb64); -pub const DES_EDE3_CFB64: Nid = Nid(ffi::NID_des_ede3_cfb64); -pub const DES_EDE_OFB64: Nid = Nid(ffi::NID_des_ede_ofb64); -pub const DES_EDE3_OFB64: Nid = Nid(ffi::NID_des_ede3_ofb64); -pub const DESX_CBC: Nid = Nid(ffi::NID_desx_cbc); -pub const SHA: Nid = Nid(ffi::NID_sha); -pub const SHA1: Nid = Nid(ffi::NID_sha1); -pub const DSAWITHSHA1_2: Nid = Nid(ffi::NID_dsaWithSHA1_2); -pub const SHA1WITHRSA: Nid = Nid(ffi::NID_sha1WithRSA); -pub const RIPEMD160: Nid = Nid(ffi::NID_ripemd160); -pub const RIPEMD160WITHRSA: Nid = Nid(ffi::NID_ripemd160WithRSA); -pub const SXNET: Nid = Nid(ffi::NID_sxnet); -pub const X500: Nid = Nid(ffi::NID_X500); -pub const X509: Nid = Nid(ffi::NID_X509); -pub const COMMONNAME: Nid = Nid(ffi::NID_commonName); -pub const SURNAME: Nid = Nid(ffi::NID_surname); -pub const SERIALNUMBER: Nid = Nid(ffi::NID_serialNumber); -pub const COUNTRYNAME: Nid = Nid(ffi::NID_countryName); -pub const LOCALITYNAME: Nid = Nid(ffi::NID_localityName); -pub const STATEORPROVINCENAME: Nid = Nid(ffi::NID_stateOrProvinceName); -pub const STREETADDRESS: Nid = Nid(ffi::NID_streetAddress); -pub const ORGANIZATIONNAME: Nid = Nid(ffi::NID_organizationName); -pub const ORGANIZATIONALUNITNAME: Nid = Nid(ffi::NID_organizationalUnitName); -pub const TITLE: Nid = Nid(ffi::NID_title); -pub const DESCRIPTION: Nid = Nid(ffi::NID_description); -pub const SEARCHGUIDE: Nid = Nid(ffi::NID_searchGuide); -pub const BUSINESSCATEGORY: Nid = Nid(ffi::NID_businessCategory); -pub const POSTALADDRESS: Nid = Nid(ffi::NID_postalAddress); -pub const POSTALCODE: Nid = Nid(ffi::NID_postalCode); -pub const POSTOFFICEBOX: Nid = Nid(ffi::NID_postOfficeBox); -pub const PHYSICALDELIVERYOFFICENAME: Nid = Nid(ffi::NID_physicalDeliveryOfficeName); -pub const TELEPHONENUMBER: Nid = Nid(ffi::NID_telephoneNumber); -pub const TELEXNUMBER: Nid = Nid(ffi::NID_telexNumber); -pub const TELETEXTERMINALIDENTIFIER: Nid = Nid(ffi::NID_teletexTerminalIdentifier); -pub const FACSIMILETELEPHONENUMBER: Nid = Nid(ffi::NID_facsimileTelephoneNumber); -pub const X121ADDRESS: Nid = Nid(ffi::NID_x121Address); -pub const INTERNATIONALISDNNUMBER: Nid = Nid(ffi::NID_internationaliSDNNumber); -pub const REGISTEREDADDRESS: Nid = Nid(ffi::NID_registeredAddress); -pub const DESTINATIONINDICATOR: Nid = Nid(ffi::NID_destinationIndicator); -pub const PREFERREDDELIVERYMETHOD: Nid = Nid(ffi::NID_preferredDeliveryMethod); -pub const PRESENTATIONADDRESS: Nid = Nid(ffi::NID_presentationAddress); -pub const SUPPORTEDAPPLICATIONCONTEXT: Nid = Nid(ffi::NID_supportedApplicationContext); -pub const MEMBER: Nid = Nid(ffi::NID_member); -pub const OWNER: Nid = Nid(ffi::NID_owner); -pub const ROLEOCCUPANT: Nid = Nid(ffi::NID_roleOccupant); -pub const SEEALSO: Nid = Nid(ffi::NID_seeAlso); -pub const USERPASSWORD: Nid = Nid(ffi::NID_userPassword); -pub const USERCERTIFICATE: Nid = Nid(ffi::NID_userCertificate); -pub const CACERTIFICATE: Nid = Nid(ffi::NID_cACertificate); -pub const AUTHORITYREVOCATIONLIST: Nid = Nid(ffi::NID_authorityRevocationList); -pub const CERTIFICATEREVOCATIONLIST: Nid = Nid(ffi::NID_certificateRevocationList); -pub const CROSSCERTIFICATEPAIR: Nid = Nid(ffi::NID_crossCertificatePair); -pub const NAME: Nid = Nid(ffi::NID_name); -pub const GIVENNAME: Nid = Nid(ffi::NID_givenName); -pub const INITIALS: Nid = Nid(ffi::NID_initials); -pub const GENERATIONQUALIFIER: Nid = Nid(ffi::NID_generationQualifier); -pub const X500UNIQUEIDENTIFIER: Nid = Nid(ffi::NID_x500UniqueIdentifier); -pub const DNQUALIFIER: Nid = Nid(ffi::NID_dnQualifier); -pub const ENHANCEDSEARCHGUIDE: Nid = Nid(ffi::NID_enhancedSearchGuide); -pub const PROTOCOLINFORMATION: Nid = Nid(ffi::NID_protocolInformation); -pub const DISTINGUISHEDNAME: Nid = Nid(ffi::NID_distinguishedName); -pub const UNIQUEMEMBER: Nid = Nid(ffi::NID_uniqueMember); -pub const HOUSEIDENTIFIER: Nid = Nid(ffi::NID_houseIdentifier); -pub const SUPPORTEDALGORITHMS: Nid = Nid(ffi::NID_supportedAlgorithms); -pub const DELTAREVOCATIONLIST: Nid = Nid(ffi::NID_deltaRevocationList); -pub const DMDNAME: Nid = Nid(ffi::NID_dmdName); -pub const PSEUDONYM: Nid = Nid(ffi::NID_pseudonym); -pub const ROLE: Nid = Nid(ffi::NID_role); -pub const X500ALGORITHMS: Nid = Nid(ffi::NID_X500algorithms); -pub const RSA: Nid = Nid(ffi::NID_rsa); -pub const MDC2WITHRSA: Nid = Nid(ffi::NID_mdc2WithRSA); -pub const MDC2: Nid = Nid(ffi::NID_mdc2); -pub const ID_CE: Nid = Nid(ffi::NID_id_ce); -pub const SUBJECT_DIRECTORY_ATTRIBUTES: Nid = Nid(ffi::NID_subject_directory_attributes); -pub const SUBJECT_KEY_IDENTIFIER: Nid = Nid(ffi::NID_subject_key_identifier); -pub const KEY_USAGE: Nid = Nid(ffi::NID_key_usage); -pub const PRIVATE_KEY_USAGE_PERIOD: Nid = Nid(ffi::NID_private_key_usage_period); -pub const SUBJECT_ALT_NAME: Nid = Nid(ffi::NID_subject_alt_name); -pub const ISSUER_ALT_NAME: Nid = Nid(ffi::NID_issuer_alt_name); -pub const BASIC_CONSTRAINTS: Nid = Nid(ffi::NID_basic_constraints); -pub const CRL_NUMBER: Nid = Nid(ffi::NID_crl_number); -pub const CRL_REASON: Nid = Nid(ffi::NID_crl_reason); -pub const INVALIDITY_DATE: Nid = Nid(ffi::NID_invalidity_date); -pub const DELTA_CRL: Nid = Nid(ffi::NID_delta_crl); -pub const ISSUING_DISTRIBUTION_POINT: Nid = Nid(ffi::NID_issuing_distribution_point); -pub const CERTIFICATE_ISSUER: Nid = Nid(ffi::NID_certificate_issuer); -pub const NAME_CONSTRAINTS: Nid = Nid(ffi::NID_name_constraints); -pub const CRL_DISTRIBUTION_POINTS: Nid = Nid(ffi::NID_crl_distribution_points); -pub const CERTIFICATE_POLICIES: Nid = Nid(ffi::NID_certificate_policies); -pub const ANY_POLICY: Nid = Nid(ffi::NID_any_policy); -pub const POLICY_MAPPINGS: Nid = Nid(ffi::NID_policy_mappings); -pub const AUTHORITY_KEY_IDENTIFIER: Nid = Nid(ffi::NID_authority_key_identifier); -pub const POLICY_CONSTRAINTS: Nid = Nid(ffi::NID_policy_constraints); -pub const EXT_KEY_USAGE: Nid = Nid(ffi::NID_ext_key_usage); -pub const FRESHEST_CRL: Nid = Nid(ffi::NID_freshest_crl); -pub const INHIBIT_ANY_POLICY: Nid = Nid(ffi::NID_inhibit_any_policy); -pub const TARGET_INFORMATION: Nid = Nid(ffi::NID_target_information); -pub const NO_REV_AVAIL: Nid = Nid(ffi::NID_no_rev_avail); -pub const ANYEXTENDEDKEYUSAGE: Nid = Nid(ffi::NID_anyExtendedKeyUsage); -pub const NETSCAPE: Nid = Nid(ffi::NID_netscape); -pub const NETSCAPE_CERT_EXTENSION: Nid = Nid(ffi::NID_netscape_cert_extension); -pub const NETSCAPE_DATA_TYPE: Nid = Nid(ffi::NID_netscape_data_type); -pub const NETSCAPE_CERT_TYPE: Nid = Nid(ffi::NID_netscape_cert_type); -pub const NETSCAPE_BASE_URL: Nid = Nid(ffi::NID_netscape_base_url); -pub const NETSCAPE_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_revocation_url); -pub const NETSCAPE_CA_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_ca_revocation_url); -pub const NETSCAPE_RENEWAL_URL: Nid = Nid(ffi::NID_netscape_renewal_url); -pub const NETSCAPE_CA_POLICY_URL: Nid = Nid(ffi::NID_netscape_ca_policy_url); -pub const NETSCAPE_SSL_SERVER_NAME: Nid = Nid(ffi::NID_netscape_ssl_server_name); -pub const NETSCAPE_COMMENT: Nid = Nid(ffi::NID_netscape_comment); -pub const NETSCAPE_CERT_SEQUENCE: Nid = Nid(ffi::NID_netscape_cert_sequence); -pub const NS_SGC: Nid = Nid(ffi::NID_ns_sgc); -pub const ORG: Nid = Nid(ffi::NID_org); -pub const DOD: Nid = Nid(ffi::NID_dod); -pub const IANA: Nid = Nid(ffi::NID_iana); -pub const DIRECTORY: Nid = Nid(ffi::NID_Directory); -pub const MANAGEMENT: Nid = Nid(ffi::NID_Management); -pub const EXPERIMENTAL: Nid = Nid(ffi::NID_Experimental); -pub const PRIVATE: Nid = Nid(ffi::NID_Private); -pub const SECURITY: Nid = Nid(ffi::NID_Security); -pub const SNMPV2: Nid = Nid(ffi::NID_SNMPv2); -pub const MAIL: Nid = Nid(ffi::NID_Mail); -pub const ENTERPRISES: Nid = Nid(ffi::NID_Enterprises); -pub const DCOBJECT: Nid = Nid(ffi::NID_dcObject); -pub const MIME_MHS: Nid = Nid(ffi::NID_mime_mhs); -pub const MIME_MHS_HEADINGS: Nid = Nid(ffi::NID_mime_mhs_headings); -pub const MIME_MHS_BODIES: Nid = Nid(ffi::NID_mime_mhs_bodies); -pub const ID_HEX_PARTIAL_MESSAGE: Nid = Nid(ffi::NID_id_hex_partial_message); -pub const ID_HEX_MULTIPART_MESSAGE: Nid = Nid(ffi::NID_id_hex_multipart_message); -pub const ZLIB_COMPRESSION: Nid = Nid(ffi::NID_zlib_compression); -pub const AES_128_ECB: Nid = Nid(ffi::NID_aes_128_ecb); -pub const AES_128_CBC: Nid = Nid(ffi::NID_aes_128_cbc); -pub const AES_128_OFB128: Nid = Nid(ffi::NID_aes_128_ofb128); -pub const AES_128_CFB128: Nid = Nid(ffi::NID_aes_128_cfb128); -pub const ID_AES128_WRAP: Nid = Nid(ffi::NID_id_aes128_wrap); -pub const AES_128_GCM: Nid = Nid(ffi::NID_aes_128_gcm); -pub const AES_128_CCM: Nid = Nid(ffi::NID_aes_128_ccm); -pub const ID_AES128_WRAP_PAD: Nid = Nid(ffi::NID_id_aes128_wrap_pad); -pub const AES_192_ECB: Nid = Nid(ffi::NID_aes_192_ecb); -pub const AES_192_CBC: Nid = Nid(ffi::NID_aes_192_cbc); -pub const AES_192_OFB128: Nid = Nid(ffi::NID_aes_192_ofb128); -pub const AES_192_CFB128: Nid = Nid(ffi::NID_aes_192_cfb128); -pub const ID_AES192_WRAP: Nid = Nid(ffi::NID_id_aes192_wrap); -pub const AES_192_GCM: Nid = Nid(ffi::NID_aes_192_gcm); -pub const AES_192_CCM: Nid = Nid(ffi::NID_aes_192_ccm); -pub const ID_AES192_WRAP_PAD: Nid = Nid(ffi::NID_id_aes192_wrap_pad); -pub const AES_256_ECB: Nid = Nid(ffi::NID_aes_256_ecb); -pub const AES_256_CBC: Nid = Nid(ffi::NID_aes_256_cbc); -pub const AES_256_OFB128: Nid = Nid(ffi::NID_aes_256_ofb128); -pub const AES_256_CFB128: Nid = Nid(ffi::NID_aes_256_cfb128); -pub const ID_AES256_WRAP: Nid = Nid(ffi::NID_id_aes256_wrap); -pub const AES_256_GCM: Nid = Nid(ffi::NID_aes_256_gcm); -pub const AES_256_CCM: Nid = Nid(ffi::NID_aes_256_ccm); -pub const ID_AES256_WRAP_PAD: Nid = Nid(ffi::NID_id_aes256_wrap_pad); -pub const AES_128_CFB1: Nid = Nid(ffi::NID_aes_128_cfb1); -pub const AES_192_CFB1: Nid = Nid(ffi::NID_aes_192_cfb1); -pub const AES_256_CFB1: Nid = Nid(ffi::NID_aes_256_cfb1); -pub const AES_128_CFB8: Nid = Nid(ffi::NID_aes_128_cfb8); -pub const AES_192_CFB8: Nid = Nid(ffi::NID_aes_192_cfb8); -pub const AES_256_CFB8: Nid = Nid(ffi::NID_aes_256_cfb8); -pub const AES_128_CTR: Nid = Nid(ffi::NID_aes_128_ctr); -pub const AES_192_CTR: Nid = Nid(ffi::NID_aes_192_ctr); -pub const AES_256_CTR: Nid = Nid(ffi::NID_aes_256_ctr); -pub const AES_128_XTS: Nid = Nid(ffi::NID_aes_128_xts); -pub const AES_256_XTS: Nid = Nid(ffi::NID_aes_256_xts); -pub const DES_CFB1: Nid = Nid(ffi::NID_des_cfb1); -pub const DES_CFB8: Nid = Nid(ffi::NID_des_cfb8); -pub const DES_EDE3_CFB1: Nid = Nid(ffi::NID_des_ede3_cfb1); -pub const DES_EDE3_CFB8: Nid = Nid(ffi::NID_des_ede3_cfb8); -pub const SHA256: Nid = Nid(ffi::NID_sha256); -pub const SHA384: Nid = Nid(ffi::NID_sha384); -pub const SHA512: Nid = Nid(ffi::NID_sha512); -pub const SHA224: Nid = Nid(ffi::NID_sha224); -pub const DSA_WITH_SHA224: Nid = Nid(ffi::NID_dsa_with_SHA224); -pub const DSA_WITH_SHA256: Nid = Nid(ffi::NID_dsa_with_SHA256); -pub const HOLD_INSTRUCTION_CODE: Nid = Nid(ffi::NID_hold_instruction_code); -pub const HOLD_INSTRUCTION_NONE: Nid = Nid(ffi::NID_hold_instruction_none); -pub const HOLD_INSTRUCTION_CALL_ISSUER: Nid = Nid(ffi::NID_hold_instruction_call_issuer); -pub const HOLD_INSTRUCTION_REJECT: Nid = Nid(ffi::NID_hold_instruction_reject); -pub const DATA: Nid = Nid(ffi::NID_data); -pub const PSS: Nid = Nid(ffi::NID_pss); -pub const UCL: Nid = Nid(ffi::NID_ucl); -pub const PILOT: Nid = Nid(ffi::NID_pilot); -pub const PILOTATTRIBUTETYPE: Nid = Nid(ffi::NID_pilotAttributeType); -pub const PILOTATTRIBUTESYNTAX: Nid = Nid(ffi::NID_pilotAttributeSyntax); -pub const PILOTOBJECTCLASS: Nid = Nid(ffi::NID_pilotObjectClass); -pub const PILOTGROUPS: Nid = Nid(ffi::NID_pilotGroups); -pub const IA5STRINGSYNTAX: Nid = Nid(ffi::NID_iA5StringSyntax); -pub const CASEIGNOREIA5STRINGSYNTAX: Nid = Nid(ffi::NID_caseIgnoreIA5StringSyntax); -pub const PILOTOBJECT: Nid = Nid(ffi::NID_pilotObject); -pub const PILOTPERSON: Nid = Nid(ffi::NID_pilotPerson); -pub const ACCOUNT: Nid = Nid(ffi::NID_account); -pub const DOCUMENT: Nid = Nid(ffi::NID_document); -pub const ROOM: Nid = Nid(ffi::NID_room); -pub const DOCUMENTSERIES: Nid = Nid(ffi::NID_documentSeries); -pub const DOMAIN: Nid = Nid(ffi::NID_Domain); -pub const RFC822LOCALPART: Nid = Nid(ffi::NID_rFC822localPart); -pub const DNSDOMAIN: Nid = Nid(ffi::NID_dNSDomain); -pub const DOMAINRELATEDOBJECT: Nid = Nid(ffi::NID_domainRelatedObject); -pub const FRIENDLYCOUNTRY: Nid = Nid(ffi::NID_friendlyCountry); -pub const SIMPLESECURITYOBJECT: Nid = Nid(ffi::NID_simpleSecurityObject); -pub const PILOTORGANIZATION: Nid = Nid(ffi::NID_pilotOrganization); -pub const PILOTDSA: Nid = Nid(ffi::NID_pilotDSA); -pub const QUALITYLABELLEDDATA: Nid = Nid(ffi::NID_qualityLabelledData); -pub const USERID: Nid = Nid(ffi::NID_userId); -pub const TEXTENCODEDORADDRESS: Nid = Nid(ffi::NID_textEncodedORAddress); -pub const RFC822MAILBOX: Nid = Nid(ffi::NID_rfc822Mailbox); -pub const INFO: Nid = Nid(ffi::NID_info); -pub const FAVOURITEDRINK: Nid = Nid(ffi::NID_favouriteDrink); -pub const ROOMNUMBER: Nid = Nid(ffi::NID_roomNumber); -pub const PHOTO: Nid = Nid(ffi::NID_photo); -pub const USERCLASS: Nid = Nid(ffi::NID_userClass); -pub const HOST: Nid = Nid(ffi::NID_host); -pub const MANAGER: Nid = Nid(ffi::NID_manager); -pub const DOCUMENTIDENTIFIER: Nid = Nid(ffi::NID_documentIdentifier); -pub const DOCUMENTTITLE: Nid = Nid(ffi::NID_documentTitle); -pub const DOCUMENTVERSION: Nid = Nid(ffi::NID_documentVersion); -pub const DOCUMENTAUTHOR: Nid = Nid(ffi::NID_documentAuthor); -pub const DOCUMENTLOCATION: Nid = Nid(ffi::NID_documentLocation); -pub const HOMETELEPHONENUMBER: Nid = Nid(ffi::NID_homeTelephoneNumber); -pub const SECRETARY: Nid = Nid(ffi::NID_secretary); -pub const OTHERMAILBOX: Nid = Nid(ffi::NID_otherMailbox); -pub const LASTMODIFIEDTIME: Nid = Nid(ffi::NID_lastModifiedTime); -pub const LASTMODIFIEDBY: Nid = Nid(ffi::NID_lastModifiedBy); -pub const DOMAINCOMPONENT: Nid = Nid(ffi::NID_domainComponent); -pub const ARECORD: Nid = Nid(ffi::NID_aRecord); -pub const PILOTATTRIBUTETYPE27: Nid = Nid(ffi::NID_pilotAttributeType27); -pub const MXRECORD: Nid = Nid(ffi::NID_mXRecord); -pub const NSRECORD: Nid = Nid(ffi::NID_nSRecord); -pub const SOARECORD: Nid = Nid(ffi::NID_sOARecord); -pub const CNAMERECORD: Nid = Nid(ffi::NID_cNAMERecord); -pub const ASSOCIATEDDOMAIN: Nid = Nid(ffi::NID_associatedDomain); -pub const ASSOCIATEDNAME: Nid = Nid(ffi::NID_associatedName); -pub const HOMEPOSTALADDRESS: Nid = Nid(ffi::NID_homePostalAddress); -pub const PERSONALTITLE: Nid = Nid(ffi::NID_personalTitle); -pub const MOBILETELEPHONENUMBER: Nid = Nid(ffi::NID_mobileTelephoneNumber); -pub const PAGERTELEPHONENUMBER: Nid = Nid(ffi::NID_pagerTelephoneNumber); -pub const FRIENDLYCOUNTRYNAME: Nid = Nid(ffi::NID_friendlyCountryName); -pub const ORGANIZATIONALSTATUS: Nid = Nid(ffi::NID_organizationalStatus); -pub const JANETMAILBOX: Nid = Nid(ffi::NID_janetMailbox); -pub const MAILPREFERENCEOPTION: Nid = Nid(ffi::NID_mailPreferenceOption); -pub const BUILDINGNAME: Nid = Nid(ffi::NID_buildingName); -pub const DSAQUALITY: Nid = Nid(ffi::NID_dSAQuality); -pub const SINGLELEVELQUALITY: Nid = Nid(ffi::NID_singleLevelQuality); -pub const SUBTREEMINIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMinimumQuality); -pub const SUBTREEMAXIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMaximumQuality); -pub const PERSONALSIGNATURE: Nid = Nid(ffi::NID_personalSignature); -pub const DITREDIRECT: Nid = Nid(ffi::NID_dITRedirect); -pub const AUDIO: Nid = Nid(ffi::NID_audio); -pub const DOCUMENTPUBLISHER: Nid = Nid(ffi::NID_documentPublisher); -pub const ID_SET: Nid = Nid(ffi::NID_id_set); -pub const SET_CTYPE: Nid = Nid(ffi::NID_set_ctype); -pub const SET_MSGEXT: Nid = Nid(ffi::NID_set_msgExt); -pub const SET_ATTR: Nid = Nid(ffi::NID_set_attr); -pub const SET_POLICY: Nid = Nid(ffi::NID_set_policy); -pub const SET_CERTEXT: Nid = Nid(ffi::NID_set_certExt); -pub const SET_BRAND: Nid = Nid(ffi::NID_set_brand); -pub const SETCT_PANDATA: Nid = Nid(ffi::NID_setct_PANData); -pub const SETCT_PANTOKEN: Nid = Nid(ffi::NID_setct_PANToken); -pub const SETCT_PANONLY: Nid = Nid(ffi::NID_setct_PANOnly); -pub const SETCT_OIDATA: Nid = Nid(ffi::NID_setct_OIData); -pub const SETCT_PI: Nid = Nid(ffi::NID_setct_PI); -pub const SETCT_PIDATA: Nid = Nid(ffi::NID_setct_PIData); -pub const SETCT_PIDATAUNSIGNED: Nid = Nid(ffi::NID_setct_PIDataUnsigned); -pub const SETCT_HODINPUT: Nid = Nid(ffi::NID_setct_HODInput); -pub const SETCT_AUTHRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthResBaggage); -pub const SETCT_AUTHREVREQBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevReqBaggage); -pub const SETCT_AUTHREVRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevResBaggage); -pub const SETCT_CAPTOKENSEQ: Nid = Nid(ffi::NID_setct_CapTokenSeq); -pub const SETCT_PINITRESDATA: Nid = Nid(ffi::NID_setct_PInitResData); -pub const SETCT_PI_TBS: Nid = Nid(ffi::NID_setct_PI_TBS); -pub const SETCT_PRESDATA: Nid = Nid(ffi::NID_setct_PResData); -pub const SETCT_AUTHREQTBS: Nid = Nid(ffi::NID_setct_AuthReqTBS); -pub const SETCT_AUTHRESTBS: Nid = Nid(ffi::NID_setct_AuthResTBS); -pub const SETCT_AUTHRESTBSX: Nid = Nid(ffi::NID_setct_AuthResTBSX); -pub const SETCT_AUTHTOKENTBS: Nid = Nid(ffi::NID_setct_AuthTokenTBS); -pub const SETCT_CAPTOKENDATA: Nid = Nid(ffi::NID_setct_CapTokenData); -pub const SETCT_CAPTOKENTBS: Nid = Nid(ffi::NID_setct_CapTokenTBS); -pub const SETCT_ACQCARDCODEMSG: Nid = Nid(ffi::NID_setct_AcqCardCodeMsg); -pub const SETCT_AUTHREVREQTBS: Nid = Nid(ffi::NID_setct_AuthRevReqTBS); -pub const SETCT_AUTHREVRESDATA: Nid = Nid(ffi::NID_setct_AuthRevResData); -pub const SETCT_AUTHREVRESTBS: Nid = Nid(ffi::NID_setct_AuthRevResTBS); -pub const SETCT_CAPREQTBS: Nid = Nid(ffi::NID_setct_CapReqTBS); -pub const SETCT_CAPREQTBSX: Nid = Nid(ffi::NID_setct_CapReqTBSX); -pub const SETCT_CAPRESDATA: Nid = Nid(ffi::NID_setct_CapResData); -pub const SETCT_CAPREVREQTBS: Nid = Nid(ffi::NID_setct_CapRevReqTBS); -pub const SETCT_CAPREVREQTBSX: Nid = Nid(ffi::NID_setct_CapRevReqTBSX); -pub const SETCT_CAPREVRESDATA: Nid = Nid(ffi::NID_setct_CapRevResData); -pub const SETCT_CREDREQTBS: Nid = Nid(ffi::NID_setct_CredReqTBS); -pub const SETCT_CREDREQTBSX: Nid = Nid(ffi::NID_setct_CredReqTBSX); -pub const SETCT_CREDRESDATA: Nid = Nid(ffi::NID_setct_CredResData); -pub const SETCT_CREDREVREQTBS: Nid = Nid(ffi::NID_setct_CredRevReqTBS); -pub const SETCT_CREDREVREQTBSX: Nid = Nid(ffi::NID_setct_CredRevReqTBSX); -pub const SETCT_CREDREVRESDATA: Nid = Nid(ffi::NID_setct_CredRevResData); -pub const SETCT_PCERTREQDATA: Nid = Nid(ffi::NID_setct_PCertReqData); -pub const SETCT_PCERTRESTBS: Nid = Nid(ffi::NID_setct_PCertResTBS); -pub const SETCT_BATCHADMINREQDATA: Nid = Nid(ffi::NID_setct_BatchAdminReqData); -pub const SETCT_BATCHADMINRESDATA: Nid = Nid(ffi::NID_setct_BatchAdminResData); -pub const SETCT_CARDCINITRESTBS: Nid = Nid(ffi::NID_setct_CardCInitResTBS); -pub const SETCT_MEAQCINITRESTBS: Nid = Nid(ffi::NID_setct_MeAqCInitResTBS); -pub const SETCT_REGFORMRESTBS: Nid = Nid(ffi::NID_setct_RegFormResTBS); -pub const SETCT_CERTREQDATA: Nid = Nid(ffi::NID_setct_CertReqData); -pub const SETCT_CERTREQTBS: Nid = Nid(ffi::NID_setct_CertReqTBS); -pub const SETCT_CERTRESDATA: Nid = Nid(ffi::NID_setct_CertResData); -pub const SETCT_CERTINQREQTBS: Nid = Nid(ffi::NID_setct_CertInqReqTBS); -pub const SETCT_ERRORTBS: Nid = Nid(ffi::NID_setct_ErrorTBS); -pub const SETCT_PIDUALSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIDualSignedTBE); -pub const SETCT_PIUNSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIUnsignedTBE); -pub const SETCT_AUTHREQTBE: Nid = Nid(ffi::NID_setct_AuthReqTBE); -pub const SETCT_AUTHRESTBE: Nid = Nid(ffi::NID_setct_AuthResTBE); -pub const SETCT_AUTHRESTBEX: Nid = Nid(ffi::NID_setct_AuthResTBEX); -pub const SETCT_AUTHTOKENTBE: Nid = Nid(ffi::NID_setct_AuthTokenTBE); -pub const SETCT_CAPTOKENTBE: Nid = Nid(ffi::NID_setct_CapTokenTBE); -pub const SETCT_CAPTOKENTBEX: Nid = Nid(ffi::NID_setct_CapTokenTBEX); -pub const SETCT_ACQCARDCODEMSGTBE: Nid = Nid(ffi::NID_setct_AcqCardCodeMsgTBE); -pub const SETCT_AUTHREVREQTBE: Nid = Nid(ffi::NID_setct_AuthRevReqTBE); -pub const SETCT_AUTHREVRESTBE: Nid = Nid(ffi::NID_setct_AuthRevResTBE); -pub const SETCT_AUTHREVRESTBEB: Nid = Nid(ffi::NID_setct_AuthRevResTBEB); -pub const SETCT_CAPREQTBE: Nid = Nid(ffi::NID_setct_CapReqTBE); -pub const SETCT_CAPREQTBEX: Nid = Nid(ffi::NID_setct_CapReqTBEX); -pub const SETCT_CAPRESTBE: Nid = Nid(ffi::NID_setct_CapResTBE); -pub const SETCT_CAPREVREQTBE: Nid = Nid(ffi::NID_setct_CapRevReqTBE); -pub const SETCT_CAPREVREQTBEX: Nid = Nid(ffi::NID_setct_CapRevReqTBEX); -pub const SETCT_CAPREVRESTBE: Nid = Nid(ffi::NID_setct_CapRevResTBE); -pub const SETCT_CREDREQTBE: Nid = Nid(ffi::NID_setct_CredReqTBE); -pub const SETCT_CREDREQTBEX: Nid = Nid(ffi::NID_setct_CredReqTBEX); -pub const SETCT_CREDRESTBE: Nid = Nid(ffi::NID_setct_CredResTBE); -pub const SETCT_CREDREVREQTBE: Nid = Nid(ffi::NID_setct_CredRevReqTBE); -pub const SETCT_CREDREVREQTBEX: Nid = Nid(ffi::NID_setct_CredRevReqTBEX); -pub const SETCT_CREDREVRESTBE: Nid = Nid(ffi::NID_setct_CredRevResTBE); -pub const SETCT_BATCHADMINREQTBE: Nid = Nid(ffi::NID_setct_BatchAdminReqTBE); -pub const SETCT_BATCHADMINRESTBE: Nid = Nid(ffi::NID_setct_BatchAdminResTBE); -pub const SETCT_REGFORMREQTBE: Nid = Nid(ffi::NID_setct_RegFormReqTBE); -pub const SETCT_CERTREQTBE: Nid = Nid(ffi::NID_setct_CertReqTBE); -pub const SETCT_CERTREQTBEX: Nid = Nid(ffi::NID_setct_CertReqTBEX); -pub const SETCT_CERTRESTBE: Nid = Nid(ffi::NID_setct_CertResTBE); -pub const SETCT_CRLNOTIFICATIONTBS: Nid = Nid(ffi::NID_setct_CRLNotificationTBS); -pub const SETCT_CRLNOTIFICATIONRESTBS: Nid = Nid(ffi::NID_setct_CRLNotificationResTBS); -pub const SETCT_BCIDISTRIBUTIONTBS: Nid = Nid(ffi::NID_setct_BCIDistributionTBS); -pub const SETEXT_GENCRYPT: Nid = Nid(ffi::NID_setext_genCrypt); -pub const SETEXT_MIAUTH: Nid = Nid(ffi::NID_setext_miAuth); -pub const SETEXT_PINSECURE: Nid = Nid(ffi::NID_setext_pinSecure); -pub const SETEXT_PINANY: Nid = Nid(ffi::NID_setext_pinAny); -pub const SETEXT_TRACK2: Nid = Nid(ffi::NID_setext_track2); -pub const SETEXT_CV: Nid = Nid(ffi::NID_setext_cv); -pub const SET_POLICY_ROOT: Nid = Nid(ffi::NID_set_policy_root); -pub const SETCEXT_HASHEDROOT: Nid = Nid(ffi::NID_setCext_hashedRoot); -pub const SETCEXT_CERTTYPE: Nid = Nid(ffi::NID_setCext_certType); -pub const SETCEXT_MERCHDATA: Nid = Nid(ffi::NID_setCext_merchData); -pub const SETCEXT_CCERTREQUIRED: Nid = Nid(ffi::NID_setCext_cCertRequired); -pub const SETCEXT_TUNNELING: Nid = Nid(ffi::NID_setCext_tunneling); -pub const SETCEXT_SETEXT: Nid = Nid(ffi::NID_setCext_setExt); -pub const SETCEXT_SETQUALF: Nid = Nid(ffi::NID_setCext_setQualf); -pub const SETCEXT_PGWYCAPABILITIES: Nid = Nid(ffi::NID_setCext_PGWYcapabilities); -pub const SETCEXT_TOKENIDENTIFIER: Nid = Nid(ffi::NID_setCext_TokenIdentifier); -pub const SETCEXT_TRACK2DATA: Nid = Nid(ffi::NID_setCext_Track2Data); -pub const SETCEXT_TOKENTYPE: Nid = Nid(ffi::NID_setCext_TokenType); -pub const SETCEXT_ISSUERCAPABILITIES: Nid = Nid(ffi::NID_setCext_IssuerCapabilities); -pub const SETATTR_CERT: Nid = Nid(ffi::NID_setAttr_Cert); -pub const SETATTR_PGWYCAP: Nid = Nid(ffi::NID_setAttr_PGWYcap); -pub const SETATTR_TOKENTYPE: Nid = Nid(ffi::NID_setAttr_TokenType); -pub const SETATTR_ISSCAP: Nid = Nid(ffi::NID_setAttr_IssCap); -pub const SET_ROOTKEYTHUMB: Nid = Nid(ffi::NID_set_rootKeyThumb); -pub const SET_ADDPOLICY: Nid = Nid(ffi::NID_set_addPolicy); -pub const SETATTR_TOKEN_EMV: Nid = Nid(ffi::NID_setAttr_Token_EMV); -pub const SETATTR_TOKEN_B0PRIME: Nid = Nid(ffi::NID_setAttr_Token_B0Prime); -pub const SETATTR_ISSCAP_CVM: Nid = Nid(ffi::NID_setAttr_IssCap_CVM); -pub const SETATTR_ISSCAP_T2: Nid = Nid(ffi::NID_setAttr_IssCap_T2); -pub const SETATTR_ISSCAP_SIG: Nid = Nid(ffi::NID_setAttr_IssCap_Sig); -pub const SETATTR_GENCRYPTGRM: Nid = Nid(ffi::NID_setAttr_GenCryptgrm); -pub const SETATTR_T2ENC: Nid = Nid(ffi::NID_setAttr_T2Enc); -pub const SETATTR_T2CLEARTXT: Nid = Nid(ffi::NID_setAttr_T2cleartxt); -pub const SETATTR_TOKICCSIG: Nid = Nid(ffi::NID_setAttr_TokICCsig); -pub const SETATTR_SECDEVSIG: Nid = Nid(ffi::NID_setAttr_SecDevSig); -pub const SET_BRAND_IATA_ATA: Nid = Nid(ffi::NID_set_brand_IATA_ATA); -pub const SET_BRAND_DINERS: Nid = Nid(ffi::NID_set_brand_Diners); -pub const SET_BRAND_AMERICANEXPRESS: Nid = Nid(ffi::NID_set_brand_AmericanExpress); -pub const SET_BRAND_JCB: Nid = Nid(ffi::NID_set_brand_JCB); -pub const SET_BRAND_VISA: Nid = Nid(ffi::NID_set_brand_Visa); -pub const SET_BRAND_MASTERCARD: Nid = Nid(ffi::NID_set_brand_MasterCard); -pub const SET_BRAND_NOVUS: Nid = Nid(ffi::NID_set_brand_Novus); -pub const DES_CDMF: Nid = Nid(ffi::NID_des_cdmf); -pub const RSAOAEPENCRYPTIONSET: Nid = Nid(ffi::NID_rsaOAEPEncryptionSET); -pub const IPSEC3: Nid = Nid(ffi::NID_ipsec3); -pub const IPSEC4: Nid = Nid(ffi::NID_ipsec4); -pub const WHIRLPOOL: Nid = Nid(ffi::NID_whirlpool); -pub const CRYPTOPRO: Nid = Nid(ffi::NID_cryptopro); -pub const CRYPTOCOM: Nid = Nid(ffi::NID_cryptocom); -pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001: Nid = - Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001); -pub const ID_GOSTR3411_94_WITH_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94); -pub const ID_GOSTR3411_94: Nid = Nid(ffi::NID_id_GostR3411_94); -pub const ID_HMACGOSTR3411_94: Nid = Nid(ffi::NID_id_HMACGostR3411_94); -pub const ID_GOSTR3410_2001: Nid = Nid(ffi::NID_id_GostR3410_2001); -pub const ID_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3410_94); -pub const ID_GOST28147_89: Nid = Nid(ffi::NID_id_Gost28147_89); -pub const GOST89_CNT: Nid = Nid(ffi::NID_gost89_cnt); -pub const ID_GOST28147_89_MAC: Nid = Nid(ffi::NID_id_Gost28147_89_MAC); -pub const ID_GOSTR3411_94_PRF: Nid = Nid(ffi::NID_id_GostR3411_94_prf); -pub const ID_GOSTR3410_2001DH: Nid = Nid(ffi::NID_id_GostR3410_2001DH); -pub const ID_GOSTR3410_94DH: Nid = Nid(ffi::NID_id_GostR3410_94DH); -pub const ID_GOST28147_89_CRYPTOPRO_KEYMESHING: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_KeyMeshing); -pub const ID_GOST28147_89_NONE_KEYMESHING: Nid = Nid(ffi::NID_id_Gost28147_89_None_KeyMeshing); -pub const ID_GOSTR3411_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_TestParamSet); -pub const ID_GOSTR3411_94_CRYPTOPROPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_CryptoProParamSet); -pub const ID_GOST28147_89_TESTPARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_TestParamSet); -pub const ID_GOST28147_89_CRYPTOPRO_A_PARAMSET: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_A_ParamSet); -pub const ID_GOST28147_89_CRYPTOPRO_B_PARAMSET: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_B_ParamSet); -pub const ID_GOST28147_89_CRYPTOPRO_C_PARAMSET: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_C_ParamSet); -pub const ID_GOST28147_89_CRYPTOPRO_D_PARAMSET: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_D_ParamSet); -pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_1_PARAMSET: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet); -pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_0_PARAMSET: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet); -pub const ID_GOST28147_89_CRYPTOPRO_RIC_1_PARAMSET: Nid = - Nid(ffi::NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet); -pub const ID_GOSTR3410_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_TestParamSet); -pub const ID_GOSTR3410_94_CRYPTOPRO_A_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_94_CryptoPro_A_ParamSet); -pub const ID_GOSTR3410_94_CRYPTOPRO_B_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_94_CryptoPro_B_ParamSet); -pub const ID_GOSTR3410_94_CRYPTOPRO_C_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_94_CryptoPro_C_ParamSet); -pub const ID_GOSTR3410_94_CRYPTOPRO_D_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_94_CryptoPro_D_ParamSet); -pub const ID_GOSTR3410_94_CRYPTOPRO_XCHA_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchA_ParamSet); -pub const ID_GOSTR3410_94_CRYPTOPRO_XCHB_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchB_ParamSet); -pub const ID_GOSTR3410_94_CRYPTOPRO_XCHC_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchC_ParamSet); -pub const ID_GOSTR3410_2001_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_TestParamSet); -pub const ID_GOSTR3410_2001_CRYPTOPRO_A_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_2001_CryptoPro_A_ParamSet); -pub const ID_GOSTR3410_2001_CRYPTOPRO_B_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_2001_CryptoPro_B_ParamSet); -pub const ID_GOSTR3410_2001_CRYPTOPRO_C_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_2001_CryptoPro_C_ParamSet); -pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHA_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet); -pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHB_PARAMSET: Nid = - Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet); -pub const ID_GOSTR3410_94_A: Nid = Nid(ffi::NID_id_GostR3410_94_a); -pub const ID_GOSTR3410_94_ABIS: Nid = Nid(ffi::NID_id_GostR3410_94_aBis); -pub const ID_GOSTR3410_94_B: Nid = Nid(ffi::NID_id_GostR3410_94_b); -pub const ID_GOSTR3410_94_BBIS: Nid = Nid(ffi::NID_id_GostR3410_94_bBis); -pub const ID_GOST28147_89_CC: Nid = Nid(ffi::NID_id_Gost28147_89_cc); -pub const ID_GOSTR3410_94_CC: Nid = Nid(ffi::NID_id_GostR3410_94_cc); -pub const ID_GOSTR3410_2001_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_cc); -pub const ID_GOSTR3411_94_WITH_GOSTR3410_94_CC: Nid = - Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94_cc); -pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001_CC: Nid = - Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001_cc); -pub const ID_GOSTR3410_2001_PARAMSET_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_ParamSet_cc); -pub const CAMELLIA_128_CBC: Nid = Nid(ffi::NID_camellia_128_cbc); -pub const CAMELLIA_192_CBC: Nid = Nid(ffi::NID_camellia_192_cbc); -pub const CAMELLIA_256_CBC: Nid = Nid(ffi::NID_camellia_256_cbc); -pub const ID_CAMELLIA128_WRAP: Nid = Nid(ffi::NID_id_camellia128_wrap); -pub const ID_CAMELLIA192_WRAP: Nid = Nid(ffi::NID_id_camellia192_wrap); -pub const ID_CAMELLIA256_WRAP: Nid = Nid(ffi::NID_id_camellia256_wrap); -pub const CAMELLIA_128_ECB: Nid = Nid(ffi::NID_camellia_128_ecb); -pub const CAMELLIA_128_OFB128: Nid = Nid(ffi::NID_camellia_128_ofb128); -pub const CAMELLIA_128_CFB128: Nid = Nid(ffi::NID_camellia_128_cfb128); -pub const CAMELLIA_192_ECB: Nid = Nid(ffi::NID_camellia_192_ecb); -pub const CAMELLIA_192_OFB128: Nid = Nid(ffi::NID_camellia_192_ofb128); -pub const CAMELLIA_192_CFB128: Nid = Nid(ffi::NID_camellia_192_cfb128); -pub const CAMELLIA_256_ECB: Nid = Nid(ffi::NID_camellia_256_ecb); -pub const CAMELLIA_256_OFB128: Nid = Nid(ffi::NID_camellia_256_ofb128); -pub const CAMELLIA_256_CFB128: Nid = Nid(ffi::NID_camellia_256_cfb128); -pub const CAMELLIA_128_CFB1: Nid = Nid(ffi::NID_camellia_128_cfb1); -pub const CAMELLIA_192_CFB1: Nid = Nid(ffi::NID_camellia_192_cfb1); -pub const CAMELLIA_256_CFB1: Nid = Nid(ffi::NID_camellia_256_cfb1); -pub const CAMELLIA_128_CFB8: Nid = Nid(ffi::NID_camellia_128_cfb8); -pub const CAMELLIA_192_CFB8: Nid = Nid(ffi::NID_camellia_192_cfb8); -pub const CAMELLIA_256_CFB8: Nid = Nid(ffi::NID_camellia_256_cfb8); -pub const KISA: Nid = Nid(ffi::NID_kisa); -pub const SEED_ECB: Nid = Nid(ffi::NID_seed_ecb); -pub const SEED_CBC: Nid = Nid(ffi::NID_seed_cbc); -pub const SEED_CFB128: Nid = Nid(ffi::NID_seed_cfb128); -pub const SEED_OFB128: Nid = Nid(ffi::NID_seed_ofb128); -pub const HMAC: Nid = Nid(ffi::NID_hmac); -pub const CMAC: Nid = Nid(ffi::NID_cmac); -pub const RC4_HMAC_MD5: Nid = Nid(ffi::NID_rc4_hmac_md5); -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(test)] +mod test { + use super::Nid; + + #[test] + fn signature_digest() { + let algs = Nid::SHA256WITHRSAENCRYPTION.signature_algorithms().unwrap(); + assert_eq!(algs.digest, Nid::SHA256); + assert_eq!(algs.pkey, Nid::RSAENCRYPTION); + } + + #[test] + fn test_long_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.long_name().unwrap(), "commonName"); + assert_eq!( + organizational_unit_name.long_name().unwrap(), + "organizationalUnitName" + ); + assert_eq!( + aes256_cbc_hmac_sha1.long_name().unwrap(), + "aes-256-cbc-hmac-sha1" + ); + assert_eq!( + id_cmc_lrapopwitness.long_name().unwrap(), + "id-cmc-lraPOPWitness" + ); + assert_eq!( + ms_ctl_sign.long_name().unwrap(), + "Microsoft Trust List Signing" + ); + assert!( + undefined_nid.long_name().is_err(), + "undefined_nid should not return a valid value" + ); + } + + #[test] + fn test_short_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.short_name().unwrap(), "CN"); + assert_eq!(organizational_unit_name.short_name().unwrap(), "OU"); + assert_eq!( + aes256_cbc_hmac_sha1.short_name().unwrap(), + "AES-256-CBC-HMAC-SHA1" + ); + assert_eq!( + id_cmc_lrapopwitness.short_name().unwrap(), + "id-cmc-lraPOPWitness" + ); + assert_eq!(ms_ctl_sign.short_name().unwrap(), "msCTLSign"); + assert!( + undefined_nid.short_name().is_err(), + "undefined_nid should not return a valid value" + ); + } + + #[test] + fn test_create() { + let nid = Nid::create("1.2.3.4", "foo", "foobar").unwrap(); + assert_eq!(nid.short_name().unwrap(), "foo"); + assert_eq!(nid.long_name().unwrap(), "foobar"); + + let invalid_oid = Nid::create("invalid_oid", "invalid", "invalid"); + assert!( + invalid_oid.is_err(), + "invalid_oid should not return a valid value" + ); + } +} diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs index 65436a4..7506d34 100644 --- a/openssl/src/ocsp.rs +++ b/openssl/src/ocsp.rs @@ -1,77 +1,57 @@ -use ffi; +use bitflags::bitflags; use foreign_types::ForeignTypeRef; use libc::{c_int, c_long, c_ulong}; -use std::ptr; use std::mem; +use std::ptr; -use {cvt, cvt_p}; -use asn1::Asn1GeneralizedTimeRef; -use error::ErrorStack; -use hash::MessageDigest; -use stack::StackRef; -use x509::store::X509StoreRef; -use x509::{X509, X509Ref}; +use crate::asn1::Asn1GeneralizedTimeRef; +use crate::error::ErrorStack; +use crate::hash::MessageDigest; +use crate::stack::StackRef; +use crate::util::ForeignTypeRefExt; +use crate::x509::store::X509StoreRef; +use crate::x509::{X509Ref, X509}; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; bitflags! { - pub struct Flag: c_ulong { - const FLAG_NO_CERTS = ffi::OCSP_NOCERTS; - const FLAG_NO_INTERN = ffi::OCSP_NOINTERN; - const FLAG_NO_CHAIN = ffi::OCSP_NOCHAIN; - const FLAG_NO_VERIFY = ffi::OCSP_NOVERIFY; - const FLAG_NO_EXPLICIT = ffi::OCSP_NOEXPLICIT; - const FLAG_NO_CA_SIGN = ffi::OCSP_NOCASIGN; - const FLAG_NO_DELEGATED = ffi::OCSP_NODELEGATED; - const FLAG_NO_CHECKS = ffi::OCSP_NOCHECKS; - const FLAG_TRUST_OTHER = ffi::OCSP_TRUSTOTHER; - const FLAG_RESPID_KEY = ffi::OCSP_RESPID_KEY; - const FLAG_NO_TIME = ffi::OCSP_NOTIME; + pub struct OcspFlag: c_ulong { + const NO_CERTS = ffi::OCSP_NOCERTS; + const NO_INTERN = ffi::OCSP_NOINTERN; + const NO_CHAIN = ffi::OCSP_NOCHAIN; + const NO_VERIFY = ffi::OCSP_NOVERIFY; + const NO_EXPLICIT = ffi::OCSP_NOEXPLICIT; + const NO_CA_SIGN = ffi::OCSP_NOCASIGN; + const NO_DELEGATED = ffi::OCSP_NODELEGATED; + const NO_CHECKS = ffi::OCSP_NOCHECKS; + const TRUST_OTHER = ffi::OCSP_TRUSTOTHER; + const RESPID_KEY = ffi::OCSP_RESPID_KEY; + const NO_TIME = ffi::OCSP_NOTIME; } } -pub const RESPONSE_STATUS_SUCCESSFUL: OcspResponseStatus = - OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SUCCESSFUL); -pub const RESPONSE_STATUS_MALFORMED_REQUEST: OcspResponseStatus = - OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_MALFORMEDREQUEST); -pub const RESPONSE_STATUS_INTERNAL_ERROR: OcspResponseStatus = - OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_INTERNALERROR); -pub const RESPONSE_STATUS_TRY_LATER: OcspResponseStatus = - OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_TRYLATER); -pub const RESPONSE_STATUS_SIG_REQUIRED: OcspResponseStatus = - OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SIGREQUIRED); -pub const RESPONSE_STATUS_UNAUTHORIZED: OcspResponseStatus = - OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_UNAUTHORIZED); - -pub const CERT_STATUS_GOOD: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_GOOD); -pub const CERT_STATUS_REVOKED: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_REVOKED); -pub const CERT_STATUS_UNKNOWN: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_UNKNOWN); - -pub const REVOKED_STATUS_NO_STATUS: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_NOSTATUS); -pub const REVOKED_STATUS_UNSPECIFIED: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_UNSPECIFIED); -pub const REVOKED_STATUS_KEY_COMPROMISE: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_KEYCOMPROMISE); -pub const REVOKED_STATUS_CA_COMPROMISE: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CACOMPROMISE); -pub const REVOKED_STATUS_AFFILIATION_CHANGED: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_AFFILIATIONCHANGED); -pub const REVOKED_STATUS_SUPERSEDED: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_SUPERSEDED); -pub const REVOKED_STATUS_CESSATION_OF_OPERATION: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CESSATIONOFOPERATION); -pub const REVOKED_STATUS_CERTIFICATE_HOLD: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CERTIFICATEHOLD); -pub const REVOKED_STATUS_REMOVE_FROM_CRL: OcspRevokedStatus = - OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_REMOVEFROMCRL); - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OcspResponseStatus(c_int); impl OcspResponseStatus { + pub const SUCCESSFUL: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SUCCESSFUL); + pub const MALFORMED_REQUEST: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_MALFORMEDREQUEST); + pub const INTERNAL_ERROR: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_INTERNALERROR); + pub const TRY_LATER: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_TRYLATER); + pub const SIG_REQUIRED: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SIGREQUIRED); + pub const UNAUTHORIZED: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_UNAUTHORIZED); + pub fn from_raw(raw: c_int) -> OcspResponseStatus { OcspResponseStatus(raw) } + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } @@ -81,10 +61,15 @@ impl OcspResponseStatus { pub struct OcspCertStatus(c_int); impl OcspCertStatus { + pub const GOOD: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_GOOD); + pub const REVOKED: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_REVOKED); + pub const UNKNOWN: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_UNKNOWN); + pub fn from_raw(raw: c_int) -> OcspCertStatus { OcspCertStatus(raw) } + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } @@ -94,16 +79,35 @@ impl OcspCertStatus { pub struct OcspRevokedStatus(c_int); impl OcspRevokedStatus { + pub const NO_STATUS: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_NOSTATUS); + pub const UNSPECIFIED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_UNSPECIFIED); + pub const KEY_COMPROMISE: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_KEYCOMPROMISE); + pub const CA_COMPROMISE: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CACOMPROMISE); + pub const AFFILIATION_CHANGED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_AFFILIATIONCHANGED); + pub const STATUS_SUPERSEDED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_SUPERSEDED); + pub const STATUS_CESSATION_OF_OPERATION: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CESSATIONOFOPERATION); + pub const STATUS_CERTIFICATE_HOLD: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CERTIFICATEHOLD); + pub const REMOVE_FROM_CRL: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_REMOVEFROMCRL); + pub fn from_raw(raw: c_int) -> OcspRevokedStatus { OcspRevokedStatus(raw) } + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } -pub struct Status<'a> { +pub struct OcspStatus<'a> { /// The overall status of the response. pub status: OcspCertStatus, /// If `status` is `CERT_STATUS_REVOKED`, the reason for the revocation. @@ -116,7 +120,7 @@ pub struct Status<'a> { pub next_update: &'a Asn1GeneralizedTimeRef, } -impl<'a> Status<'a> { +impl<'a> OcspStatus<'a> { /// Checks validity of the `this_update` and `next_update` fields. /// /// The `nsec` parameter specifies an amount of slack time that will be used when comparing @@ -124,6 +128,7 @@ impl<'a> Status<'a> { /// /// The `maxsec` parameter limits the maximum age of the `this_update` parameter to prohibit /// very old responses. + #[corresponds(OCSP_check_validity)] pub fn check_validity(&self, nsec: u32, maxsec: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::OCSP_check_validity( @@ -131,7 +136,8 @@ impl<'a> Status<'a> { self.next_update.as_ptr(), nsec as c_long, maxsec.map(|n| n as c_long).unwrap_or(-1), - )).map(|_| ()) + )) + .map(|_| ()) } } } @@ -149,11 +155,12 @@ impl OcspBasicResponseRef { /// /// The `certs` parameter contains a set of certificates that will be searched when locating the /// OCSP response signing certificate. Some responders do not include this in the response. + #[corresponds(OCSP_basic_verify)] pub fn verify( &self, certs: &StackRef, store: &X509StoreRef, - flags: Flag, + flags: OcspFlag, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::OCSP_basic_verify( @@ -161,12 +168,14 @@ impl OcspBasicResponseRef { certs.as_ptr(), store.as_ptr(), flags.bits(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Looks up the status for the specified certificate ID. - pub fn find_status<'a>(&'a self, id: &OcspCertIdRef) -> Option> { + #[corresponds(OCSP_resp_find_status)] + pub fn find_status<'a>(&'a self, id: &OcspCertIdRef) -> Option> { unsafe { let mut status = ffi::V_OCSP_CERTSTATUS_UNKNOWN; let mut reason = ffi::OCSP_REVOKED_STATUS_NOSTATUS; @@ -184,15 +193,12 @@ impl OcspBasicResponseRef { &mut next_update, ); if r == 1 { - let revocation_time = if revocation_time.is_null() { - None - } else { - Some(Asn1GeneralizedTimeRef::from_ptr(revocation_time)) - }; - Some(Status { + let revocation_time = Asn1GeneralizedTimeRef::from_const_ptr_opt(revocation_time); + + Some(OcspStatus { status: OcspCertStatus(status), reason: OcspRevokedStatus(status), - revocation_time: revocation_time, + revocation_time, this_update: Asn1GeneralizedTimeRef::from_ptr(this_update), next_update: Asn1GeneralizedTimeRef::from_ptr(next_update), }) @@ -213,6 +219,7 @@ foreign_type_and_impl_send_sync! { impl OcspCertId { /// Constructs a certificate ID for certificate `subject`. + #[corresponds(OCSP_cert_to_id)] pub fn from_cert( digest: MessageDigest, subject: &X509Ref, @@ -223,7 +230,8 @@ impl OcspCertId { digest.as_ptr(), subject.as_ptr(), issuer.as_ptr(), - )).map(OcspCertId) + )) + .map(OcspCertId) } } } @@ -240,6 +248,7 @@ impl OcspResponse { /// Creates an OCSP response from the status and optional body. /// /// A body should only be provided if `status` is `RESPONSE_STATUS_SUCCESSFUL`. + #[corresponds(OCSP_response_create)] pub fn create( status: OcspResponseStatus, body: Option<&OcspBasicResponseRef>, @@ -250,17 +259,30 @@ impl OcspResponse { cvt_p(ffi::OCSP_response_create( status.as_raw(), body.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut()), - )).map(OcspResponse) + )) + .map(OcspResponse) } } - from_der!(OcspResponse, ffi::d2i_OCSP_RESPONSE); + from_der! { + /// Deserializes a DER-encoded OCSP response. + #[corresponds(d2i_OCSP_RESPONSE)] + from_der, + OcspResponse, + ffi::d2i_OCSP_RESPONSE + } } impl OcspResponseRef { - to_der!(ffi::i2d_OCSP_RESPONSE); + to_der! { + /// Serializes the response to its standard DER encoding. + #[corresponds(i2d_OCSP_RESPONSE)] + to_der, + ffi::i2d_OCSP_RESPONSE + } /// Returns the status of the response. + #[corresponds(OCSP_response_status)] pub fn status(&self) -> OcspResponseStatus { unsafe { OcspResponseStatus(ffi::OCSP_response_status(self.as_ptr())) } } @@ -268,6 +290,7 @@ impl OcspResponseRef { /// Returns the basic response. /// /// This will only succeed if `status()` returns `RESPONSE_STATUS_SUCCESSFUL`. + #[corresponds(OCSP_response_get1_basic)] pub fn basic(&self) -> Result { unsafe { cvt_p(ffi::OCSP_response_get1_basic(self.as_ptr())).map(OcspBasicResponse) } } @@ -282,6 +305,7 @@ foreign_type_and_impl_send_sync! { } impl OcspRequest { + #[corresponds(OCSP_REQUEST_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -290,12 +314,24 @@ impl OcspRequest { } } - from_der!(OcspRequest, ffi::d2i_OCSP_REQUEST); + from_der! { + /// Deserializes a DER-encoded OCSP request. + #[corresponds(d2i_OCSP_REQUEST)] + from_der, + OcspRequest, + ffi::d2i_OCSP_REQUEST + } } impl OcspRequestRef { - to_der!(ffi::i2d_OCSP_REQUEST); + to_der! { + /// Serializes the request to its standard DER encoding. + #[corresponds(i2d_OCSP_REQUEST)] + to_der, + ffi::i2d_OCSP_REQUEST + } + #[corresponds(OCSP_request_add0_id)] pub fn add_id(&mut self, id: OcspCertId) -> Result<&mut OcspOneReqRef, ErrorStack> { unsafe { let ptr = cvt_p(ffi::OCSP_request_add0_id(self.as_ptr(), id.as_ptr()))?; diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index 8611128..d74705e 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -1,17 +1,20 @@ //! PKCS #12 archives. -use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; -use std::ptr; use std::ffi::CString; +use std::ptr; -use {cvt, cvt_p}; -use pkey::{PKey, PKeyRef}; -use error::ErrorStack; -use x509::X509; -use stack::Stack; -use nid; +use crate::error::ErrorStack; +#[cfg(not(boringssl))] +use crate::hash::MessageDigest; +use crate::nid::Nid; +use crate::pkey::{HasPrivate, PKey, PKeyRef, Private}; +use crate::stack::Stack; +use crate::util::ForeignTypeExt; +use crate::x509::{X509Ref, X509}; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; foreign_type_and_impl_send_sync! { type CType = ffi::PKCS12; @@ -22,92 +25,155 @@ foreign_type_and_impl_send_sync! { } impl Pkcs12Ref { - to_der!(ffi::i2d_PKCS12); + to_der! { + /// Serializes the `Pkcs12` to its standard DER encoding. + #[corresponds(i2d_PKCS12)] + to_der, + ffi::i2d_PKCS12 + } - /// Extracts the contents of the `Pkcs12`. - // FIXME should take an &[u8] + /// Deprecated. + #[deprecated(note = "Use parse2 instead", since = "0.10.46")] + #[allow(deprecated)] pub fn parse(&self, pass: &str) -> Result { + let parsed = self.parse2(pass)?; + + Ok(ParsedPkcs12 { + pkey: parsed.pkey.unwrap(), + cert: parsed.cert.unwrap(), + chain: parsed.ca, + }) + } + + /// Extracts the contents of the `Pkcs12`. + #[corresponds(PKCS12_parse)] + pub fn parse2(&self, pass: &str) -> Result { unsafe { - let pass = CString::new(pass).unwrap(); + let pass = CString::new(pass.as_bytes()).unwrap(); let mut pkey = ptr::null_mut(); let mut cert = ptr::null_mut(); - let mut chain = ptr::null_mut(); + let mut ca = ptr::null_mut(); cvt(ffi::PKCS12_parse( self.as_ptr(), pass.as_ptr(), &mut pkey, &mut cert, - &mut chain, + &mut ca, ))?; - let pkey = PKey::from_ptr(pkey); - let cert = X509::from_ptr(cert); - - let chain = if chain.is_null() { - Stack::new()? - } else { - Stack::from_ptr(chain) - }; + let pkey = PKey::from_ptr_opt(pkey); + let cert = X509::from_ptr_opt(cert); + let ca = Stack::from_ptr_opt(ca); - Ok(ParsedPkcs12 { - pkey: pkey, - cert: cert, - chain: chain, - }) + Ok(ParsedPkcs12_2 { pkey, cert, ca }) } } } impl Pkcs12 { - from_der!(Pkcs12, ffi::d2i_PKCS12); + from_der! { + /// Deserializes a DER-encoded PKCS#12 archive. + #[corresponds(d2i_PKCS12)] + from_der, + Pkcs12, + ffi::d2i_PKCS12 + } /// Creates a new builder for a protected pkcs12 certificate. /// /// This uses the defaults from the OpenSSL library: /// - /// * `nid_key` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` - /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC` + /// * `nid_key` - `AES_256_CBC` (3.0.0+) or `PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` + /// * `nid_cert` - `AES_256_CBC` (3.0.0+) or `PBE_WITHSHA1AND40BITRC2_CBC` /// * `iter` - `2048` /// * `mac_iter` - `2048` + /// * `mac_md` - `SHA-256` (3.0.0+) or `SHA-1` (`SHA-1` only for BoringSSL) pub fn builder() -> Pkcs12Builder { ffi::init(); Pkcs12Builder { - nid_key: nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, - nid_cert: nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, + name: None, + pkey: None, + cert: None, + ca: None, + nid_key: Nid::UNDEF, + nid_cert: Nid::UNDEF, iter: ffi::PKCS12_DEFAULT_ITER, mac_iter: ffi::PKCS12_DEFAULT_ITER, - ca: None, + #[cfg(not(boringssl))] + mac_md: None, } } } +#[deprecated(note = "Use ParsedPkcs12_2 instead", since = "0.10.46")] pub struct ParsedPkcs12 { - pub pkey: PKey, + pub pkey: PKey, pub cert: X509, - // FIXME Make this Option in the next breaking release - pub chain: Stack, + pub chain: Option>, +} + +pub struct ParsedPkcs12_2 { + pub pkey: Option>, + pub cert: Option, + pub ca: Option>, } pub struct Pkcs12Builder { - nid_key: nid::Nid, - nid_cert: nid::Nid, + // FIXME borrow + name: Option, + pkey: Option>, + cert: Option, + ca: Option>, + nid_key: Nid, + nid_cert: Nid, iter: c_int, mac_iter: c_int, - ca: Option>, + // FIXME remove + #[cfg(not(boringssl))] + mac_md: Option, } impl Pkcs12Builder { + /// The `friendlyName` used for the certificate and private key. + pub fn name(&mut self, name: &str) -> &mut Self { + self.name = Some(CString::new(name).unwrap()); + self + } + + /// The private key. + pub fn pkey(&mut self, pkey: &PKeyRef) -> &mut Self + where + T: HasPrivate, + { + let new_pkey = unsafe { PKeyRef::from_ptr(pkey.as_ptr()) }; + self.pkey = Some(new_pkey.to_owned()); + self + } + + /// The certificate. + pub fn cert(&mut self, cert: &X509Ref) -> &mut Self { + self.cert = Some(cert.to_owned()); + self + } + + /// An additional set of certificates to include in the archive beyond the one provided to + /// `build`. + pub fn ca(&mut self, ca: Stack) -> &mut Self { + self.ca = Some(ca); + self + } + /// The encryption algorithm that should be used for the key - pub fn key_algorithm(&mut self, nid: nid::Nid) -> &mut Self { + pub fn key_algorithm(&mut self, nid: Nid) -> &mut Self { self.nid_key = nid; self } /// The encryption algorithm that should be used for the cert - pub fn cert_algorithm(&mut self, nid: nid::Nid) -> &mut Self { + pub fn cert_algorithm(&mut self, nid: Nid) -> &mut Self { self.nid_cert = nid; self } @@ -127,107 +193,140 @@ impl Pkcs12Builder { self } - /// An additional set of certificates to include in the archive beyond the one provided to - /// `build`. - pub fn ca(&mut self, ca: Stack) -> &mut Self { - self.ca = Some(ca); + /// MAC message digest type + #[cfg(not(boringssl))] + pub fn mac_md(&mut self, md: MessageDigest) -> &mut Self { + self.mac_md = Some(md); self } - /// Builds the PKCS #12 object - /// - /// # Arguments - /// - /// * `password` - the password used to encrypt the key and certificate - /// * `friendly_name` - user defined name for the certificate - /// * `pkey` - key to store - /// * `cert` - certificate to store - pub fn build( - self, + /// Deprecated. + #[deprecated( + note = "Use Self::{name, pkey, cert, build2} instead.", + since = "0.10.46" + )] + pub fn build( + mut self, password: &str, friendly_name: &str, - pkey: &PKeyRef, - cert: &X509, - ) -> Result { + pkey: &PKeyRef, + cert: &X509Ref, + ) -> Result + where + T: HasPrivate, + { + self.name(friendly_name) + .pkey(pkey) + .cert(cert) + .build2(password) + } + + /// Builds the PKCS#12 object. + #[corresponds(PKCS12_create)] + pub fn build2(&self, password: &str) -> Result { unsafe { let pass = CString::new(password).unwrap(); - let friendly_name = CString::new(friendly_name).unwrap(); - let pkey = pkey.as_ptr(); - let cert = cert.as_ptr(); - let ca = self.ca.as_ref().map(|ca| ca.as_ptr()).unwrap_or( - ptr::null_mut(), - ); + let pass = pass.as_ptr(); + let friendly_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr()); + let pkey = self.pkey.as_ref().map_or(ptr::null(), |p| p.as_ptr()); + let cert = self.cert.as_ref().map_or(ptr::null(), |p| p.as_ptr()); + let ca = self + .ca + .as_ref() + .map(|ca| ca.as_ptr()) + .unwrap_or(ptr::null_mut()); let nid_key = self.nid_key.as_raw(); let nid_cert = self.nid_cert.as_raw(); // According to the OpenSSL docs, keytype is a non-standard extension for MSIE, // It's values are KEY_SIG or KEY_EX, see the OpenSSL docs for more information: - // https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html + // https://www.openssl.org/docs/manmaster/crypto/PKCS12_create.html let keytype = 0; - cvt_p(ffi::PKCS12_create( - pass.as_ptr() as *const _ as *mut _, - friendly_name.as_ptr() as *const _ as *mut _, - pkey, - cert, + let pkcs12 = cvt_p(ffi::PKCS12_create( + pass as *mut _, + friendly_name as *mut _, + pkey as *mut _, + cert as *mut _, ca, nid_key, nid_cert, self.iter, self.mac_iter, keytype, - )).map(Pkcs12) + )) + .map(Pkcs12)?; + + #[cfg(not(boringssl))] + // BoringSSL does not support overriding the MAC and will always + // use SHA-1 + { + let md_type = self + .mac_md + .map(|md_type| md_type.as_ptr()) + .unwrap_or(ptr::null()); + + cvt(ffi::PKCS12_set_mac( + pkcs12.as_ptr(), + pass, + -1, + ptr::null_mut(), + 0, + self.mac_iter, + md_type, + ))?; + } + + Ok(pkcs12) } } } #[cfg(test)] mod test { - use hash::MessageDigest; - use hex::ToHex; - - use asn1::Asn1Time; - use rsa::Rsa; - use pkey::PKey; - use nid; - use x509::{X509, X509Name}; - use x509::extension::KeyUsage; + use crate::asn1::Asn1Time; + use crate::hash::MessageDigest; + use crate::nid::Nid; + use crate::pkey::PKey; + use crate::rsa::Rsa; + use crate::x509::extension::KeyUsage; + use crate::x509::{X509Name, X509}; use super::*; #[test] fn parse() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + let der = include_bytes!("../test/identity.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); - let parsed = pkcs12.parse("mypass").unwrap(); + let parsed = pkcs12.parse2("mypass").unwrap(); assert_eq!( - parsed - .cert - .fingerprint(MessageDigest::sha1()) - .unwrap() - .to_hex(), + hex::encode(parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); - assert_eq!(parsed.chain.len(), 1); + let chain = parsed.ca.unwrap(); + assert_eq!(chain.len(), 1); assert_eq!( - parsed.chain[0] - .fingerprint(MessageDigest::sha1()) - .unwrap() - .to_hex(), + hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } #[test] fn parse_empty_chain() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + let der = include_bytes!("../test/keystore-empty-chain.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); - let parsed = pkcs12.parse("cassandra").unwrap(); - - assert_eq!(parsed.chain.len(), 0); - assert_eq!(parsed.chain.into_iter().collect::>().len(), 0); + let parsed = pkcs12.parse2("cassandra").unwrap(); + if let Some(stack) = parsed.ca { + assert_eq!(stack.len(), 0); + } } #[test] @@ -237,7 +336,7 @@ mod test { let pkey = PKey::from_rsa(rsa).unwrap(); let mut name = X509Name::builder().unwrap(); - name.append_entry_by_nid(nid::COMMONNAME, subject_name) + name.append_entry_by_nid(Nid::COMMONNAME, subject_name) .unwrap(); let name = name.build(); @@ -258,19 +357,36 @@ mod test { builder.sign(&pkey, MessageDigest::sha256()).unwrap(); let cert = builder.build(); - let pkcs12_builder = Pkcs12::builder(); - let pkcs12 = pkcs12_builder - .build("mypass", subject_name, &pkey, &cert) + let pkcs12 = Pkcs12::builder() + .name(subject_name) + .pkey(&pkey) + .cert(&cert) + .build2("mypass") .unwrap(); let der = pkcs12.to_der().unwrap(); let pkcs12 = Pkcs12::from_der(&der).unwrap(); - let parsed = pkcs12.parse("mypass").unwrap(); + let parsed = pkcs12.parse2("mypass").unwrap(); assert_eq!( - parsed.cert.fingerprint(MessageDigest::sha1()).unwrap(), - cert.fingerprint(MessageDigest::sha1()).unwrap() + &*parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap(), + &*cert.digest(MessageDigest::sha1()).unwrap() ); - assert!(parsed.pkey.public_eq(&pkey)); + assert!(parsed.pkey.unwrap().public_eq(&pkey)); + } + + #[test] + fn create_only_ca() { + let ca = include_bytes!("../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let mut chain = Stack::new().unwrap(); + chain.push(ca).unwrap(); + + let pkcs12 = Pkcs12::builder().ca(chain).build2("hunter2").unwrap(); + let parsed = pkcs12.parse2("hunter2").unwrap(); + + assert!(parsed.cert.is_none()); + assert!(parsed.pkey.is_none()); + assert_eq!(parsed.ca.unwrap().len(), 1); } } diff --git a/openssl/src/pkcs5.rs b/openssl/src/pkcs5.rs index b37e477..c15ce47 100644 --- a/openssl/src/pkcs5.rs +++ b/openssl/src/pkcs5.rs @@ -1,11 +1,11 @@ use libc::c_int; use std::ptr; -use ffi; -use cvt; -use hash::MessageDigest; -use symm::Cipher; -use error::ErrorStack; +use crate::cvt; +use crate::error::ErrorStack; +use crate::hash::MessageDigest; +use crate::symm::Cipher; +use openssl_macros::corresponds; #[derive(Clone, Eq, PartialEq, Hash, Debug)] pub struct KeyIvPair { @@ -23,6 +23,8 @@ pub struct KeyIvPair { /// /// New applications should not use this and instead use /// `pbkdf2_hmac` or another more modern key derivation algorithm. +#[corresponds(EVP_BytesToKey)] +#[allow(clippy::useless_conversion)] pub fn bytes_to_key( cipher: Cipher, digest: MessageDigest, @@ -59,9 +61,10 @@ pub fn bytes_to_key( ))?; let mut key = vec![0; len as usize]; - let iv_ptr = iv.as_mut().map(|v| v.as_mut_ptr()).unwrap_or( - ptr::null_mut(), - ); + let iv_ptr = iv + .as_mut() + .map(|v| v.as_mut_ptr()) + .unwrap_or(ptr::null_mut()); cvt(ffi::EVP_BytesToKey( cipher, @@ -74,11 +77,12 @@ pub fn bytes_to_key( iv_ptr, ))?; - Ok(KeyIvPair { key: key, iv: iv }) + Ok(KeyIvPair { key, iv }) } } /// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. +#[corresponds(PKCS5_PBKDF2_HMAC)] pub fn pbkdf2_hmac( pass: &[u8], salt: &[u8], @@ -101,14 +105,16 @@ pub fn pbkdf2_hmac( hash.as_ptr(), key.len() as c_int, key.as_mut_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Derives a key from a password and salt using the scrypt algorithm. /// -/// Requires the `v110` feature and OpenSSL 1.1.0. -#[cfg(all(feature = "v110", ossl110))] +/// Requires OpenSSL 1.1.0 or newer. +#[corresponds(EVP_PBE_scrypt)] +#[cfg(any(ossl110))] pub fn scrypt( pass: &[u8], salt: &[u8], @@ -131,14 +137,15 @@ pub fn scrypt( maxmem, key.as_mut_ptr() as *mut _, key.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } #[cfg(test)] mod tests { - use hash::MessageDigest; - use symm::Cipher; + use crate::hash::MessageDigest; + use crate::symm::Cipher; // Test vectors from // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c @@ -150,24 +157,9 @@ mod tests { assert_eq!( buf, &[ - 0x55_u8, - 0xac_u8, - 0x04_u8, - 0x6e_u8, - 0x56_u8, - 0xe3_u8, - 0x08_u8, - 0x9f_u8, - 0xec_u8, - 0x16_u8, - 0x91_u8, - 0xc2_u8, - 0x25_u8, - 0x44_u8, - 0xb6_u8, - 0x05_u8, - ] - [..] + 0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8, 0xec_u8, + 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8, + ][..] ); super::pbkdf2_hmac( @@ -176,28 +168,14 @@ mod tests { 80000, MessageDigest::sha256(), &mut buf, - ).unwrap(); + ) + .unwrap(); assert_eq!( buf, &[ - 0x4d_u8, - 0xdc_u8, - 0xd8_u8, - 0xf6_u8, - 0x0b_u8, - 0x98_u8, - 0xbe_u8, - 0x21_u8, - 0x83_u8, - 0x0c_u8, - 0xee_u8, - 0x5e_u8, - 0xf2_u8, - 0x27_u8, - 0x01_u8, - 0xf9_u8, - ] - [..] + 0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8, 0x83_u8, + 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8, + ][..] ); } @@ -211,72 +189,15 @@ mod tests { assert_eq!( &buf[..], &[ - 0x73_u8, - 0xde_u8, - 0xcf_u8, - 0xa5_u8, - 0x8a_u8, - 0xa2_u8, - 0xe8_u8, - 0x4f_u8, - 0x94_u8, - 0x77_u8, - 0x1a_u8, - 0x75_u8, - 0x73_u8, - 0x6b_u8, - 0xb8_u8, - 0x8b_u8, - 0xd3_u8, - 0xc7_u8, - 0xb3_u8, - 0x82_u8, - 0x70_u8, - 0xcf_u8, - 0xb5_u8, - 0x0c_u8, - 0xb3_u8, - 0x90_u8, - 0xed_u8, - 0x78_u8, - 0xb3_u8, - 0x05_u8, - 0x65_u8, - 0x6a_u8, - 0xf8_u8, - 0x14_u8, - 0x8e_u8, - 0x52_u8, - 0x45_u8, - 0x2b_u8, - 0x22_u8, - 0x16_u8, - 0xb2_u8, - 0xb8_u8, - 0x09_u8, - 0x8b_u8, - 0x76_u8, - 0x1f_u8, - 0xc6_u8, - 0x33_u8, - 0x60_u8, - 0x60_u8, - 0xa0_u8, - 0x9f_u8, - 0x76_u8, - 0x41_u8, - 0x5e_u8, - 0x9f_u8, - 0x71_u8, - 0xea_u8, - 0x47_u8, - 0xf9_u8, - 0xe9_u8, + 0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8, 0x94_u8, + 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8, 0xd3_u8, 0xc7_u8, + 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8, 0xb3_u8, 0x90_u8, 0xed_u8, + 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8, 0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, + 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8, 0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, + 0x1f_u8, 0xc6_u8, 0x33_u8, 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, + 0x5e_u8, 0x9f_u8, 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8, - 0x43_u8, - 0x06_u8, - ] - [..] + ][..] ); super::pbkdf2_hmac( @@ -285,76 +206,20 @@ mod tests { 1, MessageDigest::sha512(), &mut buf, - ).unwrap(); + ) + .unwrap(); assert_eq!( &buf[..], &[ - 0x71_u8, - 0xa0_u8, - 0xec_u8, - 0x84_u8, - 0x2a_u8, - 0xbd_u8, - 0x5c_u8, - 0x67_u8, - 0x8b_u8, - 0xcf_u8, - 0xd1_u8, - 0x45_u8, - 0xf0_u8, - 0x9d_u8, - 0x83_u8, - 0x52_u8, - 0x2f_u8, - 0x93_u8, - 0x36_u8, - 0x15_u8, - 0x60_u8, - 0x56_u8, - 0x3c_u8, - 0x4d_u8, - 0x0d_u8, - 0x63_u8, - 0xb8_u8, - 0x83_u8, - 0x29_u8, - 0x87_u8, - 0x10_u8, - 0x90_u8, - 0xe7_u8, - 0x66_u8, - 0x04_u8, - 0xa4_u8, - 0x9a_u8, - 0xf0_u8, - 0x8f_u8, - 0xe7_u8, - 0xc9_u8, - 0xf5_u8, - 0x71_u8, - 0x56_u8, - 0xc8_u8, - 0x79_u8, - 0x09_u8, - 0x96_u8, - 0xb2_u8, - 0x0f_u8, - 0x06_u8, - 0xbc_u8, - 0x53_u8, - 0x5e_u8, - 0x5a_u8, - 0xb5_u8, - 0x44_u8, - 0x0d_u8, - 0xf7_u8, - 0xe8_u8, - 0x78_u8, - 0x29_u8, - 0x6f_u8, + 0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8, 0x8b_u8, + 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8, 0x2f_u8, 0x93_u8, + 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8, 0x0d_u8, 0x63_u8, 0xb8_u8, + 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8, 0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, + 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8, 0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, + 0x79_u8, 0x09_u8, 0x96_u8, 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, + 0x5a_u8, 0xb5_u8, 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8, - ] - [..] + ][..] ); super::pbkdf2_hmac( @@ -363,76 +228,20 @@ mod tests { 50, MessageDigest::sha512(), &mut buf, - ).unwrap(); + ) + .unwrap(); assert_eq!( &buf[..], &[ - 0x01_u8, - 0x68_u8, - 0x71_u8, - 0xa4_u8, - 0xc4_u8, - 0xb7_u8, - 0x5f_u8, - 0x96_u8, - 0x85_u8, - 0x7f_u8, - 0xd2_u8, - 0xb9_u8, - 0xf8_u8, - 0xca_u8, - 0x28_u8, - 0x02_u8, - 0x3b_u8, - 0x30_u8, - 0xee_u8, - 0x2a_u8, + 0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8, 0x85_u8, + 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8, 0x3b_u8, 0x30_u8, + 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8, 0xc8_u8, 0xc9_u8, 0x37_u8, + 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8, 0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, + 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8, 0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, + 0x00_u8, 0x56_u8, 0xc6_u8, 0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, + 0x4b_u8, 0x1a_u8, 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, 0x39_u8, - 0xf5_u8, - 0xad_u8, - 0xca_u8, - 0xc8_u8, - 0xc9_u8, - 0x37_u8, - 0x5f_u8, - 0x9b_u8, - 0xda_u8, - 0x1c_u8, - 0xcd_u8, - 0x1b_u8, - 0x6f_u8, - 0x0b_u8, - 0x2f_u8, - 0xc3_u8, - 0xad_u8, - 0xda_u8, - 0x50_u8, - 0x54_u8, - 0x12_u8, - 0xe7_u8, - 0x9d_u8, - 0x89_u8, - 0x00_u8, - 0x56_u8, - 0xc6_u8, - 0x2e_u8, - 0x52_u8, - 0x4c_u8, - 0x7d_u8, - 0x51_u8, - 0x15_u8, - 0x4b_u8, - 0x1a_u8, - 0x85_u8, - 0x34_u8, - 0x57_u8, - 0x5b_u8, - 0xd0_u8, - 0x2d_u8, - 0xee_u8, - 0x39_u8, - ] - [..] + ][..] ); } @@ -441,93 +250,19 @@ mod tests { let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8]; let data = [ - 143_u8, - 210_u8, - 75_u8, - 63_u8, - 214_u8, - 179_u8, - 155_u8, - 241_u8, - 242_u8, - 31_u8, - 154_u8, - 56_u8, - 198_u8, - 145_u8, - 192_u8, - 64_u8, - 2_u8, - 245_u8, - 167_u8, - 220_u8, - 55_u8, - 119_u8, - 233_u8, - 136_u8, - 139_u8, - 27_u8, - 71_u8, - 242_u8, - 119_u8, - 175_u8, - 65_u8, - 207_u8, + 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8, + 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, + 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8, ]; - - let expected_key = vec![ - 249_u8, - 115_u8, - 114_u8, - 97_u8, - 32_u8, - 213_u8, - 165_u8, - 146_u8, - 58_u8, - 87_u8, - 234_u8, - 3_u8, - 43_u8, - 250_u8, - 97_u8, - 114_u8, - 26_u8, - 98_u8, - 245_u8, - 246_u8, - 238_u8, - 177_u8, - 229_u8, - 161_u8, - 183_u8, - 224_u8, - 174_u8, - 3_u8, - 6_u8, - 244_u8, - 236_u8, - 255_u8, + 249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8, 58_u8, 87_u8, 234_u8, + 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8, 98_u8, 245_u8, 246_u8, 238_u8, 177_u8, + 229_u8, 161_u8, 183_u8, 224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8, ]; let expected_iv = vec![ - 4_u8, - 223_u8, - 153_u8, - 219_u8, - 28_u8, - 142_u8, - 234_u8, - 68_u8, - 227_u8, - 69_u8, - 98_u8, - 107_u8, - 208_u8, - 14_u8, - 236_u8, - 60_u8, + 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, + 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, ]; assert_eq!( @@ -537,7 +272,8 @@ mod tests { &data, Some(&salt), 1, - ).unwrap(), + ) + .unwrap(), super::KeyIvPair { key: expected_key, iv: Some(expected_iv), @@ -546,14 +282,13 @@ mod tests { } #[test] - #[cfg(all(feature = "v110", ossl110))] + #[cfg(any(ossl110))] fn scrypt() { - use hex::ToHex; - let pass = "pleaseletmein"; let salt = "SodiumChloride"; - let expected = "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613\ - f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"; + let expected = + "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613\ + f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"; let mut actual = [0; 64]; super::scrypt( @@ -564,7 +299,8 @@ mod tests { 1, 0, &mut actual, - ).unwrap(); - assert_eq!((&actual[..]).to_hex(), expected); + ) + .unwrap(); + assert_eq!(hex::encode(&actual[..]), expected); } } diff --git a/openssl/src/pkcs7.rs b/openssl/src/pkcs7.rs new file mode 100644 index 0000000..ae4571d --- /dev/null +++ b/openssl/src/pkcs7.rs @@ -0,0 +1,446 @@ +use bitflags::bitflags; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::mem; +use std::ptr; + +use crate::bio::{MemBio, MemBioSlice}; +use crate::error::ErrorStack; +use crate::pkey::{HasPrivate, PKeyRef}; +use crate::stack::{Stack, StackRef}; +use crate::symm::Cipher; +use crate::x509::store::X509StoreRef; +use crate::x509::{X509Ref, X509}; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; + +foreign_type_and_impl_send_sync! { + type CType = ffi::PKCS7; + fn drop = ffi::PKCS7_free; + + /// A PKCS#7 structure. + /// + /// Contains signed and/or encrypted data. + pub struct Pkcs7; + + /// Reference to `Pkcs7` + pub struct Pkcs7Ref; +} + +bitflags! { + pub struct Pkcs7Flags: c_int { + const TEXT = ffi::PKCS7_TEXT; + const NOCERTS = ffi::PKCS7_NOCERTS; + const NOSIGS = ffi::PKCS7_NOSIGS; + const NOCHAIN = ffi::PKCS7_NOCHAIN; + const NOINTERN = ffi::PKCS7_NOINTERN; + const NOVERIFY = ffi::PKCS7_NOVERIFY; + const DETACHED = ffi::PKCS7_DETACHED; + const BINARY = ffi::PKCS7_BINARY; + const NOATTR = ffi::PKCS7_NOATTR; + const NOSMIMECAP = ffi::PKCS7_NOSMIMECAP; + const NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE; + const CRLFEOL = ffi::PKCS7_CRLFEOL; + const STREAM = ffi::PKCS7_STREAM; + const NOCRL = ffi::PKCS7_NOCRL; + const PARTIAL = ffi::PKCS7_PARTIAL; + const REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST; + #[cfg(not(any(ossl101, ossl102, libressl)))] + const NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT; + } +} + +impl Pkcs7 { + from_pem! { + /// Deserializes a PEM-encoded PKCS#7 signature + /// + /// The input should have a header of `-----BEGIN PKCS7-----`. + #[corresponds(PEM_read_bio_PKCS7)] + from_pem, + Pkcs7, + ffi::PEM_read_bio_PKCS7 + } + + from_der! { + /// Deserializes a DER-encoded PKCS#7 signature + #[corresponds(d2i_PKCS7)] + from_der, + Pkcs7, + ffi::d2i_PKCS7 + } + + /// Parses a message in S/MIME format. + /// + /// Returns the loaded signature, along with the cleartext message (if + /// available). + #[corresponds(SMIME_read_PKCS7)] + pub fn from_smime(input: &[u8]) -> Result<(Pkcs7, Option>), ErrorStack> { + ffi::init(); + + let input_bio = MemBioSlice::new(input)?; + let mut bcont_bio = ptr::null_mut(); + unsafe { + let pkcs7 = + cvt_p(ffi::SMIME_read_PKCS7(input_bio.as_ptr(), &mut bcont_bio)).map(Pkcs7)?; + let out = if !bcont_bio.is_null() { + let bcont_bio = MemBio::from_ptr(bcont_bio); + Some(bcont_bio.get_buf().to_vec()) + } else { + None + }; + Ok((pkcs7, out)) + } + } + + /// Creates and returns a PKCS#7 `envelopedData` structure. + /// + /// `certs` is a list of recipient certificates. `input` is the content to be + /// encrypted. `cipher` is the symmetric cipher to use. `flags` is an optional + /// set of flags. + #[corresponds(PKCS7_encrypt)] + pub fn encrypt( + certs: &StackRef, + input: &[u8], + cipher: Cipher, + flags: Pkcs7Flags, + ) -> Result { + let input_bio = MemBioSlice::new(input)?; + + unsafe { + cvt_p(ffi::PKCS7_encrypt( + certs.as_ptr(), + input_bio.as_ptr(), + cipher.as_ptr(), + flags.bits, + )) + .map(Pkcs7) + } + } + + /// Creates and returns a PKCS#7 `signedData` structure. + /// + /// `signcert` is the certificate to sign with, `pkey` is the corresponding + /// private key. `certs` is an optional additional set of certificates to + /// include in the PKCS#7 structure (for example any intermediate CAs in the + /// chain). + #[corresponds(PKCS7_sign)] + pub fn sign( + signcert: &X509Ref, + pkey: &PKeyRef, + certs: &StackRef, + input: &[u8], + flags: Pkcs7Flags, + ) -> Result + where + PT: HasPrivate, + { + let input_bio = MemBioSlice::new(input)?; + unsafe { + cvt_p(ffi::PKCS7_sign( + signcert.as_ptr(), + pkey.as_ptr(), + certs.as_ptr(), + input_bio.as_ptr(), + flags.bits, + )) + .map(Pkcs7) + } + } +} + +impl Pkcs7Ref { + /// Converts PKCS#7 structure to S/MIME format + #[corresponds(SMIME_write_PKCS7)] + pub fn to_smime(&self, input: &[u8], flags: Pkcs7Flags) -> Result, ErrorStack> { + let input_bio = MemBioSlice::new(input)?; + let output = MemBio::new()?; + unsafe { + cvt(ffi::SMIME_write_PKCS7( + output.as_ptr(), + self.as_ptr(), + input_bio.as_ptr(), + flags.bits, + )) + .map(|_| output.get_buf().to_owned()) + } + } + + to_pem! { + /// Serializes the data into a PEM-encoded PKCS#7 structure. + /// + /// The output will have a header of `-----BEGIN PKCS7-----`. + #[corresponds(PEM_write_bio_PKCS7)] + to_pem, + ffi::PEM_write_bio_PKCS7 + } + + to_der! { + /// Serializes the data into a DER-encoded PKCS#7 structure. + #[corresponds(i2d_PKCS7)] + to_der, + ffi::i2d_PKCS7 + } + + /// Decrypts data using the provided private key. + /// + /// `pkey` is the recipient's private key, and `cert` is the recipient's + /// certificate. + /// + /// Returns the decrypted message. + #[corresponds(PKCS7_decrypt)] + pub fn decrypt( + &self, + pkey: &PKeyRef, + cert: &X509Ref, + flags: Pkcs7Flags, + ) -> Result, ErrorStack> + where + PT: HasPrivate, + { + let output = MemBio::new()?; + + unsafe { + cvt(ffi::PKCS7_decrypt( + self.as_ptr(), + pkey.as_ptr(), + cert.as_ptr(), + output.as_ptr(), + flags.bits, + )) + .map(|_| output.get_buf().to_owned()) + } + } + + /// Verifies the PKCS#7 `signedData` structure contained by `&self`. + /// + /// `certs` is a set of certificates in which to search for the signer's + /// certificate. `store` is a trusted certificate store (used for chain + /// verification). `indata` is the signed data if the content is not present + /// in `&self`. The content is written to `out` if it is not `None`. + #[corresponds(PKCS7_verify)] + pub fn verify( + &self, + certs: &StackRef, + store: &X509StoreRef, + indata: Option<&[u8]>, + out: Option<&mut Vec>, + flags: Pkcs7Flags, + ) -> Result<(), ErrorStack> { + let out_bio = MemBio::new()?; + + let indata_bio = match indata { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, + }; + let indata_bio_ptr = indata_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); + + unsafe { + cvt(ffi::PKCS7_verify( + self.as_ptr(), + certs.as_ptr(), + store.as_ptr(), + indata_bio_ptr, + out_bio.as_ptr(), + flags.bits, + )) + .map(|_| ())? + } + + if let Some(data) = out { + data.clear(); + data.extend_from_slice(out_bio.get_buf()); + } + + Ok(()) + } + + /// Retrieve the signer's certificates from the PKCS#7 structure without verifying them. + #[corresponds(PKCS7_get0_signers)] + pub fn signers( + &self, + certs: &StackRef, + flags: Pkcs7Flags, + ) -> Result, ErrorStack> { + unsafe { + let ptr = cvt_p(ffi::PKCS7_get0_signers( + self.as_ptr(), + certs.as_ptr(), + flags.bits, + ))?; + + // The returned stack is owned by the caller, but the certs inside are not! Our stack interface can't deal + // with that, so instead we just manually bump the refcount of the certs so that the whole stack is properly + // owned. + let stack = Stack::::from_ptr(ptr); + for cert in &stack { + mem::forget(cert.to_owned()); + } + + Ok(stack) + } + } +} + +#[cfg(test)] +mod tests { + use crate::hash::MessageDigest; + use crate::pkcs7::{Pkcs7, Pkcs7Flags}; + use crate::pkey::PKey; + use crate::stack::Stack; + use crate::symm::Cipher; + use crate::x509::store::X509StoreBuilder; + use crate::x509::X509; + + #[test] + fn encrypt_decrypt_test() { + let cert = include_bytes!("../test/certs.pem"); + let cert = X509::from_pem(cert).unwrap(); + let mut certs = Stack::new().unwrap(); + certs.push(cert.clone()).unwrap(); + let message: String = String::from("foo"); + let cipher = Cipher::des_ede3_cbc(); + let flags = Pkcs7Flags::STREAM; + let pkey = include_bytes!("../test/key.pem"); + let pkey = PKey::private_key_from_pem(pkey).unwrap(); + + let pkcs7 = + Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed"); + + let encrypted = pkcs7 + .to_smime(message.as_bytes(), flags) + .expect("should succeed"); + + let (pkcs7_decoded, _) = Pkcs7::from_smime(encrypted.as_slice()).expect("should succeed"); + + let decoded = pkcs7_decoded + .decrypt(&pkey, &cert, Pkcs7Flags::empty()) + .expect("should succeed"); + + assert_eq!(decoded, message.into_bytes()); + } + + #[test] + fn sign_verify_test_detached() { + let cert = include_bytes!("../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let certs = Stack::new().unwrap(); + let message = "foo"; + let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED; + let pkey = include_bytes!("../test/key.pem"); + let pkey = PKey::private_key_from_pem(pkey).unwrap(); + let mut store_builder = X509StoreBuilder::new().expect("should succeed"); + + let root_ca = include_bytes!("../test/root-ca.pem"); + let root_ca = X509::from_pem(root_ca).unwrap(); + store_builder.add_cert(root_ca).expect("should succeed"); + + let store = store_builder.build(); + + let pkcs7 = + Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); + + let signed = pkcs7 + .to_smime(message.as_bytes(), flags) + .expect("should succeed"); + println!("{:?}", String::from_utf8(signed.clone()).unwrap()); + let (pkcs7_decoded, content) = + Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); + + let mut output = Vec::new(); + pkcs7_decoded + .verify( + &certs, + &store, + Some(message.as_bytes()), + Some(&mut output), + flags, + ) + .expect("should succeed"); + + assert_eq!(output, message.as_bytes()); + 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(); + let certs = Stack::new().unwrap(); + let message = "foo"; + let flags = Pkcs7Flags::STREAM; + let pkey = include_bytes!("../test/key.pem"); + let pkey = PKey::private_key_from_pem(pkey).unwrap(); + let mut store_builder = X509StoreBuilder::new().expect("should succeed"); + + let root_ca = include_bytes!("../test/root-ca.pem"); + let root_ca = X509::from_pem(root_ca).unwrap(); + store_builder.add_cert(root_ca).expect("should succeed"); + + let store = store_builder.build(); + + let pkcs7 = + Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); + + let signed = pkcs7 + .to_smime(message.as_bytes(), flags) + .expect("should succeed"); + + let (pkcs7_decoded, content) = + Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); + + let mut output = Vec::new(); + pkcs7_decoded + .verify(&certs, &store, None, Some(&mut output), flags) + .expect("should succeed"); + + assert_eq!(output, message.as_bytes()); + 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(); + let cert_digest = cert.digest(MessageDigest::sha256()).unwrap(); + let certs = Stack::new().unwrap(); + let message = "foo"; + let flags = Pkcs7Flags::STREAM; + let pkey = include_bytes!("../test/key.pem"); + let pkey = PKey::private_key_from_pem(pkey).unwrap(); + let mut store_builder = X509StoreBuilder::new().expect("should succeed"); + + let root_ca = include_bytes!("../test/root-ca.pem"); + let root_ca = X509::from_pem(root_ca).unwrap(); + store_builder.add_cert(root_ca).expect("should succeed"); + + let pkcs7 = + Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); + + let signed = pkcs7 + .to_smime(message.as_bytes(), flags) + .expect("should succeed"); + + let (pkcs7_decoded, _) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); + + let empty_certs = Stack::new().unwrap(); + let signer_certs = pkcs7_decoded + .signers(&empty_certs, flags) + .expect("should succeed"); + assert_eq!(empty_certs.len(), 0); + assert_eq!(signer_certs.len(), 1); + let signer_digest = signer_certs[0].digest(MessageDigest::sha256()).unwrap(); + assert_eq!(*cert_digest, *signer_digest); + } + + #[test] + fn invalid_from_smime() { + let input = String::from("Invalid SMIME Message"); + let result = Pkcs7::from_smime(input.as_bytes()); + + assert!(result.is_err()); + } +} diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 9ef7e88..bec4bfd 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -1,30 +1,159 @@ -use libc::{c_void, c_char, c_int, size_t}; -use std::ptr; -use std::mem; -use std::ffi::CString; -use ffi; +//! Public/private key processing. +//! +//! Asymmetric public key algorithms solve the problem of establishing and sharing +//! secret keys to securely send and receive messages. +//! This system uses a pair of keys: a public key, which can be freely +//! distributed, and a private key, which is kept to oneself. An entity may +//! encrypt information using a user's public key. The encrypted information can +//! only be deciphered using that user's private key. +//! +//! This module offers support for five popular algorithms: +//! +//! * RSA +//! +//! * DSA +//! +//! * Diffie-Hellman +//! +//! * Elliptic Curves +//! +//! * HMAC +//! +//! These algorithms rely on hard mathematical problems - namely integer factorization, +//! discrete logarithms, and elliptic curve relationships - that currently do not +//! yield efficient solutions. This property ensures the security of these +//! cryptographic algorithms. +//! +//! # Example +//! +//! Generate a 2048-bit RSA public/private key pair and print the public key. +//! +//! ```rust +//! use openssl::rsa::Rsa; +//! use openssl::pkey::PKey; +//! use std::str; +//! +//! let rsa = Rsa::generate(2048).unwrap(); +//! let pkey = PKey::from_rsa(rsa).unwrap(); +//! +//! let pub_key: Vec = pkey.public_key_to_pem().unwrap(); +//! println!("{:?}", str::from_utf8(pub_key.as_slice()).unwrap()); +//! ``` +#![allow(clippy::missing_safety_doc)] +use crate::bio::{MemBio, MemBioSlice}; +#[cfg(ossl110)] +use crate::cipher::CipherRef; +use crate::dh::Dh; +use crate::dsa::Dsa; +use crate::ec::EcKey; +use crate::error::ErrorStack; +#[cfg(any(ossl110, boringssl, libressl370))] +use crate::pkey_ctx::PkeyCtx; +use crate::rsa::Rsa; +use crate::symm::Cipher; +use crate::util::{invoke_passwd_cb, CallbackState}; +use crate::{cvt, cvt_p}; +use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::{c_int, c_long}; +use openssl_macros::corresponds; +use std::convert::TryFrom; +use std::ffi::CString; +use std::fmt; +use std::mem; +use std::ptr; + +/// A tag type indicating that a key only has parameters. +pub enum Params {} + +/// A tag type indicating that a key only has public components. +pub enum Public {} + +/// A tag type indicating that a key has private components. +pub enum Private {} + +/// An identifier of a kind of key. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Id(c_int); + +impl Id { + pub const RSA: Id = Id(ffi::EVP_PKEY_RSA); + #[cfg(not(boringssl))] + pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC); + #[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); + pub const EC: Id = Id(ffi::EVP_PKEY_EC); + + #[cfg(ossl110)] + pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF); + + #[cfg(any(ossl111, boringssl, libressl370))] + pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519); + #[cfg(ossl111)] + pub const ED448: Id = Id(ffi::EVP_PKEY_ED448); + #[cfg(any(ossl111, boringssl, libressl370))] + pub const X25519: Id = Id(ffi::EVP_PKEY_X25519); + #[cfg(ossl111)] + pub const X448: Id = Id(ffi::EVP_PKEY_X448); + + /// Creates a `Id` from an integer representation. + pub fn from_raw(value: c_int) -> Id { + Id(value) + } + + /// Returns the integer representation of the `Id`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> c_int { + self.0 + } +} -use {cvt, cvt_p}; -use bio::MemBioSlice; -use dh::Dh; -use dsa::Dsa; -use ec::EcKey; -use rsa::{Rsa, Padding}; -use error::ErrorStack; -use util::{CallbackState, invoke_passwd_cb, invoke_passwd_cb_old}; +/// A trait indicating that a key has parameters. +pub unsafe trait HasParams {} -foreign_type_and_impl_send_sync! { +unsafe impl HasParams for Params {} + +unsafe impl HasParams for T where T: HasPublic {} + +/// A trait indicating that a key has public components. +pub unsafe trait HasPublic {} + +unsafe impl HasPublic for Public {} + +unsafe impl HasPublic for T where T: HasPrivate {} + +/// A trait indicating that a key has private components. +pub unsafe trait HasPrivate {} + +unsafe impl HasPrivate for Private {} + +generic_foreign_type_and_impl_send_sync! { type CType = ffi::EVP_PKEY; fn drop = ffi::EVP_PKEY_free; - pub struct PKey; - pub struct PKeyRef; + /// A public or private key. + pub struct PKey; + /// Reference to `PKey`. + pub struct PKeyRef; } -impl PKeyRef { +impl ToOwned for PKeyRef { + type Owned = PKey; + + fn to_owned(&self) -> PKey { + unsafe { + EVP_PKEY_up_ref(self.as_ptr()); + PKey::from_ptr(self.as_ptr()) + } + } +} + +impl PKeyRef { /// Returns a copy of the internal RSA key. - pub fn rsa(&self) -> Result { + #[corresponds(EVP_PKEY_get1_RSA)] + pub fn rsa(&self) -> Result, ErrorStack> { unsafe { let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?; Ok(Rsa::from_ptr(rsa)) @@ -32,7 +161,8 @@ impl PKeyRef { } /// Returns a copy of the internal DSA key. - pub fn dsa(&self) -> Result { + #[corresponds(EVP_PKEY_get1_DSA)] + pub fn dsa(&self) -> Result, ErrorStack> { unsafe { let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?; Ok(Dsa::from_ptr(dsa)) @@ -40,7 +170,8 @@ impl PKeyRef { } /// Returns a copy of the internal DH key. - pub fn dh(&self) -> Result { + #[corresponds(EVP_PKEY_get1_DH)] + pub fn dh(&self) -> Result, ErrorStack> { unsafe { let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?; Ok(Dh::from_ptr(dh)) @@ -48,39 +179,233 @@ impl PKeyRef { } /// Returns a copy of the internal elliptic curve key. - pub fn ec_key(&self) -> Result { + #[corresponds(EVP_PKEY_get1_EC_KEY)] + pub fn ec_key(&self) -> Result, ErrorStack> { unsafe { let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?; Ok(EcKey::from_ptr(ec_key)) } } - public_key_to_pem!(ffi::PEM_write_bio_PUBKEY); - private_key_to_pem!(ffi::PEM_write_bio_PKCS8PrivateKey); + /// Returns the `Id` that represents the type of this key. + #[corresponds(EVP_PKEY_id)] + pub fn id(&self) -> Id { + unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) } + } + + /// Returns the maximum size of a signature in bytes. + #[corresponds(EVP_PKEY_size)] + pub fn size(&self) -> usize { + unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize } + } +} + +impl PKeyRef +where + T: HasPublic, +{ + to_pem! { + /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_write_bio_PUBKEY)] + public_key_to_pem, + ffi::PEM_write_bio_PUBKEY + } - private_key_to_der!(ffi::i2d_PrivateKey); - public_key_to_der!(ffi::i2d_PUBKEY); + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + #[corresponds(i2d_PUBKEY)] + public_key_to_der, + ffi::i2d_PUBKEY + } /// Returns the size of the key. /// /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the /// group order for an elliptic curve key, for example. + #[corresponds(EVP_PKEY_bits)] pub fn bits(&self) -> u32 { unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } } + ///Returns the number of security bits. + /// + ///Bits of security is defined in NIST SP800-57. + #[corresponds(EVP_PKEY_security_bits)] + #[cfg(any(ossl110, libressl360))] + pub fn security_bits(&self) -> u32 { + unsafe { ffi::EVP_PKEY_security_bits(self.as_ptr()) as u32 } + } + /// Compares the public component of this key with another. - pub fn public_eq(&self, other: &PKeyRef) -> bool { + #[corresponds(EVP_PKEY_cmp)] + pub fn public_eq(&self, other: &PKeyRef) -> bool + where + U: HasPublic, + { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } + + /// Raw byte representation of a public key. + /// + /// 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(any(ossl111, boringssl, libressl370))] + pub fn raw_public_key(&self) -> Result, ErrorStack> { + unsafe { + let mut len = 0; + cvt(ffi::EVP_PKEY_get_raw_public_key( + self.as_ptr(), + ptr::null_mut(), + &mut len, + ))?; + let mut buf = vec![0u8; len]; + cvt(ffi::EVP_PKEY_get_raw_public_key( + self.as_ptr(), + buf.as_mut_ptr(), + &mut len, + ))?; + buf.truncate(len); + Ok(buf) + } + } } -impl PKey { +impl PKeyRef +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_PKCS8PrivateKey)] + private_key_to_pem_pkcs8, + /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_PKCS8PrivateKey)] + private_key_to_pem_pkcs8_passphrase, + ffi::PEM_write_bio_PKCS8PrivateKey + } + + to_der! { + /// Serializes the private key to a DER-encoded key type specific format. + #[corresponds(i2d_PrivateKey)] + private_key_to_der, + ffi::i2d_PrivateKey + } + + /// Raw byte representation of a private key. + /// + /// 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(any(ossl111, boringssl, libressl370))] + pub fn raw_private_key(&self) -> Result, ErrorStack> { + unsafe { + let mut len = 0; + cvt(ffi::EVP_PKEY_get_raw_private_key( + self.as_ptr(), + ptr::null_mut(), + &mut len, + ))?; + let mut buf = vec![0u8; len]; + cvt(ffi::EVP_PKEY_get_raw_private_key( + self.as_ptr(), + buf.as_mut_ptr(), + &mut len, + ))?; + buf.truncate(len); + Ok(buf) + } + } + + /// Serializes a private key into an unencrypted DER-formatted PKCS#8 + #[corresponds(i2d_PKCS8PrivateKey_bio)] + pub fn private_key_to_pkcs8(&self) -> Result, ErrorStack> { + unsafe { + let bio = MemBio::new()?; + cvt(ffi::i2d_PKCS8PrivateKey_bio( + bio.as_ptr(), + self.as_ptr(), + ptr::null(), + ptr::null_mut(), + 0, + None, + ptr::null_mut(), + ))?; + + Ok(bio.get_buf().to_owned()) + } + } + + /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to + /// encrypt the key. + /// + /// # Panics + /// + /// Panics if `passphrase` contains an embedded null. + #[corresponds(i2d_PKCS8PrivateKey_bio)] + pub fn private_key_to_pkcs8_passphrase( + &self, + cipher: Cipher, + passphrase: &[u8], + ) -> Result, ErrorStack> { + unsafe { + let bio = MemBio::new()?; + let len = passphrase.len(); + let passphrase = CString::new(passphrase).unwrap(); + cvt(ffi::i2d_PKCS8PrivateKey_bio( + bio.as_ptr(), + self.as_ptr(), + cipher.as_ptr(), + passphrase.as_ptr() as *const _ as *mut _, + len as ::libc::c_int, + None, + ptr::null_mut(), + ))?; + + Ok(bio.get_buf().to_owned()) + } + } +} + +impl fmt::Debug for PKey { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let alg = match self.id() { + Id::RSA => "RSA", + #[cfg(not(boringssl))] + Id::HMAC => "HMAC", + Id::DSA => "DSA", + Id::DH => "DH", + Id::EC => "EC", + #[cfg(ossl111)] + Id::ED25519 => "Ed25519", + #[cfg(ossl111)] + Id::ED448 => "Ed448", + _ => "unknown", + }; + fmt.debug_struct("PKey").field("algorithm", &alg).finish() + // TODO: Print details for each specific type of key + } +} + +impl Clone for PKey { + fn clone(&self) -> PKey { + PKeyRef::to_owned(self) + } +} + +impl PKey { /// Creates a new `PKey` containing an RSA key. - pub fn from_rsa(rsa: Rsa) -> Result { + #[corresponds(EVP_PKEY_assign_RSA)] + pub fn from_rsa(rsa: Rsa) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; - let pkey = PKey(evp); + let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_RSA, @@ -92,10 +417,11 @@ impl PKey { } /// Creates a new `PKey` containing a DSA key. - pub fn from_dsa(dsa: Dsa) -> Result { + #[corresponds(EVP_PKEY_assign_DSA)] + pub fn from_dsa(dsa: Dsa) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; - let pkey = PKey(evp); + let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_DSA, @@ -107,10 +433,11 @@ impl PKey { } /// Creates a new `PKey` containing a Diffie-Hellman key. - pub fn from_dh(dh: Dh) -> Result { + #[corresponds(EVP_PKEY_assign_DH)] + pub fn from_dh(dh: Dh) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; - let pkey = PKey(evp); + let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_DH, @@ -122,10 +449,11 @@ impl PKey { } /// Creates a new `PKey` containing an elliptic curve key. - pub fn from_ec_key(ec_key: EcKey) -> Result { + #[corresponds(EVP_PKEY_assign_EC_KEY)] + pub fn from_ec_key(ec_key: EcKey) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; - let pkey = PKey(evp); + let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_EC, @@ -135,12 +463,17 @@ impl PKey { Ok(pkey) } } +} +impl PKey { /// Creates a new `PKey` containing an HMAC key. /// /// # Note + /// /// To compute HMAC values, use the `sign` module. - pub fn hmac(key: &[u8]) -> Result { + #[corresponds(EVP_PKEY_new_mac_key)] + #[cfg(not(boringssl))] + pub fn hmac(key: &[u8]) -> Result, ErrorStack> { unsafe { assert!(key.len() <= c_int::max_value() as usize); let key = cvt_p(ffi::EVP_PKEY_new_mac_key( @@ -149,21 +482,215 @@ impl PKey { key.as_ptr() as *const _, key.len() as c_int, ))?; - Ok(PKey(key)) + Ok(PKey::from_ptr(key)) + } + } + + /// Creates a new `PKey` containing a CMAC key. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// # Note + /// + /// To compute CMAC values, use the `sign` module. + #[cfg(all(not(boringssl), ossl110))] + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result, ErrorStack> { + let mut ctx = PkeyCtx::new_id(Id::CMAC)?; + ctx.keygen_init()?; + ctx.set_keygen_cipher(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) })?; + ctx.set_keygen_mac_key(key)?; + ctx.keygen() + } + + #[cfg(any(ossl111, boringssl, libressl370))] + fn generate_eddsa(id: Id) -> Result, ErrorStack> { + let mut ctx = PkeyCtx::new_id(id)?; + ctx.keygen_init()?; + ctx.keygen() + } + + /// 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> { + /// 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(ossl111, boringssl, libressl370))] + pub fn generate_x25519() -> Result, ErrorStack> { + PKey::generate_eddsa(Id::X25519) + } + + /// 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> { + /// 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, ErrorStack> { + PKey::generate_eddsa(Id::X448) + } + + /// 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> { + /// 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(ossl111, boringssl, libressl370))] + pub fn generate_ed25519() -> Result, ErrorStack> { + PKey::generate_eddsa(Id::ED25519) + } + + /// 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> { + /// 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, ErrorStack> { + PKey::generate_eddsa(Id::ED448) + } + + /// Generates a new EC key using the provided curve. + /// + /// Requires OpenSSL 3.0.0 or newer. + #[corresponds(EVP_EC_gen)] + #[cfg(ossl300)] + pub fn ec_gen(curve: &str) -> Result, ErrorStack> { + ffi::init(); + + let curve = CString::new(curve).unwrap(); + unsafe { + let ptr = cvt_p(ffi::EVP_EC_gen(curve.as_ptr()))?; + Ok(PKey::from_ptr(ptr)) } } - private_key_from_pem!(PKey, ffi::PEM_read_bio_PrivateKey); - public_key_from_pem!(PKey, ffi::PEM_read_bio_PUBKEY); - public_key_from_der!(PKey, ffi::d2i_PUBKEY); - private_key_from_der!(PKey, ffi::d2i_AutoPrivateKey); + private_key_from_pem! { + /// Deserializes a private key from a PEM-encoded key type specific format. + #[corresponds(PEM_read_bio_PrivateKey)] + private_key_from_pem, + + /// Deserializes a private key from a PEM-encoded encrypted key type specific format. + #[corresponds(PEM_read_bio_PrivateKey)] + private_key_from_pem_passphrase, + + /// Deserializes a private key from a PEM-encoded encrypted key type specific format. + /// + /// The callback should fill the password into the provided buffer and return its length. + #[corresponds(PEM_read_bio_PrivateKey)] + private_key_from_pem_callback, + PKey, + ffi::PEM_read_bio_PrivateKey + } + + from_der! { + /// Decodes a DER-encoded private key. + /// + /// This function will attempt to automatically detect the underlying key format, and + /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific + /// formats. + #[corresponds(d2i_AutoPrivateKey)] + private_key_from_der, + PKey, + ffi::d2i_AutoPrivateKey + } + + /// Deserializes a DER-formatted PKCS#8 unencrypted private key. + /// + /// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred. + pub fn private_key_from_pkcs8(der: &[u8]) -> Result, ErrorStack> { + unsafe { + ffi::init(); + let len = der.len().min(c_long::max_value() as usize) as c_long; + let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO( + ptr::null_mut(), + &mut der.as_ptr(), + len, + ))?; + let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p)); + ffi::PKCS8_PRIV_KEY_INFO_free(p8inf); + res + } + } /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password - /// if the key is encrpyted. + /// if the key is encrypted. /// /// The callback should copy the password into the provided buffer and return the number of /// bytes written. - pub fn private_key_from_pkcs8_callback(der: &[u8], callback: F) -> Result + #[corresponds(d2i_PKCS8PrivateKey_bio)] + pub fn private_key_from_pkcs8_callback( + der: &[u8], + callback: F, + ) -> Result, ErrorStack> where F: FnOnce(&mut [u8]) -> Result, { @@ -176,7 +703,8 @@ impl PKey { ptr::null_mut(), Some(invoke_passwd_cb::), &mut cb as *mut _ as *mut _, - )).map(PKey) + )) + .map(|p| PKey::from_ptr(p)) } } @@ -186,10 +714,11 @@ impl PKey { /// # Panics /// /// Panics if `passphrase` contains an embedded null. + #[corresponds(d2i_PKCS8PrivateKey_bio)] pub fn private_key_from_pkcs8_passphrase( der: &[u8], passphrase: &[u8], - ) -> Result { + ) -> Result, ErrorStack> { unsafe { ffi::init(); let bio = MemBioSlice::new(der)?; @@ -199,131 +728,211 @@ impl PKey { ptr::null_mut(), None, passphrase.as_ptr() as *const _ as *mut _, - )).map(PKey) + )) + .map(|p| PKey::from_ptr(p)) } } - #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] - pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result - where - F: FnOnce(&mut [c_char]) -> usize, - { - ffi::init(); - let mut cb = CallbackState::new(pass_cb); - let mem_bio = MemBioSlice::new(buf)?; + /// Creates a private key from its raw byte representation + /// + /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448 + #[corresponds(EVP_PKEY_new_raw_private_key)] + #[cfg(any(ossl111, boringssl, libressl370))] + pub fn private_key_from_raw_bytes( + bytes: &[u8], + key_type: Id, + ) -> Result, ErrorStack> { unsafe { - let evp = cvt_p(ffi::PEM_read_bio_PrivateKey( - mem_bio.as_ptr(), + ffi::init(); + cvt_p(ffi::EVP_PKEY_new_raw_private_key( + key_type.as_raw(), ptr::null_mut(), - Some(invoke_passwd_cb_old::), - &mut cb as *mut _ as *mut c_void, - ))?; - Ok(PKey::from_ptr(evp)) + bytes.as_ptr(), + bytes.len(), + )) + .map(|p| PKey::from_ptr(p)) } } } -foreign_type_and_impl_send_sync! { - type CType = ffi::EVP_PKEY_CTX; - fn drop = ffi::EVP_PKEY_CTX_free; +impl PKey { + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_read_bio_PUBKEY)] + public_key_from_pem, + PKey, + ffi::PEM_read_bio_PUBKEY + } - pub struct PKeyCtx; - pub struct PKeyCtxRef; -} + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure. + #[corresponds(d2i_PUBKEY)] + public_key_from_der, + PKey, + ffi::d2i_PUBKEY + } -impl PKeyCtx { - pub fn from_pkey(pkey: &PKeyRef) -> Result { + /// Creates a public key from its raw byte representation + /// + /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448 + #[corresponds(EVP_PKEY_new_raw_public_key)] + #[cfg(any(ossl111, boringssl, libressl370))] + pub fn public_key_from_raw_bytes( + bytes: &[u8], + key_type: Id, + ) -> Result, ErrorStack> { unsafe { - let evp = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; - Ok(PKeyCtx(evp)) + ffi::init(); + cvt_p(ffi::EVP_PKEY_new_raw_public_key( + key_type.as_raw(), + ptr::null_mut(), + bytes.as_ptr(), + bytes.len(), + )) + .map(|p| PKey::from_ptr(p)) } } } -impl PKeyCtxRef { - pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( - self.as_ptr(), - pad.as_raw(), - ))?; +cfg_if! { + if #[cfg(any(boringssl, ossl110, libressl270))] { + use ffi::EVP_PKEY_up_ref; + } else { + #[allow(bad_style)] + unsafe extern "C" fn EVP_PKEY_up_ref(pkey: *mut ffi::EVP_PKEY) { + ffi::CRYPTO_add_lock( + &mut (*pkey).references, + 1, + ffi::CRYPTO_LOCK_EVP_PKEY, + "pkey.rs\0".as_ptr() as *const _, + line!() as c_int, + ); } - Ok(()) } +} - pub fn rsa_padding(&self) -> Result { - let mut pad: c_int = 0; - unsafe { - cvt( - ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad), - )?; - }; - Ok(Padding::from_raw(pad)) +impl TryFrom> for PKey { + type Error = ErrorStack; + + fn try_from(ec_key: EcKey) -> Result, ErrorStack> { + PKey::from_ec_key(ec_key) } +} - pub fn derive_init(&mut self) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?; - } - Ok(()) +impl TryFrom> for EcKey { + type Error = ErrorStack; + + fn try_from(pkey: PKey) -> Result, ErrorStack> { + pkey.ec_key() } +} - pub fn derive_set_peer(&mut self, peer: &PKeyRef) -> Result<(), ErrorStack> { - unsafe { - cvt( - ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), peer.as_ptr()), - )?; - } - Ok(()) +impl TryFrom> for PKey { + type Error = ErrorStack; + + fn try_from(rsa: Rsa) -> Result, ErrorStack> { + PKey::from_rsa(rsa) } +} - pub fn derive(&mut self) -> Result, ErrorStack> { - let mut len: size_t = 0; - unsafe { - cvt(ffi::EVP_PKEY_derive( - self.as_ptr(), - ptr::null_mut(), - &mut len, - ))?; - } +impl TryFrom> for Rsa { + type Error = ErrorStack; - let mut key = vec![0u8; len]; - unsafe { - cvt(ffi::EVP_PKEY_derive( - self.as_ptr(), - key.as_mut_ptr(), - &mut len, - ))?; - } - Ok(key) + fn try_from(pkey: PKey) -> Result, ErrorStack> { + pkey.rsa() + } +} + +impl TryFrom> for PKey { + type Error = ErrorStack; + + fn try_from(dsa: Dsa) -> Result, ErrorStack> { + PKey::from_dsa(dsa) + } +} + +impl TryFrom> for Dsa { + type Error = ErrorStack; + + fn try_from(pkey: PKey) -> Result, ErrorStack> { + pkey.dsa() + } +} + +impl TryFrom> for PKey { + type Error = ErrorStack; + + fn try_from(dh: Dh) -> Result, ErrorStack> { + PKey::from_dh(dh) + } +} + +impl TryFrom> for Dh { + type Error = ErrorStack; + + fn try_from(pkey: PKey) -> Result, ErrorStack> { + pkey.dh() } } #[cfg(test)] mod tests { - use symm::Cipher; - use dh::Dh; - use dsa::Dsa; - use ec::{EcGroup, EcKey}; - use rsa::Rsa; - use nid; + use std::convert::TryInto; + + #[cfg(not(boringssl))] + use crate::dh::Dh; + use crate::dsa::Dsa; + use crate::ec::EcKey; + use crate::nid::Nid; + use crate::rsa::Rsa; + use crate::symm::Cipher; use super::*; + #[cfg(ossl111)] + use crate::rand::rand_bytes; + #[test] fn test_to_password() { let rsa = Rsa::generate(2048).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); - let pem = pkey.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") + let pem = pkey + .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar") .unwrap(); PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); } + #[test] + fn test_unencrypted_pkcs8() { + let key = include_bytes!("../test/pkcs8-nocrypt.der"); + let pkey = PKey::private_key_from_pkcs8(key).unwrap(); + let serialized = pkey.private_key_to_pkcs8().unwrap(); + let pkey2 = PKey::private_key_from_pkcs8(&serialized).unwrap(); + + assert_eq!( + pkey2.private_key_to_der().unwrap(), + pkey.private_key_to_der().unwrap() + ); + } + #[test] fn test_encrypted_pkcs8_passphrase() { let key = include_bytes!("../test/pkcs8.der"); PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap(); + + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + let der = pkey + .private_key_to_pkcs8_passphrase(Cipher::aes_128_cbc(), b"mypass") + .unwrap(); + let pkey2 = PKey::private_key_from_pkcs8_passphrase(&der, b"mypass").unwrap(); + assert_eq!( + pkey.private_key_to_der().unwrap(), + pkey2.private_key_to_der().unwrap() + ); } #[test] @@ -334,7 +943,8 @@ mod tests { password_queried = true; password[..6].copy_from_slice(b"mypass"); Ok(6) - }).unwrap(); + }) + .unwrap(); assert!(password_queried); } @@ -367,7 +977,7 @@ mod tests { let key = include_bytes!("../test/key.pem"); let key = PKey::private_key_from_pem(key).unwrap(); - let priv_key = key.private_key_to_pem().unwrap(); + let priv_key = key.private_key_to_pem_pkcs8().unwrap(); let pub_key = key.public_key_to_pem().unwrap(); // As a super-simple verification, just check that the buffers contain @@ -381,6 +991,7 @@ mod tests { let rsa = Rsa::generate(2048).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); pkey.rsa().unwrap(); + assert_eq!(pkey.id(), Id::RSA); assert!(pkey.dsa().is_err()); } @@ -389,37 +1000,172 @@ mod tests { let dsa = Dsa::generate(2048).unwrap(); let pkey = PKey::from_dsa(dsa).unwrap(); pkey.dsa().unwrap(); + assert_eq!(pkey.id(), Id::DSA); assert!(pkey.rsa().is_err()); } #[test] + #[cfg(not(boringssl))] fn test_dh_accessor() { let dh = include_bytes!("../test/dhparams.pem"); - let dh = Dh::from_pem(dh).unwrap(); + let dh = Dh::params_from_pem(dh).unwrap(); let pkey = PKey::from_dh(dh).unwrap(); pkey.dh().unwrap(); + assert_eq!(pkey.id(), Id::DH); assert!(pkey.rsa().is_err()); } #[test] fn test_ec_key_accessor() { - let ec_key = EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let pkey = PKey::from_ec_key(ec_key).unwrap(); pkey.ec_key().unwrap(); + assert_eq!(pkey.id(), Id::EC); assert!(pkey.rsa().is_err()); } #[test] - fn test_ec_key_derive() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + fn test_rsa_conversion() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey: PKey = rsa.clone().try_into().unwrap(); + let rsa_: Rsa = pkey.try_into().unwrap(); + // Eq is missing + assert_eq!(rsa.p(), rsa_.p()); + assert_eq!(rsa.q(), rsa_.q()); + } + + #[test] + fn test_dsa_conversion() { + let dsa = Dsa::generate(2048).unwrap(); + let pkey: PKey = dsa.clone().try_into().unwrap(); + let dsa_: Dsa = pkey.try_into().unwrap(); + // Eq is missing + assert_eq!(dsa.priv_key(), dsa_.priv_key()); + } + + #[test] + fn test_ec_key_conversion() { + let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let pkey: PKey = ec_key.clone().try_into().unwrap(); + let ec_key_: EcKey = pkey.try_into().unwrap(); + // Eq is missing + assert_eq!(ec_key.private_key(), ec_key_.private_key()); + } + + #[test] + #[cfg(any(ossl110, libressl360))] + fn test_security_bits() { + let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::SECP521R1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let pkey: PKey = ec_key.try_into().unwrap(); + + assert_eq!(pkey.security_bits(), 256); + } + + #[test] + #[cfg(not(boringssl))] + fn test_dh_conversion() { + let dh_params = include_bytes!("../test/dhparams.pem"); + let dh_params = Dh::params_from_pem(dh_params).unwrap(); + let dh = dh_params.generate_key().unwrap(); + + // Clone is missing for Dh, save the parameters + let p = dh.prime_p().to_owned().unwrap(); + let q = dh.prime_q().map(|q| q.to_owned().unwrap()); + let g = dh.generator().to_owned().unwrap(); + + let pkey: PKey = dh.try_into().unwrap(); + let dh_: Dh = pkey.try_into().unwrap(); + + // Eq is missing + assert_eq!(&p, dh_.prime_p()); + assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap())); + assert_eq!(&g, dh_.generator()); + } + + #[cfg(any(ossl111, boringssl, libressl370))] + fn test_raw_public_key(gen: fn() -> Result, ErrorStack>, key_type: Id) { + // Generate a new key + let key = gen().unwrap(); + + // Get the raw bytes, and create a new key from the raw bytes + let raw = key.raw_public_key().unwrap(); + let from_raw = PKey::public_key_from_raw_bytes(&raw, key_type).unwrap(); + + // Compare the der encoding of the original and raw / restored public key + assert_eq!( + key.public_key_to_der().unwrap(), + from_raw.public_key_to_der().unwrap() + ); + } + + #[cfg(any(ossl111, boringssl, libressl370))] + fn test_raw_private_key(gen: fn() -> Result, ErrorStack>, key_type: Id) { + // Generate a new key + let key = gen().unwrap(); + + // Get the raw bytes, and create a new key from the raw bytes + let raw = key.raw_private_key().unwrap(); + let from_raw = PKey::private_key_from_raw_bytes(&raw, key_type).unwrap(); + + // Compare the der encoding of the original and raw / restored public key + assert_eq!( + key.private_key_to_pkcs8().unwrap(), + from_raw.private_key_to_pkcs8().unwrap() + ); + } + + #[cfg(any(ossl111, boringssl, libressl370))] + #[test] + fn test_raw_public_key_bytes() { + test_raw_public_key(PKey::generate_x25519, Id::X25519); + test_raw_public_key(PKey::generate_ed25519, Id::ED25519); + #[cfg(all(not(boringssl), not(libressl370)))] + test_raw_public_key(PKey::generate_x448, Id::X448); + #[cfg(all(not(boringssl), not(libressl370)))] + test_raw_public_key(PKey::generate_ed448, Id::ED448); + } + + #[cfg(any(ossl111, boringssl, libressl370))] + #[test] + fn test_raw_private_key_bytes() { + test_raw_private_key(PKey::generate_x25519, Id::X25519); + test_raw_private_key(PKey::generate_ed25519, Id::ED25519); + #[cfg(all(not(boringssl), not(libressl370)))] + test_raw_private_key(PKey::generate_x448, Id::X448); + #[cfg(all(not(boringssl), not(libressl370)))] + test_raw_private_key(PKey::generate_ed448, Id::ED448); + } + + #[cfg(ossl111)] + #[test] + fn test_raw_hmac() { + let mut test_bytes = vec![0u8; 32]; + rand_bytes(&mut test_bytes).unwrap(); + + let hmac_key = PKey::hmac(&test_bytes).unwrap(); + assert!(hmac_key.raw_public_key().is_err()); + + let key_bytes = hmac_key.raw_private_key().unwrap(); + assert_eq!(key_bytes, test_bytes); + } + + #[cfg(ossl111)] + #[test] + fn test_raw_key_fail() { + // Getting a raw byte representation will not work with Nist curves + let group = crate::ec::EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); let ec_key = EcKey::generate(&group).unwrap(); - let ec_key2 = EcKey::generate(&group).unwrap(); let pkey = PKey::from_ec_key(ec_key).unwrap(); - let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); - let mut pkey_ctx = PKeyCtx::from_pkey(&pkey).unwrap(); - pkey_ctx.derive_init().unwrap(); - pkey_ctx.derive_set_peer(&pkey2).unwrap(); - let shared = pkey_ctx.derive().unwrap(); - assert!(!shared.is_empty()); + assert!(pkey.raw_private_key().is_err()); + assert!(pkey.raw_public_key().is_err()); + } + + #[cfg(ossl300)] + #[test] + fn test_ec_gen() { + let key = PKey::ec_gen("prime256v1").unwrap(); + assert!(key.ec_key().is_ok()); } } diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs new file mode 100644 index 0000000..42289b9 --- /dev/null +++ b/openssl/src/pkey_ctx.rs @@ -0,0 +1,804 @@ +//! The asymmetric encryption context. +//! +//! # Examples +//! +//! Encrypt data with RSA +//! +//! ``` +//! use openssl::rsa::Rsa; +//! use openssl::pkey::PKey; +//! use openssl::pkey_ctx::PkeyCtx; +//! +//! let key = Rsa::generate(4096).unwrap(); +//! let key = PKey::from_rsa(key).unwrap(); +//! +//! let mut ctx = PkeyCtx::new(&key).unwrap(); +//! ctx.encrypt_init().unwrap(); +//! +//! let data = b"Some Crypto Text"; +//! let mut ciphertext = vec![]; +//! ctx.encrypt_to_vec(data, &mut ciphertext).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 +//! +//! ``` +//! use openssl::pkey_ctx::PkeyCtx; +//! use openssl::pkey::PKey; +//! use openssl::rsa::Rsa; +//! +//! // Generate a random RSA key. +//! let key = Rsa::generate(4096).unwrap(); +//! let key = PKey::from_rsa(key).unwrap(); +//! +//! let text = b"Some Crypto Text"; +//! +//! // Create the signature. +//! let mut ctx = PkeyCtx::new(&key).unwrap(); +//! ctx.sign_init().unwrap(); +//! let mut signature = vec![]; +//! ctx.sign_to_vec(text, &mut signature).unwrap(); +//! +//! // Verify the signature. +//! let mut ctx = PkeyCtx::new(&key).unwrap(); +//! ctx.verify_init().unwrap(); +//! 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; +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; +use std::ptr; + +/// HKDF modes of operation. +#[cfg(ossl111)] +pub struct HkdfMode(c_int); + +#[cfg(ossl111)] +impl HkdfMode { + /// This is the default mode. Calling [`derive`][PkeyCtxRef::derive] on a [`PkeyCtxRef`] set up + /// for HKDF will perform an extract followed by an expand operation in one go. The derived key + /// returned will be the result after the expand operation. The intermediate fixed-length + /// pseudorandom key K is not returned. + pub const EXTRACT_THEN_EXPAND: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND); + + /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the extract operation. + /// The value returned will be the intermediate fixed-length pseudorandom key K. + /// + /// The digest, key and salt values must be set before a key is derived or an error occurs. + pub const EXTRACT_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY); + + /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the expand operation. + /// The input key should be set to the intermediate fixed-length pseudorandom key K returned + /// from a previous extract operation. + /// + /// The digest, key and info values must be set before a key is derived or an error occurs. + pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY); +} + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::EVP_PKEY_CTX; + fn drop = ffi::EVP_PKEY_CTX_free; + + /// A context object which can perform asymmetric cryptography operations. + pub struct PkeyCtx; + /// A reference to a [`PkeyCtx`]. + pub struct PkeyCtxRef; +} + +impl PkeyCtx { + /// Creates a new pkey context using the provided key. + #[corresponds(EVP_PKEY_CTX_new)] + #[inline] + pub fn new(pkey: &PKeyRef) -> Result { + unsafe { + let ptr = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; + Ok(PkeyCtx::from_ptr(ptr)) + } + } +} + +impl PkeyCtx<()> { + /// Creates a new pkey context for the specified algorithm ID. + #[corresponds(EVP_PKEY_new_id)] + #[inline] + pub fn new_id(id: Id) -> Result { + unsafe { + let ptr = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?; + Ok(PkeyCtx::from_ptr(ptr)) + } + } +} + +impl PkeyCtxRef +where + T: HasPublic, +{ + /// Prepares the context for encryption using the public key. + #[corresponds(EVP_PKEY_encrypt_init)] + #[inline] + pub fn encrypt_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_encrypt_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Prepares the context for signature verification using the public key. + #[corresponds(EVP_PKEY_verify_init)] + #[inline] + pub fn verify_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_verify_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Encrypts data using the public key. + /// + /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be + /// returned. + #[corresponds(EVP_PKEY_encrypt)] + #[inline] + pub fn encrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { + let mut written = to.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_encrypt( + self.as_ptr(), + to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } + + /// Like [`Self::encrypt`] but appends ciphertext to a [`Vec`]. + pub fn encrypt_to_vec(&mut self, from: &[u8], out: &mut Vec) -> Result { + let base = out.len(); + let len = self.encrypt(from, None)?; + out.resize(base + len, 0); + let len = self.encrypt(from, Some(&mut out[base..]))?; + out.truncate(base + len); + Ok(len) + } + + /// Verifies the signature of data using the public key. + /// + /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error + /// occurred. + /// + /// # Note + /// + /// This verifies the signature of the *raw* data. It is more common to compute and verify the signature of the + /// cryptographic hash of an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do + /// that. + #[corresponds(EVP_PKEY_verify)] + #[inline] + pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result { + unsafe { + let r = cvt_n(ffi::EVP_PKEY_verify( + self.as_ptr(), + sig.as_ptr(), + sig.len(), + data.as_ptr(), + data.len(), + ))?; + Ok(r == 1) + } + } +} + +impl PkeyCtxRef +where + T: HasPrivate, +{ + /// Prepares the context for decryption using the private key. + #[corresponds(EVP_PKEY_decrypt_init)] + #[inline] + pub fn decrypt_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_decrypt_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Prepares the context for signing using the private key. + #[corresponds(EVP_PKEY_sign_init)] + #[inline] + pub fn sign_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_sign_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Sets the peer key used for secret derivation. + #[corresponds(EVP_PKEY_derive_set_peer)] + pub fn derive_set_peer(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + U: HasPublic, + { + unsafe { + cvt(ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), key.as_ptr()))?; + } + + Ok(()) + } + + /// Decrypts data using the private key. + /// + /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be + /// returned. + #[corresponds(EVP_PKEY_decrypt)] + #[inline] + pub fn decrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { + let mut written = to.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_decrypt( + self.as_ptr(), + to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } + + /// Like [`Self::decrypt`] but appends plaintext to a [`Vec`]. + pub fn decrypt_to_vec(&mut self, from: &[u8], out: &mut Vec) -> Result { + let base = out.len(); + let len = self.decrypt(from, None)?; + out.resize(base + len, 0); + let len = self.decrypt(from, Some(&mut out[base..]))?; + out.truncate(base + len); + Ok(len) + } + + /// Signs the contents of `data`. + /// + /// If `sig` is set to `None`, an upper bound on the number of bytes required for the output buffer will be + /// returned. + /// + /// # Note + /// + /// This computes the signature of the *raw* bytes of `data`. It is more common to sign the cryptographic hash of + /// an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do that. + #[corresponds(EVP_PKEY_sign)] + #[inline] + pub fn sign(&mut self, data: &[u8], sig: Option<&mut [u8]>) -> Result { + let mut written = sig.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_sign( + self.as_ptr(), + sig.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut written, + data.as_ptr(), + data.len(), + ))?; + } + + Ok(written) + } + + /// Like [`Self::sign`] but appends the signature to a [`Vec`]. + pub fn sign_to_vec(&mut self, data: &[u8], sig: &mut Vec) -> Result { + let base = sig.len(); + let len = self.sign(data, None)?; + sig.resize(base + len, 0); + let len = self.sign(data, Some(&mut sig[base..]))?; + sig.truncate(base + len); + Ok(len) + } +} + +impl PkeyCtxRef { + /// Prepares the context for shared secret derivation. + #[corresponds(EVP_PKEY_derive_init)] + #[inline] + pub fn derive_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Prepares the context for key generation. + #[corresponds(EVP_PKEY_keygen_init)] + #[inline] + pub fn keygen_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_keygen_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Returns the RSA padding mode in use. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_get_rsa_padding)] + #[inline] + pub fn rsa_padding(&self) -> Result { + let mut pad = 0; + unsafe { + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))?; + } + + Ok(Padding::from_raw(pad)) + } + + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_set_rsa_padding)] + #[inline] + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.as_ptr(), + padding.as_raw(), + ))?; + } + + Ok(()) + } + + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)] + #[inline] + pub fn set_rsa_mgf1_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.as_ptr(), + md.as_ptr(), + ))?; + } + + Ok(()) + } + + /// Sets the RSA OAEP algorithm. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_set_rsa_oaep_md)] + #[cfg(any(ossl102, libressl310))] + #[inline] + pub fn set_rsa_oaep_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( + self.as_ptr(), + md.as_ptr() as *mut _, + ))?; + } + + Ok(()) + } + + /// Sets the RSA OAEP label. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_set0_rsa_oaep_label)] + #[cfg(any(ossl102, libressl310, boringssl))] + pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { + 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 as *mut _, + len, + )); + if r.is_err() { + ffi::OPENSSL_free(p); + } + r?; + } + + Ok(()) + } + + /// Sets the cipher used during key generation. + #[cfg(not(boringssl))] + #[corresponds(EVP_PKEY_CTX_ctrl)] + #[inline] + pub fn set_keygen_cipher(&mut self, cipher: &CipherRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_ctrl( + self.as_ptr(), + -1, + ffi::EVP_PKEY_OP_KEYGEN, + ffi::EVP_PKEY_CTRL_CIPHER, + 0, + cipher.as_ptr() as *mut _, + ))?; + } + + Ok(()) + } + + /// Sets the key MAC key used during key generation. + #[cfg(not(boringssl))] + #[corresponds(EVP_PKEY_CTX_ctrl)] + #[inline] + pub fn set_keygen_mac_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { + let len = c_int::try_from(key.len()).unwrap(); + + unsafe { + cvt(ffi::EVP_PKEY_CTX_ctrl( + self.as_ptr(), + -1, + ffi::EVP_PKEY_OP_KEYGEN, + ffi::EVP_PKEY_CTRL_SET_MAC_KEY, + len, + key.as_ptr() as *mut _, + ))?; + } + + Ok(()) + } + + /// Sets the digest used for HKDF derivation. + /// + /// Requires OpenSSL 1.1.0 or newer. + #[corresponds(EVP_PKEY_CTX_set_hkdf_md)] + #[cfg(ossl110)] + #[inline] + pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_hkdf_md( + self.as_ptr(), + digest.as_ptr(), + ))?; + } + + Ok(()) + } + + /// Sets the HKDF mode of operation. + /// + /// Defaults to [`HkdfMode::EXTRACT_THEN_EXPAND`]. + /// + /// WARNING: Although this API calls it a "mode", HKDF-Extract and HKDF-Expand are distinct + /// operations with distinct inputs and distinct kinds of keys. Callers should not pass input + /// secrets for one operation into the other. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(EVP_PKEY_CTX_set_hkdf_mode)] + #[cfg(ossl111)] + #[inline] + pub fn set_hkdf_mode(&mut self, mode: HkdfMode) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_hkdf_mode(self.as_ptr(), mode.0))?; + } + + Ok(()) + } + + /// Sets the input material for HKDF generation as the "key". + /// + /// Which input is the key depends on the "mode" (see [`set_hkdf_mode`][Self::set_hkdf_mode]). + /// If [`HkdfMode::EXTRACT_THEN_EXPAND`] or [`HkdfMode::EXTRACT_ONLY`], this function specifies + /// the input keying material (IKM) for HKDF-Extract. If [`HkdfMode::EXPAND_ONLY`], it instead + /// specifies the pseudorandom key (PRK) for HKDF-Expand. + /// + /// Requires OpenSSL 1.1.0 or newer. + #[corresponds(EVP_PKEY_CTX_set1_hkdf_key)] + #[cfg(ossl110)] + #[inline] + pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { + let len = c_int::try_from(key.len()).unwrap(); + + unsafe { + cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key( + self.as_ptr(), + key.as_ptr(), + len, + ))?; + } + + Ok(()) + } + + /// Sets the salt value for HKDF generation. + /// + /// If performing HKDF-Expand only, this parameter is ignored. + /// + /// Requires OpenSSL 1.1.0 or newer. + #[corresponds(EVP_PKEY_CTX_set1_hkdf_salt)] + #[cfg(ossl110)] + #[inline] + pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> { + let len = c_int::try_from(salt.len()).unwrap(); + + unsafe { + cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt( + self.as_ptr(), + salt.as_ptr(), + len, + ))?; + } + + Ok(()) + } + + /// Appends info bytes for HKDF generation. + /// + /// If performing HKDF-Extract only, this parameter is ignored. + /// + /// Requires OpenSSL 1.1.0 or newer. + #[corresponds(EVP_PKEY_CTX_add1_hkdf_info)] + #[cfg(ossl110)] + #[inline] + pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> { + let len = c_int::try_from(info.len()).unwrap(); + + unsafe { + cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info( + self.as_ptr(), + info.as_ptr(), + len, + ))?; + } + + Ok(()) + } + + /// Derives a shared secret between two keys. + /// + /// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned. + #[corresponds(EVP_PKEY_derive)] + pub fn derive(&mut self, buf: Option<&mut [u8]>) -> Result { + let mut len = buf.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_derive( + self.as_ptr(), + buf.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut len, + ))?; + } + + Ok(len) + } + + /// Like [`Self::derive`] but appends the secret to a [`Vec`]. + pub fn derive_to_vec(&mut self, buf: &mut Vec) -> Result { + let base = buf.len(); + let len = self.derive(None)?; + buf.resize(base + len, 0); + let len = self.derive(Some(&mut buf[base..]))?; + buf.truncate(base + len); + Ok(len) + } + + /// Generates a new public/private keypair. + #[corresponds(EVP_PKEY_keygen)] + #[inline] + pub fn keygen(&mut self) -> Result, ErrorStack> { + unsafe { + let mut key = ptr::null_mut(); + cvt(ffi::EVP_PKEY_keygen(self.as_ptr(), &mut key))?; + Ok(PKey::from_ptr(key)) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + #[cfg(not(boringssl))] + use crate::cipher::Cipher; + use crate::ec::{EcGroup, EcKey}; + #[cfg(any(ossl102, libressl310))] + use crate::md::Md; + use crate::nid::Nid; + use crate::pkey::PKey; + use crate::rsa::Rsa; + + #[test] + fn rsa() { + let key = include_bytes!("../test/rsa.pem"); + let rsa = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let mut ctx = PkeyCtx::new(&pkey).unwrap(); + ctx.encrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + + let pt = "hello world".as_bytes(); + let mut ct = vec![]; + ctx.encrypt_to_vec(pt, &mut ct).unwrap(); + + ctx.decrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + + let mut out = vec![]; + ctx.decrypt_to_vec(&ct, &mut out).unwrap(); + + assert_eq!(pt, out); + } + + #[test] + #[cfg(any(ossl102, libressl310))] + fn rsa_oaep() { + let key = include_bytes!("../test/rsa.pem"); + let rsa = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let mut ctx = PkeyCtx::new(&pkey).unwrap(); + ctx.encrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); + ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); + + let pt = "hello world".as_bytes(); + let mut ct = vec![]; + ctx.encrypt_to_vec(pt, &mut ct).unwrap(); + + ctx.decrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); + ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); + + let mut out = vec![]; + ctx.decrypt_to_vec(&ct, &mut out).unwrap(); + + assert_eq!(pt, out); + } + + #[test] + fn derive() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key1 = EcKey::generate(&group).unwrap(); + let key1 = PKey::from_ec_key(key1).unwrap(); + let key2 = EcKey::generate(&group).unwrap(); + let key2 = PKey::from_ec_key(key2).unwrap(); + + let mut ctx = PkeyCtx::new(&key1).unwrap(); + ctx.derive_init().unwrap(); + ctx.derive_set_peer(&key2).unwrap(); + + let mut buf = vec![]; + ctx.derive_to_vec(&mut buf).unwrap(); + } + + #[test] + #[cfg(not(boringssl))] + fn cmac_keygen() { + 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(&hex::decode("9294727a3638bb1c13f48ef8158bfc9d").unwrap()) + .unwrap(); + ctx.keygen().unwrap(); + } + + #[test] + #[cfg(ossl110)] + fn hkdf() { + let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); + ctx.derive_init().unwrap(); + ctx.set_hkdf_md(Md::sha256()).unwrap(); + ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap()) + .unwrap(); + ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap()) + .unwrap(); + ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap()) + .unwrap(); + let mut out = [0; 42]; + ctx.derive(Some(&mut out)).unwrap(); + + assert_eq!( + &out[..], + hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") + .unwrap() + ); + } + + #[test] + #[cfg(ossl111)] + fn hkdf_expand() { + let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); + ctx.derive_init().unwrap(); + ctx.set_hkdf_mode(HkdfMode::EXPAND_ONLY).unwrap(); + ctx.set_hkdf_md(Md::sha256()).unwrap(); + ctx.set_hkdf_key( + &hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") + .unwrap(), + ) + .unwrap(); + ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap()) + .unwrap(); + let mut out = [0; 42]; + ctx.derive(Some(&mut out)).unwrap(); + + assert_eq!( + &out[..], + hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") + .unwrap() + ); + } + + #[test] + #[cfg(ossl111)] + fn hkdf_extract() { + let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); + ctx.derive_init().unwrap(); + ctx.set_hkdf_mode(HkdfMode::EXTRACT_ONLY).unwrap(); + ctx.set_hkdf_md(Md::sha256()).unwrap(); + ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap()) + .unwrap(); + ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap()) + .unwrap(); + let mut out = vec![]; + ctx.derive_to_vec(&mut out).unwrap(); + + assert_eq!( + &out[..], + hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") + .unwrap() + ); + } + + #[test] + fn verify_fail() { + let key1 = Rsa::generate(4096).unwrap(); + let key1 = PKey::from_rsa(key1).unwrap(); + + let data = b"Some Crypto Text"; + + let mut ctx = PkeyCtx::new(&key1).unwrap(); + ctx.sign_init().unwrap(); + let mut signature = vec![]; + ctx.sign_to_vec(data, &mut signature).unwrap(); + + let bad_data = b"Some Crypto text"; + + ctx.verify_init().unwrap(); + let valid = ctx.verify(bad_data, &signature).unwrap(); + assert!(!valid); + } +} diff --git a/openssl/src/provider.rs b/openssl/src/provider.rs new file mode 100644 index 0000000..147fadf --- /dev/null +++ b/openssl/src/provider.rs @@ -0,0 +1,77 @@ +use crate::error::ErrorStack; +use crate::lib_ctx::LibCtxRef; +use crate::{cvt, cvt_p}; +use foreign_types::{ForeignType, ForeignTypeRef}; +use openssl_macros::corresponds; +use std::ffi::CString; +use std::ptr; + +foreign_type_and_impl_send_sync! { + type CType = ffi::OSSL_PROVIDER; + fn drop = ossl_provider_free; + + pub struct Provider; + /// A reference to a [`Provider`]. + pub struct ProviderRef; +} + +#[inline] +unsafe fn ossl_provider_free(p: *mut ffi::OSSL_PROVIDER) { + ffi::OSSL_PROVIDER_unload(p); +} + +impl Provider { + /// Loads a new provider into the specified library context, disabling the fallback providers. + /// + /// If `ctx` is `None`, the provider will be loaded in to the default library context. + #[corresponds(OSSL_provider_load)] + pub fn load(ctx: Option<&LibCtxRef>, name: &str) -> Result { + let name = CString::new(name).unwrap(); + unsafe { + let p = cvt_p(ffi::OSSL_PROVIDER_load( + ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + name.as_ptr(), + ))?; + + Ok(Provider::from_ptr(p)) + } + } + + /// Loads a new provider into the specified library context, disabling the fallback providers if `retain_fallbacks` + /// is `false` and the load succeeds. + /// + /// If `ctx` is `None`, the provider will be loaded into the default library context. + #[corresponds(OSSL_provider_try_load)] + pub fn try_load( + ctx: Option<&LibCtxRef>, + name: &str, + retain_fallbacks: bool, + ) -> Result { + let name = CString::new(name).unwrap(); + unsafe { + let p = cvt_p(ffi::OSSL_PROVIDER_try_load( + ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + name.as_ptr(), + retain_fallbacks as _, + ))?; + + Ok(Provider::from_ptr(p)) + } + } + + /// Specifies the default search path that is to be used for looking for providers in the specified library context. + /// If left unspecified, an environment variable and a fall back default value will be used instead + /// + /// If `ctx` is `None`, the provider will be loaded into the default library context. + #[corresponds(OSSL_PROVIDER_set_default_search_path)] + pub fn set_default_search_path(ctx: Option<&LibCtxRef>, path: &str) -> Result<(), ErrorStack> { + let path = CString::new(path).unwrap(); + unsafe { + cvt(ffi::OSSL_PROVIDER_set_default_search_path( + ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + path.as_ptr(), + )) + .map(|_| ()) + } + } +} diff --git a/openssl/src/rand.rs b/openssl/src/rand.rs index da52ef5..8317951 100644 --- a/openssl/src/rand.rs +++ b/openssl/src/rand.rs @@ -11,16 +11,16 @@ //! rand_bytes(&mut buf).unwrap(); //! ``` use libc::c_int; -use ffi; -use cvt; -use error::ErrorStack; +use crate::error::ErrorStack; +use crate::{cvt, LenType}; +use openssl_macros::corresponds; /// Fill buffer with cryptographically strong pseudo-random bytes. /// /// # Examples /// -/// To generate a buffer with cryptographically strong bytes: +/// To generate a buffer with cryptographically strong random bytes: /// /// ``` /// use openssl::rand::rand_bytes; @@ -28,15 +28,23 @@ use error::ErrorStack; /// let mut buf = [0; 256]; /// rand_bytes(&mut buf).unwrap(); /// ``` -/// -/// # External OpenSSL Documentation -/// -/// [RAND_bytes](https://www.openssl.org/docs/man1.1.0/crypto/RAND_bytes.html) +#[corresponds(RAND_bytes)] pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> { unsafe { ffi::init(); assert!(buf.len() <= c_int::max_value() as usize); - cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int)).map(|_| ()) + cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as LenType)).map(|_| ()) + } +} + +/// Controls random device file descriptor behavior. +/// +/// Requires OpenSSL 1.1.1 or newer. +#[corresponds(RAND_keep_random_devices_open)] +#[cfg(ossl111)] +pub fn keep_random_devices_open(keep: bool) { + unsafe { + ffi::RAND_keep_random_devices_open(keep as LenType); } } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index b02b921..68cf64b 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -1,64 +1,120 @@ -use ffi; +//! Rivest–Shamir–Adleman cryptosystem +//! +//! RSA is one of the earliest asymmetric public key encryption schemes. +//! Like many other cryptosystems, RSA relies on the presumed difficulty of a hard +//! mathematical problem, namely factorization of the product of two large prime +//! numbers. At the moment there does not exist an algorithm that can factor such +//! large numbers in reasonable time. RSA is used in a wide variety of +//! applications including digital signatures and key exchanges such as +//! establishing a TLS/SSL connection. +//! +//! The RSA acronym is derived from the first letters of the surnames of the +//! algorithm's founding trio. +//! +//! # Example +//! +//! Generate a 2048-bit RSA key pair and use the public key to encrypt some data. +//! +//! ```rust +//! use openssl::rsa::{Rsa, Padding}; +//! +//! let rsa = Rsa::generate(2048).unwrap(); +//! let data = b"foobar"; +//! let mut buf = vec![0; rsa.size() as usize]; +//! let encrypted_len = rsa.public_encrypt(data, &mut buf, Padding::PKCS1).unwrap(); +//! ``` +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; use std::fmt; -use std::ptr; use std::mem; -use libc::{c_int, c_void, c_char}; -use foreign_types::ForeignTypeRef; +use std::ptr; -use {cvt, cvt_p, cvt_n}; -use bn::{BigNum, BigNumRef}; -use bio::MemBioSlice; -use error::ErrorStack; -use util::{CallbackState, invoke_passwd_cb_old}; +use crate::bn::{BigNum, BigNumRef}; +use crate::error::ErrorStack; +use crate::pkey::{HasPrivate, HasPublic, Private, Public}; +use crate::util::ForeignTypeRefExt; +use crate::{cvt, cvt_n, cvt_p, LenType}; +use openssl_macros::corresponds; /// Type of encryption padding to use. +/// +/// Random length padding is primarily used to prevent attackers from +/// predicting or knowing the exact length of a plaintext message that +/// can possibly lead to breaking encryption. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Padding(c_int); impl Padding { + pub const NONE: Padding = Padding(ffi::RSA_NO_PADDING); + pub const PKCS1: Padding = Padding(ffi::RSA_PKCS1_PADDING); + pub const PKCS1_OAEP: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING); + pub const PKCS1_PSS: Padding = Padding(ffi::RSA_PKCS1_PSS_PADDING); + + /// Creates a `Padding` from an integer representation. pub fn from_raw(value: c_int) -> Padding { Padding(value) } + /// Returns the integer representation of `Padding`. + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } -pub const NO_PADDING: Padding = Padding(ffi::RSA_NO_PADDING); -pub const PKCS1_PADDING: Padding = Padding(ffi::RSA_PKCS1_PADDING); -pub const PKCS1_OAEP_PADDING: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING); - -foreign_type_and_impl_send_sync! { +generic_foreign_type_and_impl_send_sync! { type CType = ffi::RSA; fn drop = ffi::RSA_free; - pub struct Rsa; - pub struct RsaRef; -} + /// An RSA key. + pub struct Rsa; -impl RsaRef { - // FIXME these need to specify output format - private_key_to_pem!(ffi::PEM_write_bio_RSAPrivateKey); - public_key_to_pem!(ffi::PEM_write_bio_RSA_PUBKEY); + /// Reference to `RSA` + pub struct RsaRef; +} - private_key_to_der!(ffi::i2d_RSAPrivateKey); - public_key_to_der!(ffi::i2d_RSA_PUBKEY); +impl Clone for Rsa { + fn clone(&self) -> Rsa { + (**self).to_owned() + } +} - to_der_inner!( - /// Serializes the public key to DER-encoded PKCS#1. - public_key_to_der_pkcs1, - ffi::i2d_RSAPublicKey - ); +impl ToOwned for RsaRef { + type Owned = Rsa; - // FIXME should return u32 - pub fn size(&self) -> usize { + fn to_owned(&self) -> Rsa { unsafe { - assert!(self.n().is_some()); - - ffi::RSA_size(self.as_ptr()) as usize + ffi::RSA_up_ref(self.as_ptr()); + Rsa::from_ptr(self.as_ptr()) } } +} + +impl RsaRef +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded PKCS#1 RSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_RSAPrivateKey)] + private_key_to_pem, + /// Serializes the private key to a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. + #[corresponds(PEM_write_bio_RSAPrivateKey)] + private_key_to_pem_passphrase, + ffi::PEM_write_bio_RSAPrivateKey + } + + to_der! { + /// Serializes the private key to a DER-encoded PKCS#1 RSAPrivateKey structure. + #[corresponds(i2d_RSAPrivateKey)] + private_key_to_der, + ffi::i2d_RSAPrivateKey + } /// Decrypts data using the private key, returning the number of decrypted bytes. /// @@ -66,19 +122,19 @@ impl RsaRef { /// /// Panics if `self` has no private components, or if `to` is smaller /// than `self.size()`. + #[corresponds(RSA_private_decrypt)] pub fn private_decrypt( &self, from: &[u8], to: &mut [u8], padding: Padding, ) -> Result { - assert!(self.d().is_some(), "private components missing"); assert!(from.len() <= i32::max_value() as usize); - assert!(to.len() >= self.size()); + assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_private_decrypt( - from.len() as c_int, + from.len() as LenType, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), @@ -94,19 +150,19 @@ impl RsaRef { /// /// Panics if `self` has no private components, or if `to` is smaller /// than `self.size()`. + #[corresponds(RSA_private_encrypt)] pub fn private_encrypt( &self, from: &[u8], to: &mut [u8], padding: Padding, ) -> Result { - assert!(self.d().is_some(), "private components missing"); assert!(from.len() <= i32::max_value() as usize); - assert!(to.len() >= self.size()); + assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_private_encrypt( - from.len() as c_int, + from.len() as LenType, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), @@ -116,11 +172,129 @@ impl RsaRef { } } + /// Returns a reference to the private exponent of the key. + #[corresponds(RSA_get0_key)] + pub fn d(&self) -> &BigNumRef { + unsafe { + let mut d = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut d); + BigNumRef::from_const_ptr(d) + } + } + + /// Returns a reference to the first factor of the exponent of the key. + #[corresponds(RSA_get0_factors)] + pub fn p(&self) -> Option<&BigNumRef> { + unsafe { + let mut p = ptr::null(); + RSA_get0_factors(self.as_ptr(), &mut p, ptr::null_mut()); + BigNumRef::from_const_ptr_opt(p) + } + } + + /// Returns a reference to the second factor of the exponent of the key. + #[corresponds(RSA_get0_factors)] + pub fn q(&self) -> Option<&BigNumRef> { + unsafe { + let mut q = ptr::null(); + RSA_get0_factors(self.as_ptr(), ptr::null_mut(), &mut q); + BigNumRef::from_const_ptr_opt(q) + } + } + + /// Returns a reference to the first exponent used for CRT calculations. + #[corresponds(RSA_get0_crt_params)] + pub fn dmp1(&self) -> Option<&BigNumRef> { + unsafe { + let mut dp = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), &mut dp, ptr::null_mut(), ptr::null_mut()); + BigNumRef::from_const_ptr_opt(dp) + } + } + + /// Returns a reference to the second exponent used for CRT calculations. + #[corresponds(RSA_get0_crt_params)] + pub fn dmq1(&self) -> Option<&BigNumRef> { + unsafe { + let mut dq = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), &mut dq, ptr::null_mut()); + BigNumRef::from_const_ptr_opt(dq) + } + } + + /// Returns a reference to the coefficient used for CRT calculations. + #[corresponds(RSA_get0_crt_params)] + pub fn iqmp(&self) -> Option<&BigNumRef> { + unsafe { + let mut qi = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut qi); + BigNumRef::from_const_ptr_opt(qi) + } + } + + /// Validates RSA parameters for correctness + #[corresponds(RSA_check_key)] + #[allow(clippy::unnecessary_cast)] + pub fn check_key(&self) -> Result { + unsafe { + let result = ffi::RSA_check_key(self.as_ptr()) as i32; + if result == -1 { + Err(ErrorStack::get()) + } else { + Ok(result == 1) + } + } + } +} + +impl RsaRef +where + T: HasPublic, +{ + to_pem! { + /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_write_bio_RSA_PUBKEY)] + public_key_to_pem, + ffi::PEM_write_bio_RSA_PUBKEY + } + + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + #[corresponds(i2d_RSA_PUBKEY)] + public_key_to_der, + ffi::i2d_RSA_PUBKEY + } + + to_pem! { + /// Serializes the public key into a PEM-encoded PKCS#1 RSAPublicKey structure. + /// + /// The output will have a header of `-----BEGIN RSA PUBLIC KEY-----`. + #[corresponds(PEM_write_bio_RSAPublicKey)] + public_key_to_pem_pkcs1, + ffi::PEM_write_bio_RSAPublicKey + } + + to_der! { + /// Serializes the public key into a DER-encoded PKCS#1 RSAPublicKey structure. + #[corresponds(i2d_RSAPublicKey)] + public_key_to_der_pkcs1, + ffi::i2d_RSAPublicKey + } + + /// Returns the size of the modulus in bytes. + #[corresponds(RSA_size)] + pub fn size(&self) -> u32 { + unsafe { ffi::RSA_size(self.as_ptr()) as u32 } + } + /// Decrypts data using the public key, returning the number of decrypted bytes. /// /// # Panics /// /// Panics if `to` is smaller than `self.size()`. + #[corresponds(RSA_public_decrypt)] pub fn public_decrypt( &self, from: &[u8], @@ -128,11 +302,11 @@ impl RsaRef { padding: Padding, ) -> Result { assert!(from.len() <= i32::max_value() as usize); - assert!(to.len() >= self.size()); + assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_public_decrypt( - from.len() as c_int, + from.len() as LenType, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), @@ -147,6 +321,7 @@ impl RsaRef { /// # Panics /// /// Panics if `to` is smaller than `self.size()`. + #[corresponds(RSA_public_encrypt)] pub fn public_encrypt( &self, from: &[u8], @@ -154,11 +329,11 @@ impl RsaRef { padding: Padding, ) -> Result { assert!(from.len() <= i32::max_value() as usize); - assert!(to.len() >= self.size()); + assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_public_encrypt( - from.len() as c_int, + from.len() as LenType, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), @@ -168,149 +343,199 @@ impl RsaRef { } } - pub fn n(&self) -> Option<&BigNumRef> { + /// Returns a reference to the modulus of the key. + #[corresponds(RSA_get0_key)] + pub fn n(&self) -> &BigNumRef { unsafe { - let n = compat::key(self.as_ptr())[0]; - if n.is_null() { - None - } else { - Some(BigNumRef::from_ptr(n as *mut _)) - } + let mut n = ptr::null(); + RSA_get0_key(self.as_ptr(), &mut n, ptr::null_mut(), ptr::null_mut()); + BigNumRef::from_const_ptr(n) } } - pub fn d(&self) -> Option<&BigNumRef> { + /// Returns a reference to the public exponent of the key. + #[corresponds(RSA_get0_key)] + pub fn e(&self) -> &BigNumRef { unsafe { - let d = compat::key(self.as_ptr())[2]; - if d.is_null() { - None - } else { - Some(BigNumRef::from_ptr(d as *mut _)) - } + let mut e = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut e, ptr::null_mut()); + BigNumRef::from_const_ptr(e) } } +} - pub fn e(&self) -> Option<&BigNumRef> { +impl Rsa { + /// Creates a new RSA key with only public components. + /// + /// `n` is the modulus common to both public and private key. + /// `e` is the public exponent. + /// + /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. + /// + /// [`RSA_new`]: https://www.openssl.org/docs/manmaster/crypto/RSA_new.html + /// [`RSA_set0_key`]: https://www.openssl.org/docs/manmaster/crypto/RSA_set0_key.html + pub fn from_public_components(n: BigNum, e: BigNum) -> Result, ErrorStack> { unsafe { - let e = compat::key(self.as_ptr())[1]; - if e.is_null() { - None - } else { - Some(BigNumRef::from_ptr(e as *mut _)) - } + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), ptr::null_mut()); + mem::forget((n, e)); + Ok(Rsa::from_ptr(rsa)) } } - pub fn p(&self) -> Option<&BigNumRef> { - unsafe { - let p = compat::factors(self.as_ptr())[0]; - if p.is_null() { - None - } else { - Some(BigNumRef::from_ptr(p as *mut _)) - } - } + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing an RSA key. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + #[corresponds(PEM_read_bio_RSA_PUBKEY)] + public_key_from_pem, + Rsa, + ffi::PEM_read_bio_RSA_PUBKEY } - pub fn q(&self) -> Option<&BigNumRef> { - unsafe { - let q = compat::factors(self.as_ptr())[1]; - if q.is_null() { - None - } else { - Some(BigNumRef::from_ptr(q as *mut _)) - } - } + from_pem! { + /// Decodes a PEM-encoded PKCS#1 RSAPublicKey structure. + /// + /// The input should have a header of `-----BEGIN RSA PUBLIC KEY-----`. + #[corresponds(PEM_read_bio_RSAPublicKey)] + public_key_from_pem_pkcs1, + Rsa, + ffi::PEM_read_bio_RSAPublicKey } - pub fn dp(&self) -> Option<&BigNumRef> { - unsafe { - let dp = compat::crt_params(self.as_ptr())[0]; - if dp.is_null() { - None - } else { - Some(BigNumRef::from_ptr(dp as *mut _)) - } - } + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing an RSA key. + #[corresponds(d2i_RSA_PUBKEY)] + public_key_from_der, + Rsa, + ffi::d2i_RSA_PUBKEY } - pub fn dq(&self) -> Option<&BigNumRef> { + from_der! { + /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure. + #[corresponds(d2i_RSAPublicKey)] + public_key_from_der_pkcs1, + Rsa, + ffi::d2i_RSAPublicKey + } +} + +pub struct RsaPrivateKeyBuilder { + rsa: Rsa, +} + +impl RsaPrivateKeyBuilder { + /// Creates a new `RsaPrivateKeyBuilder`. + /// + /// `n` is the modulus common to both public and private key. + /// `e` is the public exponent and `d` is the private exponent. + /// + /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. + /// + /// [`RSA_new`]: https://www.openssl.org/docs/manmaster/crypto/RSA_new.html + /// [`RSA_set0_key`]: https://www.openssl.org/docs/manmaster/crypto/RSA_set0_key.html + pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result { unsafe { - let dq = compat::crt_params(self.as_ptr())[1]; - if dq.is_null() { - None - } else { - Some(BigNumRef::from_ptr(dq as *mut _)) - } + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), d.as_ptr()); + mem::forget((n, e, d)); + Ok(RsaPrivateKeyBuilder { + rsa: Rsa::from_ptr(rsa), + }) } } - pub fn qi(&self) -> Option<&BigNumRef> { + /// Sets the factors of the Rsa key. + /// + /// `p` and `q` are the first and second factors of `n`. + #[corresponds(RSA_set0_factors)] + // FIXME should be infallible + pub fn set_factors(self, p: BigNum, q: BigNum) -> Result { unsafe { - let qi = compat::crt_params(self.as_ptr())[2]; - if qi.is_null() { - None - } else { - Some(BigNumRef::from_ptr(qi as *mut _)) - } + RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr()); + mem::forget((p, q)); } + Ok(self) } -} -impl Rsa { - /// only useful for associating the key material directly with the key, it's safer to use - /// the supplied load and save methods for DER formatted keys. - pub fn from_public_components(n: BigNum, e: BigNum) -> Result { + /// Sets the Chinese Remainder Theorem params of the Rsa key. + /// + /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for + /// CRT calculations which is used to speed up RSA operations. + #[corresponds(RSA_set0_crt_params)] + // FIXME should be infallible + pub fn set_crt_params( + self, + dmp1: BigNum, + dmq1: BigNum, + iqmp: BigNum, + ) -> Result { unsafe { - let rsa = Rsa(cvt_p(ffi::RSA_new())?); - cvt(compat::set_key( - rsa.0, - n.as_ptr(), - e.as_ptr(), - ptr::null_mut(), - ))?; - mem::forget((n, e)); - Ok(rsa) + RSA_set0_crt_params( + self.rsa.as_ptr(), + dmp1.as_ptr(), + dmq1.as_ptr(), + iqmp.as_ptr(), + ); + mem::forget((dmp1, dmq1, iqmp)); } + Ok(self) + } + + /// Returns the Rsa key. + pub fn build(self) -> Rsa { + self.rsa } +} +impl Rsa { + /// Creates a new RSA key with private components (public components are assumed). + /// + /// This a convenience method over: + /// ``` + /// # use openssl::rsa::RsaPrivateKeyBuilder; + /// # fn main() -> Result<(), Box> { + /// # 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, e: BigNum, d: BigNum, p: BigNum, q: BigNum, - dp: BigNum, - dq: BigNum, - qi: BigNum, - ) -> Result { - unsafe { - let rsa = Rsa(cvt_p(ffi::RSA_new())?); - cvt( - compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr()), - )?; - mem::forget((n, e, d)); - cvt(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr()))?; - mem::forget((p, q)); - cvt(compat::set_crt_params( - rsa.0, - dp.as_ptr(), - dq.as_ptr(), - qi.as_ptr(), - ))?; - mem::forget((dp, dq, qi)); - Ok(rsa) - } + dmp1: BigNum, + dmq1: BigNum, + iqmp: BigNum, + ) -> Result, ErrorStack> { + Ok(RsaPrivateKeyBuilder::new(n, e, d)? + .set_factors(p, q)? + .set_crt_params(dmp1, dmq1, iqmp)? + .build()) } /// Generates a public/private key pair with the specified size. /// /// The public exponent will be 65537. - pub fn generate(bits: u32) -> Result { - ffi::init(); + #[corresponds(RSA_generate_key_ex)] + pub fn generate(bits: u32) -> Result, ErrorStack> { + let e = BigNum::from_u32(ffi::RSA_F4 as u32)?; + Rsa::generate_with_e(bits, &e) + } + + /// Generates a public/private key pair with the specified size and a custom exponent. + /// + /// Unless you have specific needs and know what you're doing, use `Rsa::generate` instead. + #[corresponds(RSA_generate_key_ex)] + pub fn generate_with_e(bits: u32, e: &BigNumRef) -> Result, ErrorStack> { unsafe { - let rsa = Rsa(cvt_p(ffi::RSA_new())?); - let e = BigNum::from_u32(ffi::RSA_F4 as u32)?; + let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); cvt(ffi::RSA_generate_key_ex( rsa.0, bits as c_int, @@ -322,135 +547,138 @@ impl Rsa { } // FIXME these need to identify input formats - private_key_from_pem!(Rsa, ffi::PEM_read_bio_RSAPrivateKey); - private_key_from_der!(Rsa, ffi::d2i_RSAPrivateKey); - public_key_from_pem!(Rsa, ffi::PEM_read_bio_RSA_PUBKEY); - public_key_from_der!(Rsa, ffi::d2i_RSA_PUBKEY); - - from_der_inner!( - /// Deserializes a public key from DER-encoded PKCS#1 data. - public_key_from_der_pkcs1, - Rsa, - ffi::d2i_RSAPublicKey - ); - - #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] - pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result - where - F: FnOnce(&mut [c_char]) -> usize, - { - ffi::init(); - let mut cb = CallbackState::new(pass_cb); - let mem_bio = MemBioSlice::new(buf)?; - - unsafe { - let cb_ptr = &mut cb as *mut _ as *mut c_void; - let rsa = cvt_p(ffi::PEM_read_bio_RSAPrivateKey( - mem_bio.as_ptr(), - ptr::null_mut(), - Some(invoke_passwd_cb_old::), - cb_ptr, - ))?; - Ok(Rsa(rsa)) - } + private_key_from_pem! { + /// Deserializes a private key from a PEM-encoded PKCS#1 RSAPrivateKey structure. + #[corresponds(PEM_read_bio_RSAPrivateKey)] + private_key_from_pem, + + /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. + #[corresponds(PEM_read_bio_RSAPrivateKey)] + private_key_from_pem_passphrase, + + /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. + /// + /// The callback should fill the password into the provided buffer and return its length. + #[corresponds(PEM_read_bio_RSAPrivateKey)] + private_key_from_pem_callback, + Rsa, + ffi::PEM_read_bio_RSAPrivateKey + } + + from_der! { + /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure. + #[corresponds(d2i_RSAPrivateKey)] + private_key_from_der, + Rsa, + ffi::d2i_RSAPrivateKey } } -impl fmt::Debug for Rsa { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Rsa { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Rsa") } } -#[cfg(ossl110)] -mod compat { - use std::ptr; - - use ffi::{self, BIGNUM, RSA}; - use libc::c_int; - - pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] { - let (mut n, mut e, mut d) = (ptr::null(), ptr::null(), ptr::null()); - ffi::RSA_get0_key(r, &mut n, &mut e, &mut d); - [n, e, d] - } - - pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] { - let (mut p, mut q) = (ptr::null(), ptr::null()); - ffi::RSA_get0_factors(r, &mut p, &mut q); - [p, q] - } - - pub unsafe fn crt_params(r: *const RSA) -> [*const BIGNUM; 3] { - let (mut dp, mut dq, mut qi) = (ptr::null(), ptr::null(), ptr::null()); - ffi::RSA_get0_crt_params(r, &mut dp, &mut dq, &mut qi); - [dp, dq, qi] - } - - pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int { - ffi::RSA_set0_key(r, n, e, d) - } - - pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int { - ffi::RSA_set0_factors(r, p, q) - } - - pub unsafe fn set_crt_params( - r: *mut RSA, - dmp1: *mut BIGNUM, - dmq1: *mut BIGNUM, - iqmp: *mut BIGNUM, - ) -> c_int { - ffi::RSA_set0_crt_params(r, dmp1, dmq1, iqmp) - } -} - -#[cfg(ossl10x)] -mod compat { - use libc::c_int; - use ffi::{BIGNUM, RSA}; - - pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] { - [(*r).n, (*r).e, (*r).d] - } +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{ + RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors, + RSA_set0_crt_params, + }; + } else { + #[allow(bad_style)] + unsafe fn RSA_get0_key( + r: *const ffi::RSA, + n: *mut *const ffi::BIGNUM, + e: *mut *const ffi::BIGNUM, + d: *mut *const ffi::BIGNUM, + ) { + if !n.is_null() { + *n = (*r).n; + } + if !e.is_null() { + *e = (*r).e; + } + if !d.is_null() { + *d = (*r).d; + } + } - pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] { - [(*r).p, (*r).q] - } + #[allow(bad_style)] + unsafe fn RSA_get0_factors( + r: *const ffi::RSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + ) { + if !p.is_null() { + *p = (*r).p; + } + if !q.is_null() { + *q = (*r).q; + } + } - pub unsafe fn crt_params(r: *const RSA) -> [*const BIGNUM; 3] { - [(*r).dmp1, (*r).dmq1, (*r).iqmp] - } + #[allow(bad_style)] + unsafe fn RSA_get0_crt_params( + r: *const ffi::RSA, + dmp1: *mut *const ffi::BIGNUM, + dmq1: *mut *const ffi::BIGNUM, + iqmp: *mut *const ffi::BIGNUM, + ) { + if !dmp1.is_null() { + *dmp1 = (*r).dmp1; + } + if !dmq1.is_null() { + *dmq1 = (*r).dmq1; + } + if !iqmp.is_null() { + *iqmp = (*r).iqmp; + } + } - pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int { - (*r).n = n; - (*r).e = e; - (*r).d = d; - 1 // TODO: is this right? should it be 0? what's success? - } + #[allow(bad_style)] + unsafe fn RSA_set0_key( + r: *mut ffi::RSA, + n: *mut ffi::BIGNUM, + e: *mut ffi::BIGNUM, + d: *mut ffi::BIGNUM, + ) -> c_int { + (*r).n = n; + (*r).e = e; + (*r).d = d; + 1 + } - pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int { - (*r).p = p; - (*r).q = q; - 1 // TODO: is this right? should it be 0? what's success? - } + #[allow(bad_style)] + unsafe fn RSA_set0_factors( + r: *mut ffi::RSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + ) -> c_int { + (*r).p = p; + (*r).q = q; + 1 + } - pub unsafe fn set_crt_params( - r: *mut RSA, - dmp1: *mut BIGNUM, - dmq1: *mut BIGNUM, - iqmp: *mut BIGNUM, - ) -> c_int { - (*r).dmp1 = dmp1; - (*r).dmq1 = dmq1; - (*r).iqmp = iqmp; - 1 // TODO: is this right? should it be 0? what's success? + #[allow(bad_style)] + unsafe fn RSA_set0_crt_params( + r: *mut ffi::RSA, + dmp1: *mut ffi::BIGNUM, + dmq1: *mut ffi::BIGNUM, + iqmp: *mut ffi::BIGNUM, + ) -> c_int { + (*r).dmp1 = dmp1; + (*r).dmq1 = dmq1; + (*r).iqmp = iqmp; + 1 + } } } #[cfg(test)] mod test { - use symm::Cipher; + use crate::symm::Cipher; use super::*; @@ -468,7 +696,8 @@ mod test { password_queried = true; password[..6].copy_from_slice(b"mypass"); Ok(6) - }).unwrap(); + }) + .unwrap(); assert!(password_queried); } @@ -476,7 +705,8 @@ mod test { #[test] fn test_to_password() { let key = Rsa::generate(2048).unwrap(); - let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") + let pem = key + .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") .unwrap(); Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); @@ -487,18 +717,18 @@ mod test { let key = include_bytes!("../test/rsa.pem.pub"); let public_key = Rsa::public_key_from_pem(key).unwrap(); - let mut result = vec![0; public_key.size()]; + let mut result = vec![0; public_key.size() as usize]; let original_data = b"This is test"; let len = public_key - .public_encrypt(original_data, &mut result, PKCS1_PADDING) + .public_encrypt(original_data, &mut result, Padding::PKCS1) .unwrap(); assert_eq!(len, 256); let pkey = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(pkey).unwrap(); - let mut dec_result = vec![0; private_key.size()]; + let mut dec_result = vec![0; private_key.size() as usize]; let len = private_key - .private_decrypt(&result, &mut dec_result, PKCS1_PADDING) + .private_decrypt(&result, &mut dec_result, Padding::PKCS1) .unwrap(); assert_eq!(&dec_result[..len], original_data); @@ -512,10 +742,12 @@ mod test { let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; - let mut emesg = vec![0; k0.size()]; - k0.private_encrypt(&msg, &mut emesg, PKCS1_PADDING).unwrap(); - let mut dmesg = vec![0; k1.size()]; - let len = k1.public_decrypt(&emesg, &mut dmesg, PKCS1_PADDING) + let mut emesg = vec![0; k0.size() as usize]; + k0.private_encrypt(&msg, &mut emesg, Padding::PKCS1) + .unwrap(); + let mut dmesg = vec![0; k1.size() as usize]; + let len = k1 + .public_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } @@ -528,11 +760,93 @@ mod test { let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; - let mut emesg = vec![0; k0.size()]; - k0.public_encrypt(&msg, &mut emesg, PKCS1_PADDING).unwrap(); - let mut dmesg = vec![0; k1.size()]; - let len = k1.private_decrypt(&emesg, &mut dmesg, PKCS1_PADDING) + let mut emesg = vec![0; k0.size() as usize]; + k0.public_encrypt(&msg, &mut emesg, Padding::PKCS1).unwrap(); + let mut dmesg = vec![0; k1.size() as usize]; + let len = k1 + .private_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } + + #[test] + fn test_public_key_from_pem_pkcs1() { + let key = include_bytes!("../test/pkcs1.pem.pub"); + Rsa::public_key_from_pem_pkcs1(key).unwrap(); + } + + #[test] + #[should_panic] + fn test_public_key_from_pem_pkcs1_file_panic() { + let key = include_bytes!("../test/key.pem.pub"); + Rsa::public_key_from_pem_pkcs1(key).unwrap(); + } + + #[test] + fn test_public_key_to_pem_pkcs1() { + let keypair = super::Rsa::generate(512).unwrap(); + let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); + super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + } + + #[test] + #[should_panic] + fn test_public_key_from_pem_pkcs1_generate_panic() { + let keypair = super::Rsa::generate(512).unwrap(); + let pubkey_pem = keypair.public_key_to_pem().unwrap(); + super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + } + + #[test] + fn test_pem_pkcs1_encrypt() { + let keypair = super::Rsa::generate(2048).unwrap(); + let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); + let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + let msg = b"Hello, world!"; + + let mut encrypted = vec![0; pubkey.size() as usize]; + let len = pubkey + .public_encrypt(msg, &mut encrypted, Padding::PKCS1) + .unwrap(); + assert!(len > msg.len()); + let mut decrypted = vec![0; keypair.size() as usize]; + let len = keypair + .private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1) + .unwrap(); + assert_eq!(len, msg.len()); + assert_eq!(&decrypted[..len], msg); + } + + #[test] + fn test_pem_pkcs1_padding() { + let keypair = super::Rsa::generate(2048).unwrap(); + let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); + let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + let msg = b"foo"; + + let mut encrypted1 = vec![0; pubkey.size() as usize]; + let mut encrypted2 = vec![0; pubkey.size() as usize]; + let len1 = pubkey + .public_encrypt(msg, &mut encrypted1, Padding::PKCS1) + .unwrap(); + let len2 = pubkey + .public_encrypt(msg, &mut encrypted2, Padding::PKCS1) + .unwrap(); + assert!(len1 > (msg.len() + 1)); + assert_eq!(len1, len2); + assert_ne!(encrypted1, encrypted2); + } + + #[test] + #[allow(clippy::redundant_clone)] + fn clone() { + let key = Rsa::generate(2048).unwrap(); + drop(key.clone()); + } + + #[test] + fn generate_with_e() { + let e = BigNum::from_u32(0x10001).unwrap(); + Rsa::generate_with_e(2048, &e).unwrap(); + } } diff --git a/openssl/src/sha.rs b/openssl/src/sha.rs index 2af8f50..2412890 100644 --- a/openssl/src/sha.rs +++ b/openssl/src/sha.rs @@ -3,7 +3,7 @@ //! SHA, or Secure Hash Algorithms, are a family of cryptographic hashing algorithms published by //! the National Institute of Standards and Technology (NIST). Hash algorithms such as those in //! the SHA family are used to map data of an arbitrary size to a fixed-size string of bytes. -//! As cryptographic hashing algorithms, these mappings have the property of being irreversable. +//! As cryptographic hashing algorithms, these mappings have the property of being irreversible. //! This property makes hash algorithms like these excellent for uses such as verifying the //! contents of a file- if you know the hash you expect beforehand, then you can verify that the //! data you have is correct if it hashes to the same value. @@ -14,42 +14,31 @@ //! you can create a hasher that you can repeatedly update to add bytes to. //! //! ```rust -//! extern crate openssl; -//! extern crate hex; -//! //! use openssl::sha; -//! use hex::ToHex; -//! -//! fn main() { -//! let mut hasher = sha::Sha256::new(); -//! -//! hasher.update(b"Hello, "); -//! hasher.update(b"world"); -//! -//! let hash = hasher.finish(); -//! println!("Hashed \"Hello, world\" to {}", hash.to_hex()); -//! } +//! +//! let mut hasher = sha::Sha256::new(); +//! +//! hasher.update(b"Hello, "); +//! hasher.update(b"world"); +//! +//! let hash = hasher.finish(); +//! println!("Hashed \"Hello, world\" to {}", hex::encode(hash)); //! ``` //! -//! On the other hand, if you already have access to all of the data you woud like to hash, you +//! On the other hand, if you already have access to all of the data you would like to hash, you //! may prefer to use the slightly simpler method of simply calling the hash function corresponding //! to the algorithm you want to use. //! //! ```rust -//! extern crate openssl; -//! extern crate hex; -//! //! use openssl::sha::sha256; -//! use hex::ToHex; //! -//! fn main() { -//! let hash = sha256(b"your data or message"); -//! println!("Hash = {}", hash.to_hex()); -//! } +//! let hash = sha256(b"your data or message"); +//! println!("Hash = {}", hex::encode(hash)); //! ``` +use cfg_if::cfg_if; use libc::c_void; -use ffi; -use std::mem; +use openssl_macros::corresponds; +use std::mem::MaybeUninit; /// Computes the SHA1 hash of some data. /// @@ -57,239 +46,301 @@ use std::mem; /// /// SHA1 is known to be insecure - it should not be used unless required for /// compatibility with existing systems. +#[corresponds(SHA1)] #[inline] pub fn sha1(data: &[u8]) -> [u8; 20] { unsafe { - let mut hash: [u8; 20] = mem::uninitialized(); - ffi::SHA1(data.as_ptr(), data.len(), hash.as_mut_ptr()); - hash + let mut hash = MaybeUninit::<[u8; 20]>::uninit(); + ffi::SHA1(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); + hash.assume_init() } } /// Computes the SHA224 hash of some data. +#[corresponds(SHA224)] #[inline] pub fn sha224(data: &[u8]) -> [u8; 28] { unsafe { - let mut hash: [u8; 28] = mem::uninitialized(); - ffi::SHA224(data.as_ptr(), data.len(), hash.as_mut_ptr()); - hash + let mut hash = MaybeUninit::<[u8; 28]>::uninit(); + ffi::SHA224(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); + hash.assume_init() } } /// Computes the SHA256 hash of some data. +#[corresponds(SHA256)] #[inline] pub fn sha256(data: &[u8]) -> [u8; 32] { unsafe { - let mut hash: [u8; 32] = mem::uninitialized(); - ffi::SHA256(data.as_ptr(), data.len(), hash.as_mut_ptr()); - hash + let mut hash = MaybeUninit::<[u8; 32]>::uninit(); + ffi::SHA256(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); + hash.assume_init() } } /// Computes the SHA384 hash of some data. +#[corresponds(SHA384)] #[inline] pub fn sha384(data: &[u8]) -> [u8; 48] { unsafe { - let mut hash: [u8; 48] = mem::uninitialized(); - ffi::SHA384(data.as_ptr(), data.len(), hash.as_mut_ptr()); - hash + let mut hash = MaybeUninit::<[u8; 48]>::uninit(); + ffi::SHA384(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); + hash.assume_init() } } /// Computes the SHA512 hash of some data. +#[corresponds(SHA512)] #[inline] pub fn sha512(data: &[u8]) -> [u8; 64] { unsafe { - let mut hash: [u8; 64] = mem::uninitialized(); - ffi::SHA512(data.as_ptr(), data.len(), hash.as_mut_ptr()); - hash + let mut hash = MaybeUninit::<[u8; 64]>::uninit(); + ffi::SHA512(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); + hash.assume_init() } } -/// An object which calculates a SHA1 hash of some data. -/// -/// # Warning -/// -/// SHA1 is known to be insecure - it should not be used unless required for -/// compatibility with existing systems. -pub struct Sha1(ffi::SHA_CTX); - -impl Sha1 { - /// Creates a new hasher. - #[inline] - pub fn new() -> Sha1 { - unsafe { - let mut ctx = mem::uninitialized(); - ffi::SHA1_Init(&mut ctx); - Sha1(ctx) +cfg_if! { + if #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] { + /// An object which calculates a SHA1 hash of some data. + /// + /// # Warning + /// + /// SHA1 is known to be insecure - it should not be used unless required for + /// compatibility with existing systems. + #[derive(Clone)] + pub struct Sha1(ffi::SHA_CTX); + + impl Default for Sha1 { + #[inline] + fn default() -> Sha1 { + Sha1::new() + } } - } - /// Feeds some data into the hasher. - /// - /// This can be called multiple times. - #[inline] - pub fn update(&mut self, buf: &[u8]) { - unsafe { - ffi::SHA1_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + impl Sha1 { + /// Creates a new hasher. + #[corresponds(SHA1_Init)] + #[inline] + pub fn new() -> Sha1 { + unsafe { + let mut ctx = MaybeUninit::uninit(); + ffi::SHA1_Init( ctx.as_mut_ptr()); + Sha1(ctx.assume_init()) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[corresponds(SHA1_Update)] + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA1_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[corresponds(SHA1_Final)] + #[inline] + pub fn finish(mut self) -> [u8; 20] { + unsafe { + let mut hash = MaybeUninit::<[u8; 20]>::uninit(); + ffi::SHA1_Final(hash.as_mut_ptr() as *mut _, &mut self.0); + hash.assume_init() + } + } } - } - /// Returns the hash of the data. - #[inline] - pub fn finish(mut self) -> [u8; 20] { - unsafe { - let mut hash: [u8; 20] = mem::uninitialized(); - ffi::SHA1_Final(hash.as_mut_ptr(), &mut self.0); - hash - } - } -} + /// An object which calculates a SHA224 hash of some data. + #[derive(Clone)] + pub struct Sha224(ffi::SHA256_CTX); -/// An object which calculates a SHA224 hash of some data. -pub struct Sha224(ffi::SHA256_CTX); - -impl Sha224 { - /// Creates a new hasher. - #[inline] - pub fn new() -> Sha224 { - unsafe { - let mut ctx = mem::uninitialized(); - ffi::SHA224_Init(&mut ctx); - Sha224(ctx) + impl Default for Sha224 { + #[inline] + fn default() -> Sha224 { + Sha224::new() + } } - } - /// Feeds some data into the hasher. - /// - /// This can be called multiple times. - #[inline] - pub fn update(&mut self, buf: &[u8]) { - unsafe { - ffi::SHA224_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + impl Sha224 { + /// Creates a new hasher. + #[corresponds(SHA224_Init)] + #[inline] + pub fn new() -> Sha224 { + unsafe { + let mut ctx = MaybeUninit::uninit(); + ffi::SHA224_Init(ctx.as_mut_ptr()); + Sha224(ctx.assume_init()) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[corresponds(SHA224_Update)] + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA224_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[corresponds(SHA224_Final)] + #[inline] + pub fn finish(mut self) -> [u8; 28] { + unsafe { + let mut hash = MaybeUninit::<[u8; 28]>::uninit(); + ffi::SHA224_Final(hash.as_mut_ptr() as *mut _, &mut self.0); + hash.assume_init() + } + } } - } - /// Returns the hash of the data. - #[inline] - pub fn finish(mut self) -> [u8; 28] { - unsafe { - let mut hash: [u8; 28] = mem::uninitialized(); - ffi::SHA224_Final(hash.as_mut_ptr(), &mut self.0); - hash - } - } -} + /// An object which calculates a SHA256 hash of some data. + #[derive(Clone)] + pub struct Sha256(ffi::SHA256_CTX); -/// An object which calculates a SHA256 hash of some data. -pub struct Sha256(ffi::SHA256_CTX); - -impl Sha256 { - /// Creates a new hasher. - #[inline] - pub fn new() -> Sha256 { - unsafe { - let mut ctx = mem::uninitialized(); - ffi::SHA256_Init(&mut ctx); - Sha256(ctx) + impl Default for Sha256 { + #[inline] + fn default() -> Sha256 { + Sha256::new() + } } - } - /// Feeds some data into the hasher. - /// - /// This can be called multiple times. - #[inline] - pub fn update(&mut self, buf: &[u8]) { - unsafe { - ffi::SHA256_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + impl Sha256 { + /// Creates a new hasher. + #[corresponds(SHA256_Init)] + #[inline] + pub fn new() -> Sha256 { + unsafe { + let mut ctx = MaybeUninit::uninit(); + ffi::SHA256_Init(ctx.as_mut_ptr()); + Sha256(ctx.assume_init()) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[corresponds(SHA256_Update)] + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA256_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[corresponds(SHA256_Final)] + #[inline] + pub fn finish(mut self) -> [u8; 32] { + unsafe { + let mut hash = MaybeUninit::<[u8; 32]>::uninit(); + ffi::SHA256_Final(hash.as_mut_ptr() as *mut _, &mut self.0); + hash.assume_init() + } + } } - } - /// Returns the hash of the data. - #[inline] - pub fn finish(mut self) -> [u8; 32] { - unsafe { - let mut hash: [u8; 32] = mem::uninitialized(); - ffi::SHA256_Final(hash.as_mut_ptr(), &mut self.0); - hash - } - } -} + /// An object which calculates a SHA384 hash of some data. + #[derive(Clone)] + pub struct Sha384(ffi::SHA512_CTX); -/// An object which calculates a SHA384 hash of some data. -pub struct Sha384(ffi::SHA512_CTX); - -impl Sha384 { - /// Creates a new hasher. - #[inline] - pub fn new() -> Sha384 { - unsafe { - let mut ctx = mem::uninitialized(); - ffi::SHA384_Init(&mut ctx); - Sha384(ctx) + impl Default for Sha384 { + #[inline] + fn default() -> Sha384 { + Sha384::new() + } } - } - /// Feeds some data into the hasher. - /// - /// This can be called multiple times. - #[inline] - pub fn update(&mut self, buf: &[u8]) { - unsafe { - ffi::SHA384_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + impl Sha384 { + /// Creates a new hasher. + #[corresponds(SHA384_Init)] + #[inline] + pub fn new() -> Sha384 { + unsafe { + let mut ctx = MaybeUninit::uninit(); + ffi::SHA384_Init(ctx.as_mut_ptr()); + Sha384(ctx.assume_init()) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[corresponds(SHA384_Update)] + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA384_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[corresponds(SHA384_Final)] + #[inline] + pub fn finish(mut self) -> [u8; 48] { + unsafe { + let mut hash = MaybeUninit::<[u8; 48]>::uninit(); + ffi::SHA384_Final(hash.as_mut_ptr() as *mut _, &mut self.0); + hash.assume_init() + } + } } - } - /// Returns the hash of the data. - #[inline] - pub fn finish(mut self) -> [u8; 48] { - unsafe { - let mut hash: [u8; 48] = mem::uninitialized(); - ffi::SHA384_Final(hash.as_mut_ptr(), &mut self.0); - hash - } - } -} + /// An object which calculates a SHA512 hash of some data. + #[derive(Clone)] + pub struct Sha512(ffi::SHA512_CTX); -/// An object which calculates a SHA512 hash of some data. -pub struct Sha512(ffi::SHA512_CTX); - -impl Sha512 { - /// Creates a new hasher. - #[inline] - pub fn new() -> Sha512 { - unsafe { - let mut ctx = mem::uninitialized(); - ffi::SHA512_Init(&mut ctx); - Sha512(ctx) + impl Default for Sha512 { + #[inline] + fn default() -> Sha512 { + Sha512::new() + } } - } - /// Feeds some data into the hasher. - /// - /// This can be called multiple times. - #[inline] - pub fn update(&mut self, buf: &[u8]) { - unsafe { - ffi::SHA512_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + impl Sha512 { + /// Creates a new hasher. + #[corresponds(SHA512_Init)] + #[inline] + pub fn new() -> Sha512 { + unsafe { + let mut ctx = MaybeUninit::uninit(); + ffi::SHA512_Init(ctx.as_mut_ptr()); + Sha512(ctx.assume_init()) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[corresponds(SHA512_Update)] + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA512_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[corresponds(SHA512_Final)] + #[inline] + pub fn finish(mut self) -> [u8; 64] { + unsafe { + let mut hash= MaybeUninit::<[u8; 64]>::uninit(); + ffi::SHA512_Final(hash.as_mut_ptr() as *mut _, &mut self.0); + hash.assume_init() + } } } - - /// Returns the hash of the data. - #[inline] - pub fn finish(mut self) -> [u8; 64] { - unsafe { - let mut hash: [u8; 64] = mem::uninitialized(); - ffi::SHA512_Final(hash.as_mut_ptr(), &mut self.0); - hash - } } } #[cfg(test)] mod test { - use hex::ToHex; - use super::*; #[test] @@ -297,17 +348,33 @@ mod test { let data = b"abc"; let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; - assert_eq!(sha1(data).to_hex(), expected); + assert_eq!(hex::encode(sha1(data)), expected); } #[test] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn struct_1() { let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; let mut hasher = Sha1::new(); hasher.update(b"a"); hasher.update(b"bc"); - assert_eq!(hasher.finish().to_hex(), expected); + assert_eq!(hex::encode(hasher.finish()), expected); + } + + #[test] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] + fn cloning_allows_incremental_hashing() { + let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; + + let mut hasher = Sha1::new(); + hasher.update(b"a"); + + let mut incr_hasher = hasher.clone(); + incr_hasher.update(b"bc"); + + assert_eq!(hex::encode(incr_hasher.finish()), expected); + assert_ne!(hex::encode(hasher.finish()), expected); } #[test] @@ -315,17 +382,18 @@ mod test { let data = b"abc"; let expected = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; - assert_eq!(sha224(data).to_hex(), expected); + assert_eq!(hex::encode(sha224(data)), expected); } #[test] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn struct_224() { let expected = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; let mut hasher = Sha224::new(); hasher.update(b"a"); hasher.update(b"bc"); - assert_eq!(hasher.finish().to_hex(), expected); + assert_eq!(hex::encode(hasher.finish()), expected); } #[test] @@ -333,56 +401,63 @@ mod test { let data = b"abc"; let expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; - assert_eq!(sha256(data).to_hex(), expected); + assert_eq!(hex::encode(sha256(data)), expected); } #[test] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn struct_256() { let expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; let mut hasher = Sha256::new(); hasher.update(b"a"); hasher.update(b"bc"); - assert_eq!(hasher.finish().to_hex(), expected); + assert_eq!(hex::encode(hasher.finish()), expected); } #[test] fn standalone_384() { let data = b"abc"; - let expected = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ - 7cc2358baeca134c825a7"; + let expected = + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ + 7cc2358baeca134c825a7"; - assert_eq!((&sha384(data)[..]).to_hex(), expected); + assert_eq!(hex::encode(&sha384(data)[..]), expected); } #[test] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn struct_384() { - let expected = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ - 7cc2358baeca134c825a7"; + let expected = + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ + 7cc2358baeca134c825a7"; let mut hasher = Sha384::new(); hasher.update(b"a"); hasher.update(b"bc"); - assert_eq!((&hasher.finish()[..]).to_hex(), expected); + assert_eq!(hex::encode(&hasher.finish()[..]), expected); } #[test] fn standalone_512() { let data = b"abc"; - let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ - fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + let expected = + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ + fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; - assert_eq!((&sha512(data)[..]).to_hex(), expected); + assert_eq!(hex::encode(&sha512(data)[..]), expected); } #[test] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn struct_512() { - let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ - fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + let expected = + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ + fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; let mut hasher = Sha512::new(); hasher.update(b"a"); hasher.update(b"bc"); - assert_eq!((&hasher.finish()[..]).to_hex(), expected); + assert_eq!(hex::encode(&hasher.finish()[..]), expected); } } diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index a90d157..406bb42 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -26,7 +26,7 @@ //! let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap(); //! signer.update(data).unwrap(); //! signer.update(data2).unwrap(); -//! let signature = signer.finish().unwrap(); +//! let signature = signer.sign_to_vec().unwrap(); //! //! // Verify the data //! let mut verifier = Verifier::new(MessageDigest::sha256(), &keypair).unwrap(); @@ -34,56 +34,92 @@ //! 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)); -//! ``` -use ffi; + +#![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; use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; -use {cvt, cvt_p}; -use hash::MessageDigest; -use pkey::{PKeyCtxRef, PKeyRef}; -use error::ErrorStack; +use crate::error::ErrorStack; +use crate::hash::MessageDigest; +use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; +use crate::rsa::Padding; +use crate::{cvt, cvt_p}; + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} + +/// Salt lengths that must be used with `set_rsa_pss_saltlen`. +pub struct RsaPssSaltlen(c_int); + +impl RsaPssSaltlen { + /// Returns the integer representation of `RsaPssSaltlen`. + fn as_raw(&self) -> c_int { + self.0 + } + + /// Sets the salt length to the given value. + pub fn custom(val: c_int) -> RsaPssSaltlen { + RsaPssSaltlen(val) + } -#[cfg(ossl110)] -use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; -#[cfg(any(ossl101, ossl102))] -use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + /// The salt length is set to the digest length. + /// Corresponds to the special value `-1`. + pub const DIGEST_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-1); + /// The salt length is set to the maximum permissible value. + /// Corresponds to the special value `-2`. + pub const MAXIMUM_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-2); +} /// A type which computes cryptographic signatures of data. pub struct Signer<'a> { md_ctx: *mut ffi::EVP_MD_CTX, - pkey_ctx: *mut ffi::EVP_PKEY_CTX, - pkey_pd: PhantomData<&'a PKeyRef>, + pctx: *mut ffi::EVP_PKEY_CTX, + _p: PhantomData<&'a ()>, } +unsafe impl<'a> Sync for Signer<'a> {} +unsafe impl<'a> Send for Signer<'a> {} + impl<'a> Drop for Signer<'a> { fn drop(&mut self) { // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. @@ -93,13 +129,45 @@ impl<'a> Drop for Signer<'a> { } } +#[allow(clippy::len_without_is_empty)] impl<'a> Signer<'a> { /// Creates a new `Signer`. /// + /// This cannot be used with Ed25519 or Ed448 keys. Please refer to + /// `new_without_digest`. + /// /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html - pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> { + pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + Self::new_intern(Some(type_), pkey) + } + + /// Creates a new `Signer` without a digest. + /// + /// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys. + /// It can also be used to create a CMAC. + /// + /// OpenSSL documentation at [`EVP_DigestSignInit`]. + /// + /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html + pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + Self::new_intern(None, pkey) + } + + fn new_intern( + type_: Option, + pkey: &'a PKeyRef, + ) -> Result, ErrorStack> + where + T: HasPrivate, + { unsafe { ffi::init(); @@ -108,7 +176,7 @@ impl<'a> Signer<'a> { let r = ffi::EVP_DigestSignInit( ctx, &mut pctx, - type_.as_ptr(), + type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()), ptr::null_mut(), pkey.as_ptr(), ); @@ -121,24 +189,81 @@ impl<'a> Signer<'a> { Ok(Signer { md_ctx: ctx, - pkey_ctx: pctx, - pkey_pd: PhantomData, + pctx, + _p: PhantomData, }) } } - /// Returns a shared reference to the `PKeyCtx` associated with the `Signer`. - pub fn pkey_ctx(&self) -> &PKeyCtxRef { - unsafe { PKeyCtxRef::from_ptr(self.pkey_ctx) } + /// Returns the RSA padding mode in use. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + pub fn rsa_padding(&self) -> Result { + unsafe { + let mut pad = 0; + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) + .map(|_| Padding::from_raw(pad)) + } } - /// Returns a mutable reference to the `PKeyCtx` associated with the `Signer`. - pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { - unsafe { PKeyCtxRef::from_ptr_mut(self.pkey_ctx) } + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.pctx, + padding.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA PSS salt length. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( + self.pctx, + len.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } } /// Feeds more data into the `Signer`. /// + /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. + /// Use `sign_oneshot` instead. + /// /// OpenSSL documentation at [`EVP_DigestUpdate`]. /// /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html @@ -148,7 +273,8 @@ impl<'a> Signer<'a> { self.md_ctx, buf.as_ptr() as *const _, buf.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -159,8 +285,13 @@ impl<'a> Signer<'a> { /// /// OpenSSL documentation at [`EVP_DigestSignFinal`]. /// - /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestSignFinal.html pub fn len(&self) -> Result { + self.len_intern() + } + + #[cfg(all(not(ossl111), not(boringssl), not(libressl370)))] + fn len_intern(&self) -> Result { unsafe { let mut len = 0; cvt(ffi::EVP_DigestSignFinal( @@ -172,6 +303,21 @@ impl<'a> Signer<'a> { } } + #[cfg(any(ossl111, boringssl, libressl370))] + fn len_intern(&self) -> Result { + unsafe { + let mut len = 0; + cvt(ffi::EVP_DigestSign( + self.md_ctx, + ptr::null_mut(), + &mut len, + ptr::null(), + 0, + ))?; + Ok(len) + } + } + /// Writes the signature into the provided buffer, returning the number of bytes written. /// /// This method will fail if the buffer is not large enough for the signature. Use the `len` @@ -179,7 +325,7 @@ impl<'a> Signer<'a> { /// /// OpenSSL documentation at [`EVP_DigestSignFinal`]. /// - /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestSignFinal.html pub fn sign(&self, buf: &mut [u8]) -> Result { unsafe { let mut len = buf.len(); @@ -203,9 +349,46 @@ impl<'a> Signer<'a> { Ok(buf) } - #[deprecated(since = "0.9.23", note = "renamed to sign_to_vec")] - pub fn finish(&self) -> Result, ErrorStack> { - self.sign_to_vec() + /// Signs the data in `data_buf` and writes the signature into the buffer `sig_buf`, returning the + /// number of bytes written. + /// + /// For PureEdDSA (Ed25519 and Ed448 keys), this is the only way to sign data. + /// + /// This method will fail if the buffer is not large enough for the signature. Use the `len` + /// method to get an upper bound on the required size. + /// + /// OpenSSL documentation at [`EVP_DigestSign`]. + /// + /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html + #[cfg(any(ossl111, boringssl, libressl370))] + pub fn sign_oneshot( + &mut self, + sig_buf: &mut [u8], + data_buf: &[u8], + ) -> Result { + unsafe { + let mut sig_len = sig_buf.len(); + cvt(ffi::EVP_DigestSign( + self.md_ctx, + sig_buf.as_mut_ptr() as *mut _, + &mut sig_len, + data_buf.as_ptr() as *const _, + data_buf.len(), + ))?; + Ok(sig_len) + } + } + + /// Returns the signature. + /// + /// This is a simple convenience wrapper over `len` and `sign_oneshot`. + #[cfg(any(ossl111, boringssl, libressl370))] + pub fn sign_oneshot_to_vec(&mut self, data_buf: &[u8]) -> Result, ErrorStack> { + let mut sig_buf = vec![0; self.len()?]; + let len = self.sign_oneshot(&mut sig_buf, data_buf)?; + // The advertised length is not always equal to the real length for things like DSA + sig_buf.truncate(len); + Ok(sig_buf) } } @@ -220,12 +403,17 @@ impl<'a> Write for Signer<'a> { } } +/// A type which can be used to verify the integrity and authenticity +/// of data given the signature. pub struct Verifier<'a> { md_ctx: *mut ffi::EVP_MD_CTX, - pkey_ctx: *mut ffi::EVP_PKEY_CTX, - pkey_pd: PhantomData<&'a PKeyRef>, + pctx: *mut ffi::EVP_PKEY_CTX, + pkey_pd: PhantomData<&'a ()>, } +unsafe impl<'a> Sync for Verifier<'a> {} +unsafe impl<'a> Send for Verifier<'a> {} + impl<'a> Drop for Verifier<'a> { fn drop(&mut self) { // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. @@ -239,10 +427,40 @@ impl<'a> Drop for Verifier<'a> { impl<'a> Verifier<'a> { /// Creates a new `Verifier`. /// + /// This cannot be used with Ed25519 or Ed448 keys. Please refer to + /// [`Verifier::new_without_digest`]. + /// + /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. + /// + /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html + pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPublic, + { + Verifier::new_intern(Some(type_), pkey) + } + + /// Creates a new `Verifier` without a digest. + /// + /// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys. + /// /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. /// /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html - pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> { + pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPublic, + { + Verifier::new_intern(None, pkey) + } + + fn new_intern( + type_: Option, + pkey: &'a PKeyRef, + ) -> Result, ErrorStack> + where + T: HasPublic, + { unsafe { ffi::init(); @@ -251,7 +469,7 @@ impl<'a> Verifier<'a> { let r = ffi::EVP_DigestVerifyInit( ctx, &mut pctx, - type_.as_ptr(), + type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()), ptr::null_mut(), pkey.as_ptr(), ); @@ -264,24 +482,81 @@ impl<'a> Verifier<'a> { Ok(Verifier { md_ctx: ctx, - pkey_ctx: pctx, + pctx, pkey_pd: PhantomData, }) } } - /// Returns a shared reference to the `PKeyCtx` associated with the `Verifier`. - pub fn pkey_ctx(&self) -> &PKeyCtxRef { - unsafe { PKeyCtxRef::from_ptr(self.pkey_ctx) } + /// Returns the RSA padding mode in use. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + pub fn rsa_padding(&self) -> Result { + unsafe { + let mut pad = 0; + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) + .map(|_| Padding::from_raw(pad)) + } + } + + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.pctx, + padding.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA PSS salt length. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( + self.pctx, + len.as_raw(), + )) + .map(|_| ()) + } } - /// Returns a mutable reference to the `PKeyCtx` associated with the `Verifier`. - pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { - unsafe { PKeyCtxRef::from_ptr_mut(self.pkey_ctx) } + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } } /// Feeds more data into the `Verifier`. /// + /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. + /// Use [`Verifier::verify_oneshot`] instead. + /// /// OpenSSL documentation at [`EVP_DigestUpdate`]. /// /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html @@ -291,7 +566,8 @@ impl<'a> Verifier<'a> { self.md_ctx, buf.as_ptr() as *const _, buf.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -303,7 +579,7 @@ impl<'a> Verifier<'a> { pub fn verify(&self, signature: &[u8]) -> Result { unsafe { let r = - EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *const _, signature.len()); + EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *mut _, signature.len()); match r { 1 => Ok(true), 0 => { @@ -315,9 +591,30 @@ impl<'a> Verifier<'a> { } } - #[deprecated(since = "0.9.23", note = "renamed to `verify`")] - pub fn finish(&self, signature: &[u8]) -> Result { - self.verify(signature) + /// Determines if the data given in `buf` matches the provided signature. + /// + /// OpenSSL documentation at [`EVP_DigestVerify`]. + /// + /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html + #[cfg(any(ossl111, boringssl, libressl370))] + pub fn verify_oneshot(&mut self, signature: &[u8], buf: &[u8]) -> Result { + unsafe { + let r = ffi::EVP_DigestVerify( + self.md_ctx, + signature.as_ptr() as *const _, + signature.len(), + buf.as_ptr() as *const _, + buf.len(), + ); + match r { + 1 => Ok(true), + 0 => { + ErrorStack::get(); + Ok(false) + } + _ => Err(ErrorStack::get()), + } + } } } @@ -347,23 +644,25 @@ unsafe fn EVP_DigestVerifyFinal( #[cfg(test)] mod test { - use hex::{FromHex, ToHex}; + use hex::{self, FromHex}; + #[cfg(not(boringssl))] use std::iter; - use hash::MessageDigest; - use sign::{Signer, Verifier}; - use ec::{EcGroup, EcKey}; - use nid; - use rsa::{PKCS1_PADDING, Rsa}; - use dsa::Dsa; - use pkey::PKey; + use crate::ec::{EcGroup, EcKey}; + use crate::hash::MessageDigest; + use crate::nid::Nid; + use crate::pkey::PKey; + use crate::rsa::{Padding, Rsa}; + #[cfg(ossl111)] + use crate::sign::RsaPssSaltlen; + use crate::sign::{Signer, Verifier}; - const INPUT: &'static str = + const INPUT: &str = "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ 654841694f6a457a4d4441344d546b7a4f44417344516f67496d6830644841364c79396c654746746347786c4c\ 6d4e76625339706331397962323930496a7030636e566c6651"; - const SIGNATURE: &'static str = + const SIGNATURE: &str = "702e218943e88fd11eb5d82dbf7845f34106ae1b81fff7731116add1717d83656d420afd3c96eedd73a2663e51\ 66687b000b87226e0187ed1073f945e582adfcef16d85a798ee8c66ddb3db8975b17d09402beedd5d9d9700710\ 8db28160d5f8040ca7445762b81fbe7ff9d92e0ae76f24f25b33bbe6f44ae61eb1040acb20044d3ef9128ed401\ @@ -378,15 +677,12 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); - assert_eq!(signer.pkey_ctx_mut().rsa_padding().unwrap(), PKCS1_PADDING); - signer - .pkey_ctx_mut() - .set_rsa_padding(PKCS1_PADDING) - .unwrap(); + assert_eq!(signer.rsa_padding().unwrap(), Padding::PKCS1); + signer.set_rsa_padding(Padding::PKCS1).unwrap(); signer.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); let result = signer.sign_to_vec().unwrap(); - assert_eq!(result.to_hex(), SIGNATURE); + assert_eq!(hex::encode(result), SIGNATURE); } #[test] @@ -396,10 +692,7 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); - assert_eq!( - verifier.pkey_ctx_mut().rsa_padding().unwrap(), - PKCS1_PADDING - ); + assert_eq!(verifier.rsa_padding().unwrap(), Padding::PKCS1); verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); assert!(verifier.verify(&Vec::from_hex(SIGNATURE).unwrap()).unwrap()); } @@ -416,58 +709,9 @@ mod test { assert!(!verifier.verify(&Vec::from_hex(SIGNATURE).unwrap()).unwrap()); } - #[test] - pub fn dsa_sign_verify() { - let input: Vec = (0..25).cycle().take(1024).collect(); - - let private_key = { - let key = include_bytes!("../test/dsa.pem"); - PKey::from_dsa(Dsa::private_key_from_pem(key).unwrap()).unwrap() - }; - - let public_key = { - let key = include_bytes!("../test/dsa.pem.pub"); - PKey::from_dsa(Dsa::public_key_from_pem(key).unwrap()).unwrap() - }; - - let mut signer = Signer::new(MessageDigest::sha1(), &private_key).unwrap(); - signer.update(&input).unwrap(); - let sig = signer.sign_to_vec().unwrap(); - - let mut verifier = Verifier::new(MessageDigest::sha1(), &public_key).unwrap(); - verifier.update(&input).unwrap(); - assert!(verifier.verify(&sig).unwrap()); - } - - #[test] - pub fn dsa_sign_verify_fail() { - let input: Vec = (0..25).cycle().take(1024).collect(); - - let private_key = { - let key = include_bytes!("../test/dsa.pem"); - PKey::from_dsa(Dsa::private_key_from_pem(key).unwrap()).unwrap() - }; - - let public_key = { - let key = include_bytes!("../test/dsa.pem.pub"); - PKey::from_dsa(Dsa::public_key_from_pem(key).unwrap()).unwrap() - }; - - let mut signer = Signer::new(MessageDigest::sha1(), &private_key).unwrap(); - signer.update(&input).unwrap(); - let mut sig = signer.sign_to_vec().unwrap(); - sig[0] -= 1; - - let mut verifier = Verifier::new(MessageDigest::sha1(), &public_key).unwrap(); - verifier.update(&input).unwrap(); - match verifier.verify(&sig) { - Ok(true) => panic!("unexpected success"), - Ok(false) | Err(_) => {} - } - } - + #[cfg(not(boringssl))] fn test_hmac(ty: MessageDigest, tests: &[(Vec, Vec, Vec)]) { - for &(ref key, ref data, ref res) in tests.iter() { + for (key, data, res) in tests.iter() { let pkey = PKey::hmac(key).unwrap(); let mut signer = Signer::new(ty, &pkey).unwrap(); signer.update(data).unwrap(); @@ -476,6 +720,7 @@ mod test { } #[test] + #[cfg(not(boringssl))] fn hmac_md5() { // test vectors from RFC 2202 let tests: [(Vec, Vec, Vec); 7] = [ @@ -522,6 +767,7 @@ mod test { } #[test] + #[cfg(not(boringssl))] fn hmac_sha1() { // test vectors from RFC 2202 let tests: [(Vec, Vec, Vec); 7] = [ @@ -567,9 +813,26 @@ mod test { test_hmac(MessageDigest::sha1(), &tests); } + #[test] + #[cfg(ossl110)] + fn test_cmac() { + let cipher = crate::symm::Cipher::aes_128_cbc(); + let key = Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap(); + let pkey = PKey::cmac(&cipher, &key).unwrap(); + let mut signer = Signer::new_without_digest(&pkey).unwrap(); + + let data = b"Hi There"; + signer.update(data as &[u8]).unwrap(); + + let expected = vec![ + 136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19, + ]; + assert_eq!(signer.sign_to_vec().unwrap(), expected); + } + #[test] fn ec() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let key = PKey::from_ec_key(key).unwrap(); @@ -581,4 +844,43 @@ mod test { verifier.update(b"hello world").unwrap(); assert!(verifier.verify(&signature).unwrap()); } + + #[test] + #[cfg(any(ossl111, boringssl, libressl370))] + fn eddsa() { + let key = PKey::generate_ed25519().unwrap(); + + let mut signer = Signer::new_without_digest(&key).unwrap(); + let signature = signer.sign_oneshot_to_vec(b"hello world").unwrap(); + + let mut verifier = Verifier::new_without_digest(&key).unwrap(); + assert!(verifier.verify_oneshot(&signature, b"hello world").unwrap()); + } + + #[test] + #[cfg(ossl111)] + fn rsa_sign_verify() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); + signer.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); + assert_eq!(signer.rsa_padding().unwrap(), Padding::PKCS1_PSS); + signer + .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH) + .unwrap(); + signer.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap(); + signer.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); + let signature = signer.sign_to_vec().unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); + verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); + verifier + .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH) + .unwrap(); + verifier.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap(); + verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); + assert!(verifier.verify(&signature).unwrap()); + } } diff --git a/openssl/src/srtp.rs b/openssl/src/srtp.rs new file mode 100644 index 0000000..595757d --- /dev/null +++ b/openssl/src/srtp.rs @@ -0,0 +1,66 @@ +use crate::stack::Stackable; +use foreign_types::ForeignTypeRef; +use libc::c_ulong; +use std::ffi::CStr; +use std::str; + +/// fake free method, since SRTP_PROTECTION_PROFILE is static +unsafe fn free(_profile: *mut ffi::SRTP_PROTECTION_PROFILE) {} + +foreign_type_and_impl_send_sync! { + type CType = ffi::SRTP_PROTECTION_PROFILE; + fn drop = free; + + pub struct SrtpProtectionProfile; + /// Reference to `SrtpProtectionProfile`. + pub struct SrtpProtectionProfileRef; +} + +impl Stackable for SrtpProtectionProfile { + type StackType = ffi::stack_st_SRTP_PROTECTION_PROFILE; +} + +impl SrtpProtectionProfileRef { + pub fn id(&self) -> SrtpProfileId { + SrtpProfileId::from_raw(unsafe { (*self.as_ptr()).id }) + } + pub fn name(&self) -> &'static str { + unsafe { CStr::from_ptr((*self.as_ptr()).name as *const _) } + .to_str() + .expect("should be UTF-8") + } +} + +/// An identifier of an SRTP protection profile. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SrtpProfileId(c_ulong); + +impl SrtpProfileId { + pub const SRTP_AES128_CM_SHA1_80: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AES128_CM_SHA1_80 as c_ulong); + pub const SRTP_AES128_CM_SHA1_32: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AES128_CM_SHA1_32 as c_ulong); + pub const SRTP_AES128_F8_SHA1_80: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_80 as c_ulong); + pub const SRTP_AES128_F8_SHA1_32: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_32 as c_ulong); + pub const SRTP_NULL_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_80 as c_ulong); + pub const SRTP_NULL_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_32 as c_ulong); + #[cfg(any(boringssl, ossl110))] + pub const SRTP_AEAD_AES_128_GCM: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AEAD_AES_128_GCM as c_ulong); + #[cfg(any(boringssl, ossl110))] + pub const SRTP_AEAD_AES_256_GCM: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AEAD_AES_256_GCM as c_ulong); + + /// Creates a `SrtpProfileId` from an integer representation. + pub fn from_raw(value: c_ulong) -> SrtpProfileId { + SrtpProfileId(value) + } + + /// Returns the integer representation of `SrtpProfileId`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> c_ulong { + self.0 + } +} diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 4b792a7..36cea23 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -1,29 +1,32 @@ +use cfg_if::cfg_if; +use ffi::{ + self, BIO_clear_retry_flags, BIO_new, BIO_set_retry_read, BIO_set_retry_write, BIO, + BIO_CTRL_DGRAM_QUERY_MTU, BIO_CTRL_FLUSH, +}; use libc::{c_char, c_int, c_long, c_void, strlen}; -use ffi::{BIO, BIO_CTRL_FLUSH, BIO_new, BIO_clear_retry_flags, BIO_set_retry_read, - BIO_set_retry_write}; use std::any::Any; use std::io; use std::io::prelude::*; -use std::mem; -use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::ptr; use std::slice; -use cvt_p; -use error::ErrorStack; +use crate::cvt_p; +use crate::error::ErrorStack; pub struct StreamState { pub stream: S, pub error: Option, - pub panic: Option>, + pub panic: Option>, + pub dtls_mtu_size: c_long, } -/// Safe wrapper for BIO_METHOD -pub struct BioMethod(compat::BIO_METHOD); +/// Safe wrapper for `BIO_METHOD` +pub struct BioMethod(BIO_METHOD); impl BioMethod { - fn new() -> BioMethod { - BioMethod(compat::BIO_METHOD::new::()) + fn new() -> Result { + BIO_METHOD::new::().map(BioMethod) } } @@ -31,20 +34,21 @@ unsafe impl Sync for BioMethod {} unsafe impl Send for BioMethod {} pub fn new(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> { - let method = BioMethod::new::(); + let method = BioMethod::new::()?; let state = Box::new(StreamState { - stream: stream, + stream, error: None, panic: None, + dtls_mtu_size: 0, }); unsafe { let bio = cvt_p(BIO_new(method.0.get()))?; - compat::BIO_set_data(bio, Box::into_raw(state) as *mut _); - compat::BIO_set_init(bio, 1); + BIO_set_data(bio, Box::into_raw(state) as *mut _); + BIO_set_init(bio, 1); - return Ok((bio, method)); + Ok((bio, method)) } } @@ -53,13 +57,13 @@ pub unsafe fn take_error(bio: *mut BIO) -> Option { state.error.take() } -pub unsafe fn take_panic(bio: *mut BIO) -> Option> { +pub unsafe fn take_panic(bio: *mut BIO) -> Option> { let state = state::(bio); state.panic.take() } pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { - let state: &'a StreamState = mem::transmute(compat::BIO_get_data(bio)); + let state = &*(BIO_get_data(bio) as *const StreamState); &state.stream } @@ -67,8 +71,18 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { &mut state(bio).stream } +pub unsafe fn set_dtls_mtu_size(bio: *mut BIO, mtu_size: usize) { + if mtu_size as u64 > c_long::max_value() as u64 { + panic!( + "Given MTU size {} can't be represented in a positive `c_long` range", + mtu_size + ) + } + state::(bio).dtls_mtu_size = mtu_size as c_long; +} + unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { - &mut *(compat::BIO_get_data(bio) as *mut _) + &mut *(BIO_get_data(bio) as *mut _) } unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { @@ -115,10 +129,10 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) } } +#[allow(clippy::match_like_matches_macro)] // matches macro requires rust 1.42.0 fn retriable_error(err: &io::Error) -> bool { match err.kind() { - io::ErrorKind::WouldBlock | - io::ErrorKind::NotConnected => true, + io::ErrorKind::WouldBlock | io::ErrorKind::NotConnected => true, _ => false, } } @@ -133,9 +147,9 @@ unsafe extern "C" fn ctrl( _num: c_long, _ptr: *mut c_void, ) -> c_long { - if cmd == BIO_CTRL_FLUSH { - let state = state::(bio); + let state = state::(bio); + if cmd == BIO_CTRL_FLUSH { match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) { Ok(Ok(())) => 1, Ok(Err(err)) => { @@ -147,16 +161,18 @@ unsafe extern "C" fn ctrl( 0 } } + } else if cmd == BIO_CTRL_DGRAM_QUERY_MTU { + state.dtls_mtu_size } else { 0 } } unsafe extern "C" fn create(bio: *mut BIO) -> c_int { - compat::BIO_set_init(bio, 0); - compat::BIO_set_num(bio, 0); - compat::BIO_set_data(bio, ptr::null_mut()); - compat::BIO_set_flags(bio, 0); + BIO_set_init(bio, 0); + BIO_set_num(bio, 0); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_flags(bio, 0); 1 } @@ -165,115 +181,110 @@ unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { return 0; } - let data = compat::BIO_get_data(bio); + let data = BIO_get_data(bio); assert!(!data.is_null()); - Box::>::from_raw(data as *mut _); - compat::BIO_set_data(bio, ptr::null_mut()); - compat::BIO_set_init(bio, 0); + let _ = Box::>::from_raw(data as *mut _); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_init(bio, 0); 1 } -#[cfg(ossl110)] -#[allow(bad_style)] -mod compat { - use std::io::{Read, Write}; - - use libc::c_int; - use ffi; - pub use ffi::{BIO_set_init, BIO_set_flags, BIO_set_data, BIO_get_data}; - - pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} - - pub struct BIO_METHOD(*mut ffi::BIO_METHOD); - - impl BIO_METHOD { - pub fn new() -> BIO_METHOD { - unsafe { - let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _); - assert!(!ptr.is_null()); - let ret = BIO_METHOD(ptr); - assert!(ffi::BIO_meth_set_write(ptr, super::bwrite::) != 0); - assert!(ffi::BIO_meth_set_read(ptr, super::bread::) != 0); - assert!(ffi::BIO_meth_set_puts(ptr, super::bputs::) != 0); - assert!(ffi::BIO_meth_set_ctrl(ptr, super::ctrl::) != 0); - assert!(ffi::BIO_meth_set_create(ptr, super::create) != 0); - assert!(ffi::BIO_meth_set_destroy(ptr, super::destroy::) != 0); - return ret; +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{BIO_get_data, BIO_set_data, BIO_set_flags, BIO_set_init}; + use crate::cvt; + + #[allow(bad_style)] + unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} + + #[allow(bad_style, clippy::upper_case_acronyms)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); + + impl BIO_METHOD { + fn new() -> Result { + unsafe { + let ptr = cvt_p(ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _))?; + let method = BIO_METHOD(ptr); + cvt(ffi::BIO_meth_set_write__fixed_rust(method.0, Some(bwrite::)))?; + cvt(ffi::BIO_meth_set_read__fixed_rust(method.0, Some(bread::)))?; + cvt(ffi::BIO_meth_set_puts__fixed_rust(method.0, Some(bputs::)))?; + cvt(ffi::BIO_meth_set_ctrl__fixed_rust(method.0, Some(ctrl::)))?; + cvt(ffi::BIO_meth_set_create__fixed_rust(method.0, Some(create)))?; + cvt(ffi::BIO_meth_set_destroy__fixed_rust(method.0, Some(destroy::)))?; + Ok(method) + } } - } - pub fn get(&self) -> *mut ffi::BIO_METHOD { - self.0 - } - } - - impl Drop for BIO_METHOD { - fn drop(&mut self) { - unsafe { - ffi::BIO_meth_free(self.0); + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 } } - } -} -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use std::io::{Read, Write}; - - use ffi; - use libc::{c_int, c_void}; - - pub struct BIO_METHOD(*mut ffi::BIO_METHOD); - - impl BIO_METHOD { - pub fn new() -> BIO_METHOD { - let ptr = Box::new(ffi::BIO_METHOD { - type_: ffi::BIO_TYPE_NONE, - name: b"rust\0".as_ptr() as *const _, - bwrite: Some(super::bwrite::), - bread: Some(super::bread::), - bputs: Some(super::bputs::), - bgets: None, - ctrl: Some(super::ctrl::), - create: Some(super::create), - destroy: Some(super::destroy::), - callback_ctrl: None, - }); - - BIO_METHOD(Box::into_raw(ptr)) + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + ffi::BIO_meth_free(self.0); + } + } } + } else { + #[allow(bad_style, clippy::upper_case_acronyms)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); + + impl BIO_METHOD { + fn new() -> Result { + let ptr = Box::new(ffi::BIO_METHOD { + type_: ffi::BIO_TYPE_NONE, + name: b"rust\0".as_ptr() as *const _, + bwrite: Some(bwrite::), + bread: Some(bread::), + bputs: Some(bputs::), + bgets: None, + ctrl: Some(ctrl::), + create: Some(create), + destroy: Some(destroy::), + callback_ctrl: None, + }); + + Ok(BIO_METHOD(Box::into_raw(ptr))) + } - pub fn get(&self) -> *mut ffi::BIO_METHOD { - self.0 + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 + } } - } - impl Drop for BIO_METHOD { - fn drop(&mut self) { - unsafe { - Box::::from_raw(self.0); + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + let _ = Box::::from_raw(self.0); + } } } - } - pub unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { - (*bio).init = init; - } + #[allow(bad_style)] + unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { + (*bio).init = init; + } - pub unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { - (*bio).flags = flags; - } + #[allow(bad_style)] + unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { + (*bio).flags = flags; + } - pub unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { - (*bio).ptr - } + #[allow(bad_style)] + unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { + (*bio).ptr + } - pub unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { - (*bio).ptr = data; - } + #[allow(bad_style)] + unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { + (*bio).ptr = data; + } - pub unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { - (*bio).num = num; + #[allow(bad_style)] + unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { + (*bio).num = num; + } } } diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs index d7c4805..091b1fb 100644 --- a/openssl/src/ssl/callbacks.rs +++ b/openssl/src/ssl/callbacks.rs @@ -1,40 +1,63 @@ -use ffi; -use libc::{c_int, c_uint, c_char, c_uchar, c_void}; -use std::any::Any; +use cfg_if::cfg_if; +use foreign_types::ForeignType; +use foreign_types::ForeignTypeRef; +#[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))] +use libc::c_char; +#[cfg(ossl111)] +use libc::size_t; +use libc::{c_int, c_uchar, c_uint, c_void}; +#[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))] use std::ffi::CStr; +use std::mem; use std::ptr; use std::slice; -use std::mem; -use foreign_types::ForeignTypeRef; +#[cfg(ossl111)] +use std::str; +use std::sync::Arc; -use error::ErrorStack; -use dh::Dh; -#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] -use ec_key::EcKey; -use ssl::{get_callback_idx, get_ssl_callback_idx, SslRef, SniError, NPN_PROTOS_IDX}; -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -use ssl::ALPN_PROTOS_IDX; -use x509::X509StoreContextRef; +use crate::dh::Dh; +#[cfg(all(ossl101, not(ossl110)))] +use crate::ec::EcKey; +use crate::error::ErrorStack; +use crate::pkey::Params; +#[cfg(any(ossl102, libressl261))] +use crate::ssl::AlpnError; +use crate::ssl::{ + try_get_session_ctx_index, SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, + SslSession, SslSessionRef, +}; +#[cfg(ossl111)] +use crate::ssl::{ClientHelloResponse, ExtensionContext}; +#[cfg(ossl111)] +use crate::util::ForeignTypeRefExt; +#[cfg(ossl111)] +use crate::x509::X509Ref; +use crate::x509::{X509StoreContext, X509StoreContextRef}; pub extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int where - F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send, + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { - let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); - let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); - let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); - let verify: &F = &*(verify as *mut F); + let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx); + let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); + let verify_idx = SslContext::cached_ex_index::(); - let ctx = X509StoreContextRef::from_ptr(x509_ctx); + // raw pointer shenanigans to break the borrow of ctx + // the callback can't mess with its own ex_data slot so this is safe + let verify = ctx + .ex_data(ssl_idx) + .expect("BUG: store context missing ssl") + .ssl_context() + .ex_data(verify_idx) + .expect("BUG: verify callback missing") as *const F; - verify(preverify_ok != 0, ctx) as c_int + (*verify)(preverify_ok != 0, ctx) as c_int } } #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] -pub extern "C" fn raw_psk( +pub extern "C" fn raw_client_psk( ssl: *mut ffi::SSL, hint: *const c_char, identity: *mut c_char, @@ -44,17 +67,19 @@ pub extern "C" fn raw_psk( ) -> c_uint where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result - + Any + 'static + Sync + Send, { unsafe { - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); - let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); let ssl = SslRef::from_ptr_mut(ssl); - let callback = &*(callback as *mut F); - let hint = if hint != ptr::null() { + let callback_idx = SslContext::cached_ex_index::(); + + let callback = ssl + .ssl_context() + .ex_data(callback_idx) + .expect("BUG: psk callback missing") as *const F; + let hint = if !hint.is_null() { Some(CStr::from_ptr(hint).to_bytes()) } else { None @@ -62,9 +87,50 @@ where // Give the callback mutable slices into which it can write the identity and psk. let identity_sl = slice::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize); let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); - match callback(ssl, hint, identity_sl, psk_sl) { + match (*callback)(ssl, hint, identity_sl, psk_sl) { + Ok(psk_len) => psk_len as u32, + Err(e) => { + e.put(); + 0 + } + } + } +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +pub extern "C" fn raw_server_psk( + ssl: *mut ffi::SSL, + identity: *const c_char, + psk: *mut c_uchar, + max_psk_len: c_uint, +) -> c_uint +where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result + + 'static + + Sync + + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback_idx = SslContext::cached_ex_index::(); + + let callback = ssl + .ssl_context() + .ex_data(callback_idx) + .expect("BUG: psk callback missing") as *const F; + let identity = if identity.is_null() { + None + } else { + Some(CStr::from_ptr(identity).to_bytes()) + }; + // Give the callback mutable slices into which it can write the psk. + let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); + match (*callback)(ssl, identity, psk_sl) { Ok(psk_len) => psk_len as u32, - _ => 0, + Err(e) => { + e.put(); + 0 + } } } } @@ -74,100 +140,71 @@ pub extern "C" fn ssl_raw_verify( x509_ctx: *mut ffi::X509_STORE_CTX, ) -> c_int where - F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send, + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { - let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); - let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); - let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_callback_idx::()); - let verify: &F = &*(verify as *mut F); + let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx); + let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); + let callback_idx = Ssl::cached_ex_index::>(); - let ctx = X509StoreContextRef::from_ptr(x509_ctx); + let callback = ctx + .ex_data(ssl_idx) + .expect("BUG: store context missing ssl") + .ex_data(callback_idx) + .expect("BUG: ssl verify callback missing") + .clone(); - verify(preverify_ok != 0, ctx) as c_int + callback(preverify_ok != 0, ctx) as c_int } } -pub extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int +pub extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, arg: *mut c_void) -> c_int where - F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send, { unsafe { - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); - let callback: &F = &*(callback as *mut F); let ssl = SslRef::from_ptr_mut(ssl); + let callback = arg as *const F; + let mut alert = SslAlert(*al); - match callback(ssl) { + let r = (*callback)(ssl, &mut alert); + *al = alert.0; + match r { Ok(()) => ffi::SSL_TLSEXT_ERR_OK, - Err(SniError::Fatal(e)) => { - *al = e; - ffi::SSL_TLSEXT_ERR_ALERT_FATAL - } - Err(SniError::Warning(e)) => { - *al = e; - ffi::SSL_TLSEXT_ERR_ALERT_WARNING - } - Err(SniError::NoAck) => ffi::SSL_TLSEXT_ERR_NOACK, + Err(e) => e.0, } } } -pub unsafe fn select_proto_using( - ssl: *mut ffi::SSL, - out: *mut *mut c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - ex_data: c_int, -) -> c_int { - - // First, get the list of protocols (that the client should support) saved in the context - // extra data. - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, ex_data); - let protocols: &Vec = &*(protocols as *mut Vec); - // Prepare the client list parameters to be passed to the OpenSSL function... - let client = protocols.as_ptr(); - let client_len = protocols.len() as c_uint; - // Finally, let OpenSSL find a protocol to be used, by matching the given server and - // client lists. - if ffi::SSL_select_next_proto(out, outlen, inbuf, inlen, client, client_len) != - ffi::OPENSSL_NPN_NEGOTIATED - { - ffi::SSL_TLSEXT_ERR_NOACK - } else { - ffi::SSL_TLSEXT_ERR_OK - } -} - -/// The function is given as the callback to `SSL_CTX_set_next_proto_select_cb`. -/// -/// It chooses the protocol that the client wishes to use, out of the given list of protocols -/// supported by the server. It achieves this by delegating to the `SSL_select_next_proto` -/// function. The list of protocols supported by the client is found in the extra data of the -/// OpenSSL context. -pub extern "C" fn raw_next_proto_select_cb( - ssl: *mut ffi::SSL, - out: *mut *mut c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - _arg: *mut c_void, -) -> c_int { - unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *NPN_PROTOS_IDX) } -} - -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -pub extern "C" fn raw_alpn_select_cb( +#[cfg(any(ossl102, libressl261))] +pub extern "C" fn raw_alpn_select( ssl: *mut ffi::SSL, out: *mut *const c_uchar, outlen: *mut c_uchar, inbuf: *const c_uchar, inlen: c_uint, _arg: *mut c_void, -) -> c_int { - unsafe { select_proto_using(ssl, out as *mut _, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) } +) -> c_int +where + F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: alpn callback missing") as *const F; + let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize); + + match (*callback)(ssl, protos) { + Ok(proto) => { + *out = proto.as_ptr() as *const c_uchar; + *outlen = proto.len() as c_uchar; + ffi::SSL_TLSEXT_ERR_OK + } + Err(e) => e.0, + } + } } pub unsafe extern "C" fn raw_tmp_dh( @@ -176,48 +213,50 @@ pub unsafe extern "C" fn raw_tmp_dh( keylength: c_int, ) -> *mut ffi::DH where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { - let ctx = ffi::SSL_get_SSL_CTX(ssl); - let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::()); - let callback = &*(callback as *mut F); - let ssl = SslRef::from_ptr_mut(ssl); - match callback(ssl, is_export != 0, keylength as u32) { + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: tmp dh callback missing") as *const F; + + match (*callback)(ssl, is_export != 0, keylength as u32) { Ok(dh) => { let ptr = dh.as_ptr(); mem::forget(dh); ptr } - Err(_) => { - // FIXME reset error stack + Err(e) => { + e.put(); ptr::null_mut() } } } -#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +#[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh( ssl: *mut ffi::SSL, is_export: c_int, keylength: c_int, ) -> *mut ffi::EC_KEY where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { - let ctx = ffi::SSL_get_SSL_CTX(ssl); - let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::()); - let callback = &*(callback as *mut F); - let ssl = SslRef::from_ptr_mut(ssl); - match callback(ssl, is_export != 0, keylength as u32) { + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: tmp ecdh callback missing") as *const F; + + match (*callback)(ssl, is_export != 0, keylength as u32) { Ok(ec_key) => { let ptr = ec_key.as_ptr(); mem::forget(ec_key); ptr } - Err(_) => { - // FIXME reset error stack + Err(e) => { + e.put(); ptr::null_mut() } } @@ -229,46 +268,50 @@ pub unsafe extern "C" fn raw_tmp_dh_ssl( keylength: c_int, ) -> *mut ffi::DH where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { - let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::()); - let callback = &*(callback as *mut F); - let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) + .expect("BUG: ssl tmp dh callback missing") + .clone(); + match callback(ssl, is_export != 0, keylength as u32) { Ok(dh) => { let ptr = dh.as_ptr(); mem::forget(dh); ptr } - Err(_) => { - // FIXME reset error stack + Err(e) => { + e.put(); ptr::null_mut() } } } -#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +#[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh_ssl( ssl: *mut ffi::SSL, is_export: c_int, keylength: c_int, ) -> *mut ffi::EC_KEY where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { - let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::()); - let callback = &*(callback as *mut F); - let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) + .expect("BUG: ssl tmp ecdh callback missing") + .clone(); + match callback(ssl, is_export != 0, keylength as u32) { Ok(ec_key) => { let ptr = ec_key.as_ptr(); mem::forget(ec_key); ptr } - Err(_) => { - // FIXME reset error stack + Err(e) => { + e.put(); ptr::null_mut() } } @@ -276,21 +319,21 @@ where pub unsafe extern "C" fn raw_tlsext_status(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int where - F: Fn(&mut SslRef) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, { - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); - let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); - let callback = &*(callback as *mut F); - let ssl = SslRef::from_ptr_mut(ssl); - let ret = callback(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: ocsp callback missing") as *const F; + let ret = (*callback)(ssl); if ssl.is_server() { match ret { Ok(true) => ffi::SSL_TLSEXT_ERR_OK, Ok(false) => ffi::SSL_TLSEXT_ERR_NOACK, - Err(_) => { - // FIXME reset error stack + Err(e) => { + e.put(); ffi::SSL_TLSEXT_ERR_ALERT_FATAL } } @@ -298,42 +341,358 @@ where match ret { Ok(true) => 1, Ok(false) => 0, - Err(_) => { - // FIXME reset error stack + Err(e) => { + e.put(); -1 } } } } -/// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. -/// -/// It causes the parameter `out` to point at a `*const c_uchar` instance that -/// represents the list of protocols that the server should advertise as those -/// that it supports. -/// The list of supported protocols is found in the extra data of the OpenSSL -/// context. -pub extern "C" fn raw_next_protos_advertise_cb( +pub unsafe extern "C" fn raw_new_session( + ssl: *mut ffi::SSL, + session: *mut ffi::SSL_SESSION, +) -> c_int +where + F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, +{ + let session_ctx_index = + try_get_session_ctx_index().expect("BUG: session context index initialization failed"); + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(*session_ctx_index) + .expect("BUG: session context missing") + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: new session callback missing") as *const F; + let session = SslSession::from_ptr(session); + + (*callback)(ssl, session); + + // the return code doesn't indicate error vs success, but whether or not we consumed the session + 1 +} + +pub unsafe extern "C" fn raw_remove_session( + ctx: *mut ffi::SSL_CTX, + session: *mut ffi::SSL_SESSION, +) where + F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, +{ + let ctx = SslContextRef::from_ptr(ctx); + let callback = ctx + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: remove session callback missing"); + let session = SslSessionRef::from_ptr(session); + + callback(ctx, session) +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280, boringssl))] { + type DataPtr = *const c_uchar; + } else { + type DataPtr = *mut c_uchar; + } +} + +pub unsafe extern "C" fn raw_get_session( + ssl: *mut ffi::SSL, + data: DataPtr, + len: c_int, + copy: *mut c_int, +) -> *mut ffi::SSL_SESSION +where + F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, +{ + let session_ctx_index = + try_get_session_ctx_index().expect("BUG: session context index initialization failed"); + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(*session_ctx_index) + .expect("BUG: session context missing") + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: get session callback missing") as *const F; + let data = slice::from_raw_parts(data as *const u8, len as usize); + + match (*callback)(ssl, data) { + Some(session) => { + let p = session.as_ptr(); + mem::forget(session); + *copy = 0; + p + } + None => ptr::null_mut(), + } +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_keylog(ssl: *const ffi::SSL, line: *const c_char) +where + F: Fn(&SslRef, &str) + 'static + Sync + Send, +{ + let ssl = SslRef::from_const_ptr(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: get session callback missing"); + let line = CStr::from_ptr(line).to_bytes(); + let line = str::from_utf8_unchecked(line); + + callback(ssl, line); +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_stateless_cookie_generate( + ssl: *mut ffi::SSL, + cookie: *mut c_uchar, + cookie_len: *mut size_t, +) -> c_int +where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: stateless cookie generate callback missing") as *const F; + let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize); + match (*callback)(ssl, slice) { + Ok(len) => { + *cookie_len = len as size_t; + 1 + } + Err(e) => { + e.put(); + 0 + } + } +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_stateless_cookie_verify( + ssl: *mut ffi::SSL, + cookie: *const c_uchar, + cookie_len: size_t, +) -> c_int +where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: stateless cookie verify callback missing") as *const F; + let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len); + (*callback)(ssl, slice) as c_int +} + +#[cfg(not(boringssl))] +pub extern "C" fn raw_cookie_generate( + ssl: *mut ffi::SSL, + cookie: *mut c_uchar, + cookie_len: *mut c_uint, +) -> c_int +where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: cookie generate callback missing") as *const F; + // We subtract 1 from DTLS1_COOKIE_LENGTH as the ostensible value, 256, is erroneous but retained for + // compatibility. See comments in dtls1.h. + let slice = + slice::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1); + match (*callback)(ssl, slice) { + Ok(len) => { + *cookie_len = len as c_uint; + 1 + } + Err(e) => { + e.put(); + 0 + } + } + } +} + +#[cfg(not(boringssl))] +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + type CookiePtr = *const c_uchar; + } else { + type CookiePtr = *mut c_uchar; + } +} + +#[cfg(not(boringssl))] +pub extern "C" fn raw_cookie_verify( + ssl: *mut ffi::SSL, + cookie: CookiePtr, + cookie_len: c_uint, +) -> c_int +where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: cookie verify callback missing") as *const F; + let slice = + slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); + (*callback)(ssl, slice) as c_int + } +} + +#[cfg(ossl111)] +pub struct CustomExtAddState(Option); + +#[cfg(ossl111)] +pub extern "C" fn raw_custom_ext_add( ssl: *mut ffi::SSL, + _: c_uint, + context: c_uint, out: *mut *const c_uchar, - outlen: *mut c_uint, - _arg: *mut c_void, -) -> c_int { + outlen: *mut size_t, + x: *mut ffi::X509, + chainidx: size_t, + al: *mut c_int, + _: *mut c_void, +) -> c_int +where + F: Fn(&mut SslRef, ExtensionContext, Option<(usize, &X509Ref)>) -> Result, SslAlert> + + 'static + + Sync + + Send, + T: AsRef<[u8]> + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: custom ext add callback missing") as *const F; + let ectx = ExtensionContext::from_bits_truncate(context); + let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { + Some((chainidx, X509Ref::from_ptr(x))) + } else { + None + }; + match (*callback)(ssl, ectx, cert) { + Ok(None) => 0, + Ok(Some(buf)) => { + *outlen = buf.as_ref().len(); + *out = buf.as_ref().as_ptr(); + + let idx = Ssl::cached_ex_index::>(); + let mut buf = Some(buf); + let new = match ssl.ex_data_mut(idx) { + Some(state) => { + state.0 = buf.take(); + false + } + None => true, + }; + if new { + ssl.set_ex_data(idx, CustomExtAddState(buf)); + } + 1 + } + Err(alert) => { + *al = alert.0; + -1 + } + } + } +} + +#[cfg(ossl111)] +pub extern "C" fn raw_custom_ext_free( + ssl: *mut ffi::SSL, + _: c_uint, + _: c_uint, + _: *const c_uchar, + _: *mut c_void, +) where + T: 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let idx = Ssl::cached_ex_index::>(); + if let Some(state) = ssl.ex_data_mut(idx) { + state.0 = None; + } + } +} + +#[cfg(ossl111)] +pub extern "C" fn raw_custom_ext_parse( + ssl: *mut ffi::SSL, + _: c_uint, + context: c_uint, + input: *const c_uchar, + inlen: size_t, + x: *mut ffi::X509, + chainidx: size_t, + al: *mut c_int, + _: *mut c_void, +) -> c_int +where + F: Fn(&mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>) -> Result<(), SslAlert> + + 'static + + Sync + + Send, +{ unsafe { - // First, get the list of (supported) protocols saved in the context extra data. - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, *NPN_PROTOS_IDX); - if protocols.is_null() { - *out = b"".as_ptr(); - *outlen = 0; + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: custom ext parse callback missing") as *const F; + let ectx = ExtensionContext::from_bits_truncate(context); + let slice = slice::from_raw_parts(input as *const u8, inlen); + let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { + Some((chainidx, X509Ref::from_ptr(x))) } else { - // If the pointer is valid, put the pointer to the actual byte array into the - // output parameter `out`, as well as its length into `outlen`. - let protocols: &Vec = &*(protocols as *mut Vec); - *out = protocols.as_ptr(); - *outlen = protocols.len() as c_uint; + None + }; + match (*callback)(ssl, ectx, slice, cert) { + Ok(()) => 1, + Err(alert) => { + *al = alert.0; + 0 + } } } +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_client_hello( + ssl: *mut ffi::SSL, + al: *mut c_int, + arg: *mut c_void, +) -> c_int +where + F: Fn(&mut SslRef, &mut SslAlert) -> Result + + 'static + + Sync + + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = arg as *const F; + let mut alert = SslAlert(*al); - ffi::SSL_TLSEXT_ERR_OK + let r = (*callback)(ssl, &mut alert); + *al = alert.0; + match r { + Ok(c) => c.0, + Err(e) => { + e.put(); + ffi::SSL_CLIENT_HELLO_ERROR + } + } } diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index a730cc4..39f729d 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -1,21 +1,18 @@ +use cfg_if::cfg_if; use std::io::{Read, Write}; use std::ops::{Deref, DerefMut}; -use dh::Dh; -use error::ErrorStack; -use ssl::{self, HandshakeError, Ssl, SslRef, SslContext, SslContextBuilder, SslMethod, SslStream, - SSL_VERIFY_PEER}; -use pkey::PKeyRef; -use version; -use x509::X509Ref; - -#[cfg(ossl101)] -lazy_static! { - static ref HOSTNAME_IDX: ::ex_data::Index = Ssl::new_ex_index().unwrap(); -} - -// ffdhe2048 from https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe2048 -const DHPARAM_PEM: &'static str = " +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, +}; +use crate::version; + +const FFDHE_2048: &str = " -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a @@ -26,29 +23,32 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- "; +#[allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] fn ctx(method: SslMethod) -> Result { let mut ctx = SslContextBuilder::new(method)?; - let mut opts = ssl::SSL_OP_ALL; - opts &= !ssl::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; - opts &= !ssl::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; - opts |= ssl::SSL_OP_NO_TICKET; - opts |= ssl::SSL_OP_NO_COMPRESSION; - opts |= ssl::SSL_OP_NO_SSLV2; - opts |= ssl::SSL_OP_NO_SSLV3; - opts |= ssl::SSL_OP_SINGLE_DH_USE; - opts |= ssl::SSL_OP_SINGLE_ECDH_USE; - opts |= ssl::SSL_OP_CIPHER_SERVER_PREFERENCE; - ctx.set_options(opts); - - let mut mode = ssl::SSL_MODE_AUTO_RETRY | ssl::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER - | ssl::SSL_MODE_ENABLE_PARTIAL_WRITE; + cfg_if! { + if #[cfg(not(boringssl))] { + let mut opts = SslOptions::ALL + | SslOptions::NO_COMPRESSION + | SslOptions::NO_SSLV2 + | SslOptions::NO_SSLV3 + | SslOptions::SINGLE_DH_USE + | SslOptions::SINGLE_ECDH_USE; + opts &= !SslOptions::DONT_INSERT_EMPTY_FRAGMENTS; + + ctx.set_options(opts); + } + } + + let mut mode = + SslMode::AUTO_RETRY | SslMode::ACCEPT_MOVING_WRITE_BUFFER | SslMode::ENABLE_PARTIAL_WRITE; // This is quite a useful optimization for saving memory, but historically // caused CVEs in OpenSSL pre-1.0.1h, according to // https://bugs.python.org/issue25672 - if version::number() >= 0x1000108f { - mode |= ssl::SSL_MODE_RELEASE_BUFFERS; + if version::number() >= 0x1_00_01_08_0 { + mode |= SslMode::RELEASE_BUFFERS; } ctx.set_mode(mode); @@ -56,41 +56,65 @@ fn ctx(method: SslMethod) -> Result { Ok(ctx) } -/// A builder for `SslConnector`s. -pub struct SslConnectorBuilder(SslContextBuilder); +/// A type which wraps client-side streams in a TLS session. +/// +/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL +/// structures, configuring cipher suites, session options, hostname verification, and more. +/// +/// OpenSSL's built-in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, +/// and a custom implementation is used when linking against OpenSSL 1.0.1. +#[derive(Clone, Debug)] +pub struct SslConnector(SslContext); -impl SslConnectorBuilder { +impl SslConnector { /// Creates a new builder for TLS connections. /// /// The default configuration is subject to change, and is currently derived from Python. - pub fn new(method: SslMethod) -> Result { + pub fn builder(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_default_verify_paths()?; - // From https://github.com/python/cpython/blob/a170fa162dc03f0a014373349e548954fff2e567/Lib/ssl.py#L193 ctx.set_cipher_list( - "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:\ - TLS13-AES-128-GCM-SHA256:\ - ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:\ - ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:\ - !aNULL:!eNULL:!MD5:!3DES", + "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK", )?; setup_verify(&mut ctx); Ok(SslConnectorBuilder(ctx)) } - #[deprecated(since = "0.9.23", - note = "SslConnectorBuilder now implements Deref")] - pub fn builder(&self) -> &SslContextBuilder { - self + /// Initiates a client-side TLS session on a stream. + /// + /// The domain is used for SNI and hostname verification. + pub fn connect(&self, domain: &str, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + self.configure()?.connect(domain, stream) } - #[deprecated(since = "0.9.23", - note = "SslConnectorBuilder now implements DerefMut")] - pub fn builder_mut(&mut self) -> &mut SslContextBuilder { - self + /// Returns a structure allowing for configuration of a single TLS session before connection. + pub fn configure(&self) -> Result { + Ssl::new(&self.0).map(|ssl| ConnectConfiguration { + ssl, + sni: true, + verify_hostname: true, + }) } + /// Consumes the `SslConnector`, returning the inner raw `SslContext`. + pub fn into_context(self) -> SslContext { + self.0 + } + + /// Returns a shared reference to the inner raw `SslContext`. + pub fn context(&self) -> &SslContextRef { + &self.0 + } +} + +/// A builder for `SslConnector`s. +pub struct SslConnectorBuilder(SslContextBuilder); + +impl SslConnectorBuilder { /// Consumes the builder, returning an `SslConnector`. pub fn build(self) -> SslConnector { SslConnector(self.0.build()) @@ -111,101 +135,69 @@ impl DerefMut for SslConnectorBuilder { } } -/// A type which wraps client-side streams in a TLS session. -/// -/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL -/// structures, configuring cipher suites, session options, hostname verification, and more. -/// -/// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, -/// and a custom implementation is used when linking against OpenSSL 1.0.1. -#[derive(Clone)] -pub struct SslConnector(SslContext); +/// A type which allows for configuration of a client-side TLS session before connection. +pub struct ConnectConfiguration { + ssl: Ssl, + sni: bool, + verify_hostname: bool, +} -impl SslConnector { - /// Initiates a client-side TLS session on a stream. +impl ConnectConfiguration { + /// A builder-style version of `set_use_server_name_indication`. + pub fn use_server_name_indication(mut self, use_sni: bool) -> ConnectConfiguration { + self.set_use_server_name_indication(use_sni); + self + } + + /// Configures the use of Server Name Indication (SNI) when connecting. /// - /// The domain is used for SNI and hostname verification. - pub fn connect(&self, domain: &str, stream: S) -> Result, HandshakeError> - where - S: Read + Write, - { - self.configure()?.connect(domain, stream) + /// Defaults to `true`. + pub fn set_use_server_name_indication(&mut self, use_sni: bool) { + self.sni = use_sni; + } + + /// A builder-style version of `set_verify_hostname`. + pub fn verify_hostname(mut self, verify_hostname: bool) -> ConnectConfiguration { + self.set_verify_hostname(verify_hostname); + self } - /// Initiates a client-side TLS session on a stream without performing hostname verification. + /// Configures the use of hostname verification when connecting. + /// + /// Defaults to `true`. /// /// # Warning /// /// You should think very carefully before you use this method. If hostname verification is not /// used, *any* valid certificate for *any* site will be trusted for use from any other. This /// introduces a significant vulnerability to man-in-the-middle attacks. - pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication< - S, - >( - &self, - stream: S, - ) -> Result, HandshakeError> - where - S: Read + Write, - { - self.configure()? - .danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream) - } - - /// Returns a structure allowing for configuration of a single TLS session before connection. - pub fn configure(&self) -> Result { - Ssl::new(&self.0).map(ConnectConfiguration) + pub fn set_verify_hostname(&mut self, verify_hostname: bool) { + self.verify_hostname = verify_hostname; } -} -/// A type which allows for configuration of a client-side TLS session before connection. -pub struct ConnectConfiguration(Ssl); + /// Returns an `Ssl` configured to connect to the provided domain. + /// + /// The domain is used for SNI and hostname verification if enabled. + pub fn into_ssl(mut self, domain: &str) -> Result { + if self.sni { + self.ssl.set_hostname(domain)?; + } -impl ConnectConfiguration { - #[deprecated(since = "0.9.23", - note = "ConnectConfiguration now implements Deref")] - pub fn ssl(&self) -> &Ssl { - &self.0 - } + if self.verify_hostname { + setup_verify_hostname(&mut self.ssl, domain)?; + } - #[deprecated(since = "0.9.23", - note = "ConnectConfiguration now implements DerefMut")] - pub fn ssl_mut(&mut self) -> &mut Ssl { - &mut self.0 + Ok(self.ssl) } /// Initiates a client-side TLS session on a stream. /// - /// The domain is used for SNI and hostname verification. - pub fn connect(mut self, domain: &str, stream: S) -> Result, HandshakeError> + /// The domain is used for SNI and hostname verification if enabled. + pub fn connect(self, domain: &str, stream: S) -> Result, HandshakeError> where S: Read + Write, { - self.0.set_hostname(domain)?; - setup_verify_hostname(&mut self.0, domain)?; - - self.0.connect(stream) - } - - /// Initiates a client-side TLS session on a stream without performing hostname verification. - /// - /// The verification configuration of the connector's `SslContext` is not overridden. - /// - /// # Warning - /// - /// You should think very carefully before you use this method. If hostname verification is not - /// used, *any* valid certificate for *any* site will be trusted for use from any other. This - /// introduces a significant vulnerability to man-in-the-middle attacks. - pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication< - S, - >( - self, - stream: S, - ) -> Result, HandshakeError> - where - S: Read + Write, - { - self.0.connect(stream) + self.into_ssl(domain)?.connect(stream) } } @@ -213,126 +205,143 @@ impl Deref for ConnectConfiguration { type Target = SslRef; fn deref(&self) -> &SslRef { - &self.0 + &self.ssl } } impl DerefMut for ConnectConfiguration { fn deref_mut(&mut self) -> &mut SslRef { - &mut self.0 + &mut self.ssl } } -/// A builder for `SslAcceptor`s. -pub struct SslAcceptorBuilder(SslContextBuilder); +/// A type which wraps server-side streams in a TLS session. +/// +/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL +/// structures, configuring cipher suites, session options, and more. +#[derive(Clone)] +pub struct SslAcceptor(SslContext); -impl SslAcceptorBuilder { +impl SslAcceptor { /// Creates a new builder configured to connect to non-legacy clients. This should generally be /// considered a reasonable default choice. /// - /// This corresponds to the intermediate configuration of Mozilla's server side TLS + /// This corresponds to the intermediate configuration of version 5 of Mozilla's server side TLS /// recommendations. See its [documentation][docs] for more details on specifics. /// /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS - pub fn mozilla_intermediate( - method: SslMethod, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I, - ) -> Result - where - I: IntoIterator, - I::Item: AsRef, - { - let builder = SslAcceptorBuilder::mozilla_intermediate_raw(method)?; - builder.finish_setup(private_key, certificate, chain) + pub fn mozilla_intermediate_v5(method: SslMethod) -> Result { + let mut ctx = ctx(method)?; + ctx.set_options(SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1); + let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?; + ctx.set_tmp_dh(&dh)?; + setup_curves(&mut ctx)?; + ctx.set_cipher_list( + "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\ + ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ + DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" + )?; + #[cfg(any(ossl111, libressl340))] + ctx.set_ciphersuites( + "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256", + )?; + Ok(SslAcceptorBuilder(ctx)) } /// Creates a new builder configured to connect to modern clients. /// - /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations. + /// 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 LibreSSL 3.4.0 or newer. + /// /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS - pub fn mozilla_modern( - method: SslMethod, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I, - ) -> Result - where - I: IntoIterator, - I::Item: AsRef, - { - let builder = SslAcceptorBuilder::mozilla_modern_raw(method)?; - builder.finish_setup(private_key, certificate, chain) + #[cfg(any(ossl111, libressl340))] + pub fn mozilla_modern_v5(method: SslMethod) -> Result { + let mut ctx = ctx(method)?; + 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", + )?; + Ok(SslAcceptorBuilder(ctx)) } - /// Like `mozilla_intermediate`, but does not load the certificate chain and private key. - pub fn mozilla_intermediate_raw(method: SslMethod) -> Result { + /// Creates a new builder configured to connect to non-legacy clients. This should generally be + /// considered a reasonable default choice. + /// + /// This corresponds to the intermediate configuration of version 4 of Mozilla's server side TLS + /// recommendations. See its [documentation][docs] for more details on specifics. + /// + /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS + // FIXME remove in next major version + pub fn mozilla_intermediate(method: SslMethod) -> Result { let mut ctx = ctx(method)?; - let dh = Dh::from_pem(DHPARAM_PEM.as_bytes())?; + ctx.set_options(SslOptions::CIPHER_SERVER_PREFERENCE); + #[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)?; setup_curves(&mut ctx)?; ctx.set_cipher_list( - "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ - ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ - ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ - DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\ - ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:\ - ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\ - ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:\ - DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\ - EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:\ - AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS", + "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\ + ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ + DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\ + ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\ + ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\ + DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\ + EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\ + AES256-SHA:DES-CBC3-SHA:!DSS", )?; Ok(SslAcceptorBuilder(ctx)) } - /// Like `mozilla_modern`, but does not load the certificate chain and private key. - pub fn mozilla_modern_raw(method: SslMethod) -> Result { + /// Creates a new builder configured to connect to modern clients. + /// + /// This corresponds to the modern configuration of version 4 of Mozilla's server side TLS recommendations. + /// See its [documentation][docs] for more details on specifics. + /// + /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS + // FIXME remove in next major version + pub fn mozilla_modern(method: SslMethod) -> Result { let mut ctx = ctx(method)?; + ctx.set_options( + SslOptions::CIPHER_SERVER_PREFERENCE | SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1, + ); + #[cfg(any(ossl111, libressl340))] + ctx.set_options(SslOptions::NO_TLSV1_3); setup_curves(&mut ctx)?; ctx.set_cipher_list( - "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ - ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ - ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:\ - ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256", + "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:\ + ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ + ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256", )?; Ok(SslAcceptorBuilder(ctx)) } - fn finish_setup( - mut self, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I, - ) -> Result + /// Initiates a server-side TLS session on a stream. + pub fn accept(&self, stream: S) -> Result, HandshakeError> where - I: IntoIterator, - I::Item: AsRef, + S: Read + Write, { - self.0.set_private_key(private_key)?; - self.0.set_certificate(certificate)?; - self.0.check_private_key()?; - for cert in chain { - self.0.add_extra_chain_cert(cert.as_ref().to_owned())?; - } - Ok(self) + let ssl = Ssl::new(&self.0)?; + ssl.accept(stream) } - #[deprecated(since = "0.9.23", - note = "SslAcceptorBuilder now implements Deref")] - pub fn builder(&self) -> &SslContextBuilder { - self + /// Consumes the `SslAcceptor`, returning the inner raw `SslContext`. + pub fn into_context(self) -> SslContext { + self.0 } - #[deprecated(since = "0.9.23", - note = "SslAcceptorBuilder now implements DerefMut")] - pub fn builder_mut(&mut self) -> &mut SslContextBuilder { - self + /// Returns a shared reference to the inner raw `SslContext`. + pub fn context(&self) -> &SslContextRef { + &self.0 } +} +/// A builder for `SslAcceptor`s. +pub struct SslAcceptorBuilder(SslContextBuilder); + +impl SslAcceptorBuilder { /// Consumes the builder, returning a `SslAcceptor`. pub fn build(self) -> SslAcceptor { SslAcceptor(self.0.build()) @@ -353,247 +362,243 @@ impl DerefMut for SslAcceptorBuilder { } } -#[cfg(ossl101)] -fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - use ec::EcKey; - use nid; - - let curve = EcKey::from_curve_name(nid::X9_62_PRIME256V1)?; - ctx.set_tmp_ecdh(&curve) -} - -#[cfg(ossl102)] -fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - ctx._set_ecdh_auto(true) -} +cfg_if! { + if #[cfg(ossl110)] { + #[allow(clippy::unnecessary_wraps)] + fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { + Ok(()) + } + } else if #[cfg(any(ossl102, libressl))] { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + ctx.set_ecdh_auto(true) + } + } else { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + use crate::ec::EcKey; + use crate::nid::Nid; -#[cfg(ossl110)] -fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { - Ok(()) + let curve = EcKey::from_curve_name(Nid::X9_62_PRIME256V1)?; + ctx.set_tmp_ecdh(&curve) + } + } } -/// A type which wraps server-side streams in a TLS session. -/// -/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL -/// structures, configuring cipher suites, session options, and more. -#[derive(Clone)] -pub struct SslAcceptor(SslContext); +cfg_if! { + if #[cfg(any(ossl102, libressl261))] { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify(SslVerifyMode::PEER); + } -impl SslAcceptor { - /// Initiates a server-side TLS session on a stream. - pub fn accept(&self, stream: S) -> Result, HandshakeError> - where - S: Read + Write, - { - let ssl = Ssl::new(&self.0)?; - ssl.accept(stream) - } -} + fn setup_verify_hostname(ssl: &mut SslRef, domain: &str) -> Result<(), ErrorStack> { + use crate::x509::verify::X509CheckFlags; -#[cfg(any(ossl102, ossl110))] -fn setup_verify(ctx: &mut SslContextBuilder) { - ctx.set_verify(SSL_VERIFY_PEER); -} + let param = ssl.param_mut(); + param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + match domain.parse() { + Ok(ip) => param.set_ip(ip), + Err(_) => param.set_host(domain), + } + } + } else { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify_callback(SslVerifyMode::PEER, verify::verify_callback); + } -#[cfg(ossl101)] -fn setup_verify(ctx: &mut SslContextBuilder) { - ctx.set_verify_callback(SSL_VERIFY_PEER, |p, x509| { - let hostname = match x509.ssl() { - Ok(Some(ssl)) => ssl.ex_data(*HOSTNAME_IDX), - _ => None, - }; - match hostname { - Some(hostname) => verify::verify_callback(hostname, p, x509), - None => p, + fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { + let domain = domain.to_string(); + let hostname_idx = verify::try_get_hostname_idx()?; + ssl.set_ex_data(*hostname_idx, domain); + Ok(()) } - }); -} -#[cfg(any(ossl102, ossl110))] -fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - let param = ssl._param_mut(); - param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); - match domain.parse() { - Ok(ip) => param.set_ip(ip), - Err(_) => param.set_host(domain), - } -} + mod verify { + use std::net::IpAddr; + use std::str; + use once_cell::sync::OnceCell; + + use crate::error::ErrorStack; + use crate::ex_data::Index; + use crate::nid::Nid; + use crate::ssl::Ssl; + use crate::stack::Stack; + use crate::x509::{ + GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, + X509VerifyResult, + }; -#[cfg(ossl101)] -fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - let domain = domain.to_string(); - ssl.set_ex_data(*HOSTNAME_IDX, domain); - Ok(()) -} + static HOSTNAME_IDX: OnceCell> = OnceCell::new(); -#[cfg(ossl101)] -mod verify { - use std::net::IpAddr; - use std::str; - - use nid; - use x509::{GeneralName, X509NameRef, X509Ref, X509StoreContextRef}; - use stack::Stack; - - pub fn verify_callback( - domain: &str, - preverify_ok: bool, - x509_ctx: &X509StoreContextRef, - ) -> bool { - if !preverify_ok || x509_ctx.error_depth() != 0 { - return preverify_ok; - } + pub fn try_get_hostname_idx() -> Result<&'static Index, ErrorStack> { + HOSTNAME_IDX.get_or_try_init(Ssl::new_ex_index) + } - match x509_ctx.current_cert() { - Some(x509) => verify_hostname(domain, &x509), - None => true, - } - } + pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { + if !preverify_ok || x509_ctx.error_depth() != 0 { + return preverify_ok; + } - fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { - match cert.subject_alt_names() { - Some(names) => verify_subject_alt_names(domain, names), - None => verify_subject_name(domain, &cert.subject_name()), - } - } + let hostname_idx = + try_get_hostname_idx().expect("failed to initialize hostname index"); + let ok = match ( + x509_ctx.current_cert(), + X509StoreContext::ssl_idx() + .ok() + .and_then(|idx| x509_ctx.ex_data(idx)) + .and_then(|ssl| ssl.ex_data(*hostname_idx)), + ) { + (Some(x509), Some(domain)) => verify_hostname(domain, &x509), + _ => true, + }; + + if !ok { + x509_ctx.set_error(X509VerifyResult::APPLICATION_VERIFICATION); + } - fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { - let ip = domain.parse(); + ok + } - for name in &names { - match ip { - Ok(ip) => { - if let Some(actual) = name.ipaddress() { - if matches_ip(&ip, actual) { - return true; + fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { + match cert.subject_alt_names() { + Some(names) => verify_subject_alt_names(domain, names), + None => verify_subject_name(domain, &cert.subject_name()), + } + } + + fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { + let ip = domain.parse(); + + for name in &names { + match ip { + Ok(ip) => { + if let Some(actual) = name.ipaddress() { + if matches_ip(&ip, actual) { + return true; + } + } + } + Err(_) => { + if let Some(pattern) = name.dnsname() { + if matches_dns(pattern, domain) { + return true; + } + } } } } - Err(_) => { - if let Some(pattern) = name.dnsname() { - if matches_dns(pattern, domain, false) { - return true; + + false + } + + fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { + match subject_name.entries_by_nid(Nid::COMMONNAME).next() { + Some(pattern) => { + let pattern = match str::from_utf8(pattern.data().as_slice()) { + Ok(pattern) => pattern, + Err(_) => return false, + }; + + // Unlike SANs, IP addresses in the subject name don't have a + // different encoding. + match domain.parse::() { + Ok(ip) => pattern + .parse::() + .ok() + .map_or(false, |pattern| pattern == ip), + Err(_) => matches_dns(pattern, domain), } } + None => false, } } - } - - false - } - - fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { - if let Some(pattern) = subject_name.entries_by_nid(nid::COMMONNAME).next() { - let pattern = match str::from_utf8(pattern.data().as_slice()) { - Ok(pattern) => pattern, - Err(_) => return false, - }; - // Unlike with SANs, IP addresses in the subject name don't have a - // different encoding. We need to pass this down to matches_dns to - // disallow wildcard matches with bogus patterns like *.0.0.1 - let is_ip = domain.parse::().is_ok(); + fn matches_dns(mut pattern: &str, mut hostname: &str) -> bool { + // first strip trailing . off of pattern and hostname to normalize + if pattern.ends_with('.') { + pattern = &pattern[..pattern.len() - 1]; + } + if hostname.ends_with('.') { + hostname = &hostname[..hostname.len() - 1]; + } - if matches_dns(&pattern, domain, is_ip) { - return true; + matches_wildcard(pattern, hostname).unwrap_or_else(|| pattern.eq_ignore_ascii_case(hostname)) } - } - false - } - - fn matches_dns(mut pattern: &str, mut hostname: &str, is_ip: bool) -> bool { - // first strip trailing . off of pattern and hostname to normalize - if pattern.ends_with('.') { - pattern = &pattern[..pattern.len() - 1]; - } - if hostname.ends_with('.') { - hostname = &hostname[..hostname.len() - 1]; - } + fn matches_wildcard(pattern: &str, hostname: &str) -> Option { + let wildcard_location = match pattern.find('*') { + Some(l) => l, + None => return None, + }; + + let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); + let wildcard_end = match dot_idxs.next() { + Some(l) => l, + None => return None, + }; + + // Never match wildcards if the pattern has less than 2 '.'s (no *.com) + // + // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. + // Chrome has a black- and white-list for this, but Firefox (via NSS) does + // the same thing we do here. + // + // The Public Suffix (https://www.publicsuffix.org/) list could + // potentially be used here, but it's both huge and updated frequently + // enough that management would be a PITA. + if dot_idxs.next().is_none() { + return None; + } - matches_wildcard(pattern, hostname, is_ip).unwrap_or_else(|| pattern == hostname) - } + // Wildcards can only be in the first component, and must be the entire first label + if wildcard_location != 0 || wildcard_end != wildcard_location + 1 { + return None; + } - fn matches_wildcard(pattern: &str, hostname: &str, is_ip: bool) -> Option { - // IP addresses and internationalized domains can't involved in wildcards - if is_ip || pattern.starts_with("xn--") { - return None; - } + let hostname_label_end = match hostname.find('.') { + Some(l) => l, + None => return None, + }; - let wildcard_location = match pattern.find('*') { - Some(l) => l, - None => return None, - }; - - let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); - let wildcard_end = match dot_idxs.next() { - Some(l) => l, - None => return None, - }; - - // Never match wildcards if the pattern has less than 2 '.'s (no *.com) - // - // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. - // Chrome has a black- and white-list for this, but Firefox (via NSS) does - // the same thing we do here. - // - // The Public Suffix (https://www.publicsuffix.org/) list could - // potentially be used here, but it's both huge and updated frequently - // enough that management would be a PITA. - if dot_idxs.next().is_none() { - return None; - } + let pattern_after_wildcard = &pattern[wildcard_end..]; + let hostname_after_wildcard = &hostname[hostname_label_end..]; - // Wildcards can only be in the first component - if wildcard_location > wildcard_end { - return None; - } + Some(pattern_after_wildcard.eq_ignore_ascii_case(hostname_after_wildcard)) + } - let hostname_label_end = match hostname.find('.') { - Some(l) => l, - None => return None, - }; + fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { + match *expected { + IpAddr::V4(ref addr) => actual == addr.octets(), + IpAddr::V6(ref addr) => actual == addr.octets(), + } + } - // check that the non-wildcard parts are identical - if pattern[wildcard_end..] != hostname[hostname_label_end..] { - return Some(false); - } + #[test] + fn test_dns_match() { + use crate::ssl::connector::verify::matches_dns; + assert!(matches_dns("website.tld", "website.tld")); // A name should match itself. + assert!(matches_dns("website.tld", "wEbSiTe.tLd")); // DNS name matching ignores case of hostname. + assert!(matches_dns("wEbSiTe.TlD", "website.tld")); // DNS name matching ignores case of subject. - let wildcard_prefix = &pattern[..wildcard_location]; - let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; + assert!(matches_dns("xn--bcher-kva.tld", "xn--bcher-kva.tld")); // Likewise, nothing special to punycode names. + assert!(matches_dns("xn--bcher-kva.tld", "xn--BcHer-Kva.tLd")); // And punycode must be compared similarly case-insensitively. - let hostname_label = &hostname[..hostname_label_end]; + assert!(matches_dns("*.example.com", "subdomain.example.com")); // Wildcard matching works. + assert!(matches_dns("*.eXaMpLe.cOm", "subdomain.example.com")); // Wildcard matching ignores case of subject. + assert!(matches_dns("*.example.com", "sUbDoMaIn.eXaMpLe.cOm")); // Wildcard matching ignores case of hostname. - // check the prefix of the first label - if !hostname_label.starts_with(wildcard_prefix) { - return Some(false); - } + assert!(!matches_dns("prefix*.example.com", "p.example.com")); // Prefix longer than the label works and does not match. + assert!(!matches_dns("*suffix.example.com", "s.example.com")); // Suffix longer than the label works and does not match. - // and the suffix - if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { - return Some(false); - } + assert!(!matches_dns("prefix*.example.com", "prefix.example.com")); // Partial wildcards do not work. + assert!(!matches_dns("*suffix.example.com", "suffix.example.com")); // Partial wildcards do not work. - Some(true) - } + assert!(!matches_dns("prefix*.example.com", "prefixdomain.example.com")); // Partial wildcards do not work. + assert!(!matches_dns("*suffix.example.com", "domainsuffix.example.com")); // Partial wildcards do not work. - fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { - match (expected, actual.len()) { - (&IpAddr::V4(ref addr), 4) => actual == addr.octets(), - (&IpAddr::V6(ref addr), 16) => { - let segments = [ - ((actual[0] as u16) << 8) | actual[1] as u16, - ((actual[2] as u16) << 8) | actual[3] as u16, - ((actual[4] as u16) << 8) | actual[5] as u16, - ((actual[6] as u16) << 8) | actual[7] as u16, - ((actual[8] as u16) << 8) | actual[9] as u16, - ((actual[10] as u16) << 8) | actual[11] as u16, - ((actual[12] as u16) << 8) | actual[13] as u16, - ((actual[14] as u16) << 8) | actual[15] as u16, - ]; - segments == addr.segments() + assert!(!matches_dns("xn--*.example.com", "subdomain.example.com")); // Punycode domains with wildcard parts do not match. + assert!(!matches_dns("xN--*.example.com", "subdomain.example.com")); // And we can't bypass a punycode test with weird casing. + assert!(!matches_dns("Xn--*.example.com", "subdomain.example.com")); // And we can't bypass a punycode test with weird casing. + assert!(!matches_dns("XN--*.example.com", "subdomain.example.com")); // And we can't bypass a punycode test with weird casing. } - _ => false, } } } diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 48f4997..5565833 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -1,61 +1,88 @@ -use std::any::Any; +use libc::c_int; use std::error; use std::error::Error as StdError; use std::fmt; use std::io; -use error::ErrorStack; -use ssl::MidHandshakeSslStream; +use crate::error::ErrorStack; +use crate::ssl::MidHandshakeSslStream; +use crate::x509::X509VerifyResult; + +/// An error code returned from SSL functions. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ErrorCode(c_int); + +impl ErrorCode { + /// The SSL session has been closed. + pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN); + + /// An attempt to read data from the underlying socket returned `WouldBlock`. + /// + /// Wait for read readiness and retry the operation. + pub const WANT_READ: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_READ); + + /// An attempt to write data to the underlying socket returned `WouldBlock`. + /// + /// Wait for write readiness and retry the operation. + pub const WANT_WRITE: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_WRITE); + + /// A non-recoverable IO error occurred. + pub const SYSCALL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SYSCALL); + + /// An error occurred in the SSL library. + pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL); + + /// The client hello callback indicated that it needed to be retried. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[cfg(ossl111)] + pub const WANT_CLIENT_HELLO_CB: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_CLIENT_HELLO_CB); + + pub fn from_raw(raw: c_int) -> ErrorCode { + ErrorCode(raw) + } + + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> c_int { + self.0 + } +} -/// An SSL error. -// FIXME this is missing variants #[derive(Debug)] -pub enum Error { - /// The SSL session has been closed by the other end - ZeroReturn, - /// An attempt to read data from the underlying socket returned - /// `WouldBlock`. Wait for read readiness and reattempt the operation. - WantRead(io::Error), - /// An attempt to write data from the underlying socket returned - /// `WouldBlock`. Wait for write readiness and reattempt the operation. - WantWrite(io::Error), - /// The client certificate callback requested to be called again. - WantX509Lookup, - /// An error reported by the underlying stream. - Stream(io::Error), - /// An error in the OpenSSL library. +pub(crate) enum InnerError { + Io(io::Error), Ssl(ErrorStack), } -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(self.description())?; - if let Some(err) = self.cause() { - write!(fmt, ": {}", err) - } else { - Ok(()) +/// An SSL error. +#[derive(Debug)] +pub struct Error { + pub(crate) code: ErrorCode, + pub(crate) cause: Option, +} + +impl Error { + pub fn code(&self) -> ErrorCode { + self.code + } + + pub fn io_error(&self) -> Option<&io::Error> { + match self.cause { + Some(InnerError::Io(ref e)) => Some(e), + _ => None, } } -} -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::ZeroReturn => "The SSL session was closed by the other end", - Error::WantRead(_) => "A read attempt returned a `WouldBlock` error", - Error::WantWrite(_) => "A write attempt returned a `WouldBlock` error", - Error::WantX509Lookup => "The client certificate callback requested to be called again", - Error::Stream(_) => "The underlying stream reported an error", - Error::Ssl(_) => "The OpenSSL library reported an error", + pub fn into_io_error(self) -> Result { + match self.cause { + Some(InnerError::Io(e)) => Ok(e), + _ => Err(self), } } - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::WantRead(ref err) => Some(err), - Error::WantWrite(ref err) => Some(err), - Error::Stream(ref err) => Some(err), - Error::Ssl(ref err) => Some(err), + pub fn ssl_error(&self) -> Option<&ErrorStack> { + match self.cause { + Some(InnerError::Ssl(ref e)) => Some(e), _ => None, } } @@ -63,79 +90,87 @@ impl error::Error for Error { impl From for Error { fn from(e: ErrorStack) -> Error { - Error::Ssl(e) + Error { + code: ErrorCode::SSL, + cause: Some(InnerError::Ssl(e)), + } } } -/// An error indicating that the operation can be immediately retried. -/// -/// OpenSSL's [`SSL_read`] and [`SSL_write`] functions can return `SSL_ERROR_WANT_READ` even when -/// the underlying socket is performing blocking IO in certain cases. When this happens, the -/// the operation can be immediately retried. -/// -/// To signal this event, the `io::Error` inside of [`Error::WantRead`] will be constructed around -/// a `RetryError`. -/// -/// [`SSL_read`]: https://www.openssl.org/docs/manmaster/man3/SSL_read.html -/// [`SSL_write`]: https://www.openssl.org/docs/manmaster/man3/SSL_write.html -/// [`Error::WantRead`]: enum.Error.html#variant.WantRead -#[derive(Debug)] -pub struct RetryError; - -impl fmt::Display for RetryError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(error::Error::description(self)) +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.code { + ErrorCode::ZERO_RETURN => fmt.write_str("the SSL session has been shut down"), + ErrorCode::WANT_READ => match self.io_error() { + Some(_) => fmt.write_str("a nonblocking read call would have blocked"), + None => fmt.write_str("the operation should be retried"), + }, + ErrorCode::WANT_WRITE => match self.io_error() { + Some(_) => fmt.write_str("a nonblocking write call would have blocked"), + None => fmt.write_str("the operation should be retried"), + }, + ErrorCode::SYSCALL => match self.io_error() { + Some(err) => write!(fmt, "{}", err), + None => fmt.write_str("unexpected EOF"), + }, + ErrorCode::SSL => match self.ssl_error() { + Some(e) => write!(fmt, "{}", e), + None => fmt.write_str("OpenSSL error"), + }, + ErrorCode(code) => write!(fmt, "unknown error code {}", code), + } } } -impl error::Error for RetryError { - fn description(&self) -> &str { - "operation must be retried" +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self.cause { + Some(InnerError::Io(ref e)) => Some(e), + Some(InnerError::Ssl(ref e)) => Some(e), + None => None, + } } } /// An error or intermediate state after a TLS handshake attempt. +// FIXME overhaul #[derive(Debug)] pub enum HandshakeError { /// Setup failed. SetupFailure(ErrorStack), /// The handshake failed. Failure(MidHandshakeSslStream), - /// The handshake was interrupted midway through. + /// The handshake encountered a `WouldBlock` error midway through. /// /// This error will never be returned for blocking streams. - // FIXME change to WouldBlock - Interrupted(MidHandshakeSslStream), + WouldBlock(MidHandshakeSslStream), } -impl StdError for HandshakeError { - fn description(&self) -> &str { - match *self { - HandshakeError::SetupFailure(_) => "stream setup failed", - HandshakeError::Failure(_) => "the handshake failed", - HandshakeError::Interrupted(_) => "the handshake was interrupted", - } - } - - fn cause(&self) -> Option<&StdError> { +impl StdError for HandshakeError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { match *self { HandshakeError::SetupFailure(ref e) => Some(e), - HandshakeError::Failure(ref s) | - HandshakeError::Interrupted(ref s) => Some(s.error()), + HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => Some(s.error()), } } } -impl fmt::Display for HandshakeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(StdError::description(self))?; +impl fmt::Display for HandshakeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - HandshakeError::SetupFailure(ref e) => write!(f, ": {}", e)?, - HandshakeError::Failure(ref s) | - HandshakeError::Interrupted(ref s) => { - write!(f, ": {}", s.error())?; - if let Some(err) = s.ssl().verify_result() { - write!(f, ": {}", err)?; + HandshakeError::SetupFailure(ref e) => write!(f, "stream setup failed: {}", e)?, + HandshakeError::Failure(ref s) => { + write!(f, "the handshake failed: {}", s.error())?; + let verify = s.ssl().verify_result(); + if verify != X509VerifyResult::OK { + write!(f, ": {}", verify)?; + } + } + HandshakeError::WouldBlock(ref s) => { + write!(f, "the handshake was interrupted: {}", s.error())?; + let verify = s.ssl().verify_result(); + if verify != X509VerifyResult::OK { + write!(f, ": {}", verify)?; } } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6ef3996..c8648c4 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -7,12 +7,12 @@ //! //! To connect as a client to a remote server: //! -//! ``` -//! use openssl::ssl::{SslMethod, SslConnectorBuilder}; +//! ```no_run +//! use openssl::ssl::{SslMethod, SslConnector}; //! use std::io::{Read, Write}; //! use std::net::TcpStream; //! -//! let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); +//! let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); //! //! let stream = TcpStream::connect("google.com:443").unwrap(); //! let mut stream = connector.connect("google.com", stream).unwrap(); @@ -26,30 +26,17 @@ //! To accept connections as a server from remote clients: //! //! ```no_run -//! use openssl::pkcs12::Pkcs12; -//! use openssl::ssl::{SslMethod, SslAcceptorBuilder, SslStream}; -//! use std::fs::File; -//! use std::io::{Read, Write}; +//! use openssl::ssl::{SslMethod, SslAcceptor, SslStream, SslFiletype}; //! use std::net::{TcpListener, TcpStream}; //! use std::sync::Arc; //! use std::thread; //! -//! // In this example we retrieve our keypair and certificate chain from a PKCS #12 archive, -//! // but but they can also be retrieved from, for example, individual PEM- or DER-formatted -//! // files. See the documentation for the `PKey` and `X509` types for more details. -//! let mut file = File::open("identity.pfx").unwrap(); -//! let mut pkcs12 = vec![]; -//! file.read_to_end(&mut pkcs12).unwrap(); -//! let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap(); -//! let identity = pkcs12.parse("password123").unwrap(); //! -//! let acceptor = SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(), -//! &identity.pkey, -//! &identity.cert, -//! &identity.chain) -//! .unwrap() -//! .build(); -//! let acceptor = Arc::new(acceptor); +//! let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); +//! acceptor.set_private_key_file("key.pem", SslFiletype::PEM).unwrap(); +//! acceptor.set_certificate_chain_file("certs.pem").unwrap(); +//! acceptor.check_private_key().unwrap(); +//! let acceptor = Arc::new(acceptor.build()); //! //! let listener = TcpListener::bind("0.0.0.0:8443").unwrap(); //! @@ -70,11 +57,34 @@ //! } //! } //! ``` -use ffi; +use crate::dh::{Dh, DhRef}; +#[cfg(all(ossl101, not(ossl110)))] +use crate::ec::EcKey; +use crate::ec::EcKeyRef; +use crate::error::ErrorStack; +use crate::ex_data::Index; +#[cfg(ossl111)] +use crate::hash::MessageDigest; +#[cfg(any(ossl110, libressl270))] +use crate::nid::Nid; +use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; +use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; +use crate::ssl::bio::BioMethod; +use crate::ssl::callbacks::*; +use crate::ssl::error::InnerError; +use crate::stack::{Stack, StackRef}; +use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; +use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; +#[cfg(any(ossl102, libressl261))] +use crate::x509::verify::X509VerifyParamRef; +use crate::x509::{X509Name, X509Ref, X509StoreContextRef, X509VerifyResult, X509}; +use crate::{cvt, cvt_n, cvt_p, init}; +use bitflags::bitflags; +use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; -use libc::{c_int, c_long, c_ulong, c_void}; -use libc::{c_uchar, c_uint}; -use std::any::Any; +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; use std::cmp; use std::collections::HashMap; @@ -83,178 +93,205 @@ use std::fmt; use std::io; use std::io::prelude::*; use std::marker::PhantomData; -use std::mem; +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::Mutex; - -use {cvt, cvt_n, cvt_p, init}; -use dh::{Dh, DhRef}; -use ec::EcKeyRef; -#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] -use ec::EcKey; -use x509::{X509, X509FileType, X509Name, X509Ref, X509StoreContextRef, X509VerifyError}; -use x509::store::{X509StoreBuilderRef, X509StoreRef}; -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -use x509::store::X509Store; -#[cfg(any(ossl102, ossl110))] -use verify::X509VerifyParamRef; -use pkey::PKeyRef; -use error::ErrorStack; -use ex_data::Index; -use stack::{Stack, StackRef}; -use ssl::bio::BioMethod; -use ssl::callbacks::*; - -pub use ssl::connector::{ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, - SslConnectorBuilder}; -pub use ssl::error::{Error, HandshakeError, RetryError}; +use std::sync::{Arc, Mutex}; -mod error; +pub use crate::ssl::connector::{ + ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, +}; +pub use crate::ssl::error::{Error, ErrorCode, HandshakeError}; + +mod bio; mod callbacks; mod connector; -mod bio; +mod error; #[cfg(test)] -mod tests; +mod test; + +/// Returns the OpenSSL name of a cipher corresponding to an RFC-standard cipher name. +/// +/// If the cipher has no corresponding OpenSSL name, the string `(NONE)` is returned. +/// +/// Requires OpenSSL 1.1.1 or newer. +#[corresponds(OPENSSL_cipher_name)] +#[cfg(ossl111)] +pub fn cipher_name(std_name: &str) -> &'static str { + unsafe { + ffi::init(); + + let s = CString::new(std_name).unwrap(); + let ptr = ffi::OPENSSL_cipher_name(s.as_ptr()); + CStr::from_ptr(ptr).to_str().unwrap() + } +} + +cfg_if! { + if #[cfg(ossl300)] { + type SslOptionsRepr = u64; + } else if #[cfg(boringssl)] { + type SslOptionsRepr = u32; + } else { + type SslOptionsRepr = libc::c_ulong; + } +} -// FIXME drop SSL_ prefix -// FIXME remvove flags not used in OpenSSL 1.1 bitflags! { /// Options controlling the behavior of an `SslContext`. - pub struct SslOption: c_ulong { - // FIXME remove - const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG; - // FIXME remove - const SSL_OP_NETSCAPE_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG; - // FIXME remove - const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = - ffi::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; - // FIXME remove - const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ffi::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER; - // FIXME remove - const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ffi::SSL_OP_SSLEAY_080_CLIENT_DH_BUG; - // FIXME remove - const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG; - // FIXME remove - const SSL_OP_TLS_BLOCK_PADDING_BUG = ffi::SSL_OP_TLS_BLOCK_PADDING_BUG; - - // FIXME remove? not documented anywhere - const SSL_OP_CISCO_ANYCONNECT = ffi::SSL_OP_CISCO_ANYCONNECT; - + pub struct SslOptions: SslOptionsRepr { /// Disables a countermeasure against an SSLv3/TLSv1.0 vulnerability affecting CBC ciphers. - const SSL_OP_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. - const SSL_OP_ALL = ffi::SSL_OP_ALL; + #[cfg(not(boringssl))] + const ALL = ffi::SSL_OP_ALL as SslOptionsRepr; /// Do not query the MTU. /// /// Only affects DTLS connections. - const SSL_OP_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]. /// /// Only affects DTLS connections. /// /// [RFC 4347 Section 4.2.1]: https://tools.ietf.org/html/rfc4347#section-4.2.1 - const SSL_OP_COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE; + #[cfg(not(boringssl))] + const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE as SslOptionsRepr; /// Disables the use of session tickets for session resumption. - const SSL_OP_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. - const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = - ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; + #[cfg(not(boringssl))] + const NO_SESSION_RESUMPTION_ON_RENEGOTIATION = + ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION as SslOptionsRepr; /// Disables the use of TLS compression. - const SSL_OP_NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION; + #[cfg(not(boringssl))] + 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 SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = - ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; + const 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 SSL_OP_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 SSL_OP_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 SSL_OP_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 SSL_OP_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 SSL_OP_NO_SSLV2 = ffi::SSL_OP_NO_SSLv2; + const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2 as SslOptionsRepr; /// Disables the use of SSLv3. - const SSL_OP_NO_SSLV3 = ffi::SSL_OP_NO_SSLv3; + const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3 as SslOptionsRepr; /// Disables the use of TLSv1.0. - const SSL_OP_NO_TLSV1 = ffi::SSL_OP_NO_TLSv1; + const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1 as SslOptionsRepr; /// Disables the use of TLSv1.1. - const SSL_OP_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 SSL_OP_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 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 the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - const SSL_OP_NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1; + /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer. + #[cfg(any(boringssl, ossl102, ossl110, libressl332))] + const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1 as SslOptionsRepr; /// Disables the use of DTLSv1.2. - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - const SSL_OP_NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2; + /// + /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer. + #[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. /// /// This can be used as a mask when whitelisting protocol versions. /// - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. + /// Requires OpenSSL 1.0.2 or newer. /// /// # Examples /// /// Only support TLSv1.2: /// /// ```rust - /// use openssl::ssl::{SSL_OP_NO_SSL_MASK, SSL_OP_NO_TLSV1_2}; + /// use openssl::ssl::SslOptions; /// - /// let options = SSL_OP_NO_SSL_MASK & !SSL_OP_NO_TLSV1_2; + /// let options = SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_2; /// ``` - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - const SSL_OP_NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK; + #[cfg(any(ossl102, ossl110))] + 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(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 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; } } bitflags! { /// Options controlling the behavior of an `SslContext`. - pub struct SslMode: c_long { + pub struct SslMode: SslBitType { /// Enables "short writes". /// /// Normally, a write in OpenSSL will always write out all of the requested data, even if it /// requires more than one TLS record or write to the underlying stream. This option will /// cause a write to return after writing a single TLS record instead. - const SSL_MODE_ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE; + const ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE; /// Disables a check that the data buffer has not moved between calls when operating in a - /// nonblocking context. - const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; + /// non-blocking context. + const ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; /// Enables automatic retries after TLS session events such as renegotiations or heartbeats. /// @@ -265,25 +302,19 @@ bitflags! { /// Note that `SslStream::read` and `SslStream::write` will automatically retry regardless /// of the state of this option. It only affects `SslStream::ssl_read` and /// `SslStream::ssl_write`. - const SSL_MODE_AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY; + const AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY; /// Disables automatic chain building when verifying a peer's certificate. /// /// TLS peers are responsible for sending the entire certificate chain from the leaf to a /// trusted root, but some will incorrectly not do so. OpenSSL will try to build the chain /// out of certificates it knows of, and this option will disable that behavior. - const SSL_MODE_NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN; + const NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN; /// Release memory buffers when the session does not need them. /// /// This saves ~34 KiB of memory for idle streams. - const SSL_MODE_RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS; - - // FIXME remove - #[cfg(not(libressl))] - const SSL_MODE_SEND_CLIENTHELLO_TIME = ffi::SSL_MODE_SEND_CLIENTHELLO_TIME; - #[cfg(not(libressl))] - const SSL_MODE_SEND_SERVERHELLO_TIME = ffi::SSL_MODE_SEND_SERVERHELLO_TIME; + const RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS; /// Sends the fake `TLS_FALLBACK_SCSV` cipher suite in the ClientHello message of a /// handshake. @@ -293,7 +324,7 @@ bitflags! { /// /// Do not use this unless you know what you're doing! #[cfg(not(libressl))] - const SSL_MODE_SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV; + const SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV; } } @@ -303,51 +334,170 @@ pub struct SslMethod(*const ffi::SSL_METHOD); impl SslMethod { /// Support all versions of the TLS protocol. - /// - /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method` - /// on OpenSSL 1.0.x. + #[corresponds(TLS_method)] pub fn tls() -> SslMethod { - SslMethod(compat::tls_method()) + unsafe { SslMethod(TLS_method()) } } /// Support all versions of the DTLS protocol. - /// - /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method` - /// on OpenSSL 1.0.x. + #[corresponds(DTLS_method)] pub fn dtls() -> SslMethod { - SslMethod(compat::dtls_method()) + unsafe { SslMethod(DTLS_method()) } + } + + /// Support all versions of the TLS protocol, explicitly as a client. + #[corresponds(TLS_client_method)] + pub fn tls_client() -> SslMethod { + unsafe { SslMethod(TLS_client_method()) } + } + + /// Support all versions of the TLS protocol, explicitly as a server. + #[corresponds(TLS_server_method)] + pub fn tls_server() -> SslMethod { + unsafe { SslMethod(TLS_server_method()) } } /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value. + /// + /// # Safety + /// + /// The caller must ensure the pointer is valid. pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod { SslMethod(ptr) } /// Returns a pointer to the underlying OpenSSL value. + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_ptr(&self) -> *const ffi::SSL_METHOD { self.0 } } +unsafe impl Sync for SslMethod {} +unsafe impl Send for SslMethod {} + bitflags! { - /// Options controling the behavior of certificate verification. + /// Options controlling the behavior of certificate verification. pub struct SslVerifyMode: i32 { /// Verifies that the peer's certificate is trusted. /// /// On the server side, this will cause OpenSSL to request a certificate from the client. - const SSL_VERIFY_PEER = ::ffi::SSL_VERIFY_PEER; + const PEER = ffi::SSL_VERIFY_PEER; /// Disables verification of the peer's certificate. /// /// On the server side, this will cause OpenSSL to not request a certificate from the /// client. On the client side, the certificate will be checked for validity, but the /// negotiation will continue regardless of the result of that check. - const SSL_VERIFY_NONE = ::ffi::SSL_VERIFY_NONE; + const NONE = ffi::SSL_VERIFY_NONE; /// On the server side, abort the handshake if the client did not send a certificate. /// /// This should be paired with `SSL_VERIFY_PEER`. It has no effect on the client side. - const SSL_VERIFY_FAIL_IF_NO_PEER_CERT = ::ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + const FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } +} + +#[cfg(boringssl)] +type SslBitType = c_int; +#[cfg(not(boringssl))] +type SslBitType = c_long; + +#[cfg(boringssl)] +type SslTimeTy = u64; +#[cfg(not(boringssl))] +type SslTimeTy = c_long; + +bitflags! { + /// Options controlling the behavior of session caching. + pub struct SslSessionCacheMode: SslBitType { + /// No session caching for the client or server takes place. + const OFF = ffi::SSL_SESS_CACHE_OFF; + + /// Enable session caching on the client side. + /// + /// OpenSSL has no way of identifying the proper session to reuse automatically, so the + /// application is responsible for setting it explicitly via [`SslRef::set_session`]. + /// + /// [`SslRef::set_session`]: struct.SslRef.html#method.set_session + const CLIENT = ffi::SSL_SESS_CACHE_CLIENT; + + /// Enable session caching on the server side. + /// + /// This is the default mode. + const SERVER = ffi::SSL_SESS_CACHE_SERVER; + + /// Enable session caching on both the client and server side. + const BOTH = ffi::SSL_SESS_CACHE_BOTH; + + /// Disable automatic removal of expired sessions from the session cache. + const NO_AUTO_CLEAR = ffi::SSL_SESS_CACHE_NO_AUTO_CLEAR; + + /// Disable use of the internal session cache for session lookups. + const NO_INTERNAL_LOOKUP = ffi::SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; + + /// Disable use of the internal session cache for session storage. + const NO_INTERNAL_STORE = ffi::SSL_SESS_CACHE_NO_INTERNAL_STORE; + + /// Disable use of the internal session cache for storage and lookup. + const NO_INTERNAL = ffi::SSL_SESS_CACHE_NO_INTERNAL; + } +} + +#[cfg(ossl111)] +bitflags! { + /// Which messages and under which conditions an extension should be added or expected. + pub struct ExtensionContext: c_uint { + /// This extension is only allowed in TLS + const TLS_ONLY = ffi::SSL_EXT_TLS_ONLY; + /// This extension is only allowed in DTLS + const DTLS_ONLY = ffi::SSL_EXT_DTLS_ONLY; + /// Some extensions may be allowed in DTLS but we don't implement them for it + const TLS_IMPLEMENTATION_ONLY = ffi::SSL_EXT_TLS_IMPLEMENTATION_ONLY; + /// Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is + const SSL3_ALLOWED = ffi::SSL_EXT_SSL3_ALLOWED; + /// Extension is only defined for TLS1.2 and below + const TLS1_2_AND_BELOW_ONLY = ffi::SSL_EXT_TLS1_2_AND_BELOW_ONLY; + /// Extension is only defined for TLS1.3 and above + const TLS1_3_ONLY = ffi::SSL_EXT_TLS1_3_ONLY; + /// Ignore this extension during parsing if we are resuming + const IGNORE_ON_RESUMPTION = ffi::SSL_EXT_IGNORE_ON_RESUMPTION; + const CLIENT_HELLO = ffi::SSL_EXT_CLIENT_HELLO; + /// Really means TLS1.2 or below + const TLS1_2_SERVER_HELLO = ffi::SSL_EXT_TLS1_2_SERVER_HELLO; + const TLS1_3_SERVER_HELLO = ffi::SSL_EXT_TLS1_3_SERVER_HELLO; + const TLS1_3_ENCRYPTED_EXTENSIONS = ffi::SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS; + const TLS1_3_HELLO_RETRY_REQUEST = ffi::SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST; + const TLS1_3_CERTIFICATE = ffi::SSL_EXT_TLS1_3_CERTIFICATE; + const TLS1_3_NEW_SESSION_TICKET = ffi::SSL_EXT_TLS1_3_NEW_SESSION_TICKET; + const TLS1_3_CERTIFICATE_REQUEST = ffi::SSL_EXT_TLS1_3_CERTIFICATE_REQUEST; + } +} + +/// An identifier of the format of a certificate or key file. +#[derive(Copy, Clone)] +pub struct SslFiletype(c_int); + +impl SslFiletype { + /// The PEM format. + /// + /// This corresponds to `SSL_FILETYPE_PEM`. + pub const PEM: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_PEM); + + /// The ASN1 format. + /// + /// This corresponds to `SSL_FILETYPE_ASN1`. + pub const ASN1: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_ASN1); + + /// Constructs an `SslFiletype` from a raw OpenSSL value. + pub fn from_raw(raw: c_int) -> SslFiletype { + SslFiletype(raw) + } + + /// Returns the raw OpenSSL value represented by this type. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> c_int { + self.0 } } @@ -356,51 +506,47 @@ bitflags! { pub struct StatusType(c_int); impl StatusType { + /// An OSCP status. + pub const OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp); + /// Constructs a `StatusType` from a raw OpenSSL value. pub fn from_raw(raw: c_int) -> StatusType { StatusType(raw) } /// Returns the raw OpenSSL value represented by this type. + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } -/// An OSCP status. -pub const STATUS_TYPE_OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp); +/// An identifier of a session name type. +#[derive(Copy, Clone)] +pub struct NameType(c_int); -lazy_static! { - static ref INDEXES: Mutex> = Mutex::new(HashMap::new()); - static ref SSL_INDEXES: Mutex> = Mutex::new(HashMap::new()); -} +impl NameType { + /// A host name. + pub const HOST_NAME: NameType = NameType(ffi::TLSEXT_NAMETYPE_host_name); -// Creates a static index for user data of type T -// Registers a destructor for the data which will be called -// when context is freed -fn get_callback_idx() -> c_int { - *INDEXES - .lock() - .unwrap() - .entry(TypeId::of::()) - .or_insert_with(|| get_new_idx::()) -} + /// Constructs a `StatusType` from a raw OpenSSL value. + pub fn from_raw(raw: c_int) -> StatusType { + StatusType(raw) + } -fn get_ssl_callback_idx() -> c_int { - *SSL_INDEXES - .lock() - .unwrap() - .entry(TypeId::of::()) - .or_insert_with(|| get_new_ssl_idx::()) + /// Returns the raw OpenSSL value represented by this type. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> c_int { + self.0 + } } -lazy_static! { - static ref NPN_PROTOS_IDX: c_int = get_new_idx::>(); -} +static INDEXES: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); +static SSL_INDEXES: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); +static SESSION_CTX_INDEX: OnceCell> = OnceCell::new(); -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -lazy_static! { - static ref ALPN_PROTOS_IDX: c_int = get_new_idx::>(); +fn try_get_session_ctx_index() -> Result<&'static Index, ErrorStack> { + SESSION_CTX_INDEX.get_or_try_init(Ssl::new_ex_index) } unsafe extern "C" fn free_data_box( @@ -412,68 +558,145 @@ unsafe extern "C" fn free_data_box( _argp: *mut c_void, ) { if !ptr.is_null() { - Box::::from_raw(ptr as *mut T); + let _ = Box::::from_raw(ptr as *mut T); } } -fn get_new_idx() -> c_int { - unsafe { - let idx = compat::get_new_idx(free_data_box::); - assert!(idx >= 0); - idx - } +/// An error returned from the SNI callback. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SniError(c_int); + +impl SniError { + /// Abort the handshake with a fatal alert. + pub const ALERT_FATAL: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); + + /// Send a warning alert to the client and continue the handshake. + pub const ALERT_WARNING: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_WARNING); + + pub const NOACK: SniError = SniError(ffi::SSL_TLSEXT_ERR_NOACK); } -fn get_new_ssl_idx() -> c_int { - unsafe { - let idx = compat::get_new_ssl_idx(free_data_box::); - assert!(idx >= 0); - idx - } +/// An SSL/TLS alert. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SslAlert(c_int); + +impl SslAlert { + /// Alert 112 - `unrecognized_name`. + pub const UNRECOGNIZED_NAME: SslAlert = SslAlert(ffi::SSL_AD_UNRECOGNIZED_NAME); + pub const ILLEGAL_PARAMETER: SslAlert = SslAlert(ffi::SSL_AD_ILLEGAL_PARAMETER); + pub const DECODE_ERROR: SslAlert = SslAlert(ffi::SSL_AD_DECODE_ERROR); } -/// Convert a set of byte slices into a series of byte strings encoded for SSL. Encoding is a byte -/// containing the length followed by the string. -fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec { - let mut enc = Vec::new(); - for string in strings { - let len = string.len() as u8; - if len as usize != string.len() { - // If the item does not fit, discard it - continue; - } - enc.push(len); - enc.extend(string[..len as usize].to_vec()); - } - enc +/// An error returned from an ALPN selection callback. +/// +/// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. +#[cfg(any(ossl102, libressl261))] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct AlpnError(c_int); + +#[cfg(any(ossl102, libressl261))] +impl AlpnError { + /// Terminate the handshake with a fatal alert. + /// + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(any(ossl110))] + pub const ALERT_FATAL: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); + + /// Do not select a protocol, but continue the handshake. + pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK); } -// FIXME look into this -/// An error returned from an SNI callback. -pub enum SniError { - Fatal(c_int), - Warning(c_int), - NoAck, +/// The result of a client hello callback. +/// +/// Requires OpenSSL 1.1.1 or newer. +#[cfg(ossl111)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ClientHelloResponse(c_int); + +#[cfg(ossl111)] +impl ClientHelloResponse { + /// Continue the handshake. + pub const SUCCESS: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_SUCCESS); + + /// Return from the handshake with an `ErrorCode::WANT_CLIENT_HELLO_CB` error. + pub const RETRY: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_RETRY); } -/// A builder for `SslContext`s. -pub struct SslContextBuilder(*mut ffi::SSL_CTX); +/// An SSL/TLS protocol version. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SslVersion(c_int); -unsafe impl Sync for SslContextBuilder {} -unsafe impl Send for SslContextBuilder {} +impl SslVersion { + /// SSLv3 + pub const SSL3: SslVersion = SslVersion(ffi::SSL3_VERSION); -impl Drop for SslContextBuilder { - fn drop(&mut self) { - unsafe { ffi::SSL_CTX_free(self.as_ptr()) } + /// TLSv1.0 + pub const TLS1: SslVersion = SslVersion(ffi::TLS1_VERSION); + + /// TLSv1.1 + pub const TLS1_1: SslVersion = SslVersion(ffi::TLS1_1_VERSION); + + /// TLSv1.2 + pub const TLS1_2: SslVersion = SslVersion(ffi::TLS1_2_VERSION); + + /// TLSv1.3 + /// + /// 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 SslCacheTy = i64; + type SslCacheSize = libc::c_ulong; + type MtuTy = u32; + type SizeTy = usize; + } else { + type SslCacheTy = i64; + type SslCacheSize = c_long; + type MtuTy = c_long; + type SizeTy = u32; + } +} + +/// A standard implementation of protocol selection for Application Layer Protocol Negotiation +/// (ALPN). +/// +/// `server` should contain the server's list of supported protocols and `client` the client's. They +/// must both be in the ALPN wire format. See the documentation for +/// [`SslContextBuilder::set_alpn_protos`] for details. +/// +/// It will select the first protocol supported by the server which is also supported by the client. +/// +/// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos +#[corresponds(SSL_select_next_proto)] +pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]> { + unsafe { + let mut out = ptr::null_mut(); + let mut outlen = 0; + let r = ffi::SSL_select_next_proto( + &mut out, + &mut outlen, + server.as_ptr(), + server.len() as c_uint, + client.as_ptr(), + client.len() as c_uint, + ); + if r == ffi::OPENSSL_NPN_NEGOTIATED { + Some(slice::from_raw_parts(out as *const u8, outlen as usize)) + } else { + None + } } } +/// A builder for `SslContext`s. +pub struct SslContextBuilder(SslContext); + impl SslContextBuilder { /// Creates a new `SslContextBuilder`. - /// - /// This corresponds to [`SSL_CTX_new`]. - /// - /// [`SSL_CTX_new`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_new.html + #[corresponds(SSL_CTX_new)] pub fn new(method: SslMethod) -> Result { unsafe { init(); @@ -484,20 +707,21 @@ impl SslContextBuilder { } /// Creates an `SslContextBuilder` from a pointer to a raw OpenSSL value. + /// + /// # Safety + /// + /// The caller must ensure that the pointer is valid and uniquely owned by the builder. pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder { - SslContextBuilder(ctx) + SslContextBuilder(SslContext::from_ptr(ctx)) } /// Returns a pointer to the raw OpenSSL value. pub fn as_ptr(&self) -> *mut ffi::SSL_CTX { - self.0 + self.0.as_ptr() } /// Configures the certificate verification method for new connections. - /// - /// This corresponds to [`SSL_CTX_set_verify`]. - /// - /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html + #[corresponds(SSL_CTX_set_verify)] pub fn set_verify(&mut self, mode: SslVerifyMode) { unsafe { ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, None); @@ -510,22 +734,13 @@ impl SslContextBuilder { /// The callback is passed a boolean indicating if OpenSSL's internal verification succeeded as /// well as a reference to the `X509StoreContext` which can be used to examine the certificate /// chain. It should return a boolean indicating if verification succeeded. - /// - /// This corresponds to [`SSL_CTX_set_verify`]. - /// - /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html + #[corresponds(SSL_CTX_set_verify)] pub fn set_verify_callback(&mut self, mode: SslVerifyMode, verify: F) where - // FIXME should take a mutable reference to the store - F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send, + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { - let verify = Box::new(verify); - ffi::SSL_CTX_set_ex_data( - self.as_ptr(), - get_callback_idx::(), - mem::transmute(verify), - ); + self.set_ex_data(SslContext::cached_ex_index::(), verify); ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::)); } } @@ -537,34 +752,34 @@ impl SslContextBuilder { /// /// Obtain the server name with the `servername` method and then set the corresponding context /// with `set_ssl_context` - /// - /// This corresponds to [`SSL_CTX_set_tlsext_servername_callback`]. - /// - /// [`SSL_CTX_set_tlsext_servername_callback`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_tlsext_servername_callback.html + #[corresponds(SSL_CTX_set_tlsext_servername_callback)] + // FIXME tlsext prefix? pub fn set_servername_callback(&mut self, callback: F) where - F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send, { unsafe { - let callback = Box::new(callback); - ffi::SSL_CTX_set_ex_data( + // The SNI callback is somewhat unique in that the callback associated with the original + // context associated with an SSL can be used even if the SSL's context has been swapped + // out. When that happens, we wouldn't be able to look up the callback's state in the + // context's ex data. Instead, pass the pointer directly as the servername arg. It's + // still stored in ex data to manage the lifetime. + let arg = self.set_ex_data_inner(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_tlsext_servername_arg(self.as_ptr(), arg); + #[cfg(boringssl)] + ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(raw_sni::)); + #[cfg(not(boringssl))] + ffi::SSL_CTX_set_tlsext_servername_callback__fixed_rust( self.as_ptr(), - get_callback_idx::(), - mem::transmute(callback), + Some(raw_sni::), ); - let f: extern "C" fn(_, _, _) -> _ = raw_sni::; - let f: extern "C" fn() = mem::transmute(f); - ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(f)); } } /// Sets the certificate verification depth. /// /// If the peer's certificate chain is longer than this value, verification will fail. - /// - /// This corresponds to [`SSL_CTX_set_verify_depth`]. - /// - /// [`SSL_CTX_set_verify_depth`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify_depth.html + #[corresponds(SSL_CTX_set_verify_depth)] pub fn set_verify_depth(&mut self, depth: u32) { unsafe { ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int); @@ -573,57 +788,53 @@ impl SslContextBuilder { /// Sets a custom certificate store for verifying peer certificates. /// - /// Requires the `v102` feature and OpenSSL 1.0.2, or the `v110` feature and OpenSSL 1.1.0. - /// - /// This corresponds to [`SSL_CTX_set0_verify_cert_store`]. - /// - /// [`SSL_CTX_set0_verify_cert_store`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set0_verify_cert_store.html - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(SSL_CTX_set0_verify_cert_store)] + #[cfg(ossl102)] pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { unsafe { let ptr = cert_store.as_ptr(); - cvt(ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) - as c_int)?; + cvt(ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) as c_int)?; mem::forget(cert_store); Ok(()) } } + /// Replaces the context's certificate store. + #[corresponds(SSL_CTX_set_cert_store)] + pub fn set_cert_store(&mut self, cert_store: X509Store) { + unsafe { + ffi::SSL_CTX_set_cert_store(self.as_ptr(), cert_store.as_ptr()); + mem::forget(cert_store); + } + } + /// Controls read ahead behavior. /// /// If enabled, OpenSSL will read as much data as is available from the underlying stream, /// instead of a single record at a time. /// /// It has no effect when used with DTLS. - /// - /// This corresponds to [`SSL_CTX_set_read_ahead`]. - /// - /// [`SSL_CTX_set_read_ahead`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_read_ahead.html + #[corresponds(SSL_CTX_set_read_ahead)] pub fn set_read_ahead(&mut self, read_ahead: bool) { unsafe { - ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as c_long); + ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as SslBitType); } } /// Sets the mode used by the context, returning the previous mode. - /// - /// This corresponds to [`SSL_CTX_set_mode`]. - /// - /// [`SSL_CTX_set_mode`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_mode.html + #[corresponds(SSL_CTX_set_mode)] pub fn set_mode(&mut self, mode: SslMode) -> SslMode { unsafe { - let mode = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits()); - SslMode::from_bits(mode).unwrap() + let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits() as MtuTy) as SslBitType; + SslMode { bits } } } /// Sets the parameters to be used during ephemeral Diffie-Hellman key exchange. - /// - /// This corresponds to [`SSL_CTX_set_tmp_dh`]. - /// - /// [`SSL_CTX_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tmp_dh.html - pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { + #[corresponds(SSL_CTX_set_tmp_dh)] + pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } @@ -633,35 +844,25 @@ impl SslContextBuilder { /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean /// indicating if the selected cipher is export-grade, and the key length. The export and key /// length options are archaic and should be ignored in almost all cases. - /// - /// This corresponds to [`SSL_CTX_set_tmp_dh_callback`]. - /// - /// [`SSL_CTX_set_tmp_dh_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tmp_dh.html + #[corresponds(SSL_CTX_set_tmp_dh_callback)] pub fn set_tmp_dh_callback(&mut self, callback: F) where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { - let callback = Box::new(callback); - ffi::SSL_CTX_set_ex_data( - self.as_ptr(), - get_callback_idx::(), - Box::into_raw(callback) as *mut c_void, - ); - let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_dh::; - ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), f); + self.set_ex_data(SslContext::cached_ex_index::(), callback); + + #[cfg(not(boringssl))] + ffi::SSL_CTX_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh::)); + #[cfg(boringssl)] + ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh::)); } } /// Sets the parameters to be used during ephemeral elliptic curve Diffie-Hellman key exchange. - /// - /// This corresponds to `SSL_CTX_set_tmp_ecdh`. - pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) - as c_int) - .map(|_| ()) - } + #[corresponds(SSL_CTX_set_tmp_ecdh)] + pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } /// Sets the callback which will generate parameters to be used during ephemeral elliptic curve @@ -671,23 +872,17 @@ impl SslContextBuilder { /// indicating if the selected cipher is export-grade, and the key length. The export and key /// length options are archaic and should be ignored in almost all cases. /// - /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. - /// - /// This corresponds to `SSL_CTX_set_tmp_ecdh_callback`. - #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] + /// Requires OpenSSL 1.0.1 or 1.0.2. + #[corresponds(SSL_CTX_set_tmp_ecdh_callback)] + #[cfg(all(ossl101, not(ossl110)))] + #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { - let callback = Box::new(callback); - ffi::SSL_CTX_set_ex_data( - self.as_ptr(), - get_callback_idx::(), - Box::into_raw(callback) as *mut c_void, - ); - let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_ecdh::; - ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), f); + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_tmp_ecdh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_ecdh::)); } } @@ -695,10 +890,7 @@ impl SslContextBuilder { /// /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables /// if present, or defaults specified at OpenSSL build time otherwise. - /// - /// This corresponds to [`SSL_CTX_set_default_verify_paths`]. - /// - /// [`SSL_CTX_set_default_verify_paths`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_default_verify_paths.html + #[corresponds(SSL_CTX_set_default_verify_paths)] pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_default_verify_paths(self.as_ptr())).map(|_| ()) } } @@ -706,10 +898,7 @@ impl SslContextBuilder { /// Loads trusted root certificates from a file. /// /// The file should contain a sequence of PEM-formatted CA certificates. - /// - /// This corresponds to [`SSL_CTX_set_default_verify_file`]. - /// - /// [`SSL_CTX_set_default_verify_file`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_default_verify_paths.html + #[corresponds(SSL_CTX_load_verify_locations)] pub fn set_ca_file>(&mut self, file: P) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { @@ -717,7 +906,8 @@ impl SslContextBuilder { self.as_ptr(), file.as_ptr() as *const _, ptr::null(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -725,10 +915,7 @@ impl SslContextBuilder { /// /// The CA certificates must still be added to the trust root - they are not automatically set /// as trusted by this method. - /// - /// This corresponds to [`SSL_CTX_set_client_CA_list`]. - /// - /// [`SSL_CTX_set_client_CA_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_client_CA_list.html + #[corresponds(SSL_CTX_set_client_CA_list)] pub fn set_client_ca_list(&mut self, list: Stack) { unsafe { ffi::SSL_CTX_set_client_CA_list(self.as_ptr(), list.as_ptr()); @@ -736,26 +923,31 @@ impl SslContextBuilder { } } + /// 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)] + 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(|_| ()) } + } + /// Set the context identifier for sessions. /// /// This value identifies the server's session cache to clients, telling them when they're - /// able to reuse sessions. It should be be set to a unique value per server, unless multiple + /// able to reuse sessions. It should be set to a unique value per server, unless multiple /// servers share a session cache. /// /// This value should be set when using client certificates, or each request will fail its /// handshake and need to be restarted. - /// - /// This corresponds to [`SSL_CTX_set_session_id_context`]. - /// - /// [`SSL_CTX_set_session_id_context`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_session_id_context.html + #[corresponds(SSL_CTX_set_session_id_context)] pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(sid_ctx.len() <= c_uint::max_value() as usize); cvt(ffi::SSL_CTX_set_session_id_context( self.as_ptr(), sid_ctx.as_ptr(), - sid_ctx.len() as c_uint, - )).map(|_| ()) + sid_ctx.len() as SizeTy, + )) + .map(|_| ()) } } @@ -764,14 +956,11 @@ impl SslContextBuilder { /// Only a single certificate will be loaded - use `add_extra_chain_cert` to add the remainder /// of the certificate chain, or `set_certificate_chain_file` to load the entire chain from a /// single file. - /// - /// This corresponds to [`SSL_CTX_use_certificate_file`]. - /// - /// [`SSL_CTX_use_certificate_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + #[corresponds(SSL_CTX_use_certificate_file)] pub fn set_certificate_file>( &mut self, file: P, - file_type: X509FileType, + file_type: SslFiletype, ) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { @@ -779,7 +968,8 @@ impl SslContextBuilder { self.as_ptr(), file.as_ptr() as *const _, file_type.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -788,10 +978,7 @@ impl SslContextBuilder { /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf /// certificate, and the remainder forming the chain of certificates up to and including the /// trusted root certificate. - /// - /// This corresponds to [`SSL_CTX_use_certificate_chain_file`]. - /// - /// [`SSL_CTX_use_certificate_chain_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + #[corresponds(SSL_CTX_use_certificate_chain_file)] pub fn set_certificate_chain_file>( &mut self, file: P, @@ -801,17 +988,15 @@ impl SslContextBuilder { cvt(ffi::SSL_CTX_use_certificate_chain_file( self.as_ptr(), file.as_ptr() as *const _, - )).map(|_| ()) + )) + .map(|_| ()) } } /// Sets the leaf certificate. /// /// Use `add_extra_chain_cert` to add the remainder of the certificate chain. - /// - /// This corresponds to [`SSL_CTX_use_certificate`]. - /// - /// [`SSL_CTX_use_certificate`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + #[corresponds(SSL_CTX_use_certificate)] pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } @@ -820,10 +1005,7 @@ impl SslContextBuilder { /// /// This chain should contain all certificates necessary to go from the certificate specified by /// `set_certificate` to a trusted root. - /// - /// This corresponds to [`SSL_CTX_add_extra_chain_cert`]. - /// - /// [`SSL_CTX_add_extra_chain_cert`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html + #[corresponds(SSL_CTX_add_extra_chain_cert)] pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)?; @@ -833,14 +1015,11 @@ impl SslContextBuilder { } /// Loads the private key from a file. - /// - /// This corresponds to [`SSL_CTX_use_PrivateKey_file`]. - /// - /// [`SSL_CTX_use_PrivateKey_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html + #[corresponds(SSL_CTX_use_PrivateKey_file)] pub fn set_private_key_file>( &mut self, file: P, - file_type: X509FileType, + file_type: SslFiletype, ) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { @@ -848,189 +1027,278 @@ impl SslContextBuilder { self.as_ptr(), file.as_ptr() as *const _, file_type.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Sets the private key. - /// - /// This corresponds to [`SSL_CTX_use_PrivateKey`]. - /// - /// [`SSL_CTX_use_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html - pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { + #[corresponds(SSL_CTX_use_PrivateKey)] + pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + T: HasPrivate, + { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } } - /// Sets the list of supported ciphers. + /// Sets the list of supported ciphers for protocols before TLSv1.3. /// - /// See `man 1 ciphers` for details on the format. + /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3. /// - /// This corresponds to [`SSL_CTX_set_cipher_list`]. + /// See [`ciphers`] for details on the format. /// - /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_ciphers.html + /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html + #[corresponds(SSL_CTX_set_cipher_list)] pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { cvt(ffi::SSL_CTX_set_cipher_list( self.as_ptr(), cipher_list.as_ptr() as *const _, - )).map(|_| ()) + )) + .map(|_| ()) } } - /// Enables ECDHE key exchange with an automatically chosen curve list. + /// Sets the list of supported ciphers for the TLSv1.3 protocol. /// - /// Requires the `v102` feature and OpenSSL 1.0.2. + /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3. /// - /// This corresponds to [`SSL_CTX_set_ecdh_auto`]. + /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of + /// preference. /// - /// [`SSL_CTX_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ecdh_auto.html - #[cfg(all(feature = "v102", any(ossl102, libressl)))] - pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { - self._set_ecdh_auto(onoff) + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_CTX_set_ciphersuites)] + #[cfg(any(ossl111, libressl340))] + pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_set_ciphersuites( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )) + .map(|_| ()) + } } - #[cfg(any(ossl102, libressl))] - fn _set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { + /// Enables ECDHE key exchange with an automatically chosen curve list. + /// + /// Requires OpenSSL 1.0.2. + #[corresponds(SSL_CTX_set_ecdh_auto)] + #[cfg(any(libressl, all(ossl102, not(ossl110))))] + pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } /// Sets the options used by the context, returning the old set. /// - /// This corresponds to [`SSL_CTX_set_options`]. + /// # Note /// - /// [`SSL_CTX_set_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html - pub fn set_options(&mut self, option: SslOption) -> SslOption { - let ret = unsafe { compat::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; - SslOption::from_bits(ret).unwrap() + /// This *enables* the specified options, but does not disable unspecified options. Use + /// `clear_options` for that. + #[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 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 SslOptionsRepr; + SslOptions { bits } + } + + /// Clears the options used by the context, returning the old set. + #[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 SslOptionsRepr; + SslOptions { bits } + } + + /// Sets the minimum supported protocol version. /// - /// This corresponds to [`SSL_CTX_get_options`]. + /// A value of `None` will enable protocol versions down the the lowest version supported by + /// OpenSSL. /// - /// [`SSL_CTX_get_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html - pub fn options(&self) -> SslOption { - let ret = unsafe { compat::SSL_CTX_get_options(self.as_ptr()) }; - SslOption::from_bits(ret).unwrap() + /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_CTX_set_min_proto_version)] + #[cfg(any(ossl110, libressl261))] + pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_CTX_set_min_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } } - /// Clears the options used by the context, returning the old set. + /// Sets the maximum supported protocol version. /// - /// This corresponds to [`SSL_CTX_clear_options`]. + /// A value of `None` will enable protocol versions down the the highest version supported by + /// OpenSSL. /// - /// [`SSL_CTX_clear_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html - pub fn clear_options(&mut self, option: SslOption) -> SslOption { - let ret = unsafe { compat::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; - SslOption::from_bits(ret).unwrap() + /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_CTX_set_max_proto_version)] + #[cfg(any(ossl110, libressl261))] + pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_CTX_set_max_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } } - /// Set the protocols to be used during Next Protocol Negotiation (the protocols - /// supported by the application). - // FIXME overhaul - #[cfg(not(any(libressl261, libressl262, libressl26x)))] - pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) -> Result<(), ErrorStack> { - // Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL - // APIs -- a list of length-prefixed strings. - let protocols: Box> = Box::new(ssl_encode_byte_strings(protocols)); + /// Gets the minimum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the lowest version supported by + /// OpenSSL are enabled. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + #[corresponds(SSL_CTX_get_min_proto_version)] + #[cfg(any(ossl110g, libressl270))] + pub fn min_proto_version(&mut self) -> Option { + unsafe { + let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } + /// Gets the maximum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the highest version supported by + /// OpenSSL are enabled. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + #[corresponds(SSL_CTX_get_max_proto_version)] + #[cfg(any(ossl110g, libressl270))] + pub fn max_proto_version(&mut self) -> Option { unsafe { - // Attach the protocol list to the OpenSSL context structure, - // so that we can refer to it within the callback. - cvt(ffi::SSL_CTX_set_ex_data( - self.as_ptr(), - *NPN_PROTOS_IDX, - Box::into_raw(protocols) as *mut c_void, - ))?; - // Now register the callback that performs the default protocol - // matching based on the client-supported list of protocols that - // has been saved. - ffi::SSL_CTX_set_next_proto_select_cb( - self.as_ptr(), - raw_next_proto_select_cb, - ptr::null_mut(), - ); - // Also register the callback to advertise these protocols, if a server socket is - // created with the context. - ffi::SSL_CTX_set_next_protos_advertised_cb( - self.as_ptr(), - raw_next_protos_advertise_cb, - ptr::null_mut(), - ); - Ok(()) + let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } } } - /// Set the protocols to be used during ALPN (application layer protocol negotiation). - /// If this is a server, these are the protocols we report to the client. - /// If this is a client, these are the protocols we try to match with those reported by the - /// server. + /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN). /// - /// Note that ordering of the protocols controls the priority with which they are chosen. + /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol + /// names prefixed by their byte length. For example, the protocol list consisting of `spdy/1` + /// and `http/1.1` is encoded as `b"\x06spdy/1\x08http/1.1"`. The protocols are ordered by + /// preference. /// - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - // FIXME overhaul - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) -> Result<(), ErrorStack> { - let protocols: Box> = Box::new(ssl_encode_byte_strings(protocols)); + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_CTX_set_alpn_protos)] + #[cfg(any(ossl102, libressl261))] + pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { - // Set the context's internal protocol list for use if we are a server + assert!(protocols.len() <= c_uint::max_value() as usize); let r = ffi::SSL_CTX_set_alpn_protos( self.as_ptr(), protocols.as_ptr(), protocols.len() as c_uint, ); // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D: - if r != 0 { - return Err(ErrorStack::get()); + if r == 0 { + Ok(()) + } else { + Err(ErrorStack::get()) } + } + } - // Rather than use the argument to the callback to contain our data, store it in the - // ssl ctx's ex_data so that we can configure a function to free it later. In the - // future, it might make sense to pull this into our internal struct Ssl instead of - // leaning on openssl and using function pointers. - cvt(ffi::SSL_CTX_set_ex_data( - self.as_ptr(), - *ALPN_PROTOS_IDX, - Box::into_raw(protocols) as *mut c_void, - ))?; - - // Now register the callback that performs the default protocol - // matching based on the client-supported list of protocols that - // has been saved. - ffi::SSL_CTX_set_alpn_select_cb(self.as_ptr(), raw_alpn_select_cb, ptr::null_mut()); + /// Enables the DTLS extension "use_srtp" as defined in RFC5764. + #[corresponds(SSL_CTX_set_tlsext_use_srtp)] + pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { + unsafe { + let cstr = CString::new(protocols).unwrap(); - Ok(()) + let r = ffi::SSL_CTX_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr()); + // fun fact, set_tlsext_use_srtp has a reversed return code D: + if r == 0 { + Ok(()) + } else { + Err(ErrorStack::get()) + } } } - /// Checks for consistency between the private key and certificate. + /// Sets the callback used by a server to select a protocol for Application Layer Protocol + /// Negotiation (ALPN). + /// + /// The callback is provided with the client's protocol list in ALPN wire format. See the + /// documentation for [`SslContextBuilder::set_alpn_protos`] for details. It should return one + /// of those protocols on success. The [`select_next_proto`] function implements the standard + /// protocol selection algorithm. /// - /// This corresponds to [`SSL_CTX_check_private_key`]. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// - /// [`SSL_CTX_check_private_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_check_private_key.html + /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos + /// [`select_next_proto`]: fn.select_next_proto.html + #[corresponds(SSL_CTX_set_alpn_select_cb)] + #[cfg(any(ossl102, libressl261))] + pub fn set_alpn_select_callback(&mut self, callback: F) + where + F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_alpn_select_cb__fixed_rust( + self.as_ptr(), + Some(callbacks::raw_alpn_select::), + ptr::null_mut(), + ); + } + } + + /// Checks for consistency between the private key and certificate. + #[corresponds(SSL_CTX_check_private_key)] pub fn check_private_key(&self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) } } /// Returns a shared reference to the context's certificate store. - /// - /// This corresponds to [`SSL_CTX_get_cert_store`]. - /// - /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + #[corresponds(SSL_CTX_get_cert_store)] pub fn cert_store(&self) -> &X509StoreBuilderRef { unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } /// Returns a mutable reference to the context's certificate store. - /// - /// This corresponds to [`SSL_CTX_get_cert_store`]. - /// - /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + #[corresponds(SSL_CTX_get_cert_store)] pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef { unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } + /// Returns a reference to the X509 verification configuration. + /// + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(SSL_CTX_get0_param)] + #[cfg(any(ossl102, libressl261))] + pub fn verify_param(&self) -> &X509VerifyParamRef { + unsafe { X509VerifyParamRef::from_ptr(ffi::SSL_CTX_get0_param(self.as_ptr())) } + } + + /// Returns a mutable reference to the X509 verification configuration. + /// + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(SSL_CTX_get0_param)] + #[cfg(any(ossl102, libressl261))] + pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { + unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_CTX_get0_param(self.as_ptr())) } + } + /// Sets the callback dealing with OCSP stapling. /// /// On the client side, this callback is responsible for validating the OCSP status response @@ -1039,29 +1307,22 @@ impl SslContextBuilder { /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be /// terminated. /// - /// On the server side, this callback is resopnsible for setting the OCSP status response to be + /// On the server side, this callback is responsible for setting the OCSP status response to be /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and /// `Ok(false)` indicates that the status should not be returned to the client. - /// - /// This corresponds to [`SSL_CTX_set_tlsext_status_cb`]. - /// - /// [`SSL_CTX_set_tlsext_status_cb`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tlsext_status_cb.html + #[corresponds(SSL_CTX_set_tlsext_status_cb)] pub fn set_status_callback(&mut self, callback: F) -> Result<(), ErrorStack> where - F: Fn(&mut SslRef) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, { unsafe { - let callback = Box::new(callback); - ffi::SSL_CTX_set_ex_data( - self.as_ptr(), - get_callback_idx::(), - Box::into_raw(callback) as *mut c_void, - ); - let f: unsafe extern "C" fn(_, _) -> _ = raw_tlsext_status::; - cvt(ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(f)) - as c_int) - .map(|_| ()) + self.set_ex_data(SslContext::cached_ex_index::(), callback); + cvt( + ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::)) + as c_int, + ) + .map(|_| ()) } } @@ -1070,27 +1331,215 @@ impl SslContextBuilder { /// The callback will be called with the SSL context, an identity hint if one was provided /// by the server, a mutable slice for each of the identity and pre-shared key bytes. The /// identity must be written as a null-terminated C string. - /// - /// This corresponds to [`SSL_CTX_set_psk_client_callback`]. - /// - /// [`SSL_CTX_set_psk_client_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_psk_client_callback.html + #[corresponds(SSL_CTX_set_psk_client_callback)] + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + pub fn set_psk_client_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + + 'static + + Sync + + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_client_psk::)); + } + } + + #[deprecated(since = "0.10.10", note = "renamed to `set_psk_client_callback`")] #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn set_psk_callback(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result - + Any + 'static + Sync + Send, + { + self.set_psk_client_callback(callback) + } + + /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server. + /// + /// The callback will be called with the SSL context, an identity provided by the client, + /// and, a mutable slice for the pre-shared key bytes. The callback returns the number of + /// bytes in the pre-shared key. + #[corresponds(SSL_CTX_set_psk_server_callback)] + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + pub fn set_psk_server_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result + + 'static + + Sync + + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_psk_server_callback(self.as_ptr(), Some(raw_server_psk::)); + } + } + + /// Sets the callback which is called when new sessions are negotiated. + /// + /// This can be used by clients to implement session caching. While in TLSv1.2 the session is + /// available to access via [`SslRef::session`] immediately after the handshake completes, this + /// is not the case for TLSv1.3. There, a session is not generally available immediately, and + /// the server may provide multiple session tokens to the client over a single session. The new + /// session callback is a portable way to deal with both cases. + /// + /// Note that session caching must be enabled for the callback to be invoked, and it defaults + /// off for clients. [`set_session_cache_mode`] controls that behavior. + /// + /// [`SslRef::session`]: struct.SslRef.html#method.session + /// [`set_session_cache_mode`]: #method.set_session_cache_mode + #[corresponds(SSL_CTX_sess_set_new_cb)] + pub fn set_new_session_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::)); + } + } + + /// Sets the callback which is called when sessions are removed from the context. + /// + /// Sessions can be removed because they have timed out or because they are considered faulty. + #[corresponds(SSL_CTX_sess_set_remove_cb)] + pub fn set_remove_session_callback(&mut self, callback: F) + where + F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_sess_set_remove_cb( + self.as_ptr(), + Some(callbacks::raw_remove_session::), + ); + } + } + + /// Sets the callback which is called when a client proposed to resume a session but it was not + /// found in the internal cache. + /// + /// The callback is passed a reference to the session ID provided by the client. It should + /// return the session corresponding to that ID if available. This is only used for servers, not + /// clients. + /// + /// # Safety + /// + /// The returned `SslSession` must not be associated with a different `SslContext`. + #[corresponds(SSL_CTX_sess_set_get_cb)] + pub unsafe fn set_get_session_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, + { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::)); + } + + /// Sets the TLS key logging callback. + /// + /// The callback is invoked whenever TLS key material is generated, and is passed a line of NSS + /// SSLKEYLOGFILE-formatted text. This can be used by tools like Wireshark to decrypt message + /// traffic. The line does not contain a trailing newline. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CTX_set_keylog_callback)] + #[cfg(ossl111)] + pub fn set_keylog_callback(&mut self, callback: F) + where + F: Fn(&SslRef, &str) + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::)); + } + } + + /// Sets the session caching mode use for connections made with the context. + /// + /// Returns the previous session caching mode. + #[corresponds(SSL_CTX_set_session_cache_mode)] + pub fn set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode { + unsafe { + let bits = ffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode.bits()); + SslSessionCacheMode { bits } + } + } + + /// Sets the callback for generating an application cookie for TLS1.3 + /// stateless handshakes. + /// + /// The callback will be called with the SSL context and a slice into which the cookie + /// should be written. The callback should return the number of bytes written. + #[corresponds(SSL_CTX_set_stateless_cookie_generate_cb)] + #[cfg(ossl111)] + pub fn set_stateless_cookie_generate_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { - let callback = Box::new(callback); - ffi::SSL_CTX_set_ex_data( + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_stateless_cookie_generate_cb( self.as_ptr(), - get_callback_idx::(), - mem::transmute(callback), + Some(raw_stateless_cookie_generate::), ); - ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_psk::)) + } + } + + /// Sets the callback for verifying an application cookie for TLS1.3 + /// stateless handshakes. + /// + /// The callback will be called with the SSL context and the cookie supplied by the + /// client. It should return true if and only if the cookie is valid. + /// + /// Note that the OpenSSL implementation independently verifies the integrity of + /// application cookies using an HMAC before invoking the supplied callback. + #[corresponds(SSL_CTX_set_stateless_cookie_verify_cb)] + #[cfg(ossl111)] + pub fn set_stateless_cookie_verify_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_stateless_cookie_verify_cb( + self.as_ptr(), + Some(raw_stateless_cookie_verify::), + ) + } + } + + /// Sets the callback for generating a DTLSv1 cookie + /// + /// The callback will be called with the SSL context and a slice into which the cookie + /// should be written. The callback should return the number of bytes written. + #[corresponds(SSL_CTX_set_cookie_generate_cb)] + #[cfg(not(boringssl))] + pub fn set_cookie_generate_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::)); + } + } + + /// Sets the callback for verifying a DTLSv1 cookie + /// + /// The callback will be called with the SSL context and the cookie supplied by the + /// client. It should return true if and only if the cookie is valid. + #[corresponds(SSL_CTX_set_cookie_verify_cb)] + #[cfg(not(boringssl))] + pub fn set_cookie_verify_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::)); } } @@ -1098,30 +1547,163 @@ impl SslContextBuilder { /// /// This can be used to provide data to callbacks registered with the context. Use the /// `SslContext::new_ex_index` method to create an `Index`. + #[corresponds(SSL_CTX_set_ex_data)] + pub fn set_ex_data(&mut self, index: Index, data: T) { + self.set_ex_data_inner(index, data); + } + + fn set_ex_data_inner(&mut self, index: Index, data: T) -> *mut c_void { + unsafe { + let data = Box::into_raw(Box::new(data)) as *mut c_void; + ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data); + data + } + } + + /// Adds a custom extension for a TLS/DTLS client or server for all supported protocol versions. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CTX_add_custom_ext)] + #[cfg(ossl111)] + pub fn add_custom_ext( + &mut self, + ext_type: u16, + context: ExtensionContext, + add_cb: AddFn, + parse_cb: ParseFn, + ) -> Result<(), ErrorStack> + where + AddFn: Fn( + &mut SslRef, + ExtensionContext, + Option<(usize, &X509Ref)>, + ) -> Result, SslAlert> + + 'static + + Sync + + Send, + T: AsRef<[u8]> + 'static + Sync + Send, + ParseFn: Fn( + &mut SslRef, + ExtensionContext, + &[u8], + Option<(usize, &X509Ref)>, + ) -> Result<(), SslAlert> + + 'static + + Sync + + Send, + { + let ret = unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), add_cb); + self.set_ex_data(SslContext::cached_ex_index::(), parse_cb); + + ffi::SSL_CTX_add_custom_ext( + self.as_ptr(), + ext_type as c_uint, + context.bits(), + Some(raw_custom_ext_add::), + Some(raw_custom_ext_free::), + ptr::null_mut(), + Some(raw_custom_ext_parse::), + ptr::null_mut(), + ) + }; + if ret == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + + /// Sets the maximum amount of early data that will be accepted on incoming connections. /// - /// This corresponds to [`SSL_CTX_set_ex_data`]. + /// Defaults to 0. /// - /// [`SSL_CTX_set_ex_data`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ex_data.html - pub fn set_ex_data(&mut self, index: Index, data: T) { + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_CTX_set_max_early_data)] + #[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(()) + } else { + Err(ErrorStack::get()) + } + } + + /// Sets a callback which will be invoked just after the client's hello message is received. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CTX_set_client_hello_cb)] + #[cfg(ossl111)] + pub fn set_client_hello_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &mut SslAlert) -> Result + + 'static + + Sync + + Send, + { unsafe { - let data = Box::new(data); - ffi::SSL_CTX_set_ex_data( + let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_client_hello_cb( self.as_ptr(), - index.as_raw(), - Box::into_raw(data) as *mut c_void, + Some(callbacks::raw_client_hello::), + ptr, ); } } + /// Sets the context's session cache size limit, returning the previous limit. + /// + /// A value of 0 means that the cache size is unbounded. + #[corresponds(SSL_CTX_sess_set_cache_size)] + #[allow(clippy::useless_conversion)] + pub fn set_session_cache_size(&mut self, size: i32) -> i64 { + unsafe { + ffi::SSL_CTX_sess_set_cache_size(self.as_ptr(), size as SslCacheSize) as SslCacheTy + } + } + + /// Sets the context's supported signature algorithms. + /// + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(SSL_CTX_set1_sigalgs_list)] + #[cfg(ossl102)] + pub fn set_sigalgs_list(&mut self, sigalgs: &str) -> Result<(), ErrorStack> { + let sigalgs = CString::new(sigalgs).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_set1_sigalgs_list(self.as_ptr(), sigalgs.as_ptr()) as c_int) + .map(|_| ()) + } + } + + /// Sets the context's supported elliptic curve groups. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 2.5.1 or newer. + #[corresponds(SSL_CTX_set1_groups_list)] + #[cfg(any(ossl111, libressl251))] + pub fn set_groups_list(&mut self, groups: &str) -> Result<(), ErrorStack> { + let groups = CString::new(groups).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_set1_groups_list(self.as_ptr(), groups.as_ptr()) as c_int).map(|_| ()) + } + } + + /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CTX_set_num_tickets)] + #[cfg(ossl111)] + pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { - let ctx = SslContext(self.0); - mem::forget(self); - ctx + self.0 } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::SSL_CTX; fn drop = ffi::SSL_CTX_free; @@ -1137,13 +1719,18 @@ foreign_type! { pub struct SslContextRef; } -unsafe impl Send for SslContext {} -unsafe impl Sync for SslContext {} - impl Clone for SslContext { fn clone(&self) -> Self { + (**self).to_owned() + } +} + +impl ToOwned for SslContextRef { + type Owned = SslContext; + + fn to_owned(&self) -> Self::Owned { unsafe { - compat::SSL_CTX_up_ref(self.as_ptr()); + SSL_CTX_up_ref(self.as_ptr()); SslContext::from_ptr(self.as_ptr()) } } @@ -1151,7 +1738,7 @@ impl Clone for SslContext { // TODO: add useful info here impl fmt::Debug for SslContext { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "SslContext") } } @@ -1166,87 +1753,80 @@ impl SslContext { /// /// Each invocation of this function is guaranteed to return a distinct index. These can be used /// to store data in the context that can be retrieved later by callbacks, for example. - /// - /// This corresponds to [`SSL_CTX_get_ex_new_index`]. - /// - /// [`SSL_CTX_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_get_ex_new_index.html + #[corresponds(SSL_CTX_get_ex_new_index)] pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, { unsafe { ffi::init(); - let idx = cvt_n(compat::get_new_idx(free_data_box::))?; + #[cfg(boringssl)] + let idx = cvt_n(get_new_idx(Some(free_data_box::)))?; + #[cfg(not(boringssl))] + let idx = cvt_n(get_new_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } + + // FIXME should return a result? + fn cached_ex_index() -> Index + where + T: 'static + Sync + Send, + { + unsafe { + let idx = *INDEXES + .lock() + .unwrap_or_else(|e| e.into_inner()) + .entry(TypeId::of::()) + .or_insert_with(|| SslContext::new_ex_index::().unwrap().as_raw()); + Index::from_raw(idx) + } + } } impl SslContextRef { /// Returns the certificate associated with this `SslContext`, if present. /// - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - /// - /// This corresponds to [`SSL_CTX_get0_certificate`]. - /// - /// [`SSL_CTX_get0_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] + /// Requires OpenSSL 1.0.2 or LibreSSL 2.7.0 or newer. + #[corresponds(SSL_CTX_get0_certificate)] + #[cfg(any(ossl102, libressl270))] pub fn certificate(&self) -> Option<&X509Ref> { unsafe { let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(X509Ref::from_ptr(ptr)) - } + X509Ref::from_const_ptr_opt(ptr) } } /// Returns the private key associated with this `SslContext`, if present. /// - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. - /// - /// This corresponds to [`SSL_CTX_get0_privatekey`]. - /// - /// [`SSL_CTX_get0_privatekey`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - pub fn private_key(&self) -> Option<&PKeyRef> { + /// Requires OpenSSL 1.0.2 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_CTX_get0_privatekey)] + #[cfg(any(ossl102, libressl340))] + pub fn private_key(&self) -> Option<&PKeyRef> { unsafe { let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(PKeyRef::from_ptr(ptr)) - } + PKeyRef::from_const_ptr_opt(ptr) } } /// Returns a shared reference to the certificate store used for verification. - /// - /// This corresponds to [`SSL_CTX_get_cert_store`]. - /// - /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + #[corresponds(SSL_CTX_get_cert_store)] pub fn cert_store(&self) -> &X509StoreRef { unsafe { X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } /// Returns a shared reference to the stack of certificates making up the chain from the leaf. - /// - /// This corresponds to `SSL_CTX_get_extra_chain_certs`. + #[corresponds(SSL_CTX_get_extra_chain_certs)] pub fn extra_chain_certs(&self) -> &StackRef { unsafe { let mut chain = ptr::null_mut(); ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain); - assert!(!chain.is_null()); - StackRef::from_ptr(chain) + StackRef::from_const_ptr_opt(chain).expect("extra chain certs must not be null") } } /// Returns a reference to the extra data at the specified index. - /// - /// This corresponds to [`SSL_CTX_get_ex_data`]. - /// - /// [`SSL_CTX_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ex_data.html + #[corresponds(SSL_CTX_get_ex_data)] pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw()); @@ -1257,6 +1837,69 @@ impl SslContextRef { } } } + + /// Gets the maximum amount of early data that will be accepted on incoming connections. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_CTX_get_max_early_data)] + #[cfg(any(ossl111, libressl340))] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) } + } + + /// Adds a session to the context's cache. + /// + /// Returns `true` if the session was successfully added to the cache, and `false` if it was already present. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session has never been used with another + /// `SslContext` than this one. + #[corresponds(SSL_CTX_add_session)] + pub unsafe fn add_session(&self, session: &SslSessionRef) -> bool { + ffi::SSL_CTX_add_session(self.as_ptr(), session.as_ptr()) != 0 + } + + /// Removes a session from the context's cache and marks it as non-resumable. + /// + /// Returns `true` if the session was successfully found and removed, and `false` otherwise. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session has never been used with another + /// `SslContext` than this one. + #[corresponds(SSL_CTX_remove_session)] + pub unsafe fn remove_session(&self, session: &SslSessionRef) -> bool { + ffi::SSL_CTX_remove_session(self.as_ptr(), session.as_ptr()) != 0 + } + + /// Returns the context's session cache size limit. + /// + /// A value of 0 means that the cache size is unbounded. + #[corresponds(SSL_CTX_sess_get_cache_size)] + #[allow(clippy::unnecessary_cast)] + pub fn session_cache_size(&self) -> i64 { + unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()) as i64 } + } + + /// Returns the verify mode that was set on this context from [`SslContextBuilder::set_verify`]. + /// + /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify + #[corresponds(SSL_CTX_get_verify_mode)] + pub fn verify_mode(&self) -> SslVerifyMode { + let mode = unsafe { ffi::SSL_CTX_get_verify_mode(self.as_ptr()) }; + SslVerifyMode::from_bits(mode).expect("SSL_CTX_get_verify_mode returned invalid mode") + } + + /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CTX_get_num_tickets)] + #[cfg(ossl111)] + pub fn num_tickets(&self) -> usize { + unsafe { ffi::SSL_CTX_get_num_tickets(self.as_ptr()) } + } } /// Information about the state of a cipher. @@ -1311,25 +1954,33 @@ impl ForeignTypeRef for SslCipherRef { impl SslCipherRef { /// Returns the name of the cipher. - /// - /// This corresponds to [`SSL_CIPHER_get_name`]. - /// - /// [`SSL_CIPHER_get_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html - pub fn name(&self) -> &str { - let name = unsafe { + #[corresponds(SSL_CIPHER_get_name)] + pub fn name(&self) -> &'static str { + unsafe { let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr()); - CStr::from_ptr(ptr as *const _) - }; + CStr::from_ptr(ptr).to_str().unwrap() + } + } - str::from_utf8(name.to_bytes()).unwrap() + /// Returns the RFC-standard name of the cipher, if one exists. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CIPHER_standard_name)] + #[cfg(ossl111)] + pub fn standard_name(&self) -> Option<&'static str> { + unsafe { + let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(CStr::from_ptr(ptr).to_str().unwrap()) + } + } } /// Returns the SSL/TLS protocol version that first defined the cipher. - /// - /// This corresponds to [`SSL_CIPHER_get_version`]. - /// - /// [`SSL_CIPHER_get_version`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html - pub fn version(&self) -> &str { + #[corresponds(SSL_CIPHER_get_version)] + pub fn version(&self) -> &'static str { let version = unsafe { let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr()); CStr::from_ptr(ptr as *const _) @@ -1339,10 +1990,8 @@ impl SslCipherRef { } /// Returns the number of bits used for the cipher. - /// - /// This corresponds to [`SSL_CIPHER_get_bits`]. - /// - /// [`SSL_CIPHER_get_bits`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[corresponds(SSL_CIPHER_get_bits)] + #[allow(clippy::useless_conversion)] pub fn bits(&self) -> CipherBits { unsafe { let mut algo_bits = 0; @@ -1355,10 +2004,7 @@ impl SslCipherRef { } /// Returns a textual description of the cipher. - /// - /// This corresponds to [`SSL_CIPHER_description`]. - /// - /// [`SSL_CIPHER_description`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[corresponds(SSL_CIPHER_description)] pub fn description(&self) -> String { unsafe { // SSL_CIPHER_description requires a buffer of at least 128 bytes. @@ -1367,29 +2013,66 @@ impl SslCipherRef { String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap() } } -} - -foreign_type! { - type CType = ffi::SSL_SESSION; - fn drop = ffi::SSL_SESSION_free; - - /// An encoded SSL session. - /// - /// These can be cached to share sessions across connections. - pub struct SslSession; - /// Reference to [`SslSession]`. + /// Returns the handshake digest of the cipher. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CIPHER_get_handshake_digest)] + #[cfg(ossl111)] + pub fn handshake_digest(&self) -> Option { + unsafe { + let ptr = ffi::SSL_CIPHER_get_handshake_digest(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(MessageDigest::from_ptr(ptr)) + } + } + } + + /// Returns the NID corresponding to the cipher. + /// + /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer. + #[corresponds(SSL_CIPHER_get_cipher_nid)] + #[cfg(any(ossl110, libressl270))] + pub fn cipher_nid(&self) -> Option { + let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) }; + if n == 0 { + None + } else { + Some(Nid::from_raw(n)) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::SSL_SESSION; + fn drop = ffi::SSL_SESSION_free; + + /// An encoded SSL session. + /// + /// These can be cached to share sessions across connections. + pub struct SslSession; + + /// Reference to [`SslSession`]. /// /// [`SslSession`]: struct.SslSession.html pub struct SslSessionRef; } -unsafe impl Sync for SslSession {} -unsafe impl Send for SslSession {} - impl Clone for SslSession { fn clone(&self) -> SslSession { - self.to_owned() + SslSessionRef::to_owned(self) + } +} + +impl SslSession { + from_der! { + /// Deserializes a DER-encoded session structure. + #[corresponds(d2i_SSL_SESSION)] + from_der, + SslSession, + ffi::d2i_SSL_SESSION } } @@ -1398,7 +2081,7 @@ impl ToOwned for SslSessionRef { fn to_owned(&self) -> SslSession { unsafe { - compat::SSL_SESSION_up_ref(self.as_ptr()); + SSL_SESSION_up_ref(self.as_ptr()); SslSession(self.as_ptr()) } } @@ -1406,10 +2089,7 @@ impl ToOwned for SslSessionRef { impl SslSessionRef { /// Returns the SSL session ID. - /// - /// This corresponds to [`SSL_SESSION_get_id`]. - /// - /// [`SSL_SESSION_get_id`]: https://www.openssl.org/docs/manmaster/man3/SSL_SESSION_get_id.html + #[corresponds(SSL_SESSION_get_id)] pub fn id(&self) -> &[u8] { unsafe { let mut len = 0; @@ -1419,27 +2099,65 @@ impl SslSessionRef { } /// Returns the length of the master key. - /// - /// This corresponds to [`SSL_SESSION_get_master_key`]. - /// - /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html + #[corresponds(SSL_SESSION_get_master_key)] pub fn master_key_len(&self) -> usize { - unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } } /// Copies the master key into the provided buffer. /// - /// Returns the number of bytes written. + /// Returns the number of bytes written, or the size of the master key if the buffer is empty. + #[corresponds(SSL_SESSION_get_master_key)] + pub fn master_key(&self, buf: &mut [u8]) -> usize { + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } + } + + /// Gets the maximum amount of early data that can be sent on this session. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_SESSION_get_max_early_data)] + #[cfg(any(ossl111, libressl340))] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) } + } + + /// Returns the time at which the session was established, in seconds since the Unix epoch. + #[corresponds(SSL_SESSION_get_time)] + #[allow(clippy::useless_conversion)] + pub fn time(&self) -> SslTimeTy { + unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()) } + } + + /// Returns the sessions timeout, in seconds. /// - /// This corresponds to [`SSL_SESSION_get_master_key`]. + /// A session older than this time should not be used for session resumption. + #[corresponds(SSL_SESSION_get_timeout)] + #[allow(clippy::useless_conversion)] + pub fn timeout(&self) -> i64 { + unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()).into() } + } + + /// Returns the session's TLS protocol version. /// - /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html - pub fn master_key(&self, buf: &mut [u8]) -> usize { - unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } + /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer. + #[corresponds(SSL_SESSION_get_protocol_version)] + #[cfg(any(ossl110, libressl270))] + pub fn protocol_version(&self) -> SslVersion { + unsafe { + let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr()); + SslVersion(version) + } + } + + to_der! { + /// Serializes the session into a DER-encoded structure. + #[corresponds(i2d_SSL_SESSION)] + to_der, + ffi::i2d_SSL_SESSION } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::SSL; fn drop = ffi::SSL_free; @@ -1457,35 +2175,109 @@ foreign_type! { pub struct SslRef; } +impl fmt::Debug for Ssl { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, fmt) + } +} + impl Ssl { /// Returns a new extra data index. /// /// Each invocation of this function is guaranteed to return a distinct index. These can be used /// to store data in the context that can be retrieved later by callbacks, for example. - /// - /// This corresponds to [`SSL_get_ex_new_index`]. - /// - /// [`SSL_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_ex_new_index.html + #[corresponds(SSL_get_ex_new_index)] pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, { unsafe { ffi::init(); - let idx = cvt_n(compat::get_new_ssl_idx(free_data_box::))?; + #[cfg(boringssl)] + let idx = cvt_n(get_new_ssl_idx(Some(free_data_box::)))?; + #[cfg(not(boringssl))] + let idx = cvt_n(get_new_ssl_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } + + // FIXME should return a result? + fn cached_ex_index() -> Index + where + T: 'static + Sync + Send, + { + unsafe { + let idx = *SSL_INDEXES + .lock() + .unwrap_or_else(|e| e.into_inner()) + .entry(TypeId::of::()) + .or_insert_with(|| Ssl::new_ex_index::().unwrap().as_raw()); + Index::from_raw(idx) + } + } + + /// Creates a new `Ssl`. + /// + /// This corresponds to [`SSL_new`]. + /// + /// [`SSL_new`]: https://www.openssl.org/docs/manmaster/ssl/SSL_new.html + #[corresponds(SSL_new)] + pub fn new(ctx: &SslContextRef) -> Result { + let session_ctx_index = try_get_session_ctx_index()?; + unsafe { + let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; + let mut ssl = Ssl::from_ptr(ptr); + ssl.set_ex_data(*session_ctx_index, ctx.to_owned()); + + Ok(ssl) + } + } + + /// Initiates a client-side TLS handshake. + /// + /// This corresponds to [`SSL_connect`]. + /// + /// # Warning + /// + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `SslConnector` rather than `Ssl` directly, as it manages that configuration. + /// + /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html + #[corresponds(SSL_connect)] + #[allow(deprecated)] + pub fn connect(self, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + SslStreamBuilder::new(self, stream).connect() + } + + /// Initiates a server-side TLS handshake. + /// + /// This corresponds to [`SSL_accept`]. + /// + /// # Warning + /// + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration. + /// + /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html + #[corresponds(SSL_accept)] + #[allow(deprecated)] + pub fn accept(self, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + SslStreamBuilder::new(self, stream).accept() + } } impl fmt::Debug for SslRef { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("Ssl"); - builder.field("state", &self.state_string_long()); - if let Some(err) = self.verify_result() { - builder.field("verify_result", &err); - } - builder.finish() + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Ssl") + .field("state", &self.state_string_long()) + .field("verify_result", &self.verify_result()) + .finish() } } @@ -1499,147 +2291,160 @@ impl SslRef { unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) } } + fn peek(&mut self, buf: &mut [u8]) -> c_int { + let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; + unsafe { ffi::SSL_peek(self.as_ptr(), buf.as_ptr() as *mut c_void, len) } + } + fn write(&mut self, buf: &[u8]) -> c_int { let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) } } - fn get_error(&self, ret: c_int) -> c_int { - unsafe { ffi::SSL_get_error(self.as_ptr(), ret) } + fn get_error(&self, ret: c_int) -> ErrorCode { + unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) } + } + + /// Configure as an outgoing stream from a client. + #[corresponds(SSL_set_connect_state)] + pub fn set_connect_state(&mut self) { + unsafe { ffi::SSL_set_connect_state(self.as_ptr()) } + } + + /// Configure as an incoming stream to a server. + #[corresponds(SSL_set_accept_state)] + pub fn set_accept_state(&mut self) { + unsafe { ffi::SSL_set_accept_state(self.as_ptr()) } } /// Like [`SslContextBuilder::set_verify`]. /// - /// This corresponds to [`SSL_set_verify`]. - /// /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify - /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html + #[corresponds(SSL_set_verify)] pub fn set_verify(&mut self, mode: SslVerifyMode) { unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) } } + /// Returns the verify mode that was set using `set_verify`. + #[corresponds(SSL_set_verify_mode)] + pub fn verify_mode(&self) -> SslVerifyMode { + let mode = unsafe { ffi::SSL_get_verify_mode(self.as_ptr()) }; + SslVerifyMode::from_bits(mode).expect("SSL_get_verify_mode returned invalid mode") + } + /// Like [`SslContextBuilder::set_verify_callback`]. /// - /// This corresponds to [`SSL_set_verify`]. - /// /// [`SslContextBuilder::set_verify_callback`]: struct.SslContextBuilder.html#method.set_verify_callback - /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html + #[corresponds(SSL_set_verify)] pub fn set_verify_callback(&mut self, mode: SslVerifyMode, verify: F) where - // FIXME should take a mutable reference to the x509 store - F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send, + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { - let verify = Box::new(verify); - ffi::SSL_set_ex_data( - self.as_ptr(), - get_ssl_callback_idx::(), - mem::transmute(verify), - ); + // this needs to be in an Arc since the callback can register a new callback! + self.set_ex_data(Ssl::cached_ex_index(), Arc::new(verify)); ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::)); } } /// Like [`SslContextBuilder::set_tmp_dh`]. /// - /// This corresponds to [`SSL_set_tmp_dh`]. - /// /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh - /// [`SSL_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html - pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { + #[corresponds(SSL_set_tmp_dh)] + pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } /// Like [`SslContextBuilder::set_tmp_dh_callback`]. /// - /// This corresponds to [`SSL_set_tmp_dh_callback`]. - /// /// [`SslContextBuilder::set_tmp_dh_callback`]: struct.SslContextBuilder.html#method.set_tmp_dh_callback - /// [`SSL_set_tmp_dh_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html + #[corresponds(SSL_set_tmp_dh_callback)] pub fn set_tmp_dh_callback(&mut self, callback: F) where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { - let callback = Box::new(callback); - ffi::SSL_set_ex_data( - self.as_ptr(), - get_ssl_callback_idx::(), - Box::into_raw(callback) as *mut c_void, - ); - let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_dh_ssl::; - ffi::SSL_set_tmp_dh_callback(self.as_ptr(), f); + // this needs to be in an Arc since the callback can register a new callback! + self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback)); + #[cfg(boringssl)] + ffi::SSL_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh_ssl::)); + #[cfg(not(boringssl))] + ffi::SSL_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh_ssl::)); } } /// Like [`SslContextBuilder::set_tmp_ecdh`]. /// - /// This corresponds to `SSL_set_tmp_ecdh`. - /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh - pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { + #[corresponds(SSL_set_tmp_ecdh)] + pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } /// Like [`SslContextBuilder::set_tmp_ecdh_callback`]. /// - /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. - /// - /// This corresponds to `SSL_set_tmp_ecdh_callback`. - /// - /// [`SslContextBuilder::set_tmp_ecdh_callback`]: struct.SslContextBuilder.html#method.set_tmp_ecdh_callback - #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] + /// Requires OpenSSL 1.0.1 or 1.0.2. + #[corresponds(SSL_set_tmp_ecdh_callback)] + #[cfg(any(all(ossl101, not(ossl110))))] + #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where - F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send, + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { - let callback = Box::new(callback); - ffi::SSL_set_ex_data( - self.as_ptr(), - get_ssl_callback_idx::(), - Box::into_raw(callback) as *mut c_void, - ); - let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_ecdh_ssl::; - ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), f); + // this needs to be in an Arc since the callback can register a new callback! + self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback)); + ffi::SSL_set_tmp_ecdh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_ecdh_ssl::)); } } /// Like [`SslContextBuilder::set_ecdh_auto`]. /// - /// Requires the `v102` feature and OpenSSL 1.0.2. - /// - /// This corresponds to [`SSL_set_ecdh_auto`]. + /// Requires OpenSSL 1.0.2 or LibreSSL. /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh - /// [`SSL_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_ecdh_auto.html - #[cfg(all(feature = "v102", ossl102))] + #[corresponds(SSL_set_ecdh_auto)] + #[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(|_| ()) } } - /// Returns the current cipher if the session is active. + /// Like [`SslContextBuilder::set_alpn_protos`]. /// - /// This corresponds to [`SSL_get_current_cipher`]. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// - /// [`SSL_get_current_cipher`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_current_cipher.html + /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos + #[corresponds(SSL_set_alpn_protos)] + #[cfg(any(ossl102, libressl261))] + pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(protocols.len() <= c_uint::max_value() as usize); + let r = ffi::SSL_set_alpn_protos( + self.as_ptr(), + protocols.as_ptr(), + protocols.len() as c_uint, + ); + // fun fact, SSL_set_alpn_protos has a reversed return code D: + if r == 0 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + } + + /// Returns the current cipher if the session is active. + #[corresponds(SSL_get_current_cipher)] pub fn current_cipher(&self) -> Option<&SslCipherRef> { unsafe { let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(SslCipherRef::from_ptr(ptr as *mut _)) - } + SslCipherRef::from_const_ptr_opt(ptr) } } /// Returns a short string describing the state of the session. - /// - /// This corresponds to [`SSL_state_string`]. - /// - /// [`SSL_state_string`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_state_string.html + #[corresponds(SSL_state_string)] pub fn state_string(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string(self.as_ptr()); @@ -1650,10 +2455,7 @@ impl SslRef { } /// Returns a longer string describing the state of the session. - /// - /// This corresponds to [`SSL_state_string_long`]. - /// - /// [`SSL_state_string_long`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_state_string_long.html + #[corresponds(SSL_state_string_long)] pub fn state_string_long(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string_long(self.as_ptr()); @@ -1666,10 +2468,7 @@ impl SslRef { /// Sets the host name to be sent to the server for Server Name Indication (SNI). /// /// It has no effect for a server-side connection. - /// - /// This corresponds to [`SSL_set_tlsext_host_name`]. - /// - /// [`SSL_set_tlsext_host_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername_type.html + #[corresponds(SSL_set_tlsext_host_name)] pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> { let cstr = CString::new(hostname).unwrap(); unsafe { @@ -1679,18 +2478,11 @@ impl SslRef { } /// Returns the peer's certificate, if present. - /// - /// This corresponds to [`SSL_get_peer_certificate`]. - /// - /// [`SSL_get_peer_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_certificate.html + #[corresponds(SSL_get_peer_certificate)] pub fn peer_certificate(&self) -> Option { unsafe { - let ptr = ffi::SSL_get_peer_certificate(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(X509::from_ptr(ptr)) - } + let ptr = SSL_get1_peer_certificate(self.as_ptr()); + X509::from_ptr_opt(ptr) } } @@ -1698,59 +2490,73 @@ impl SslRef { /// /// On the client side, the chain includes the leaf certificate, but on the server side it does /// not. Fun! - /// - /// This corresponds to [`SSL_get_peer_cert_chain`]. - /// - /// [`SSL_get_peer_cert_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_cert_chain.html + #[corresponds(SSL_get_peer_cert_chain)] pub fn peer_cert_chain(&self) -> Option<&StackRef> { unsafe { let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(StackRef::from_ptr(ptr)) - } + StackRef::from_const_ptr_opt(ptr) } } - /// Like [`SslContext::certificate`]. + /// Returns the verified certificate chain of the peer, including the leaf certificate. /// - /// This corresponds to `SSL_get_certificate`. + /// If verification was not successful (i.e. [`verify_result`] does not return + /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid. /// - /// [`SslContext::certificate`]: struct.SslContext.html#method.certificate + /// Requires OpenSSL 1.1.0 or newer. + /// + /// [`verify_result`]: #method.verify_result + /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK + #[corresponds(SSL_get0_verified_chain)] + #[cfg(ossl110)] + pub fn verified_chain(&self) -> Option<&StackRef> { + unsafe { + let ptr = ffi::SSL_get0_verified_chain(self.as_ptr()); + StackRef::from_const_ptr_opt(ptr) + } + } + + /// Like [`SslContext::certificate`]. + #[corresponds(SSL_get_certificate)] pub fn certificate(&self) -> Option<&X509Ref> { unsafe { let ptr = ffi::SSL_get_certificate(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(X509Ref::from_ptr(ptr)) - } + X509Ref::from_const_ptr_opt(ptr) } } /// Like [`SslContext::private_key`]. /// - /// This corresponds to `SSL_get_privatekey`. - /// /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key - pub fn private_key(&self) -> Option<&PKeyRef> { + #[corresponds(SSL_get_privatekey)] + pub fn private_key(&self) -> Option<&PKeyRef> { unsafe { let ptr = ffi::SSL_get_privatekey(self.as_ptr()); - if ptr.is_null() { + PKeyRef::from_const_ptr_opt(ptr) + } + } + + #[deprecated(since = "0.10.5", note = "renamed to `version_str`")] + pub fn version(&self) -> &str { + self.version_str() + } + + /// Returns the protocol version of the session. + #[corresponds(SSL_version)] + pub fn version2(&self) -> Option { + unsafe { + let r = ffi::SSL_version(self.as_ptr()); + if r == 0 { None } else { - Some(PKeyRef::from_ptr(ptr)) + Some(SslVersion(r)) } } } /// Returns a string describing the protocol version of the session. - /// - /// This corresponds to [`SSL_get_version`]. - /// - /// [`SSL_get_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_version.html - pub fn version(&self) -> &'static str { + #[corresponds(SSL_get_version)] + pub fn version_str(&self) -> &'static str { let version = unsafe { let ptr = ffi::SSL_get_version(self.as_ptr()); CStr::from_ptr(ptr as *const _) @@ -1759,22 +2565,21 @@ impl SslRef { str::from_utf8(version.to_bytes()).unwrap() } - /// Returns the protocol selected by performing Next Protocol Negotiation, if any. + /// Returns the protocol selected via Application Layer Protocol Negotiation (ALPN). /// /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client /// to interpret it. /// - /// This corresponds to [`SSL_get0_next_proto_negotiated`]. - /// - /// [`SSL_get0_next_proto_negotiated`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html - #[cfg(not(any(libressl261, libressl262, libressl26x)))] - pub fn selected_npn_protocol(&self) -> Option<&[u8]> { + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_get0_alpn_selected)] + #[cfg(any(ossl102, libressl261))] + pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { unsafe { let mut data: *const c_uchar = ptr::null(); let mut len: c_uint = 0; // Get the negotiated protocol from the SSL instance. // `data` will point at a `c_uchar` array; `len` will contain the length of this array. - ffi::SSL_get0_next_proto_negotiated(self.as_ptr(), &mut data, &mut len); + ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len); if data.is_null() { None @@ -1784,102 +2589,111 @@ impl SslRef { } } - /// Returns the protocol selected by performing ALPN, if any. - /// - /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client - /// to interpret it. + /// Enables the DTLS extension "use_srtp" as defined in RFC5764. /// - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. + /// This corresponds to [`SSL_set_tlsext_use_srtp`]. /// - /// This corresponds to [`SSL_get0_alpn_selected`]. - /// - /// [`SSL_get0_alpn_selected`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { + /// [`SSL_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + #[corresponds(SSL_set_tlsext_use_srtp)] + pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { unsafe { - let mut data: *const c_uchar = ptr::null(); - let mut len: c_uint = 0; - // Get the negotiated protocol from the SSL instance. - // `data` will point at a `c_uchar` array; `len` will contain the length of this array. - ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len); + let cstr = CString::new(protocols).unwrap(); - if data.is_null() { - None + let r = ffi::SSL_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr()); + // fun fact, set_tlsext_use_srtp has a reversed return code D: + if r == 0 { + Ok(()) } else { - Some(slice::from_raw_parts(data, len as usize)) + Err(ErrorStack::get()) } } } - /// Returns the number of bytes remaining in the currently processed TLS record. + /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp /// - /// If this is greater than 0, the next call to `read` will not call down to the underlying - /// stream. + /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. /// - /// This corresponds to [`SSL_pending]`. + /// This corresponds to [`SSL_get_srtp_profiles`]. /// - /// [`SSL_pending`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_pending.html - pub fn pending(&self) -> usize { - unsafe { ffi::SSL_pending(self.as_ptr()) as usize } - } + /// [`SSL_get_srtp_profiles`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + #[corresponds(SSL_get_srtp_profiles)] + pub fn srtp_profiles(&self) -> Option<&StackRef> { + unsafe { + let chain = ffi::SSL_get_srtp_profiles(self.as_ptr()); - /// Returns the compression method currently in use. - /// - /// This corresponds to `SSL_get_current_compression`. - pub fn compression(&self) -> Option<&str> { - self._compression() + StackRef::from_const_ptr_opt(chain) + } } - #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] - fn _compression(&self) -> Option<&str> { + /// Gets the SRTP profile selected by handshake. + /// + /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. + #[corresponds(SSL_get_selected_srtp_profile)] + pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> { unsafe { - let ptr = ffi::SSL_get_current_compression(self.as_ptr()); - if ptr == ptr::null() { - return None; - } - let meth = ffi::SSL_COMP_get_name(ptr); - Some(str::from_utf8(CStr::from_ptr(meth as *const _).to_bytes()).unwrap()) + let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr()); + + SrtpProtectionProfileRef::from_const_ptr_opt(profile) } } - #[cfg(osslconf = "OPENSSL_NO_COMP")] - fn _compression(&self) -> Option<&str> { - None + /// Returns the number of bytes remaining in the currently processed TLS record. + /// + /// If this is greater than 0, the next call to `read` will not call down to the underlying + /// stream. + #[corresponds(SSL_pending)] + pub fn pending(&self) -> usize { + unsafe { ffi::SSL_pending(self.as_ptr()) as usize } } /// Returns the servername sent by the client via Server Name Indication (SNI). /// /// It is only useful on the server side. /// - /// This corresponds to [`SSL_get_servername`]. + /// # Note + /// + /// While the SNI specification requires that servernames be valid domain names (and therefore + /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client + /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns + /// the raw bytes and does not have this restriction. /// /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html - // FIXME add name parameter - pub fn servername(&self) -> Option<&str> { + #[corresponds(SSL_get_servername)] + // FIXME maybe rethink in 0.11? + pub fn servername(&self, type_: NameType) -> Option<&str> { + self.servername_raw(type_) + .and_then(|b| str::from_utf8(b).ok()) + } + + /// Returns the servername sent by the client via Server Name Indication (SNI). + /// + /// It is only useful on the server side. + /// + /// # Note + /// + /// Unlike `servername`, this method does not require the name be valid UTF-8. + #[corresponds(SSL_get_servername)] + pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> { unsafe { - let name = ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name); - if name == ptr::null() { - return None; + let name = ffi::SSL_get_servername(self.as_ptr(), type_.0); + if name.is_null() { + None + } else { + Some(CStr::from_ptr(name as *const _).to_bytes()) } - - Some(str::from_utf8(CStr::from_ptr(name as *const _).to_bytes()).unwrap()) } } /// Changes the context corresponding to the current connection. /// /// It is most commonly used in the Server Name Indication (SNI) callback. - /// - /// This corresponds to `SSL_set_SSL_CTX`. + #[corresponds(SSL_set_SSL_CTX)] pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> { unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) } } /// Returns the context corresponding to the current connection. - /// - /// This corresponds to [`SSL_get_SSL_CTX`]. - /// - /// [`SSL_get_SSL_CTX`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_SSL_CTX.html + #[corresponds(SSL_get_SSL_CTX)] pub fn ssl_context(&self) -> &SslContextRef { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr()); @@ -1889,89 +2703,157 @@ impl SslRef { /// Returns a mutable reference to the X509 verification configuration. /// - /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0. - /// - /// This corresponds to [`SSL_get0_param`]. - /// - /// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] + /// Requires OpenSSL 1.0.2 or newer. + #[corresponds(SSL_get0_param)] + #[cfg(any(ossl102, libressl261))] pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { - self._param_mut() - } - - #[cfg(any(ossl102, ossl110))] - fn _param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } } /// Returns the certificate verification result. - /// - /// This corresponds to [`SSL_get_verify_result`]. - /// - /// [`SSL_get_verify_result`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_verify_result.html - pub fn verify_result(&self) -> Option { - unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) } + #[corresponds(SSL_get_verify_result)] + pub fn verify_result(&self) -> X509VerifyResult { + unsafe { X509VerifyResult::from_raw(ffi::SSL_get_verify_result(self.as_ptr()) as c_int) } } /// Returns a shared reference to the SSL session. - /// - /// This corresponds to [`SSL_get_session`]. - /// - /// [`SSL_get_session`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_session.html + #[corresponds(SSL_get_session)] pub fn session(&self) -> Option<&SslSessionRef> { unsafe { let p = ffi::SSL_get_session(self.as_ptr()); - if p.is_null() { - None - } else { - Some(SslSessionRef::from_ptr(p)) - } + SslSessionRef::from_const_ptr_opt(p) } } - /// Sets the session to be used. + /// Copies the `client_random` value sent by the client in the TLS handshake into a buffer. /// - /// This should be called before the handshake to attempt to reuse a previously established - /// session. If the server is not willing to reuse the session, a new one will be transparently - /// negotiated. + /// Returns the number of bytes copied, or if the buffer is empty, the size of the `client_random` + /// value. /// - /// This corresponds to [`SSL_set_session`]. + /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer. + #[corresponds(SSL_get_client_random)] + #[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()) + } + } + + /// Copies the `server_random` value sent by the server in the TLS handshake into a buffer. /// - /// # Safety + /// Returns the number of bytes copied, or if the buffer is empty, the size of the `server_random` + /// value. /// - /// The caller of this method is responsible for ensuring that the session is associated - /// with the same `SslContext` as this `Ssl`. + /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer. + #[corresponds(SSL_get_server_random)] + #[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()) + } + } + + /// Derives keying material for application use in accordance to RFC 5705. + #[corresponds(SSL_export_keying_material)] + pub fn export_keying_material( + &self, + out: &mut [u8], + label: &str, + context: Option<&[u8]>, + ) -> Result<(), ErrorStack> { + unsafe { + let (context, contextlen, use_context) = match context { + Some(context) => (context.as_ptr() as *const c_uchar, context.len(), 1), + None => (ptr::null(), 0, 0), + }; + cvt(ffi::SSL_export_keying_material( + self.as_ptr(), + out.as_mut_ptr() as *mut c_uchar, + out.len(), + label.as_ptr() as *const c_char, + label.len(), + context, + contextlen, + use_context, + )) + .map(|_| ()) + } + } + + /// Derives keying material for application use in accordance to RFC 5705. + /// + /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no + /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_export_keying_material_early)] + #[cfg(ossl111)] + pub fn export_keying_material_early( + &self, + out: &mut [u8], + label: &str, + context: &[u8], + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_export_keying_material_early( + self.as_ptr(), + out.as_mut_ptr() as *mut c_uchar, + out.len(), + label.as_ptr() as *const c_char, + label.len(), + context.as_ptr() as *const c_uchar, + context.len(), + )) + .map(|_| ()) + } + } + + /// Sets the session to be used. + /// + /// This should be called before the handshake to attempt to reuse a previously established + /// session. If the server is not willing to reuse the session, a new one will be transparently + /// negotiated. /// - /// [`SSL_set_session`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_session.html + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session is associated + /// with the same `SslContext` as this `Ssl`. + #[corresponds(SSL_set_session)] pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> { cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ()) } /// Determines if the session provided to `set_session` was successfully reused. - /// - /// This corresponds to [`SSL_session_reused`]. - /// - /// [`SSL_session_reused`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_session_reused.html + #[corresponds(SSL_session_reused)] pub fn session_reused(&self) -> bool { unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 } } /// Sets the status response a client wishes the server to reply with. - /// - /// This corresponds to [`SSL_set_tlsext_status_type`]. - /// - /// [`SSL_set_tlsext_status_type`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + #[corresponds(SSL_set_tlsext_status_type)] pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ()) } } - /// Returns the server's OCSP response, if present. + /// Determines if current session used Extended Master Secret /// - /// This corresponds to [`SSL_get_tlsext_status_oscp_resp`]. - /// - /// [`SSL_get_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + /// Returns `None` if the handshake is still in-progress. + #[corresponds(SSL_get_extms_support)] + #[cfg(ossl110)] + pub fn extms_support(&self) -> Option { + unsafe { + match ffi::SSL_get_extms_support(self.as_ptr()) { + -1 => None, + ret => Some(ret != 0), + } + } + } + + /// Returns the server's OCSP response, if present. + #[corresponds(SSL_get_tlsext_status_ocsp_resp)] + #[cfg(not(boringssl))] pub fn ocsp_status(&self) -> Option<&[u8]> { unsafe { let mut p = ptr::null_mut(); @@ -1986,45 +2868,37 @@ impl SslRef { } /// Sets the OCSP response to be returned to the client. - /// - /// This corresponds to [`SSL_set_tlsext_status_oscp_resp`]. - /// - /// [`SSL_set_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + #[corresponds(SSL_set_tlsext_status_oscp_resp)] + #[cfg(not(boringssl))] pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(response.len() <= c_int::max_value() as usize); - let p = cvt_p(ffi::CRYPTO_malloc( - response.len() as _, - concat!(file!(), "\0").as_ptr() as *const _, - line!() as c_int, - ))?; + let p = cvt_p(ffi::OPENSSL_malloc(response.len() as _))?; ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len()); cvt(ffi::SSL_set_tlsext_status_ocsp_resp( self.as_ptr(), p as *mut c_uchar, response.len() as c_long, ) as c_int) - .map(|_| ()) + .map(|_| ()) + .map_err(|e| { + ffi::OPENSSL_free(p); + e + }) } } /// Determines if this `Ssl` is configured for server-side or client-side use. - /// - /// This corresponds to [`SSL_is_server`]. - /// - /// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html + #[corresponds(SSL_is_server)] pub fn is_server(&self) -> bool { - unsafe { compat::SSL_is_server(self.as_ptr()) != 0 } + unsafe { SSL_is_server(self.as_ptr()) != 0 } } /// Sets the extra data at the specified index. /// /// This can be used to provide data to callbacks registered with the context. Use the /// `Ssl::new_ex_index` method to create an `Index`. - /// - /// This corresponds to [`SSL_set_ex_data`]. - /// - /// [`SSL_set_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + #[corresponds(SSL_set_ex_data)] pub fn set_ex_data(&mut self, index: Index, data: T) { unsafe { let data = Box::new(data); @@ -2037,10 +2911,7 @@ impl SslRef { } /// Returns a reference to the extra data at the specified index. - /// - /// This corresponds to [`SSL_get_ex_data`]. - /// - /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + #[corresponds(SSL_get_ex_data)] pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); @@ -2051,97 +2922,411 @@ impl SslRef { } } } -} -unsafe impl Sync for Ssl {} -unsafe impl Send for Ssl {} + /// Returns a mutable reference to the extra data at the specified index. + #[corresponds(SSL_get_ex_data)] + pub fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { + unsafe { + let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None + } else { + Some(&mut *(data as *mut T)) + } + } + } -impl fmt::Debug for Ssl { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, fmt) + /// Sets the maximum amount of early data that will be accepted on this connection. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_set_max_early_data)] + #[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(()) + } else { + Err(ErrorStack::get()) + } } -} -impl Ssl { - /// Creates a new `Ssl`. + /// Gets the maximum amount of early data that can be sent on this connection. /// - /// This corresponds to [`SSL_new`]. + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_get_max_early_data)] + #[cfg(any(ossl111, libressl340))] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) } + } + + /// Copies the contents of the last Finished message sent to the peer into the provided buffer. /// - /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html - pub fn new(ctx: &SslContext) -> Result { + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + #[corresponds(SSL_get_finished)] + pub fn finished(&self, buf: &mut [u8]) -> usize { + unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } + } + + /// Copies the contents of the last Finished message received from the peer into the provided + /// buffer. + /// + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + #[corresponds(SSL_get_peer_finished)] + pub fn peer_finished(&self, buf: &mut [u8]) -> usize { unsafe { - let ssl = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; - Ok(Ssl::from_ptr(ssl)) + ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } } - /// Initiates a client-side TLS handshake. + /// Determines if the initial handshake has been completed. + #[corresponds(SSL_is_init_finished)] + #[cfg(ossl110)] + pub fn is_init_finished(&self) -> bool { + unsafe { ffi::SSL_is_init_finished(self.as_ptr()) != 0 } + } + + /// Determines if the client's hello message is in the SSLv2 format. /// - /// This corresponds to [`SSL_connect`]. + /// This can only be used inside of the client hello callback. Otherwise, `false` is returned. /// - /// # Warning + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_client_hello_isv2)] + #[cfg(ossl111)] + pub fn client_hello_isv2(&self) -> bool { + unsafe { ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 } + } + + /// Returns the legacy version field of the client's hello message. /// - /// OpenSSL's default configuration is insecure. It is highly recommended to use - /// `SslConnector` rather than `Ssl` directly, as it manages that configuration. + /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. /// - /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html - pub fn connect(self, stream: S) -> Result, HandshakeError> - where - S: Read + Write, - { - let mut stream = SslStream::new_base(self, stream); - let ret = unsafe { ffi::SSL_connect(stream.ssl.as_ptr()) }; - if ret > 0 { - Ok(stream) - } else { - match stream.make_error(ret) { - e @ Error::WantWrite(_) | e @ Error::WantRead(_) => { - Err(HandshakeError::Interrupted(MidHandshakeSslStream { - stream: stream, - error: e, - })) - } - err => Err(HandshakeError::Failure(MidHandshakeSslStream { - stream: stream, - error: err, - })), + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_client_hello_get0_legacy_version)] + #[cfg(ossl111)] + pub fn client_hello_legacy_version(&self) -> Option { + unsafe { + let version = ffi::SSL_client_hello_get0_legacy_version(self.as_ptr()); + if version == 0 { + None + } else { + Some(SslVersion(version as c_int)) } } } - /// Initiates a server-side TLS handshake. + /// Returns the random field of the client's hello message. /// - /// This corresponds to [`SSL_accept`]. + /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. /// - /// # Warning + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_client_hello_get0_random)] + #[cfg(ossl111)] + pub fn client_hello_random(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_random(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } + + /// Returns the session ID field of the client's hello message. /// - /// OpenSSL's default configuration is insecure. It is highly recommended to use - /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration. + /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. /// - /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html - pub fn accept(self, stream: S) -> Result, HandshakeError> - where - S: Read + Write, - { - let mut stream = SslStream::new_base(self, stream); - let ret = unsafe { ffi::SSL_accept(stream.ssl.as_ptr()) }; - if ret > 0 { - Ok(stream) - } else { - match stream.make_error(ret) { - e @ Error::WantWrite(_) | e @ Error::WantRead(_) => { - Err(HandshakeError::Interrupted(MidHandshakeSslStream { - stream: stream, - error: e, - })) - } - err => Err(HandshakeError::Failure(MidHandshakeSslStream { - stream: stream, - error: err, - })), + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_client_hello_get0_session_id)] + #[cfg(ossl111)] + pub fn client_hello_session_id(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_session_id(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } + + /// Returns the ciphers field of the client's hello message. + /// + /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_client_hello_get0_ciphers)] + #[cfg(ossl111)] + pub fn client_hello_ciphers(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_ciphers(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } + + /// Returns the compression methods field of the client's hello message. + /// + /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_client_hello_get0_compression_methods)] + #[cfg(ossl111)] + pub fn client_hello_compression_methods(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_compression_methods(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } + + /// Sets the MTU used for DTLS connections. + #[corresponds(SSL_set_mtu)] + 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()) + } + } + } + + #[corresponds(SSL_add0_chain_cert)] + #[cfg(ossl102)] + pub fn add_chain_cert(&mut self, chain: X509) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_add0_chain_cert(self.as_ptr(), chain.as_ptr()) as c_int).map(|_| ())?; + mem::forget(chain); + } + Ok(()) + } + + /// Sets a new default TLS/SSL method for SSL objects + #[cfg(not(boringssl))] + pub fn set_method(&mut self, method: SslMethod) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_ssl_method(self.as_ptr(), method.as_ptr()))?; + }; + Ok(()) + } + + /// Loads the private key from a file. + #[corresponds(SSL_use_Private_Key_file)] + pub fn set_private_key_file>( + &mut self, + path: P, + ssl_file_type: SslFiletype, + ) -> Result<(), ErrorStack> { + let p = path.as_ref().as_os_str().to_str().unwrap(); + let key_file = CString::new(p).unwrap(); + unsafe { + cvt(ffi::SSL_use_PrivateKey_file( + self.as_ptr(), + key_file.as_ptr(), + ssl_file_type.as_raw(), + ))?; + }; + Ok(()) + } + + /// Sets the private key. + #[corresponds(SSL_use_PrivateKey)] + pub fn set_private_key(&mut self, pkey: &PKeyRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), pkey.as_ptr()))?; + }; + Ok(()) + } + + /// Sets the certificate + #[corresponds(SSL_use_certificate)] + pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?; + }; + Ok(()) + } + + /// Loads a certificate chain from a file. + /// + /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf + /// certificate, and the remainder forming the chain of certificates up to and including the + /// trusted root certificate. + #[corresponds(SSL_use_certificate_chain_file)] + #[cfg(any(ossl110, libressl332))] + pub fn set_certificate_chain_file>( + &mut self, + path: P, + ) -> Result<(), ErrorStack> { + let p = path.as_ref().as_os_str().to_str().unwrap(); + let cert_file = CString::new(p).unwrap(); + unsafe { + cvt(ffi::SSL_use_certificate_chain_file( + self.as_ptr(), + cert_file.as_ptr(), + ))?; + }; + Ok(()) + } + + /// Sets ca certificate that client trusted + #[corresponds(SSL_add_client_CA)] + pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_add_client_CA(self.as_ptr(), cacert.as_ptr()))?; + }; + Ok(()) + } + + // Sets the list of CAs sent to the client when requesting a client certificate for the chosen ssl + #[corresponds(SSL_set_client_CA_list)] + pub fn set_client_ca_list(&mut self, list: Stack) { + unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) } + mem::forget(list); + } + + /// Sets the minimum supported protocol version. + /// + /// A value of `None` will enable protocol versions down the the lowest version supported by + /// OpenSSL. + /// + /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_set_min_proto_version)] + #[cfg(any(ossl110, libressl261))] + pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_min_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } + } + + /// Sets the maximum supported protocol version. + /// + /// A value of `None` will enable protocol versions down the the highest version supported by + /// OpenSSL. + /// + /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_set_max_proto_version)] + #[cfg(any(ossl110, libressl261))] + pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_max_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } + } + + /// Sets the list of supported ciphers for the TLSv1.3 protocol. + /// + /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3. + /// + /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of + /// preference. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_set_ciphersuites)] + #[cfg(any(ossl111, libressl340))] + pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_set_ciphersuites( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + + /// Sets the list of supported ciphers for protocols before TLSv1.3. + /// + /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3. + /// + /// See [`ciphers`] for details on the format. + /// + /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html + #[corresponds(SSL_set_cipher_list)] + pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_set_cipher_list( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + + /// Set the certificate store used for certificate verification + #[corresponds(SSL_set_cert_store)] + #[cfg(ossl102)] + pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?; + mem::forget(cert_store); + Ok(()) + } + } + + /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_set_num_tickets)] + #[cfg(ossl111)] + pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) } + } + + /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_get_num_tickets)] + #[cfg(ossl111)] + pub fn num_tickets(&self) -> usize { + unsafe { ffi::SSL_get_num_tickets(self.as_ptr()) } + } } /// An SSL stream midway through the handshake process. @@ -2176,25 +3361,27 @@ impl MidHandshakeSslStream { pub fn into_error(self) -> Error { self.error } +} +impl MidHandshakeSslStream +where + S: Read + Write, +{ /// Restarts the handshake process. /// /// This corresponds to [`SSL_do_handshake`]. /// /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html pub fn handshake(mut self) -> Result, HandshakeError> { - let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) }; - if ret > 0 { - Ok(self.stream) - } else { - match self.stream.make_error(ret) { - e @ Error::WantWrite(_) | e @ Error::WantRead(_) => { - self.error = e; - Err(HandshakeError::Interrupted(self)) - } - err => { - self.error = err; - Err(HandshakeError::Failure(self)) + match self.stream.do_handshake() { + Ok(()) => Ok(self.stream), + Err(error) => { + self.error = error; + match self.error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(self)) + } + _ => Err(HandshakeError::Failure(self)), } } } @@ -2203,17 +3390,26 @@ impl MidHandshakeSslStream { /// A TLS session over a stream. pub struct SslStream { - // FIXME use ManuallyDrop - ssl: Ssl, - _method: BioMethod, // NOTE: this *must* be after the Ssl field so things drop right + ssl: ManuallyDrop, + method: ManuallyDrop, _p: PhantomData, } +impl Drop for SslStream { + fn drop(&mut self) { + // ssl holds a reference to method internally so it has to drop first + unsafe { + ManuallyDrop::drop(&mut self.ssl); + ManuallyDrop::drop(&mut self.method); + } + } +} + impl fmt::Debug for SslStream where S: fmt::Debug, { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("SslStream") .field("stream", &self.get_ref()) .field("ssl", &self.ssl()) @@ -2222,34 +3418,174 @@ where } impl SslStream { - fn new_base(ssl: Ssl, stream: S) -> Self { + /// Creates a new `SslStream`. + /// + /// This function performs no IO; the stream will not have performed any part of the handshake + /// with the peer. If the `Ssl` was configured with [`SslRef::set_connect_state`] or + /// [`SslRef::set_accept_state`], the handshake can be performed automatically during the first + /// call to read or write. Otherwise the `connect` and `accept` methods can be used to + /// explicitly perform the handshake. + #[corresponds(SSL_set_bio)] + pub fn new(ssl: Ssl, stream: S) -> Result { + let (bio, method) = bio::new(stream)?; unsafe { - let (bio, method) = bio::new(stream).unwrap(); ffi::SSL_set_bio(ssl.as_ptr(), bio, bio); + } - SslStream { - ssl: ssl, - _method: method, - _p: PhantomData, - } + Ok(SslStream { + ssl: ManuallyDrop::new(ssl), + method: ManuallyDrop::new(method), + _p: PhantomData, + }) + } + + /// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct. + /// + /// This is useful if the handshake has already been completed elsewhere. + /// + /// # Safety + /// + /// The caller must ensure the pointer is valid. + #[deprecated( + since = "0.10.32", + note = "use Ssl::from_ptr and SslStream::new instead" + )] + pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self { + let ssl = Ssl::from_ptr(ssl); + Self::new(ssl, stream).unwrap() + } + + /// Read application data transmitted by a client before handshake completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// [`SslRef::set_accept_state`] first. + /// + /// Returns `Ok(0)` if all early data has been read. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_read_early_data)] + #[cfg(any(ossl111, libressl340))] + pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result { + let mut read = 0; + let ret = unsafe { + ffi::SSL_read_early_data( + self.ssl.as_ptr(), + buf.as_ptr() as *mut c_void, + buf.len(), + &mut read, + ) + }; + match ret { + ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.make_error(ret)), + ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read), + ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0), + _ => unreachable!(), } } - /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`. + /// Send data to the server without blocking on handshake completion. /// - /// It is particularly useful with a nonblocking socket, where the error value will identify if - /// OpenSSL is waiting on read or write readiness. + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// [`SslRef::set_connect_state`] first. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_write_early_data)] + #[cfg(any(ossl111, libressl340))] + pub fn write_early_data(&mut self, buf: &[u8]) -> Result { + let mut written = 0; + let ret = unsafe { + ffi::SSL_write_early_data( + self.ssl.as_ptr(), + buf.as_ptr() as *const c_void, + buf.len(), + &mut written, + ) + }; + if ret > 0 { + Ok(written) + } else { + Err(self.make_error(ret)) + } + } + + /// Initiates a client-side TLS handshake. /// - /// This corresponds to [`SSL_read`]. + /// # Warning /// - /// [`SSL_read`]: https://www.openssl.org/docs/manmaster/man3/SSL_read.html + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `SslConnector` rather than `Ssl` directly, as it manages that configuration. + #[corresponds(SSL_connect)] + pub fn connect(&mut self) -> Result<(), Error> { + let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) }; + if ret > 0 { + Ok(()) + } else { + Err(self.make_error(ret)) + } + } + + /// Initiates a server-side TLS handshake. + /// + /// # Warning + /// + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration. + #[corresponds(SSL_accept)] + pub fn accept(&mut self) -> Result<(), Error> { + let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) }; + if ret > 0 { + Ok(()) + } else { + Err(self.make_error(ret)) + } + } + + /// Initiates the handshake. + /// + /// This will fail if `set_accept_state` or `set_connect_state` was not called first. + #[corresponds(SSL_do_handshake)] + pub fn do_handshake(&mut self) -> Result<(), Error> { + let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) }; + if ret > 0 { + Ok(()) + } else { + Err(self.make_error(ret)) + } + } + + /// Perform a stateless server-side handshake. + /// + /// Requires that cookie generation and verification callbacks were + /// set on the SSL context. + /// + /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie + /// was read, in which case the handshake should be continued via + /// `accept`. If a HelloRetryRequest containing a fresh cookie was + /// transmitted, `Ok(false)` is returned instead. If the handshake cannot + /// proceed at all, `Err` is returned. + #[corresponds(SSL_stateless)] + #[cfg(ossl111)] + pub fn stateless(&mut self) -> Result { + match unsafe { ffi::SSL_stateless(self.ssl.as_ptr()) } { + 1 => Ok(true), + 0 => Ok(false), + -1 => Err(ErrorStack::get()), + _ => unreachable!(), + } + } + + /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`. + /// + /// It is particularly useful with a non-blocking socket, where the error value will identify if + /// OpenSSL is waiting on read or write readiness. + #[corresponds(SSL_read)] pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { - // The intepretation of the return code here is a little odd with a + // The interpretation of the return code here is a little odd with a // zero-length write. OpenSSL will likely correctly report back to us // that it read zero bytes, but zero is also the sentinel for "error". // To avoid that confusion short-circuit that logic and return quickly // if `buf` has a length of zero. - if buf.len() == 0 { + if buf.is_empty() { return Ok(0); } @@ -2257,26 +3593,18 @@ impl SslStream { if ret > 0 { Ok(ret as usize) } else { - match self.make_error(ret) { - // FIXME only do this in read - // Don't treat unexpected EOFs as errors when reading - Error::Stream(ref e) if e.kind() == io::ErrorKind::ConnectionAborted => Ok(0), - e => Err(e), - } + Err(self.make_error(ret)) } } /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`. /// - /// It is particularly useful with a nonblocking socket, where the error value will identify if + /// It is particularly useful with a non-blocking socket, where the error value will identify if /// OpenSSL is waiting on read or write readiness. - /// - /// This corresponds to [`SSL_write`]. - /// - /// [`SSL_write`]: https://www.openssl.org/docs/manmaster/man3/SSL_write.html + #[corresponds(SSL_write)] pub fn ssl_write(&mut self, buf: &[u8]) -> Result { // See above for why we short-circuit on zero-length buffers - if buf.len() == 0 { + if buf.is_empty() { return Ok(0); } @@ -2288,6 +3616,22 @@ impl SslStream { } } + /// Reads data from the stream, without removing it from the queue. + #[corresponds(SSL_peek)] + pub fn ssl_peek(&mut self, buf: &mut [u8]) -> Result { + // See above for why we short-circuit on zero-length buffers + if buf.is_empty() { + return Ok(0); + } + + let ret = self.ssl.peek(buf); + if ret > 0 { + Ok(ret as usize) + } else { + Err(self.make_error(ret)) + } + } + /// Shuts down the session. /// /// The shutdown process consists of two steps. The first step sends a close notify message to @@ -2297,8 +3641,7 @@ impl SslStream { /// While the connection may be closed after the first step, it is recommended to fully shut the /// session down. In particular, it must be fully shut down if the connection is to be used for /// further communication in the future. - /// - /// This corresponds to [`SSL_shutdown`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_shutdown.html + #[corresponds(SSL_shutdown)] pub fn shutdown(&mut self) -> Result { match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } { 0 => Ok(ShutdownResult::Sent), @@ -2306,51 +3649,50 @@ impl SslStream { n => Err(self.make_error(n)), } } + + /// Returns the session's shutdown state. + #[corresponds(SSL_get_shutdown)] + pub fn get_shutdown(&mut self) -> ShutdownState { + unsafe { + let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr()); + ShutdownState { bits } + } + } + + /// Sets the session's shutdown state. + /// + /// This can be used to tell OpenSSL that the session should be cached even if a full two-way + /// shutdown was not completed. + #[corresponds(SSL_set_shutdown)] + pub fn set_shutdown(&mut self, state: ShutdownState) { + unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) } + } } impl SslStream { fn make_error(&mut self, ret: c_int) -> Error { self.check_panic(); - match self.ssl.get_error(ret) { - ffi::SSL_ERROR_SSL => Error::Ssl(ErrorStack::get()), - ffi::SSL_ERROR_SYSCALL => { + let code = self.ssl.get_error(ret); + + let cause = match code { + ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())), + ErrorCode::SYSCALL => { let errs = ErrorStack::get(); if errs.errors().is_empty() { - match self.get_bio_error() { - Some(err) => Error::Stream(err), - None => Error::Stream(io::Error::new( - io::ErrorKind::ConnectionAborted, - "unexpected EOF observed", - )), - } + self.get_bio_error().map(InnerError::Io) } else { - Error::Ssl(errs) + Some(InnerError::Ssl(errs)) } } - ffi::SSL_ERROR_ZERO_RETURN => Error::ZeroReturn, - ffi::SSL_ERROR_WANT_WRITE => { - let err = match self.get_bio_error() { - Some(err) => err, - None => io::Error::new( - io::ErrorKind::Other, - "BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO", - ), - }; - Error::WantWrite(err) + ErrorCode::ZERO_RETURN => None, + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + self.get_bio_error().map(InnerError::Io) } - ffi::SSL_ERROR_WANT_READ => { - let err = match self.get_bio_error() { - Some(err) => err, - None => io::Error::new(io::ErrorKind::Other, RetryError), - }; - Error::WantRead(err) - } - err => Error::Stream(io::Error::new( - io::ErrorKind::InvalidData, - format!("unexpected error {}", err), - )), - } + _ => None, + }; + + Error { code, cause } } fn check_panic(&mut self) { @@ -2395,13 +3737,16 @@ impl Read for SslStream { loop { match self.ssl_read(buf) { Ok(n) => return Ok(n), - Err(Error::ZeroReturn) => return Ok(0), - Err(Error::WantRead(ref e)) - if e.get_ref().map_or(false, |e| e.is::()) => {} - Err(Error::Stream(e)) | Err(Error::WantRead(e)) | Err(Error::WantWrite(e)) => { - return Err(e); + Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0), + Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => { + return Ok(0); + } + Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} + Err(e) => { + return Err(e + .into_io_error() + .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))); } - Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), } } } @@ -2412,12 +3757,12 @@ impl Write for SslStream { loop { match self.ssl_write(buf) { Ok(n) => return Ok(n), - Err(Error::WantRead(ref e)) - if e.get_ref().map_or(false, |e| e.is::()) => {} - Err(Error::Stream(e)) | Err(Error::WantRead(e)) | Err(Error::WantWrite(e)) => { - return Err(e); + Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} + Err(e) => { + return Err(e + .into_io_error() + .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))); } - Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), } } } @@ -2427,141 +3772,360 @@ impl Write for SslStream { } } -/// The result of a shutdown request. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ShutdownResult { - /// A close notify message has been sent to the peer. - Sent, - - /// A close notify response message has been received from the peer. - Received, +/// A partially constructed `SslStream`, useful for unusual handshakes. +#[deprecated( + since = "0.10.32", + note = "use the methods directly on Ssl/SslStream instead" +)] +pub struct SslStreamBuilder { + inner: SslStream, } -#[cfg(ossl110)] -mod compat { - use std::ptr; - - use ffi; - use libc::c_int; +#[allow(deprecated)] +impl SslStreamBuilder +where + S: Read + Write, +{ + /// Begin creating an `SslStream` atop `stream` + pub fn new(ssl: Ssl, stream: S) -> Self { + Self { + inner: SslStream::new(ssl, stream).unwrap(), + } + } - pub use ffi::{SSL_CTX_clear_options, SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_up_ref, - SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server}; + /// Perform a stateless server-side handshake + /// + /// Requires that cookie generation and verification callbacks were + /// set on the SSL context. + /// + /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie + /// was read, in which case the handshake should be continued via + /// `accept`. If a HelloRetryRequest containing a fresh cookie was + /// transmitted, `Ok(false)` is returned instead. If the handshake cannot + /// proceed at all, `Err` is returned. + /// + /// This corresponds to [`SSL_stateless`] + /// + /// [`SSL_stateless`]: https://www.openssl.org/docs/manmaster/man3/SSL_stateless.html + #[cfg(ossl111)] + pub fn stateless(&mut self) -> Result { + match unsafe { ffi::SSL_stateless(self.inner.ssl.as_ptr()) } { + 1 => Ok(true), + 0 => Ok(false), + -1 => Err(ErrorStack::get()), + _ => unreachable!(), + } + } - pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::CRYPTO_get_ex_new_index( - ffi::CRYPTO_EX_INDEX_SSL_CTX, - 0, - ptr::null_mut(), - None, - None, - Some(f), - ) + /// Configure as an outgoing stream from a client. + /// + /// This corresponds to [`SSL_set_connect_state`]. + /// + /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html + pub fn set_connect_state(&mut self) { + unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) } } - pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::CRYPTO_get_ex_new_index( - ffi::CRYPTO_EX_INDEX_SSL, - 0, - ptr::null_mut(), - None, - None, - Some(f), - ) + /// Configure as an incoming stream to a server. + /// + /// This corresponds to [`SSL_set_accept_state`]. + /// + /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html + pub fn set_accept_state(&mut self) { + unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) } } - pub fn tls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::TLS_method() } + /// See `Ssl::connect` + pub fn connect(mut self) -> Result, HandshakeError> { + match self.inner.connect() { + Ok(()) => Ok(self.inner), + Err(error) => match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(MidHandshakeSslStream { + stream: self.inner, + error, + })) + } + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream: self.inner, + error, + })), + }, + } } - pub fn dtls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::DTLS_method() } + /// See `Ssl::accept` + pub fn accept(mut self) -> Result, HandshakeError> { + match self.inner.accept() { + Ok(()) => Ok(self.inner), + Err(error) => match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(MidHandshakeSslStream { + stream: self.inner, + error, + })) + } + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream: self.inner, + error, + })), + }, + } } -} -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use std::ptr; + /// Initiates the handshake. + /// + /// This will fail if `set_accept_state` or `set_connect_state` was not called first. + /// + /// This corresponds to [`SSL_do_handshake`]. + /// + /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html + pub fn handshake(mut self) -> Result, HandshakeError> { + match self.inner.do_handshake() { + Ok(()) => Ok(self.inner), + Err(error) => match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(MidHandshakeSslStream { + stream: self.inner, + error, + })) + } + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream: self.inner, + error, + })), + }, + } + } - use ffi; - use libc::{self, c_int, c_long, c_uchar, c_ulong, size_t}; + /// Read application data transmitted by a client before handshake + /// completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_accept_state` first. + /// + /// Returns `Ok(0)` if all early data has been read. + /// + /// 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(any(ossl111, libressl340))] + pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result { + self.inner.read_early_data(buf) + } - pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong { - ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong + /// Send data to the server without blocking on handshake completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_connect_state` first. + /// + /// 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(any(ossl111, libressl340))] + pub fn write_early_data(&mut self, buf: &[u8]) -> Result { + self.inner.write_early_data(buf) } +} - pub unsafe fn SSL_CTX_set_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong { - ffi::SSL_CTX_ctrl( - ctx as *mut _, - ffi::SSL_CTRL_OPTIONS, - op as c_long, - ptr::null_mut(), - ) as c_ulong +#[allow(deprecated)] +impl SslStreamBuilder { + /// Returns a shared reference to the underlying stream. + pub fn get_ref(&self) -> &S { + unsafe { + let bio = self.inner.ssl.get_raw_rbio(); + bio::get_ref(bio) + } } - pub unsafe fn SSL_CTX_clear_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong { - ffi::SSL_CTX_ctrl( - ctx as *mut _, - ffi::SSL_CTRL_CLEAR_OPTIONS, - op as c_long, - ptr::null_mut(), - ) as c_ulong + /// Returns a mutable reference to the underlying stream. + /// + /// # Warning + /// + /// It is inadvisable to read from or write to the underlying stream as it + /// will most likely corrupt the SSL session. + pub fn get_mut(&mut self) -> &mut S { + unsafe { + let bio = self.inner.ssl.get_raw_rbio(); + bio::get_mut(bio) + } } - pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + /// Returns a shared reference to the `Ssl` object associated with this builder. + pub fn ssl(&self) -> &SslRef { + &self.inner.ssl } - pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + /// Set the DTLS MTU size. + /// + /// It will be ignored if the value is smaller than the minimum packet size + /// the DTLS protocol requires. + /// + /// # Panics + /// This function panics if the given mtu size can't be represented in a positive `c_long` range + #[deprecated(note = "Use SslRef::set_mtu instead", since = "0.10.30")] + pub fn set_dtls_mtu_size(&mut self, mtu_size: usize) { + unsafe { + let bio = self.inner.ssl.get_raw_rbio(); + bio::set_dtls_mtu_size::(bio, mtu_size); + } } +} - pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> libc::c_int { - ffi::CRYPTO_add_lock( - &mut (*ssl).references, - 1, - ffi::CRYPTO_LOCK_SSL_CTX, - "mod.rs\0".as_ptr() as *const _, - line!() as libc::c_int, - ); - 0 +/// The result of a shutdown request. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ShutdownResult { + /// A close notify message has been sent to the peer. + Sent, + + /// A close notify response message has been received from the peer. + Received, +} + +bitflags! { + /// The shutdown state of a session. + pub struct ShutdownState: c_int { + /// A close notify message has been sent to the peer. + const SENT = ffi::SSL_SENT_SHUTDOWN; + /// A close notify message has been received from the peer. + const RECEIVED = ffi::SSL_RECEIVED_SHUTDOWN; } +} - pub unsafe fn SSL_SESSION_get_master_key( - session: *const ffi::SSL_SESSION, - out: *mut c_uchar, - mut outlen: size_t, - ) -> size_t { - if outlen == 0 { - return (*session).master_key_length as size_t; +cfg_if! { + if #[cfg(any(boringssl, ossl110, libressl273))] { + use ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server}; + } else { + #[allow(bad_style)] + pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ssl).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 } - if outlen > (*session).master_key_length as size_t { - outlen = (*session).master_key_length as size_t; + + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_get_master_key( + session: *const ffi::SSL_SESSION, + out: *mut c_uchar, + mut outlen: usize, + ) -> usize { + if outlen == 0 { + return (*session).master_key_length as usize; + } + if outlen > (*session).master_key_length as usize { + outlen = (*session).master_key_length as usize; + } + ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); + outlen } - ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); - outlen - } - pub fn tls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::SSLv23_method() } - } + #[allow(bad_style)] + pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { + (*s).server + } - pub fn dtls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::DTLSv1_method() } + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ses).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 + } } +} - pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { - (*s).server +cfg_if! { + if #[cfg(ossl300)] { + use ffi::SSL_get1_peer_certificate; + } else { + use ffi::SSL_get_peer_certificate as SSL_get1_peer_certificate; } +} +cfg_if! { + if #[cfg(any(boringssl, ossl110, libressl291))] { + use ffi::{TLS_method, DTLS_method, TLS_client_method, TLS_server_method}; + } else { + use ffi::{ + SSLv23_method as TLS_method, DTLSv1_method as DTLS_method, SSLv23_client_method as TLS_client_method, + SSLv23_server_method as TLS_server_method, + }; + } +} +cfg_if! { + if #[cfg(ossl110)] { + unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL_CTX, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } - pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { - ffi::CRYPTO_add_lock( - &mut (*ses).references, - 1, - ffi::CRYPTO_LOCK_SSL_CTX, - "mod.rs\0".as_ptr() as *const _, - line!() as libc::c_int, - ); - 0 + unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } + } else { + use std::sync::Once; + + unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest + static ONCE: Once = Once::new(); + ONCE.call_once(|| { + cfg_if! { + if #[cfg(not(boringssl))] { + ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, None); + } else { + ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None); + } + } + }); + + cfg_if! { + if #[cfg(not(boringssl))] { + ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + } else { + ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f) + } + } + } + + unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest + static ONCE: Once = Once::new(); + ONCE.call_once(|| { + #[cfg(not(boringssl))] + ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, None); + #[cfg(boringssl)] + ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None); + }); + + #[cfg(not(boringssl))] + return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)); + #[cfg(boringssl)] + return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f); + } } } diff --git a/openssl/src/ssl/test/mod.rs b/openssl/src/ssl/test/mod.rs new file mode 100644 index 0000000..1eb9fe4 --- /dev/null +++ b/openssl/src/ssl/test/mod.rs @@ -0,0 +1,1493 @@ +#![allow(unused_imports)] + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::io::{self, BufReader}; +use std::iter; +use std::mem; +use std::net::UdpSocket; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::path::Path; +use std::process::{Child, ChildStdin, Command, Stdio}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::Duration; + +use crate::dh::Dh; +use crate::error::ErrorStack; +use crate::hash::MessageDigest; +#[cfg(not(boringssl))] +use crate::ocsp::{OcspResponse, OcspResponseStatus}; +use crate::pkey::PKey; +use crate::srtp::SrtpProfileId; +use crate::ssl; +use crate::ssl::test::server::Server; +#[cfg(any(ossl110, ossl111, libressl261))] +use crate::ssl::SslVersion; +#[cfg(ossl111)] +use crate::ssl::{ClientHelloResponse, ExtensionContext}; +use crate::ssl::{ + Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, ShutdownState, Ssl, SslAcceptor, + SslAcceptorBuilder, SslConnector, SslContext, SslContextBuilder, SslFiletype, SslMethod, + SslOptions, SslSessionCacheMode, SslStream, SslVerifyMode, StatusType, +}; +#[cfg(ossl102)] +use crate::x509::store::X509StoreBuilder; +#[cfg(ossl102)] +use crate::x509::verify::X509CheckFlags; +use crate::x509::{X509Name, X509StoreContext, X509VerifyResult, X509}; + +mod server; + +static ROOT_CERT: &[u8] = include_bytes!("../../../test/root-ca.pem"); +static CERT: &[u8] = include_bytes!("../../../test/cert.pem"); +static KEY: &[u8] = include_bytes!("../../../test/key.pem"); + +#[test] +fn verify_untrusted() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_verify(SslVerifyMode::PEER); + + client.connect_err(); +} + +#[test] +fn verify_trusted() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + + client.connect(); +} + +#[test] +#[cfg(ossl102)] +fn verify_trusted_with_set_cert() { + let server = Server::builder().build(); + + let mut store = X509StoreBuilder::new().unwrap(); + let x509 = X509::from_pem(ROOT_CERT).unwrap(); + store.add_cert(x509).unwrap(); + + let mut client = server.client(); + client.ctx().set_verify(SslVerifyMode::PEER); + client.ctx().set_verify_cert_store(store.build()).unwrap(); + + client.connect(); +} + +#[test] +fn verify_untrusted_callback_override_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_untrusted_callback_override_bad() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, _| false); + + client.connect_err(); +} + +#[test] +fn verify_trusted_callback_override_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_callback_override_bad() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, _| false); + + client.connect_err(); +} + +#[test] +fn verify_callback_load_certs() { + let server = Server::builder().build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_get_error_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert_eq!(x509.error(), X509VerifyResult::OK); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_get_error_err() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert_ne!(x509.error(), X509VerifyResult::OK); + false + }); + + client.connect_err(); +} + +#[test] +fn verify_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let server = Server::builder().build(); + + let mut client = server.client(); + let expected = "59172d9313e84459bcff27f967e79e6e9217e584"; + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, move |_, x509| { + 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); + true + }); + + client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn ssl_verify_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let server = Server::builder().build(); + + let mut client = server.client().build().builder(); + let expected = "59172d9313e84459bcff27f967e79e6e9217e584"; + client + .ssl() + .set_verify_callback(SslVerifyMode::PEER, move |_, x509| { + 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); + true + }); + + client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn get_ctx_options() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.options(); +} + +#[test] +fn set_ctx_options() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let opts = ctx.set_options(SslOptions::NO_TICKET); + assert!(opts.contains(SslOptions::NO_TICKET)); +} + +#[test] +#[cfg(not(boringssl))] +fn clear_ctx_options() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_options(SslOptions::ALL); + let opts = ctx.clear_options(SslOptions::ALL); + assert!(!opts.contains(SslOptions::ALL)); +} + +#[test] +fn zero_length_buffers() { + let server = Server::builder().build(); + + let mut s = server.client().connect(); + assert_eq!(s.write(&[]).unwrap(), 0); + assert_eq!(s.read(&mut []).unwrap(), 0); +} + +#[test] +fn peer_certificate() { + let server = Server::builder().build(); + + let s = server.client().connect(); + let cert = s.ssl().peer_certificate().unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + assert_eq!( + hex::encode(fingerprint), + "59172d9313e84459bcff27f967e79e6e9217e584" + ); +} + +#[test] +fn pending() { + let mut server = Server::builder(); + server.io_cb(|mut s| s.write_all(&[0; 10]).unwrap()); + let server = server.build(); + + let mut s = server.client().connect(); + s.read_exact(&mut [0]).unwrap(); + + assert_eq!(s.ssl().pending(), 9); + assert_eq!(s.read(&mut [0; 10]).unwrap(), 9); +} + +#[test] +fn state() { + let server = Server::builder().build(); + + let s = server.client().connect(); + #[cfg(not(boringssl))] + assert_eq!(s.ssl().state_string().trim(), "SSLOK"); + #[cfg(boringssl)] + assert_eq!(s.ssl().state_string(), "!!!!!!"); + assert_eq!( + s.ssl().state_string_long(), + "SSL negotiation finished successfully" + ); +} + +/// Tests that when both the client as well as the server use SRTP and their +/// lists of supported protocols have an overlap -- with only ONE protocol +/// being valid for both. +#[test] +fn test_connect_with_srtp_ctx() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + 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) + .unwrap(); + 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(); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 60]; + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_mtu(1500).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 60]; + { + let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); + assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); + assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); + } + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .expect("extract"); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf[..], buf2[..]); +} + +/// Tests that when both the client as well as the server use SRTP and their +/// lists of supported protocols have an overlap -- with only ONE protocol +/// being valid for both. +#[test] +fn test_connect_with_srtp_ssl() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + 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) + .unwrap(); + 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") + .unwrap(); + let mut profilenames = String::new(); + for profile in ssl.srtp_profiles().unwrap() { + if !profilenames.is_empty() { + profilenames.push(':'); + } + profilenames += profile.name(); + } + assert_eq!( + "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", + profilenames + ); + ssl.set_mtu(1500).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 60]; + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + ssl.set_mtu(1500).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 60]; + { + let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); + assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); + assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); + } + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .expect("extract"); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf[..], buf2[..]); +} + +/// Tests that when the `SslStream` is created as a server stream, the protocols +/// are correctly advertised to the client. +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_advertise_multiple() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) + }); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x08spdy/3.1").unwrap(); + let s = client.connect(); + assert_eq!(s.ssl().selected_alpn_protocol(), Some(&b"spdy/3.1"[..])); +} + +#[test] +#[cfg(any(ossl110))] +fn test_alpn_server_select_none_fatal() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client) + .ok_or(ssl::AlpnError::ALERT_FATAL) + }); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + client.connect_err(); +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_select_none() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) + }); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + let s = client.connect(); + assert_eq!(None, s.ssl().selected_alpn_protocol()); +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_unilateral() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + let s = client.connect(); + assert_eq!(None, s.ssl().selected_alpn_protocol()); +} + +#[test] +#[should_panic(expected = "blammo")] +fn write_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + } + + impl Write for ExplodingStream { + fn write(&mut self, _: &[u8]) -> io::Result { + panic!("blammo"); + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +#[should_panic(expected = "blammo")] +fn read_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, _: &mut [u8]) -> io::Result { + panic!("blammo"); + } + } + + impl Write for ExplodingStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +#[cfg_attr(all(libressl321, not(libressl340)), ignore)] +#[should_panic(expected = "blammo")] +fn flush_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + } + + impl Write for ExplodingStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + panic!("blammo"); + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +fn refcount_ssl_context() { + let mut ssl = { + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ssl::Ssl::new(&ctx.build()).unwrap() + }; + + { + let new_ctx_a = SslContext::builder(SslMethod::tls()).unwrap().build(); + let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); + } +} + +#[test] +#[cfg_attr(libressl250, ignore)] +#[cfg_attr(target_os = "windows", ignore)] +#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] +fn default_verify_paths() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_default_verify_paths().unwrap(); + ctx.set_verify(SslVerifyMode::PEER); + let ctx = ctx.build(); + let s = match TcpStream::connect("google.com:443") { + Ok(s) => s, + Err(_) => return, + }; + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_hostname("google.com").unwrap(); + let mut socket = ssl.connect(s).unwrap(); + + socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut result = vec![]; + socket.read_to_end(&mut result).unwrap(); + + println!("{}", String::from_utf8_lossy(&result)); + assert!(result.starts_with(b"HTTP/1.0")); + assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); +} + +#[test] +fn add_extra_chain_cert() { + let cert = X509::from_pem(CERT).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.add_extra_chain_cert(cert).unwrap(); +} + +#[test] +#[cfg(ossl102)] +fn verify_valid_hostname() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + client + .ssl() + .param_mut() + .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + client.ssl().param_mut().set_host("foobar.com").unwrap(); + client.connect(); +} + +#[test] +#[cfg(ossl102)] +fn verify_invalid_hostname() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + client + .ssl() + .param_mut() + .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + client.ssl().param_mut().set_host("bogus.com").unwrap(); + client.connect_err(); +} + +#[test] +fn connector_valid_hostname() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector.build().connect("foobar.com", s).unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_invalid_hostname() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + connector.build().connect("bogus.com", s).unwrap_err(); +} + +#[test] +fn connector_invalid_no_hostname_verification() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector + .build() + .configure() + .unwrap() + .verify_hostname(false) + .connect("bogus.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_no_hostname_still_verifies() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); + + let s = server.connect_tcp(); + assert!(connector + .configure() + .unwrap() + .verify_hostname(false) + .connect("fizzbuzz.com", s) + .is_err()); +} + +#[test] +fn connector_no_hostname_can_disable_verify() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_verify(SslVerifyMode::NONE); + let connector = connector.build(); + + let s = server.connect_tcp(); + let mut s = connector + .configure() + .unwrap() + .verify_hostname(false) + .connect("foobar.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +fn test_mozilla_server(new: fn(SslMethod) -> Result) { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + let t = thread::spawn(move || { + let key = PKey::private_key_from_pem(KEY).unwrap(); + let cert = X509::from_pem(CERT).unwrap(); + let mut acceptor = new(SslMethod::tls()).unwrap(); + acceptor.set_private_key(&key).unwrap(); + acceptor.set_certificate(&cert).unwrap(); + let acceptor = acceptor.build(); + let stream = listener.accept().unwrap().0; + let mut stream = acceptor.accept(stream).unwrap(); + + stream.write_all(b"hello").unwrap(); + }); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + let connector = connector.build(); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut stream = connector.connect("foobar.com", stream).unwrap(); + + let mut buf = [0; 5]; + stream.read_exact(&mut buf).unwrap(); + assert_eq!(b"hello", &buf); + + t.join().unwrap(); +} + +#[test] +fn connector_client_server_mozilla_intermediate() { + test_mozilla_server(SslAcceptor::mozilla_intermediate); +} + +#[test] +fn connector_client_server_mozilla_modern() { + test_mozilla_server(SslAcceptor::mozilla_modern); +} + +#[test] +fn connector_client_server_mozilla_intermediate_v5() { + test_mozilla_server(SslAcceptor::mozilla_intermediate_v5); +} + +#[test] +#[cfg(any(ossl111, libressl340))] +fn connector_client_server_mozilla_modern_v5() { + test_mozilla_server(SslAcceptor::mozilla_modern_v5); +} + +#[test] +fn shutdown() { + let mut server = Server::builder(); + server.io_cb(|mut s| { + assert_eq!(s.read(&mut [0]).unwrap(), 0); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Received); + }); + let server = server.build(); + + let mut s = server.client().connect(); + + assert_eq!(s.get_shutdown(), ShutdownState::empty()); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Sent); + assert_eq!(s.get_shutdown(), ShutdownState::SENT); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Received); + assert_eq!( + s.get_shutdown(), + ShutdownState::SENT | ShutdownState::RECEIVED + ); +} + +#[test] +fn client_ca_list() { + let names = X509Name::load_client_ca_file("test/root-ca.pem").unwrap(); + assert_eq!(names.len(), 1); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_client_ca_list(names); +} + +#[test] +fn cert_store() { + let server = Server::builder().build(); + + let mut client = server.client(); + let cert = X509::from_pem(ROOT_CERT).unwrap(); + client.ctx().cert_store_mut().add_cert(cert).unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + client.connect(); +} + +#[test] +#[cfg_attr(any(all(libressl321, not(libressl340)), boringssl), ignore)] +fn tmp_dh_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::params_from_pem(dh) + }); + + let server = server.build(); + + let mut client = server.client(); + // TLS 1.3 has no DH suites, so make sure we don't pick that version + #[cfg(any(ossl111, libressl340))] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list("EDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(all(ossl101, not(ossl110)))] +#[allow(deprecated)] +fn tmp_ecdh_callback() { + use crate::ec::EcKey; + use crate::nid::Nid; + + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::from_curve_name(Nid::X9_62_PRIME256V1) + }); + + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_cipher_list("ECDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg_attr(any(all(libressl321, not(libressl340)), boringssl), ignore)] +fn tmp_dh_callback_ssl() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ssl_cb(|ssl| { + ssl.set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::params_from_pem(dh) + }); + }); + + let server = server.build(); + + let mut client = server.client(); + // TLS 1.3 has no DH suites, so make sure we don't pick that version + #[cfg(any(ossl111, libressl340))] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list("EDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(all(ossl101, not(ossl110)))] +#[allow(deprecated)] +fn tmp_ecdh_callback_ssl() { + use crate::ec::EcKey; + use crate::nid::Nid; + + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ssl_cb(|ssl| { + ssl.set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::from_curve_name(Nid::X9_62_PRIME256V1) + }); + }); + + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_cipher_list("ECDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn idle_session() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.session().is_none()); +} + +/// possible LibreSSL bug since 3.2.1 +#[test] +#[cfg_attr(libressl321, ignore)] +fn active_session() { + let server = Server::builder().build(); + + let s = server.client().connect(); + + let session = s.ssl().session().unwrap(); + let len = session.master_key_len(); + let mut buf = vec![0; len - 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, buf.len()); + let mut buf = vec![0; len + 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, len); +} + +#[test] +#[cfg(not(boringssl))] +fn status_callbacks() { + static CALLED_BACK_SERVER: AtomicBool = AtomicBool::new(false); + static CALLED_BACK_CLIENT: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server + .ctx() + .set_status_callback(|ssl| { + CALLED_BACK_SERVER.store(true, Ordering::SeqCst); + let response = OcspResponse::create(OcspResponseStatus::UNAUTHORIZED, None).unwrap(); + let response = response.to_der().unwrap(); + ssl.set_ocsp_status(&response).unwrap(); + Ok(true) + }) + .unwrap(); + + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_status_callback(|ssl| { + CALLED_BACK_CLIENT.store(true, Ordering::SeqCst); + let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); + assert_eq!(response.status(), OcspResponseStatus::UNAUTHORIZED); + Ok(true) + }) + .unwrap(); + + let mut client = client.build().builder(); + client.ssl().set_status_type(StatusType::OCSP).unwrap(); + + client.connect(); + + assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); + assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); +} + +/// possible LibreSSL bug since 3.2.1 +#[test] +#[cfg_attr(libressl321, ignore)] +fn new_session_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_session_id_context(b"foo").unwrap(); + + let server = server.build(); + + let mut client = server.client(); + + client + .ctx() + .set_session_cache_mode(SslSessionCacheMode::CLIENT | SslSessionCacheMode::NO_INTERNAL); + client + .ctx() + .set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); + + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +/// possible LibreSSL bug since 3.2.1 +#[test] +#[cfg_attr(libressl321, ignore)] +fn new_session_callback_swapped_ctx() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_session_id_context(b"foo").unwrap(); + + let server = server.build(); + + let mut client = server.client(); + + client + .ctx() + .set_session_cache_mode(SslSessionCacheMode::CLIENT | SslSessionCacheMode::NO_INTERNAL); + client + .ctx() + .set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); + + let mut client = client.build().builder(); + + let ctx = SslContextBuilder::new(SslMethod::tls()).unwrap().build(); + client.ssl().set_ssl_context(&ctx).unwrap(); + + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn keying_export() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let label = "EXPERIMENTAL test"; + let context = b"my context"; + + 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) + .unwrap(); + 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(); + + let mut buf = [0; 32]; + stream + .ssl() + .export_keying_material(&mut buf, label, Some(context)) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 32]; + stream + .ssl() + .export_keying_material(&mut buf, label, Some(context)) + .unwrap(); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf, buf2); +} + +#[test] +#[cfg(any(ossl110, libressl261))] +fn no_version_overlap() { + let mut server = Server::builder(); + server.ctx().set_min_proto_version(None).unwrap(); + server + .ctx() + .set_max_proto_version(Some(SslVersion::TLS1_1)) + .unwrap(); + #[cfg(any(ossl110g, libressl270))] + assert_eq!(server.ctx().max_proto_version(), Some(SslVersion::TLS1_1)); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_min_proto_version(Some(SslVersion::TLS1_2)) + .unwrap(); + #[cfg(ossl110g)] + assert_eq!(client.ctx().min_proto_version(), Some(SslVersion::TLS1_2)); + client.ctx().set_max_proto_version(None).unwrap(); + + client.connect_err(); +} + +#[test] +#[cfg(ossl111)] +fn custom_extensions() { + static FOUND_EXTENSION: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server + .ctx() + .add_custom_ext( + 12345, + ExtensionContext::CLIENT_HELLO, + |_, _, _| -> Result, _> { unreachable!() }, + |_, _, data, _| { + FOUND_EXTENSION.store(data == b"hello", Ordering::SeqCst); + Ok(()) + }, + ) + .unwrap(); + + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .add_custom_ext( + 12345, + ssl::ExtensionContext::CLIENT_HELLO, + |_, _, _| Ok(Some(b"hello")), + |_, _, _, _| unreachable!(), + ) + .unwrap(); + + client.connect(); + + assert!(FOUND_EXTENSION.load(Ordering::SeqCst)); +} + +fn _check_kinds() { + fn is_send() {} + fn is_sync() {} + + is_send::>(); + is_sync::>(); +} + +#[test] +#[cfg(ossl111)] +fn stateless() { + use super::SslOptions; + + #[derive(Debug)] + struct MemoryStream { + incoming: io::Cursor>, + outgoing: Vec, + } + + impl MemoryStream { + pub fn new() -> Self { + Self { + incoming: io::Cursor::new(Vec::new()), + outgoing: Vec::new(), + } + } + + pub fn extend_incoming(&mut self, data: &[u8]) { + self.incoming.get_mut().extend_from_slice(data); + } + + pub fn take_outgoing(&mut self) -> Outgoing<'_> { + Outgoing(&mut self.outgoing) + } + } + + impl Read for MemoryStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let n = self.incoming.read(buf)?; + if self.incoming.position() == self.incoming.get_ref().len() as u64 { + self.incoming.set_position(0); + self.incoming.get_mut().clear(); + } + if n == 0 { + return Err(io::Error::new( + io::ErrorKind::WouldBlock, + "no data available", + )); + } + Ok(n) + } + } + + impl Write for MemoryStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.outgoing.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + pub struct Outgoing<'a>(&'a mut Vec); + + impl<'a> Drop for Outgoing<'a> { + fn drop(&mut self) { + self.0.clear(); + } + } + + impl<'a> ::std::ops::Deref for Outgoing<'a> { + type Target = [u8]; + fn deref(&self) -> &[u8] { + self.0 + } + } + + impl<'a> AsRef<[u8]> for Outgoing<'a> { + fn as_ref(&self) -> &[u8] { + self.0 + } + } + + fn send(from: &mut MemoryStream, to: &mut MemoryStream) { + to.extend_incoming(&from.take_outgoing()); + } + + // + // Setup + // + + let mut client_ctx = SslContext::builder(SslMethod::tls()).unwrap(); + client_ctx.clear_options(SslOptions::ENABLE_MIDDLEBOX_COMPAT); + let mut client_stream = + SslStream::new(Ssl::new(&client_ctx.build()).unwrap(), MemoryStream::new()).unwrap(); + + let mut server_ctx = SslContext::builder(SslMethod::tls()).unwrap(); + server_ctx + .set_certificate_file(Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + server_ctx + .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| { + buf[0..COOKIE.len()].copy_from_slice(COOKIE); + Ok(COOKIE.len()) + }); + server_ctx.set_stateless_cookie_verify_cb(|_tls, buf| buf == COOKIE); + let mut server_stream = + SslStream::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new()).unwrap(); + + // + // Handshake + // + + // Initial ClientHello + client_stream.connect().unwrap_err(); + send(client_stream.get_mut(), server_stream.get_mut()); + // HelloRetryRequest + assert!(!server_stream.stateless().unwrap()); + send(server_stream.get_mut(), client_stream.get_mut()); + // Second ClientHello + client_stream.do_handshake().unwrap_err(); + send(client_stream.get_mut(), server_stream.get_mut()); + // OldServerHello + assert!(server_stream.stateless().unwrap()); + server_stream.accept().unwrap_err(); + send(server_stream.get_mut(), client_stream.get_mut()); + // Finished + client_stream.do_handshake().unwrap(); + send(client_stream.get_mut(), server_stream.get_mut()); + server_stream.do_handshake().unwrap(); +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +#[test] +fn psk_ciphers() { + const CIPHER: &str = "PSK-AES256-CBC-SHA"; + const PSK: &[u8] = b"thisisaverysecurekey"; + const CLIENT_IDENT: &[u8] = b"thisisaclient"; + static CLIENT_CALLED: AtomicBool = AtomicBool::new(false); + static SERVER_CALLED: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_cipher_list(CIPHER).unwrap(); + server.ctx().set_psk_server_callback(|_, identity, psk| { + assert!(identity.unwrap_or(&[]) == CLIENT_IDENT); + psk[..PSK.len()].copy_from_slice(PSK); + SERVER_CALLED.store(true, Ordering::SeqCst); + Ok(PSK.len()) + }); + + let server = server.build(); + + let mut client = server.client(); + // This test relies on TLS 1.2 suites + #[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| { + identity[..CLIENT_IDENT.len()].copy_from_slice(CLIENT_IDENT); + identity[CLIENT_IDENT.len()] = 0; + psk[..PSK.len()].copy_from_slice(PSK); + CLIENT_CALLED.store(true, Ordering::SeqCst); + Ok(PSK.len()) + }); + + client.connect(); + + assert!(SERVER_CALLED.load(Ordering::SeqCst)); + assert!(CLIENT_CALLED.load(Ordering::SeqCst)); +} + +#[test] +fn sni_callback_swapped_ctx() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_servername_callback(|_, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(()) + }); + + let keyed_ctx = mem::replace(server.ctx(), ctx).build(); + server.ssl_cb(move |ssl| ssl.set_ssl_context(&keyed_ctx).unwrap()); + + let server = server.build(); + + server.client().connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(ossl111)] +fn client_hello() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_client_hello_callback(|ssl, _| { + assert!(!ssl.client_hello_isv2()); + assert_eq!(ssl.client_hello_legacy_version(), Some(SslVersion::TLS1_2)); + assert!(ssl.client_hello_random().is_some()); + assert!(ssl.client_hello_session_id().is_some()); + assert!(ssl.client_hello_ciphers().is_some()); + assert!(ssl.client_hello_compression_methods().is_some()); + + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(ClientHelloResponse::SUCCESS) + }); + + let server = server.build(); + server.client().connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(ossl111)] +fn openssl_cipher_name() { + assert_eq!( + super::cipher_name("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"), + "ECDHE-RSA-AES256-SHA384", + ); + + assert_eq!(super::cipher_name("asdf"), "(NONE)"); +} + +#[test] +fn session_cache_size() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_session_cache_size(1234); + let ctx = ctx.build(); + assert_eq!(ctx.session_cache_size(), 1234); +} + +#[test] +#[cfg(ossl102)] +fn add_chain_cert() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let cert = X509::from_pem(CERT).unwrap(); + let mut ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.add_chain_cert(cert).is_ok()); +} +#[test] +#[cfg(ossl111)] +fn set_ssl_certificate_key_related_api() { + let cert_str: &str = include_str!("../../../test/cert.pem"); + let key_str: &str = include_str!("../../../test/key.pem"); + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let cert_x509 = X509::from_pem(CERT).unwrap(); + let mut ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.set_method(SslMethod::tls()).is_ok()); + ssl.set_private_key_file("test/key.pem", SslFiletype::PEM) + .unwrap(); + { + let pkey = String::from_utf8( + ssl.private_key() + .unwrap() + .private_key_to_pem_pkcs8() + .unwrap(), + ) + .unwrap(); + assert!(pkey.lines().eq(key_str.lines())); + } + let pkey = PKey::private_key_from_pem(KEY).unwrap(); + ssl.set_private_key(pkey.as_ref()).unwrap(); + { + let pkey = String::from_utf8( + ssl.private_key() + .unwrap() + .private_key_to_pem_pkcs8() + .unwrap(), + ) + .unwrap(); + assert!(pkey.lines().eq(key_str.lines())); + } + ssl.set_certificate(cert_x509.as_ref()).unwrap(); + let cert = String::from_utf8(ssl.certificate().unwrap().to_pem().unwrap()).unwrap(); + assert!(cert.lines().eq(cert_str.lines())); + ssl.add_client_ca(cert_x509.as_ref()).unwrap(); + ssl.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap(); + ssl.set_max_proto_version(Some(SslVersion::TLS1_3)).unwrap(); + ssl.set_cipher_list("HIGH:!aNULL:!MD5").unwrap(); + ssl.set_ciphersuites("TLS_AES_128_GCM_SHA256").unwrap(); + let x509 = X509::from_pem(ROOT_CERT).unwrap(); + let mut builder = X509StoreBuilder::new().unwrap(); + builder.add_cert(x509).unwrap(); + let store = builder.build(); + ssl.set_verify_cert_store(store).unwrap(); +} + +#[test] +#[cfg(ossl110)] +fn test_ssl_set_cert_chain_file() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_certificate_chain_file("test/cert.pem").unwrap(); +} + +#[test] +#[cfg(ossl111)] +fn set_num_tickets() { + let mut ctx = SslContext::builder(SslMethod::tls_server()).unwrap(); + ctx.set_num_tickets(3).unwrap(); + let ctx = ctx.build(); + assert_eq!(3, ctx.num_tickets()); + + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_num_tickets(5).unwrap(); + let ssl = ssl; + assert_eq!(5, ssl.num_tickets()); +} diff --git a/openssl/src/ssl/test/server.rs b/openssl/src/ssl/test/server.rs new file mode 100644 index 0000000..41677e5 --- /dev/null +++ b/openssl/src/ssl/test/server.rs @@ -0,0 +1,167 @@ +use std::io::{Read, Write}; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::thread::{self, JoinHandle}; + +use crate::ssl::{Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, SslRef, SslStream}; + +pub struct Server { + handle: Option>, + addr: SocketAddr, +} + +impl Drop for Server { + fn drop(&mut self) { + if !thread::panicking() { + self.handle.take().unwrap().join().unwrap(); + } + } +} + +impl Server { + pub fn builder() -> Builder { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_chain_file("test/cert.pem").unwrap(); + ctx.set_private_key_file("test/key.pem", SslFiletype::PEM) + .unwrap(); + + Builder { + ctx, + ssl_cb: Box::new(|_| {}), + io_cb: Box::new(|_| {}), + should_error: false, + } + } + + pub fn client(&self) -> ClientBuilder { + ClientBuilder { + ctx: SslContext::builder(SslMethod::tls()).unwrap(), + addr: self.addr, + } + } + + pub fn connect_tcp(&self) -> TcpStream { + TcpStream::connect(self.addr).unwrap() + } +} + +pub struct Builder { + ctx: SslContextBuilder, + ssl_cb: Box, + io_cb: Box) + Send>, + should_error: bool, +} + +impl Builder { + pub fn ctx(&mut self) -> &mut SslContextBuilder { + &mut self.ctx + } + + pub fn ssl_cb(&mut self, cb: F) + where + F: 'static + FnMut(&mut SslRef) + Send, + { + self.ssl_cb = Box::new(cb); + } + + pub fn io_cb(&mut self, cb: F) + where + F: 'static + FnMut(SslStream) + Send, + { + self.io_cb = Box::new(cb); + } + + pub fn should_error(&mut self) { + self.should_error = true; + } + + pub fn build(self) -> Server { + let ctx = self.ctx.build(); + let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = socket.local_addr().unwrap(); + let mut ssl_cb = self.ssl_cb; + let mut io_cb = self.io_cb; + let should_error = self.should_error; + + let handle = thread::spawn(move || { + let socket = socket.accept().unwrap().0; + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl_cb(&mut ssl); + let r = ssl.accept(socket); + if should_error { + r.unwrap_err(); + } else { + let mut socket = r.unwrap(); + socket.write_all(&[0]).unwrap(); + io_cb(socket); + } + }); + + Server { + handle: Some(handle), + addr, + } + } +} + +pub struct ClientBuilder { + ctx: SslContextBuilder, + addr: SocketAddr, +} + +impl ClientBuilder { + pub fn ctx(&mut self) -> &mut SslContextBuilder { + &mut self.ctx + } + + pub fn build(self) -> Client { + Client { + ctx: self.ctx.build(), + addr: self.addr, + } + } + + pub fn connect(self) -> SslStream { + self.build().builder().connect() + } + + pub fn connect_err(self) { + self.build().builder().connect_err(); + } +} + +pub struct Client { + ctx: SslContext, + addr: SocketAddr, +} + +impl Client { + pub fn builder(&self) -> ClientSslBuilder { + ClientSslBuilder { + ssl: Ssl::new(&self.ctx).unwrap(), + addr: self.addr, + } + } +} + +pub struct ClientSslBuilder { + ssl: Ssl, + addr: SocketAddr, +} + +impl ClientSslBuilder { + pub fn ssl(&mut self) -> &mut SslRef { + &mut self.ssl + } + + pub fn connect(self) -> SslStream { + let socket = TcpStream::connect(self.addr).unwrap(); + let mut s = self.ssl.connect(socket).unwrap(); + s.read_exact(&mut [0]).unwrap(); + s + } + + pub fn connect_err(self) { + let socket = TcpStream::connect(self.addr).unwrap(); + self.ssl.connect(socket).unwrap_err(); + } +} diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs deleted file mode 100644 index 1cc36c7..0000000 --- a/openssl/src/ssl/tests/mod.rs +++ /dev/null @@ -1,1416 +0,0 @@ -#![allow(unused_imports)] - -use std::env; -use std::fs::File; -use std::io::prelude::*; -use std::io::{self, BufReader}; -use std::iter; -use std::mem; -use std::net::{TcpStream, TcpListener, SocketAddr}; -use std::path::Path; -use std::process::{Command, Child, Stdio, ChildStdin}; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; -use std::thread; -use std::time::Duration; -use tempdir::TempDir; - -use dh::Dh; -use hash::MessageDigest; -use ocsp::{OcspResponse, RESPONSE_STATUS_UNAUTHORIZED}; -use ssl; -use ssl::{SslMethod, HandshakeError, SslContext, SslStream, Ssl, ShutdownResult, - SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE, - STATUS_TYPE_OCSP}; -use x509::{X509StoreContext, X509, X509Name, X509_FILETYPE_PEM}; -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; -use pkey::PKey; - -use std::net::UdpSocket; - -mod select; - -static ROOT_CERT: &'static [u8] = include_bytes!("../../../test/root-ca.pem"); -static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem"); -static KEY: &'static [u8] = include_bytes!("../../../test/key.pem"); - -fn next_addr() -> SocketAddr { - use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - static PORT: AtomicUsize = ATOMIC_USIZE_INIT; - let port = 15411 + PORT.fetch_add(1, Ordering::SeqCst); - - format!("127.0.0.1:{}", port).parse().unwrap() -} - -struct Server { - p: Child, - _temp: TempDir, -} - -impl Server { - fn spawn(args: &[&str], input: Option>) -> (Server, SocketAddr) { - let td = TempDir::new("openssl").unwrap(); - let cert = td.path().join("cert.pem"); - let key = td.path().join("key.pem"); - File::create(&cert).unwrap().write_all(CERT).unwrap(); - File::create(&key).unwrap().write_all(KEY).unwrap(); - - let addr = next_addr(); - let mut child = Command::new("openssl") - .arg("s_server") - .arg("-accept") - .arg(addr.port().to_string()) - .args(args) - .arg("-cert") - .arg(&cert) - .arg("-key") - .arg(&key) - .arg("-no_dhe") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .stdin(Stdio::piped()) - .spawn() - .unwrap(); - let stdin = child.stdin.take().unwrap(); - if let Some(mut input) = input { - thread::spawn(move || input(stdin)); - } - ( - Server { - p: child, - _temp: td, - }, - addr, - ) - } - - fn new_tcp(args: &[&str]) -> (Server, TcpStream) { - let (server, addr) = Server::spawn(args, None); - for _ in 0..20 { - match TcpStream::connect(&addr) { - Ok(s) => return (server, s), - Err(ref e) if e.kind() == io::ErrorKind::ConnectionRefused => { - thread::sleep(Duration::from_millis(100)); - } - Err(e) => panic!("wut: {}", e), - } - } - panic!("server never came online"); - } - - fn new() -> (Server, TcpStream) { - Server::new_tcp(&["-www"]) - } - - #[allow(dead_code)] - fn new_alpn() -> (Server, TcpStream) { - Server::new_tcp( - &[ - "-www", - "-nextprotoneg", - "http/1.1,spdy/3.1", - "-alpn", - "http/1.1,spdy/3.1", - ], - ) - } -} - -impl Drop for Server { - fn drop(&mut self) { - let _ = self.p.kill(); - let _ = self.p.wait(); - } -} - -macro_rules! run_test( - ($module:ident, $blk:expr) => ( - #[cfg(test)] - mod $module { - use std::io; - use std::io::prelude::*; - use std::path::Path; - use std::net::UdpSocket; - use std::net::TcpStream; - use ssl; - use ssl::SslMethod; - use ssl::{SslContext, Ssl, SslStream}; - use ssl::SSL_VERIFY_PEER; - use hash::MessageDigest; - use x509::X509StoreContext; - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - use x509::X509; - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - use x509::store::X509StoreBuilder; - use hex::FromHex; - use foreign_types::ForeignTypeRef; - use super::Server; - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - use super::ROOT_CERT; - - #[test] - fn sslv23() { - let (_s, stream) = Server::new(); - $blk(SslMethod::tls(), stream); - } - } - ); -); - -run_test!( - new_ctx, - |method, _| { SslContext::builder(method).unwrap(); } -); - -run_test!(verify_untrusted, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => panic!("expected failure"), - Err(err) => println!("error {:?}", err), - } -}); - -run_test!(verify_trusted, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -run_test!(verify_trusted_with_set_cert, |method, stream| { - let x509 = X509::from_pem(ROOT_CERT).unwrap(); - let mut store = X509StoreBuilder::new().unwrap(); - store.add_cert(x509).unwrap(); - - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - - match ctx.set_verify_cert_store(store.build()) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(verify_untrusted_callback_override_ok, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true); - - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(verify_untrusted_callback_override_bad, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false); - - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err()); -}); - -run_test!(verify_trusted_callback_override_ok, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true); - - match ctx.set_ca_file(&Path::new("test/cert.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(verify_trusted_callback_override_bad, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false); - - match ctx.set_ca_file(&Path::new("test/cert.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err()); -}); - -run_test!(verify_callback_load_certs, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| { - assert!(x509_ctx.current_cert().is_some()); - true - }); - - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_ok()); -}); - -run_test!(verify_trusted_get_error_ok, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| { - assert!(x509_ctx.error().is_none()); - true - }); - - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_ok()); -}); - -run_test!(verify_trusted_get_error_err, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| { - assert!(x509_ctx.error().is_some()); - false - }); - - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err()); -}); - -run_test!(verify_callback_data, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - - // Node id was generated as SHA256 hash of certificate "test/cert.pem" - // in DER format. - // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 - // Please update if "test/cert.pem" will ever change - let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = Vec::from_hex(node_hash_str).unwrap(); - ctx.set_verify_callback(SSL_VERIFY_PEER, move |_preverify_ok, x509_ctx| { - let cert = x509_ctx.current_cert(); - match cert { - None => false, - Some(cert) => { - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); - fingerprint == node_id - } - } - }); - ctx.set_verify_depth(1); - - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(ssl_verify_callback, |method, stream| { - use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - - static CHECKED: AtomicUsize = ATOMIC_USIZE_INIT; - - let ctx = SslContext::builder(method).unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - - let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = Vec::from_hex(node_hash_str).unwrap(); - ssl.set_verify_callback(SSL_VERIFY_PEER, move |_, x509| { - CHECKED.store(1, Ordering::SeqCst); - match x509.current_cert() { - None => false, - Some(cert) => { - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); - fingerprint == node_id - } - } - }); - - match ssl.connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } - - assert_eq!(CHECKED.load(Ordering::SeqCst), 1); -}); - -// Make sure every write call translates to a write call to the underlying socket. -#[test] -fn test_write_hits_stream() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let guard = thread::spawn(move || { - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let stream = TcpStream::connect(addr).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - stream - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - let stream = listener.accept().unwrap().0; - let mut stream = Ssl::new(&ctx.build()).unwrap().accept(stream).unwrap(); - - let mut buf = [0; 5]; - assert_eq!(5, stream.read(&mut buf).unwrap()); - assert_eq!(&b"hello"[..], &buf[..]); - guard.join().unwrap(); -} - -#[test] -fn test_set_certificate_and_private_key() { - let key = include_bytes!("../../../test/key.pem"); - let key = PKey::private_key_from_pem(key).unwrap(); - let cert = include_bytes!("../../../test/cert.pem"); - let cert = X509::from_pem(cert).unwrap(); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_private_key(&key).unwrap(); - ctx.set_certificate(&cert).unwrap(); - - assert!(ctx.check_private_key().is_ok()); -} - -run_test!(get_ctx_options, |method, _| { - let ctx = SslContext::builder(method).unwrap(); - ctx.options(); -}); - -run_test!(set_ctx_options, |method, _| { - let mut ctx = SslContext::builder(method).unwrap(); - let opts = ctx.set_options(ssl::SSL_OP_NO_TICKET); - assert!(opts.contains(ssl::SSL_OP_NO_TICKET)); -}); - -run_test!(clear_ctx_options, |method, _| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_options(ssl::SSL_OP_ALL); - let opts = ctx.clear_options(ssl::SSL_OP_ALL); - assert!(!opts.contains(ssl::SSL_OP_ALL)); -}); - -#[test] -fn test_write() { - let (_s, stream) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - stream.write_all("hello".as_bytes()).unwrap(); - stream.flush().unwrap(); - stream.write_all(" there".as_bytes()).unwrap(); - stream.flush().unwrap(); -} - -#[test] -fn zero_length_buffers() { - let (_s, stream) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - - assert_eq!(stream.write(b"").unwrap(), 0); - assert_eq!(stream.read(&mut []).unwrap(), 0); -} - -run_test!(get_peer_certificate, |method, stream| { - let ctx = SslContext::builder(method).unwrap(); - let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - let cert = stream.ssl().peer_certificate().unwrap(); - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); - let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = Vec::from_hex(node_hash_str).unwrap(); - assert_eq!(node_id, fingerprint) -}); - -#[test] -fn test_read() { - let (_s, tcp) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap(); - stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); - stream.flush().unwrap(); - io::copy(&mut stream, &mut io::sink()).ok().expect( - "read error", - ); -} - -#[test] -fn test_pending() { - let (_s, tcp) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap(); - stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); - stream.flush().unwrap(); - - // wait for the response and read first byte... - let mut buf = [0u8; 16 * 1024]; - stream.read(&mut buf[..1]).unwrap(); - - let pending = stream.ssl().pending(); - let len = stream.read(&mut buf[1..]).unwrap(); - - assert_eq!(pending, len); - - stream.read(&mut buf[..1]).unwrap(); - - let pending = stream.ssl().pending(); - let len = stream.read(&mut buf[1..]).unwrap(); - assert_eq!(pending, len); -} - -#[test] -fn test_state() { - let (_s, tcp) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap(); - assert_eq!(stream.ssl().state_string(), "SSLOK "); - assert_eq!( - stream.ssl().state_string_long(), - "SSL negotiation finished successfully" - ); -} - -/// Tests that connecting with the client using ALPN, but the server not does not -/// break the existing connection behavior. -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn test_connect_with_unilateral_alpn() { - let (_s, stream) = Server::new(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // Since the socket to which we connected is not configured to use ALPN, - // there should be no selected protocol... - assert!(stream.ssl().selected_alpn_protocol().is_none()); -} - -/// Tests that connecting with the client using NPN, but the server not does not -/// break the existing connection behavior. -#[test] -#[cfg(not(any(libressl261, libressl262, libressl26x)))] -fn test_connect_with_unilateral_npn() { - let (_s, stream) = Server::new(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // Since the socket to which we connected is not configured to use NPN, - // there should be no selected protocol... - assert!(stream.ssl().selected_npn_protocol().is_none()); -} - -/// Tests that when both the client as well as the server use ALPN and their -/// lists of supported protocols have an overlap, the correct protocol is chosen. -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn test_connect_with_alpn_successful_multiple_matching() { - let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // The server prefers "http/1.1", so that is chosen, even though the client - // would prefer "spdy/3.1" - assert_eq!(b"http/1.1", stream.ssl().selected_alpn_protocol().unwrap()); -} - -/// Tests that when both the client as well as the server use NPN and their -/// lists of supported protocols have an overlap, the correct protocol is chosen. -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn test_connect_with_npn_successful_multiple_matching() { - let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // The server prefers "http/1.1", so that is chosen, even though the client - // would prefer "spdy/3.1" - assert_eq!(b"http/1.1", stream.ssl().selected_npn_protocol().unwrap()); -} - -/// Tests that when both the client as well as the server use ALPN and their -/// lists of supported protocols have an overlap -- with only ONE protocol -/// being valid for both. -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn test_connect_with_alpn_successful_single_match() { - let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_alpn_protocols(&[b"spdy/3.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // The client now only supports one of the server's protocols, so that one - // is used. - assert_eq!(b"spdy/3.1", stream.ssl().selected_alpn_protocol().unwrap()); -} - - -/// Tests that when both the client as well as the server use NPN and their -/// lists of supported protocols have an overlap -- with only ONE protocol -/// being valid for both. -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn test_connect_with_npn_successful_single_match() { - let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_npn_protocols(&[b"spdy/3.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // The client now only supports one of the server's protocols, so that one - // is used. - assert_eq!(b"spdy/3.1", stream.ssl().selected_npn_protocol().unwrap()); -} - -/// Tests that when the `SslStream` is created as a server stream, the protocols -/// are correctly advertised to the client. -#[test] -#[cfg(not(any(libressl261, libressl262, libressl26x)))] -fn test_npn_server_advertise_multiple() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let localhost = listener.local_addr().unwrap(); - // We create a different context instance for the server... - let listener_ctx = { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap(); - assert!( - ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM) - .is_ok() - ); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - ctx.build() - }; - // Have the listener wait on the connection in a different thread. - thread::spawn(move || { - let (stream, _) = listener.accept().unwrap(); - Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_npn_protocols(&[b"spdy/3.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - // Now connect to the socket and make sure the protocol negotiation works... - let stream = TcpStream::connect(localhost).unwrap(); - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // SPDY is selected since that's the only thing the client supports. - assert_eq!(b"spdy/3.1", stream.ssl().selected_npn_protocol().unwrap()); -} - -/// Tests that when the `SslStream` is created as a server stream, the protocols -/// are correctly advertised to the client. -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn test_alpn_server_advertise_multiple() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let localhost = listener.local_addr().unwrap(); - // We create a different context instance for the server... - let listener_ctx = { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap(); - assert!( - ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM) - .is_ok() - ); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - ctx.build() - }; - // Have the listener wait on the connection in a different thread. - thread::spawn(move || { - let (stream, _) = listener.accept().unwrap(); - Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_alpn_protocols(&[b"spdy/3.1"]).unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - // Now connect to the socket and make sure the protocol negotiation works... - let stream = TcpStream::connect(localhost).unwrap(); - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // SPDY is selected since that's the only thing the client supports. - assert_eq!(b"spdy/3.1", stream.ssl().selected_alpn_protocol().unwrap()); -} - -/// Test that Servers supporting ALPN don't report a protocol when none of their protocols match -/// the client's reported protocol. -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn test_alpn_server_select_none() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let localhost = listener.local_addr().unwrap(); - // We create a different context instance for the server... - let listener_ctx = { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap(); - assert!( - ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM) - .is_ok() - ); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - ctx.build() - }; - // Have the listener wait on the connection in a different thread. - thread::spawn(move || { - let (stream, _) = listener.accept().unwrap(); - Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - ctx.set_alpn_protocols(&[b"http/2"]).unwrap(); - ctx.set_ca_file(&Path::new("test/root-ca.pem")).unwrap(); - // Now connect to the socket and make sure the protocol negotiation works... - let stream = TcpStream::connect(localhost).unwrap(); - let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - - // Since the protocols from the server and client don't overlap at all, no protocol is selected - assert_eq!(None, stream.ssl().selected_alpn_protocol()); -} - -fn wait_io(stream: &TcpStream, read: bool, timeout_ms: u32) -> bool { - unsafe { - let mut set: select::fd_set = mem::zeroed(); - select::fd_set(&mut set, stream); - - let write = if read { - 0 as *mut _ - } else { - &mut set as *mut _ - }; - let read = if !read { - 0 as *mut _ - } else { - &mut set as *mut _ - }; - select::select(stream, read, write, 0 as *mut _, timeout_ms).unwrap() - } -} - -fn handshake(res: Result, HandshakeError>) -> SslStream { - match res { - Ok(s) => s, - Err(HandshakeError::Interrupted(s)) => { - wait_io(s.get_ref(), true, 1_000); - handshake(s.handshake()) - } - Err(err) => panic!("error on handshake {:?}", err), - } -} - -#[test] -fn test_write_nonblocking() { - let (_s, stream) = Server::new(); - stream.set_nonblocking(true).unwrap(); - let cx = SslContext::builder(SslMethod::tls()).unwrap().build(); - let mut stream = handshake(Ssl::new(&cx).unwrap().connect(stream)); - - let mut iterations = 0; - loop { - iterations += 1; - if iterations > 7 { - // Probably a safe assumption for the foreseeable future of - // openssl. - panic!("Too many read/write round trips in handshake!!"); - } - let result = stream.ssl_write(b"hello"); - match result { - Ok(_) => { - break; - } - Err(Error::WantRead(_)) => { - assert!(wait_io(stream.get_ref(), true, 1000)); - } - Err(Error::WantWrite(_)) => { - assert!(wait_io(stream.get_ref(), false, 1000)); - } - Err(other) => { - panic!("Unexpected SSL Error: {:?}", other); - } - } - } - - // Second write should succeed immediately--plenty of space in kernel - // buffer, and handshake just completed. - stream.write(" there".as_bytes()).unwrap(); -} - -#[test] -#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) -fn test_read_nonblocking() { - let (_s, stream) = Server::new(); - stream.set_nonblocking(true).unwrap(); - let cx = SslContext::builder(SslMethod::tls()).unwrap().build(); - let mut stream = handshake(Ssl::new(&cx).unwrap().connect(stream)); - - let mut iterations = 0; - loop { - iterations += 1; - if iterations > 7 { - // Probably a safe assumption for the foreseeable future of - // openssl. - panic!("Too many read/write round trips in handshake!!"); - } - let result = stream.ssl_write(b"GET /\r\n\r\n"); - match result { - Ok(n) => { - assert_eq!(n, 9); - break; - } - Err(Error::WantRead(..)) => { - assert!(wait_io(stream.get_ref(), true, 1000)); - } - Err(Error::WantWrite(..)) => { - assert!(wait_io(stream.get_ref(), false, 1000)); - } - Err(other) => { - panic!("Unexpected SSL Error: {:?}", other); - } - } - } - let mut input_buffer = [0u8; 1500]; - let result = stream.ssl_read(&mut input_buffer); - let bytes_read = match result { - Ok(n) => { - // This branch is unlikely, but on an overloaded VM with - // unlucky context switching, the response could actually - // be in the receive buffer before we issue the read() syscall... - n - } - Err(Error::WantRead(..)) => { - assert!(wait_io(stream.get_ref(), true, 3000)); - // Second read should return application data. - stream.read(&mut input_buffer).unwrap() - } - Err(other) => { - panic!("Unexpected SSL Error: {:?}", other); - } - }; - assert!(bytes_read >= 5); - assert_eq!(&input_buffer[..5], b"HTTP/"); -} - -#[test] -#[should_panic(expected = "blammo")] -fn write_panic() { - struct ExplodingStream(TcpStream); - - impl Read for ExplodingStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - } - - impl Write for ExplodingStream { - fn write(&mut self, _: &[u8]) -> io::Result { - panic!("blammo"); - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } - } - - let (_s, stream) = Server::new(); - let stream = ExplodingStream(stream); - - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); -} - -#[test] -#[should_panic(expected = "blammo")] -fn read_panic() { - struct ExplodingStream(TcpStream); - - impl Read for ExplodingStream { - fn read(&mut self, _: &mut [u8]) -> io::Result { - panic!("blammo"); - } - } - - impl Write for ExplodingStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } - } - - let (_s, stream) = Server::new(); - let stream = ExplodingStream(stream); - - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); -} - -#[test] -#[should_panic(expected = "blammo")] -fn flush_panic() { - struct ExplodingStream(TcpStream); - - impl Read for ExplodingStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - } - - impl Write for ExplodingStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - panic!("blammo"); - } - } - - let (_s, stream) = Server::new(); - let stream = ExplodingStream(stream); - - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()) - .unwrap() - .connect(stream) - .ok() - .unwrap(); - let _ = stream.flush(); -} - -#[test] -fn refcount_ssl_context() { - let mut ssl = { - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ssl::Ssl::new(&ctx.build()).unwrap() - }; - - { - let new_ctx_a = SslContext::builder(SslMethod::tls()).unwrap().build(); - let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); - } -} - -#[test] -fn default_verify_paths() { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_default_verify_paths().unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - let s = TcpStream::connect("google.com:443").unwrap(); - let mut socket = Ssl::new(&ctx.build()).unwrap().connect(s).unwrap(); - - socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); - let mut result = vec![]; - socket.read_to_end(&mut result).unwrap(); - - println!("{}", String::from_utf8_lossy(&result)); - assert!(result.starts_with(b"HTTP/1.0")); - assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); -} - -#[test] -fn add_extra_chain_cert() { - let cert = include_bytes!("../../../test/cert.pem"); - let cert = X509::from_pem(cert).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.add_extra_chain_cert(cert).unwrap(); -} - -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn verify_valid_hostname() { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_default_verify_paths().unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.param_mut().set_hostflags( - X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, - ); - ssl.param_mut().set_host("google.com").unwrap(); - - let s = TcpStream::connect("google.com:443").unwrap(); - let mut socket = ssl.connect(s).unwrap(); - - socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); - let mut result = vec![]; - socket.read_to_end(&mut result).unwrap(); - - println!("{}", String::from_utf8_lossy(&result)); - assert!(result.starts_with(b"HTTP/1.0")); - assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); -} - -#[test] -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -fn verify_invalid_hostname() { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_default_verify_paths().unwrap(); - ctx.set_verify(SSL_VERIFY_PEER); - - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.param_mut().set_hostflags( - X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, - ); - ssl.param_mut().set_host("foobar.com").unwrap(); - - let s = TcpStream::connect("google.com:443").unwrap(); - assert!(ssl.connect(s).is_err()); -} - -#[test] -fn connector_valid_hostname() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - let mut socket = connector.connect("google.com", s).unwrap(); - - socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); - let mut result = vec![]; - socket.read_to_end(&mut result).unwrap(); - - println!("{}", String::from_utf8_lossy(&result)); - assert!(result.starts_with(b"HTTP/1.0")); - assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); -} - -#[test] -fn connector_invalid_hostname() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - assert!(connector.connect("foobar.com", s).is_err()); -} - -#[test] -fn connector_invalid_no_hostname_verification() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s) - .unwrap(); -} - -#[test] -fn connector_no_hostname_still_verifies() { - let (_s, tcp) = Server::new(); - - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); - - assert!(connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp) - .is_err()); -} - -#[test] -fn connector_no_hostname_can_disable_verify() { - let (_s, tcp) = Server::new(); - - let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); - connector.set_verify(SSL_VERIFY_NONE); - let connector = connector.build(); - - connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap(); -} - -#[test] -fn connector_client_server_mozilla_intermediate() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let t = thread::spawn(move || { - let key = PKey::private_key_from_pem(KEY).unwrap(); - let cert = X509::from_pem(CERT).unwrap(); - let connector = - SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(), &key, &cert, None::) - .unwrap() - .build(); - let stream = listener.accept().unwrap().0; - let mut stream = connector.accept(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - }); - - let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); - connector - .set_ca_file("test/root-ca.pem") - .unwrap(); - let connector = connector.build(); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut stream = connector.connect("foobar.com", stream).unwrap(); - - let mut buf = [0; 5]; - stream.read_exact(&mut buf).unwrap(); - assert_eq!(b"hello", &buf); - - t.join().unwrap(); -} - -#[test] -fn connector_client_server_mozilla_modern() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let t = thread::spawn(move || { - let key = PKey::private_key_from_pem(KEY).unwrap(); - let cert = X509::from_pem(CERT).unwrap(); - let connector = - SslAcceptorBuilder::mozilla_modern(SslMethod::tls(), &key, &cert, None::) - .unwrap() - .build(); - let stream = listener.accept().unwrap().0; - let mut stream = connector.accept(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - }); - - let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); - connector - .set_ca_file("test/root-ca.pem") - .unwrap(); - let connector = connector.build(); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut stream = connector.connect("foobar.com", stream).unwrap(); - - let mut buf = [0; 5]; - stream.read_exact(&mut buf).unwrap(); - assert_eq!(b"hello", &buf); - - t.join().unwrap(); -} - -#[test] -fn shutdown() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - 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"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - let mut buf = [0; 1]; - assert_eq!(stream.read(&mut buf).unwrap(), 0); - assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - - let mut buf = [0; 5]; - stream.read_exact(&mut buf).unwrap(); - assert_eq!(b"hello", &buf); - - assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Sent); - assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received); -} - -#[test] -fn client_ca_list() { - let names = X509Name::load_client_ca_file("test/root-ca.pem").unwrap(); - assert_eq!(names.len(), 1); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_client_ca_list(names); -} - -#[test] -fn cert_store() { - let (_s, tcp) = Server::new(); - - let cert = X509::from_pem(ROOT_CERT).unwrap(); - - let mut ctx = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); - ctx.cert_store_mut().add_cert(cert).unwrap(); - let ctx = ctx.build(); - - ctx.connect("foobar.com", tcp).unwrap(); -} - -#[test] -fn tmp_dh_callback() { - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - 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"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_tmp_dh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - let dh = include_bytes!("../../../test/dhparams.pem"); - Dh::from_pem(dh) - }); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("EDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); -} - -#[test] -#[cfg(any(all(feature = "v101", ossl101, not(any(libressl261, libressl262, libressl26x))), all(feature = "v102", ossl102)))] -fn tmp_ecdh_callback() { - use ec::EcKey; - use nid; - - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - 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"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_tmp_ecdh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - EcKey::new_by_curve_name(nid::X9_62_PRIME256V1) - }); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); -} - -#[test] -fn tmp_dh_callback_ssl() { - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - 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"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_tmp_dh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - let dh = include_bytes!("../../../test/dhparams.pem"); - Dh::from_pem(dh) - }); - ssl.accept(stream).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("EDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); -} - -#[test] -#[cfg(any(all(feature = "v101", ossl101, not(any(libressl261, libressl262, libressl26x))), all(feature = "v102", ossl102)))] -fn tmp_ecdh_callback_ssl() { - use ec::EcKey; - use nid; - - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - 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"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_tmp_ecdh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - EcKey::new_by_curve_name(nid::X9_62_PRIME256V1) - }); - ssl.accept(stream).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); -} - -#[test] -fn idle_session() { - let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); - let ssl = Ssl::new(&ctx).unwrap(); - assert!(ssl.session().is_none()); -} - -#[test] -fn active_session() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - let socket = connector.connect("google.com", s).unwrap(); - let session = socket.ssl().session().unwrap(); - let len = session.master_key_len(); - let mut buf = vec![0; len - 1]; - let copied = session.master_key(&mut buf); - assert_eq!(copied, buf.len()); - let mut buf = vec![0; len + 1]; - let copied = session.master_key(&mut buf); - assert_eq!(copied, len); -} - -#[test] -fn status_callbacks() { - static CALLED_BACK_SERVER: AtomicBool = ATOMIC_BOOL_INIT; - static CALLED_BACK_CLIENT: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - 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"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM) - .unwrap(); - ctx.set_status_callback(|ssl| { - CALLED_BACK_SERVER.store(true, Ordering::SeqCst); - let response = OcspResponse::create(RESPONSE_STATUS_UNAUTHORIZED, None).unwrap(); - let response = response.to_der().unwrap(); - ssl.set_ocsp_status(&response).unwrap(); - Ok(true) - }).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_status_callback(|ssl| { - CALLED_BACK_CLIENT.store(true, Ordering::SeqCst); - let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); - assert_eq!(response.status(), RESPONSE_STATUS_UNAUTHORIZED); - Ok(true) - }).unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_status_type(STATUS_TYPE_OCSP).unwrap(); - ssl.connect(stream).unwrap(); - - assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); - assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -fn _check_kinds() { - fn is_send() {} - fn is_sync() {} - - is_send::>(); - is_sync::>(); -} diff --git a/openssl/src/ssl/tests/select.rs b/openssl/src/ssl/tests/select.rs deleted file mode 100644 index 36d5ed4..0000000 --- a/openssl/src/ssl/tests/select.rs +++ /dev/null @@ -1,74 +0,0 @@ -use libc; -pub use self::imp::*; - -#[cfg(unix)] -mod imp { - use std::os::unix::prelude::*; - use std::io; - use libc; - - pub use libc::fd_set; - - pub fn fd_set(set: &mut fd_set, f: &F) { - unsafe { - libc::FD_SET(f.as_raw_fd(), set); - } - } - - pub unsafe fn select( - max: &F, - read: *mut fd_set, - write: *mut fd_set, - error: *mut fd_set, - timeout_ms: u32, - ) -> io::Result { - let mut timeout = libc::timeval { - tv_sec: (timeout_ms / 1000) as libc::time_t, - tv_usec: (timeout_ms % 1000 * 1000) as libc::suseconds_t, - }; - let rc = libc::select(max.as_raw_fd() + 1, read, write, error, &mut timeout); - if rc < 0 { - Err(io::Error::last_os_error()) - } else { - Ok(rc != 0) - } - } -} - -#[cfg(windows)] -mod imp { - extern crate winapi; - extern crate ws2_32; - - use std::os::windows::prelude::*; - use std::io; - use libc::{c_uint, c_long}; - use self::winapi::SOCKET; - use self::winapi::winsock2; - - pub use self::winapi::winsock2::fd_set; - - pub fn fd_set(set: &mut fd_set, f: &F) { - set.fd_array[set.fd_count as usize] = f.as_raw_socket(); - set.fd_count += 1; - } - - pub unsafe fn select( - _max: &F, - read: *mut fd_set, - write: *mut fd_set, - error: *mut fd_set, - timeout_ms: u32, - ) -> io::Result { - let mut timeout = winsock2::timeval { - tv_sec: (timeout_ms / 1000) as c_long, - tv_usec: (timeout_ms % 1000 * 1000) as c_long, - }; - let rc = ws2_32::select(1, read, write, error, &mut timeout); - if rc < 0 { - Err(io::Error::last_os_error()) - } else { - Ok(rc != 0) - } - } -} diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index d858935..416efd5 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -1,23 +1,32 @@ -use foreign_types::{ForeignTypeRef, ForeignType, Opaque}; +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::c_int; use std::borrow::Borrow; use std::convert::AsRef; +use std::fmt; use std::iter; use std::marker::PhantomData; use std::mem; -use ffi; +use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; -use {cvt, cvt_p}; -use error::ErrorStack; -use std::ops::{Deref, DerefMut, Index, IndexMut}; +use crate::error::ErrorStack; +use crate::util::ForeignTypeExt; +use crate::{cvt, cvt_p, LenType}; -#[cfg(ossl10x)] -use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, - sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, - sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push}; -#[cfg(ossl110)] -use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, - OPENSSL_sk_new_null, OPENSSL_sk_push}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, + OPENSSL_sk_new_null, OPENSSL_sk_push, + }; + } else { + use ffi::{ + sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, + sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, + sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push, + }; + } +} /// Trait implemented by types which can be placed in a stack. /// @@ -33,25 +42,37 @@ pub trait Stackable: ForeignType { /// An owned stack of `T`. pub struct Stack(*mut T::StackType); -impl Stack { - pub fn new() -> Result, ErrorStack> { - unsafe { - ffi::init(); - let ptr = cvt_p(OPENSSL_sk_new_null())?; - Ok(Stack(ptr as *mut _)) - } +unsafe impl Send for Stack {} +unsafe impl Sync for Stack {} + +impl fmt::Debug for Stack +where + T: Stackable, + T::Ref: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().entries(self).finish() } } - impl Drop for Stack { fn drop(&mut self) { unsafe { - while let Some(_) = self.pop() {} + while self.pop().is_some() {} OPENSSL_sk_free(self.0 as *mut _); } } } +impl Stack { + pub fn new() -> Result, ErrorStack> { + unsafe { + ffi::init(); + let ptr = cvt_p(OPENSSL_sk_new_null())?; + Ok(Stack(ptr as *mut _)) + } + } +} + impl iter::IntoIterator for Stack { type IntoIter = IntoIter; type Item = T; @@ -59,7 +80,7 @@ impl iter::IntoIterator for Stack { fn into_iter(self) -> IntoIter { let it = IntoIter { stack: self.0, - idx: 0, + idxs: 0..self.len() as LenType, }; mem::forget(self); it @@ -68,13 +89,13 @@ impl iter::IntoIterator for Stack { impl AsRef> for Stack { fn as_ref(&self) -> &StackRef { - &*self + self } } impl Borrow> for Stack { fn borrow(&self) -> &StackRef { - &*self + self } } @@ -87,7 +108,7 @@ impl ForeignType for Stack { assert!( !ptr.is_null(), "Must not instantiate a Stack from a null-ptr - use Stack::new() in \ - that case" + that case" ); Stack(ptr) } @@ -114,18 +135,14 @@ impl DerefMut for Stack { pub struct IntoIter { stack: *mut T::StackType, - idx: c_int, -} - -impl IntoIter { - fn stack_len(&self) -> c_int { - unsafe { OPENSSL_sk_num(self.stack as *mut _) } - } + idxs: Range, } impl Drop for IntoIter { fn drop(&mut self) { unsafe { + // https://github.com/rust-lang/rust-clippy/issues/7510 + #[allow(clippy::while_let_on_iterator)] while let Some(_) = self.next() {} OPENSSL_sk_free(self.stack as *mut _); } @@ -137,19 +154,24 @@ impl Iterator for IntoIter { fn next(&mut self) -> Option { unsafe { - if self.idx == self.stack_len() { - None - } else { - let ptr = OPENSSL_sk_value(self.stack as *mut _, self.idx); - self.idx += 1; - Some(T::from_ptr(ptr as *mut _)) - } + self.idxs + .next() + .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _)) } } fn size_hint(&self) -> (usize, Option) { - let size = (self.stack_len() - self.idx) as usize; - (size, Some(size)) + self.idxs.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + unsafe { + self.idxs + .next_back() + .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _)) + } } } @@ -157,6 +179,9 @@ impl ExactSizeIterator for IntoIter {} pub struct StackRef(Opaque, PhantomData); +unsafe impl Send for StackRef {} +unsafe impl Sync for StackRef {} + impl ForeignTypeRef for StackRef { type CType = T::StackType; } @@ -166,28 +191,27 @@ impl StackRef { self.as_ptr() as *mut _ } - /// Returns the number of items in the stack + /// Returns the number of items in the stack. pub fn len(&self) -> usize { unsafe { OPENSSL_sk_num(self.as_stack()) as usize } } - pub fn iter(&self) -> Iter { - // Unfortunately we can't simply convert the stack into a - // slice and use that because OpenSSL 1.1.0 doesn't directly - // expose the stack data (we have to use `OPENSSL_sk_value` - // instead). We have to rewrite the entire iteration framework - // instead. + /// Determines if the stack is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn iter(&self) -> Iter<'_, T> { Iter { stack: self, - pos: 0, + idxs: 0..self.len() as LenType, } } - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { + idxs: 0..self.len() as LenType, stack: self, - pos: 0, } } @@ -218,9 +242,7 @@ impl StackRef { /// Pushes a value onto the top of the stack. pub fn push(&mut self, data: T) -> Result<(), ErrorStack> { unsafe { - cvt( - OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _), - )?; + cvt(OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _) as c_int)?; mem::forget(data); Ok(()) } @@ -230,16 +252,12 @@ impl StackRef { pub fn pop(&mut self) -> Option { unsafe { let ptr = OPENSSL_sk_pop(self.as_stack()); - if ptr.is_null() { - None - } else { - Some(T::from_ptr(ptr as *mut _)) - } + T::from_ptr_opt(ptr as *mut _) } } unsafe fn _get(&self, idx: usize) -> *mut T::CType { - OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ + OPENSSL_sk_value(self.as_stack(), idx as LenType) as *mut _ } } @@ -294,67 +312,69 @@ impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack { } /// An iterator over the stack's contents. -pub struct Iter<'a, T: Stackable> -where - T: 'a, -{ +pub struct Iter<'a, T: Stackable> { stack: &'a StackRef, - pos: usize, + idxs: Range, } -impl<'a, T: Stackable> iter::Iterator for Iter<'a, T> { +impl<'a, T: Stackable> Iterator for Iter<'a, T> { type Item = &'a T::Ref; fn next(&mut self) -> Option<&'a T::Ref> { - let n = self.stack.get(self.pos); - - if n.is_some() { - self.pos += 1; + unsafe { + self.idxs + .next() + .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) } - - n } fn size_hint(&self) -> (usize, Option) { - let rem = self.stack.len() - self.pos; + self.idxs.size_hint() + } +} - (rem, Some(rem)) +impl<'a, T: Stackable> DoubleEndedIterator for Iter<'a, T> { + fn next_back(&mut self) -> Option<&'a T::Ref> { + unsafe { + self.idxs + .next_back() + .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) + } } } -impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> {} +impl<'a, T: Stackable> ExactSizeIterator for Iter<'a, T> {} /// A mutable iterator over the stack's contents. -pub struct IterMut<'a, T: Stackable + 'a> { +pub struct IterMut<'a, T: Stackable> { stack: &'a mut StackRef, - pos: usize, + idxs: Range, } -impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> { +impl<'a, T: Stackable> Iterator for IterMut<'a, T> { type Item = &'a mut T::Ref; fn next(&mut self) -> Option<&'a mut T::Ref> { - if self.pos >= self.stack.len() { - None - } else { - // Rust won't allow us to get a mutable reference into - // `stack` in this situation since it can't statically - // guarantee that we won't return several references to - // the same object, so we have to use unsafe code for - // mutable iterators. - let n = unsafe { Some(T::Ref::from_ptr_mut(self.stack._get(self.pos))) }; - - self.pos += 1; - - n + unsafe { + self.idxs + .next() + .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) } } fn size_hint(&self) -> (usize, Option) { - let rem = self.stack.len() - self.pos; + self.idxs.size_hint() + } +} - (rem, Some(rem)) +impl<'a, T: Stackable> DoubleEndedIterator for IterMut<'a, T> { + fn next_back(&mut self) -> Option<&'a mut T::Ref> { + unsafe { + self.idxs + .next_back() + .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) + } } } -impl<'a, T: Stackable> iter::ExactSizeIterator for IterMut<'a, T> {} +impl<'a, T: Stackable> ExactSizeIterator for IterMut<'a, T> {} diff --git a/openssl/src/string.rs b/openssl/src/string.rs index af58130..95494b5 100644 --- a/openssl/src/string.rs +++ b/openssl/src/string.rs @@ -1,12 +1,12 @@ -use ffi; -use foreign_types::{ForeignType, ForeignTypeRef}; +use foreign_types::ForeignTypeRef; use libc::{c_char, c_void}; -use std::fmt; +use std::convert::AsRef; use std::ffi::CStr; +use std::fmt; use std::ops::Deref; use std::str; -use stack::Stackable; +use crate::stack::Stackable; foreign_type_and_impl_send_sync! { type CType = c_char; @@ -16,26 +16,14 @@ foreign_type_and_impl_send_sync! { pub struct OpensslStringRef; } -impl OpensslString { - #[deprecated(note = "use from_ptr", since = "0.9.7")] - pub unsafe fn from_raw_parts(buf: *mut u8, _: usize) -> OpensslString { - OpensslString::from_ptr(buf as *mut c_char) - } - - #[deprecated(note = "use from_ptr", since = "0.9.7")] - pub unsafe fn from_null_terminated(buf: *mut c_char) -> OpensslString { - OpensslString::from_ptr(buf) - } -} - impl fmt::Display for OpensslString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } impl fmt::Debug for OpensslString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } @@ -44,6 +32,18 @@ impl Stackable for OpensslString { type StackType = ffi::stack_st_OPENSSL_STRING; } +impl AsRef for OpensslString { + fn as_ref(&self) -> &str { + self + } +} + +impl AsRef<[u8]> for OpensslString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + impl Deref for OpensslStringRef { type Target = str; @@ -55,26 +55,40 @@ impl Deref for OpensslStringRef { } } +impl AsRef for OpensslStringRef { + fn as_ref(&self) -> &str { + self + } +} + +impl AsRef<[u8]> for OpensslStringRef { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + impl fmt::Display for OpensslStringRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } impl fmt::Debug for OpensslStringRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -#[cfg(not(ossl110))] +#[inline] +#[cfg(not(boringssl))] unsafe fn free(buf: *mut c_char) { - ::ffi::CRYPTO_free(buf as *mut c_void); + ffi::OPENSSL_free(buf as *mut c_void); } -#[cfg(ossl110)] +#[inline] +#[cfg(boringssl)] unsafe fn free(buf: *mut c_char) { - ::ffi::CRYPTO_free( + ffi::CRYPTO_free( buf as *mut c_void, concat!(file!(), "\0").as_ptr() as *const c_char, line!() as ::libc::c_int, diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index e109b2a..911a7ab 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -22,13 +22,41 @@ //! \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1", //! &ciphertext[..]); //! ``` -use std::cmp; -use std::ptr; -use libc::c_int; -use ffi; - -use {cvt, cvt_p}; -use error::ErrorStack; +//! +//! Encrypting an asymmetric key with a symmetric cipher +//! +//! ``` +//! use openssl::rsa::{Padding, Rsa}; +//! use openssl::symm::Cipher; +//! +//! // Generate keypair and encrypt private key: +//! let keypair = Rsa::generate(2048).unwrap(); +//! let cipher = Cipher::aes_256_cbc(); +//! let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); +//! let privkey_pem = keypair.private_key_to_pem_passphrase(cipher, b"Rust").unwrap(); +//! // pubkey_pem and privkey_pem could be written to file here. +//! +//! // Load private and public key from string: +//! let pubkey = Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); +//! let privkey = Rsa::private_key_from_pem_passphrase(&privkey_pem, b"Rust").unwrap(); +//! +//! // Use the asymmetric keys to encrypt and decrypt a short message: +//! let msg = b"Foo bar"; +//! let mut encrypted = vec![0; pubkey.size() as usize]; +//! let mut decrypted = vec![0; privkey.size() as usize]; +//! let len = pubkey.public_encrypt(msg, &mut encrypted, Padding::PKCS1).unwrap(); +//! assert!(len > msg.len()); +//! let len = privkey.private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1).unwrap(); +//! let output_string = String::from_utf8(decrypted[..len].to_vec()).unwrap(); +//! assert_eq!("Foo bar", output_string); +//! println!("Decrypted: '{}'", output_string); +//! ``` +use crate::cipher::CipherRef; +use crate::cipher_ctx::{CipherCtx, CipherCtxRef}; +use crate::error::ErrorStack; +use crate::nid::Nid; +use cfg_if::cfg_if; +use foreign_types::ForeignTypeRef; #[derive(Copy, Clone)] pub enum Mode { @@ -40,11 +68,35 @@ pub enum Mode { /// /// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms. /// -/// [`EVP_EncryptInit`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_EncryptInit.html -#[derive(Copy, Clone)] +/// [`EVP_EncryptInit`]: https://www.openssl.org/docs/manmaster/crypto/EVP_EncryptInit.html +#[derive(Copy, Clone, PartialEq, Eq)] pub struct Cipher(*const ffi::EVP_CIPHER); impl Cipher { + /// Looks up the cipher for a certain nid. + /// + /// This corresponds to [`EVP_get_cipherbynid`] + /// + /// [`EVP_get_cipherbynid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_get_cipherbyname.html + pub fn from_nid(nid: Nid) -> Option { + let ptr = unsafe { ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())) }; + if ptr.is_null() { + None + } else { + Some(Cipher(ptr)) + } + } + + /// Returns the cipher's Nid. + /// + /// This corresponds to [`EVP_CIPHER_nid`] + /// + /// [`EVP_CIPHER_nid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_CIPHER_nid.html + pub fn nid(&self) -> Nid { + let nid = unsafe { ffi::EVP_CIPHER_nid(self.0) }; + Nid::from_raw(nid) + } + pub fn aes_128_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ecb()) } } @@ -53,6 +105,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_128_cbc()) } } + #[cfg(not(boringssl))] pub fn aes_128_xts() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_xts()) } } @@ -61,6 +114,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_128_ctr()) } } + #[cfg(not(boringssl))] pub fn aes_128_cfb1() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_cfb1()) } } @@ -69,6 +123,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_128_cfb128()) } } + #[cfg(not(boringssl))] pub fn aes_128_cfb8() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_cfb8()) } } @@ -77,6 +132,66 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_128_gcm()) } } + #[cfg(not(boringssl))] + pub fn aes_128_ccm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_ccm()) } + } + + pub fn aes_128_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_ofb()) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_128_ocb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_ocb()) } + } + + pub fn aes_192_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_ecb()) } + } + + pub fn aes_192_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_cbc()) } + } + + pub fn aes_192_ctr() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_ctr()) } + } + + #[cfg(not(boringssl))] + pub fn aes_192_cfb1() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_cfb1()) } + } + + pub fn aes_192_cfb128() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_cfb128()) } + } + + #[cfg(not(boringssl))] + pub fn aes_192_cfb8() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_cfb8()) } + } + + pub fn aes_192_gcm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_gcm()) } + } + + #[cfg(not(boringssl))] + pub fn aes_192_ccm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_ccm()) } + } + + pub fn aes_192_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_ofb()) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_192_ocb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_192_ocb()) } + } + pub fn aes_256_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ecb()) } } @@ -85,6 +200,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_256_cbc()) } } + #[cfg(not(boringssl))] pub fn aes_256_xts() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_xts()) } } @@ -93,6 +209,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_256_ctr()) } } + #[cfg(not(boringssl))] pub fn aes_256_cfb1() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_cfb1()) } } @@ -101,6 +218,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_256_cfb128()) } } + #[cfg(not(boringssl))] pub fn aes_256_cfb8() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_cfb8()) } } @@ -109,18 +227,37 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_256_gcm()) } } + #[cfg(not(boringssl))] + pub fn aes_256_ccm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_ccm()) } + } + + pub fn aes_256_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_ofb()) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_256_ocb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_ocb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_bf_cbc()) } } + #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_bf_ecb()) } } + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))] pub fn bf_cfb64() -> Cipher { unsafe { Cipher(ffi::EVP_bf_cfb64()) } } + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))] pub fn bf_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_bf_ofb()) } } @@ -133,41 +270,111 @@ impl Cipher { unsafe { Cipher(ffi::EVP_des_ecb()) } } + pub fn des_ede3() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3()) } + } + + pub fn des_ede3_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_cbc()) } + } + + #[cfg(not(boringssl))] + pub fn des_ede3_cfb64() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) } + } + pub fn rc4() -> Cipher { unsafe { Cipher(ffi::EVP_rc4()) } } - /// Requires the `v110` feature and OpenSSL 1.1.0. - #[cfg(all(ossl110, feature = "v110"))] + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20() -> Cipher { unsafe { Cipher(ffi::EVP_chacha20()) } } - /// Requires the `v110` feature and OpenSSL 1.1.0. - #[cfg(all(ossl110, feature = "v110"))] + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20_poly1305() -> Cipher { unsafe { Cipher(ffi::EVP_chacha20_poly1305()) } } + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED")))] + pub fn seed_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_seed_cbc()) } + } + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED")))] + pub fn seed_cfb128() -> Cipher { + unsafe { Cipher(ffi::EVP_seed_cfb128()) } + } + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED")))] + pub fn seed_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_seed_ecb()) } + } + + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED")))] + pub fn seed_ofb() -> Cipher { + 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 + /// + /// The caller must ensure the pointer is valid for the `'static` lifetime. pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher { Cipher(ptr) } + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER { self.0 } /// Returns the length of keys used with this cipher. + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn key_len(&self) -> usize { unsafe { EVP_CIPHER_key_length(self.0) as usize } } /// Returns the length of the IV used with this cipher, or `None` if the /// cipher does not use an IV. + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn iv_len(&self) -> Option { unsafe { let len = EVP_CIPHER_iv_length(self.0) as usize; - if len == 0 { None } else { Some(len) } + if len == 0 { + None + } else { + Some(len) + } } } @@ -176,11 +383,40 @@ impl Cipher { /// # Note /// /// Stream ciphers such as RC4 have a block size of 1. + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn block_size(&self) -> usize { unsafe { EVP_CIPHER_block_size(self.0) as usize } } + + /// Determines whether the cipher is using CCM mode + #[cfg(not(boringssl))] + fn is_ccm(self) -> bool { + // NOTE: OpenSSL returns pointers to static structs, which makes this work as expected + self == Cipher::aes_128_ccm() || self == Cipher::aes_256_ccm() + } + + #[cfg(boringssl)] + fn is_ccm(self) -> bool { + false + } + + /// Determines whether the cipher is using OCB mode + #[cfg(ossl110)] + fn is_ocb(self) -> bool { + self == Cipher::aes_128_ocb() + || self == Cipher::aes_192_ocb() + || self == Cipher::aes_256_ocb() + } + + #[cfg(not(ossl110))] + const fn is_ocb(self) -> bool { + false + } } +unsafe impl Sync for Cipher {} +unsafe impl Send for Cipher {} + /// Represents a symmetric cipher context. /// /// Padding is enabled by default. @@ -242,12 +478,11 @@ impl Cipher { /// assert_eq!(b"Some Stream of Crypto Text", &plaintext[..]); /// ``` pub struct Crypter { - ctx: *mut ffi::EVP_CIPHER_CTX, - block_size: usize, + ctx: CipherCtx, } impl Crypter { - /// Creates a new `Crypter`. The initialisation vector, `iv`, is not necesarry for certain + /// Creates a new `Crypter`. The initialisation vector, `iv`, is not necessary for certain /// types of `Cipher`. /// /// # Panics @@ -260,63 +495,31 @@ impl Crypter { key: &[u8], iv: Option<&[u8]>, ) -> Result { - ffi::init(); + let mut ctx = CipherCtx::new()?; - unsafe { - let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?; - let crypter = Crypter { - ctx: ctx, - block_size: t.block_size(), - }; - - let mode = match mode { - Mode::Encrypt => 1, - Mode::Decrypt => 0, - }; - - cvt(ffi::EVP_CipherInit_ex( - crypter.ctx, - t.as_ptr(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - mode, - ))?; - - assert!(key.len() <= c_int::max_value() as usize); - cvt(ffi::EVP_CIPHER_CTX_set_key_length( - crypter.ctx, - key.len() as c_int, - ))?; - - let key = key.as_ptr() as *mut _; - let iv = match (iv, t.iv_len()) { - (Some(iv), Some(len)) => { - if iv.len() != len { - assert!(iv.len() <= c_int::max_value() as usize); - cvt(ffi::EVP_CIPHER_CTX_ctrl( - crypter.ctx, - ffi::EVP_CTRL_GCM_SET_IVLEN, - iv.len() as c_int, - ptr::null_mut(), - ))?; - } - iv.as_ptr() as *mut _ - } - (Some(_), None) | (None, None) => ptr::null_mut(), - (None, Some(_)) => panic!("an IV is required for this cipher"), - }; - cvt(ffi::EVP_CipherInit_ex( - crypter.ctx, - ptr::null(), - ptr::null_mut(), - key, - iv, - mode, - ))?; - - Ok(crypter) + let f = match mode { + Mode::Encrypt => CipherCtxRef::encrypt_init, + Mode::Decrypt => CipherCtxRef::decrypt_init, + }; + + f( + &mut ctx, + Some(unsafe { CipherRef::from_ptr(t.as_ptr() as *mut _) }), + None, + None, + )?; + + ctx.set_key_length(key.len())?; + + if let (Some(iv), Some(iv_len)) = (iv, t.iv_len()) { + if iv.len() != iv_len { + ctx.set_iv_length(iv.len())?; + } } + + f(&mut ctx, None, Some(key), iv)?; + + Ok(Crypter { ctx }) } /// Enables or disables padding. @@ -324,25 +527,30 @@ impl Crypter { /// If padding is disabled, total amount of data encrypted/decrypted must /// be a multiple of the cipher's block size. pub fn pad(&mut self, padding: bool) { - unsafe { - ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); - } + self.ctx.set_padding(padding) } /// Sets the tag used to authenticate ciphertext in AEAD ciphers such as AES GCM. /// /// When decrypting cipher text using an AEAD cipher, this must be called before `finalize`. pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> { - unsafe { - assert!(tag.len() <= c_int::max_value() as usize); - // NB: this constant is actually more general than just GCM. - cvt(ffi::EVP_CIPHER_CTX_ctrl( - self.ctx, - ffi::EVP_CTRL_GCM_SET_TAG, - tag.len() as c_int, - tag.as_ptr() as *mut _, - )).map(|_| ()) - } + self.ctx.set_tag(tag) + } + + /// Sets the length of the authentication tag to generate in AES CCM. + /// + /// When encrypting with AES CCM, the tag length needs to be explicitly set in order + /// to use a value different than the default 12 bytes. + pub fn set_tag_len(&mut self, tag_len: usize) -> Result<(), ErrorStack> { + self.ctx.set_tag_length(tag_len) + } + + /// Feeds total plaintext length to the cipher. + /// + /// The total plaintext or ciphertext length MUST be passed to the cipher when it operates in + /// CCM mode. + pub fn set_data_len(&mut self, data_len: usize) -> Result<(), ErrorStack> { + self.ctx.set_data_len(data_len) } /// Feeds Additional Authenticated Data (AAD) through the cipher. @@ -351,17 +559,8 @@ impl Crypter { /// is factored into the authentication tag. It must be called before the first call to /// `update`. pub fn aad_update(&mut self, input: &[u8]) -> Result<(), ErrorStack> { - unsafe { - assert!(input.len() <= c_int::max_value() as usize); - let mut len = 0; - cvt(ffi::EVP_CipherUpdate( - self.ctx, - ptr::null_mut(), - &mut len, - input.as_ptr(), - input.len() as c_int, - )).map(|_| ()) - } + self.ctx.cipher_update(input, None)?; + Ok(()) } /// Feeds data from `input` through the cipher, writing encrypted/decrypted @@ -372,26 +571,14 @@ impl Crypter { /// /// # Panics /// - /// Panics if `output.len() < input.len() + block_size` where - /// `block_size` is the block size of the cipher (see `Cipher::block_size`), - /// or if `output.len() > c_int::max_value()`. + /// Panics for stream ciphers if `output.len() < input.len()`. + /// + /// Panics for block ciphers if `output.len() < input.len() + block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). + /// + /// Panics if `output.len() > c_int::max_value()`. pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { - unsafe { - assert!(output.len() >= input.len() + self.block_size); - assert!(output.len() <= c_int::max_value() as usize); - let mut outl = output.len() as c_int; - let inl = input.len() as c_int; - - cvt(ffi::EVP_CipherUpdate( - self.ctx, - output.as_mut_ptr(), - &mut outl, - input.as_ptr(), - inl, - ))?; - - Ok(outl as usize) - } + self.ctx.cipher_update(input, Some(output)) } /// Finishes the encryption/decryption process, writing any remaining data @@ -403,20 +590,10 @@ impl Crypter { /// /// # Panics /// - /// Panics if `output` is less than the cipher's block size. + /// Panics for block ciphers if `output.len() < block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). pub fn finalize(&mut self, output: &mut [u8]) -> Result { - unsafe { - assert!(output.len() >= self.block_size); - let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; - - cvt(ffi::EVP_CipherFinal( - self.ctx, - output.as_mut_ptr(), - &mut outl, - ))?; - - Ok(outl as usize) - } + self.ctx.cipher_final(output) } /// Retrieves the authentication tag used to authenticate ciphertext in AEAD ciphers such @@ -428,33 +605,17 @@ impl Crypter { /// range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 /// bytes, for example. pub fn get_tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { - unsafe { - assert!(tag.len() <= c_int::max_value() as usize); - cvt(ffi::EVP_CIPHER_CTX_ctrl( - self.ctx, - ffi::EVP_CTRL_GCM_GET_TAG, - tag.len() as c_int, - tag.as_mut_ptr() as *mut _, - )).map(|_| ()) - } - } -} - -impl Drop for Crypter { - fn drop(&mut self) { - unsafe { - ffi::EVP_CIPHER_CTX_free(self.ctx); - } + self.ctx.tag(tag) } } /// Encrypts data in one go, and returns the encrypted data. /// /// Data is encrypted using the specified cipher type `t` in encrypt mode with the specified `key` -/// and initailization vector `iv`. +/// and initialization vector `iv`. Padding is enabled. /// /// This is a convenient interface to `Crypter` to encrypt all data in one go. To encrypt a stream -/// of data increamentally , use `Crypter` instead. +/// of data incrementally , use `Crypter` instead. /// /// # Examples /// @@ -490,14 +651,14 @@ pub fn encrypt( /// Decrypts data in one go, and returns the decrypted data. /// /// Data is decrypted using the specified cipher type `t` in decrypt mode with the specified `key` -/// and initailization vector `iv`. +/// and initialization vector `iv`. Padding is enabled. /// /// This is a convenient interface to `Crypter` to decrypt all data in one go. To decrypt a stream -/// of data increamentally , use `Crypter` instead. +/// of data incrementally , use `Crypter` instead. /// /// # Examples /// -/// Decrypt data in AES256 ECB mode +/// Decrypt data in AES128 CBC mode /// /// ``` /// use openssl::symm::{decrypt, Cipher}; @@ -559,6 +720,15 @@ pub fn encrypt_aead( ) -> Result, ErrorStack> { let mut c = Crypter::new(t, Mode::Encrypt, key, iv)?; let mut out = vec![0; data.len() + t.block_size()]; + + let is_ccm = t.is_ccm(); + if is_ccm || t.is_ocb() { + c.set_tag_len(tag.len())?; + if is_ccm { + c.set_data_len(data.len())?; + } + } + c.aad_update(aad)?; let count = c.update(data, &mut out)?; let rest = c.finalize(&mut out[count..])?; @@ -581,222 +751,142 @@ pub fn decrypt_aead( ) -> Result, ErrorStack> { let mut c = Crypter::new(t, Mode::Decrypt, key, iv)?; let mut out = vec![0; data.len() + t.block_size()]; + + let is_ccm = t.is_ccm(); + if is_ccm || t.is_ocb() { + c.set_tag(tag)?; + if is_ccm { + c.set_data_len(data.len())?; + } + } + c.aad_update(aad)?; let count = c.update(data, &mut out)?; - c.set_tag(tag)?; - let rest = c.finalize(&mut out[count..])?; + + let rest = if t.is_ccm() { + 0 + } else { + c.set_tag(tag)?; + c.finalize(&mut out[count..])? + }; + out.truncate(count + rest); Ok(out) } -#[cfg(ossl110)] -use ffi::{EVP_CIPHER_iv_length, EVP_CIPHER_block_size, EVP_CIPHER_key_length}; +cfg_if! { + if #[cfg(any(boringssl, ossl110, libressl273))] { + use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; + } else { + use crate::LenType; -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use libc::c_int; - use ffi::EVP_CIPHER; - - pub unsafe fn EVP_CIPHER_iv_length(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).iv_len - } + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> LenType { + (*ptr).iv_len + } - pub unsafe fn EVP_CIPHER_block_size(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).block_size - } + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> LenType { + (*ptr).block_size + } - pub unsafe fn EVP_CIPHER_key_length(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).key_len + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> LenType { + (*ptr).key_len + } } } -#[cfg(ossl10x)] -use self::compat::*; #[cfg(test)] mod tests { - use hex::{FromHex, ToHex}; use super::*; + use hex::{self, FromHex}; + + #[test] + fn test_stream_cipher_output() { + let key = [0u8; 16]; + let iv = [0u8; 16]; + let mut c = super::Crypter::new( + super::Cipher::aes_128_ctr(), + super::Mode::Encrypt, + &key, + Some(&iv), + ) + .unwrap(); + + assert_eq!(c.update(&[0u8; 15], &mut [0u8; 15]).unwrap(), 15); + assert_eq!(c.update(&[0u8; 1], &mut [0u8; 1]).unwrap(), 1); + assert_eq!(c.finalize(&mut [0u8; 0]).unwrap(), 0); + } // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf #[test] fn test_aes_256_ecb() { let k0 = [ - 0x00u8, - 0x01u8, - 0x02u8, - 0x03u8, - 0x04u8, - 0x05u8, - 0x06u8, - 0x07u8, - 0x08u8, - 0x09u8, - 0x0au8, - 0x0bu8, - 0x0cu8, - 0x0du8, - 0x0eu8, - 0x0fu8, - 0x10u8, - 0x11u8, - 0x12u8, - 0x13u8, - 0x14u8, - 0x15u8, - 0x16u8, - 0x17u8, - 0x18u8, - 0x19u8, - 0x1au8, - 0x1bu8, - 0x1cu8, - 0x1du8, - 0x1eu8, - 0x1fu8, + 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0au8, + 0x0bu8, 0x0cu8, 0x0du8, 0x0eu8, 0x0fu8, 0x10u8, 0x11u8, 0x12u8, 0x13u8, 0x14u8, 0x15u8, + 0x16u8, 0x17u8, 0x18u8, 0x19u8, 0x1au8, 0x1bu8, 0x1cu8, 0x1du8, 0x1eu8, 0x1fu8, ]; let p0 = [ - 0x00u8, - 0x11u8, - 0x22u8, - 0x33u8, - 0x44u8, - 0x55u8, - 0x66u8, - 0x77u8, - 0x88u8, - 0x99u8, - 0xaau8, - 0xbbu8, - 0xccu8, - 0xddu8, - 0xeeu8, - 0xffu8, + 0x00u8, 0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8, 0x66u8, 0x77u8, 0x88u8, 0x99u8, 0xaau8, + 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8, ]; let c0 = [ - 0x8eu8, - 0xa2u8, - 0xb7u8, - 0xcau8, - 0x51u8, - 0x67u8, - 0x45u8, - 0xbfu8, - 0xeau8, - 0xfcu8, - 0x49u8, - 0x90u8, - 0x4bu8, - 0x49u8, - 0x60u8, - 0x89u8, + 0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, 0x49u8, + 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8, ]; let mut c = super::Crypter::new( super::Cipher::aes_256_ecb(), super::Mode::Encrypt, &k0, None, - ).unwrap(); + ) + .unwrap(); c.pad(false); let mut r0 = vec![0; c0.len() + super::Cipher::aes_256_ecb().block_size()]; let count = c.update(&p0, &mut r0).unwrap(); let rest = c.finalize(&mut r0[count..]).unwrap(); r0.truncate(count + rest); - assert_eq!(r0.to_hex(), c0.to_hex()); + assert_eq!(hex::encode(&r0), hex::encode(c0)); let mut c = super::Crypter::new( super::Cipher::aes_256_ecb(), super::Mode::Decrypt, &k0, None, - ).unwrap(); + ) + .unwrap(); c.pad(false); let mut p1 = vec![0; r0.len() + super::Cipher::aes_256_ecb().block_size()]; let count = c.update(&r0, &mut p1).unwrap(); let rest = c.finalize(&mut p1[count..]).unwrap(); p1.truncate(count + rest); - assert_eq!(p1.to_hex(), p0.to_hex()); + assert_eq!(hex::encode(p1), hex::encode(p0)); } #[test] fn test_aes_256_cbc_decrypt() { let iv = [ - 4_u8, - 223_u8, - 153_u8, - 219_u8, - 28_u8, - 142_u8, - 234_u8, - 68_u8, - 227_u8, - 69_u8, - 98_u8, - 107_u8, - 208_u8, - 14_u8, - 236_u8, - 60_u8, + 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, + 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, ]; let data = [ - 143_u8, - 210_u8, - 75_u8, - 63_u8, - 214_u8, - 179_u8, - 155_u8, - 241_u8, - 242_u8, - 31_u8, - 154_u8, - 56_u8, - 198_u8, - 145_u8, - 192_u8, - 64_u8, - 2_u8, - 245_u8, - 167_u8, - 220_u8, - 55_u8, - 119_u8, - 233_u8, - 136_u8, - 139_u8, - 27_u8, - 71_u8, - 242_u8, - 119_u8, - 175_u8, - 65_u8, - 207_u8, + 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8, + 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, + 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8, ]; let ciphered_data = [ - 0x4a_u8, - 0x2e_u8, - 0xe5_u8, - 0x6_u8, - 0xbf_u8, - 0xcf_u8, - 0xf2_u8, - 0xd7_u8, - 0xea_u8, - 0x2d_u8, - 0xb1_u8, - 0x85_u8, - 0x6c_u8, - 0x93_u8, - 0x65_u8, - 0x6f_u8, + 0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8, 0xea_u8, + 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8, ]; let mut cr = super::Crypter::new( super::Cipher::aes_256_cbc(), super::Mode::Decrypt, &data, Some(&iv), - ).unwrap(); + ) + .unwrap(); cr.pad(false); let mut unciphered_data = vec![0; data.len() + super::Cipher::aes_256_cbc().block_size()]; let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap(); @@ -818,8 +908,8 @@ mod tests { let expected = pt; if computed != expected { - println!("Computed: {}", computed.to_hex()); - println!("Expected: {}", expected.to_hex()); + println!("Computed: {}", hex::encode(&computed)); + println!("Expected: {}", hex::encode(&expected)); if computed.len() != expected.len() { println!( "Lengths differ: {} in computed vs {} expected", @@ -831,6 +921,7 @@ mod tests { } } + #[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(); @@ -849,8 +940,8 @@ mod tests { let expected = pt; if computed != expected { - println!("Computed: {}", computed.to_hex()); - println!("Expected: {}", expected.to_hex()); + println!("Computed: {}", hex::encode(&computed)); + println!("Expected: {}", hex::encode(&expected)); if computed.len() != expected.len() { println!( "Lengths differ: {} in computed vs {} expected", @@ -864,6 +955,8 @@ mod tests { #[test] fn test_rc4() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "0000000000000000000000000000000000000000000000000000000000000000000000000000"; let ct = "A68686B04D686AA107BD8D4CAB191A3EEC0A6294BC78B60F65C25CB47BD7BB3A48EFC4D26BE4"; @@ -874,6 +967,7 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn test_aes256_xts() { // Test case 174 from // http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip @@ -890,7 +984,6 @@ mod tests { #[test] fn test_aes128_ctr() { - let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411\ E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710"; let ct = "874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E\ @@ -902,6 +995,7 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn test_aes128_cfb1() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf @@ -914,8 +1008,8 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn test_aes128_cfb128() { - let pt = "6bc1bee22e409f96e93d7e117393172a"; let ct = "3b3fd92eb72dad20333449f8e83cfb4a"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; @@ -925,8 +1019,8 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn test_aes128_cfb8() { - let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; let ct = "3b79424c9c0dd436bace9e0ed4586a4f32b9"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; @@ -936,8 +1030,83 @@ mod tests { } #[test] - fn test_aes256_cfb1() { + fn test_aes128_ofb() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; + let ct = "3b3fd92eb72dad20333449f8e83cfb4a7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a82260edcc304c6528f659c77866a510d9c1d6ae5e"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_128_ofb(), pt, ct, key, iv); + } + + #[test] + fn test_aes192_ctr() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; + let ct = "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + let iv = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + + cipher_test(super::Cipher::aes_192_ctr(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(boringssl))] + fn test_aes192_cfb1() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + let pt = "6bc1"; + let ct = "9359"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_192_cfb1(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(boringssl))] + fn test_aes192_cfb128() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; + let ct = "cdc80d6fddf18cab34c25909c99a417467ce7f7f81173621961a2b70171d3d7a2e1e8a1dd59b88b1c8e60fed1efac4c9c05f9f9ca9834fa042ae8fba584b09ff"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_192_cfb128(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(boringssl))] + fn test_aes192_cfb8() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; + let ct = "cda2521ef0a905ca44cd057cbf0d47a0678a"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_192_cfb8(), pt, ct, key, iv); + } + + #[test] + fn test_aes192_ofb() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; + let ct = "cdc80d6fddf18cab34c25909c99a4174fcc28b8d4c63837c09e81700c11004018d9a9aeac0f6596f559c6d4daf59a5f26d9f200857ca6c3e9cac524bd9acc92a"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_192_ofb(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(boringssl))] + fn test_aes256_cfb1() { let pt = "6bc1"; let ct = "9029"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; @@ -947,8 +1116,8 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn test_aes256_cfb128() { - let pt = "6bc1bee22e409f96e93d7e117393172a"; let ct = "dc7e84bfda79164b7ecd8486985d3860"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; @@ -958,8 +1127,8 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn test_aes256_cfb8() { - let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; let ct = "dc1f1a8520a64db55fcc8ac554844e889700"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; @@ -969,7 +1138,24 @@ mod tests { } #[test] + fn test_aes256_ofb() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; + let ct = "dc7e84bfda79164b7ecd8486985d38604febdc6740d20b3ac88f6ad82a4fb08d71ab47a086e86eedf39d1c5bba97c4080126141d67f37be8538f5a8be740e484"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_256_ofb(), pt, ct, key, iv); + } + + #[test] + #[cfg_attr(ossl300, ignore)] + #[cfg(not(boringssl))] fn test_bf_cbc() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + // https://www.schneier.com/code/vectors.txt let pt = "37363534333231204E6F77206973207468652074696D6520666F722000000000"; @@ -981,7 +1167,11 @@ mod tests { } #[test] + #[cfg_attr(ossl300, ignore)] + #[cfg(not(boringssl))] fn test_bf_ecb() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "5CD54CA83DEF57DA"; let ct = "B1B8CC0B250F09A0"; @@ -992,7 +1182,11 @@ mod tests { } #[test] + #[cfg_attr(ossl300, ignore)] + #[cfg(not(boringssl))] fn test_bf_cfb64() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; let ct = "E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"; @@ -1003,7 +1197,11 @@ mod tests { } #[test] + #[cfg_attr(ossl300, ignore)] + #[cfg(not(boringssl))] fn test_bf_ofb() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; let ct = "E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"; @@ -1015,6 +1213,8 @@ mod tests { #[test] fn test_des_cbc() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "54686973206973206120746573742e"; let ct = "6f2867cfefda048a4046ef7e556c7132"; @@ -1026,6 +1226,8 @@ mod tests { #[test] fn test_des_ecb() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "54686973206973206120746573742e"; let ct = "0050ab8aecec758843fe157b4dde938c"; @@ -1035,20 +1237,45 @@ mod tests { cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv); } + #[test] + fn test_des_ede3() { + let pt = "9994f4c69d40ae4f34ff403b5cf39d4c8207ea5d3e19a5fd"; + let ct = "9e5c4297d60582f81071ac8ab7d0698d4c79de8b94c519858207ea5d3e19a5fd"; + let key = "010203040506070801020304050607080102030405060708"; + let iv = "5cc118306dc702e4"; + + cipher_test(super::Cipher::des_ede3(), pt, ct, key, iv); + } + + #[test] + fn test_des_ede3_cbc() { + let pt = "54686973206973206120746573742e"; + let ct = "6f2867cfefda048a4046ef7e556c7132"; + let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe"; + let iv = "0001020304050607"; + + cipher_test(super::Cipher::des_ede3_cbc(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(boringssl))] + fn test_des_ede3_cfb64() { + let pt = "2b1773784b5889dc788477367daa98ad"; + let ct = "6f2867cfefda048a4046ef7e556c7132"; + let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe"; + let iv = "0001020304050607"; + + cipher_test(super::Cipher::des_ede3_cfb64(), pt, ct, key, iv); + } + #[test] fn test_aes128_gcm() { - let key = "0e00c76561d2bd9b40c3c15427e2b08f"; - let iv = "492cadaccd3ca3fbc9cf9f06eb3325c4e159850b0dbe98199b89b7af528806610b6f63998e1eae80c348e7\ - 4cbb921d8326631631fc6a5d304f39166daf7ea15fa1977f101819adb510b50fe9932e12c5a85aa3fd1e73\ - d8d760af218be829903a77c63359d75edd91b4f6ed5465a72662f5055999e059e7654a8edc921aa0d496"; - let pt = "fef03c2d7fb15bf0d2df18007d99f967c878ad59359034f7bb2c19af120685d78e32f6b8b83b032019956c\ - a9c0195721476b85"; - let aad = "d8f1163d8c840292a2b2dacf4ac7c36aff8733f18fabb4fa5594544125e03d1e6e5d6d0fd61656c8d8f327\ - c92839ae5539bb469c9257f109ebff85aad7bd220fdaa95c022dbd0c7bb2d878ad504122c943045d3c5eba\ - 8f1f56c0"; - let ct = "4f6cf471be7cbd2575cd5a1747aea8fe9dea83e51936beac3e68f66206922060c697ffa7af80ad6bb68f2c\ - f4fc97416ee52abe"; - let tag = "e20b6655"; + let key = "23dc8d23d95b6fd1251741a64f7d4f41"; + let iv = "f416f48ad44d9efa1179e167"; + let pt = "6cb9b71dd0ccd42cdf87e8e396fc581fd8e0d700e360f590593b748e105390de"; + let aad = "45074844c97d515c65bbe37c210a5a4b08c21c588efe5c5f73c4d9c17d34dacddc0bb6a8a53f7bf477b9780c1c2a928660df87016b2873fe876b2b887fb5886bfd63216b7eaecc046372a82c047eb043f0b063226ee52a12c69b"; + let ct = "8ad20486778e87387efb3f2574e509951c0626816722018129e578b2787969d3"; + let tag = "91e1bc09"; // this tag is smaller than you'd normally want, but I pulled this test from the part of // the NIST test vectors that cover 4 byte tags. @@ -1060,9 +1287,10 @@ mod tests { &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, - ).unwrap(); - assert_eq!(ct, out.to_hex()); - assert_eq!(tag, actual_tag.to_hex()); + ) + .unwrap(); + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); let out = decrypt_aead( Cipher::aes_128_gcm(), @@ -1071,35 +1299,212 @@ mod tests { &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), - ).unwrap(); - assert_eq!(pt, out.to_hex()); + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } + + #[test] + #[cfg(not(boringssl))] + fn test_aes128_ccm() { + let key = "3ee186594f110fb788a8bf8aa8be5d4a"; + let nonce = "44f705d52acf27b7f17196aa9b"; + let aad = "2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57"; + + let pt = "d71864877f2578db092daba2d6a1f9f4698a9c356c7830a1"; + let ct = "b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0"; + let tag = "d6965f5aa6e31302a9cc2b36"; + + let mut actual_tag = [0; 12]; + let out = encrypt_aead( + Cipher::aes_128_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag, + ) + .unwrap(); + + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); + + let out = decrypt_aead( + Cipher::aes_128_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); } #[test] - #[cfg(all(ossl110, feature = "v110"))] + #[cfg(not(boringssl))] + fn test_aes128_ccm_verify_fail() { + let key = "3ee186594f110fb788a8bf8aa8be5d4a"; + let nonce = "44f705d52acf27b7f17196aa9b"; + let aad = "2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57"; + + let ct = "b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0"; + let tag = "00005f5aa6e31302a9cc2b36"; + + let out = decrypt_aead( + Cipher::aes_128_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ); + assert!(out.is_err()); + } + + #[test] + #[cfg(not(boringssl))] + fn test_aes256_ccm() { + let key = "7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d"; + let nonce = "dde2a362ce81b2b6913abc3095"; + let aad = "404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695"; + + let pt = "7ebef26bf4ecf6f0ebb2eb860edbf900f27b75b4a6340fdb"; + let ct = "353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd"; + let tag = "2927a053c9244d3217a7ad05"; + + let mut actual_tag = [0; 12]; + let out = encrypt_aead( + Cipher::aes_256_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag, + ) + .unwrap(); + + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); + + let out = decrypt_aead( + Cipher::aes_256_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } + + #[test] + #[cfg(not(boringssl))] + fn test_aes256_ccm_verify_fail() { + let key = "7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d"; + let nonce = "dde2a362ce81b2b6913abc3095"; + let aad = "404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695"; + + let ct = "353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd"; + let tag = "0000a053c9244d3217a7ad05"; + + let out = decrypt_aead( + Cipher::aes_256_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ); + assert!(out.is_err()); + } + + #[test] + #[cfg(ossl110)] + fn test_aes_128_ocb() { + let key = "000102030405060708090a0b0c0d0e0f"; + let aad = "0001020304050607"; + let tag = "16dc76a46d47e1ead537209e8a96d14e"; + let iv = "000102030405060708090a0b"; + let pt = "0001020304050607"; + let ct = "92b657130a74b85a"; + + let mut actual_tag = [0; 16]; + let out = encrypt_aead( + Cipher::aes_128_ocb(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag, + ) + .unwrap(); + + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); + + let out = decrypt_aead( + Cipher::aes_128_ocb(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } + + #[test] + #[cfg(ossl110)] + fn test_aes_128_ocb_fail() { + let key = "000102030405060708090a0b0c0d0e0f"; + let aad = "0001020304050607"; + let tag = "16dc76a46d47e1ead537209e8a96d14e"; + let iv = "000000000405060708090a0b"; + let ct = "92b657130a74b85a"; + + let out = decrypt_aead( + Cipher::aes_128_ocb(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ); + assert!(out.is_err()); + } + + #[test] + #[cfg(any(ossl110))] fn test_chacha20() { let key = "0000000000000000000000000000000000000000000000000000000000000000"; let iv = "00000000000000000000000000000000"; - let pt = "000000000000000000000000000000000000000000000000000000000000000000000000000000000\ - 00000000000000000000000000000000000000000000000"; - let ct = "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7\ - 724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586"; + let pt = + "000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + 00000000000000000000000000000000000000000000000"; + let ct = + "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7\ + 724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586"; cipher_test(Cipher::chacha20(), pt, ct, key, iv); } #[test] - #[cfg(all(ossl110, feature = "v110"))] + #[cfg(any(ossl110))] fn test_chacha20_poly1305() { let key = "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"; let iv = "070000004041424344454647"; let aad = "50515253c0c1c2c3c4c5c6c7"; - let pt = "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393\ - a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f722074\ - 6865206675747572652c2073756e73637265656e20776f756c642062652069742e"; - let ct = "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca967128\ - 2fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa\ - b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116"; + let pt = + "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393\ + a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f722074\ + 6865206675747572652c2073756e73637265656e20776f756c642062652069742e"; + let ct = + "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca967128\ + 2fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa\ + b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116"; let tag = "1ae10b594f09e26a7e902ecbd0600691"; let mut actual_tag = [0; 16]; @@ -1110,9 +1515,10 @@ mod tests { &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, - ).unwrap(); - assert_eq!(ct, out.to_hex()); - assert_eq!(tag, actual_tag.to_hex()); + ) + .unwrap(); + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); let out = decrypt_aead( Cipher::chacha20_poly1305(), @@ -1121,7 +1527,106 @@ mod tests { &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), - ).unwrap(); - assert_eq!(pt, out.to_hex()); + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } + + #[test] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED", ossl300)))] + fn test_seed_cbc() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + + let pt = "5363686f6b6f6c6164656e6b756368656e0a"; + let ct = "c2edf0fb2eb11bf7b2f39417a8528896d34b24b6fd79e5923b116dfcd2aba5a4"; + let key = "41414141414141414141414141414141"; + let iv = "41414141414141414141414141414141"; + + cipher_test(super::Cipher::seed_cbc(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED", ossl300)))] + fn test_seed_cfb128() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + + let pt = "5363686f6b6f6c6164656e6b756368656e0a"; + let ct = "71d4d25fc1750cb7789259e7f34061939a41"; + let key = "41414141414141414141414141414141"; + let iv = "41414141414141414141414141414141"; + + cipher_test(super::Cipher::seed_cfb128(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED", ossl300)))] + fn test_seed_ecb() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + + let pt = "5363686f6b6f6c6164656e6b756368656e0a"; + let ct = "0263a9cd498cf0edb0ef72a3231761d00ce601f7d08ad19ad74f0815f2c77f7e"; + let key = "41414141414141414141414141414141"; + let iv = "41414141414141414141414141414141"; + + cipher_test(super::Cipher::seed_ecb(), pt, ct, key, iv); + } + + #[test] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED", ossl300)))] + fn test_seed_ofb() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + + let pt = "5363686f6b6f6c6164656e6b756368656e0a"; + let ct = "71d4d25fc1750cb7789259e7f34061930afd"; + let key = "41414141414141414141414141414141"; + let iv = "41414141414141414141414141414141"; + + 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/types.rs b/openssl/src/types.rs deleted file mode 100644 index 25ffe50..0000000 --- a/openssl/src/types.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[deprecated(note = "use foreign_types instead", since = "0.9.7")] -pub use foreign_types::ForeignType as OpenSslType; - -#[deprecated(note = "use foreign_types instead", since = "0.9.7")] -pub use foreign_types::ForeignTypeRef as OpenSslTypeRef; diff --git a/openssl/src/util.rs b/openssl/src/util.rs index e401058..d852a4b 100644 --- a/openssl/src/util.rs +++ b/openssl/src/util.rs @@ -1,10 +1,10 @@ -use libc::{c_int, c_char, c_void}; +use crate::error::ErrorStack; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::{c_char, c_int, c_void}; use std::any::Any; use std::panic::{self, AssertUnwindSafe}; use std::slice; -use error::ErrorStack; - /// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI /// frames are on the stack). /// @@ -14,7 +14,7 @@ pub struct CallbackState { cb: Option, /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL /// returns. - panic: Option>, + panic: Option>, } impl CallbackState { @@ -34,31 +34,6 @@ impl Drop for CallbackState { } } -pub unsafe extern "C" fn invoke_passwd_cb_old( - buf: *mut c_char, - size: c_int, - _rwflag: c_int, - cb_state: *mut c_void, -) -> c_int -where - F: FnOnce(&mut [c_char]) -> usize, -{ - let callback = &mut *(cb_state as *mut CallbackState); - - let result = panic::catch_unwind(AssertUnwindSafe(|| { - let pass_slice = slice::from_raw_parts_mut(buf, size as usize); - callback.cb.take().unwrap()(pass_slice) - })); - - match result { - Ok(len) => len as c_int, - Err(err) => { - callback.panic = Some(err); - 0 - } - } -} - /// Password callback function, passed to private key loading functions. /// /// `cb_state` is expected to be a pointer to a `CallbackState`. @@ -90,3 +65,29 @@ where } } } + +pub trait ForeignTypeExt: ForeignType { + unsafe fn from_ptr_opt(ptr: *mut Self::CType) -> Option { + if ptr.is_null() { + None + } else { + Some(Self::from_ptr(ptr)) + } + } +} +impl ForeignTypeExt for FT {} + +pub trait ForeignTypeRefExt: ForeignTypeRef { + unsafe fn from_const_ptr<'a>(ptr: *const Self::CType) -> &'a Self { + Self::from_ptr(ptr as *mut Self::CType) + } + + unsafe fn from_const_ptr_opt<'a>(ptr: *const Self::CType) -> Option<&'a Self> { + if ptr.is_null() { + None + } else { + Some(Self::from_const_ptr(ptr as *mut Self::CType)) + } + } +} +impl ForeignTypeRefExt for FT {} diff --git a/openssl/src/verify.rs b/openssl/src/verify.rs deleted file mode 100644 index 65315e4..0000000 --- a/openssl/src/verify.rs +++ /dev/null @@ -1,68 +0,0 @@ -use libc::c_uint; -use ffi; -use foreign_types::ForeignTypeRef; -use std::net::IpAddr; - -use cvt; -use error::ErrorStack; - -bitflags! { - pub struct X509CheckFlags: c_uint { - const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT; - const X509_CHECK_FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS; - const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; - const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS; - const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS - = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS; - /// Requires the `v110` feature and OpenSSL 1.1.0. - #[cfg(all(feature = "v110", ossl110))] - const X509_CHECK_FLAG_NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; - } -} - -foreign_type_and_impl_send_sync! { - type CType = ffi::X509_VERIFY_PARAM; - fn drop = ffi::X509_VERIFY_PARAM_free; - - pub struct X509VerifyParam; - pub struct X509VerifyParamRef; -} - -impl X509VerifyParamRef { - pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) { - unsafe { - ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits); - } - } - - pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::X509_VERIFY_PARAM_set1_host( - self.as_ptr(), - host.as_ptr() as *const _, - host.len(), - )).map(|_| ()) - } - } - - pub fn set_ip(&mut self, ip: IpAddr) -> Result<(), ErrorStack> { - unsafe { - let mut buf = [0; 16]; - let len = match ip { - IpAddr::V4(addr) => { - buf[..4].copy_from_slice(&addr.octets()); - 4 - } - IpAddr::V6(addr) => { - buf.copy_from_slice(&addr.octets()); - 16 - } - }; - cvt(ffi::X509_VERIFY_PARAM_set1_ip( - self.as_ptr(), - buf.as_ptr() as *const _, - len, - )).map(|_| ()) - } - } -} diff --git a/openssl/src/version.rs b/openssl/src/version.rs index 7254d7b..f1a324c 100644 --- a/openssl/src/version.rs +++ b/openssl/src/version.rs @@ -11,17 +11,27 @@ // limitations under the License. // -use std::ffi::CStr; +//! Build and version information. -#[cfg(ossl10x)] -use ffi::{SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, - SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, - SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, - SSLeay_version as OpenSSL_version}; +use cfg_if::cfg_if; +use openssl_macros::corresponds; +use std::ffi::CStr; -#[cfg(ossl110)] -use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, - OpenSSL_version_num, OpenSSL_version}; +cfg_if! { + if #[cfg(any(ossl110, libressl271))] { + use ffi::{ + OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, + OpenSSL_version_num, OpenSSL_version, + }; + } else { + use ffi::{ + SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, + SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, + SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, + SSLeay_version as OpenSSL_version, + }; + } +} /// OPENSSL_VERSION_NUMBER is a numeric release version identifier: /// @@ -34,25 +44,13 @@ use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, O /// `0x000906000 == 0.9.6 dev` /// `0x000906023 == 0.9.6b beta 3` /// `0x00090605f == 0.9.6e release` -/// -/// Versions prior to 0.9.3 have identifiers < 0x0930. Versions between 0.9.3 and 0.9.5 had a version identifier with this interpretation: -/// -/// `MMNNFFRBB major minor fix final beta/patch` -/// -/// for example -/// -/// `0x000904100 == 0.9.4 release` -/// `0x000905000 == 0.9.5 dev` -/// -/// Version 0.9.5a had an interim interpretation that is like the current one, except the patch level got the highest bit set, to keep continuity. The number was therefore 0x0090581f -/// -/// The return value of this function can be compared to the macro to make sure that the correct version of the library has been loaded, especially when using DLLs on Windows systems. +#[corresponds(OpenSSL_version_num)] pub fn number() -> i64 { unsafe { OpenSSL_version_num() as i64 } } - /// The text variant of the version number and the release date. For example, "OpenSSL 0.9.5a 1 Apr 2000". +#[corresponds(OpenSSL_version)] pub fn version() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_VERSION)) @@ -63,6 +61,7 @@ pub fn version() -> &'static str { /// The compiler flags set for the compilation process in the form "compiler: ..." if available or /// "compiler: information not available" otherwise. +#[corresponds(OpenSSL_version)] pub fn c_flags() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_CFLAGS)) @@ -72,6 +71,7 @@ pub fn c_flags() -> &'static str { } /// The date of the build process in the form "built on: ..." if available or "built on: date not available" otherwise. +#[corresponds(OpenSSL_version)] pub fn built_on() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_BUILT_ON)) @@ -81,6 +81,7 @@ pub fn built_on() -> &'static str { } /// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise. +#[corresponds(OpenSSL_version)] pub fn platform() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_PLATFORM)) @@ -90,6 +91,7 @@ pub fn platform() -> &'static str { } /// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise. +#[corresponds(OpenSSL_version)] pub fn dir() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_DIR)) @@ -109,7 +111,7 @@ fn test_versions() { println!("Platform: '{}'", platform()); println!("Dir: '{}'", dir()); - #[cfg(not(libressl))] + #[cfg(not(any(libressl, boringssl)))] fn expected_name() -> &'static str { "OpenSSL" } @@ -117,10 +119,17 @@ fn test_versions() { fn expected_name() -> &'static str { "LibreSSL" } + #[cfg(boringssl)] + fn expected_name() -> &'static str { + "BoringSSL" + } assert!(number() > 0); assert!(version().starts_with(expected_name())); assert!(c_flags().starts_with("compiler:")); - assert!(built_on().starts_with("built on:")); + // some distributions patch out dates out of openssl so that the builds are reproducible + if !built_on().is_empty() { + assert!(built_on().starts_with("built on:")); + } assert!(dir().starts_with("OPENSSLDIR:")); } diff --git a/openssl/src/x509/extension.rs b/openssl/src/x509/extension.rs index 83a8266..ebbea1c 100644 --- a/openssl/src/x509/extension.rs +++ b/openssl/src/x509/extension.rs @@ -1,250 +1,42 @@ -use std::fmt::{self, Write}; - -use error::ErrorStack; -use nid::{self, Nid}; -use x509::{X509v3Context, X509Extension}; - -/// Type-only version of the `Extension` enum. -/// -/// See the `Extension` documentation for more information on the different -/// variants. -#[derive(Clone, Hash, PartialEq, Eq)] -#[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] -pub enum ExtensionType { - KeyUsage, - ExtKeyUsage, - SubjectAltName, - IssuerAltName, - OtherNid(Nid), - OtherStr(String), -} - -/// A X.509 v3 certificate extension. -/// -/// Only one extension of each type is allow in a certificate. -/// See RFC 3280 for more information about extensions. -#[derive(Clone)] -#[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] -pub enum Extension { - /// The purposes of the key contained in the certificate - KeyUsage(Vec), - /// The extended purposes of the key contained in the certificate - ExtKeyUsage(Vec), - /// Subject Alternative Names - SubjectAltName(Vec<(AltNameOption, String)>), - /// Issuer Alternative Names - IssuerAltName(Vec<(AltNameOption, String)>), - /// Arbitrary extensions by NID. See `man x509v3_config` for value syntax. - /// - /// You must not use this to add extensions which this enum can express directly. - /// - /// ``` - /// use openssl::x509::extension::Extension::*; - /// use openssl::nid; - /// - /// # let generator = openssl::x509::X509Generator::new(); - /// generator.add_extension(OtherNid(nid::BASIC_CONSTRAINTS,"critical,CA:TRUE".to_owned())); - /// ``` - OtherNid(Nid, String), - /// Arbitrary extensions by OID string. See `man ASN1_generate_nconf` for value syntax. - /// - /// You must not use this to add extensions which this enum can express directly. - /// - /// ``` - /// use openssl::x509::extension::Extension::*; - /// - /// # let generator = openssl::x509::X509Generator::new(); - /// generator.add_extension(OtherStr("2.999.2".to_owned(),"ASN1:UTF8:example value".to_owned())); - /// ``` - OtherStr(String, String), -} - -impl Extension { - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn get_type(&self) -> ExtensionType { - match self { - &Extension::KeyUsage(_) => ExtensionType::KeyUsage, - &Extension::ExtKeyUsage(_) => ExtensionType::ExtKeyUsage, - &Extension::SubjectAltName(_) => ExtensionType::SubjectAltName, - &Extension::IssuerAltName(_) => ExtensionType::IssuerAltName, - &Extension::OtherNid(nid, _) => ExtensionType::OtherNid(nid), - &Extension::OtherStr(ref s, _) => ExtensionType::OtherStr(s.clone()), - } - } -} - -impl ExtensionType { - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn get_nid(&self) -> Option { - match self { - &ExtensionType::KeyUsage => Some(nid::KEY_USAGE), - &ExtensionType::ExtKeyUsage => Some(nid::EXT_KEY_USAGE), - &ExtensionType::SubjectAltName => Some(nid::SUBJECT_ALT_NAME), - &ExtensionType::IssuerAltName => Some(nid::ISSUER_ALT_NAME), - &ExtensionType::OtherNid(nid) => Some(nid), - &ExtensionType::OtherStr(_) => None, - } - } - - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn get_name(&self) -> Option<&str> { - match self { - &ExtensionType::OtherStr(ref s) => Some(s), - _ => None, - } - } -} - -// FIXME: This would be nicer as a method on Iterator. This can -// eventually be replaced by the successor to std::slice::SliceConcatExt.connect -fn join, T: ToString>(iter: I, sep: &str) -> String { - iter.enumerate().fold(String::new(), |mut acc, (idx, v)| { - if idx > 0 { - acc.push_str(sep) - }; - acc.push_str(&v.to_string()); - acc - }) -} - -impl ToString for Extension { - fn to_string(&self) -> String { - match self { - &Extension::KeyUsage(ref purposes) => join(purposes.iter(), ","), - &Extension::ExtKeyUsage(ref purposes) => join(purposes.iter(), ","), - &Extension::SubjectAltName(ref names) => { - join( - names.iter().map(|&(ref opt, ref val)| { - opt.to_string() + ":" + &val - }), - ",", - ) - } - &Extension::IssuerAltName(ref names) => { - join( - names.iter().map(|&(ref opt, ref val)| { - opt.to_string() + ":" + &val - }), - ",", - ) - } - &Extension::OtherNid(_, ref value) => value.clone(), - &Extension::OtherStr(_, ref value) => value.clone(), - } - } -} - -#[derive(Clone, Copy)] -#[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] -pub enum KeyUsageOption { - DigitalSignature, - NonRepudiation, - KeyEncipherment, - DataEncipherment, - KeyAgreement, - KeyCertSign, - CRLSign, - EncipherOnly, - DecipherOnly, -} - -impl fmt::Display for KeyUsageOption { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.pad(match self { - &KeyUsageOption::DigitalSignature => "digitalSignature", - &KeyUsageOption::NonRepudiation => "nonRepudiation", - &KeyUsageOption::KeyEncipherment => "keyEncipherment", - &KeyUsageOption::DataEncipherment => "dataEncipherment", - &KeyUsageOption::KeyAgreement => "keyAgreement", - &KeyUsageOption::KeyCertSign => "keyCertSign", - &KeyUsageOption::CRLSign => "cRLSign", - &KeyUsageOption::EncipherOnly => "encipherOnly", - &KeyUsageOption::DecipherOnly => "decipherOnly", - }) - } -} - -#[derive(Clone)] -#[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] -pub enum ExtKeyUsageOption { - ServerAuth, - ClientAuth, - CodeSigning, - EmailProtection, - TimeStamping, - MsCodeInd, - MsCodeCom, - MsCtlSign, - MsSgc, - MsEfs, - NsSgc, - /// An arbitrary key usage by OID. - Other(String), -} - -impl fmt::Display for ExtKeyUsageOption { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.pad(match self { - &ExtKeyUsageOption::ServerAuth => "serverAuth", - &ExtKeyUsageOption::ClientAuth => "clientAuth", - &ExtKeyUsageOption::CodeSigning => "codeSigning", - &ExtKeyUsageOption::EmailProtection => "emailProtection", - &ExtKeyUsageOption::TimeStamping => "timeStamping", - &ExtKeyUsageOption::MsCodeInd => "msCodeInd", - &ExtKeyUsageOption::MsCodeCom => "msCodeCom", - &ExtKeyUsageOption::MsCtlSign => "msCTLSign", - &ExtKeyUsageOption::MsSgc => "msSGC", - &ExtKeyUsageOption::MsEfs => "msEFS", - &ExtKeyUsageOption::NsSgc => "nsSGC", - &ExtKeyUsageOption::Other(ref s) => &s[..], - }) - } -} - -#[derive(Clone, Copy)] -#[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] -pub enum AltNameOption { - /// The value is specified as OID;content. See `man ASN1_generate_nconf` for more information on the content syntax. - /// - /// ``` - /// use openssl::x509::extension::Extension::*; - /// use openssl::x509::extension::AltNameOption::Other as OtherName; - /// - /// # let generator = openssl::x509::X509Generator::new(); - /// generator.add_extension(SubjectAltName(vec![(OtherName,"2.999.3;ASN1:UTF8:some other name".to_owned())])); - /// ``` - Other, - Email, - DNS, - // X400, // Not supported by OpenSSL - Directory, - // EDIParty, // Not supported by OpenSSL - URI, - IPAddress, - RegisteredID, -} - -impl fmt::Display for AltNameOption { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.pad(match self { - &AltNameOption::Other => "otherName", - &AltNameOption::Email => "email", - &AltNameOption::DNS => "DNS", - &AltNameOption::Directory => "dirName", - &AltNameOption::URI => "URI", - &AltNameOption::IPAddress => "IP", - &AltNameOption::RegisteredID => "RID", - }) - } -} - +//! Add extensions to an `X509` certificate or certificate request. +//! +//! The extensions defined for X.509 v3 certificates provide methods for +//! associating additional attributes with users or public keys and for +//! managing relationships between CAs. The extensions created using this +//! module can be used with `X509v3Context` objects. +//! +//! # Example +//! +//! ```rust +//! use openssl::x509::extension::BasicConstraints; +//! use openssl::x509::X509Extension; +//! +//! let mut bc = BasicConstraints::new(); +//! let bc = bc.critical().ca().pathlen(1); +//! +//! let extension: X509Extension = bc.build().unwrap(); +//! ``` +use std::fmt::Write; + +use crate::error::ErrorStack; +use crate::nid::Nid; +use crate::x509::{X509Extension, X509v3Context}; + +/// An extension which indicates whether a certificate is a CA certificate. pub struct BasicConstraints { critical: bool, ca: bool, pathlen: Option, } +impl Default for BasicConstraints { + fn default() -> BasicConstraints { + BasicConstraints::new() + } +} + impl BasicConstraints { + /// Construct a new `BasicConstraints` extension. pub fn new() -> BasicConstraints { BasicConstraints { critical: false, @@ -253,21 +45,26 @@ impl BasicConstraints { } } + /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut BasicConstraints { self.critical = true; self } + /// Sets the `ca` flag to `true`. pub fn ca(&mut self) -> &mut BasicConstraints { self.ca = true; self } + /// Sets the `pathlen` to an optional non-negative value. The `pathlen` is the + /// maximum number of CAs that can appear below this one in a chain. pub fn pathlen(&mut self, pathlen: u32) -> &mut BasicConstraints { self.pathlen = Some(pathlen); self } + /// Return the `BasicConstraints` extension as an `X509Extension`. pub fn build(&self) -> Result { let mut value = String::new(); if self.critical { @@ -282,10 +79,11 @@ impl BasicConstraints { if let Some(pathlen) = self.pathlen { write!(value, ",pathlen:{}", pathlen).unwrap(); } - X509Extension::new_nid(None, None, nid::BASIC_CONSTRAINTS, &value) + X509Extension::new_nid(None, None, Nid::BASIC_CONSTRAINTS, &value) } } +/// An extension consisting of a list of names of the permitted key usages. pub struct KeyUsage { critical: bool, digital_signature: bool, @@ -299,7 +97,14 @@ pub struct KeyUsage { decipher_only: bool, } +impl Default for KeyUsage { + fn default() -> KeyUsage { + KeyUsage::new() + } +} + impl KeyUsage { + /// Construct a new `KeyUsage` extension. pub fn new() -> KeyUsage { KeyUsage { critical: false, @@ -315,56 +120,67 @@ impl KeyUsage { } } + /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut KeyUsage { self.critical = true; self } + /// Sets the `digitalSignature` flag to `true`. pub fn digital_signature(&mut self) -> &mut KeyUsage { self.digital_signature = true; self } + /// Sets the `nonRepudiation` flag to `true`. pub fn non_repudiation(&mut self) -> &mut KeyUsage { self.non_repudiation = true; self } + /// Sets the `keyEncipherment` flag to `true`. pub fn key_encipherment(&mut self) -> &mut KeyUsage { self.key_encipherment = true; self } + /// Sets the `dataEncipherment` flag to `true`. pub fn data_encipherment(&mut self) -> &mut KeyUsage { self.data_encipherment = true; self } + /// Sets the `keyAgreement` flag to `true`. pub fn key_agreement(&mut self) -> &mut KeyUsage { self.key_agreement = true; self } + /// Sets the `keyCertSign` flag to `true`. pub fn key_cert_sign(&mut self) -> &mut KeyUsage { self.key_cert_sign = true; self } + /// Sets the `cRLSign` flag to `true`. pub fn crl_sign(&mut self) -> &mut KeyUsage { self.crl_sign = true; self } + /// Sets the `encipherOnly` flag to `true`. pub fn encipher_only(&mut self) -> &mut KeyUsage { self.encipher_only = true; self } + /// Sets the `decipherOnly` flag to `true`. pub fn decipher_only(&mut self) -> &mut KeyUsage { self.decipher_only = true; self } + /// Return the `KeyUsage` extension as an `X509Extension`. pub fn build(&self) -> Result { let mut value = String::new(); let mut first = true; @@ -398,10 +214,12 @@ impl KeyUsage { append(&mut value, &mut first, self.crl_sign, "cRLSign"); append(&mut value, &mut first, self.encipher_only, "encipherOnly"); append(&mut value, &mut first, self.decipher_only, "decipherOnly"); - X509Extension::new_nid(None, None, nid::KEY_USAGE, &value) + X509Extension::new_nid(None, None, Nid::KEY_USAGE, &value) } } +/// An extension consisting of a list of usages indicating purposes +/// for which the certificate public key can be used for. pub struct ExtendedKeyUsage { critical: bool, server_auth: bool, @@ -418,7 +236,14 @@ pub struct ExtendedKeyUsage { other: Vec, } +impl Default for ExtendedKeyUsage { + fn default() -> ExtendedKeyUsage { + ExtendedKeyUsage::new() + } +} + impl ExtendedKeyUsage { + /// Construct a new `ExtendedKeyUsage` extension. pub fn new() -> ExtendedKeyUsage { ExtendedKeyUsage { critical: false, @@ -437,66 +262,85 @@ impl ExtendedKeyUsage { } } + /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut ExtendedKeyUsage { self.critical = true; self } + /// Sets the `serverAuth` flag to `true`. pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage { self.server_auth = true; self } + /// Sets the `clientAuth` flag to `true`. pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage { self.client_auth = true; self } + /// Sets the `codeSigning` flag to `true`. pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage { self.code_signing = true; self } + /// Sets the `emailProtection` flag to `true`. + pub fn email_protection(&mut self) -> &mut ExtendedKeyUsage { + self.email_protection = true; + self + } + + /// Sets the `timeStamping` flag to `true`. pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage { self.time_stamping = true; self } + /// Sets the `msCodeInd` flag to `true`. pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage { self.ms_code_ind = true; self } + /// Sets the `msCodeCom` flag to `true`. pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage { self.ms_code_com = true; self } + /// Sets the `msCTLSign` flag to `true`. pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage { self.ms_ctl_sign = true; self } + /// Sets the `msSGC` flag to `true`. pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage { self.ms_sgc = true; self } + /// Sets the `msEFS` flag to `true`. pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage { self.ms_efs = true; self } + /// Sets the `nsSGC` flag to `true`. pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage { self.ns_sgc = true; self } + /// Sets a flag not already defined. pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage { self.other.push(other.to_owned()); self } + /// Return the `ExtendedKeyUsage` extension as an `X509Extension`. pub fn build(&self) -> Result { let mut value = String::new(); let mut first = true; @@ -520,40 +364,60 @@ impl ExtendedKeyUsage { for other in &self.other { append(&mut value, &mut first, true, other); } - X509Extension::new_nid(None, None, nid::EXT_KEY_USAGE, &value) + X509Extension::new_nid(None, None, Nid::EXT_KEY_USAGE, &value) } } +/// An extension that provides a means of identifying certificates that contain a +/// particular public key. pub struct SubjectKeyIdentifier { critical: bool, } +impl Default for SubjectKeyIdentifier { + fn default() -> SubjectKeyIdentifier { + SubjectKeyIdentifier::new() + } +} + impl SubjectKeyIdentifier { + /// Construct a new `SubjectKeyIdentifier` extension. pub fn new() -> SubjectKeyIdentifier { SubjectKeyIdentifier { critical: false } } + /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut SubjectKeyIdentifier { self.critical = true; self } - pub fn build(&self, ctx: &X509v3Context) -> Result { + /// Return a `SubjectKeyIdentifier` extension as an `X509Extension`. + pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); append(&mut value, &mut first, true, "hash"); - X509Extension::new_nid(None, Some(ctx), nid::SUBJECT_KEY_IDENTIFIER, &value) + X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_KEY_IDENTIFIER, &value) } } +/// An extension that provides a means of identifying the public key corresponding +/// to the private key used to sign a CRL. pub struct AuthorityKeyIdentifier { critical: bool, keyid: Option, issuer: Option, } +impl Default for AuthorityKeyIdentifier { + fn default() -> AuthorityKeyIdentifier { + AuthorityKeyIdentifier::new() + } +} + impl AuthorityKeyIdentifier { + /// Construct a new `AuthorityKeyIdentifier` extension. pub fn new() -> AuthorityKeyIdentifier { AuthorityKeyIdentifier { critical: false, @@ -562,22 +426,26 @@ impl AuthorityKeyIdentifier { } } + /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut AuthorityKeyIdentifier { self.critical = true; self } + /// Sets the `keyid` flag. pub fn keyid(&mut self, always: bool) -> &mut AuthorityKeyIdentifier { self.keyid = Some(always); self } + /// Sets the `issuer` flag. pub fn issuer(&mut self, always: bool) -> &mut AuthorityKeyIdentifier { self.issuer = Some(always); self } - pub fn build(&self, ctx: &X509v3Context) -> Result { + /// Return a `AuthorityKeyIdentifier` extension as an `X509Extension`. + pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); @@ -591,16 +459,25 @@ impl AuthorityKeyIdentifier { Some(false) => append(&mut value, &mut first, true, "issuer"), None => {} } - X509Extension::new_nid(None, Some(ctx), nid::AUTHORITY_KEY_IDENTIFIER, &value) + X509Extension::new_nid(None, Some(ctx), Nid::AUTHORITY_KEY_IDENTIFIER, &value) } } +/// An extension that allows additional identities to be bound to the subject +/// of the certificate. pub struct SubjectAlternativeName { critical: bool, names: Vec, } +impl Default for SubjectAlternativeName { + fn default() -> SubjectAlternativeName { + SubjectAlternativeName::new() + } +} + impl SubjectAlternativeName { + /// Construct a new `SubjectAlternativeName` extension. pub fn new() -> SubjectAlternativeName { SubjectAlternativeName { critical: false, @@ -608,54 +485,63 @@ impl SubjectAlternativeName { } } + /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut SubjectAlternativeName { self.critical = true; self } + /// Sets the `email` flag. pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName { self.names.push(format!("email:{}", email)); self } + /// Sets the `uri` flag. pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName { self.names.push(format!("URI:{}", uri)); self } + /// Sets the `dns` flag. pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName { self.names.push(format!("DNS:{}", dns)); self } + /// Sets the `rid` flag. pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName { self.names.push(format!("RID:{}", rid)); self } + /// Sets the `ip` flag. pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName { self.names.push(format!("IP:{}", ip)); self } + /// Sets the `dirName` flag. pub fn dir_name(&mut self, dir_name: &str) -> &mut SubjectAlternativeName { self.names.push(format!("dirName:{}", dir_name)); self } + /// Sets the `otherName` flag. pub fn other_name(&mut self, other_name: &str) -> &mut SubjectAlternativeName { self.names.push(format!("otherName:{}", other_name)); self } - pub fn build(&self, ctx: &X509v3Context) -> Result { + /// Return a `SubjectAlternativeName` extension as an `X509Extension`. + pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); for name in &self.names { append(&mut value, &mut first, true, name); } - X509Extension::new_nid(None, Some(ctx), nid::SUBJECT_ALT_NAME, &value) + X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_ALT_NAME, &value) } } diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index dff6522..4f08bbc 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -1,319 +1,210 @@ -#![allow(deprecated)] -use libc::{c_int, c_long}; -use ffi; -use foreign_types::{ForeignType, ForeignTypeRef}; -use std::collections::HashMap; +//! The standard defining the format of public key certificates. +//! +//! An `X509` certificate binds an identity to a public key, and is either +//! signed by a certificate authority (CA) or self-signed. An entity that gets +//! a hold of a certificate can both verify your identity (via a CA) and encrypt +//! data with the included public key. `X509` certificates are used in many +//! Internet protocols, including SSL/TLS, which is the basis for HTTPS, +//! the secure protocol for browsing the web. + +use cfg_if::cfg_if; +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; +use libc::{c_int, c_long, c_uint}; +use std::cmp::{self, Ordering}; +use std::convert::TryFrom; use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt; use std::marker::PhantomData; use std::mem; +use std::net::IpAddr; use std::path::Path; use std::ptr; use std::slice; use std::str; -use {cvt, cvt_p, cvt_n}; -use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef, Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef}; -use bio::MemBioSlice; -use bn::{BigNum, MSB_MAYBE_ZERO}; -use conf::ConfRef; -use error::ErrorStack; -use hash::MessageDigest; -use nid::{self, Nid}; -use pkey::{PKey, PKeyRef}; -use stack::{Stack, StackRef, Stackable}; -use string::OpensslString; -use ssl::SslRef; - -#[cfg(ossl10x)] -use ffi::{X509_set_notBefore, X509_set_notAfter, ASN1_STRING_data, X509_STORE_CTX_get_chain}; -#[cfg(ossl110)] -use ffi::{X509_set1_notBefore as X509_set_notBefore, X509_set1_notAfter as X509_set_notAfter, - ASN1_STRING_get0_data as ASN1_STRING_data, - X509_STORE_CTX_get0_chain as X509_STORE_CTX_get_chain}; - -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] +use crate::asn1::{ + Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, Asn1Type, +}; +use crate::bio::MemBioSlice; +use crate::conf::ConfRef; +use crate::error::ErrorStack; +use crate::ex_data::Index; +use crate::hash::{DigestBytes, MessageDigest}; +use crate::nid::Nid; +use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; +use crate::ssl::SslRef; +use crate::stack::{Stack, StackRef, Stackable}; +use crate::string::OpensslString; +use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; +use crate::{cvt, cvt_n, cvt_p}; +use openssl_macros::corresponds; + +#[cfg(any(ossl102, libressl261))] pub mod verify; -use x509::extension::{ExtensionType, Extension}; - pub mod extension; pub mod store; #[cfg(test)] mod tests; -pub struct X509FileType(c_int); - -impl X509FileType { - pub fn as_raw(&self) -> c_int { - self.0 - } -} - -pub const X509_FILETYPE_PEM: X509FileType = X509FileType(ffi::X509_FILETYPE_PEM); -pub const X509_FILETYPE_ASN1: X509FileType = X509FileType(ffi::X509_FILETYPE_ASN1); -pub const X509_FILETYPE_DEFAULT: X509FileType = X509FileType(ffi::X509_FILETYPE_DEFAULT); - -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE_CTX; fn drop = ffi::X509_STORE_CTX_free; + /// An `X509` certificate store context. pub struct X509StoreContext; + + /// A reference to an [`X509StoreContext`]. pub struct X509StoreContextRef; } -impl X509StoreContextRef { - pub fn error(&self) -> Option { - unsafe { X509VerifyError::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr()) as c_long) } - } - - pub fn current_cert(&self) -> Option<&X509Ref> { - unsafe { - let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(X509Ref::from_ptr(ptr)) - } - } - } - - pub fn error_depth(&self) -> u32 { - unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } +impl X509StoreContext { + /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a + /// context. + #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)] + pub fn ssl_idx() -> Result, ErrorStack> { + unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } } - pub fn chain(&self) -> Option<&StackRef> { + /// Creates a new `X509StoreContext` instance. + #[corresponds(X509_STORE_CTX_new)] + pub fn new() -> Result { unsafe { - let chain = X509_STORE_CTX_get_chain(self.as_ptr()); - - if chain.is_null() { - return None; - } - - Some(StackRef::from_ptr(chain)) + ffi::init(); + cvt_p(ffi::X509_STORE_CTX_new()).map(X509StoreContext) } } +} - /// Returns a reference to the `Ssl` associated with this context. - pub fn ssl(&self) -> Result, ErrorStack> { +impl X509StoreContextRef { + /// Returns application data pertaining to an `X509` store context. + #[corresponds(X509_STORE_CTX_get_ex_data)] + pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { - let idx = cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx())?; - let ssl = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), idx); - if ssl.is_null() { - Ok(None) + let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None } else { - Ok(Some(SslRef::from_ptr(ssl as *mut ffi::SSL))) + Some(&*(data as *const T)) } } } -} -#[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] -pub struct X509Generator { - days: u32, - names: Vec<(String, String)>, - extensions: Extensions, - hash_type: MessageDigest, -} + /// Returns the error code of the context. + #[corresponds(X509_STORE_CTX_get_error)] + pub fn error(&self) -> X509VerifyResult { + unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } + } -#[allow(deprecated)] -impl X509Generator { - /// Creates a new generator with the following defaults: + /// Initializes this context with the given certificate, certificates chain and certificate + /// store. After initializing the context, the `with_context` closure is called with the prepared + /// context. As long as the closure is running, the context stays initialized and can be used + /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished. /// - /// validity period: 365 days + /// * `trust` - The certificate store with the trusted certificates. + /// * `cert` - The certificate that should be verified. + /// * `cert_chain` - The certificates chain. + /// * `with_context` - The closure that is called with the initialized context. /// - /// CN: "rust-openssl" + /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to + /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. /// - /// hash: SHA1 - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn new() -> X509Generator { - X509Generator { - days: 365, - names: vec![], - extensions: Extensions::new(), - hash_type: MessageDigest::sha1(), - } - } + /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_init.html + /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_cleanup.html + pub fn init( + &mut self, + trust: &store::X509StoreRef, + cert: &X509Ref, + cert_chain: &StackRef, + with_context: F, + ) -> Result + where + F: FnOnce(&mut X509StoreContextRef) -> Result, + { + struct Cleanup<'a>(&'a mut X509StoreContextRef); - /// Sets certificate validity period in days since today - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn set_valid_period(mut self, days: u32) -> X509Generator { - self.days = days; - self - } + impl<'a> Drop for Cleanup<'a> { + fn drop(&mut self) { + unsafe { + ffi::X509_STORE_CTX_cleanup(self.0.as_ptr()); + } + } + } - /// Add attribute to the name of the certificate - /// - /// ``` - /// # let generator = openssl::x509::X509Generator::new(); - /// generator.add_name("CN".to_string(),"example.com".to_string()); - /// ``` - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn add_name(mut self, attr_type: String, attr_value: String) -> X509Generator { - self.names.push((attr_type, attr_value)); - self - } + unsafe { + cvt(ffi::X509_STORE_CTX_init( + self.as_ptr(), + trust.as_ptr(), + cert.as_ptr(), + cert_chain.as_ptr(), + ))?; - /// Add multiple attributes to the name of the certificate - /// - /// ``` - /// # let generator = openssl::x509::X509Generator::new(); - /// generator.add_names(vec![("CN".to_string(),"example.com".to_string())]); - /// ``` - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn add_names(mut self, attrs: I) -> X509Generator - where - I: IntoIterator, - { - self.names.extend(attrs); - self + let cleanup = Cleanup(self); + with_context(cleanup.0) + } } - /// Add an extension to a certificate + /// Verifies the stored certificate. /// - /// If the extension already exists, it will be replaced. - /// - /// ``` - /// use openssl::x509::extension::Extension::*; - /// use openssl::x509::extension::KeyUsageOption::*; + /// Returns `true` if verification succeeds. The `error` method will return the specific + /// validation error if the certificate was not valid. /// - /// # let generator = openssl::x509::X509Generator::new(); - /// generator.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment])); - /// ``` - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn add_extension(mut self, ext: extension::Extension) -> X509Generator { - self.extensions.add(ext); - self + /// This will only work inside of a call to `init`. + #[corresponds(X509_verify_cert)] + pub fn verify_cert(&mut self) -> Result { + unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) } } - /// Add multiple extensions to a certificate - /// - /// If any of the extensions already exist, they will be replaced. - /// - /// ``` - /// use openssl::x509::extension::Extension::*; - /// use openssl::x509::extension::KeyUsageOption::*; - /// - /// # let generator = openssl::x509::X509Generator::new(); - /// generator.add_extensions(vec![KeyUsage(vec![DigitalSignature, KeyEncipherment])]); - /// ``` - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn add_extensions(mut self, exts: I) -> X509Generator - where - I: IntoIterator, - { - for ext in exts { - self.extensions.add(ext); + /// Set the error code of the context. + #[corresponds(X509_STORE_CTX_set_error)] + pub fn set_error(&mut self, result: X509VerifyResult) { + unsafe { + ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw()); } - - self } - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn set_sign_hash(mut self, hash_type: MessageDigest) -> X509Generator { - self.hash_type = hash_type; - self - } - - /// Sets the certificate public-key, then self-sign and return it - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn sign(&self, p_key: &PKeyRef) -> Result { - let mut builder = X509::builder()?; - builder.set_version(2)?; - - let mut serial = BigNum::new()?; - serial.rand(128, MSB_MAYBE_ZERO, false)?; - let serial = serial.to_asn1_integer()?; - builder.set_serial_number(&serial)?; - - let not_before = Asn1Time::days_from_now(0)?; - builder.set_not_before(¬_before)?; - let not_after = Asn1Time::days_from_now(self.days)?; - builder.set_not_after(¬_after)?; - - builder.set_pubkey(p_key)?; - - let mut name = X509Name::builder()?; - if self.names.is_empty() { - name.append_entry_by_nid(nid::COMMONNAME, "rust-openssl")?; - } else { - for &(ref key, ref value) in &self.names { - name.append_entry_by_text(key, value)?; - } - } - let name = name.build(); - - builder.set_subject_name(&name)?; - builder.set_issuer_name(&name)?; - - for (exttype, ext) in self.extensions.iter() { - let extension = match exttype.get_nid() { - Some(nid) => { - let ctx = builder.x509v3_context(None, None); - X509Extension::new_nid( - None, - Some(&ctx), - nid, - &ext.to_string(), - )? - } - None => { - let ctx = builder.x509v3_context(None, None); - X509Extension::new( - None, - Some(&ctx), - &exttype.get_name().unwrap(), - &ext.to_string(), - )? - } - }; - builder.append_extension(extension)?; + /// Returns a reference to the certificate which caused the error or None if + /// no certificate is relevant to the error. + #[corresponds(X509_STORE_CTX_get_current_cert)] + pub fn current_cert(&self) -> Option<&X509Ref> { + unsafe { + let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); + X509Ref::from_const_ptr_opt(ptr) } - - builder.sign(p_key, self.hash_type)?; - Ok(builder.build()) } - /// Obtain a certificate signing request (CSR) - #[deprecated(since = "0.9.7", note = "use X509Builder and X509ReqBuilder instead")] - pub fn request(&self, p_key: &PKeyRef) -> Result { - let cert = match self.sign(p_key) { - Ok(c) => c, - Err(x) => return Err(x), - }; + /// Returns a non-negative integer representing the depth in the certificate + /// chain where the error occurred. If it is zero it occurred in the end + /// entity certificate, one if it is the certificate which signed the end + /// entity certificate and so on. + #[corresponds(X509_STORE_CTX_get_error_depth)] + pub fn error_depth(&self) -> u32 { + unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } + } + /// Returns a reference to a complete valid `X509` certificate chain. + #[corresponds(X509_STORE_CTX_get0_chain)] + pub fn chain(&self) -> Option<&StackRef> { unsafe { - let req = cvt_p(ffi::X509_to_X509_REQ( - cert.as_ptr(), - ptr::null_mut(), - ptr::null(), - ))?; - let req = X509Req::from_ptr(req); + let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); - let exts = compat::X509_get0_extensions(cert.as_ptr()); - if exts != ptr::null_mut() { - cvt( - ffi::X509_REQ_add_extensions(req.as_ptr(), exts as *mut _), - )?; + if chain.is_null() { + None + } else { + Some(StackRef::from_ptr(chain)) } - - let hash_fn = self.hash_type.as_ptr(); - cvt( - ffi::X509_REQ_sign(req.as_ptr(), p_key.as_ptr(), hash_fn), - )?; - - Ok(req) } } } -/// A builder type which can create `X509` objects. +/// A builder used to construct an `X509`. pub struct X509Builder(X509); impl X509Builder { /// Creates a new builder. + #[corresponds(X509_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -322,40 +213,48 @@ impl X509Builder { } /// Sets the notAfter constraint on the certificate. + #[corresponds(X509_set1_notAfter)] pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { - unsafe { cvt(X509_set_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } + unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } } /// Sets the notBefore constraint on the certificate. + #[corresponds(X509_set1_notBefore)] pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { - unsafe { cvt(X509_set_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } + unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } } /// Sets the version of the certificate. /// /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of /// the X.509 standard should pass `2` to this method. + #[corresponds(X509_set_version)] + #[allow(clippy::useless_conversion)] 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. + #[corresponds(X509_set_serialNumber)] pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_serialNumber( self.0.as_ptr(), serial_number.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Sets the issuer name of the certificate. + #[corresponds(X509_set_issuer_name)] pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_issuer_name( self.0.as_ptr(), issuer_name.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -377,23 +276,30 @@ impl X509Builder { /// let mut x509 = openssl::x509::X509::builder().unwrap(); /// x509.set_subject_name(&x509_name).unwrap(); /// ``` + #[corresponds(X509_set_subject_name)] pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_subject_name( self.0.as_ptr(), subject_name.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } /// Sets the public key associated with the certificate. - pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { + #[corresponds(X509_set_pubkey)] + pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + T: HasPublic, + { unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } } /// Returns a context object which is needed to create certain X509 extension values. /// /// Set `issuer` to `None` if the certificate will be self-signed. + #[corresponds(X509V3_set_ctx)] pub fn x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, @@ -426,18 +332,27 @@ impl X509Builder { } /// Adds an X509 extension value to the certificate. + /// + /// This works just as `append_extension` except it takes ownership of the `X509Extension`. pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { + self.append_extension2(&extension) + } + + /// Adds an X509 extension value to the certificate. + #[corresponds(X509_add_ext)] + pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> { unsafe { - cvt( - ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1), - )?; - mem::forget(extension); + cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; Ok(()) } } /// Signs the certificate with a private key. - pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> { + #[corresponds(X509_sign)] + pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> + where + T: HasPrivate, + { unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) } } @@ -447,23 +362,54 @@ impl X509Builder { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509; fn drop = ffi::X509_free; + /// An `X509` public key certificate. pub struct X509; + /// Reference to `X509`. pub struct X509Ref; } +#[cfg(boringssl)] +type X509LenTy = c_uint; +#[cfg(not(boringssl))] +type X509LenTy = c_int; + impl X509Ref { + /// Returns this certificate's subject name. + #[corresponds(X509_get_subject_name)] pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = ffi::X509_get_subject_name(self.as_ptr()); - X509NameRef::from_ptr(name) + X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") } } - /// Returns this certificate's SAN entries, if they exist. + /// Returns the hash of the certificates subject + #[corresponds(X509_subject_name_hash)] + pub fn subject_name_hash(&self) -> u32 { + unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } + } + + /// Returns this certificate's issuer name. + #[corresponds(X509_get_issuer_name)] + pub fn issuer_name(&self) -> &X509NameRef { + unsafe { + let name = ffi::X509_get_issuer_name(self.as_ptr()); + X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null") + } + } + + /// Returns the hash of the certificates issuer + #[corresponds(X509_issuer_name_hash)] + pub fn issuer_name_hash(&self) -> u32 { + unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 } + } + + /// Returns this certificate's subject alternative name entries, if they exist. + #[corresponds(X509_get_ext_d2i)] pub fn subject_alt_names(&self) -> Option> { unsafe { let stack = ffi::X509_get_ext_d2i( @@ -472,95 +418,184 @@ impl X509Ref { ptr::null_mut(), ptr::null_mut(), ); - if stack.is_null() { - return None; - } + Stack::from_ptr_opt(stack as *mut _) + } + } + + /// Returns this certificate's issuer alternative name entries, if they exist. + #[corresponds(X509_get_ext_d2i)] + pub fn issuer_alt_names(&self) -> Option> { + unsafe { + let stack = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_issuer_alt_name, + ptr::null_mut(), + ptr::null_mut(), + ); + Stack::from_ptr_opt(stack as *mut _) + } + } - Some(Stack::from_ptr(stack as *mut _)) + /// Returns this certificate's [`authority information access`] entries, if they exist. + /// + /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1 + #[corresponds(X509_get_ext_d2i)] + pub fn authority_info(&self) -> Option> { + unsafe { + let stack = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_info_access, + ptr::null_mut(), + ptr::null_mut(), + ); + Stack::from_ptr_opt(stack as *mut _) } } - pub fn public_key(&self) -> Result { + #[corresponds(X509_get_pubkey)] + pub fn public_key(&self) -> Result, ErrorStack> { unsafe { let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; Ok(PKey::from_ptr(pkey)) } } - /// Returns certificate fingerprint calculated using provided hash - pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { + /// Returns a digest of the DER representation of the certificate. + #[corresponds(X509_digest)] + pub fn digest(&self, hash_type: MessageDigest) -> Result { unsafe { - let evp = hash_type.as_ptr(); - let mut len = ffi::EVP_MAX_MD_SIZE; - let mut buf = vec![0u8; len as usize]; + let mut digest = DigestBytes { + buf: [0; ffi::EVP_MAX_MD_SIZE as usize], + len: ffi::EVP_MAX_MD_SIZE as usize, + }; + let mut len = ffi::EVP_MAX_MD_SIZE as c_uint; cvt(ffi::X509_digest( self.as_ptr(), - evp, - buf.as_mut_ptr() as *mut _, + hash_type.as_ptr(), + digest.buf.as_mut_ptr() as *mut _, &mut len, ))?; - buf.truncate(len as usize); - Ok(buf) + digest.len = len as usize; + + Ok(digest) } } + #[deprecated(since = "0.10.9", note = "renamed to digest")] + pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { + self.digest(hash_type).map(|b| b.to_vec()) + } + /// Returns the certificate's Not After validity period. + #[corresponds(X509_getm_notAfter)] pub fn not_after(&self) -> &Asn1TimeRef { unsafe { - let date = compat::X509_get_notAfter(self.as_ptr()); - assert!(!date.is_null()); - Asn1TimeRef::from_ptr(date) + let date = X509_getm_notAfter(self.as_ptr()); + Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null") } } /// Returns the certificate's Not Before validity period. + #[corresponds(X509_getm_notBefore)] pub fn not_before(&self) -> &Asn1TimeRef { unsafe { - let date = compat::X509_get_notBefore(self.as_ptr()); - assert!(!date.is_null()); - Asn1TimeRef::from_ptr(date) + let date = X509_getm_notBefore(self.as_ptr()); + Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null") } } /// Returns the certificate's signature + #[corresponds(X509_get0_signature)] pub fn signature(&self) -> &Asn1BitStringRef { unsafe { let mut signature = ptr::null(); - compat::X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); - assert!(!signature.is_null()); - Asn1BitStringRef::from_ptr(signature as *mut _) + X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); + Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null") } } /// Returns the certificate's signature algorithm. + #[corresponds(X509_get0_signature)] pub fn signature_algorithm(&self) -> &X509AlgorithmRef { unsafe { let mut algor = ptr::null(); - compat::X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); - assert!(!algor.is_null()); - X509AlgorithmRef::from_ptr(algor as *mut _) + X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); + X509AlgorithmRef::from_const_ptr_opt(algor) + .expect("signature algorithm must not be null") } } /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information /// Access field. + #[corresponds(X509_get1_ocsp)] pub fn ocsp_responders(&self) -> Result, ErrorStack> { unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) } } /// Checks that this certificate issued `subject`. - pub fn issued(&self, subject: &X509Ref) -> Result<(), X509VerifyError> { + #[corresponds(X509_check_issued)] + pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult { unsafe { let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); - match X509VerifyError::from_raw(r as c_long) { - Some(e) => Err(e), - None => Ok(()), - } + X509VerifyResult::from_raw(r) + } + } + + /// Returns certificate version. If this certificate has no explicit version set, it defaults to + /// version 1. + /// + /// Note that `0` return value stands for version 1, `1` for version 2 and so on. + #[corresponds(X509_get_version)] + #[cfg(ossl110)] + pub fn version(&self) -> i32 { + unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } + } + + /// Check if the certificate is signed using the given public key. + /// + /// Only the signature is checked: no other checks (such as certificate chain validity) + /// are performed. + /// + /// Returns `true` if verification succeeds. + #[corresponds(X509_verify)] + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } + + /// Returns this certificate's serial number. + #[corresponds(X509_get_serialNumber)] + pub fn serial_number(&self) -> &Asn1IntegerRef { + unsafe { + let r = ffi::X509_get_serialNumber(self.as_ptr()); + Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null") } } - to_pem!(ffi::PEM_write_bio_X509); - to_der!(ffi::i2d_X509); + to_pem! { + /// Serializes the certificate into a PEM-encoded X509 structure. + /// + /// The output will have a header of `-----BEGIN CERTIFICATE-----`. + #[corresponds(PEM_write_bio_X509)] + to_pem, + ffi::PEM_write_bio_X509 + } + + to_der! { + /// Serializes the certificate into a DER-encoded X509 structure. + #[corresponds(i2d_X509)] + 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 { @@ -568,22 +603,73 @@ impl ToOwned for X509Ref { fn to_owned(&self) -> X509 { unsafe { - compat::X509_up_ref(self.as_ptr()); + X509_up_ref(self.as_ptr()); X509::from_ptr(self.as_ptr()) } } } +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 { + Some(self.cmp(other)) + } +} + +impl PartialOrd for X509Ref { + fn partial_cmp(&self, other: &X509) -> Option { + >::partial_cmp(self, other) + } +} + +impl PartialEq for X509Ref { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == cmp::Ordering::Equal + } +} + +impl PartialEq for X509Ref { + fn eq(&self, other: &X509) -> bool { + >::eq(self, other) + } +} + +impl Eq for X509Ref {} + impl X509 { /// Returns a new builder. pub fn builder() -> Result { X509Builder::new() } - from_pem!(X509, ffi::PEM_read_bio_X509); - from_der!(X509, ffi::d2i_X509); + from_pem! { + /// Deserializes a PEM-encoded X509 structure. + /// + /// The input should have a header of `-----BEGIN CERTIFICATE-----`. + #[corresponds(PEM_read_bio_X509)] + from_pem, + X509, + ffi::PEM_read_bio_X509 + } + + from_der! { + /// Deserializes a DER-encoded X509 structure. + #[corresponds(d2i_X509)] + from_der, + X509, + ffi::d2i_X509 + } /// Deserializes a list of PEM-formatted certificates. + #[corresponds(PEM_read_bio_X509)] pub fn stack_from_pem(pem: &[u8]) -> Result, ErrorStack> { unsafe { ffi::init(); @@ -595,8 +681,8 @@ impl X509 { ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); if r.is_null() { let err = ffi::ERR_peek_last_error(); - if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM && - ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE + if ffi::ERR_GET_LIB(err) as X509LenTy == ffi::ERR_LIB_PEM + && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE { ffi::ERR_clear_error(); break; @@ -619,6 +705,35 @@ impl Clone for X509 { } } +impl fmt::Debug for X509 { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let serial = match &self.serial_number().to_bn() { + Ok(bn) => match bn.to_hex_str() { + Ok(hex) => hex.to_string(), + Err(_) => "".to_string(), + }, + Err(_) => "".to_string(), + }; + let mut debug_struct = formatter.debug_struct("X509"); + debug_struct.field("serial_number", &serial); + debug_struct.field("signature_algorithm", &self.signature_algorithm().object()); + debug_struct.field("issuer", &self.issuer_name()); + debug_struct.field("subject", &self.subject_name()); + if let Some(subject_alt_names) = &self.subject_alt_names() { + debug_struct.field("subject_alt_names", subject_alt_names); + } + debug_struct.field("not_before", &self.not_before()); + debug_struct.field("not_after", &self.not_after()); + + if let Ok(public_key) = &self.public_key() { + debug_struct.field("public_key", public_key); + }; + // TODO: Print extensions once they are supported on the X509 struct. + + debug_struct.finish() + } +} + impl AsRef for X509Ref { fn as_ref(&self) -> &X509Ref { self @@ -629,7 +744,39 @@ impl Stackable for X509 { type StackType = ffi::stack_st_X509; } -/// A context object required to construct certain X509 extension values. +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 { + X509Ref::partial_cmp(self, other) + } +} + +impl PartialOrd for X509 { + fn partial_cmp(&self, other: &X509Ref) -> Option { + X509Ref::partial_cmp(self, other) + } +} + +impl PartialEq for X509 { + fn eq(&self, other: &Self) -> bool { + X509Ref::eq(self, other) + } +} + +impl PartialEq 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)>); impl<'a> X509v3Context<'a> { @@ -638,11 +785,13 @@ impl<'a> X509v3Context<'a> { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_EXTENSION; fn drop = ffi::X509_EXTENSION_free; + /// Permit additional fields to be added to an `X509` v3 certificate. pub struct X509Extension; + /// Reference to `X509Extension`. pub struct X509ExtensionRef; } @@ -660,7 +809,7 @@ impl X509Extension { /// See the extension module for builder types which will construct certain common extensions. pub fn new( conf: Option<&ConfRef>, - context: Option<&X509v3Context>, + context: Option<&X509v3Context<'_>>, name: &str, value: &str, ) -> Result { @@ -686,7 +835,7 @@ impl X509Extension { /// See the extension module for builder types which will construct certain common extensions. pub fn new_nid( conf: Option<&ConfRef>, - context: Option<&X509v3Context>, + context: Option<&X509v3Context<'_>>, name: Nid, value: &str, ) -> Result { @@ -701,11 +850,24 @@ impl X509Extension { 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`. pub struct X509NameBuilder(X509Name); impl X509NameBuilder { + /// Creates a new builder. pub fn new() -> Result { unsafe { ffi::init(); @@ -713,6 +875,26 @@ impl X509NameBuilder { } } + /// Add a name entry + #[corresponds(X509_NAME_add_entry)] + #[cfg(any(ossl101, libressl350))] + pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_NAME_add_entry( + self.0.as_ptr(), + ne.as_ptr(), + -1, + 0, + )) + .map(|_| ()) + } + } + + /// Add a field entry by str. + /// + /// This corresponds to [`X509_NAME_add_entry_by_txt`]. + /// + /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); @@ -725,10 +907,43 @@ impl X509NameBuilder { value.len() as c_int, -1, 0, - )).map(|_| ()) + )) + .map(|_| ()) + } + } + + /// Add a field entry by str with a specific type. + /// + /// This corresponds to [`X509_NAME_add_entry_by_txt`]. + /// + /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html + pub fn append_entry_by_text_with_type( + &mut self, + field: &str, + value: &str, + ty: Asn1Type, + ) -> Result<(), ErrorStack> { + unsafe { + let field = CString::new(field).unwrap(); + assert!(value.len() <= c_int::max_value() as usize); + cvt(ffi::X509_NAME_add_entry_by_txt( + self.0.as_ptr(), + field.as_ptr() as *mut _, + ty.as_raw(), + value.as_ptr(), + value.len() as c_int, + -1, + 0, + )) + .map(|_| ()) } } + /// Add a field entry by NID. + /// + /// This corresponds to [`X509_NAME_add_entry_by_NID`]. + /// + /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { unsafe { assert!(value.len() <= c_int::max_value() as usize); @@ -740,20 +955,50 @@ impl X509NameBuilder { value.len() as c_int, -1, 0, - )).map(|_| ()) + )) + .map(|_| ()) } } - pub fn build(self) -> X509Name { + /// Add a field entry by NID with a specific type. + /// + /// This corresponds to [`X509_NAME_add_entry_by_NID`]. + /// + /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html + pub fn append_entry_by_nid_with_type( + &mut self, + field: Nid, + value: &str, + ty: Asn1Type, + ) -> Result<(), ErrorStack> { + unsafe { + assert!(value.len() <= c_int::max_value() as usize); + cvt(ffi::X509_NAME_add_entry_by_NID( + self.0.as_ptr(), + field.as_raw(), + ty.as_raw(), + value.as_ptr() as *mut _, + value.len() as c_int, + -1, + 0, + )) + .map(|_| ()) + } + } + + /// Return an `X509Name`. + pub fn build(self) -> X509Name { self.0 } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_NAME; fn drop = ffi::X509_NAME_free; + /// The names of an `X509` certificate. pub struct X509Name; + /// Reference to `X509Name`. pub struct X509NameRef; } @@ -770,6 +1015,17 @@ impl X509Name { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) } } + + from_der! { + /// Deserializes a DER-encoded X509 name structure. + /// + /// This corresponds to [`d2i_X509_NAME`]. + /// + /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html + from_der, + X509Name, + ffi::d2i_X509_NAME + } } impl Stackable for X509Name { @@ -777,18 +1033,67 @@ impl Stackable for X509Name { } impl X509NameRef { - pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> { + /// Returns the name entries by the nid. + pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> { + X509NameEntries { + name: self, + nid: Some(nid), + loc: -1, + } + } + + /// Returns an iterator over all `X509NameEntry` values + pub fn entries(&self) -> X509NameEntries<'_> { X509NameEntries { name: self, - nid: nid, + nid: None, loc: -1, } } + + /// 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 { + 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)) + } + + /// Copies the name to a new `X509Name`. + #[corresponds(X509_NAME_dup)] + #[cfg(any(boringssl, ossl110, libressl270))] + pub fn to_owned(&self) -> Result { + unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) } + } + + to_der! { + /// Serializes the certificate into a DER-encoded X509 name structure. + /// + /// This corresponds to [`i2d_X509_NAME`]. + /// + /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html + to_der, + ffi::i2d_X509_NAME + } } +impl fmt::Debug for X509NameRef { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.debug_list().entries(self.entries()).finish() + } +} + +/// A type to destructure and examine an `X509Name`. pub struct X509NameEntries<'a> { name: &'a X509NameRef, - nid: Nid, + nid: Option, loc: c_int, } @@ -797,66 +1102,135 @@ impl<'a> Iterator for X509NameEntries<'a> { fn next(&mut self) -> Option<&'a X509NameEntryRef> { unsafe { - self.loc = - ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), self.nid.as_raw(), self.loc); - - if self.loc == -1 { - return None; + match self.nid { + Some(nid) => { + // There is a `Nid` specified to search for + self.loc = + ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc); + if self.loc == -1 { + return None; + } + } + None => { + // Iterate over all `Nid`s + self.loc += 1; + if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) { + return None; + } + } } let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); - assert!(!entry.is_null()); - Some(X509NameEntryRef::from_ptr(entry)) + Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null")) } } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_NAME_ENTRY; fn drop = ffi::X509_NAME_ENTRY_free; + /// A name entry associated with a `X509Name`. pub struct X509NameEntry; + /// Reference to `X509NameEntry`. pub struct X509NameEntryRef; } impl X509NameEntryRef { + /// Returns the field value of an `X509NameEntry`. + /// + /// This corresponds to [`X509_NAME_ENTRY_get_data`]. + /// + /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_data.html pub fn data(&self) -> &Asn1StringRef { unsafe { let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); Asn1StringRef::from_ptr(data) } } + + /// Returns the `Asn1Object` value of an `X509NameEntry`. + /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. + /// + /// This corresponds to [`X509_NAME_ENTRY_get_object`]. + /// + /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_object.html + pub fn object(&self) -> &Asn1ObjectRef { + unsafe { + let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); + Asn1ObjectRef::from_ptr(object) + } + } } +impl fmt::Debug for X509NameEntryRef { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data())) + } +} + +/// A builder used to construct an `X509Req`. pub struct X509ReqBuilder(X509Req); impl X509ReqBuilder { + /// Returns a builder for a certificate request. + /// + /// This corresponds to [`X509_REQ_new`]. + /// + ///[`X509_REQ_new`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_new.html pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) } - } + /// Set the numerical value of the version field. + /// + /// This corresponds to [`X509_REQ_set_version`]. + /// + ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_version.html + #[allow(clippy::useless_conversion)] 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. + /// + /// This corresponds to [`X509_REQ_set_subject_name`]. + /// + /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_subject_name.html pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_subject_name( self.0.as_ptr(), subject_name.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } - pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { + /// Set the public key. + /// + /// This corresponds to [`X509_REQ_set_pubkey`]. + /// + /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_pubkey.html + pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + T: HasPublic, + { unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } } + /// Return an `X509v3Context`. This context object can be used to construct + /// certain `X509` extensions. pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> { unsafe { let mut ctx = mem::zeroed(); @@ -879,6 +1253,7 @@ impl X509ReqBuilder { } } + /// Permits any number of extension fields to be added to the certificate. pub fn add_extensions( &mut self, extensions: &StackRef, @@ -887,246 +1262,575 @@ impl X509ReqBuilder { cvt(ffi::X509_REQ_add_extensions( self.0.as_ptr(), extensions.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } - pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> { + /// Sign the request using a private key. + /// + /// This corresponds to [`X509_REQ_sign`]. + /// + /// [`X509_REQ_sign`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_sign.html + pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> + where + T: HasPrivate, + { unsafe { cvt(ffi::X509_REQ_sign( self.0.as_ptr(), key.as_ptr(), hash.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } + /// Returns the `X509Req`. pub fn build(self) -> X509Req { self.0 } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_REQ; fn drop = ffi::X509_REQ_free; + /// An `X509` certificate request. pub struct X509Req; + /// Reference to `X509Req`. pub struct X509ReqRef; } impl X509Req { + /// A builder for `X509Req`. pub fn builder() -> Result { X509ReqBuilder::new() } - /// Reads CSR from PEM - pub fn from_pem(buf: &[u8]) -> Result { - let mem_bio = MemBioSlice::new(buf)?; - unsafe { - let handle = cvt_p(ffi::PEM_read_bio_X509_REQ( - mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut(), - ))?; - Ok(X509Req::from_ptr(handle)) - } + from_pem! { + /// Deserializes a PEM-encoded PKCS#10 certificate request structure. + /// + /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. + /// + /// This corresponds to [`PEM_read_bio_X509_REQ`]. + /// + /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_read_bio_X509_REQ.html + from_pem, + X509Req, + ffi::PEM_read_bio_X509_REQ + } + + from_der! { + /// Deserializes a DER-encoded PKCS#10 certificate request structure. + /// + /// This corresponds to [`d2i_X509_REQ`]. + /// + /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/d2i_X509_REQ.html + from_der, + X509Req, + ffi::d2i_X509_REQ } - - from_der!(X509Req, ffi::d2i_X509_REQ); } impl X509ReqRef { - to_pem!(ffi::PEM_write_bio_X509_REQ); - to_der!(ffi::i2d_X509_REQ); - + to_pem! { + /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. + /// + /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. + /// + /// This corresponds to [`PEM_write_bio_X509_REQ`]. + /// + /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_write_bio_X509_REQ.html + to_pem, + ffi::PEM_write_bio_X509_REQ + } + + to_der! { + /// Serializes the certificate request to a DER-encoded PKCS#10 structure. + /// + /// This corresponds to [`i2d_X509_REQ`]. + /// + /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_REQ.html + to_der, + 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`] + /// + /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html pub fn version(&self) -> i32 { - unsafe { compat::X509_REQ_get_version(self.as_ptr()) as i32 } + unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } + /// Returns the subject name of the certificate request. + /// + /// This corresponds to [`X509_REQ_get_subject_name`] + /// + /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_subject_name.html pub fn subject_name(&self) -> &X509NameRef { unsafe { - let name = compat::X509_REQ_get_subject_name(self.as_ptr()); - assert!(!name.is_null()); - X509NameRef::from_ptr(name) + let name = X509_REQ_get_subject_name(self.as_ptr()); + X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") + } + } + + /// Returns the public key of the certificate request. + /// + /// This corresponds to [`X509_REQ_get_pubkey"] + /// + /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_pubkey.html + pub fn public_key(&self) -> Result, ErrorStack> { + unsafe { + let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; + Ok(PKey::from_ptr(key)) + } + } + + /// Check if the certificate request is signed using the given public key. + /// + /// Returns `true` if verification succeeds. + /// + /// This corresponds to [`X509_REQ_verify"]. + /// + /// [`X509_REQ_verify`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_verify.html + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } + + /// Returns the extensions of the certificate request. + /// + /// This corresponds to [`X509_REQ_get_extensions"] + pub fn extensions(&self) -> Result, ErrorStack> { + unsafe { + let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?; + Ok(Stack::from_ptr(extensions)) } } } -/// A collection of X.509 extensions. -/// -/// Upholds the invariant that a certificate MUST NOT include more than one -/// instance of a particular extension, according to RFC 3280 §4.2. Also -/// ensures that extensions are added to the certificate during signing -/// in the order they were inserted, which is required for certain -/// extensions like SubjectKeyIdentifier and AuthorityKeyIdentifier. -struct Extensions { - /// The extensions contained in the collection. - extensions: Vec, - /// A map of used to keep track of added extensions and their indexes in `self.extensions`. - indexes: HashMap, +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_REVOKED; + fn drop = ffi::X509_REVOKED_free; + + /// An `X509` certificate request. + pub struct X509Revoked; + /// Reference to `X509Crl`. + pub struct X509RevokedRef; } -impl Extensions { - /// Creates a new `Extensions`. - pub fn new() -> Extensions { - Extensions { - extensions: vec![], - indexes: HashMap::new(), - } +impl Stackable for X509Revoked { + type StackType = ffi::stack_st_X509_REVOKED; +} + +impl X509Revoked { + from_der! { + /// Deserializes a DER-encoded certificate revocation status + #[corresponds(d2i_X509_REVOKED)] + from_der, + X509Revoked, + ffi::d2i_X509_REVOKED } +} - /// Adds a new `Extension`, replacing any existing one of the same - /// `ExtensionType`. - pub fn add(&mut self, ext: Extension) { - let ext_type = ext.get_type(); +impl X509RevokedRef { + to_der! { + /// Serializes the certificate request to a DER-encoded certificate revocation status + #[corresponds(d2i_X509_REVOKED)] + to_der, + ffi::i2d_X509_REVOKED + } - if let Some(index) = self.indexes.get(&ext_type) { - self.extensions[*index] = ext; - return; + /// Get the date that the certificate was revoked + #[corresponds(X509_REVOKED_get0_revocationDate)] + pub fn revocation_date(&self) -> &Asn1TimeRef { + unsafe { + let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _); + assert!(!r.is_null()); + Asn1TimeRef::from_ptr(r as *mut _) } + } - self.extensions.push(ext); - self.indexes.insert(ext_type, self.extensions.len() - 1); + /// Get the serial number of the revoked certificate + #[corresponds(X509_REVOKED_get0_serialNumber)] + pub fn serial_number(&self) -> &Asn1IntegerRef { + unsafe { + let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _); + assert!(!r.is_null()); + Asn1IntegerRef::from_ptr(r as *mut _) + } } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_CRL; + fn drop = ffi::X509_CRL_free; + + /// An `X509` certificate request. + pub struct X509Crl; + /// Reference to `X509Crl`. + pub struct X509CrlRef; +} + +/// The status of a certificate in a revoction list +/// +/// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods. +/// +/// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html +pub enum CrlStatus<'a> { + /// The certificate is not present in the list + NotRevoked, + /// The certificate is in the list and is revoked + Revoked(&'a X509RevokedRef), + /// The certificate is in the list, but has the "removeFromCrl" status. + /// + /// This can occur if the certificate was revoked with the "CertificateHold" + /// reason, and has since been unrevoked. + RemoveFromCrl(&'a X509RevokedRef), +} - /// Returns an `ExtensionsIter` for the collection. - pub fn iter(&self) -> ExtensionsIter { - ExtensionsIter { - current: 0, - extensions: &self.extensions, +impl<'a> CrlStatus<'a> { + // Helper used by the X509_CRL_get0_by_* methods to convert their return + // value to the status enum. + // Safety note: the returned CrlStatus must not outlive the owner of the + // revoked_entry pointer. + unsafe fn from_ffi_status( + status: c_int, + revoked_entry: *mut ffi::X509_REVOKED, + ) -> CrlStatus<'a> { + match status { + 0 => CrlStatus::NotRevoked, + 1 => { + assert!(!revoked_entry.is_null()); + CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry)) + } + 2 => { + assert!(!revoked_entry.is_null()); + CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry)) + } + _ => unreachable!( + "{}", + "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2." + ), } } } -/// An iterator that iterates over `(ExtensionType, Extension)` for each -/// extension in the collection. -struct ExtensionsIter<'a> { - current: usize, - extensions: &'a Vec, +impl X509Crl { + from_pem! { + /// Deserializes a PEM-encoded Certificate Revocation List + /// + /// The input should have a header of `-----BEGIN X509 CRL-----`. + #[corresponds(PEM_read_bio_X509_CRL)] + from_pem, + X509Crl, + ffi::PEM_read_bio_X509_CRL + } + + from_der! { + /// Deserializes a DER-encoded Certificate Revocation List + #[corresponds(d2i_X509_CRL)] + from_der, + X509Crl, + ffi::d2i_X509_CRL + } } -impl<'a> Iterator for ExtensionsIter<'a> { - type Item = (ExtensionType, &'a Extension); +impl X509CrlRef { + to_pem! { + /// Serializes the certificate request to a PEM-encoded Certificate Revocation List. + /// + /// The output will have a header of `-----BEGIN X509 CRL-----`. + #[corresponds(PEM_write_bio_X509_CRL)] + to_pem, + ffi::PEM_write_bio_X509_CRL + } - fn next(&mut self) -> Option { - if self.current < self.extensions.len() { - let ext = &self.extensions[self.current]; + to_der! { + /// Serializes the certificate request to a DER-encoded Certificate Revocation List. + #[corresponds(i2d_X509_CRL)] + to_der, + ffi::i2d_X509_CRL + } - self.current += 1; + /// Get the stack of revocation entries + pub fn get_revoked(&self) -> Option<&StackRef> { + unsafe { + let revoked = X509_CRL_get_REVOKED(self.as_ptr()); + if revoked.is_null() { + None + } else { + Some(StackRef::from_ptr(revoked)) + } + } + } - Some((ext.get_type(), ext)) - } else { - None + /// Returns the CRL's `lastUpdate` time. + #[corresponds(X509_CRL_get0_lastUpdate)] + pub fn last_update(&self) -> &Asn1TimeRef { + unsafe { + let date = X509_CRL_get0_lastUpdate(self.as_ptr()); + assert!(!date.is_null()); + Asn1TimeRef::from_ptr(date as *mut _) + } + } + + /// Returns the CRL's `nextUpdate` time. + /// + /// If the `nextUpdate` field is missing, returns `None`. + #[corresponds(X509_CRL_get0_nextUpdate)] + pub fn next_update(&self) -> Option<&Asn1TimeRef> { + unsafe { + let date = X509_CRL_get0_nextUpdate(self.as_ptr()); + Asn1TimeRef::from_const_ptr_opt(date) } } + + /// Get the revocation status of a certificate by its serial number + #[corresponds(X509_CRL_get0_by_serial)] + pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> { + unsafe { + let mut ret = ptr::null_mut::(); + let status = + ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr()); + CrlStatus::from_ffi_status(status, ret) + } + } + + /// Get the revocation status of a certificate + #[corresponds(X509_CRL_get0_by_cert)] + pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> { + unsafe { + let mut ret = ptr::null_mut::(); + let status = + ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr()); + CrlStatus::from_ffi_status(status, ret) + } + } + + /// Get the issuer name from the revocation list. + #[corresponds(X509_CRL_get_issuer)] + pub fn issuer_name(&self) -> &X509NameRef { + unsafe { + let name = X509_CRL_get_issuer(self.as_ptr()); + assert!(!name.is_null()); + X509NameRef::from_ptr(name) + } + } + + /// Check if the CRL is signed using the given public key. + /// + /// Only the signature is checked: no other checks (such as certificate chain validity) + /// are performed. + /// + /// Returns `true` if verification succeeds. + #[corresponds(X509_CRL_verify)] + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } } -pub struct X509VerifyError(c_long); +/// The result of peer certificate verification. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct X509VerifyResult(c_int); -impl fmt::Debug for X509VerifyError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("X509VerifyError") +impl fmt::Debug for X509VerifyResult { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("X509VerifyResult") .field("code", &self.0) .field("error", &self.error_string()) .finish() } } -impl fmt::Display for X509VerifyError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Display for X509VerifyResult { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str(self.error_string()) } } -impl Error for X509VerifyError { - fn description(&self) -> &str { - "an X509 validation error" - } -} +impl Error for X509VerifyResult {} -impl X509VerifyError { - /// Creates an `X509VerifyError` from a raw error number. - /// - /// `None` will be returned if `err` is `X509_V_OK`. +impl X509VerifyResult { + /// Creates an `X509VerifyResult` from a raw error number. /// /// # Safety /// - /// Some methods on `X509VerifyError` are not thread safe if the error + /// Some methods on `X509VerifyResult` are not thread safe if the error /// number is invalid. - pub unsafe fn from_raw(err: c_long) -> Option { - if err == ffi::X509_V_OK as c_long { - None - } else { - Some(X509VerifyError(err)) - } + pub unsafe fn from_raw(err: c_int) -> X509VerifyResult { + X509VerifyResult(err) } - pub fn as_raw(&self) -> c_long { + /// Return the integer representation of an `X509VerifyResult`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> c_int { self.0 } + /// Return a human readable error string from the verification error. + /// + /// This corresponds to [`X509_verify_cert_error_string`]. + /// + /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/manmaster/crypto/X509_verify_cert_error_string.html + #[allow(clippy::trivially_copy_pass_by_ref)] pub fn error_string(&self) -> &'static str { ffi::init(); unsafe { - let s = ffi::X509_verify_cert_error_string(self.0); + let s = ffi::X509_verify_cert_error_string(self.0 as c_long); str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() } } + + /// Successful peer certificate verification. + pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK); + /// Application verification failure. + pub const APPLICATION_VERIFICATION: X509VerifyResult = + X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION); } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::GENERAL_NAME; fn drop = ffi::GENERAL_NAME_free; + /// An `X509` certificate alternative names. pub struct GeneralName; + /// Reference to `GeneralName`. pub struct GeneralNameRef; } impl GeneralNameRef { - /// Returns the contents of this `GeneralName` if it is a `dNSName`. - pub fn dnsname(&self) -> Option<&str> { + fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { unsafe { - if (*self.as_ptr()).type_ != ffi::GEN_DNS { + if (*self.as_ptr()).type_ != ffi_type { return None; } - let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _); - let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); + #[cfg(boringssl)] + let d = (*self.as_ptr()).d.ptr; + #[cfg(not(boringssl))] + let d = (*self.as_ptr()).d; + + let ptr = ASN1_STRING_get0_data(d as *mut _); + let len = ffi::ASN1_STRING_length(d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); - // dNSNames are stated to be ASCII (specifically IA5). Hopefully + // IA5Strings are stated to be ASCII (specifically IA5). Hopefully // OpenSSL checks that when loading a certificate but if not we'll // use this instead of from_utf8_unchecked just in case. str::from_utf8(slice).ok() } } + /// Returns the contents of this `GeneralName` if it is an `rfc822Name`. + pub fn email(&self) -> Option<&str> { + self.ia5_string(ffi::GEN_EMAIL) + } + + /// Returns the contents of this `GeneralName` if it is a `dNSName`. + pub fn dnsname(&self) -> Option<&str> { + self.ia5_string(ffi::GEN_DNS) + } + + /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`. + pub fn uri(&self) -> Option<&str> { + self.ia5_string(ffi::GEN_URI) + } + /// Returns the contents of this `GeneralName` if it is an `iPAddress`. pub fn ipaddress(&self) -> Option<&[u8]> { unsafe { if (*self.as_ptr()).type_ != ffi::GEN_IPADD { return None; } + #[cfg(boringssl)] + let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d); + #[cfg(not(boringssl))] + let d = (*self.as_ptr()).d; - let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _); - let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); + let ptr = ASN1_STRING_get0_data(d as *mut _); + let len = ffi::ASN1_STRING_length(d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) } } } +impl fmt::Debug for GeneralNameRef { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(email) = self.email() { + formatter.write_str(email) + } else if let Some(dnsname) = self.dnsname() { + formatter.write_str(dnsname) + } else if let Some(uri) = self.uri() { + formatter.write_str(uri) + } else if let Some(ipaddress) = self.ipaddress() { + let address = <[u8; 16]>::try_from(ipaddress) + .map(IpAddr::from) + .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from)); + match address { + Ok(a) => fmt::Debug::fmt(&a, formatter), + Err(_) => fmt::Debug::fmt(ipaddress, formatter), + } + } else { + formatter.write_str("(empty)") + } + } +} + impl Stackable for GeneralName { type StackType = ffi::stack_st_GENERAL_NAME; } -foreign_type! { +foreign_type_and_impl_send_sync! { + type CType = ffi::ACCESS_DESCRIPTION; + fn drop = ffi::ACCESS_DESCRIPTION_free; + + /// `AccessDescription` of certificate authority information. + pub struct AccessDescription; + /// Reference to `AccessDescription`. + pub struct AccessDescriptionRef; +} + +impl AccessDescriptionRef { + /// Returns the access method OID. + pub fn method(&self) -> &Asn1ObjectRef { + unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) } + } + + // Returns the access location. + pub fn location(&self) -> &GeneralNameRef { + unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) } + } +} + +impl Stackable for AccessDescription { + type StackType = ffi::stack_st_ACCESS_DESCRIPTION; +} + +foreign_type_and_impl_send_sync! { type CType = ffi::X509_ALGOR; fn drop = ffi::X509_ALGOR_free; + /// An `X509` certificate signature algorithm. pub struct X509Algorithm; + /// Reference to `X509Algorithm`. pub struct X509AlgorithmRef; } @@ -1135,91 +1839,264 @@ impl X509AlgorithmRef { pub fn object(&self) -> &Asn1ObjectRef { unsafe { let mut oid = ptr::null(); - compat::X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); - assert!(!oid.is_null()); - Asn1ObjectRef::from_ptr(oid as *mut _) + X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); + Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null") } } } -#[cfg(ossl110)] -mod compat { - pub use ffi::X509_getm_notAfter as X509_get_notAfter; - pub use ffi::X509_getm_notBefore as X509_get_notBefore; - pub use ffi::X509_up_ref; - pub use ffi::X509_get0_extensions; - pub use ffi::X509_REQ_get_version; - pub use ffi::X509_REQ_get_subject_name; - pub use ffi::X509_get0_signature; - pub use ffi::X509_ALGOR_get0; +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_OBJECT; + fn drop = X509_OBJECT_free; + + /// An `X509` or an X509 certificate revocation list. + pub struct X509Object; + /// Reference to `X509Object` + pub struct X509ObjectRef; } -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use libc::{c_int, c_void}; - use ffi; +impl X509ObjectRef { + pub fn x509(&self) -> Option<&X509Ref> { + unsafe { + let ptr = X509_OBJECT_get0_X509(self.as_ptr()); + X509Ref::from_const_ptr_opt(ptr) + } + } +} + +impl Stackable for X509Object { + type StackType = ffi::stack_st_X509_OBJECT; +} + +cfg_if! { + if #[cfg(any(boringssl, ossl110, libressl273))] { + use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}; + } else { + #[allow(bad_style)] + unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notAfter + } + + #[allow(bad_style)] + unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notBefore + } - pub unsafe fn X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { - (*(*(*x).cert_info).validity).notAfter + #[allow(bad_style)] + unsafe fn X509_up_ref(x: *mut ffi::X509) { + ffi::CRYPTO_add_lock( + &mut (*x).references, + 1, + ffi::CRYPTO_LOCK_X509, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + } + + #[allow(bad_style)] + unsafe fn X509_get0_signature( + psig: *mut *const ffi::ASN1_BIT_STRING, + palg: *mut *const ffi::X509_ALGOR, + x: *const ffi::X509, + ) { + if !psig.is_null() { + *psig = (*x).signature; + } + if !palg.is_null() { + *palg = (*x).sig_alg; + } + } } +} + +cfg_if! { + 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, + }; + } else { + use ffi::{ + ASN1_STRING_data as ASN1_STRING_get0_data, + X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, + X509_set_notAfter as X509_set1_notAfter, + X509_set_notBefore as X509_set1_notBefore, + }; + + #[allow(bad_style)] + unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { + ffi::ASN1_INTEGER_get((*(*x).req_info).version) + } - pub unsafe fn X509_get_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { - (*(*(*x).cert_info).validity).notBefore + #[allow(bad_style)] + unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { + (*(*x).req_info).subject + } + + #[allow(bad_style)] + unsafe fn X509_ALGOR_get0( + paobj: *mut *const ffi::ASN1_OBJECT, + pptype: *mut c_int, + pval: *mut *mut ::libc::c_void, + alg: *const ffi::X509_ALGOR, + ) { + if !paobj.is_null() { + *paobj = (*alg).algorithm; + } + assert!(pptype.is_null()); + assert!(pval.is_null()); + } } +} - pub unsafe fn X509_up_ref(x: *mut ffi::X509) { - ffi::CRYPTO_add_lock( - &mut (*x).references, - 1, - ffi::CRYPTO_LOCK_X509, - "mod.rs\0".as_ptr() as *const _, - line!() as c_int, - ); +cfg_if! { + if #[cfg(any(ossl110, boringssl, libressl270))] { + use ffi::X509_OBJECT_get0_X509; + } else { + #[allow(bad_style)] + unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 { + if (*x).type_ == ffi::X509_LU_X509 { + (*x).data.x509 + } else { + ptr::null_mut() + } + } } +} - pub unsafe fn X509_get0_extensions( - cert: *const ffi::X509, - ) -> *const ffi::stack_st_X509_EXTENSION { - let info = (*cert).cert_info; - if info.is_null() { - 0 as *mut _ - } else { - (*info).extensions +cfg_if! { + if #[cfg(any(ossl110, libressl350))] { + use ffi::X509_OBJECT_free; + } else if #[cfg(boringssl)] { + use ffi::X509_OBJECT_free_contents as X509_OBJECT_free; + } else { + #[allow(bad_style)] + unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) { + ffi::X509_OBJECT_free_contents(x); + ffi::CRYPTO_free(x as *mut libc::c_void); + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl350, boringssl))] { + use ffi::{ + X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate, + X509_CRL_get_REVOKED, + X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber, + }; + } else { + #[allow(bad_style)] + unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { + (*(*x).crl).lastUpdate + } + #[allow(bad_style)] + unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { + (*(*x).crl).nextUpdate + } + #[allow(bad_style)] + unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME { + (*(*x).crl).issuer + } + #[allow(bad_style)] + unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED { + (*(*x).crl).revoked + } + #[allow(bad_style)] + unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER { + (*x).serialNumber + } + #[allow(bad_style)] + unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME { + (*x).revocationDate } } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct X509PurposeId(c_int); - pub unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { - ::ffi::ASN1_INTEGER_get((*(*x).req_info).version) +impl X509PurposeId { + pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT); + pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER); + pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER); + pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN); + pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT); + pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN); + pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY); + pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER); + pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN); + + /// Constructs an `X509PurposeId` from a raw OpenSSL value. + pub fn from_raw(id: c_int) -> Self { + X509PurposeId(id) } - pub unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { - (*(*x).req_info).subject + /// Returns the raw OpenSSL value represented by this type. + pub fn as_raw(&self) -> c_int { + self.0 } +} + +/// A reference to an [`X509_PURPOSE`]. +pub struct X509PurposeRef(Opaque); + +/// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL. +impl ForeignTypeRef for X509PurposeRef { + type CType = ffi::X509_PURPOSE; +} - pub unsafe fn X509_get0_signature( - psig: *mut *const ffi::ASN1_BIT_STRING, - palg: *mut *const ffi::X509_ALGOR, - x: *const ffi::X509, - ) { - if !psig.is_null() { - *psig = (*x).signature; +impl X509PurposeRef { + /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short + /// names include + /// - "sslclient", + /// - "sslserver", + /// - "nssslserver", + /// - "smimesign", + /// - "smimeencrypt", + /// - "crlsign", + /// - "any", + /// - "ocsphelper", + /// - "timestampsign" + /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose. + #[allow(clippy::unnecessary_cast)] + pub fn get_by_sname(sname: &str) -> Result { + unsafe { + let sname = CString::new(sname).unwrap(); + cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?; + } else { + let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?; + } + } + Ok(purpose) } - if !palg.is_null() { - *palg = (*x).sig_alg; + } + /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g. + /// `X509PurposeRef::get_by_sname()`. + #[corresponds(X509_PURPOSE_get0)] + pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> { + unsafe { + let ptr = cvt_p(ffi::X509_PURPOSE_get0(idx))?; + Ok(X509PurposeRef::from_ptr(ptr)) } } - pub unsafe fn X509_ALGOR_get0( - paobj: *mut *const ffi::ASN1_OBJECT, - pptype: *mut c_int, - pval: *mut *mut c_void, - alg: *const ffi::X509_ALGOR, - ) { - if !paobj.is_null() { - *paobj = (*alg).algorithm; + /// Get the purpose value from an X509Purpose structure. This value is one of + /// - `X509_PURPOSE_SSL_CLIENT` + /// - `X509_PURPOSE_SSL_SERVER` + /// - `X509_PURPOSE_NS_SSL_SERVER` + /// - `X509_PURPOSE_SMIME_SIGN` + /// - `X509_PURPOSE_SMIME_ENCRYPT` + /// - `X509_PURPOSE_CRL_SIGN` + /// - `X509_PURPOSE_ANY` + /// - `X509_PURPOSE_OCSP_HELPER` + /// - `X509_PURPOSE_TIMESTAMP_SIGN` + pub fn purpose(&self) -> X509PurposeId { + unsafe { + let x509_purpose: *mut ffi::X509_PURPOSE = self.as_ptr(); + X509PurposeId::from_raw((*x509_purpose).purpose) } - assert!(pptype.is_null()); - assert!(pval.is_null()); } } diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index 198679b..a90bf35 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -1,16 +1,71 @@ -use ffi; +//! Describe a context in which to verify an `X509` certificate. +//! +//! The `X509` certificate store holds trusted CA certificates used to verify +//! peer certificates. +//! +//! # Example +//! +//! ```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; +//! use openssl::nid::Nid; +//! +//! let rsa = Rsa::generate(2048).unwrap(); +//! let pkey = PKey::from_rsa(rsa).unwrap(); +//! +//! let mut name = X509Name::builder().unwrap(); +//! 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(); +//! +//! let mut builder = X509StoreBuilder::new().unwrap(); +//! let _ = builder.add_cert(certificate); +//! +//! let store: X509Store = builder.build(); +//! ``` + +use cfg_if::cfg_if; use foreign_types::ForeignTypeRef; use std::mem; -use {cvt, cvt_p}; -use error::ErrorStack; -use x509::X509; +use crate::error::ErrorStack; +#[cfg(not(boringssl))] +use crate::ssl::SslFiletype; +use crate::stack::StackRef; +#[cfg(any(ossl102, libressl261))] +use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef}; +use crate::x509::{X509Object, X509PurposeId, X509}; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; +#[cfg(not(boringssl))] +use std::ffi::CString; +#[cfg(not(boringssl))] +use std::path::Path; -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; + /// A builder type used to construct an `X509Store`. pub struct X509StoreBuilder; + /// A reference to an [`X509StoreBuilder`]. pub struct X509StoreBuilderRef; } @@ -18,6 +73,7 @@ impl X509StoreBuilder { /// Returns a builder for a certificate store. /// /// The store is initially empty. + #[corresponds(X509_STORE_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -36,12 +92,10 @@ impl X509StoreBuilder { impl X509StoreBuilderRef { /// Adds a certificate to the certificate store. + // FIXME should take an &X509Ref + #[corresponds(X509_STORE_add_cert)] pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { - unsafe { - let ptr = cert.as_ptr(); - mem::forget(cert); // the cert will be freed inside of X509_STORE_add_cert on error - cvt(ffi::X509_STORE_add_cert(self.as_ptr(), ptr)).map(|_| ()) - } + unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } /// Load certificates from their default locations. @@ -49,15 +103,185 @@ impl X509StoreBuilderRef { /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` /// environment variables if present, or defaults specified at OpenSSL /// build time otherwise. + #[corresponds(X509_STORE_set_default_paths)] pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) } } + + /// Adds a lookup method to the store. + #[corresponds(X509_STORE_add_lookup)] + pub fn add_lookup( + &mut self, + method: &'static X509LookupMethodRef, + ) -> Result<&mut X509LookupRef, ErrorStack> { + let lookup = unsafe { ffi::X509_STORE_add_lookup(self.as_ptr(), method.as_ptr()) }; + cvt_p(lookup).map(|ptr| unsafe { X509LookupRef::from_ptr_mut(ptr) }) + } + + /// Sets certificate chain validation related flags. + #[corresponds(X509_STORE_set_flags)] + #[cfg(any(ossl102, libressl261))] + pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) } + } + + /// Sets the certificate purpose. + /// The purpose value can be obtained by `X509PurposeRef::get_by_sname()` + #[corresponds(X509_STORE_set_purpose)] + pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_STORE_set_purpose(self.as_ptr(), purpose.as_raw())).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(|_| ()) } + } } -foreign_type! { +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::X509_LOOKUP; + fn drop = ffi::X509_LOOKUP_free; + + /// Information used by an `X509Store` to look up certificates and CRLs. + pub struct X509Lookup; + /// A reference to an [`X509Lookup`]. + pub struct X509LookupRef; +} + +/// Marker type corresponding to the [`X509_LOOKUP_hash_dir`] lookup method. +/// +/// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/manmaster/crypto/X509_LOOKUP_hash_dir.html +// FIXME should be an enum +pub struct HashDir; + +impl X509Lookup { + /// Lookup method that loads certificates and CRLs on demand and caches + /// them in memory once they are loaded. It also checks for newer CRLs upon + /// each lookup, so that newer CRLs are used as soon as they appear in the + /// directory. + #[corresponds(X509_LOOKUP_hash_dir)] + pub fn hash_dir() -> &'static X509LookupMethodRef { + unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_hash_dir()) } + } +} + +#[cfg(not(boringssl))] +impl X509LookupRef { + /// Specifies a directory from which certificates and CRLs will be loaded + /// on-demand. Must be used with `X509Lookup::hash_dir`. + #[corresponds(X509_LOOKUP_add_dir)] + pub fn add_dir(&mut self, name: &str, file_type: SslFiletype) -> Result<(), ErrorStack> { + let name = CString::new(name).unwrap(); + unsafe { + cvt(ffi::X509_LOOKUP_add_dir( + self.as_ptr(), + name.as_ptr(), + file_type.as_raw(), + )) + .map(|_| ()) + } + } +} + +/// Marker type corresponding to the [`X509_LOOKUP_file`] lookup method. +/// +/// [`X509_LOOKUP_file`]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_file.html +pub struct File; + +impl X509Lookup { + /// Lookup method loads all the certificates or CRLs present in a file + /// into memory at the time the file is added as a lookup source. + #[corresponds(X509_LOOKUP_file)] + pub fn file() -> &'static X509LookupMethodRef { + unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_file()) } + } +} + +#[cfg(not(boringssl))] +impl X509LookupRef { + /// Specifies a file from which certificates will be loaded + #[corresponds(X509_load_cert_file)] + // FIXME should return 'Result>( + &mut self, + file: P, + file_type: SslFiletype, + ) -> Result<(), ErrorStack> { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt(ffi::X509_load_cert_file( + self.as_ptr(), + file.as_ptr(), + file_type.as_raw(), + )) + .map(|_| ()) + } + } + + /// Specifies a file from which certificate revocation lists will be loaded + #[corresponds(X509_load_crl_file)] + pub fn load_crl_file>( + &mut self, + file: P, + file_type: SslFiletype, + ) -> Result { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt(ffi::X509_load_crl_file( + self.as_ptr(), + file.as_ptr(), + file_type.as_raw(), + )) + } + } +} + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::X509_LOOKUP_METHOD; + fn drop = X509_LOOKUP_meth_free; + + /// Method used to look up certificates and CRLs. + pub struct X509LookupMethod; + /// A reference to an [`X509LookupMethod`]. + pub struct X509LookupMethodRef; +} + +foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; + /// A certificate store to hold trusted `X509` certificates. pub struct X509Store; + /// Reference to an `X509Store`. pub struct X509StoreRef; } + +impl X509StoreRef { + /// Get a reference to the cache of certificates in this store. + #[corresponds(X509_STORE_get0_objects)] + pub fn objects(&self) -> &StackRef { + unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) } + } +} + +cfg_if! { + if #[cfg(any(boringssl, ossl110, libressl270))] { + use ffi::X509_STORE_get0_objects; + } else { + #[allow(bad_style)] + unsafe fn X509_STORE_get0_objects(x: *mut ffi::X509_STORE) -> *mut ffi::stack_st_X509_OBJECT { + (*x).objs + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::X509_LOOKUP_meth_free; + } else { + #[allow(bad_style)] + unsafe fn X509_LOOKUP_meth_free(_x: *mut ffi::X509_LOOKUP_METHOD) {} + } +} diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 76eeba3..5c563a2 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,139 +1,73 @@ -use hex::{FromHex, ToHex}; - -use asn1::Asn1Time; -use bn::{BigNum, MSB_MAYBE_ZERO}; -use ec::{NAMED_CURVE, EcGroup, EcKey}; -use hash::MessageDigest; -use nid::X9_62_PRIME256V1; -use pkey::PKey; -use rsa::Rsa; -use stack::Stack; -use x509::{X509, X509Generator, X509Name, X509Req}; -use x509::extension::{Extension, BasicConstraints, KeyUsage, ExtendedKeyUsage, - SubjectKeyIdentifier, AuthorityKeyIdentifier, SubjectAlternativeName}; -use ssl::{SslMethod, SslContextBuilder}; -use x509::extension::AltNameOption as SAN; -use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment}; -use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth}; -use nid; - -fn get_generator() -> X509Generator { - X509Generator::new() - .set_valid_period(365 * 2) - .add_name("CN".to_string(), "test_me".to_string()) - .set_sign_hash(MessageDigest::sha1()) - .add_extension(Extension::KeyUsage(vec![DigitalSignature, KeyEncipherment])) - .add_extension(Extension::ExtKeyUsage(vec![ - ClientAuth, - ServerAuth, - ExtKeyUsageOption::Other("2.999.1".to_owned()), - ])) - .add_extension(Extension::SubjectAltName( - vec![(SAN::DNS, "example.com".to_owned())], - )) - .add_extension(Extension::OtherNid( - nid::BASIC_CONSTRAINTS, - "critical,CA:TRUE".to_owned(), - )) - .add_extension(Extension::OtherStr( - "2.999.2".to_owned(), - "ASN1:UTF8:example value".to_owned(), - )) -} - -fn pkey() -> PKey { +use std::cmp::Ordering; + +use crate::asn1::Asn1Time; +use crate::bn::{BigNum, MsbOption}; +use crate::hash::MessageDigest; +use crate::nid::Nid; +use crate::pkey::{PKey, Private}; +use crate::rsa::Rsa; +#[cfg(not(boringssl))] +use crate::ssl::SslFiletype; +use crate::stack::Stack; +use crate::x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; +#[cfg(not(boringssl))] +use crate::x509::store::X509Lookup; +use crate::x509::store::X509StoreBuilder; +#[cfg(any(ossl102, libressl261))] +use crate::x509::verify::{X509VerifyFlags, X509VerifyParam}; +#[cfg(ossl110)] +use crate::x509::X509Builder; +#[cfg(ossl102)] +use crate::x509::X509PurposeId; +#[cfg(any(ossl102, libressl261))] +use crate::x509::X509PurposeRef; +use crate::x509::{ + CrlStatus, X509Crl, X509Name, X509Req, X509StoreContext, X509VerifyResult, X509, +}; +use hex::{self, FromHex}; +#[cfg(any(ossl102, libressl261))] +use libc::time_t; + +fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); PKey::from_rsa(rsa).unwrap() } -#[test] -fn test_cert_gen() { - let pkey = pkey(); - let cert = get_generator().sign(&pkey).unwrap(); - - // FIXME: check data in result to be correct, needs implementation - // of X509 getters - - assert_eq!( - pkey.public_key_to_pem().unwrap(), - cert.public_key().unwrap().public_key_to_pem().unwrap() - ); -} - -/// SubjectKeyIdentifier must be added before AuthorityKeyIdentifier or OpenSSL -/// is "unable to get issuer keyid." This test ensures the order of insertion -/// for extensions is preserved when the cert is signed. -#[test] -fn test_cert_gen_extension_ordering() { - let pkey = pkey(); - get_generator() - .add_extension(Extension::OtherNid( - nid::SUBJECT_KEY_IDENTIFIER, - "hash".to_owned(), - )) - .add_extension(Extension::OtherNid( - nid::AUTHORITY_KEY_IDENTIFIER, - "keyid:always".to_owned(), - )) - .sign(&pkey) - .expect("Failed to generate cert with order-dependent extensions"); -} - -/// Proves that a passing result from `test_cert_gen_extension_ordering` is -/// deterministic by reversing the order of extensions and asserting failure. -#[test] -fn test_cert_gen_extension_bad_ordering() { - let pkey = pkey(); - let result = get_generator() - .add_extension(Extension::OtherNid( - nid::AUTHORITY_KEY_IDENTIFIER, - "keyid:always".to_owned(), - )) - .add_extension(Extension::OtherNid( - nid::SUBJECT_KEY_IDENTIFIER, - "hash".to_owned(), - )) - .sign(&pkey); - - assert!(result.is_err()); -} - -#[test] -fn test_req_gen() { - let pkey = pkey(); - - let req = get_generator().request(&pkey).unwrap(); - let reqpem = req.to_pem().unwrap(); - - let req = X509Req::from_pem(&reqpem).ok().expect("Failed to load PEM"); - let cn = (*req) - .subject_name() - .entries_by_nid(nid::COMMONNAME) - .next() - .unwrap(); - assert_eq!(0, (*req).version()); - assert_eq!(cn.data().as_slice(), b"test_me"); - - // FIXME: check data in result to be correct, needs implementation - // of X509_REQ getters -} - #[test] fn test_cert_loading() { let cert = include_bytes!("../../test/cert.pem"); - let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); + let cert = X509::from_pem(cert).unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; let hash_vec = Vec::from_hex(hash_str).unwrap(); - assert_eq!(fingerprint, hash_vec); + assert_eq!(hash_vec, &*fingerprint); +} + +#[test] +fn test_debug() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let debugged = format!("{:#?}", cert); + #[cfg(boringssl)] + assert!(debugged.contains(r#"serial_number: "8771f7bdee982fa5""#)); + #[cfg(not(boringssl))] + assert!(debugged.contains(r#"serial_number: "8771F7BDEE982FA5""#)); + assert!(debugged.contains(r#"signature_algorithm: sha256WithRSAEncryption"#)); + assert!(debugged.contains(r#"countryName = "AU""#)); + assert!(debugged.contains(r#"stateOrProvinceName = "Some-State""#)); + assert!(debugged.contains(r#"not_before: Aug 14 17:00:03 2016 GMT"#)); + assert!(debugged.contains(r#"not_after: Aug 12 17:00:03 2026 GMT"#)); } #[test] fn test_cert_issue_validity() { let cert = include_bytes!("../../test/cert.pem"); - let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); + let cert = X509::from_pem(cert).unwrap(); let not_before = cert.not_before().to_string(); let not_after = cert.not_after().to_string(); @@ -144,7 +78,7 @@ fn test_cert_issue_validity() { #[test] fn test_save_der() { let cert = include_bytes!("../../test/cert.pem"); - let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); + let cert = X509::from_pem(cert).unwrap(); let der = cert.to_der().unwrap(); assert!(!der.is_empty()); @@ -155,7 +89,7 @@ fn test_subject_read_cn() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); - let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap(); + let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"foobar.com") } @@ -165,26 +99,53 @@ fn test_nid_values() { let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); - let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap(); + let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"example.com"); let email = subject - .entries_by_nid(nid::PKCS9_EMAILADDRESS) + .entries_by_nid(Nid::PKCS9_EMAILADDRESS) .next() .unwrap(); assert_eq!(email.data().as_slice(), b"test@example.com"); - let friendly = subject.entries_by_nid(nid::FRIENDLYNAME).next().unwrap(); + let friendly = subject.entries_by_nid(Nid::FRIENDLYNAME).next().unwrap(); assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example"); } +#[test] +fn test_nameref_iterator() { + let cert = include_bytes!("../../test/nid_test_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let subject = cert.subject_name(); + let mut all_entries = subject.entries(); + + let email = all_entries.next().unwrap(); + assert_eq!( + email.object().nid().as_raw(), + Nid::PKCS9_EMAILADDRESS.as_raw() + ); + assert_eq!(email.data().as_slice(), b"test@example.com"); + + let cn = all_entries.next().unwrap(); + assert_eq!(cn.object().nid().as_raw(), Nid::COMMONNAME.as_raw()); + assert_eq!(cn.data().as_slice(), b"example.com"); + + let friendly = all_entries.next().unwrap(); + assert_eq!(friendly.object().nid().as_raw(), Nid::FRIENDLYNAME.as_raw()); + assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example"); + + if all_entries.next().is_some() { + panic!(); + } +} + #[test] fn test_nid_uid_value() { let cert = include_bytes!("../../test/nid_uid_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); - let cn = subject.entries_by_nid(nid::USERID).next().unwrap(); + let cn = subject.entries_by_nid(Nid::USERID).next().unwrap(); assert_eq!(cn.data().as_slice(), b"this is the userId"); } @@ -194,25 +155,27 @@ fn test_subject_alt_name() { let cert = X509::from_pem(cert).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); - assert_eq!(3, subject_alt_names.len()); - assert_eq!(Some("foobar.com"), subject_alt_names[0].dnsname()); + assert_eq!(5, subject_alt_names.len()); + assert_eq!(Some("example.com"), subject_alt_names[0].dnsname()); assert_eq!(subject_alt_names[1].ipaddress(), Some(&[127, 0, 0, 1][..])); assert_eq!( subject_alt_names[2].ipaddress(), Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]) ); + assert_eq!(Some("test@example.com"), subject_alt_names[3].email()); + assert_eq!(Some("http://www.example.com"), subject_alt_names[4].uri()); } #[test] fn test_subject_alt_name_iter() { let cert = include_bytes!("../../test/alt_name_cert.pem"); - let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); + let cert = X509::from_pem(cert).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); let mut subject_alt_names_iter = subject_alt_names.iter(); assert_eq!( subject_alt_names_iter.next().unwrap().dnsname(), - Some("foobar.com") + Some("example.com") ); assert_eq!( subject_alt_names_iter.next().unwrap().ipaddress(), @@ -222,15 +185,41 @@ fn test_subject_alt_name_iter() { subject_alt_names_iter.next().unwrap().ipaddress(), Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]) ); + assert_eq!( + subject_alt_names_iter.next().unwrap().email(), + Some("test@example.com") + ); + assert_eq!( + subject_alt_names_iter.next().unwrap().uri(), + Some("http://www.example.com") + ); assert!(subject_alt_names_iter.next().is_none()); } +#[test] +fn test_aia_ca_issuer() { + // With AIA + let cert = include_bytes!("../../test/aia_test_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let authority_info = cert.authority_info().unwrap(); + assert_eq!(authority_info.len(), 1); + assert_eq!(authority_info[0].method().to_string(), "CA Issuers"); + assert_eq!( + authority_info[0].location().uri(), + Some("http://www.example.com/cert.pem") + ); + // Without AIA + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert!(cert.authority_info().is_none()); +} + #[test] fn x509_builder() { let pkey = pkey(); let mut name = X509Name::builder().unwrap(); - name.append_entry_by_nid(nid::COMMONNAME, "foobar.com") + name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com") .unwrap(); let name = name.build(); @@ -247,7 +236,7 @@ fn x509_builder() { builder.set_pubkey(&pkey).unwrap(); let mut serial = BigNum::new().unwrap(); - serial.rand(128, MSB_MAYBE_ZERO, false).unwrap(); + serial.rand(128, MsbOption::MAYBE_ZERO, false).unwrap(); builder .set_serial_number(&serial.to_asn1_integer().unwrap()) .unwrap(); @@ -287,12 +276,15 @@ fn x509_builder() { let x509 = builder.build(); assert!(pkey.public_eq(&x509.public_key().unwrap())); + assert!(x509.verify(&pkey).unwrap()); - let cn = x509.subject_name() - .entries_by_nid(nid::COMMONNAME) + let cn = x509 + .subject_name() + .entries_by_nid(Nid::COMMONNAME) .next() .unwrap(); - assert_eq!("foobar.com".as_bytes(), cn.data().as_slice()); + assert_eq!(cn.data().as_slice(), b"foobar.com"); + assert_eq!(serial, x509.serial_number().to_bn().unwrap()); } #[test] @@ -300,12 +292,12 @@ fn x509_req_builder() { let pkey = pkey(); let mut name = X509Name::builder().unwrap(); - name.append_entry_by_nid(nid::COMMONNAME, "foobar.com") + name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com") .unwrap(); 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(); @@ -324,6 +316,11 @@ fn x509_req_builder() { builder.add_extensions(&extensions).unwrap(); builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + + let req = builder.build(); + assert!(req.public_key().unwrap().public_eq(&pkey)); + assert_eq!(req.extensions().unwrap().len(), extensions.len()); + assert!(req.verify(&pkey).unwrap()); } #[test] @@ -333,17 +330,11 @@ fn test_stack_from_pem() { assert_eq!(certs.len(), 2); assert_eq!( - certs[0] - .fingerprint(MessageDigest::sha1()) - .unwrap() - .to_hex(), + hex::encode(certs[0].digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); assert_eq!( - certs[1] - .fingerprint(MessageDigest::sha1()) - .unwrap() - .to_hex(), + hex::encode(certs[1].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } @@ -355,28 +346,8 @@ fn issued() { let ca = include_bytes!("../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); - ca.issued(&cert).unwrap(); - cert.issued(&cert).err().unwrap(); -} - -#[test] -fn ecdsa_cert() { - let mut group = EcGroup::from_curve_name(X9_62_PRIME256V1).unwrap(); - group.set_asn1_flag(NAMED_CURVE); - let key = EcKey::generate(&group).unwrap(); - let key = PKey::from_ec_key(key).unwrap(); - - let cert = X509Generator::new() - .set_valid_period(365) - .add_name("CN".to_owned(), "TestServer".to_owned()) - .set_sign_hash(MessageDigest::sha256()) - .sign(&key) - .unwrap(); - - let mut ctx = SslContextBuilder::new(SslMethod::tls()).unwrap(); - ctx.set_certificate(&cert).unwrap(); - ctx.set_private_key(&key).unwrap(); - ctx.check_private_key().unwrap(); + assert_eq!(ca.issued(&cert), X509VerifyResult::OK); + assert_ne!(cert.issued(&cert), X509VerifyResult::OK); } #[test] @@ -385,23 +356,579 @@ fn signature() { let cert = X509::from_pem(cert).unwrap(); let signature = cert.signature(); assert_eq!( - signature.as_slice().to_hex(), + hex::encode(signature.as_slice()), "4af607b889790b43470442cfa551cdb8b6d0b0340d2958f76b9e3ef6ad4992230cead6842587f0ecad5\ - 78e6e11a221521e940187e3d6652de14e84e82f6671f097cc47932e022add3c0cb54a26bf27fa84c107\ - 4971caa6bee2e42d34a5b066c427f2d452038082b8073993399548088429de034fdd589dcfb0dd33be7\ - ebdfdf698a28d628a89568881d658151276bde333600969502c4e62e1d3470a683364dfb241f78d310a\ - 89c119297df093eb36b7fd7540224f488806780305d1e79ffc938fe2275441726522ab36d88348e6c51\ - f13dcc46b5e1cdac23c974fd5ef86aa41e91c9311655090a52333bc79687c748d833595d4c5f987508f\ - e121997410d37c" + 78e6e11a221521e940187e3d6652de14e84e82f6671f097cc47932e022add3c0cb54a26bf27fa84c107\ + 4971caa6bee2e42d34a5b066c427f2d452038082b8073993399548088429de034fdd589dcfb0dd33be7\ + ebdfdf698a28d628a89568881d658151276bde333600969502c4e62e1d3470a683364dfb241f78d310a\ + 89c119297df093eb36b7fd7540224f488806780305d1e79ffc938fe2275441726522ab36d88348e6c51\ + f13dcc46b5e1cdac23c974fd5ef86aa41e91c9311655090a52333bc79687c748d833595d4c5f987508f\ + e121997410d37c" ); let algorithm = cert.signature_algorithm(); - assert_eq!(algorithm.object().nid(), nid::SHA256WITHRSAENCRYPTION); + assert_eq!(algorithm.object().nid(), Nid::SHA256WITHRSAENCRYPTION); assert_eq!(algorithm.object().to_string(), "sha256WithRSAEncryption"); } #[test] +#[allow(clippy::redundant_clone)] fn clone_x509() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - cert.clone(); + drop(cert.clone()); +} + +#[test] +fn test_verify_cert() { + 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 store = store_bldr.build(); + + let mut context = X509StoreContext::new().unwrap(); + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); +} + +#[test] +fn test_verify_fails() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/alt_name_cert.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 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_fails_with_crl_flag_set_and_no_crl() { + 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(); + store_bldr.set_flags(X509VerifyFlags::CRL_CHECK).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(), + "unable to get certificate CRL" + ) +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_verify_cert_with_purpose() { + 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(); + let purpose_idx = X509PurposeRef::get_by_sname("sslserver") + .expect("Getting certificate purpose 'sslserver' failed"); + let x509_purposeref = + X509PurposeRef::from_idx(purpose_idx).expect("Getting certificate purpose failed"); + store_bldr + .set_purpose(x509_purposeref.purpose()) + .expect("Setting certificate purpose failed"); + store_bldr.add_cert(ca).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_cert_with_wrong_purpose_fails() { + 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(); + let purpose_idx = X509PurposeRef::get_by_sname("timestampsign") + .expect("Getting certificate purpose 'timestampsign' failed"); + let x509_purpose = + X509PurposeRef::from_idx(purpose_idx).expect("Getting certificate purpose failed"); + store_bldr + .set_purpose(x509_purpose.purpose()) + .expect("Setting certificate purpose failed"); + store_bldr.add_cert(ca).unwrap(); + + let store = store_bldr.build(); + + let expected_error = ffi::X509_V_ERR_INVALID_PURPOSE; + let mut context = X509StoreContext::new().unwrap(); + assert_eq!( + context + .init(&store, &cert, &chain, |c| { + c.verify_cert()?; + Ok(c.error()) + }) + .unwrap() + .as_raw(), + expected_error + ) +} + +#[cfg(ossl110)] +#[test] +fn x509_ref_version() { + let mut builder = X509Builder::new().unwrap(); + let expected_version = 2; + builder + .set_version(expected_version) + .expect("Failed to set certificate version"); + let cert = builder.build(); + let actual_version = cert.version(); + assert_eq!( + expected_version, actual_version, + "Obtained certificate version is incorrect", + ); +} + +#[cfg(ossl110)] +#[test] +fn x509_ref_version_no_version_set() { + let cert = X509Builder::new().unwrap().build(); + let actual_version = cert.version(); + assert_eq!( + 0, actual_version, + "Default certificate version is incorrect", + ); +} + +#[test] +fn test_load_crl() { + let ca = include_bytes!("../../test/crl-ca.crt"); + let ca = X509::from_pem(ca).unwrap(); + + let crl = include_bytes!("../../test/test.crl"); + let crl = X509Crl::from_der(crl).unwrap(); + assert!(crl.verify(&ca.public_key().unwrap()).unwrap()); + + let cert = include_bytes!("../../test/subca.crt"); + let cert = X509::from_pem(cert).unwrap(); + + let revoked = match crl.get_by_cert(&cert) { + CrlStatus::Revoked(revoked) => revoked, + _ => panic!("cert should be revoked"), + }; + + assert_eq!( + revoked.serial_number().to_bn().unwrap(), + cert.serial_number().to_bn().unwrap(), + "revoked and cert serial numbers should match" + ); +} + +#[test] +fn test_save_subject_der() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let der = cert.subject_name().to_der().unwrap(); + println!("der: {:?}", der); + assert!(!der.is_empty()); +} + +#[test] +fn test_load_subject_der() { + // The subject from ../../test/cert.pem + const SUBJECT_DER: &[u8] = &[ + 48, 90, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 65, 85, 49, 19, 48, 17, 6, 3, 85, 4, 8, 12, + 10, 83, 111, 109, 101, 45, 83, 116, 97, 116, 101, 49, 33, 48, 31, 6, 3, 85, 4, 10, 12, 24, + 73, 110, 116, 101, 114, 110, 101, 116, 32, 87, 105, 100, 103, 105, 116, 115, 32, 80, 116, + 121, 32, 76, 116, 100, 49, 19, 48, 17, 6, 3, 85, 4, 3, 12, 10, 102, 111, 111, 98, 97, 114, + 46, 99, 111, 109, + ]; + 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(boringssl, ossl110, libressl270))] +fn test_name_to_owned() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let name = cert.subject_name(); + let copied_name = name.to_owned().unwrap(); + assert_eq!(Ordering::Equal, name.try_cmp(&copied_name).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))] +#[allow(clippy::bool_to_int_with_if)] +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 + ) +} + +#[test] +#[cfg(not(boringssl))] +fn test_load_cert_file() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let chain = Stack::new().unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + let lookup = store_bldr.add_lookup(X509Lookup::file()).unwrap(); + lookup + .load_cert_file("test/root-ca.pem", SslFiletype::PEM) + .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(ossl110)] +fn test_verify_param_auth_level() { + let mut param = X509VerifyParam::new().unwrap(); + let auth_lvl = 2; + let auth_lvl_default = -1; + + assert_eq!(param.auth_level(), auth_lvl_default); + + param.set_auth_level(auth_lvl); + assert_eq!(param.auth_level(), auth_lvl); +} + +#[test] +#[cfg(ossl102)] +fn test_set_purpose() { + 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(); + verify_params.set_purpose(X509PurposeId::ANY).unwrap(); + 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(ossl102)] +fn test_set_purpose_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(); + verify_params + .set_purpose(X509PurposeId::TIMESTAMP_SIGN) + .unwrap(); + store_bldr.set_param(&verify_params).unwrap(); + let store = store_bldr.build(); + + let expected_error = ffi::X509_V_ERR_INVALID_PURPOSE; + let mut context = X509StoreContext::new().unwrap(); + assert_eq!( + context + .init(&store, &cert, &chain, |c| { + c.verify_cert()?; + Ok(c.error()) + }) + .unwrap() + .as_raw(), + expected_error + ) +} + +#[test] +#[cfg(any(ossl101, libressl350))] +fn test_add_name_entry() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let inp_name = cert.subject_name().entries().next().unwrap(); + + let mut names = X509Name::builder().unwrap(); + names.append_entry(inp_name).unwrap(); + let names = names.build(); + + let mut entries = names.entries(); + let outp_name = entries.next().unwrap(); + assert_eq!(outp_name.object().nid(), inp_name.object().nid()); + assert_eq!(outp_name.data().as_slice(), inp_name.data().as_slice()); + assert!(entries.next().is_none()); +} + +#[test] +#[cfg(not(boringssl))] +fn test_load_crl_file_fail() { + let mut store_bldr = X509StoreBuilder::new().unwrap(); + let lookup = store_bldr.add_lookup(X509Lookup::file()).unwrap(); + let res = lookup.load_crl_file("test/root-ca.pem", SslFiletype::PEM); + assert!(res.is_err()); +} + +#[cfg(ossl110)] +fn ipaddress_as_subject_alternative_name_is_formatted_in_debug(expected_ip: T) +where + T: Into, +{ + let expected_ip = format!("{:?}", expected_ip.into()); + let mut builder = X509Builder::new().unwrap(); + let san = SubjectAlternativeName::new() + .ip(&expected_ip) + .build(&builder.x509v3_context(None, None)) + .unwrap(); + builder.append_extension(san).unwrap(); + let cert = builder.build(); + let actual_ip = cert + .subject_alt_names() + .into_iter() + .flatten() + .map(|n| format!("{:?}", *n)) + .next() + .unwrap(); + assert_eq!(actual_ip, expected_ip); +} + +#[cfg(ossl110)] +#[test] +fn ipv4_as_subject_alternative_name_is_formatted_in_debug() { + ipaddress_as_subject_alternative_name_is_formatted_in_debug([8u8, 8, 8, 128]); +} + +#[cfg(ossl110)] +#[test] +fn ipv6_as_subject_alternative_name_is_formatted_in_debug() { + ipaddress_as_subject_alternative_name_is_formatted_in_debug([ + 8u8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 128, + ]); } diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs index c062125..b0e22ef 100644 --- a/openssl/src/x509/verify.rs +++ b/openssl/src/x509/verify.rs @@ -1,5 +1,188 @@ -//! X509 certificate verification -//! -//! Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0. +use bitflags::bitflags; +use foreign_types::ForeignTypeRef; +use libc::{c_int, c_uint, c_ulong, time_t}; +use std::net::IpAddr; -pub use verify::*; +use crate::error::ErrorStack; +#[cfg(ossl102)] +use crate::x509::X509PurposeId; +use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; + +bitflags! { + /// Flags used to check an `X509` certificate. + pub struct X509CheckFlags: c_uint { + const ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT; + const NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS; + const NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; + const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS; + const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS; + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(any(ossl110))] + const NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; + + #[deprecated(since = "0.10.6", note = "renamed to NO_WILDCARDS")] + const FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS; + } +} + +bitflags! { + /// Flags used to verify an `X509` certificate chain. + pub struct X509VerifyFlags: c_ulong { + const CB_ISSUER_CHECK = ffi::X509_V_FLAG_CB_ISSUER_CHECK; + const USE_CHECK_TIME = ffi::X509_V_FLAG_USE_CHECK_TIME; + const CRL_CHECK = ffi::X509_V_FLAG_CRL_CHECK; + const CRL_CHECK_ALL = ffi::X509_V_FLAG_CRL_CHECK_ALL; + const IGNORE_CRITICAL = ffi::X509_V_FLAG_IGNORE_CRITICAL; + const X509_STRICT = ffi::X509_V_FLAG_X509_STRICT; + const ALLOW_PROXY_CERTS = ffi::X509_V_FLAG_ALLOW_PROXY_CERTS; + const POLICY_CHECK = ffi::X509_V_FLAG_POLICY_CHECK; + const EXPLICIT_POLICY = ffi::X509_V_FLAG_EXPLICIT_POLICY; + const INHIBIT_ANY = ffi::X509_V_FLAG_INHIBIT_ANY; + const INHIBIT_MAP = ffi::X509_V_FLAG_INHIBIT_MAP; + const NOTIFY_POLICY = ffi::X509_V_FLAG_NOTIFY_POLICY; + const EXTENDED_CRL_SUPPORT = ffi::X509_V_FLAG_EXTENDED_CRL_SUPPORT; + const USE_DELTAS = ffi::X509_V_FLAG_USE_DELTAS; + const CHECK_SS_SIGNATURE = ffi::X509_V_FLAG_CHECK_SS_SIGNATURE; + #[cfg(ossl102)] + const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST; + #[cfg(ossl102)] + const SUITEB_128_LOS_ONLY = ffi::X509_V_FLAG_SUITEB_128_LOS_ONLY; + #[cfg(ossl102)] + const SUITEB_192_LOS = ffi::X509_V_FLAG_SUITEB_128_LOS; + #[cfg(ossl102)] + const SUITEB_128_LOS = ffi::X509_V_FLAG_SUITEB_192_LOS; + #[cfg(ossl102)] + const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN; + #[cfg(ossl110)] + const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS; + #[cfg(ossl110)] + const NO_CHECK_TIME = ffi::X509_V_FLAG_NO_CHECK_TIME; + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_VERIFY_PARAM; + fn drop = ffi::X509_VERIFY_PARAM_free; + + /// Adjust parameters associated with certificate verification. + pub struct X509VerifyParam; + /// Reference to `X509VerifyParam`. + pub struct X509VerifyParamRef; +} + +impl X509VerifyParam { + /// Create an X509VerifyParam + #[corresponds(X509_VERIFY_PARAM_new)] + pub fn new() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::X509_VERIFY_PARAM_new()).map(X509VerifyParam) + } + } +} + +impl X509VerifyParamRef { + /// Set the host flags. + #[corresponds(X509_VERIFY_PARAM_set_hostflags)] + pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) { + unsafe { + ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits); + } + } + + /// Set verification flags. + #[corresponds(X509_VERIFY_PARAM_set_flags)] + pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_VERIFY_PARAM_set_flags(self.as_ptr(), flags.bits)).map(|_| ()) } + } + + /// Clear verification flags. + #[corresponds(X509_VERIFY_PARAM_clear_flags)] + pub fn clear_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_VERIFY_PARAM_clear_flags( + self.as_ptr(), + flags.bits, + )) + .map(|_| ()) + } + } + + /// Gets verification flags. + #[corresponds(X509_VERIFY_PARAM_get_flags)] + pub fn flags(&mut self) -> X509VerifyFlags { + let bits = unsafe { ffi::X509_VERIFY_PARAM_get_flags(self.as_ptr()) }; + X509VerifyFlags { bits } + } + + /// Set the expected DNS hostname. + #[corresponds(X509_VERIFY_PARAM_set1_host)] + pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_VERIFY_PARAM_set1_host( + self.as_ptr(), + host.as_ptr() as *const _, + host.len(), + )) + .map(|_| ()) + } + } + + /// Set the expected IPv4 or IPv6 address. + #[corresponds(X509_VERIFY_PARAM_set1_ip)] + pub fn set_ip(&mut self, ip: IpAddr) -> Result<(), ErrorStack> { + unsafe { + let mut buf = [0; 16]; + let len = match ip { + IpAddr::V4(addr) => { + buf[..4].copy_from_slice(&addr.octets()); + 4 + } + IpAddr::V6(addr) => { + buf.copy_from_slice(&addr.octets()); + 16 + } + }; + cvt(ffi::X509_VERIFY_PARAM_set1_ip( + self.as_ptr(), + buf.as_ptr() as *const _, + len, + )) + .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) } + } + + /// Sets the authentication security level to auth_level + #[corresponds(X509_VERIFY_PARAM_set_auth_level)] + #[cfg(ossl110)] + pub fn set_auth_level(&mut self, lvl: c_int) { + unsafe { ffi::X509_VERIFY_PARAM_set_auth_level(self.as_ptr(), lvl) } + } + + /// Gets the current authentication security level + #[corresponds(X509_VERIFY_PARAM_get_auth_level)] + #[cfg(ossl110)] + pub fn auth_level(&self) -> i32 { + unsafe { ffi::X509_VERIFY_PARAM_get_auth_level(self.as_ptr()) } + } + + /// Sets the verification purpose + #[corresponds(X509_VERIFY_PARAM_set_purpose)] + #[cfg(ossl102)] + pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_VERIFY_PARAM_set_purpose(self.as_ptr(), purpose.0)).map(|_| ()) } + } +} diff --git a/openssl/test/aia_test_cert.pem b/openssl/test/aia_test_cert.pem new file mode 100644 index 0000000..6cc522e --- /dev/null +++ b/openssl/test/aia_test_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDozCCAougAwIBAgIJAJayG40CARAjMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV +BAMMBHRlc3QwHhcNMjEwMzAyMDA1NzQ3WhcNNDgwNzE4MDA1NzQ3WjBzMQswCQYD +VQQGEwJYWDELMAkGA1UECAwCWFgxEDAOBgNVBAcMB25vd2hlcmUxEDAOBgNVBAoM +B3Rlc3RvcmcxEjAQBgNVBAsMCXRlc3Rncm91cDEfMB0GA1UEAwwWbWFjaGluZS0w +Lm15aG9zdC5teW5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANKA +3zhwC70hbxFVdC0dYk9BHaNntZ4LPUVwFSG2HBn34oO8zCp4wkH+VIi9vOhWiySK +Gs3gW4qpjMbF82Gqc3dG2KfqUrOtWY+u54zAzqpgiJf08wmREHPoZmjqfCfgM3FO +VMEA8g1BQxXEd+y7UEDoXhPIoeFnqzMu9sg4npnL9U5BLaQJiWnXHClnBrvAAKXW +E8KDNmcavtFvo2xQVC09C6dJG5CrigWcZe4CaUl44rHiPaQd+jOp0HAccl/XLA0/ +QyHvW6ksjco/mb7ia1U9ohaC/3NHmzUA1S3kdq/qgnkPsjmy5v8k5vizowNc5rFO +XsV86BIv44rh1Jut52ECAwEAAaOBnTCBmjAMBgNVHRMEBTADAQH/MAsGA1UdDwQE +AwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIQYDVR0RBBowGIIW +bWFjaGluZS0wLm15aG9zdC5teW5ldDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUH +MAKGH2h0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2VydC5wZW0wDQYJKoZIhvcNAQEL +BQADggEBAH+ayx8qGvxzrG57jgXJudq+z783O6E2xGBJn1cT9Jhrg1VnlU+tHcNd +fFcsp0gdQZCmm3pu3E0m/FsgTpfHUgdCOmZQp45QrxCz2oRdWQM71SSA/x1VfQ9w +670iZOEY15/ss2nRl0woaYO7tBVadpZfymW5+OhsTKn5gL0pVmW3RciHuAmbIvQO +bouUwzuZIJMfca7T1MqZYdrKoJrOBj0LaPTutjfQB7O/02vUCPjTTIH20aqsMe5K +KXCrjiZO2jkxQ49Hz5uwfPx12dSVHNLpsnfOAH+MUToeW+SPx2OPvl/uAHcph2lj +MLA6Wi64rSUxzkcFLFsGpKcK6QKcHUw= +-----END CERTIFICATE----- diff --git a/openssl/test/alt_name_cert.pem b/openssl/test/alt_name_cert.pem index 9f75f12..d9e9f90 100644 --- a/openssl/test/alt_name_cert.pem +++ b/openssl/test/alt_name_cert.pem @@ -1,25 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIEOjCCAyKgAwIBAgIJAJz42fzGUJGeMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV -BAYTAlVTMQswCQYDVQQIDAJOWTERMA8GA1UEBwwITmV3IFlvcmsxFTATBgNVBAoM -DEV4YW1wbGUsIExMQzEYMBYGA1UEAwwPRXhhbXBsZSBDb21wYW55MR8wHQYJKoZI -hvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE2MDQzMDA0MDg1NloXDTE3MDQz -MDA0MDg1NlowfzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhO -ZXcgWW9yazEVMBMGA1UECgwMRXhhbXBsZSwgTExDMRgwFgYDVQQDDA9FeGFtcGxl -IENvbXBhbnkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDggl2TbtO5Ewi/q8kV56xK6HBpwsj9 -wBoqGi6hkKm/8lhLTkuUG6WbEUepi7n9d7tjI9hwYN7MKtppAnS+d+Zh6sKMgLJn -hONkbQBJkYWwuIxRVXORCdyZDNzXP1rlb6ynmj6mItuPTRVNNMaZP+24fgXtwGk8 -P2nqA1ONbmyaP27txV+Rd8fmQvW3vSmq7iDob661TOtLZRqqVRpnLDGpLXTCptYz -dLN1nDWKjBUFpPGDxvfcSE3Yf9LaQM2uDHRygSgTFusbwarAGrAk8krsm/Tiaumx -Ls74MY6OEoLnPbEi5epWLqPmoE1nxrvYLtaWh3TTET3H72yL0+1PZTkpAgMBAAGj -gbgwgbUwHQYDVR0OBBYEFAIcHhTPUqVdK85u47vo8z0viJGPMB8GA1UdIwQYMBaA -FAIcHhTPUqVdK85u47vo8z0viJGPMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMC0G -A1UdEQQmMCSCCmZvb2Jhci5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwLAYJ -YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMA0GCSqG -SIb3DQEBCwUAA4IBAQDeYsuJaxbnxR2wDRSbxMpPp2b6fHPxC1vArKTSrQ/X+5s7 -YcQ29jkzD8FbET8iPsCOn/IECBiDKOpckkO6dBWM05ma9HHzWjQOJ7Lo6gEsvk4d -+M/jJz5IaJ7hOxp1hGqwNQ+PJQOZMmlruNcOzPU36qaWJ03+NYOKar5VpIrRxCNc -uehTArmJqDLQPfgETEhMYfpkqf3s/cGb1uyeCpzgIRPpf4Ki1Oys5cV/BqIn7n5g -7sUrhXboYL4+eYt5V4rcc4rLI5J5IP/a1Z+Z6UVH+Mbiyl0iD8aRr/bo9WvKih3C -2LBO0Apl0tkXUOMWp7G0UYHVEndwPjZnVoM42f11 +MIIDsDCCApigAwIBAgIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJBVTET +MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMB4XDTE4MDExNTExMDcwM1oXDTI4MDExMzExMDcwM1owfDELMAkGA1UE +BhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9yazEVMBMGA1UECgwM +RXhhbXBsZSwgTExDMTYwNAYDVQQDDC1FeGFtcGxlIENvbXBhbnkvZW1haWxBZGRy +ZXNzPXRlc3RAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCo9CWMRLMXo1CF/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErpl +xfLkt0pJqcoiZG8g9NU0kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10 +uSDk6V9aJSX1vKwONVNSwiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1V +fOugka7UktYnk9mrBbAMjmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1G +bN4AtDuhs252eqE9E4iTHk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U +3KTfhO/mTlAUWVyg9tCtOzboKgs1AgMBAAGjdDByMAkGA1UdEwQCMAAwCwYDVR0P +BAQDAgWgMFgGA1UdEQRRME+CC2V4YW1wbGUuY29thwR/AAABhxAAAAAAAAAAAAAA +AAAAAAABgRB0ZXN0QGV4YW1wbGUuY29thhZodHRwOi8vd3d3LmV4YW1wbGUuY29t +MA0GCSqGSIb3DQEBCwUAA4IBAQAx14G99z/MnSbs8h5jSos+dgLvhc2IQB/3CChE +hPyELc7iyw1iteRs7bS1m2NZx6gv6TZ6VydDrK1dnWSatQ7sskXTO+zfC6qjMwXl +IV+u7T8EREwciniIA82d8GWs60BGyBL3zp2iUOr5ULG4+c/S6OLdlyJv+fDKv+Xo +fKv1UGDi5rcvUBikeNkpEPTN9UsE9/A8XJfDyq+4RKuDW19EtzOOeVx4xpHOMnAy +VVAQVMKJzhoXtLF4k2j409na+f6FIcZSBet+plmzfB+WZNIgUUi/7MQIXOFQRkj4 +zH3SnsPm/IYpJzlH2vHhlqIBdaSoTWpGVWPq7D+H8OS3mmXF -----END CERTIFICATE----- diff --git a/openssl/test/ca.crt b/openssl/test/ca.crt new file mode 100644 index 0000000..a0a8ab2 --- /dev/null +++ b/openssl/test/ca.crt @@ -0,0 +1,88 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 13:ae:da:d8:f4:18:d7:73:b8:bd:35:c9:ce:8e:b3:fc + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=TestCA + Validity + Not Before: Jun 6 19:11:19 2019 GMT + Not After : May 21 19:11:19 2022 GMT + Subject: CN=SubCA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b0:09:fc:54:e7:6a:9f:0c:bd:ad:5a:8d:ef:94: + 4e:11:a6:87:19:4f:bf:a6:e1:62:a5:2d:b7:17:df: + 67:53:70:da:fe:7d:99:17:ee:13:47:0b:40:0b:a2: + 34:32:a9:d3:bf:20:fc:13:77:a1:d5:26:60:1f:f0: + d4:be:dc:76:7c:1e:6c:b4:4c:01:7c:56:cd:5c:53: + ec:81:b3:81:2a:b2:35:26:06:5a:79:e0:b3:9e:e4: + 57:e1:09:de:ad:7f:c8:cd:87:ee:49:93:30:52:58: + b2:bc:0f:c1:b6:10:44:f8:85:d5:5b:0a:9b:28:fe: + f4:f4:4a:16:a6:f7:25:e9:96:47:69:73:5b:33:77: + 92:7d:61:8d:2a:3d:d5:04:89:40:bf:6b:d2:fd:5d: + e2:1a:80:a9:8e:c8:92:f6:e5:4c:00:84:f9:6e:2a: + 93:a3:23:ee:28:23:81:f4:54:f0:18:2c:ee:32:8e: + 38:9c:a0:c8:33:04:b0:fc:4c:43:1a:5c:04:84:9f: + 73:c6:08:c7:1d:64:39:fe:72:19:3b:cc:a5:fd:0b: + 43:25:0d:2b:a9:88:77:9e:62:e6:ac:c2:9a:60:42: + 4f:4a:54:47:bc:a0:29:72:7c:38:52:c9:ea:27:c5: + 3d:d0:81:4a:3e:b8:78:79:4b:89:b8:4e:6d:1b:24: + 15:bd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 CRL Distribution Points: + + Full Name: + URI:http://127.0.0.1:8081/pki/test.crl + + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Key Identifier: + FD:82:45:39:A1:91:41:F2:66:CC:0D:75:D5:0D:40:D5:81:A7:A1:43 + X509v3 Authority Key Identifier: + keyid:C5:CC:F5:A1:8C:D9:E4:A7:BA:EC:21:F5:D1:84:23:EA:0D:C2:C7:30 + DirName:/CN=TestCA + serial:33:E7:04:87:09:32:87:21:D9:CD:7C:AA:4C:5A:BB:2C:6C:7B:54:28 + + X509v3 Key Usage: + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 96:a0:ff:8a:4b:bd:45:96:c9:72:3c:63:e3:48:c4:ab:ef:7e: + db:76:3f:d9:02:9e:69:c8:d9:36:55:e1:f5:9b:c9:69:d8:69: + 02:ac:50:8c:60:94:2c:2e:b9:a8:65:ac:f5:00:b0:8b:96:25: + 0b:8a:ef:94:21:57:e2:04:c2:c3:86:bf:06:4e:91:5c:e6:bc: + 1b:03:31:8b:64:ea:c5:79:c3:5c:94:e5:aa:67:7e:74:12:07: + 14:fd:cd:32:02:26:26:c9:0a:ed:d4:da:ee:2a:84:e3:f1:60: + b3:09:77:27:a1:3c:ac:ec:61:18:30:b5:6d:1f:16:0a:24:1a: + cf:1c:1b:60:a5:60:e5:2c:8b:cf:37:83:0c:15:e7:79:30:3f: + ee:50:45:7c:4b:c6:2c:cd:2c:81:0a:98:f1:65:44:7a:ca:2a: + 20:1a:de:19:d9:4b:ca:a1:e2:a4:b5:14:47:bf:b4:68:15:03: + c0:55:e5:f4:47:0e:55:9f:fe:85:d8:2c:7d:d0:1a:96:11:b9: + 68:b7:74:1e:61:94:c1:ae:87:52:2d:c6:26:ba:51:ed:f1:91: + c0:e6:4c:f8:ad:02:23:75:51:fc:f8:69:05:ec:cf:31:50:5a: + 41:78:eb:3d:27:4d:9b:68:ef:ba:0e:ba:3a:7d:60:00:9d:53: + a5:08:3d:c6 +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIQE67a2PQY13O4vTXJzo6z/DANBgkqhkiG9w0BAQsFADAR +MQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTkwNjA2MTkxMTE5WhcNMjIwNTIxMTkxMTE5 +WjAQMQ4wDAYDVQQDDAVTdWJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALAJ/FTnap8Mva1aje+UThGmhxlPv6bhYqUttxffZ1Nw2v59mRfuE0cLQAui +NDKp078g/BN3odUmYB/w1L7cdnwebLRMAXxWzVxT7IGzgSqyNSYGWnngs57kV+EJ +3q1/yM2H7kmTMFJYsrwPwbYQRPiF1VsKmyj+9PRKFqb3JemWR2lzWzN3kn1hjSo9 +1QSJQL9r0v1d4hqAqY7IkvblTACE+W4qk6Mj7igjgfRU8Bgs7jKOOJygyDMEsPxM +QxpcBISfc8YIxx1kOf5yGTvMpf0LQyUNK6mId55i5qzCmmBCT0pUR7ygKXJ8OFLJ +6ifFPdCBSj64eHlLibhObRskFb0CAwEAAaOBwDCBvTAzBgNVHR8ELDAqMCigJqAk +hiJodHRwOi8vMTI3LjAuMC4xOjgwODEvcGtpL3Rlc3QuY3JsMAwGA1UdEwQFMAMB +Af8wHQYDVR0OBBYEFP2CRTmhkUHyZswNddUNQNWBp6FDMEwGA1UdIwRFMEOAFMXM +9aGM2eSnuuwh9dGEI+oNwscwoRWkEzARMQ8wDQYDVQQDDAZUZXN0Q0GCFDPnBIcJ +Moch2c18qkxauyxse1QoMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +lqD/iku9RZbJcjxj40jEq+9+23Y/2QKeacjZNlXh9ZvJadhpAqxQjGCULC65qGWs +9QCwi5YlC4rvlCFX4gTCw4a/Bk6RXOa8GwMxi2TqxXnDXJTlqmd+dBIHFP3NMgIm +JskK7dTa7iqE4/Fgswl3J6E8rOxhGDC1bR8WCiQazxwbYKVg5SyLzzeDDBXneTA/ +7lBFfEvGLM0sgQqY8WVEesoqIBreGdlLyqHipLUUR7+0aBUDwFXl9EcOVZ/+hdgs +fdAalhG5aLd0HmGUwa6HUi3GJrpR7fGRwOZM+K0CI3VR/PhpBezPMVBaQXjrPSdN +m2jvug66On1gAJ1TpQg9xg== +-----END CERTIFICATE----- diff --git a/openssl/test/cms.p12 b/openssl/test/cms.p12 new file mode 100644 index 0000000000000000000000000000000000000000..c4f96b6996e41e31fb19f982c59a8a0fad90462b GIT binary patch literal 1709 zcmY+DdpHvcAIEpIHn+LVn7c`1ZjY9B3L8 zjw|#n{HOuk1r&0iF%S;)#10O_bHLQUBB+o9_T5255D>7l2!AC&yfIYuKOfYAP`oAt z=CNcSqgcI!0fAtEd=6NvkuSk#s^qLM4fYzT)`$021R*6ukUX`nrU1JEH}>)EcXsPU zg-pBTda9))RCK2vRGlO@C4X=}LG)fw)ak9vetvfTIiVe5fs44L(O_&^APyl<8H2um z()M+}wK5_tWSivIzB1+y{08i}oay!IU`&+gG~RO}#Y-U1Om0q}hW={fW^6h#v{~xx z8S5N`?hw^s`;}VGNFyH&Ugsls9JM($cUxB6`iY3xFnW-fXN%$rCE*tOXX*8mD@R7- zcgH-zWng89$T`JdgjDip{Gy zpX^#5_(y<8O4lQ&nNiSzxI1mJC1b93beM~-0;!)K43}<3}rqxg-&UbyI3c!nC!e%y2r)*oJKjT9i>8QHCsB0kjp(^Fd{UX%*W9lcE>ljVg@lT`mjduj) z*)8@MFr9zVW;5%?=IMUsi}gTWf+p=5t!`I8D51Hg?Vhu8;=8wTKMMrcbgI3KS~5=Z z#YF^~eM78DG>KZ1Mpa*29`^2g;|)YdM@;Trg(Y5uS13P5!}-2a&5^;b!>tR`iScVQ z-5+}jLH(8aXe+(#{f1S@qJ`z%*dyg+?e{paXhnR4Hh>0azO7O9FTkm&+p7ERPDbysRBVeVdD-I{mnA)7t1=+ z^B=lGy?9?N+d0oaU_0b)ax1tmaZ2e|nTyw{yclv)YX9A`y16cePjcf=)i)yUoME(% zGLgM%MVXVdm{7ydL1GpkeB6)M3iB|tKDyMhIFgZG$IY6?jXG+?Rc2UaxhLInU#r0( z`AKvD%1qQJ&Pz7nYX_A{*G>K0jKWqJgPfLvaXJn&r}hH8EFdxx1|)I2uWB@|Ell>O zdJaBu!JG;>RLkA6HJiB5G<=XW+}0Cv=<`h+fwZMNeu$-QuuA{n@0PA5dOw1=Q8rjj zQ9qwYW}%}ZW|AR1^SR4Bl7Cb&ys7EO>eGyy^VpYC0O}*LfnF)&e!z;U^GQI}Dwc!K z3#b*jYdfs!L?;K}LhWA8QGeBcqaB?`mA+-n%#J zl~ZoBX$$H+!}IhG8w!9;H96`CvrrqW)rt<$?Rgi=HHTkdI@V=u z>1Yq|sZ~AR*Uk16r)P(G62i=6>5VMYZvE~a4EG!KD%im{VY)2pbMm6ya}y82?Ua3p zhv$X{mvT=8zF%oa6cofy2*T#Dwfpn+Sdzj8Zt3+bvYS*~IAJ^n5-x_R0LMRo0 z*RJi%s2aTo%o-wA4;W4_x0Z;fbmW`+!GK1S1>L6m)4Q{(F>n55&vpxtNi7g*_sSz% z>RuhWweS)?H)7~#ATZgSWP1ep$hX(>7A<5s$3U~Cj)!5a;n+ijz$zd(576gUcP4Q3 z9QMrEL}XoK>)X4QWhHyrP1Ox9Ni0b<6g3bA33Bo95k8Ii+zvawsseGB7vx zG8i;=GBq|b91ixXOq=@5P_p*Z{*#&#i#~3ZJixg5*=_$P7iAJ;+nD`Uu_yjsdvVS6 zO}84OSf1#Ko%?t(ZPTQ4euL*)v6 z{2w!J@V~k2me-m_xvs!&(Fm?xT(i7({F*E3xc@@cq3p9KYfmdxGBGnUFfI-@2sDrd zhPf;six`WDZQI)&OWtkB6}P{#&E7M4+S3PZiU#r^X=N4(1F;6|3iv?^gc%wCv#=U4 z11V%b17n^U=vh`@iLz7ean;Xlr)T>0)rr*|(A&(qcs+CQvaBLCf%Yq+OH^_~nm+2N zzURr`6Y=@W+j-lRPJa+zHR+az%5>*XtSgpU`RXn6wf->mf0yT?-O+#E`UbVG@VG2+ tW?ACCKBeQVC4U&%Q=dw1?Y^TnvwffI2CFTpMrSMo9ruMg_=E&x0|0_v@QnZf literal 0 HcmV?d00001 diff --git a/openssl/test/crl-ca.crt b/openssl/test/crl-ca.crt new file mode 100644 index 0000000..a4a9075 --- /dev/null +++ b/openssl/test/crl-ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPDCCAiSgAwIBAgIUM+cEhwkyhyHZzXyqTFq7LGx7VCgwDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGVGVzdENBMB4XDTE5MDYwNjE5MTA1NVoXDTI5MDYwMzE5 +MTA1NVowETEPMA0GA1UEAwwGVGVzdENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAtNcFPtD1MHcolhgTHIAx/b9OyawCbVzvgasv8R9+94ZMhoGc/tNc +dVg271pCSmj+zYAFYsIwjxW+iq2e5A/fiBc6uqtNfEbU7+77QzxFG5wIbXtmmqEb +dVbqBT28NeKTR6X+EHlNgbw90CHy7byA7LMewxbTt2q1eY1RnB0ji8zdGZmIUPeC +WxzkxXEd0fg+KwBFN3YHV9CJX2KJ10qv7DvbKHeIVBU7osm6tzvNglNnnT90GFSY +zc59b+zS00axcY3Kn08Vt+1qWB9Sl8tixCTGqR538y/ambDr3NCWsiQYWys9KE1L +g0nEaIjb84R7b+qNmPtOezd9tanx7j9UzQIDAQABo4GLMIGIMB0GA1UdDgQWBBTF +zPWhjNnkp7rsIfXRhCPqDcLHMDBMBgNVHSMERTBDgBTFzPWhjNnkp7rsIfXRhCPq +DcLHMKEVpBMwETEPMA0GA1UEAwwGVGVzdENBghQz5wSHCTKHIdnNfKpMWrssbHtU +KDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +gdyQq6F8DO5rn7rZSLehTFx6tbtfncC/BOXZEGLZO0ciTrQ9Q8xHwRhz0W09QE1A +/GsBzb++PuvAl9i82WvunyPB5KZh+GPiaaqf466MdQrXj+IyqxeC9Lg9wEUjwRgp +ANVd3moKap5IZ9WDvhyEng2Oy8/btP2iqVEmd58rGAodd671eOPD8QkIxSquiIwy +Cu5s3IBZ0BOuSG9fWoyPTGMKAhzQPFiXGvWOabCkMz3TsPYVY5ENpq2K8cWn2D/r +TD1yPPdINg6HrALGD3S0sD+k588oS7U5oj1L8V4KJQTLSbh6/XcBpasa5Jdv7ZZe +lVgt69Gsn5Cf2BkbwhbF2Q== +-----END CERTIFICATE----- diff --git a/openssl/test/csr.pem b/openssl/test/csr.pem new file mode 100644 index 0000000..cf9dde2 --- /dev/null +++ b/openssl/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/dsa-encrypted.pem b/openssl/test/dsa-encrypted.pem deleted file mode 100644 index 9b1984e..0000000 --- a/openssl/test/dsa-encrypted.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,5B99FC62C376CA1F - -5nN039tLa3AHnSaQ0lk+Zsguu1EE+EyUlW1GHKs7ls2gOsZH1kR0+A+MiwNKlP24 -Syy8KYyAbgsirhtwN5IOSsA97feR/vHTY4xQ8nEef8tB7VeRJzOFLHGgS0hwIxOM -Tb8gb4y0FtoWdAgorieP4c1emu8VwTTkHd44AArDXsP1Y7s+a3IEMcHcc3tW+qBk -xuVnqBEETL1t0I5rKy+AYvPmGgEZ0dGRRnUlVMC5jMTozJFcStdSzKUY27prUBz2 -FREOJOA/dIjVn1UGijI64Io5sPCAbDPPmG2k4kywbEbd7Ee/MxEvRNcAyv4boyA8 -GnHZTILKi/WY5+SNlHE3YepCFo1XU+59SovB1lDhRmi43L4vfdGc/6y8L/+rbLuU -Y58DxLdOZLTjpf9GLLf9WcpHhNZhwFfBFA8HuT8FtKDPqlf2t65z+1AVV8JTH2wM -BrRHXTrBKn8YgafXD5MisKFmajoAtNZTvhYGm0D8BLIiNwOwLsGfXZ0hYAie0eoI -Xl6MbHp1n/e+R+XKJ3M9DPM8mzWntlltAhS5+Az0Zi4aBdzqQaTpqvEku21sygq8 -Hwm0fpAq7y4bMnjNbMqQVw== ------END DSA PRIVATE KEY----- diff --git a/openssl/test/intermediate-ca.key b/openssl/test/intermediate-ca.key new file mode 100644 index 0000000..48f4495 --- /dev/null +++ b/openssl/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/openssl/test/intermediate-ca.pem b/openssl/test/intermediate-ca.pem new file mode 100644 index 0000000..266ef59 --- /dev/null +++ b/openssl/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/leaf.pem b/openssl/test/leaf.pem new file mode 100644 index 0000000..0f7aa80 --- /dev/null +++ b/openssl/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/pkcs1.pem.pub b/openssl/test/pkcs1.pem.pub new file mode 100644 index 0000000..4d55704 --- /dev/null +++ b/openssl/test/pkcs1.pem.pub @@ -0,0 +1,8 @@ +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEAyrcf7lv42BCoiDd3LYmF8eaGO4rhmGzGgi+NSZowkEuLhibHGQle +FkZC7h1VKsxKFgy7Fx+GYHkv9OLm9H5fdp3HhYlo19bZVGvSJ66OJe/Bc4S02bBb +Y8vwpc/N5O77m5J/nHLuL7XJtpfSKkX+3NPiX1X2L99iipt7F0a7hNws3G3Lxg6t +P3Yc55TPjXzXvDIgjt/fag6iF8L/bR3augJJdDhLzNucR8A5HcvPtIVo51R631Zq +MCh+dZvgz9zGCXwsvSky/iOJTHN3wnpsWuCAzS1iJMfjR783Tfv6sWFs19FH7pHP +xBA3b2enPM9KBzINGOly0eM4h0fh+VBltQIDAQAB +-----END RSA PUBLIC KEY----- diff --git a/openssl/test/pkcs8-nocrypt.der b/openssl/test/pkcs8-nocrypt.der new file mode 100644 index 0000000000000000000000000000000000000000..04fbdc208af21bef611cba201f4352939e934d5f GIT binary patch literal 1216 zcmV;x1V8&Qf&{z*0RS)!1_>&LNQUrrZ9p8q5=T`0)hbn0JtfNIjnox z>EEI=Ze~SK13M49-d&$kBOt<3&9k9a0P|d7N?y+QwntJ~9B&0j9K}X56I#~`3NM1` zijm?B8cr@(UH_HUVDw8UKFe%}zZ`8voa9cbWO`B4X0zc;_5jB5^nlh$(JX$y;o2(q z%r;kpWn6ZxR=C43P$<%a6aTylIIYlH zhcB!{Yo7-WBc(6KT}xXyvxYeb6r3uxVF*<}4-Z5N*0e}X8f+$AR)gdZ?W4zYuw9lm zSh=iB-Z)+y6lK>35p3;F8hN;}epWBQA~<#Eeo1Cgwf}=orERjV>$m_Hn4n!7Ga^oHlPN2+)Wr>;42PUb?>=NZxT zjeQ+;^D^lSC6so=(5n9(`d+IpogQhjuA#=TKg4%ZDJKsLa?P%7#3uv|XGf%28;4EG zp;}ZrpH;4Krr$*(Y9$!2dkRNnV5OqRE#Z?q3Yt@UyvBy52{NbFmJ?|eJ73|F>V;%b zWxsBqMJ3XcJ3wO2l@A$id$Lr0*qOrPDs9Xgs;(eHR?(_TGi**ozq0w%v3UZ4fdKFE zveNS_lp3vd%z!GG%VE%FAzev9(3r;{A5xXenPm5xG2r@HAl{;ySHN%BD<%DI@()eL z^tlPheDzjClo_OydkeitoRkL);!+EoaPZ zJ+@;XDQT4sA^nFGyponqwQrPEs?P#}fdIsONX~`2n}Z|Z(C&M?C3rht`CT{`s8~O> zuUoHbN)KdM4}5MGc9E!iC~D|pf#OXB5sJo(N(ze>e}LryvX~}JjUD*-}fV3oPy_GH~yRDej;@2z*qw38D?fIoHY5+%*D$ zfNQ)6VDnN_(~hFw$%IzQs|J~L&7c798cF^@QX+IBQPpDPmT{5iQcsK_ZiGpBMmv7L zEaU9RF7+3Z6V5@^lbty!j0B{>y!09tj(I{jI3{SVt5);2^^l3EH(Azz%O^ix9`{ z0)c=KT!UxWihsu=KAC|eAa=48mnzoE1hwL6PR+@+7KI_sl8v6FPRO{OT18S!El|Q8 zC5FznQMucjl~-%Zev#MtzV7D{ycin(H79?PT%WmuOozLSGRkfm5L<2yT;?3~(q^k< e{i>d=u^m@tp6-Ai2kOFUIU(JPR;qtZnHmW{L`6ve literal 0 HcmV?d00001 diff --git a/openssl/test/subca.crt b/openssl/test/subca.crt new file mode 100644 index 0000000..a0a8ab2 --- /dev/null +++ b/openssl/test/subca.crt @@ -0,0 +1,88 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 13:ae:da:d8:f4:18:d7:73:b8:bd:35:c9:ce:8e:b3:fc + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=TestCA + Validity + Not Before: Jun 6 19:11:19 2019 GMT + Not After : May 21 19:11:19 2022 GMT + Subject: CN=SubCA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b0:09:fc:54:e7:6a:9f:0c:bd:ad:5a:8d:ef:94: + 4e:11:a6:87:19:4f:bf:a6:e1:62:a5:2d:b7:17:df: + 67:53:70:da:fe:7d:99:17:ee:13:47:0b:40:0b:a2: + 34:32:a9:d3:bf:20:fc:13:77:a1:d5:26:60:1f:f0: + d4:be:dc:76:7c:1e:6c:b4:4c:01:7c:56:cd:5c:53: + ec:81:b3:81:2a:b2:35:26:06:5a:79:e0:b3:9e:e4: + 57:e1:09:de:ad:7f:c8:cd:87:ee:49:93:30:52:58: + b2:bc:0f:c1:b6:10:44:f8:85:d5:5b:0a:9b:28:fe: + f4:f4:4a:16:a6:f7:25:e9:96:47:69:73:5b:33:77: + 92:7d:61:8d:2a:3d:d5:04:89:40:bf:6b:d2:fd:5d: + e2:1a:80:a9:8e:c8:92:f6:e5:4c:00:84:f9:6e:2a: + 93:a3:23:ee:28:23:81:f4:54:f0:18:2c:ee:32:8e: + 38:9c:a0:c8:33:04:b0:fc:4c:43:1a:5c:04:84:9f: + 73:c6:08:c7:1d:64:39:fe:72:19:3b:cc:a5:fd:0b: + 43:25:0d:2b:a9:88:77:9e:62:e6:ac:c2:9a:60:42: + 4f:4a:54:47:bc:a0:29:72:7c:38:52:c9:ea:27:c5: + 3d:d0:81:4a:3e:b8:78:79:4b:89:b8:4e:6d:1b:24: + 15:bd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 CRL Distribution Points: + + Full Name: + URI:http://127.0.0.1:8081/pki/test.crl + + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Key Identifier: + FD:82:45:39:A1:91:41:F2:66:CC:0D:75:D5:0D:40:D5:81:A7:A1:43 + X509v3 Authority Key Identifier: + keyid:C5:CC:F5:A1:8C:D9:E4:A7:BA:EC:21:F5:D1:84:23:EA:0D:C2:C7:30 + DirName:/CN=TestCA + serial:33:E7:04:87:09:32:87:21:D9:CD:7C:AA:4C:5A:BB:2C:6C:7B:54:28 + + X509v3 Key Usage: + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 96:a0:ff:8a:4b:bd:45:96:c9:72:3c:63:e3:48:c4:ab:ef:7e: + db:76:3f:d9:02:9e:69:c8:d9:36:55:e1:f5:9b:c9:69:d8:69: + 02:ac:50:8c:60:94:2c:2e:b9:a8:65:ac:f5:00:b0:8b:96:25: + 0b:8a:ef:94:21:57:e2:04:c2:c3:86:bf:06:4e:91:5c:e6:bc: + 1b:03:31:8b:64:ea:c5:79:c3:5c:94:e5:aa:67:7e:74:12:07: + 14:fd:cd:32:02:26:26:c9:0a:ed:d4:da:ee:2a:84:e3:f1:60: + b3:09:77:27:a1:3c:ac:ec:61:18:30:b5:6d:1f:16:0a:24:1a: + cf:1c:1b:60:a5:60:e5:2c:8b:cf:37:83:0c:15:e7:79:30:3f: + ee:50:45:7c:4b:c6:2c:cd:2c:81:0a:98:f1:65:44:7a:ca:2a: + 20:1a:de:19:d9:4b:ca:a1:e2:a4:b5:14:47:bf:b4:68:15:03: + c0:55:e5:f4:47:0e:55:9f:fe:85:d8:2c:7d:d0:1a:96:11:b9: + 68:b7:74:1e:61:94:c1:ae:87:52:2d:c6:26:ba:51:ed:f1:91: + c0:e6:4c:f8:ad:02:23:75:51:fc:f8:69:05:ec:cf:31:50:5a: + 41:78:eb:3d:27:4d:9b:68:ef:ba:0e:ba:3a:7d:60:00:9d:53: + a5:08:3d:c6 +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIQE67a2PQY13O4vTXJzo6z/DANBgkqhkiG9w0BAQsFADAR +MQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTkwNjA2MTkxMTE5WhcNMjIwNTIxMTkxMTE5 +WjAQMQ4wDAYDVQQDDAVTdWJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALAJ/FTnap8Mva1aje+UThGmhxlPv6bhYqUttxffZ1Nw2v59mRfuE0cLQAui +NDKp078g/BN3odUmYB/w1L7cdnwebLRMAXxWzVxT7IGzgSqyNSYGWnngs57kV+EJ +3q1/yM2H7kmTMFJYsrwPwbYQRPiF1VsKmyj+9PRKFqb3JemWR2lzWzN3kn1hjSo9 +1QSJQL9r0v1d4hqAqY7IkvblTACE+W4qk6Mj7igjgfRU8Bgs7jKOOJygyDMEsPxM +QxpcBISfc8YIxx1kOf5yGTvMpf0LQyUNK6mId55i5qzCmmBCT0pUR7ygKXJ8OFLJ +6ifFPdCBSj64eHlLibhObRskFb0CAwEAAaOBwDCBvTAzBgNVHR8ELDAqMCigJqAk +hiJodHRwOi8vMTI3LjAuMC4xOjgwODEvcGtpL3Rlc3QuY3JsMAwGA1UdEwQFMAMB +Af8wHQYDVR0OBBYEFP2CRTmhkUHyZswNddUNQNWBp6FDMEwGA1UdIwRFMEOAFMXM +9aGM2eSnuuwh9dGEI+oNwscwoRWkEzARMQ8wDQYDVQQDDAZUZXN0Q0GCFDPnBIcJ +Moch2c18qkxauyxse1QoMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +lqD/iku9RZbJcjxj40jEq+9+23Y/2QKeacjZNlXh9ZvJadhpAqxQjGCULC65qGWs +9QCwi5YlC4rvlCFX4gTCw4a/Bk6RXOa8GwMxi2TqxXnDXJTlqmd+dBIHFP3NMgIm +JskK7dTa7iqE4/Fgswl3J6E8rOxhGDC1bR8WCiQazxwbYKVg5SyLzzeDDBXneTA/ +7lBFfEvGLM0sgQqY8WVEesoqIBreGdlLyqHipLUUR7+0aBUDwFXl9EcOVZ/+hdgs +fdAalhG5aLd0HmGUwa6HUi3GJrpR7fGRwOZM+K0CI3VR/PhpBezPMVBaQXjrPSdN +m2jvug66On1gAJ1TpQg9xg== +-----END CERTIFICATE----- diff --git a/openssl/test/test.crl b/openssl/test/test.crl new file mode 100644 index 0000000000000000000000000000000000000000..aead062c4d3945d2569eb9bca682f99801ec1af0 GIT binary patch literal 469 zcmXqLV!UY3xQmIA(SVnYQ>)FR?K>|cBR4C9fuJEjP>4B{g_(yfB(=E2*-@O=(9*!n z(7@2l)YQNt3dA)uGBAg74U`QOnFNH_-MaBb;(GCpy{0G6^=rZigUHb{Ul;b=e6oDk8^x~|Ta;h%9y)HYP;`kf7VDctjGwc#a~icP z-aK2g$|q{KPEK`*2AZ>(n;01x>e!C^`8Tb)ukIM*+bnQiGzTdng_%WuD6JikZ0Rp7+RNeg7o#!S^{ z5b$3;d(-X3wpCX`=I)G}%$BrRSl=#uiI(m8V(!m;yR_72Tr*m|H^_N{UTp~5J+0ZI zN%Q6%ZU|NH`+hL=T$r}ihd+;Rcgt;;H_LsxUFMR4;L7*xyC&Cdz2p4w>+J>4-`#7j z4qVjB&0xRCOYqCKzJCuj_o+>YQgTIF`ZcmsjHR)eyQu-Q8+0?ih_t#C{6sQXT0k^t> literal 0 HcmV?d00001 diff --git a/systest/Cargo.toml b/systest/Cargo.toml index 3997bf3..97a5405 100644 --- a/systest/Cargo.toml +++ b/systest/Cargo.toml @@ -2,11 +2,15 @@ name = "systest" version = "0.1.0" authors = ["Alex Crichton "] -build = "build.rs" +edition = "2018" [dependencies] libc = "0.2" openssl-sys = { path = "../openssl-sys" } [build-dependencies] -ctest = "0.1" +ctest2 = "0.4" + +[features] +vendored = ['openssl-sys/vendored'] +bindgen = ['openssl-sys/bindgen'] diff --git a/systest/build.rs b/systest/build.rs index af8ebbc..34677d2 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -1,11 +1,14 @@ -extern crate ctest; +#![allow(clippy::uninlined_format_args)] use std::env; +#[allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] +#[path = "../openssl-sys/build/cfgs.rs"] +mod cfgs; + fn main() { - let mut cfg = ctest::TestGenerator::new(); + let mut cfg = ctest2::TestGenerator::new(); let target = env::var("TARGET").unwrap(); - let mut is_libressl = false; if let Ok(out) = env::var("DEP_OPENSSL_INCLUDE") { cfg.include(&out); @@ -21,24 +24,26 @@ fn main() { if target.contains("msvc") { cfg.flag("/wd4090"); } - } - if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { - cfg.cfg("libressl", None); - is_libressl = true; - } else if let Ok(version) = env::var("DEP_OPENSSL_VERSION") { - cfg.cfg(&format!("ossl{}", version), None); + // https://github.com/sfackler/rust-openssl/issues/889 + cfg.define("WIN32_LEAN_AND_MEAN", None); } - if let (Ok(version), Ok(patch)) = - ( - env::var("DEP_OPENSSL_VERSION"), - env::var("DEP_OPENSSL_PATCH"), - ) - { - cfg.cfg(&format!("ossl{}{}", version, patch), None); + + let openssl_version = env::var("DEP_OPENSSL_VERSION_NUMBER") + .ok() + .map(|v| u64::from_str_radix(&v, 16).unwrap()); + let libressl_version = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") + .ok() + .map(|v| u64::from_str_radix(&v, 16).unwrap()); + + cfg.cfg("openssl", None); + + for c in cfgs::get(openssl_version, libressl_version) { + cfg.cfg(c, None); } + if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { - for var in vars.split(",") { + for var in vars.split(',') { cfg.cfg("osslconf", Some(var)); } } @@ -52,48 +57,71 @@ fn main() { .header("openssl/x509v3.h") .header("openssl/safestack.h") .header("openssl/hmac.h") + .header("openssl/obj_mac.h") .header("openssl/ssl.h") .header("openssl/err.h") .header("openssl/rand.h") .header("openssl/pkcs12.h") .header("openssl/bn.h") .header("openssl/aes.h") - .header("openssl/ocsp.h"); + .header("openssl/ocsp.h") + .header("openssl/evp.h") + .header("openssl/x509_vfy.h"); - if !is_libressl { + if let Some(version) = openssl_version { cfg.header("openssl/cms.h"); + if version >= 0x10100000 { + cfg.header("openssl/kdf.h"); + } + + if version >= 0x30000000 { + cfg.header("openssl/provider.h"); + } } - cfg.type_name(|s, is_struct| { + #[allow(clippy::if_same_then_else)] + cfg.type_name(|s, is_struct, _is_union| { // Add some `*` on some callback parameters to get function pointer to // typecheck in C, especially on MSVC. if s == "PasswordCallback" { - format!("pem_password_cb*") + "pem_password_cb*".to_string() } else if s == "bio_info_cb" { - format!("bio_info_cb*") + "bio_info_cb*".to_string() } else if s == "_STACK" { - format!("struct stack_st") + "struct stack_st".to_string() // This logic should really be cleaned up - } else if is_struct && s != "point_conversion_form_t" && - s.chars().next().unwrap().is_lowercase() + } else if is_struct + && s != "point_conversion_form_t" + && s.chars().next().unwrap().is_lowercase() { format!("struct {}", s) + } else if s.starts_with("stack_st_") { + format!("struct {}", s) } else { - format!("{}", s) + s.to_string() } }); cfg.skip_type(|s| { // function pointers are declared without a `*` in openssl so their // sizeof is 1 which isn't what we want. - s == "PasswordCallback" || s == "bio_info_cb" || s.starts_with("CRYPTO_EX_") + s == "PasswordCallback" + || s == "pem_password_cb" + || s == "bio_info_cb" + || s.starts_with("CRYPTO_EX_") + }); + cfg.skip_struct(|s| { + s == "ProbeResult" || s == "X509_OBJECT_data" // inline union }); - cfg.skip_struct(|s| s == "ProbeResult"); cfg.skip_fn(move |s| { s == "CRYPTO_memcmp" || // uses volatile // Skip some functions with function pointers on windows, not entirely // sure how to get them to work out... (target.contains("windows") && { + s.starts_with("PEM_read_bio_") || + (s.starts_with("PEM_write_bio_") && s.ends_with("PrivateKey")) || + s == "d2i_PKCS8PrivateKey_bio" || + s == "i2d_PKCS8PrivateKey_bio" || s == "SSL_get_ex_new_index" || s == "SSL_CTX_get_ex_new_index" || s == "CRYPTO_get_ex_new_index" @@ -101,16 +129,24 @@ fn main() { }); cfg.skip_field_type(|s, field| { (s == "EVP_PKEY" && field == "pkey") || // union - (s == "GENERAL_NAME" && field == "d") // union + (s == "GENERAL_NAME" && field == "d") || // union + (s == "X509_OBJECT" && field == "data") // union }); cfg.skip_signededness(|s| { - s.ends_with("_cb") || s.ends_with("_CB") || s.ends_with("_cb_fn") || - s.starts_with("CRYPTO_") || s == "PasswordCallback" + s.ends_with("_cb") + || s.ends_with("_CB") + || s.ends_with("_cb_fn") + || s.starts_with("CRYPTO_") + || s == "PasswordCallback" + || s.ends_with("_cb_func") + || s.ends_with("_cb_ex") }); - cfg.field_name(|_s, field| if field == "type_" { - format!("type") - } else { - format!("{}", field) + cfg.field_name(|_s, field| { + if field == "type_" { + "type".to_string() + } else { + field.to_string() + } }); cfg.fn_cname(|rust, link_name| link_name.unwrap_or(rust).to_string()); cfg.generate("../openssl-sys/src/lib.rs", "all.rs"); diff --git a/systest/src/main.rs b/systest/src/main.rs index 39d31b2..c4583dd 100644 --- a/systest/src/main.rs +++ b/systest/src/main.rs @@ -1,7 +1,4 @@ -#![allow(bad_style)] - -extern crate openssl_sys; -extern crate libc; +#![allow(bad_style, deprecated, clippy::all)] use libc::*; use openssl_sys::*; diff --git a/test/add_target.sh b/test/add_target.sh deleted file mode 100755 index a819ed5..0000000 --- a/test/add_target.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -set -e - -case "${TARGET}" in -"x86_64-unknown-linux-gnu") - exit 0 - ;; -"i686-unknown-linux-gnu") - apt-get install -y --no-install-recommends gcc-multilib - ;; -"arm-unknown-linux-gnueabihf") - dpkg --add-architecture armhf - apt-get update - apt-get install -y --no-install-recommends \ - gcc-arm-linux-gnueabihf \ - libc6-dev:armhf \ - qemu-user-static - ;; -esac - -rustup target add ${TARGET} diff --git a/test/build_openssl.sh b/test/build_openssl.sh deleted file mode 100755 index 7053243..0000000 --- a/test/build_openssl.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -set -e - -if [ -d "${OPENSSL_DIR}" ]; then - exit 0 -fi - -apt-get install -y --no-install-recommends curl - -case "${LIBRARY}" in -"libressl") - URL1="http://ftp3.usa.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${VERSION}.tar.gz" - URL2="http://ftp.eu.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${VERSION}.tar.gz" - ;; -"openssl") - URL1="https://openssl.org/source/openssl-${VERSION}.tar.gz" - URL2="http://mirrors.ibiblio.org/openssl/source/openssl-${VERSION}.tar.gz" - ;; -esac - -case "${TARGET}" in -"x86_64-unknown-linux-gnu") - OS_COMPILER=linux-x86_64 - ;; -"i686-unknown-linux-gnu") - OS_COMPILER=linux-elf - OS_FLAGS=-m32 - ;; -"arm-unknown-linux-gnueabihf") - OS_COMPILER=linux-armv4 - export AR=arm-linux-gnueabihf-ar - export CC=arm-linux-gnueabihf-gcc - ;; -esac - -mkdir -p /tmp/build -cd /tmp/build - -OUT=/tmp/openssl.tgz -MAX_REDIRECTS=5 -curl -o ${OUT} -L --max-redirs ${MAX_REDIRECTS} ${URL1} \ - || curl -o ${OUT} -L --max-redirs ${MAX_REDIRECTS} ${URL2} - -tar --strip-components=1 -xzf ${OUT} - -case "${LIBRARY}" in -"openssl") - ./Configure --prefix=${OPENSSL_DIR} ${OS_COMPILER} -fPIC -g ${OS_FLAGS} no-shared - ;; -"libressl") - ./configure --prefix=${OPENSSL_DIR} --disable-shared --with-pic - ;; -esac - -make -j$(nproc) -make install -- Gitee