From 775dc560033046ae7316e0ccc4a5a030f2ae79ce Mon Sep 17 00:00:00 2001 From: Adrian Cruceru Date: Mon, 30 Nov 2020 21:14:27 +0000 Subject: [PATCH] Moving from referene counting allows simpler move to native-tls / hyper. Arc Changes: - Each Config/Context/... will hold Arcs towards items it holds pointers to. - This forces objects to live as long as needed, once no longer used they get destroyed by reference counting. This allows passing the objects to multiple threads without worrying about lifetime. I've also added notes why classes are Sync where used. Let me know if I missed any classes. Usage example of an intermediate mbed-hyper integration is at: - https://github.com/fortanix/rust-mbedtls/tree/acruceru/wip-mbed-hyper-v2/mbedtls-hyper/examples/integrations There I added a crate to wrap hyper - similar to native-tls. (that will be moved to native-tls layer soon) That crate can be considered an integration test that I will raise a separate PR for. Changes after initial review: - Added forward_mbedtls_calloc / forward_mbedtls_free functions so we can pass certificates to and from mbedtls without allocator mismatches/corruptions. - Switched to MbedtlsList and Certificate. A MbedtlsBox is pending for this PR as well. - Fixed most comments. Still pending: - Update define! macros - Add MbedtlsBox --- Cargo.lock | 451 ++++++++++++------------ mbedtls-sys/Cargo.toml | 1 + mbedtls-sys/build/cmake.rs | 2 + mbedtls/Cargo.toml | 4 +- mbedtls/build.rs | 5 + mbedtls/examples/client.rs | 23 +- mbedtls/examples/server.rs | 25 +- mbedtls/src/lib.rs | 12 + mbedtls/src/pk/dhparam.rs | 6 + mbedtls/src/pk/mod.rs | 110 +++++- mbedtls/src/pk/rfc6979.rs | 10 +- mbedtls/src/rng/ctr_drbg.rs | 215 +++++------- mbedtls/src/rng/hmac_drbg.rs | 102 ++++-- mbedtls/src/rng/mod.rs | 8 +- mbedtls/src/rng/os_entropy.rs | 116 ++++-- mbedtls/src/rng/rdrand.rs | 31 +- mbedtls/src/rust_malloc.c | 29 ++ mbedtls/src/self_test.rs | 5 + mbedtls/src/ssl/ciphersuites.rs | 1 + mbedtls/src/ssl/config.rs | 583 ++++++++++++++++++++----------- mbedtls/src/ssl/context.rs | 379 ++++++++++++-------- mbedtls/src/ssl/mod.rs | 4 +- mbedtls/src/ssl/ticket.rs | 69 ++-- mbedtls/src/wrapper_macros.rs | 99 +++--- mbedtls/src/x509/certificate.rs | 370 ++++++++++---------- mbedtls/src/x509/crl.rs | 60 +++- mbedtls/src/x509/mod.rs | 3 +- mbedtls/tests/client_server.rs | 89 +++-- mbedtls/tests/ssl_conf_ca_cb.rs | 50 +-- mbedtls/tests/ssl_conf_verify.rs | 47 +-- mbedtls/tests/support/entropy.rs | 2 +- mbedtls/tests/support/rand.rs | 18 +- 32 files changed, 1743 insertions(+), 1186 deletions(-) create mode 100644 mbedtls/src/rust_malloc.c diff --git a/Cargo.lock b/Cargo.lock index 2c41da646..cefa56832 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,679 +4,678 @@ name = "aho-corasick" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11", ] [[package]] name = "autocfg" -version = "0.1.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bindgen" version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003f95e0fb6cf3d1fee8c62b2ec35135509477989fab15c358e0efa3972bdef6" dependencies = [ - "cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cexpr", + "clang-sys", + "docopt", + "env_logger", + "libc", + "log 0.3.9", + "rustc-serialize", + "syntex_syntax", ] [[package]] name = "bitflags" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" [[package]] name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" [[package]] name = "bitflags" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "block-cipher-trait" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] name = "block-modes" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "block-padding", ] [[package]] name = "block-padding" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools", ] [[package]] name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cc" -version = "1.0.45" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" [[package]] name = "cexpr" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" dependencies = [ - "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.9" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-integer", + "num-traits", + "time", + "winapi 0.3.9", ] [[package]] name = "clang-sys" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19911f7964ce61a02d382adee8400f919d0fedd53c5441e3d6a9858ba73e249e" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.7.0", + "glob", + "libc", ] [[package]] name = "cmake" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "core_io" version = "0.1.20190701" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3b45b225c233ea8b95309256e842264692c68eeb543e06755de9072dd1178a" dependencies = [ - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version", ] [[package]] name = "docopt" version = "0.6.86" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "regex", + "rustc-serialize", + "strsim", ] [[package]] name = "env_logger" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9", + "regex", ] [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] name = "glob" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" [[package]] name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" [[package]] name = "libc" -version = "0.2.62" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "libz-sys" -version = "1.0.25" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11", ] [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "mbedtls" version = "0.6.1" dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "core_io 0.1.20190701 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mbedtls-sys-auto 2.18.5", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rc2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rs-libc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_cbor 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "yasna 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "block-modes", + "byteorder", + "cc", + "chrono", + "core_io", + "hex", + "libc", + "matches", + "mbedtls-sys-auto", + "rand", + "rc2", + "rs-libc", + "serde", + "serde_cbor", + "serde_derive", + "spin", + "yasna", ] [[package]] name = "mbedtls-sys-auto" version = "2.18.5" dependencies = [ - "bindgen 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen", + "cmake", + "libc", + "libz-sys", ] [[package]] name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "memchr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "nom" version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 1.0.2", ] [[package]] name = "num-integer" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-traits", ] [[package]] name = "num-traits" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "pkg-config" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "proc-macro2" -version = "0.4.30" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1", ] [[package]] name = "quote" -version = "0.6.13" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.9", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rc2" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039209d71774c9b2ae967ffb66b73ed253b3c384c198ec0d620fdd5369c78e5e" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "opaque-debug", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex" version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" dependencies = [ - "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr 0.1.11", + "regex-syntax", + "thread_local", + "utf8-ranges", ] [[package]] name = "regex-syntax" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" [[package]] name = "rs-libc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80a671d6c4696a49b78e0a271c99bc58bc1a17a64893a3684a1ba1a944b26ca9" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "rustc-serialize" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" [[package]] name = "rustc_version" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" dependencies = [ - "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "semver" version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" [[package]] name = "serde_bytes" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defbb8a83d7f34cc8380751eeb892b825944222888aff18996ea7901f24aec88" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "serde_cbor" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27181cf088428830792d77a40dd44f59d663f3e909bd56cef8c815403cf814ba" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "serde", + "serde_bytes", ] [[package]] name = "serde_derive" -version = "1.0.70" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "spin" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" [[package]] name = "strsim" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c" [[package]] name = "syn" -version = "0.14.9" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid 0.2.1", ] [[package]] name = "syntex_errors" version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290933a450229bbbeee92bc4900ed0300ba54b59a0741055284c709cf2938f03" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "log 0.3.9", + "rustc-serialize", + "syntex_pos", + "term", + "unicode-xid 0.0.3", ] [[package]] name = "syntex_pos" version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c37a0a6e73cc9d6c7a16fb955bc97fb8eb513b2d7ac23279adca58548a204ca" dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize", ] [[package]] name = "syntex_syntax" version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c64b3581fad872d6b28ccad01e0a0db0c4af70acd491af6650499a5fb35c9e8" dependencies = [ - "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.5.0", + "libc", + "log 0.3.9", + "rustc-serialize", + "syntex_errors", + "syntex_pos", + "term", + "unicode-xid 0.0.3", ] [[package]] name = "term" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "winapi 0.2.8", ] [[package]] name = "thread-id" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "libc", ] [[package]] name = "thread_local" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread-id", ] [[package]] name = "time" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "wasi", + "winapi 0.3.9", ] [[package]] name = "typenum" -version = "1.11.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" [[package]] name = "unicode-xid" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" [[package]] name = "unicode-xid" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "utf8-ranges" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" [[package]] name = "vcpkg" -version = "0.2.7" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "yasna" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum bindgen 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "003f95e0fb6cf3d1fee8c62b2ec35135509477989fab15c358e0efa3972bdef6" -"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" -"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" -"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" -"checksum clang-sys 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19911f7964ce61a02d382adee8400f919d0fedd53c5441e3d6a9858ba73e249e" -"checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" -"checksum core_io 0.1.20190701 (registry+https://github.com/rust-lang/crates.io-index)" = "bb3b45b225c233ea8b95309256e842264692c68eeb543e06755de9072dd1178a" -"checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" -"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rc2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "039209d71774c9b2ae967ffb66b73ed253b3c384c198ec0d620fdd5369c78e5e" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" -"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" -"checksum rs-libc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80a671d6c4696a49b78e0a271c99bc58bc1a17a64893a3684a1ba1a944b26ca9" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" -"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" -"checksum serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "defbb8a83d7f34cc8380751eeb892b825944222888aff18996ea7901f24aec88" -"checksum serde_cbor 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27181cf088428830792d77a40dd44f59d663f3e909bd56cef8c815403cf814ba" -"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" -"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" -"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c" -"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syntex_errors 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)" = "290933a450229bbbeee92bc4900ed0300ba54b59a0741055284c709cf2938f03" -"checksum syntex_pos 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c37a0a6e73cc9d6c7a16fb955bc97fb8eb513b2d7ac23279adca58548a204ca" -"checksum syntex_syntax 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c64b3581fad872d6b28ccad01e0a0db0c4af70acd491af6650499a5fb35c9e8" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" -"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" -"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" -"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum yasna 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "79af3189e6b0484c9fd54208f8eeb8818cadee00ec81438b67a64c8e6f2f3694" +checksum = "79af3189e6b0484c9fd54208f8eeb8818cadee00ec81438b67a64c8e6f2f3694" diff --git a/mbedtls-sys/Cargo.toml b/mbedtls-sys/Cargo.toml index f0dd423c8..e926bcb02 100644 --- a/mbedtls-sys/Cargo.toml +++ b/mbedtls-sys/Cargo.toml @@ -12,6 +12,7 @@ This version generates the correct bindings at compile time using bindgen.""" readme = "../README.md" repository = "https://github.com/fortanix/rust-mbedtls" documentation = "https://docs.rs/mbedtls-sys-auto/" +links = "mbedtls_sys" [lib] name = "mbedtls_sys" diff --git a/mbedtls-sys/build/cmake.rs b/mbedtls-sys/build/cmake.rs index 673ed3903..d2c7fc4b6 100644 --- a/mbedtls-sys/build/cmake.rs +++ b/mbedtls-sys/build/cmake.rs @@ -49,5 +49,7 @@ impl super::BuildConfig { println!("cargo:rustc-link-lib=mbedtls"); println!("cargo:rustc-link-lib=mbedx509"); println!("cargo:rustc-link-lib=mbedcrypto"); + + println!("cargo:include={}/{}", ::std::env::current_dir().unwrap().display(), self.mbedtls_src.join("include").display()); } } diff --git a/mbedtls/Cargo.toml b/mbedtls/Cargo.toml index f9605a243..393b4b954 100644 --- a/mbedtls/Cargo.toml +++ b/mbedtls/Cargo.toml @@ -38,8 +38,10 @@ default-features = false features = ["custom_printf", "trusted_cert_callback"] path = "../mbedtls-sys" + + [dev-dependencies] -libc = "0.2.0" +libc = "0.2.69" rand = "0.4.0" serde_cbor = "0.6" hex = "0.3" diff --git a/mbedtls/build.rs b/mbedtls/build.rs index 004c8a9c1..18dce7f22 100644 --- a/mbedtls/build.rs +++ b/mbedtls/build.rs @@ -12,6 +12,8 @@ use std::env; fn main() { let mut b = cc::Build::new(); + b.include(env::var_os("DEP_MBEDTLS_SYS_INCLUDE").expect("Links was not properly set in mbedtls-sys package, missing DEP_MBEDTLS_SYS_INCLUDE")); + b.file("src/rust_malloc.c"); b.file("src/rust_printf.c"); if env::var_os("CARGO_FEATURE_STD").is_none() || ::std::env::var("TARGET") @@ -22,9 +24,12 @@ fn main() { .define("_FORTIFY_SOURCE", Some("0")) .flag("-ffreestanding"); } + b.compile("librust-mbedtls.a"); + // Force correct link order for mbedtls_printf println!("cargo:rustc-link-lib=static=mbedtls"); println!("cargo:rustc-link-lib=static=mbedx509"); println!("cargo:rustc-link-lib=static=mbedcrypto"); + } diff --git a/mbedtls/examples/client.rs b/mbedtls/examples/client.rs index 8b405e3b4..69f1c548a 100644 --- a/mbedtls/examples/client.rs +++ b/mbedtls/examples/client.rs @@ -14,8 +14,9 @@ use std::net::TcpStream; use mbedtls::rng::CtrDrbg; use mbedtls::ssl::config::{Endpoint, Preset, Transport}; use mbedtls::ssl::{Config, Context}; -use mbedtls::x509::Certificate; +use mbedtls::x509::{MbedtlsList, Certificate}; use mbedtls::Result as TlsResult; +use std::sync::Arc; #[path = "../tests/support/mod.rs"] mod support; @@ -23,21 +24,21 @@ use support::entropy::entropy_new; use support::keys; fn result_main(addr: &str) -> TlsResult<()> { - let mut entropy = entropy_new(); - let mut rng = CtrDrbg::new(&mut entropy, None)?; - let mut cert = Certificate::from_pem(keys::PEM_CERT)?; + let entropy = Arc::new(entropy_new()); + let rng = Arc::new(CtrDrbg::new(entropy, None)?); + let cert = Arc::new(MbedtlsList::::from_pem(keys::PEM_CERT)?); let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default); - config.set_rng(Some(&mut rng)); - config.set_ca_list(Some(&mut *cert), None); - let mut ctx = Context::new(&config)?; + config.set_rng(rng); + config.set_ca_list(cert, None); + let mut ctx = Context::new(Arc::new(config)); - let mut conn = TcpStream::connect(addr).unwrap(); - let mut session = ctx.establish(&mut conn, None)?; + let conn = TcpStream::connect(addr).unwrap(); + ctx.establish(conn, None)?; let mut line = String::new(); stdin().read_line(&mut line).unwrap(); - session.write_all(line.as_bytes()).unwrap(); - io::copy(&mut session, &mut stdout()).unwrap(); + ctx.write_all(line.as_bytes()).unwrap(); + io::copy(&mut ctx, &mut stdout()).unwrap(); Ok(()) } diff --git a/mbedtls/examples/server.rs b/mbedtls/examples/server.rs index 59f8d7597..a0ba5eb12 100644 --- a/mbedtls/examples/server.rs +++ b/mbedtls/examples/server.rs @@ -15,8 +15,9 @@ use mbedtls::pk::Pk; use mbedtls::rng::CtrDrbg; use mbedtls::ssl::config::{Endpoint, Preset, Transport}; use mbedtls::ssl::{Config, Context}; -use mbedtls::x509::Certificate; +use mbedtls::x509::{MbedtlsList, Certificate}; use mbedtls::Result as TlsResult; +use std::sync::Arc; #[path = "../tests/support/mod.rs"] mod support; @@ -29,21 +30,25 @@ fn listen Result<(), E>>(mut handle_client: F) -> Resu println!("Connection from {}", conn.peer_addr().unwrap()); handle_client(conn)?; } + Ok(()) } fn result_main() -> TlsResult<()> { - let mut entropy = entropy_new(); - let mut rng = CtrDrbg::new(&mut entropy, None)?; - let mut cert = Certificate::from_pem(keys::PEM_CERT)?; - let mut key = Pk::from_private_key(keys::PEM_KEY, None)?; + let entropy = entropy_new(); + let rng = Arc::new(CtrDrbg::new(Arc::new(entropy), None)?); + let cert = Arc::new(MbedtlsList::::from_pem(keys::PEM_CERT)?); + let key = Arc::new(Pk::from_private_key(keys::PEM_KEY, None)?); let mut config = Config::new(Endpoint::Server, Transport::Stream, Preset::Default); - config.set_rng(Some(&mut rng)); - config.push_cert(&mut *cert, &mut key)?; - let mut ctx = Context::new(&config)?; + config.set_rng(rng); + config.push_cert(cert, key)?; + + let rc_config = Arc::new(config); - listen(|mut conn| { - let mut session = BufReader::new(ctx.establish(&mut conn, None)?); + listen(move |conn| { + let mut ctx = Context::new(rc_config.clone()); + ctx.establish(conn, None)?; + let mut session = BufReader::new(ctx); let mut line = Vec::new(); session.read_until(b'\n', &mut line).unwrap(); session.get_mut().write_all(&line).unwrap(); diff --git a/mbedtls/src/lib.rs b/mbedtls/src/lib.rs index a5e15df43..55c80e892 100644 --- a/mbedtls/src/lib.rs +++ b/mbedtls/src/lib.rs @@ -163,3 +163,15 @@ pub unsafe extern "C" fn mbedtls_time(tp: *mut time_t) -> time_t { } timestamp } + +// Debug not available in SGX +#[cfg(not(target_env = "sgx"))] +pub fn set_global_debug_threshold(threshold: i32) { + unsafe { mbedtls_sys::debug_set_threshold(threshold); } +} + + +extern "C" { + pub fn forward_mbedtls_calloc(n: mbedtls_sys::types::size_t, size: mbedtls_sys::types::size_t) -> *mut mbedtls_sys::types::raw_types::c_void; + pub fn forward_mbedtls_free(n: *mut mbedtls_sys::types::raw_types::c_void); +} diff --git a/mbedtls/src/pk/dhparam.rs b/mbedtls/src/pk/dhparam.rs index 6c785efb5..a5227232d 100644 --- a/mbedtls/src/pk/dhparam.rs +++ b/mbedtls/src/pk/dhparam.rs @@ -18,6 +18,12 @@ define!( impl<'a> Into {} ); +impl Into<*mut mbedtls_sys::dhm_context> for &Dhm { + fn into(self) -> *mut mbedtls_sys::dhm_context { + &self.inner as *const _ as *mut _ + } +} + impl Dhm { /// Takes both DER and PEM forms of FFDH parameters in `DHParams` format. /// diff --git a/mbedtls/src/pk/mod.rs b/mbedtls/src/pk/mod.rs index 48e643de8..bd544a0fb 100644 --- a/mbedtls/src/pk/mod.rs +++ b/mbedtls/src/pk/mod.rs @@ -132,6 +132,7 @@ const CUSTOM_PK_INFO: pk_info_t = { } }; +// If this changes then certificate.rs unsafe code in public_key needs to also change. define!( #[c_ty(pk_context)] #[repr(C)] @@ -142,6 +143,97 @@ define!( impl<'a> UnsafeFrom {} ); +impl Into<*mut mbedtls_sys::pk_context> for &Pk { + fn into(self) -> *mut mbedtls_sys::pk_context { + &self.inner as *const _ as *mut _ + } +} + +/// # Safety +/// +/// Thread safety analysis for Pk. +/// +/// A. Usage example of Pk. +/// +/// 1.1. Common use case is to to pass it as parameter to the SSL Config class. +/// 1.2. SSL Config class is then used by multiple Context classes (one for each connection) +/// 1.3. Context classes, handled by different threads will do calls towards Pk. +/// +/// Since this is a common use case for MbedTLS it should be thread safe if threading is enabled. +/// +/// B. Verifying thread safety. +/// +/// 1. Calls towards the specific Pk implementation are done via function pointers. +/// +/// - Example call towards Pk: +/// ../../../mbedtls-sys/vendor/library/ssl_srv.c:3707 - mbedtls_pk_decrypt( private_key, p, len, ... +/// - This calls a generic function pointer via: +/// ../../../mbedtls-sys/vendor/crypto/library/pk.c:475 - return( ctx->pk_info->decrypt_func( ctx->pk_ctx, input, ilen, +/// +/// 2. Pk implementation types. +/// +/// - The function pointers are defined via function: +/// ../../../mbedtls-sys/vendor/crypto/library/pk.c:115 - mbedtls_pk_info_from_type +/// - They are as follows: mbedtls_rsa_info / mbedtls_eckey_info / mbedtls_ecdsa_info +/// - These are defined in: +/// ../../../mbedtls-sys/vendor/crypto/library/pk_wrap.c:196 +/// +/// C. Checking types one by one. +/// +/// 1. RSA: mbedtls_rsa_info at ../../../mbedtls-sys/vendor/crypto/library/pk_wrap.c:196 +/// This uses internal locks in: ../../../mbedtls-sys/vendor/crypto/library/rsa.c:718 +/// +/// 2. ECKEY: mbedtls_eckey_info at ../../../mbedtls-sys/vendor/crypto/library/pk_wrap.c:418 +/// This does not use internal locks but avoids interior mutability. +/// +/// Function checks one by one: +/// - Only const access to context: eckey_check_pair, eckey_get_bitlen, eckey_can_do, eckey_check_pair +/// +/// - Const acccess / copies context to a stack based variable +/// eckey_verify_wrap, eckey_sign_wrap: ../../../mbedtls-sys/vendor/crypto/library/pk_wrap.c:251 +/// creates a stack ecdsa variable and uses ctx to initialize it. +/// ctx is passed as 'key', a const pointer to mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) +/// ../../../mbedtls-sys/vendor/crypto/library/ecdsa.c:819 +/// int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) +/// key does not mutate. +/// +/// - Ignored due to not defined: eckey_verify_rs_wrap, eckey_sign_rs_wrap +/// (Undefined - MBEDTLS_ECP_RESTARTABLE - ../../../mbedtls-sys/build/config.rs:173) +/// +/// - Only used when creating/freeing - which is safe by design - eckey_alloc_wrap / eckey_free_wrap +/// +/// 3. ECDSA: mbedtls_ecdsa_info at ../../../mbedtls-sys/vendor/crypto/library/pk_wrap.c:729 +/// This does not use internal locks but avoids interior mutability. +/// +/// - Const access / copies context to stack based variables: +/// ecdsa_verify_wrap: ../../../mbedtls-sys/vendor/crypto/library/pk_wrap.c:544 +/// This copies the public key on the stack - in buf[] and copies the group id and nbits. +/// That is done via: mbedtls_pk_write_pubkey( &p, buf, &key ) where key.pk_ctx = ctx; +/// And the key is a const parameter to mbedtls_pk_write_pubkey - ../../../mbedtls-sys/vendor/crypto/library/pkwrite.c:158 +/// +/// - Const access with additional notes due to call stacks involved. +/// +/// ecdsa_sign_wrap: ../../../mbedtls-sys/vendor/crypto/library/pk_wrap.c:657 +/// mbedtls_ecdsa_write_signature ../../../mbedtls-sys/vendor/crypto/library/ecdsa.c:688 +/// mbedtls_ecdsa_write_signature_restartable ../../../mbedtls-sys/vendor/crypto/library/ecdsa.c:640 +/// MBEDTLS_ECDSA_DETERMINISTIC is not defined. +/// MBEDTLS_ECDSA_SIGN_ALT is not defined. +/// Passes grp to: ecdsa_sign_restartable: ../../../mbedtls-sys/vendor/crypto/library/ecdsa.c:253 +/// Const access to group - reads parameters, passed as const to mbedtls_ecp_gen_privkey, +/// mbedtls_ecp_mul_restartable: ../../../mbedtls-sys/vendor/crypto/library/ecp.c:2351 +/// MBEDTLS_ECP_INTERNAL_ALT is not defined. (otherwise it might not be safe depending on ecp_init/ecp_free) ../../../mbedtls-sys/build/config.rs:131 +/// Passes as const to: mbedtls_ecp_check_privkey / mbedtls_ecp_check_pubkey / mbedtls_ecp_get_type( grp +/// +/// - Ignored due to not defined: ecdsa_verify_rs_wrap, ecdsa_sign_rs_wrap, ecdsa_rs_alloc, ecdsa_rs_free +/// (Undefined - MBEDTLS_ECP_RESTARTABLE - ../../../mbedtls-sys/build/config.rs:173) +/// +/// - Only const access to context: eckey_check_pair +/// +/// - Only used when creating/freeing - which is safe by design: ecdsa_alloc_wrap, ecdsa_free_wrap +/// +#[cfg(feature = "threading")] +unsafe impl Sync for Pk {} + impl Pk { /// Takes both DER and PEM forms of PKCS#1 or PKCS#8 encoded keys. /// @@ -323,11 +415,13 @@ impl Pk { .is_ok() } - getter!( - /// Key length in bits - len() -> usize = fn pk_get_bitlen - ); - getter!(pk_type() -> Type = fn pk_get_type); + pub fn len(&self) -> usize { + unsafe { pk_get_bitlen(&self.inner) } + } + + pub fn pk_type(&self) -> Type { + unsafe { pk_get_type(&self.inner).into() } + } pub fn curve(&self) -> Result { match self.pk_type() { @@ -692,7 +786,7 @@ impl Pk { sig: &mut [u8], rng: &mut F, ) -> Result { - use crate::rng::RngCallback; + use crate::rng::RngCallbackMut; if self.pk_type() == Type::Ecdsa || self.pk_type() == Type::Eckey { if sig.len() < ECDSA_MAX_LEN { @@ -717,8 +811,8 @@ impl Pk { hash.len(), sig.as_mut_ptr(), &mut ret, - Some(Rfc6979Rng::call), - rng.data_ptr(), + Some(Rfc6979Rng::call_mut), + rng.data_ptr_mut(), ).into_result()?; }; Ok(ret) diff --git a/mbedtls/src/pk/rfc6979.rs b/mbedtls/src/pk/rfc6979.rs index 1bc42f134..30da45d62 100644 --- a/mbedtls/src/pk/rfc6979.rs +++ b/mbedtls/src/pk/rfc6979.rs @@ -12,7 +12,7 @@ use crate::alloc_prelude::*; use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void}; use mbedtls_sys::types::size_t; -use crate::rng::{HmacDrbg, Random, RngCallback}; +use crate::rng::{HmacDrbg, Random, RngCallbackMut}; use crate::error::Result; use crate::bignum::Mpi; @@ -67,7 +67,7 @@ fn generate_rfc6979_nonce(md: &MdInfo, x: &Mpi, q: &Mpi, digest_bytes: &[u8]) -> pub(crate) struct Rfc6979Rng { pub k: Vec, pub k_read: usize, - pub rng: HmacDrbg<'static>, + pub rng: HmacDrbg, } /// An RNG which first outputs the k for RFC 6797 followed by random data @@ -110,8 +110,8 @@ impl Rfc6979Rng { } } -impl RngCallback for Rfc6979Rng { - unsafe extern "C" fn call( +impl RngCallbackMut for Rfc6979Rng { + unsafe extern "C" fn call_mut( user_data: *mut c_void, data_ptr: *mut c_uchar, len: size_t, @@ -126,7 +126,7 @@ impl RngCallback for Rfc6979Rng { } } - fn data_ptr(&mut self) -> *mut c_void { + fn data_ptr_mut(&mut self) -> *mut c_void { self as *const _ as *mut _ } } diff --git a/mbedtls/src/rng/ctr_drbg.rs b/mbedtls/src/rng/ctr_drbg.rs index 1b4184ba2..ffc062c01 100644 --- a/mbedtls/src/rng/ctr_drbg.rs +++ b/mbedtls/src/rng/ctr_drbg.rs @@ -6,126 +6,77 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ +use mbedtls_sys::*; +use std::sync::Arc; use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void}; use mbedtls_sys::types::size_t; pub use mbedtls_sys::CTR_DRBG_RESEED_INTERVAL as RESEED_INTERVAL; -use mbedtls_sys::{ - ctr_drbg_random, ctr_drbg_reseed, ctr_drbg_seed, ctr_drbg_set_prediction_resistance, - ctr_drbg_update, CTR_DRBG_PR_OFF, CTR_DRBG_PR_ON, -}; - -use super::{EntropyCallback, RngCallback}; use crate::error::{IntoResult, Result}; +use crate::rng::{EntropyCallback, RngCallback, RngCallbackMut}; + +#[allow(dead_code)] +pub struct CtrDrbg { + // Moving data causes dangling pointers: https://github.com/ARMmbed/mbedtls/issues/2147 + // Storing data in heap and forcing rust move to only move the pointer (box) referencing it. + // The move will be faster. Access to data will be slower due to additional indirection. + inner: Box, + entropy: Arc, +} -// ==== BEGIN IMMOVABLE TYPE KLUDGE ==== -// `ctr_drbg_context` inlines an `aes_context`, which is immovable. See -// https://github.com/ARMmbed/mbedtls/issues/2147. We work around this -// by always boxing up the context, which requires this module to depend on -// std/alloc. -// -// If `ctr_drbg_context` were moveable, this entire section could be replaced -// by basically: -// ``` -// define!( -// #[c_ty(ctr_drbg_context)] -// struct CtrDrbg<'entropy>; -// fn init() { -// ctr_drbg_init -// } -// fn drop() { -// ctr_drbg_free -// } -// ); -// ``` - -use self::private::CtrDrbgInner; -#[cfg(not(feature = "std"))] -use crate::alloc_prelude::*; -use core::ops::{Deref, DerefMut}; - -mod private { - use core::marker::PhantomData; - use mbedtls_sys::{ctr_drbg_context, ctr_drbg_free, ctr_drbg_init}; - - pub struct CtrDrbgInner<'entropy> { - pub(super) inner: ctr_drbg_context, - r: PhantomData<&'entropy ()>, - } - - impl<'entropy> CtrDrbgInner<'entropy> { - pub(super) fn init() -> Self { - let mut inner = ::core::mem::MaybeUninit::uninit(); - let inner = unsafe { - ctr_drbg_init(inner.as_mut_ptr()); - inner.assume_init() - }; - CtrDrbgInner { - inner, - r: PhantomData, - } - } - } +#[cfg(feature = "threading")] +unsafe impl Send for CtrDrbg {} + +/// +/// Class has interior mutability via function called 'call'. +/// That function has an internal mutex to guarantee thread safety. +/// +/// The other potential conflict is a mutable reference changing class. +/// That is avoided by having any users of the callback hold an 'Arc' to this class. +/// Rust will then ensure that a mutable reference cannot be aquired if more then 1 Arc exists to the same class. +/// +#[cfg(feature = "threading")] +unsafe impl Sync for CtrDrbg {} - impl<'entropy> Drop for CtrDrbgInner<'entropy> { - fn drop(&mut self) { - unsafe { ctr_drbg_free(&mut self.inner) }; - } - } -} +#[allow(dead_code)] +impl CtrDrbg { -pub struct CtrDrbg<'entropy> { - boxed: Box>, -} + // If threading enabled - we are Sync, but for that to be true we need entropy to also be sync. + #[cfg(feature = "threading")] + pub fn new(entropy: Arc, additional_entropy: Option<&[u8]>) -> Result { + let mut inner = Box::new(ctr_drbg_context::default()); -impl<'entropy> CtrDrbg<'entropy> { - fn init() -> Self { - CtrDrbg { - boxed: Box::new(CtrDrbgInner::init()), + unsafe { + ctr_drbg_init(&mut *inner); + ctr_drbg_seed( + &mut *inner, + Some(T::call), + entropy.data_ptr(), + additional_entropy.map(<[_]>::as_ptr).unwrap_or(::core::ptr::null()), + additional_entropy.map(<[_]>::len).unwrap_or(0) + ).into_result()?; } - } -} -#[doc(hidden)] -impl<'entropy> Deref for CtrDrbg<'entropy> { - type Target = CtrDrbgInner<'entropy>; - fn deref(&self) -> &Self::Target { - &self.boxed + Ok(CtrDrbg { inner, entropy }) } -} -#[doc(hidden)] -impl<'entropy> DerefMut for CtrDrbg<'entropy> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.boxed - } -} - -// ==== END IMMOVABLE TYPE KLUDGE ==== + #[cfg(not(feature = "threading"))] + pub fn new(entropy: Arc, additional_entropy: Option<&[u8]>) -> Result { + let mut inner = Box::new(ctr_drbg_context::default()); -#[cfg(feature = "threading")] -unsafe impl<'entropy> Sync for CtrDrbg<'entropy> {} - -impl<'entropy> CtrDrbg<'entropy> { - pub fn new( - source: &'entropy mut F, - additional_entropy: Option<&[u8]>, - ) -> Result> { - let mut ret = Self::init(); unsafe { + ctr_drbg_init(&mut *inner); ctr_drbg_seed( - &mut ret.inner, - Some(F::call), - source.data_ptr(), - additional_entropy - .map(<[_]>::as_ptr) - .unwrap_or(::core::ptr::null()), + &mut *inner, + Some(T::call), + entropy.data_ptr(), + additional_entropy.map(<[_]>::as_ptr).unwrap_or(::core::ptr::null()), additional_entropy.map(<[_]>::len).unwrap_or(0) - ) - .into_result()? - }; - Ok(ret) - } + ).into_result()?; + } + Ok(CtrDrbg { inner, entropy }) + } + pub fn prediction_resistance(&self) -> bool { if self.inner.prediction_resistance == CTR_DRBG_PR_OFF { false @@ -137,21 +88,32 @@ impl<'entropy> CtrDrbg<'entropy> { pub fn set_prediction_resistance(&mut self, pr: bool) { unsafe { ctr_drbg_set_prediction_resistance( - &mut self.inner, + &mut *self.inner, if pr { CTR_DRBG_PR_ON } else { CTR_DRBG_PR_OFF }, ) } } - getter!(entropy_len() -> size_t = .entropy_len); - setter!(set_entropy_len(len: size_t) = ctr_drbg_set_entropy_len); - getter!(reseed_interval() -> c_int = .reseed_interval); - setter!(set_reseed_interval(i: c_int) = ctr_drbg_set_reseed_interval); + pub fn entropy_len(&self) -> size_t { + self.inner.entropy_len + } + + pub fn set_entropy_len(&mut self, len: size_t) { + unsafe { ctr_drbg_set_entropy_len(&mut *self.inner, len); } + } + + pub fn reseed_interval(&self) -> c_int { + self.inner.reseed_interval + } + + pub fn set_reseed_interval(&mut self, i: c_int) { + unsafe { ctr_drbg_set_reseed_interval(&mut *self.inner, i); } + } pub fn reseed(&mut self, additional_entropy: Option<&[u8]>) -> Result<()> { unsafe { ctr_drbg_reseed( - &mut self.inner, + &mut *self.inner, additional_entropy .map(<[_]>::as_ptr) .unwrap_or(::core::ptr::null()), @@ -163,24 +125,37 @@ impl<'entropy> CtrDrbg<'entropy> { } pub fn update(&mut self, entropy: &[u8]) { - unsafe { ctr_drbg_update(&mut self.inner, entropy.as_ptr(), entropy.len()) }; + unsafe { ctr_drbg_update(&mut *self.inner, entropy.as_ptr(), entropy.len()) }; } +} - // TODO: - // - // ctr_drbg_random_with_add - // ctr_drbg_write_seed_file - // ctr_drbg_update_seed_file - // +#[allow(dead_code)] +impl Drop for CtrDrbg { + fn drop(&mut self) { + unsafe { ctr_drbg_free(&mut *self.inner) }; + } } -impl<'entropy> RngCallback for CtrDrbg<'entropy> { +impl RngCallbackMut for CtrDrbg { #[inline(always)] - unsafe extern "C" fn call(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { + unsafe extern "C" fn call_mut(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int where Self: std::marker::Sized { + // Mutex used in ctr_drbg_random at: ../../../mbedtls-sys/vendor/crypto/library/ctr_drbg.c:546 ctr_drbg_random(user_data, data, len) } - fn data_ptr(&mut self) -> *mut c_void { - &mut self.inner as *mut _ as *mut _ + fn data_ptr_mut(&mut self) -> *mut c_void { + &*self.inner as *const _ as *mut _ + } +} + +impl RngCallback for CtrDrbg { + #[inline(always)] + unsafe extern "C" fn call(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int where Self: std::marker::Sized { + // Mutex used in ctr_drbg_random at: ../../../mbedtls-sys/vendor/crypto/library/ctr_drbg.c:546 + ctr_drbg_random(user_data, data, len) + } + + fn data_ptr(&self) -> *mut c_void { + &*self.inner as *const _ as *mut _ } } diff --git a/mbedtls/src/rng/hmac_drbg.rs b/mbedtls/src/rng/hmac_drbg.rs index 5320dd672..e97e98aaa 100644 --- a/mbedtls/src/rng/hmac_drbg.rs +++ b/mbedtls/src/rng/hmac_drbg.rs @@ -9,41 +9,51 @@ use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void}; use mbedtls_sys::types::size_t; pub use mbedtls_sys::HMAC_DRBG_RESEED_INTERVAL as RESEED_INTERVAL; -use mbedtls_sys::{ - hmac_drbg_random, hmac_drbg_reseed, hmac_drbg_seed, hmac_drbg_seed_buf, - hmac_drbg_set_prediction_resistance, hmac_drbg_update, HMAC_DRBG_PR_OFF, HMAC_DRBG_PR_ON, -}; +use mbedtls_sys::*; -use super::{EntropyCallback, RngCallback}; +use crate::rng::{EntropyCallback, RngCallback, RngCallbackMut}; use crate::error::{IntoResult, Result}; use crate::hash::MdInfo; +use std::sync::Arc; -define!( - #[c_ty(hmac_drbg_context)] - struct HmacDrbg<'entropy>; - const init: fn() -> Self = hmac_drbg_init; - const drop: fn(&mut Self) = hmac_drbg_free; -); +#[allow(dead_code)] +pub struct HmacDrbg { + inner: hmac_drbg_context, + entropy: Option>, +} + +unsafe impl Send for HmacDrbg {} #[cfg(feature = "threading")] -unsafe impl<'entropy> Sync for HmacDrbg<'entropy> {} +unsafe impl Sync for HmacDrbg {} -impl<'entropy> HmacDrbg<'entropy> { - pub fn new( +#[allow(dead_code)] +impl Drop for HmacDrbg { + fn drop(&mut self) { + unsafe { hmac_drbg_free(&mut self.inner) }; + } +} + +impl HmacDrbg { + pub fn new( md_info: MdInfo, - source: &'entropy mut F, + entropy: Arc, additional_entropy: Option<&[u8]>, - ) -> Result> { - let mut ret = Self::init(); + ) -> Result { + + let mut ret = HmacDrbg { + inner: hmac_drbg_context::default(), + entropy: Some(entropy), + }; + unsafe { + hmac_drbg_init(&mut ret.inner); hmac_drbg_seed( &mut ret.inner, md_info.into(), - Some(F::call), - source.data_ptr(), - additional_entropy - .map(<[_]>::as_ptr) - .unwrap_or(::core::ptr::null()), + Some(T::call), + ret.entropy.as_ref().unwrap().data_ptr(), + additional_entropy.map(<[_]>::as_ptr).unwrap_or(::core::ptr::null()), additional_entropy.map(<[_]>::len).unwrap_or(0) ) .into_result()? @@ -51,9 +61,15 @@ impl<'entropy> HmacDrbg<'entropy> { Ok(ret) } - pub fn from_buf(md_info: MdInfo, entropy: &[u8]) -> Result> { - let mut ret = Self::init(); + + pub fn from_buf(md_info: MdInfo, entropy: &[u8]) -> Result { + let mut ret = HmacDrbg { + inner: hmac_drbg_context::default(), + entropy: None, + }; + unsafe { + hmac_drbg_init(&mut ret.inner); hmac_drbg_seed_buf( &mut ret.inner, md_info.into(), @@ -86,10 +102,21 @@ impl<'entropy> HmacDrbg<'entropy> { } } - getter!(entropy_len() -> size_t = .entropy_len); - setter!(set_entropy_len(len: size_t) = hmac_drbg_set_entropy_len); - getter!(reseed_interval() -> c_int = .reseed_interval); - setter!(set_reseed_interval(i: c_int) = hmac_drbg_set_reseed_interval); + pub fn entropy_len(&self) -> size_t { + self.inner.entropy_len + } + + pub fn set_entropy_len(&mut self, len: size_t) { + unsafe { hmac_drbg_set_entropy_len(&mut self.inner, len); } + } + + pub fn reseed_interval(&self) -> c_int { + self.inner.reseed_interval + } + + pub fn set_reseed_interval(&mut self, i: c_int) { + unsafe { hmac_drbg_set_reseed_interval(&mut self.inner, i); } + } pub fn reseed(&mut self, additional_entropy: Option<&[u8]>) -> Result<()> { unsafe { @@ -117,13 +144,26 @@ impl<'entropy> HmacDrbg<'entropy> { // } -impl<'entropy> RngCallback for HmacDrbg<'entropy> { +impl RngCallbackMut for HmacDrbg { + #[inline(always)] + unsafe extern "C" fn call_mut(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { + // Mutex used in hmac_drbg_random: ../../../mbedtls-sys/vendor/crypto/library/hmac_drbg.c:363 + hmac_drbg_random(user_data, data, len) + } + + fn data_ptr_mut(&mut self) -> *mut c_void { + &self.inner as *const _ as *mut _ + } +} + +impl RngCallback for HmacDrbg { #[inline(always)] unsafe extern "C" fn call(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { + // Mutex used in hmac_drbg_random: ../../../mbedtls-sys/vendor/crypto/library/hmac_drbg.c:363 hmac_drbg_random(user_data, data, len) } - fn data_ptr(&mut self) -> *mut c_void { - &mut self.inner as *mut _ as *mut _ + fn data_ptr(&self) -> *mut c_void { + &self.inner as *const _ as *mut _ } } diff --git a/mbedtls/src/rng/mod.rs b/mbedtls/src/rng/mod.rs index 364ac3b7a..25d18c972 100644 --- a/mbedtls/src/rng/mod.rs +++ b/mbedtls/src/rng/mod.rs @@ -21,17 +21,17 @@ pub use self::hmac_drbg::HmacDrbg; #[doc(inline)] pub use self::os_entropy::OsEntropy; #[cfg(feature = "rdrand")] -pub use self::rdrand::{Entropy as Rdseed, Nrbg as Rdrand}; +pub use self::rdrand::{Rdseed, Rdrand}; use crate::error::{Result, IntoResult}; use mbedtls_sys::types::raw_types::{c_int, c_uchar}; use mbedtls_sys::types::size_t; -callback!(EntropyCallback:Sync(data: *mut c_uchar, len: size_t) -> c_int); -callback!(RngCallback:Sync(data: *mut c_uchar, len: size_t) -> c_int); +callback!(EntropyCallbackMut,EntropyCallback:Sync(data: *mut c_uchar, len: size_t) -> c_int); +callback!(RngCallbackMut,RngCallback:Sync(data: *mut c_uchar, len: size_t) -> c_int); pub trait Random: RngCallback { - fn random(&mut self, data: &mut [u8]) -> Result<()> { + fn random(&mut self, data: &mut [u8]) -> Result<()> where Self: std::marker::Sized { unsafe { Self::call(self.data_ptr(), data.as_mut_ptr(), data.len()) }.into_result()?; Ok(()) } diff --git a/mbedtls/src/rng/os_entropy.rs b/mbedtls/src/rng/os_entropy.rs index ec1e333d4..bffd6298c 100644 --- a/mbedtls/src/rng/os_entropy.rs +++ b/mbedtls/src/rng/os_entropy.rs @@ -6,71 +6,127 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ +use crate::error::{IntoResult, Result}; +use crate::rng::EntropyCallback; +use mbedtls_sys::*; use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void}; use mbedtls_sys::types::size_t; -use mbedtls_sys::*; +use std::sync::Arc; -use crate::error::{IntoResult, Result}; +callback!(EntropySourceCallbackMut,EntropySourceCallback(data: *mut c_uchar, size: size_t, out: *mut size_t) -> c_int); + +#[allow(dead_code)] +pub struct OsEntropy { + // Moving data causes dangling pointers: https://github.com/ARMmbed/mbedtls/issues/2147 + // Storing data in heap and forcing rust move to only move the pointer (box) referencing it. + // The move will be faster. Access to data will be slower due to additional indirection. + inner: Box, + sources: Vec>, +} + +impl Into<*mut mbedtls_sys::entropy_context> for &mut OsEntropy { + fn into(self) -> *mut mbedtls_sys::entropy_context { + &mut *self.inner + } +} + +impl Into<*const mbedtls_sys::entropy_context> for &mut OsEntropy { + fn into(self) -> *const mbedtls_sys::entropy_context { + &*self.inner + } +} + +impl Into<*const mbedtls_sys::entropy_context> for &OsEntropy { + fn into(self) -> *const mbedtls_sys::entropy_context { + &*self.inner + } +} -callback!(EntropySourceCallback(data: *mut c_uchar, size: size_t, out: *mut size_t) -> c_int); -define!( - #[c_ty(entropy_context)] - struct OsEntropy<'source>; - pub const new: fn() -> Self = entropy_init; - const drop: fn(&mut Self) = entropy_free; -); +unsafe impl Send for OsEntropy {} +/// +/// Class has interior mutability via function called 'call'. +/// That function has an internal mutex to guarantee thread safety. +/// +/// The other potential conflict is a mutable reference changing class. +/// That is avoided by having any users of the callback hold an 'Arc' to this class. +/// Rust will then ensure that a mutable reference cannot be aquired if more then 1 Arc exists to the same class. +/// #[cfg(feature = "threading")] -unsafe impl<'source> Sync for OsEntropy<'source> {} +unsafe impl Sync for OsEntropy {} -impl<'source> OsEntropy<'source> { - pub fn add_source( +#[allow(dead_code)] +impl OsEntropy { + + pub fn new() -> Self { + let mut inner = Box::new(entropy_context::default()); + + unsafe { + entropy_init(&mut *inner); + }; + + OsEntropy { + inner, + sources: vec![], + } + } + + pub fn add_source( &mut self, - source: &'source mut F, + source: Arc, threshold: size_t, strong: bool, ) -> Result<()> { unsafe { + // add_source is guarded with internal mutex: mbedtls-sys/vendor/crypto/library/entropy.c:143 + // all sources are called at later points via 'entropy_gather_internal' which in turn is called with internal mutex locked. entropy_add_source( - &mut self.inner, + self.into(), Some(F::call), source.data_ptr(), threshold, - if strong { - ENTROPY_SOURCE_STRONG - } else { - ENTROPY_SOURCE_WEAK - } + if strong { ENTROPY_SOURCE_STRONG } else { ENTROPY_SOURCE_WEAK } ) .into_result()? }; + + // Rust ensures only one mutable reference is currently in use. + self.sources.push(source); Ok(()) } - pub fn gather(&mut self) -> Result<()> { - unsafe { entropy_gather(&mut self.inner) }.into_result()?; + pub fn update_manual(&mut self, data: &[u8]) -> Result<()> { + // function is guarded with internal mutex: mbedtls-sys/vendor/crypto/library/entropy.c:241 + unsafe { entropy_update_manual(self.into(), data.as_ptr(), data.len()) }.into_result()?; Ok(()) } - pub fn update_manual(&mut self, data: &[u8]) -> Result<()> { - unsafe { entropy_update_manual(&mut self.inner, data.as_ptr(), data.len()) }.into_result()?; + pub fn gather(&mut self) -> Result<()> { + // function is guarded with internal mutex: mbedtls-sys/vendor/crypto/library/entropy.c:310 + unsafe { entropy_gather(self.into()) }.into_result()?; Ok(()) } - // TODO - // entropy_write_seed_file - // entropy_update_seed_file - // } -impl<'source> super::EntropyCallback for OsEntropy<'source> { +#[allow(dead_code)] +impl Drop for OsEntropy { + fn drop(&mut self) { + unsafe { entropy_free(self.into()); } + } +} + + +impl EntropyCallback for OsEntropy { #[inline(always)] unsafe extern "C" fn call(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { + // mutex used in entropy_func: ../../../mbedtls-sys/vendor/crypto/library/entropy.c:348 + // note: we're not using MBEDTLS_ENTROPY_NV_SEED so the initialization is not present or a race condition. entropy_func(user_data, data, len) } - fn data_ptr(&mut self) -> *mut c_void { - &mut self.inner as *mut _ as *mut _ + fn data_ptr(&self) -> *mut c_void { + &*self.inner as *const _ as *mut _ } } diff --git a/mbedtls/src/rng/rdrand.rs b/mbedtls/src/rng/rdrand.rs index 9b734a6b7..04abfe4f5 100644 --- a/mbedtls/src/rng/rdrand.rs +++ b/mbedtls/src/rng/rdrand.rs @@ -64,30 +64,47 @@ fn write_rng_to_slice(outbuf: &mut [u8], rng: fn() -> Option) -> c_int { 0 } -use super::{EntropyCallback, RngCallback}; +use super::{EntropyCallback, RngCallback, RngCallbackMut}; -pub struct Entropy; +pub struct Rdseed; -impl EntropyCallback for Entropy { +impl EntropyCallback for Rdseed { unsafe extern "C" fn call(_: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { let mut outbuf = from_raw_parts_mut(data, len); write_rng_to_slice(&mut outbuf, rdseed) } - fn data_ptr(&mut self) -> *mut c_void { + fn data_ptr(&self) -> *mut c_void { ::core::ptr::null_mut() } } -pub struct Nrbg; +pub struct Rdrand; -impl RngCallback for Nrbg { +unsafe impl RngCallbackMut for Rdrand { unsafe extern "C" fn call(_: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { + // outbuf data/len are stack variables let mut outbuf = from_raw_parts_mut(data, len); + + // rdrand function is thread safe write_rng_to_slice(&mut outbuf, rdrand) } - fn data_ptr(&mut self) -> *mut c_void { + fn data_ptr_mut(&mut self) -> *mut c_void { ::core::ptr::null_mut() } } + +impl RngCallback for Rdrand { + unsafe extern "C" fn call(_: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { + // outbuf data/len are stack variables + let mut outbuf = from_raw_parts_mut(data, len); + + // rdrand function is thread safe + write_rng_to_slice(&mut outbuf, rdrand) + } + + fn data_ptr(&self) -> *mut c_void { + ::core::ptr::null_mut() + } +} \ No newline at end of file diff --git a/mbedtls/src/rust_malloc.c b/mbedtls/src/rust_malloc.c new file mode 100644 index 000000000..fdf487b9f --- /dev/null +++ b/mbedtls/src/rust_malloc.c @@ -0,0 +1,29 @@ +/* Copyright (c) Fortanix, Inc. + * + * Licensed under the GNU General Public License, version 2 or the Apache License, Version + * 2.0 , at your + * option. This file may not be copied, modified, or distributed except + * according to those terms. */ + +// Follow same pattern for config and alloc/free as everywhere in mbedtls +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +extern void *forward_mbedtls_calloc( size_t n, size_t size ) { + return mbedtls_calloc(n, size); +} +extern void forward_mbedtls_free( void *ptr ) { + mbedtls_free(ptr); +} \ No newline at end of file diff --git a/mbedtls/src/self_test.rs b/mbedtls/src/self_test.rs index 3a97b2244..ff2229606 100644 --- a/mbedtls/src/self_test.rs +++ b/mbedtls/src/self_test.rs @@ -58,6 +58,11 @@ pub unsafe fn disable() { log_f = None; } +// +// NOTE: The following functions if used in a multithreaded or async environment will fail. +// Self test functions rely on global variables to track operations and anything non-self-test related will stomp over variables. +// While using these, make sure no other code uses mbedtls. Multiple self test operations done asynchronously may also return failures. +// pub use mbedtls_sys::{ aes_self_test as aes, arc4_self_test as arc4, base64_self_test as base64, camellia_self_test as camellia, ccm_self_test as ccm, ctr_drbg_self_test as ctr_drbg, diff --git a/mbedtls/src/ssl/ciphersuites.rs b/mbedtls/src/ssl/ciphersuites.rs index 20cbeaac8..a0b39df03 100644 --- a/mbedtls/src/ssl/ciphersuites.rs +++ b/mbedtls/src/ssl/ciphersuites.rs @@ -9,6 +9,7 @@ use mbedtls_sys::types::raw_types::c_int; use mbedtls_sys::*; +/// Always use into() to convert to i32, do not use 'as i32'. (until issue is fixed: https://github.com/fortanix/rust-mbedtls/issues/129) define!( #[non_exhaustive] #[c_ty(c_int)] diff --git a/mbedtls/src/ssl/config.rs b/mbedtls/src/ssl/config.rs index 936d047db..ad1c960b6 100644 --- a/mbedtls/src/ssl/config.rs +++ b/mbedtls/src/ssl/config.rs @@ -6,20 +6,24 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ -use core::slice::from_raw_parts; - -use mbedtls_sys::types::raw_types::{c_char, c_int, c_uchar, c_uint, c_void}; -use mbedtls_sys::types::size_t; -use mbedtls_sys::*; - -use crate::error::{Error, IntoResult, Result}; -use core::result::Result as StdResult; -use crate::pk::dhparam::Dhm; +use crate::error::{Error, Result, IntoResult}; use crate::pk::Pk; -use crate::private::UnsafeFrom; +use crate::rng::RngCallback; +use mbedtls_sys::*; +use mbedtls_sys::types::raw_types::{c_int, c_void, c_char, c_uchar, c_uint}; +use std::sync::Arc; +use crate::x509::Crl; +use crate::x509::Certificate; +use crate::x509::VerifyError; use crate::ssl::context::HandshakeContext; +use mbedtls_sys::types::size_t; +use std::slice::from_raw_parts; use crate::ssl::ticket::TicketCallback; -use crate::x509::{certificate, Crl, LinkedCertificate, Profile, VerifyError}; +use crate::pk::dhparam::Dhm; +use crate::x509::Profile; +use crate::ssl::Context; +use crate::private::UnsafeFrom; +use crate::x509::certificate::MbedtlsList; extern "C" { fn calloc(n: usize, size: usize) -> *mut c_void; @@ -83,57 +87,163 @@ define!( } ); -callback!(DbgCallback:Sync(level: c_int, file: *const c_char, line: c_int, message: *const c_char) -> ()); - define!( - #[c_ty(ssl_config)] - struct Config<'c>; - const init: fn() -> Self = ssl_config_init; - const drop: fn(&mut Self) = ssl_config_free; - impl<'q> Into {} - impl<'q> UnsafeFrom {} + #[c_ty(c_int)] + enum Renegotiation { + Enabled = SSL_RENEGOTIATION_ENABLED, + Disabled = SSL_RENEGOTIATION_DISABLED, + } ); + + +pub struct Config { + // Moving data may cause dangling pointers: https://github.com/ARMmbed/mbedtls/issues/2147 + // Storing data in heap and forcing rust move to only move the pointer (box) referencing it. + inner: Box, + + // Holding reference counters against any structures that ssl_config might hold pointer to. + // This allows caller to share structure on multiple configs if needed. + own_cert: Vec>>, + own_pk: Vec>, + + ca_cert: Option>>, + crl: Option>, + + // If we are sync we need all members to be sync, as such need to use cfg feature on all callbacks. + #[cfg(feature = "threading")] + rng: Option>, + #[cfg(not (feature = "threading"))] + rng: Option>, + + ciphersuites: Vec>>, + curves: Option>>, + + #[allow(dead_code)] + dhm: Option>, + + #[cfg(feature = "threading")] + verify_callback: Option Result<()>) + Send + Sync + 'static>>, + #[cfg(not (feature = "threading"))] + verify_callback: Option Result<()>) + 'static>>, + + #[cfg(feature = "threading")] + dbg_callback: Option ()) + Send + Sync + 'static>>, + #[cfg(not (feature = "threading"))] + dbg_callback: Option ()) + 'static>>, + + #[cfg(feature = "threading")] + sni_callback: Option Result<()>) + Send + Sync + 'static>>, + #[cfg(not (feature = "threading"))] + sni_callback: Option Result<()>) + 'static>>, + + #[cfg(feature = "threading")] + ticket_callback: Option>, + #[cfg(not (feature = "threading"))] + ticket_callback: Option>, + + #[cfg(feature = "threading")] + ca_callback: Option Result<()>) + Send + Sync + 'static>>, + #[cfg(not (feature = "threading"))] + ca_callback: Option Result<()>) + 'static>>, + +} + +#[cfg(feature = "threading")] +unsafe impl Sync for Config {} + #[cfg(feature = "threading")] -unsafe impl<'c> Sync for Config<'c> {} +unsafe impl Send for Config {} + +impl Into<*mut mbedtls_sys::ssl_config> for &mut Config { + fn into(self) -> *mut mbedtls_sys::ssl_config { + &mut *self.inner + } +} + -impl<'c> Config<'c> { +impl Into<*const mbedtls_sys::ssl_config> for &Config { + fn into(self) -> *const mbedtls_sys::ssl_config { + &*self.inner + } +} + +impl Config { pub fn new(e: Endpoint, t: Transport, p: Preset) -> Self { - let mut c = Config::init(); + let mut inner = Box::new(ssl_config::default()); + unsafe { - ssl_config_defaults(&mut c.inner, e.into(), t.into(), p.into()); + // This is just a memset to 0. + ssl_config_init(&mut *inner); + + // Set default values - after this point we will need ssl_config_free to be called. + ssl_config_defaults(&mut *inner, e as c_int, t as c_int, p as c_int); + }; + + Config { + inner, + own_cert: vec![], + own_pk: vec![], + ca_cert: None, + crl: None, + rng: None, + ciphersuites: vec![], + curves: None, + dhm: None, + verify_callback: None, + dbg_callback: None, + sni_callback: None, + ticket_callback: None, + ca_callback: None, } - c } - // need bitfield support getter!(endpoint() -> Endpoint = field endpoint); - setter!(set_endpoint(e: Endpoint) = ssl_conf_endpoint); - // need bitfield support getter!(transport() -> Transport = field transport); - setter!(set_transport(t: Transport) = ssl_conf_transport); - // need bitfield support getter!(authmode() -> AuthMode = field authmode); - setter!(set_authmode(am: AuthMode) = ssl_conf_authmode); - getter!(read_timeout() -> u32 = .read_timeout); - setter!(set_read_timeout(t: u32) = ssl_conf_read_timeout); + pub fn set_authmode(&mut self, authmode: AuthMode) { + unsafe { ssl_conf_authmode(self.into(), authmode as c_int); } + } + + pub fn read_timeout(&self) -> u32 { + self.inner.read_timeout + } + + pub fn set_read_timeout(&mut self, t: u32) { + unsafe { ssl_conf_read_timeout(self.into(), t); } + } fn check_c_list(list: &[T]) { assert!(list.last() == Some(&T::default())); } - pub fn set_ciphersuites(&mut self, list: &'c [c_int]) { - Self::check_c_list(list); - unsafe { ssl_conf_ciphersuites(&mut self.inner, list.as_ptr()) } + pub fn set_ciphersuites(&mut self, list: Arc>) { + Self::check_c_list(&list); + + unsafe { ssl_conf_ciphersuites(self.into(), (*Arc::as_ptr(&list)).as_ptr()) } + self.ciphersuites.push(list); } - pub fn set_ciphersuites_for_version(&mut self, list: &'c [c_int], major: c_int, minor: c_int) { - Self::check_c_list(list); - unsafe { ssl_conf_ciphersuites_for_version(&mut self.inner, list.as_ptr(), major, minor) } + pub fn set_ciphersuites_for_version(&mut self, list: Arc>, major: c_int, minor: c_int) { + Self::check_c_list(&list); + unsafe { ssl_conf_ciphersuites_for_version(self.into(), (*Arc::as_ptr(&list)).as_ptr(), major, minor) } + self.ciphersuites.push(list); } - pub fn set_curves(&mut self, list: &'c [ecp_group_id]) { - Self::check_c_list(list); - unsafe { ssl_conf_curves(&mut self.inner, list.as_ptr()) } + pub fn set_curves(&mut self, list: Arc>) { + Self::check_c_list(&list); + unsafe { ssl_conf_curves(self.into(), (*Arc::as_ptr(&list)).as_ptr()) } + self.curves = Some(list); } + #[cfg(feature = "threading")] + pub fn set_rng(&mut self, rng: Arc) { + unsafe { ssl_conf_rng(self.into(), Some(T::call), rng.data_ptr()) }; + self.rng = Some(rng); + } + #[cfg(not (feature = "threading"))] + pub fn set_rng(&mut self, rng: Arc) { + unsafe { ssl_conf_rng(self.into(), Some(T::call), rng.data_ptr()) }; + self.rng = Some(rng); + } + pub fn set_min_version(&mut self, version: Version) -> Result<()> { let minor = match version { Version::Ssl3 => 0, @@ -143,7 +253,7 @@ impl<'c> Config<'c> { _ => { return Err(Error::SslBadHsProtocolVersion); } }; - unsafe { ssl_conf_min_version(&mut self.inner, 3, minor) }; + unsafe { ssl_conf_min_version(self.into(), 3, minor) }; Ok(()) } @@ -155,186 +265,194 @@ impl<'c> Config<'c> { Version::Tls1_2 => 3, _ => { return Err(Error::SslBadHsProtocolVersion); } }; - unsafe { ssl_conf_max_version(&mut self.inner, 3, minor) }; + unsafe { ssl_conf_max_version(self.into(), 3, minor) }; Ok(()) } - setter!(set_cert_profile(p: &'c Profile) = ssl_conf_cert_profile); + // Profile as implemented in profile.rs can only point to global variables from mbedtls which would have 'static lifetime + pub fn set_cert_profile(&mut self, p: &'static Profile) { + unsafe { ssl_conf_cert_profile(self.into(), p.into()) }; + } /// Takes both DER and PEM forms of FFDH parameters in `DHParams` format. /// /// When calling on PEM-encoded data, `params` must be NULL-terminated pub fn set_dh_params(&mut self, params: &[u8]) -> Result<()> { - let mut ctx = Dhm::from_params(params)?; + let dhm = Arc::new(Dhm::from_params(params)?); unsafe { - ssl_conf_dh_param_ctx(&mut self.inner, (&mut ctx).into()) + ssl_conf_dh_param_ctx(self.into(), (&*dhm).into()) .into_result() - .map(|_| ()) + .map(|_| ())?; } + self.dhm = Some(dhm); + Ok(()) } - pub fn set_ca_list>( - &mut self, - list: Option, - crl: Option<&'c mut Crl>, - ) { - unsafe { - ssl_conf_ca_chain( - &mut self.inner, - list.map(Into::into) - .map(Into::into) - .unwrap_or(::core::ptr::null_mut()), - crl.map(Into::into).unwrap_or(::core::ptr::null_mut()), - ) - } - } + pub fn set_ca_list(&mut self, ca_cert: Arc>, crl: Option>) { + // This will override internal pointers to what we provide. + + unsafe { ssl_conf_ca_chain(self.into(), (&**ca_cert).into(), crl.as_ref().map(|crl| (&(**crl)).into()).unwrap_or(::core::ptr::null_mut())); } - pub fn push_cert>( - &mut self, - chain: C, - key: &'c mut Pk, - ) -> Result<()> { - unsafe { - ssl_conf_own_cert(&mut self.inner, chain.into().into(), key.into()) - .into_result() - .map(|_| ()) - } + self.ca_cert = Some(ca_cert); + self.crl = crl; } - pub fn certs(&'c self) -> KeyCertIter<'c> { - KeyCertIter { - key_cert: unsafe { UnsafeFrom::from(self.inner.key_cert as *const _) }, + pub fn push_cert(&mut self, own_cert: Arc>, own_pk: Arc) -> Result<()> { + // Need to ensure own_cert/pk_key outlive the config. + self.own_cert.push(own_cert.clone()); + self.own_pk.push(own_pk.clone()); + + // This will append pointers to our certificates inside mbedtls + unsafe { ssl_conf_own_cert(self.into(), (&**own_cert).into(), (&*own_pk).into()) + .into_result() + .map(|_| ()) } } - + /// Server only: configure callback to use for generating/interpreting session tickets. - pub fn set_session_tickets_callback(&mut self, cb: &'c mut F) { + pub fn set_session_tickets_callback(&mut self, cb: Arc) { unsafe { ssl_conf_session_tickets_cb( - &mut self.inner, - Some(F::call_write), - Some(F::call_parse), + self.into(), + Some(T::call_write), + Some(T::call_parse), cb.data_ptr(), ) }; + + self.ticket_callback = Some(cb); + } + + pub fn set_session_tickets(&mut self, u: UseSessionTickets) { + unsafe { ssl_conf_session_tickets(self.into(), u.into()); } } - setter!( - /// Client only: whether to remember and use session tickets - set_session_tickets(u: UseSessionTickets) = ssl_conf_session_tickets - ); - - setter!( - /// Client only: minimal FFDH group size - set_ffdh_min_bitlen(bitlen: c_uint) = ssl_conf_dhm_min_bitlen - ); - - // TODO: The lifetime restrictions on HandshakeContext here are too strict. - // Once we need something else, we might fix it. - pub fn set_sni_callback StdResult<(), ()>>( - &mut self, - cb: &'c mut F, - ) { - unsafe extern "C" fn sni_callback< - F: FnMut(&mut HandshakeContext, &[u8]) -> StdResult<(), ()>, - >( + pub fn set_renegotiation(&mut self, u: Renegotiation) { + unsafe { ssl_conf_renegotiation(self.into(), u.into()); } + } + + /// Client only: minimal FFDH group size + pub fn set_ffdh_min_bitlen(&mut self, bitlen: c_uint) { + unsafe { ssl_conf_dhm_min_bitlen(self.into(), bitlen); } + } + + pub fn set_sni_callback(&mut self, cb: F) + where + F: Fn(&mut HandshakeContext, &[u8]) -> Result<()> + Send + Sync + 'static, + { + unsafe extern "C" fn sni_callback( closure: *mut c_void, ctx: *mut ssl_context, name: *const c_uchar, name_len: size_t, - ) -> c_int { + ) -> c_int + where + F: Fn(&mut HandshakeContext, &[u8]) -> Result<()> + Send + Sync + 'static, + { + // This is called from: + // + // mbedtls/src/ssl/context.rs - establish + // mbedtls-sys/vendor/library/ssl_tls.c - mbedtls_ssl_handshake + // mbedtls-sys/vendor/library/ssl_tls.c - mbedtls_ssl_handshake_step + // mbedtls-sys/vendor/library/ssl_srv.c - mbedtls_ssl_handshake_server_step + // mbedtls-sys/vendor/library/ssl_srv.c - ssl_parse_client_hello + // mbedtls-sys/vendor/library/ssl_srv.c - ssl_parse_servername_ext + // + // As such: + // - The ssl_context is a rust 'Context' structure that we have a mutable reference to via 'establish' + // - We can pointer cast to it to allow storing additional objects. + // + if closure == ::core::ptr::null_mut() || ctx == ::core::ptr::null_mut() || name == ::core::ptr::null_mut() { + return ::mbedtls_sys::ERR_X509_BAD_INPUT_DATA; + } + let cb = &mut *(closure as *mut F); - let mut ctx = UnsafeFrom::from(ctx).expect("valid context"); + let context = &mut *(ctx as *mut Context); + + let mut ctx = HandshakeContext::init(context); + let name = from_raw_parts(name, name_len); match cb(&mut ctx, name) { Ok(()) => 0, - Err(()) => -1, + Err(_) => -1, } } - unsafe { ssl_conf_sni(&mut self.inner, Some(sni_callback::), cb as *mut F as _) } - } + self.sni_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_sni(self.into(), Some(sni_callback::), Arc::as_ptr(&mut self.sni_callback.as_ref().unwrap()) as *mut F as _) } + } + // The docs for mbedtls_x509_crt_verify say "The [callback] should return 0 for anything but a // fatal error.", so verify callbacks should return Ok(()) for anything but a fatal error. // Report verification errors by updating the flags in VerifyError. - pub fn set_verify_callback(&mut self, cb: &'c mut F) + #[cfg(feature = "threading")] + pub fn set_verify_callback(&mut self, cb: F) where - F: FnMut(&mut LinkedCertificate, i32, &mut VerifyError) -> Result<()>, + F: Fn(&Certificate, i32, &mut VerifyError) -> Result<()> + Send + Sync + 'static, { - unsafe extern "C" fn verify_callback( - closure: *mut c_void, - crt: *mut x509_crt, - depth: c_int, - flags: *mut u32, - ) -> c_int - where - F: FnMut(&mut LinkedCertificate, i32, &mut VerifyError) -> Result<()>, - { - let cb = &mut *(closure as *mut F); - let crt: &mut LinkedCertificate = - UnsafeFrom::from(crt).expect("valid certificate"); - let mut verify_error = match VerifyError::from_bits(*flags) { - Some(ve) => ve, - // This can only happen if mbedtls is setting flags in VerifyError that are - // missing from our definition. - None => return ::mbedtls_sys::ERR_X509_BAD_INPUT_DATA, - }; - let res = cb(crt, depth, &mut verify_error); - *flags = verify_error.bits(); - match res { - Ok(()) => 0, - Err(e) => e.to_int(), - } - } + self.verify_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_verify(self.into(), Some(verify_callback::), Arc::as_ptr(&mut self.verify_callback.as_ref().unwrap()) as *mut F as _) } + } - unsafe { - ssl_conf_verify( - &mut self.inner, - Some(verify_callback::), - cb as *mut F as _, - ) - } + #[cfg(not(feature = "threading"))] + pub fn set_verify_callback(&mut self, cb: F) + where + F: Fn(&Certificate, i32, &mut VerifyError) -> Result<()> + 'static, + { + self.verify_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_verify(self.into(), Some(verify_callback::), Arc::as_ptr(&mut self.verify_callback.as_ref().unwrap()) as *mut F as _) } } - pub fn set_ca_callback(&mut self, cb: &'c mut F) - where - F: FnMut(&LinkedCertificate, &mut ForeignOwnedCertListBuilder) -> Result<()>, + #[cfg(feature = "threading")] + pub fn set_ca_callback(&mut self, cb: F) + where + F: Fn(&Certificate, &mut ForeignOwnedCertListBuilder) -> Result<()> + Send + Sync + 'static, { - unsafe extern "C" fn ca_callback( - closure: *mut c_void, - child: *const x509_crt, - candidate_cas: *mut *mut x509_crt - ) -> c_int - where - F: FnMut(&LinkedCertificate, &mut ForeignOwnedCertListBuilder) -> Result<()>, - { - let cb = &mut *(closure as *mut F); - let child: &LinkedCertificate = UnsafeFrom::from(child).expect("valid child certificate"); - let mut cert_builder = ForeignOwnedCertListBuilder::new(); - match cb(child, &mut cert_builder) { - Ok(()) => { - *candidate_cas = cert_builder.to_x509_crt_ptr(); - 0 - }, - Err(e) => e.to_int(), - } - } + self.ca_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_ca_cb( self.into(), Some(ca_callback::), Arc::as_ptr(&mut self.ca_callback.as_ref().unwrap()) as *mut F as _) } + } - unsafe { - ssl_conf_ca_cb( - &mut self.inner, - Some(ca_callback::), - cb as *mut F as _, - ) - } + #[cfg(not(feature = "threading"))] + pub fn set_ca_callback(&mut self, cb: F) + where + F: Fn(&Certificate, &mut ForeignOwnedCertListBuilder) -> Result<()> + 'static, + { + self.ca_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_ca_cb( self.into(), Some(ca_callback::), Arc::as_ptr(&mut self.ca_callback.as_ref().unwrap()) as *mut F as _) } + } + + #[cfg(feature = "threading")] + pub fn set_dbg_callback(&mut self, cb: F) + where + F: (Fn(i32, &str, i32, &str) -> ()) + Send + Sync + 'static, + { + self.dbg_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_dbg(self.into(), Some(dbg_callback::), Arc::as_ptr(&mut self.dbg_callback.as_ref().unwrap()) as *mut F as _) } + } + + #[cfg(not(feature = "threading"))] + pub fn set_dbg_callback(&mut self, cb: F) + where + F: (Fn(i32, &str, i32, &str) -> ()) + 'static, + { + self.dbg_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_dbg(self.into(), Some(dbg_callback::), Arc::as_ptr(&mut self.dbg_callback.as_ref().unwrap()) as *mut F as _) } + } + +} + + +impl Drop for Config { + fn drop(&mut self) { + unsafe { ssl_config_free(self.into()); } } } /// Builds a linked list of x509_crt instances, all of which are owned by mbedtls. That is, the /// memory for these certificates has been allocated by mbedtls, on the C heap. This is needed for /// situations in which an mbedtls function takes ownership of a list of certs. The problem with -/// handing such functions a "normal" cert list such as certificate::LinkedCertificate or +/// handing such functions a "normal" cert list such as certificate::Certificate or /// certificate::List, is that those lists (at least partly) consist of memory allocated on the /// rust-side and hence cannot be freed on the c-side. pub struct ForeignOwnedCertListBuilder { @@ -354,10 +472,16 @@ impl ForeignOwnedCertListBuilder { } } - pub fn push_back(&mut self, cert: &LinkedCertificate) { + pub fn push_back(&mut self, cert: &Certificate) { self.try_push_back(cert.as_der()).expect("cert is a valid DER-encoded certificate"); } + pub fn try_push_back_pem(&mut self, cert: &[u8]) -> Result<()> { + // x509_crt_parse will allocate memory for the cert on the C heap + unsafe { x509_crt_parse(self.cert_list, cert.as_ptr(), cert.len()) }.into_result()?; + Ok(()) + } + pub fn try_push_back(&mut self, cert: &[u8]) -> Result<()> { // x509_crt_parse_der will allocate memory for the cert on the C heap unsafe { x509_crt_parse_der(self.cert_list, cert.as_ptr(), cert.len()) }.into_result()?; @@ -383,53 +507,88 @@ impl Drop for ForeignOwnedCertListBuilder { } } -setter_callback!(Config<'c>::set_rng(f: crate::rng::Random) = ssl_conf_rng); -setter_callback!(Config<'c>::set_dbg(f: DbgCallback) = ssl_conf_dbg); - -define!( - #[c_ty(ssl_key_cert)] - struct KeyCert; - impl<'a> UnsafeFrom {} -); +unsafe extern "C" fn verify_callback( + closure: *mut c_void, + crt: *mut x509_crt, + depth: c_int, + flags: *mut u32, +) -> c_int +where + F: Fn(&Certificate, i32, &mut VerifyError) -> Result<()> + 'static, +{ + if crt == ::core::ptr::null_mut() || closure == ::core::ptr::null_mut() || flags == ::core::ptr::null_mut() { + return ::mbedtls_sys::ERR_X509_BAD_INPUT_DATA; + } -pub struct KeyCertIter<'a> { - key_cert: Option<&'a KeyCert>, + let cb = &mut *(closure as *mut F); + let crt: &mut Certificate = UnsafeFrom::from(crt).expect("valid certificate"); + + let mut verify_error = match VerifyError::from_bits(*flags) { + Some(ve) => ve, + // This can only happen if mbedtls is setting flags in VerifyError that are + // missing from our definition. + None => return ::mbedtls_sys::ERR_X509_BAD_INPUT_DATA, + }; + + let res = cb(crt, depth, &mut verify_error); + *flags = verify_error.bits(); + match res { + Ok(()) => 0, + Err(e) => e.to_int(), + } } -impl<'a> Iterator for KeyCertIter<'a> { - type Item = (certificate::Iter<'a>, &'a Pk); - fn next(&mut self) -> Option { - self.key_cert.take().map(|key_cert| unsafe { - self.key_cert = UnsafeFrom::from(key_cert.inner.next as *const _); - ( - UnsafeFrom::from(key_cert.inner.cert as *const _).expect("not null"), - UnsafeFrom::from(key_cert.inner.key as *const _).expect("not null"), - ) - }) +unsafe extern "C" fn ca_callback( + closure: *mut c_void, + child: *const x509_crt, + candidate_cas: *mut *mut x509_crt +) -> c_int +where + F: Fn(&Certificate, &mut ForeignOwnedCertListBuilder) -> Result<()> + 'static, +{ + if child == ::core::ptr::null_mut() || closure == ::core::ptr::null_mut() || candidate_cas == ::core::ptr::null_mut() { + return ::mbedtls_sys::ERR_X509_BAD_INPUT_DATA; + } + + let cb = &mut *(closure as *mut F); + let crt: &Certificate = UnsafeFrom::from(child).expect("valid certificate"); + let mut cert_builder = ForeignOwnedCertListBuilder::new(); + match cb(&crt, &mut cert_builder) { + Ok(()) => { + *candidate_cas = cert_builder.to_x509_crt_ptr(); + 0 + }, + Err(e) => e.to_int(), } } -// TODO -// ssl_conf_export_keys_cb -// ssl_conf_dtls_cookies -// ssl_conf_dtls_anti_replay -// ssl_conf_dtls_badmac_limit -// ssl_conf_handshake_timeout -// ssl_conf_session_cache -// ssl_conf_psk -// ssl_conf_psk_cb -// ssl_conf_sig_hashes -// ssl_conf_alpn_protocols -// ssl_conf_fallback -// ssl_conf_encrypt_then_mac -// ssl_conf_extended_master_secret -// ssl_conf_arc4_support -// ssl_conf_max_frag_len -// ssl_conf_truncated_hmac -// ssl_conf_cbc_record_splitting -// ssl_conf_renegotiation -// ssl_conf_legacy_renegotiation -// ssl_conf_renegotiation_enforced -// ssl_conf_renegotiation_period -// +unsafe extern "C" fn dbg_callback( + closure: *mut c_void, + level: c_int, + file: *const c_char, + line: c_int, + message: *const c_char +) -> () +where + F: (Fn(i32, &str, i32, &str) -> ()) + 'static, +{ + if file == ::core::ptr::null_mut() || message == ::core::ptr::null_mut() { + return (); + } + + let cb = &mut *(closure as *mut F); + + let file = match std::ffi::CStr::from_ptr(file).to_str() { + Ok(text) => text, + Err(_) => return (), + }; + + let message = match std::ffi::CStr::from_ptr(message).to_str() { + Ok(text) => text, + Err(_) => return (), + }; + + + cb(level, file, line, message); +} diff --git a/mbedtls/src/ssl/context.rs b/mbedtls/src/ssl/context.rs index cbc17534a..7e9fdfc7c 100644 --- a/mbedtls/src/ssl/context.rs +++ b/mbedtls/src/ssl/context.rs @@ -6,42 +6,30 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ -#[cfg(not(feature = "std"))] -use core_io::{self as io, Read, Write}; -#[cfg(feature = "std")] -use std::io::{self, Read, Write}; - use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void}; use mbedtls_sys::types::size_t; use mbedtls_sys::*; - -use crate::error::{Error, IntoResult, Result}; +use std::io::{Read, Write}; +use crate::error::{Error, Result, IntoResult}; +use std::sync::Arc; +use crate::ssl::config::{Config, Version, AuthMode}; use core::result::Result as StdResult; -use crate::private::UnsafeFrom; -use crate::ssl::config::{AuthMode, Config, Version}; -use crate::x509::{Crl, LinkedCertificate, VerifyError}; +use crate::x509::VerifyError; +use crate::pk::Pk; +use crate::x509::Crl; +use std::any::Any; +use crate::x509::certificate::MbedtlsList; +use crate::x509::Certificate; pub trait IoCallback { - unsafe extern "C" fn call_recv( - user_data: *mut c_void, - data: *mut c_uchar, - len: size_t, - ) -> c_int; - unsafe extern "C" fn call_send( - user_data: *mut c_void, - data: *const c_uchar, - len: size_t, - ) -> c_int; - + unsafe extern "C" fn call_recv(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int where Self: Sized; + unsafe extern "C" fn call_send(user_data: *mut c_void, data: *const c_uchar, len: size_t) -> c_int where Self: Sized; fn data_ptr(&mut self) -> *mut c_void; + fn as_any(&mut self) -> &mut dyn Any; } -impl IoCallback for IO { - unsafe extern "C" fn call_recv( - user_data: *mut c_void, - data: *mut c_uchar, - len: size_t, - ) -> c_int { +impl IoCallback for IO { + unsafe extern "C" fn call_recv(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int { let len = if len > (c_int::max_value() as size_t) { c_int::max_value() as size_t } else { @@ -53,11 +41,7 @@ impl IoCallback for IO { } } - unsafe extern "C" fn call_send( - user_data: *mut c_void, - data: *const c_uchar, - len: size_t, - ) -> c_int { + unsafe extern "C" fn call_send(user_data: *mut c_void, data: *const c_uchar, len: size_t) -> c_int { let len = if len > (c_int::max_value() as size_t) { c_int::max_value() as size_t } else { @@ -72,65 +56,109 @@ impl IoCallback for IO { fn data_ptr(&mut self) -> *mut c_void { self as *mut IO as *mut _ } + + fn as_any(&mut self) -> &mut dyn Any { + self + } } -define!( - #[c_ty(ssl_context)] - struct Context<'config>; - const init: fn() -> Self = ssl_init; - const drop: fn(&mut Self) = ssl_free; - impl<'a> Into {} - impl<'a> UnsafeFrom {} -); - -pub struct Session<'ctx> { - inner: &'ctx mut ssl_context, +// We need repr(C) because we need to cast from ssl_context and back +#[repr(C)] +pub struct Context { + // This needs to always be first (and class of type repr(C)) so that casting to and from Context works. + inner: ssl_context, + + // config is used read-only for mutliple contexts and is immutable once configured. + #[allow(dead_code)] + config: Option>, + + // Must be held in heap and pointer to it as pointer is sent to MbedSSL and can't be re-allocated. + #[allow(dead_code)] + io: Option>, + + handshake_ca_cert: Option>>, + handshake_crl: Option>, + + handshake_cert: Vec>>, + handshake_pk: Vec>, } -#[cfg(feature = "threading")] -unsafe impl<'ctx> Send for Session<'ctx> {} +impl Into<*mut mbedtls_sys::ssl_context> for &mut Context { + fn into(self) -> *mut mbedtls_sys::ssl_context { + &mut self.inner + } +} -pub struct HandshakeContext<'ctx> { - inner: &'ctx mut ssl_context, +impl Into<*const mbedtls_sys::ssl_context> for &Context { + fn into(self) -> *const mbedtls_sys::ssl_context { + &self.inner + } } -impl<'config> Context<'config> { - pub fn new(config: &'config Config) -> Result> { - let mut ret = Self::init(); - unsafe { ssl_setup(&mut ret.inner, config.into()) } - .into_result() - .map(|_| ret) + +#[allow(dead_code)] +impl Context { + pub fn new(config: Arc) -> Self { + let mut inner = ssl_context::default(); + + unsafe { + ssl_init(&mut inner); + ssl_setup(&mut inner, (&*config).into()); + }; + + Context { + inner, + config: Some(config.clone()), + io: None, + + handshake_ca_cert: None, + handshake_crl: None, + + handshake_cert: vec![], + handshake_pk: vec![], + } } - pub fn establish<'c, F: IoCallback>( - &'c mut self, - io: &'c mut F, - hostname: Option<&str>, - ) -> Result> { + pub fn establish(&mut self, io: T, hostname: Option<&str>) -> Result<()> { + self.handshake_cert.clear(); + self.handshake_pk.clear(); + self.handshake_ca_cert = None; + self.handshake_crl = None; + unsafe { - ssl_session_reset(&mut self.inner).into_result()?; + let mut io = Box::new(io); + + ssl_session_reset(self.into()).into_result()?; self.set_hostname(hostname)?; + let ptr = &mut *io as *mut _ as *mut c_void; ssl_set_bio( - &mut self.inner, - io.data_ptr(), - Some(F::call_send), - Some(F::call_recv), + self.into(), + ptr, + Some(T::call_send), + Some(T::call_recv), None, ); - match ssl_handshake(&mut self.inner).into_result() { + + self.io = Some(io); + + match ssl_handshake(self.into()).into_result() { Err(e) => { // safely end borrow of io - ssl_set_bio(&mut self.inner, ::core::ptr::null_mut(), None, None, None); + ssl_set_bio(self.into(), ::core::ptr::null_mut(), None, None, None); + self.io = None; Err(e) + }, + Ok(_) => { + Ok(()) } - Ok(_) => Ok(Session { - inner: &mut self.inner, - }), } } } +} +impl Context { + #[allow(dead_code)] #[cfg(not(feature = "std"))] fn set_hostname(&mut self, hostname: Option<&str>) -> Result<()> { match hostname { @@ -139,16 +167,13 @@ impl<'config> Context<'config> { } } + #[allow(dead_code)] #[cfg(feature = "std")] fn set_hostname(&mut self, hostname: Option<&str>) -> Result<()> { - if self.inner.hostname != ::core::ptr::null_mut() { - // potential MEMORY LEAK! See https://github.com/ARMmbed/mbedtls/issues/836 - self.inner.hostname = ::core::ptr::null_mut(); - } if let Some(s) = hostname { let cstr = ::std::ffi::CString::new(s).map_err(|_| Error::SslBadInputData)?; unsafe { - ssl_set_hostname(&mut self.inner, cstr.as_ptr()) + ssl_set_hostname(self.into(), cstr.as_ptr()) .into_result() .map(|_| ()) } @@ -158,70 +183,37 @@ impl<'config> Context<'config> { } pub fn verify_result(&self) -> StdResult<(), VerifyError> { - match unsafe { ssl_get_verify_result(&self.inner) } { + match unsafe { ssl_get_verify_result(self.into()) } { 0 => Ok(()), flags => Err(VerifyError::from_bits_truncate(flags)), } } - pub fn config(&self) -> &'config Config { - unsafe { UnsafeFrom::from(self.inner.conf).expect("not null") } + pub fn config(&self) -> &Option> { + &self.config } -} - -impl<'ctx> HandshakeContext<'ctx> { - pub fn set_authmode(&mut self, am: AuthMode) { - unsafe { ssl_set_hs_authmode(self.inner, am.into()) } - } - - pub fn set_ca_list>( - &mut self, - list: Option, - crl: Option<&'ctx mut Crl>, - ) { + + #[allow(dead_code)] + pub fn close(&mut self) { unsafe { - ssl_set_hs_ca_chain( - self.inner, - list.map(Into::into) - .map(Into::into) - .unwrap_or(::core::ptr::null_mut()), - crl.map(Into::into).unwrap_or(::core::ptr::null_mut()), - ) + ssl_close_notify(self.into()); + ssl_set_bio(self.into(), ::core::ptr::null_mut(), None, None, None); + self.io = None; } } - /// If this is never called, will use the set of private keys and - /// certificates configured in the `Config` associated with this `Context`. - /// If this is called at least once, all those are ignored and the set - /// specified using this function is used. - pub fn push_cert>( - &mut self, - chain: C, - key: &'ctx mut crate::pk::Pk, - ) -> Result<()> { - unsafe { - ssl_set_hs_own_cert(self.inner, chain.into().into(), key.into()) - .into_result() - .map(|_| ()) + pub fn get_mut_io(&mut self) -> std::io::Result<&mut T> { + match self.io.as_mut() { + Some(stream) => { + match stream.as_any().downcast_mut::() { + Some(s) => Ok(s), + None => Err(std::io::Error::new(std::io::ErrorKind::NotFound, "Peer kind is not expected")), + } + } + None => Err(std::io::Error::new(std::io::ErrorKind::NotFound, "No peer available")), } } -} - -impl<'ctx> ::core::ops::Deref for HandshakeContext<'ctx> { - type Target = Context<'ctx>; - - fn deref(&self) -> &Context<'ctx> { - unsafe { UnsafeFrom::from(&*self.inner as *const _).expect("not null") } - } -} - -impl<'ctx> UnsafeFrom<*mut ssl_context> for HandshakeContext<'ctx> { - unsafe fn from(ctx: *mut ssl_context) -> Option> { - ctx.as_mut().map(|ctx| HandshakeContext { inner: ctx }) - } -} - -impl<'a> Session<'a> { + /// Return the minor number of the negotiated TLS version pub fn minor_version(&self) -> i32 { self.inner.minor_ver @@ -235,7 +227,7 @@ impl<'a> Session<'a> { /// Return the number of bytes currently available to read that /// are stored in the Session's internal read buffer pub fn bytes_available(&self) -> usize { - unsafe { ssl_get_bytes_avail(self.inner) } + unsafe { ssl_get_bytes_avail(self.into()) } } pub fn version(&self) -> Version { @@ -251,32 +243,49 @@ impl<'a> Session<'a> { } } + + // Session specific functions + /// Return the 16-bit ciphersuite identifier. /// All assigned ciphersuites are listed by the IANA in /// https://www.iana.org/assignments/tls-parameters/tls-parameters.txt - pub fn ciphersuite(&self) -> u16 { + pub fn ciphersuite(&self) -> Result { if self.inner.session == ::core::ptr::null_mut() { - 0 - } else { - unsafe { self.inner.session.as_ref().unwrap().ciphersuite as u16 } + return Err(Error::SslBadInputData); } + + Ok(unsafe { self.inner.session.as_ref().unwrap().ciphersuite as u16 }) } - pub fn peer_cert(&self) -> Option { - unsafe { UnsafeFrom::from(ssl_get_peer_cert(self.inner)) } + // This makes a copy of the certificate as peer_cert may be destroyed outside our control. + pub fn peer_cert(&self) -> Result>> { + unsafe { + // ssl_get_peer_cert checks for NULL unlike other functions. + let peer_cert = ssl_get_peer_cert(self.into()); + + if peer_cert as *const _ == ::core::ptr::null() { + return Err(Error::SslBadInputData); + } + + let cert = MbedtlsList::::from_cert(&*peer_cert); + Ok(Some(cert)) + } } +} - pub fn verify_result(&self) -> StdResult<(), VerifyError> { - match unsafe { ssl_get_verify_result(self.inner) } { - 0 => Ok(()), - flags => Err(VerifyError::from_bits_truncate(flags)), +impl Drop for Context { + fn drop(&mut self) { + unsafe { + ssl_close_notify(self.into()); + ssl_set_bio(self.into(), ::core::ptr::null_mut(), None, None, None); + ssl_free(self.into()); } } } -impl<'a> Read for Session<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match unsafe { ssl_read(self.inner, buf.as_mut_ptr(), buf.len()).into_result() } { +impl Read for Context { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + match unsafe { ssl_read(self.into(), buf.as_mut_ptr(), buf.len()).into_result() } { Err(Error::SslPeerCloseNotify) => Ok(0), Err(e) => Err(crate::private::error_to_io_error(e)), Ok(i) => Ok(i as usize), @@ -284,29 +293,105 @@ impl<'a> Read for Session<'a> { } } -impl<'a> Write for Session<'a> { - fn write(&mut self, buf: &[u8]) -> io::Result { - match unsafe { ssl_write(self.inner, buf.as_ptr(), buf.len()).into_result() } { +impl Write for Context { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + match unsafe { ssl_write(self.into(), buf.as_ptr(), buf.len()).into_result() } { Err(Error::SslPeerCloseNotify) => Ok(0), Err(e) => Err(crate::private::error_to_io_error(e)), Ok(i) => Ok(i as usize), } } - fn flush(&mut self) -> io::Result<()> { + fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } -impl<'a> Drop for Session<'a> { - fn drop(&mut self) { + +pub struct HandshakeContext<'ctx> { + pub context: &'ctx mut Context, +} + +/// +/// Class exists only during SNI callback that is configured from Config. +/// SNI Callback must provide input whos lifetime exceed the SNI closure to avoid memory corruptions. +/// That can be achieved easily by storing certificate chains/crls inside the closure for the lifetime of the closure. +/// +/// That is due to SNI being held by an Arc inside Config. +/// Config lives longer then Context. Context lives longer then Handshake. +/// +/// Alternatives are not possible due to: +/// - mbedtls not providing any callbacks on handshake finish. +/// - no reasonable way to obtain a storage within the sni callback tied to the handshake or to the rust Context. (without resorting to a unscalable map or pointer magic that mbedtls may invalidate) +/// +impl<'ctx> HandshakeContext<'ctx> { + + pub fn init(context: &'ctx mut Context) -> Self { + HandshakeContext { context } + } + + pub fn set_authmode(&mut self, am: AuthMode) -> Result<()> { + if self.context.inner.handshake as *const _ == ::core::ptr::null() { + return Err(Error::SslBadInputData); + } + + unsafe { ssl_set_hs_authmode(self.context.into(), am as i32) } + Ok(()) + } + + /// @warning: chain/crl must live the same as the SNI callback otherwise risk of dangling pointers. + pub fn set_ca_list( + &mut self, + chain: Arc>, + crl: Option>, + ) -> Result<()> { + // mbedtls_ssl_set_hs_ca_chain does not check for NULL handshake. + if self.context.inner.handshake as *const _ == ::core::ptr::null() { + return Err(Error::SslBadInputData); + } + + // This will override current handshake CA chain. + unsafe { + ssl_set_hs_ca_chain( + self.context.into(), + (&**chain).into(), + crl.as_ref().map(|crl| (&(**crl)).into()).unwrap_or(::core::ptr::null_mut()), + ); + } + + self.context.handshake_ca_cert = Some(chain); + self.context.handshake_crl = crl; + Ok(()) + } + + /// If this is never called, will use the set of private keys and + /// certificates configured in the `Config` associated with this `Context`. + /// If this is called at least once, all those are ignored and the set + /// specified using this function is used. + /// + /// @warning: chain/key must live the same as the SNI callback otherwise risk of dangling pointers. + pub fn push_cert( + &mut self, + chain: Arc>, + key: Arc, + ) -> Result<()> { + // mbedtls_ssl_set_hs_own_cert does not check for NULL handshake. + if self.context.inner.handshake as *const _ == ::core::ptr::null() { + return Err(Error::SslBadInputData); + } + + // This will append provided certificate pointers in internal structures. unsafe { - ssl_close_notify(self.inner); - ssl_set_bio(self.inner, ::core::ptr::null_mut(), None, None, None); + ssl_set_hs_own_cert(self.context.into(), (&**chain).into(), (&*key).into()).into_result()?; } + self.context.handshake_cert.push(chain); + self.context.handshake_pk.push(key); + + Ok(()) } } + // ssl_get_alpn_protocol // ssl_get_max_frag_len // ssl_get_record_expansion diff --git a/mbedtls/src/ssl/mod.rs b/mbedtls/src/ssl/mod.rs index ea79153b1..430d439ea 100644 --- a/mbedtls/src/ssl/mod.rs +++ b/mbedtls/src/ssl/mod.rs @@ -14,8 +14,8 @@ pub mod ticket; #[doc(inline)] pub use self::ciphersuites::CipherSuite; #[doc(inline)] -pub use self::config::{Config, Version}; +pub use self::config::{Config, Version, UseSessionTickets}; #[doc(inline)] -pub use self::context::{Context, HandshakeContext, Session}; +pub use self::context::Context; #[doc(inline)] pub use self::ticket::TicketContext; diff --git a/mbedtls/src/ssl/ticket.rs b/mbedtls/src/ssl/ticket.rs index 77ce26777..54bec3bc8 100644 --- a/mbedtls/src/ssl/ticket.rs +++ b/mbedtls/src/ssl/ticket.rs @@ -11,6 +11,8 @@ use crate::error::{IntoResult, Result}; use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void}; use mbedtls_sys::types::size_t; use mbedtls_sys::*; +use std::sync::Arc; +use crate::rng::RngCallback; pub trait TicketCallback { unsafe extern "C" fn call_write( @@ -20,46 +22,69 @@ pub trait TicketCallback { end: *const c_uchar, tlen: *mut size_t, lifetime: *mut u32, - ) -> c_int; + ) -> c_int where Self: Sized; unsafe extern "C" fn call_parse( p_ticket: *mut c_void, session: *mut ssl_session, buf: *mut c_uchar, len: size_t, - ) -> c_int; + ) -> c_int where Self: Sized; - fn data_ptr(&mut self) -> *mut c_void; + fn data_ptr(&self) -> *mut c_void; } -define!( - #[c_ty(ssl_ticket_context)] - struct TicketContext<'rng>; - const init: fn() -> Self = ssl_ticket_init; - const drop: fn(&mut Self) = ssl_ticket_free; -); +pub struct TicketContext { + inner: Box, -impl<'rng> TicketContext<'rng> { - pub fn new( - rng: &'rng mut F, + // We set rng from constructur, we never read it directly. It is only used to ensure rng lives as long as we need. + #[allow(dead_code)] + rng: Arc, +} + +#[cfg(feature = "threading")] +unsafe impl Sync for TicketContext {} + +#[cfg(feature = "threading")] +unsafe impl Send for TicketContext {} + + +impl Drop for TicketContext { + fn drop(&mut self) { + unsafe { ssl_ticket_free(self.into()); } + } +} + +impl Into<*mut mbedtls_sys::ssl_ticket_context> for &mut TicketContext { + fn into(self) -> *mut mbedtls_sys::ssl_ticket_context { + &mut *self.inner + } +} + +impl TicketContext { + pub fn new( + rng: Arc, cipher: CipherType, lifetime: u32, - ) -> Result> { - let mut ret = Self::init(); + ) -> Result { + + let mut inner = Box::new(ssl_ticket_context::default()); + unsafe { + ssl_ticket_init(&mut *inner); ssl_ticket_setup( - &mut ret.inner, - Some(F::call), + &mut *inner, + Some(T::call), rng.data_ptr(), cipher.into(), lifetime, - ) + ).into_result()?; } - .into_result() - .map(|_| ret) + + Ok(TicketContext { inner, rng }) } } -impl<'rng> TicketCallback for TicketContext<'rng> { +impl TicketCallback for TicketContext { unsafe extern "C" fn call_write( p_ticket: *mut c_void, session: *const ssl_session, @@ -80,7 +105,7 @@ impl<'rng> TicketCallback for TicketContext<'rng> { ssl_ticket_parse(p_ticket, session, buf, len) } - fn data_ptr(&mut self) -> *mut c_void { - &mut self.inner as *mut _ as *mut _ + fn data_ptr(&self) -> *mut c_void { + &*self.inner as *const _ as *mut _ } } diff --git a/mbedtls/src/wrapper_macros.rs b/mbedtls/src/wrapper_macros.rs index dba58ea33..e4e06e817 100644 --- a/mbedtls/src/wrapper_macros.rs +++ b/mbedtls/src/wrapper_macros.rs @@ -15,45 +15,82 @@ macro_rules! as_item { macro_rules! callback { //{ ($($arg:ident: $ty:ty),*) -> $ret:ty } => { //}; - { $n:ident$( : $sync:ident )*($($arg:ident: $ty:ty),*) -> $ret:ty } => { + { $n:ident, $m:ident$( : $sync:ident )*($($arg:ident: $ty:ty),*) -> $ret:ty } => { #[cfg(not(feature="threading"))] pub trait $n { - unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret; + unsafe extern "C" fn call_mut(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized; - fn data_ptr(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void; + fn data_ptr_mut(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void; } #[cfg(feature="threading")] pub trait $n $( : $sync )* { - unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret; + unsafe extern "C" fn call_mut(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized; - fn data_ptr(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void; + fn data_ptr_mut(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void; } #[cfg(not(feature="threading"))] impl $n for F where F: FnMut($($ty),*) -> $ret { - unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret { + unsafe extern "C" fn call_mut(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized { (&mut*(user_data as *mut F))($($arg),*) } - fn data_ptr(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void { + fn data_ptr_mut(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void { self as *mut F as *mut _ } } #[cfg(feature="threading")] impl $n for F where F: Sync + FnMut($($ty),*) -> $ret { - unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret { + unsafe extern "C" fn call_mut(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized { (&mut*(user_data as *mut F))($($arg),*) } - fn data_ptr(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void { - self as *mut F as *mut _ + fn data_ptr_mut(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void { + self as *const F as *mut _ + } + } + + #[cfg(not(feature="threading"))] + pub trait $m { + unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized; + + fn data_ptr(&self) -> *mut ::mbedtls_sys::types::raw_types::c_void; + } + + #[cfg(feature="threading")] + pub trait $m $( : $sync )* { + unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized; + + fn data_ptr(&self) -> *mut ::mbedtls_sys::types::raw_types::c_void; + } + + #[cfg(not(feature="threading"))] + impl $m for F where F: $n + Fn($($ty),*) -> $ret { + unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized { + (&mut*(user_data as *mut F))($($arg),*) + } + + fn data_ptr(&self) -> *mut ::mbedtls_sys::types::raw_types::c_void { + self as *const F as *mut F as *mut _ + } + } + + #[cfg(feature="threading")] + impl $m for F where F: $n + Sync + Fn($($ty),*) -> $ret { + unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized { + (&mut*(user_data as *mut F))($($arg),*) + } + + fn data_ptr(&self) -> *mut ::mbedtls_sys::types::raw_types::c_void { + self as *const F as *mut _ } } }; } +// TODO: simplify and reuse where possible macro_rules! define { { #[c_ty($inner:ident)] $(#[$m:meta])* struct $name:ident$(<$l:tt>)*; $($defs:tt)* } => { define_struct!(define $(#[$m])* struct $name $(lifetime $l)* inner $inner); @@ -226,44 +263,4 @@ macro_rules! define_struct { { lifetime $l:tt } => {}; } -macro_rules! setter { - { $(#[$m:meta])* $rfn:ident($n:ident : $rty:ty) = $cfn:ident } => { - $(#[$m])* - pub fn $rfn(&mut self, $n: $rty) { - unsafe{::mbedtls_sys::$cfn(&mut self.inner,$n.into())} - } - } -} - -// can't make this work without as as_XXX! macro, and there is no as_method!... -macro_rules! setter_callback { - { $(#[$m:meta])* $s:ident<$l:tt>::$rfn:ident($n:ident : $($rty:tt)+) = $cfn:ident } => { - as_item!( - impl<$l> $s<$l> { - $(#[$m])* - pub fn $rfn(&mut self, $n: Option<&$l mut F>) { - unsafe{::mbedtls_sys::$cfn( - &mut self.inner, - $n.as_ref().map(|_|F::call as _), - $n.map(|f|f.data_ptr()).unwrap_or(::core::ptr::null_mut()) - )} - } - } - ); - } -} - -macro_rules! getter { - { $(#[$m:meta])* $rfn:ident() -> $rty:ty = .$cfield:ident } => { - $(#[$m])* - pub fn $rfn(&self) -> $rty { - self.inner.$cfield.into() - } - }; - { $(#[$m:meta])* $rfn:ident() -> $rty:ty = fn $cfn:ident } => { - $(#[$m])* - pub fn $rfn(&self) -> $rty { - unsafe{::mbedtls_sys::$cfn(&self.inner).into()} - } - }; -} +// TODO: Bring back getter/setter macros \ No newline at end of file diff --git a/mbedtls/src/x509/certificate.rs b/mbedtls/src/x509/certificate.rs index 65506557f..e0e168667 100644 --- a/mbedtls/src/x509/certificate.rs +++ b/mbedtls/src/x509/certificate.rs @@ -7,24 +7,27 @@ * according to those terms. */ use core::fmt; -use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; -use core::ptr; #[cfg(not(feature = "std"))] use crate::alloc_prelude::*; use mbedtls_sys::types::raw_types::c_char; use mbedtls_sys::*; +use crate::x509::Time; #[cfg(feature = "std")] use yasna::{BERDecodable, BERReader, ASN1Result, ASN1Error, ASN1ErrorKind, models::ObjectIdentifier}; - -use crate::pk::Pk; use crate::error::{Error, IntoResult, Result}; -use crate::private::UnsafeFrom; -use crate::rng::Random; use crate::hash::Type as MdType; +use crate::pk::Pk; +use crate::rng::Random; +use crate::private::UnsafeFrom; +use crate::{forward_mbedtls_calloc, forward_mbedtls_free}; +use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; +use mbedtls_sys::types::raw_types::c_void; +use core::ptr::drop_in_place; +use core::marker::PhantomData; #[derive(Debug,Copy,Clone,Eq,PartialEq)] pub enum CertificateVersion { @@ -33,12 +36,10 @@ pub enum CertificateVersion { V3 } -define!( - #[c_ty(x509_crt)] - struct Certificate; - const init: fn() -> Self = x509_crt_init; - const drop: fn(&mut Self) = x509_crt_free; -); +#[repr(C)] +pub struct MbedtlsList { + inner: NonNull +} #[cfg(feature = "std")] #[derive(Debug, Clone, Eq, PartialEq)] @@ -60,88 +61,127 @@ impl BERDecodable for Extension { } } -impl Certificate { - pub fn from_der(der: &[u8]) -> Result { - let mut ret = Self::init(); - unsafe { x509_crt_parse_der(&mut ret.inner, der.as_ptr(), der.len()) }.into_result()?; - Ok(ret) - } +//TODO: Provide MbedtlsBox as well for single certificate storage - /// Input must be NULL-terminated - pub fn from_pem(pem: &[u8]) -> Result { - let mut ret = Self::init(); - unsafe { x509_crt_parse(&mut ret.inner, pem.as_ptr(), pem.len()) }.into_result()?; - let mut fake = Self::init(); - ::core::mem::swap(&mut fake.inner.next, &mut ret.inner.next); - Ok(ret) - } +#[cfg(feature = "threading")] +unsafe impl<> Send for MbedtlsList {} - /// Input must be NULL-terminated - #[cfg(buggy)] - pub fn from_pem_multiple(pem: &[u8]) -> Result> { - let mut vec; +#[cfg(feature = "threading")] +unsafe impl<> Sync for MbedtlsList {} + +impl<> MbedtlsList { + fn new() -> Result { unsafe { - // first, find out how many certificates we're parsing - let mut dummy = Certificate::init(); - x509_crt_parse(&mut dummy.inner, pem.as_ptr(), pem.len()).into_result()?; + let inner = forward_mbedtls_calloc(1, core::mem::size_of::()) as *mut x509_crt; + if inner == core::ptr::null_mut() { + return Err(Error::SslAllocFailed); + } + + x509_crt_init(inner); + Ok(Self { inner: NonNull::new_unchecked(inner as *mut Certificate) }) + } + } - // then allocate enough certs with our allocator - vec = Vec::new(); - let mut cur: *mut _ = &mut dummy.inner; + pub fn from_der(der: &[u8]) -> Result { + let mut cert = Self::new()?; + cert.push_back_der(der)?; + Ok(cert) + } + + pub fn from_pem(pem_or_der: &[u8]) -> Result { + let mut cert = Self::new()?; + cert.push_back(pem_or_der)?; + Ok(cert) + } + + pub fn from_cert(source: &x509_crt) -> Self { + unsafe { + let der = std::slice::from_raw_parts(source.raw.p, source.raw.len); + let mut cert = Self::from_der(&der).expect("Failed re-parsing existing DER"); + + let mut cur = source.next; while cur != ::core::ptr::null_mut() { - vec.push(Certificate::init()); + let der = std::slice::from_raw_parts((*cur).raw.p, (*cur).raw.len); + cert.push_back_der(&der).expect("Failed re-parsing existing DER"); cur = (*cur).next; } + + cert + } + } - // link them together, they will become unlinked again when List drops - let list = List::from_vec(&mut vec).unwrap(); + pub fn push_back_der(&mut self, der: &[u8]) -> Result<()> { + unsafe { x509_crt_parse_der(self.inner.as_ref().into(), der.as_ptr(), der.len()) }.into_result()?; + Ok(()) + } + + pub fn push_back(&mut self, pem_or_der: &[u8]) -> Result<()> { + unsafe { x509_crt_parse(self.inner.as_ref().into(), pem_or_der.as_ptr(), pem_or_der.len()) }.into_result()?; + Ok(()) + } - // load the data again but into our allocated list - x509_crt_parse(&mut list.head.inner, pem.as_ptr(), pem.len()).into_result()?; - }; - Ok(vec) + pub fn push_back_list(&mut self, other: MbedtlsList::) { + unsafe { + let mut i : *mut x509_crt = self.inner.as_ref().into(); + while (*i).next != ::core::ptr::null_mut() { + i = (*i).next; + } + (*i).next = other.inner.as_ref().into(); + core::mem::forget(other); + } + } + + pub fn iter(&self) -> Iter<'_> { + unsafe { + Iter { + next: self.inner.as_ref().into(), + r: PhantomData, + } + } } } -impl fmt::Debug for Certificate { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match crate::private::alloc_string_repeat(|buf, size| unsafe { - x509_crt_info(buf, size, b"\0".as_ptr() as *const _, &self.inner) - }) { - Err(_) => Err(fmt::Error), - Ok(s) => f.write_str(&s), +impl Drop for MbedtlsList { + fn drop(&mut self) { + unsafe { + drop_in_place(self.inner.as_ptr()); + forward_mbedtls_free(self.inner.as_ptr() as *mut c_void) } } } -impl Clone for Certificate { - fn clone(&self) -> Certificate { - let mut ret = Self::init(); +impl<> Clone for MbedtlsList { + fn clone(&self) -> MbedtlsList { unsafe { - x509_crt_parse_der(&mut ret.inner, self.inner.raw.p, self.inner.raw.len) - .into_result() - .unwrap() - }; - ret + Self::from_cert(&self.inner.as_ref().inner) + } } } -impl Deref for Certificate { - type Target = LinkedCertificate; - fn deref(&self) -> &LinkedCertificate { - unsafe { UnsafeFrom::from(&self.inner as *const _).unwrap() } +impl Deref for MbedtlsList { + type Target = T; + fn deref(&self) -> &T { + unsafe { self.inner.as_ref() } } } -impl DerefMut for Certificate { - fn deref_mut(&mut self) -> &mut LinkedCertificate { - unsafe { UnsafeFrom::from(&mut self.inner as *mut _).unwrap() } +impl DerefMut for MbedtlsList { + fn deref_mut(&mut self) -> &mut T { + unsafe { self.inner.as_mut() } } } #[repr(C)] -pub struct LinkedCertificate { - inner: x509_crt, +pub struct Certificate { + pub inner: x509_crt +} + +impl Drop for Certificate { + fn drop(&mut self) { + unsafe { + x509_crt_free(self.into()); + } + } } fn x509_buf_to_vec(buf: &x509_buf) -> Vec { @@ -153,16 +193,17 @@ fn x509_buf_to_vec(buf: &x509_buf) -> Vec { slice.to_owned() } -fn x509_time_to_time(tm: &x509_time) -> Result { +fn x509_time_to_time(tm: &x509_time) -> Result