diff --git a/Cargo.lock b/Cargo.lock index faeb7fbea..441be4813 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,15 @@ name = "autocfg" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bindgen" version = "0.19.2" @@ -171,11 +180,52 @@ name = "glob" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hermit-abi" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.10.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -185,6 +235,11 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "0.2.11" @@ -238,6 +293,7 @@ dependencies = [ "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)", + "hyper 0.10.16 (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.24.0", @@ -277,6 +333,14 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nom" version = "3.2.1" @@ -302,11 +366,25 @@ dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pkg-config" version = "0.3.16" @@ -413,6 +491,11 @@ dependencies = [ "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "semver" version = "0.1.20" @@ -543,11 +626,58 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tinyvec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "traitobject" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "typenum" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tinyvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-xid" version = "0.0.3" @@ -558,6 +688,16 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "0.1.3" @@ -568,6 +708,11 @@ name = "vcpkg" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.2.8" @@ -605,6 +750,7 @@ 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 base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "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" @@ -626,8 +772,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +"checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "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" @@ -636,10 +787,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "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 num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "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" @@ -654,6 +808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "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" @@ -669,11 +824,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 tinyvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +"checksum tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" "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 url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "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 version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "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" diff --git a/bors.toml b/bors.toml index ca08e818b..9db31cca7 100644 --- a/bors.toml +++ b/bors.toml @@ -1,3 +1,4 @@ status = [ "continuous-integration/travis-ci/push", ] +timeout_sec = 36000 # ten hours diff --git a/ct.sh b/ct.sh index fc3c3bd42..f34e63f2d 100755 --- a/ct.sh +++ b/ct.sh @@ -19,6 +19,7 @@ if [ $TRAVIS_RUST_VERSION = "stable" ] || [ $TRAVIS_RUST_VERSION = "beta" ] || [ cargo test --features pkcs12 cargo test --features pkcs12_rc2 cargo test --features force_aesni_support + cargo test --features default,pthread elif [ $TRAVIS_RUST_VERSION = $CORE_IO_NIGHTLY ]; then cargo +$CORE_IO_NIGHTLY test --no-default-features --features core_io,rdrand,time,custom_time,custom_gmtime_r diff --git a/mbedtls-sys/Cargo.toml b/mbedtls-sys/Cargo.toml index 6b1ab3505..90d90ce57 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" [lib] name = "mbedtls_sys" diff --git a/mbedtls-sys/build/cmake.rs b/mbedtls-sys/build/cmake.rs index 673ed3903..767684ba1 100644 --- a/mbedtls-sys/build/cmake.rs +++ b/mbedtls-sys/build/cmake.rs @@ -49,5 +49,8 @@ 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()); + println!("cargo:config_h={}", self.config_h.to_str().expect("config.h UTF-8 error")); } } diff --git a/mbedtls/Cargo.toml b/mbedtls/Cargo.toml index f9605a243..4344121fb 100644 --- a/mbedtls/Cargo.toml +++ b/mbedtls/Cargo.toml @@ -44,6 +44,7 @@ rand = "0.4.0" serde_cbor = "0.6" hex = "0.3" matches = "0.1.8" +hyper = { version = "0.10.16", default-features = false } [build-dependencies] cc = "1.0" @@ -119,3 +120,9 @@ required-features = ["std"] name = "ssl_conf_verify" path = "tests/ssl_conf_verify.rs" required-features = ["std"] + + +[[test]] +name = "hyper" +path = "tests/hyper.rs" +required-features = ["std", "threading"] diff --git a/mbedtls/build.rs b/mbedtls/build.rs index 004c8a9c1..f19fd340a 100644 --- a/mbedtls/build.rs +++ b/mbedtls/build.rs @@ -12,6 +12,12 @@ use std::env; fn main() { let mut b = cc::Build::new(); + b.include(env::var_os("DEP_MBEDTLS_INCLUDE").expect("Links was not properly set in mbedtls-sys package, missing DEP_MBEDTLS_INCLUDE")); + let config_file = format!("\"{}\"", env::var_os("DEP_MBEDTLS_CONFIG_H").expect("Links was not properly set in mbedtls-sys package, missing DEP_MBEDTLS_CONFIG_H").to_str().unwrap()); + b.define("MBEDTLS_CONFIG_FILE", + Some(config_file.as_str())); + + b.file("src/mbedtls_malloc.c"); b.file("src/rust_printf.c"); if env::var_os("CARGO_FEATURE_STD").is_none() || ::std::env::var("TARGET") diff --git a/mbedtls/examples/client.rs b/mbedtls/examples/client.rs index 9dcb907a6..18de85ba7 100644 --- a/mbedtls/examples/client.rs +++ b/mbedtls/examples/client.rs @@ -10,6 +10,7 @@ extern crate mbedtls; use std::io::{self, stdin, stdout, Write}; use std::net::TcpStream; +use std::sync::Arc; use mbedtls::rng::CtrDrbg; use mbedtls::ssl::config::{Endpoint, Preset, Transport}; @@ -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::ROOT_CA_CERT)?; + let entropy = Arc::new(entropy_new()); + let rng = Arc::new(CtrDrbg::new(entropy, None)?); + let cert = Arc::new(Certificate::from_pem_multiple(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..1ff5c5a5a 100644 --- a/mbedtls/examples/server.rs +++ b/mbedtls/examples/server.rs @@ -10,6 +10,7 @@ extern crate mbedtls; use std::io::{BufRead, BufReader, Write}; use std::net::{TcpListener, TcpStream}; +use std::sync::Arc; use mbedtls::pk::Pk; use mbedtls::rng::CtrDrbg; @@ -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(Certificate::from_pem_multiple(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/alloc.rs b/mbedtls/src/alloc.rs new file mode 100644 index 000000000..12883277e --- /dev/null +++ b/mbedtls/src/alloc.rs @@ -0,0 +1,65 @@ +/* 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. */ + +use core::fmt; +use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; +use core::ptr::drop_in_place; +use core::mem::ManuallyDrop; + +use mbedtls_sys::types::raw_types::c_void; + +extern "C" { + pub(crate) fn forward_mbedtls_free(n: *mut mbedtls_sys::types::raw_types::c_void); +} + +#[repr(transparent)] +pub struct Box { + pub(crate) inner: NonNull +} + +impl Box { + pub(crate) fn into_raw(self) -> *mut T { + let v = ManuallyDrop::new(self); + v.inner.as_ptr() + } +} + +impl Deref for Box { + type Target = T; + fn deref(&self) -> &T { + unsafe { self.inner.as_ref() } + } +} + +impl DerefMut for Box { + fn deref_mut(&mut self) -> &mut T { + unsafe { self.inner.as_mut() } + } +} + +impl fmt::Debug for Box { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl Drop for Box { + fn drop(&mut self) { + unsafe { + drop_in_place(self.inner.as_ptr()); + forward_mbedtls_free(self.inner.as_ptr() as *mut c_void) + } + } +} + +#[repr(transparent)] +pub struct List { + pub(crate) inner: Option> +} + diff --git a/mbedtls/src/lib.rs b/mbedtls/src/lib.rs index a5e15df43..b98ca07ff 100644 --- a/mbedtls/src/lib.rs +++ b/mbedtls/src/lib.rs @@ -15,7 +15,7 @@ const ERROR: _MUST_USE_EITHER_STD_OR_CORE_IO_ = (); #[cfg(not(feature = "std"))] #[macro_use] -extern crate alloc; +extern crate alloc as rust_alloc; #[cfg(feature = "std")] extern crate core; #[cfg(not(feature = "std"))] @@ -59,6 +59,7 @@ pub mod rng; pub mod self_test; pub mod ssl; pub mod x509; +pub mod alloc; #[cfg(feature = "pkcs12")] pub mod pkcs12; @@ -112,11 +113,13 @@ mod mbedtls { #[cfg(not(feature = "std"))] mod alloc_prelude { #![allow(unused)] - pub(crate) use alloc::borrow::ToOwned; - pub(crate) use alloc::boxed::Box; - pub(crate) use alloc::string::String; - pub(crate) use alloc::string::ToString; - pub(crate) use alloc::vec::Vec; + pub(crate) use rust_alloc::borrow::ToOwned; + pub(crate) use rust_alloc::boxed::Box; + pub(crate) use rust_alloc::sync::Arc; + pub(crate) use rust_alloc::string::String; + pub(crate) use rust_alloc::string::ToString; + pub(crate) use rust_alloc::vec::Vec; + pub(crate) use rust_alloc::borrow::Cow; } #[cfg(all(feature="time", any(feature="custom_gmtime_r", feature="custom_time")))] @@ -163,3 +166,11 @@ 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 unsafe fn set_global_debug_threshold(threshold: i32) { + mbedtls_sys::debug_set_threshold(threshold); +} + + diff --git a/mbedtls/src/mbedtls_malloc.c b/mbedtls/src/mbedtls_malloc.c new file mode 100644 index 000000000..a7f051f7a --- /dev/null +++ b/mbedtls/src/mbedtls_malloc.c @@ -0,0 +1,31 @@ +/* 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); +} + diff --git a/mbedtls/src/pk/dhparam.rs b/mbedtls/src/pk/dhparam.rs index 6c785efb5..8f98b9d08 100644 --- a/mbedtls/src/pk/dhparam.rs +++ b/mbedtls/src/pk/dhparam.rs @@ -22,7 +22,7 @@ impl Dhm { /// Takes both DER and PEM forms of FFDH parameters in `DHParams` format. /// /// When calling on PEM-encoded data, `params` must be NULL-terminated - pub(crate) fn from_params(params: &[u8]) -> Result { + pub fn from_params(params: &[u8]) -> Result { let mut ret = Self::init(); unsafe { dhm_parse_dhm(&mut ret.inner, params.as_ptr(), params.len()) }.into_result()?; Ok(ret) diff --git a/mbedtls/src/pk/mod.rs b/mbedtls/src/pk/mod.rs index 28cb6086f..7e152ff25 100644 --- a/mbedtls/src/pk/mod.rs +++ b/mbedtls/src/pk/mod.rs @@ -35,6 +35,8 @@ pub use self::ec::{EcGroupId, ECDSA_MAX_LEN}; #[doc(inline)] pub use crate::ecp::EcGroup; +pub use dhparam::Dhm; + // SHA-256("Fortanix")[:4] const CUSTOM_PK_TYPE: pk_type_t = 0x8b205408 as pk_type_t; @@ -132,6 +134,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 +145,91 @@ define!( impl<'a> UnsafeFrom {} ); +// # 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. /// @@ -778,7 +866,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 { @@ -803,8 +891,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/pkcs12/mod.rs b/mbedtls/src/pkcs12/mod.rs index 7d7507996..a70e98cfd 100644 --- a/mbedtls/src/pkcs12/mod.rs +++ b/mbedtls/src/pkcs12/mod.rs @@ -39,6 +39,7 @@ use crate::cipher::{Cipher, Decryption, Fresh, Traditional}; use crate::hash::{pbkdf_pkcs12, Md, MdInfo, Type as MdType}; use crate::pk::Pk; use crate::x509::Certificate; +use crate::alloc::{Box as MbedtlsBox}; use crate::Error as MbedtlsError; // Constants for various object identifiers used in PKCS12: @@ -836,7 +837,7 @@ impl Pfx { /// of "friendly names" which are associated with said certificate. /// Some or all of the certificates stored in a Pfx may be encrypted in which case /// decrypt must be called to access them. - pub fn certificates<'a>(&'a self) -> impl Iterator, Vec)> + 'a { + pub fn certificates<'a>(&'a self) -> impl Iterator, crate::Error>, Vec)> + 'a { self.authsafe_decrypted_contents() .filter_map(|sb| if let Pkcs12BagSet::Cert(CertBag(Some(cert))) = &sb.bag_value { Some((Certificate::from_der(cert), sb.friendly_name())) diff --git a/mbedtls/src/rng/ctr_drbg.rs b/mbedtls/src/rng/ctr_drbg.rs index 1b4184ba2..264a32744 100644 --- a/mbedtls/src/rng/ctr_drbg.rs +++ b/mbedtls/src/rng/ctr_drbg.rs @@ -6,126 +6,67 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ +#[cfg(feature = "std")] +use std::sync::Arc; + +pub use mbedtls_sys::CTR_DRBG_RESEED_INTERVAL as RESEED_INTERVAL; +use mbedtls_sys::*; 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}; - -// ==== 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, - } - } - } - - impl<'entropy> Drop for CtrDrbgInner<'entropy> { - fn drop(&mut self) { - unsafe { ctr_drbg_free(&mut self.inner) }; - } - } -} - -pub struct CtrDrbg<'entropy> { - boxed: Box>, -} +use crate::error::{IntoResult, Result}; +use crate::rng::{EntropyCallback, RngCallback, RngCallbackMut}; -impl<'entropy> CtrDrbg<'entropy> { - fn init() -> Self { - CtrDrbg { - boxed: Box::new(CtrDrbgInner::init()), - } - } -} +define!( + // `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 we could use c_ty instead of c_box_ty. + // + #[c_box_ty(ctr_drbg_context)] + #[repr(C)] + struct CtrDrbg { + entropy: Arc, + }; + const drop: fn(&mut Self) = ctr_drbg_free; + impl<'a> Into {} +); -#[doc(hidden)] -impl<'entropy> Deref for CtrDrbg<'entropy> { - type Target = CtrDrbgInner<'entropy>; - fn deref(&self) -> &Self::Target { - &self.boxed - } -} +// +// 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 {} -#[doc(hidden)] -impl<'entropy> DerefMut for CtrDrbg<'entropy> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.boxed - } -} +#[allow(dead_code)] +impl CtrDrbg { -// ==== END IMMOVABLE TYPE KLUDGE ==== + 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,7 +78,7 @@ 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 }, ) } @@ -151,7 +92,7 @@ impl<'entropy> CtrDrbg<'entropy> { 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,7 +104,7 @@ 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: @@ -174,13 +115,26 @@ impl<'entropy> CtrDrbg<'entropy> { // } -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: 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.handle_mut() 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: 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.handle() as *const _ as *mut _ } } diff --git a/mbedtls/src/rng/hmac_drbg.rs b/mbedtls/src/rng/hmac_drbg.rs index 5320dd672..6589e01d9 100644 --- a/mbedtls/src/rng/hmac_drbg.rs +++ b/mbedtls/src/rng/hmac_drbg.rs @@ -6,44 +6,53 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ + +#[cfg(feature = "std")] +use std::sync::Arc; + +pub use mbedtls_sys::HMAC_DRBG_RESEED_INTERVAL as RESEED_INTERVAL; +use mbedtls_sys::*; 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 super::{EntropyCallback, RngCallback}; +#[cfg(not(feature = "std"))] +use crate::alloc_prelude::*; use crate::error::{IntoResult, Result}; use crate::hash::MdInfo; +use crate::rng::{EntropyCallback, RngCallback, RngCallbackMut}; define!( #[c_ty(hmac_drbg_context)] - struct HmacDrbg<'entropy>; - const init: fn() -> Self = hmac_drbg_init; + struct HmacDrbg { + entropy: Option>, + }; const drop: fn(&mut Self) = hmac_drbg_free; + impl<'a> Into {} ); #[cfg(feature = "threading")] -unsafe impl<'entropy> Sync for HmacDrbg<'entropy> {} +unsafe impl Sync for HmacDrbg {} -impl<'entropy> HmacDrbg<'entropy> { - pub fn new( +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 +60,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(), @@ -117,13 +132,25 @@ 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 { + hmac_drbg_random(user_data, data, len) + } + + fn data_ptr_mut(&mut self) -> *mut c_void { + self.handle_mut() 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.handle() as *const _ as *mut _ } } diff --git a/mbedtls/src/rng/mod.rs b/mbedtls/src/rng/mod.rs index 364ac3b7a..5e40e958f 100644 --- a/mbedtls/src/rng/mod.rs +++ b/mbedtls/src/rng/mod.rs @@ -27,11 +27,11 @@ 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(data: *mut c_uchar, len: size_t) -> c_int); +callback!(RngCallbackMut,RngCallback(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: 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..98eccf506 100644 --- a/mbedtls/src/rng/os_entropy.rs +++ b/mbedtls/src/rng/os_entropy.rs @@ -6,71 +6,106 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ +use std::sync::Arc; + +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 crate::error::{IntoResult, Result}; +use crate::rng::{EntropyCallback,EntropyCallbackMut}; -callback!(EntropySourceCallback(data: *mut c_uchar, size: size_t, out: *mut size_t) -> c_int); +callback!(EntropySourceCallbackMut,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; + #[repr(C)] + struct OsEntropy { + sources: Vec>, + }; + pub const new: fn() -> Self = entropy_init { sources: Vec::with_capacity(1), }; const drop: fn(&mut Self) = entropy_free; + impl<'a> Into {} ); +// +// 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 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.inner_ffi_mut(), 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 gather(&self) -> Result<()> { + // function is guarded with internal mutex: mbedtls-sys/vendor/crypto/library/entropy.c:310 + unsafe { entropy_gather(self.inner_ffi_mut()) }.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 update_manual(&self, data: &[u8]) -> Result<()> { + // function is guarded with internal mutex: mbedtls-sys/vendor/crypto/library/entropy.c:241 + unsafe { entropy_update_manual(self.inner_ffi_mut(), data.as_ptr(), data.len()) }.into_result()?; Ok(()) } + // TODO // entropy_write_seed_file // entropy_update_seed_file // } -impl<'source> super::EntropyCallback for OsEntropy<'source> { +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(&self) -> *mut c_void { + &self.inner as *const _ as *mut _ + } +} + +impl EntropyCallbackMut for OsEntropy { + #[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 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_mut(&mut 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..6ca4936f1 100644 --- a/mbedtls/src/rng/rdrand.rs +++ b/mbedtls/src/rng/rdrand.rs @@ -64,7 +64,7 @@ fn write_rng_to_slice(outbuf: &mut [u8], rng: fn() -> Option) -> c_int { 0 } -use super::{EntropyCallback, RngCallback}; +use super::{EntropyCallback, EntropyCallbackMut, RngCallback, RngCallbackMut}; pub struct Entropy; @@ -74,20 +74,49 @@ impl EntropyCallback for Entropy { 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() + } +} + +impl EntropyCallbackMut for Entropy { + unsafe extern "C" fn call_mut(_: *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(&mut self) -> *mut c_void { ::core::ptr::null_mut() } } pub struct Nrbg; +impl RngCallbackMut for Nrbg { + unsafe extern "C" fn call_mut(_: *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(&mut self) -> *mut c_void { + ::core::ptr::null_mut() + } +} + impl RngCallback for Nrbg { 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(&self) -> *mut c_void { ::core::ptr::null_mut() } } + diff --git a/mbedtls/src/self_test.rs b/mbedtls/src/self_test.rs index 3a97b2244..1c9ca94d0 100644 --- a/mbedtls/src/self_test.rs +++ b/mbedtls/src/self_test.rs @@ -10,6 +10,11 @@ //! //! Calling mbedTLS self-test functions before they're enabled using the //! `enable()` function here will result in a panic. +//! +//! Using this module in multithreaded or async environment will fail. +//! Functions rely on global variables to track operations and anything non-self-test related will stomp over variables. +//! To use correctly, make sure no other code uses mbedtls. Multiple self test operations done simultaneously may also return failures. +//! #[cfg(any(target_os = "none", target_env = "sgx", not(feature = "std")))] use mbedtls_sys::types::raw_types::{c_char, c_int}; @@ -44,20 +49,29 @@ pub unsafe extern "C" fn mbedtls_log(msg: *const c_char) { log_f.expect("Called self-test log without enabling self-test")(msg) } -// unsafe since unsynchronized +/// # Safety +/// +/// The caller needs to ensure this function is not called while any other function in this module is called.. #[cfg(any(target_os = "none", target_env = "sgx", not(feature = "std")))] pub unsafe fn enable(rand: fn() -> c_int, log: unsafe fn(*const c_char)) { rand_f = Some(rand); log_f = Some(log); } -// unsafe since unsynchronized +/// # Safety +/// +/// The caller needs to ensure this function is not called while any other function in this module is called.. #[cfg(any(target_os = "none", target_env = "sgx", not(feature = "std")))] pub unsafe fn disable() { rand_f = None; log_f = None; } +/// # Safety +/// +/// This function, if used in a multithreaded or async environment will fail. +/// Function relies on global variables to track operations and anything non-self-test related will stomp over variables. +/// To use correctly, make sure no other code uses mbedtls. Multiple self test operations done simultaneously 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..5abb4b4f9 100644 --- a/mbedtls/src/ssl/config.rs +++ b/mbedtls/src/ssl/config.rs @@ -6,25 +6,32 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ +#[cfg(feature = "std")] +use std::sync::Arc; +#[cfg(feature = "std")] +use std::borrow::Cow; + 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 mbedtls_sys::types::raw_types::*; +use mbedtls_sys::types::size_t; -use crate::error::{Error, IntoResult, Result}; -use core::result::Result as StdResult; -use crate::pk::dhparam::Dhm; + +use crate::alloc::{List as MbedtlsList}; +#[cfg(not(feature = "std"))] +use crate::alloc_prelude::*; +use crate::error::{Error, Result, IntoResult}; use crate::pk::Pk; +use crate::pk::dhparam::Dhm; use crate::private::UnsafeFrom; +use crate::rng::RngCallback; use crate::ssl::context::HandshakeContext; use crate::ssl::ticket::TicketCallback; -use crate::x509::{certificate, Crl, LinkedCertificate, Profile, VerifyError}; - -extern "C" { - fn calloc(n: usize, size: usize) -> *mut c_void; - fn free(ptr: *mut c_void); -} +use crate::x509::Certificate; +use crate::x509::Crl; +use crate::x509::Profile; +use crate::x509::VerifyError; #[allow(non_camel_case_types)] #[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Copy, Clone)] @@ -83,27 +90,83 @@ define!( } ); -callback!(DbgCallback:Sync(level: c_int, file: *const c_char, line: c_int, message: *const c_char) -> ()); +define!( + #[c_ty(c_int)] + enum Renegotiation { + Enabled = SSL_RENEGOTIATION_ENABLED, + Disabled = SSL_RENEGOTIATION_DISABLED, + } +); + +callback!(VerifyCallback: Fn(&Certificate, i32, &mut VerifyError) -> Result<()>); +#[cfg(feature = "std")] +callback!(DbgCallback: Fn(i32, Cow<'_, str>, i32, Cow<'_, str>) -> ()); +callback!(SniCallback: Fn(&mut HandshakeContext, &[u8]) -> Result<()>); +callback!(CaCallback: Fn(&MbedtlsList) -> Result>); define!( #[c_ty(ssl_config)] - struct Config<'c>; - const init: fn() -> Self = ssl_config_init; + #[repr(C)] + struct Config { + // 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>, + + rng: Option>, + + ciphersuites: Vec>>, + curves: Option>>, + + #[allow(dead_code)] + dhm: Option>, + + verify_callback: Option>, + #[cfg(feature = "std")] + dbg_callback: Option>, + sni_callback: Option>, + ticket_callback: Option>, + ca_callback: Option>, + }; const drop: fn(&mut Self) = ssl_config_free; - impl<'q> Into {} - impl<'q> UnsafeFrom {} + impl<'a> Into {} ); #[cfg(feature = "threading")] -unsafe impl<'c> Sync for Config<'c> {} +unsafe impl Sync for Config {} -impl<'c> Config<'c> { +impl Config { pub fn new(e: Endpoint, t: Transport, p: Preset) -> Self { - let mut c = Config::init(); + let mut inner = 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, + #[cfg(feature = "std")] + dbg_callback: None, + sni_callback: None, + ticket_callback: None, + ca_callback: None, } - c } // need bitfield support getter!(endpoint() -> Endpoint = field endpoint); @@ -119,21 +182,30 @@ impl<'c> Config<'c> { 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(), 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(), 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(), list.as_ptr()) } + self.curves = Some(list); } + 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 +215,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,68 +227,59 @@ 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 + setter!(set_cert_profile(p: &'static Profile) = ssl_conf_cert_profile); /// 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)?; + pub fn set_dh_params(&mut self, dhm: Arc) -> Result<()> { unsafe { - ssl_conf_dh_param_ctx(&mut self.inner, (&mut ctx).into()) + ssl_conf_dh_param_ctx(self.into(), dhm.inner_ffi_mut()) .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.inner_ffi_mut(), crl.as_ref().map(|crl| crl.inner_ffi_mut()).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.inner_ffi_mut(), own_pk.inner_ffi_mut()) + .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); } setter!( @@ -224,43 +287,62 @@ impl<'c> Config<'c> { set_session_tickets(u: UseSessionTickets) = ssl_conf_session_tickets ); + setter!(set_renegotiation(u: Renegotiation) = ssl_conf_renegotiation); + 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_sni_callback(&mut self, cb: F) + where + F: SniCallback + '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<()> + '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. + // let cb = &mut *(closure as *mut F); - let mut ctx = UnsafeFrom::from(ctx).expect("valid context"); + let context = UnsafeFrom::from(ctx).unwrap(); + + 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::), &**self.sni_callback.as_mut().unwrap() as *const _ as *mut c_void) } } // 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) + pub fn set_verify_callback(&mut self, cb: F) where - F: FnMut(&mut LinkedCertificate, i32, &mut VerifyError) -> Result<()>, + F: VerifyCallback + 'static, { unsafe extern "C" fn verify_callback( closure: *mut c_void, @@ -269,17 +351,22 @@ impl<'c> Config<'c> { flags: *mut u32, ) -> c_int where - F: FnMut(&mut LinkedCertificate, i32, &mut VerifyError) -> Result<()>, + F: VerifyCallback + 'static, { + if crt.is_null() || closure.is_null() || flags.is_null() { + return ::mbedtls_sys::ERR_X509_BAD_INPUT_DATA; + } + let cb = &mut *(closure as *mut F); - let crt: &mut LinkedCertificate = - UnsafeFrom::from(crt).expect("valid certificate"); + 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 { @@ -288,125 +375,76 @@ impl<'c> Config<'c> { } } - unsafe { - ssl_conf_verify( - &mut self.inner, - Some(verify_callback::), - cb as *mut F as _, - ) - } + + self.verify_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_verify(self.into(), Some(verify_callback::), &**self.verify_callback.as_mut().unwrap() as *const _ as *mut c_void) } } - pub fn set_ca_callback(&mut self, cb: &'c mut F) - where - F: FnMut(&LinkedCertificate, &mut ForeignOwnedCertListBuilder) -> Result<()>, + pub fn set_ca_callback(&mut self, cb: F) + where + F: CaCallback + '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<()>, + where + F: CaCallback + 'static, { + if child.is_null() || closure.is_null() || candidate_cas.is_null() { + return ::mbedtls_sys::ERR_X509_BAD_INPUT_DATA; + } + 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(); + let crt: &MbedtlsList = UnsafeFrom::from(&child as *const *const x509_crt).expect("valid certificate"); + match cb(&crt) { + Ok(list) => { + // This does not leak due to mbedtls taking ownership from us and freeing the certificates itself. (logic is in: mbedtls-sys/vendor/library/x509_crt.c:2904) + *candidate_cas = list.into_raw(); 0 }, Err(e) => e.to_int(), } } - unsafe { - ssl_conf_ca_cb( - &mut self.inner, - Some(ca_callback::), - cb as *mut F as _, - ) - } + self.ca_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_ca_cb( self.into(), Some(ca_callback::), &**self.ca_callback.as_mut().unwrap() as *const _ as *mut c_void) } } -} -/// 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 -/// 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 { - cert_list: *mut x509_crt, -} - -impl ForeignOwnedCertListBuilder { - pub(crate) fn new() -> Self { - let cert_list = unsafe { calloc(1, core::mem::size_of::()) } as *mut x509_crt; - if cert_list == ::core::ptr::null_mut() { - panic!("Out of memory"); - } - unsafe { ::mbedtls_sys::x509_crt_init(cert_list); } - - Self { - cert_list - } - } - - pub fn push_back(&mut self, cert: &LinkedCertificate) { - self.try_push_back(cert.as_der()).expect("cert is a valid DER-encoded certificate"); - } - - 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()?; - Ok(()) - } - - // The memory pointed to by the return value is managed by mbedtls. If the return value is - // dropped without handing it to an mbedtls-function that takes ownership of it, that memory - // will be leaked. - pub(crate) fn to_x509_crt_ptr(mut self) -> *mut x509_crt { - let res = self.cert_list; - self.cert_list = ::core::ptr::null_mut(); - res - } -} + #[cfg(feature = "std")] + pub fn set_dbg_callback(&mut self, cb: F) + where + F: DbgCallback + 'static, + { + #[allow(dead_code)] + 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: DbgCallback + 'static, + { + let cb = &mut *(closure as *mut F); -impl Drop for ForeignOwnedCertListBuilder { - fn drop(&mut self) { - unsafe { - ::mbedtls_sys::x509_crt_free(self.cert_list); - free(self.cert_list as *mut c_void); + let file = match file.is_null() { + false => std::ffi::CStr::from_ptr(file).to_string_lossy(), + true => Cow::from(""), + }; + + let message = match message.is_null() { + false => std::ffi::CStr::from_ptr(message).to_string_lossy(), + true => Cow::from(""), + }; + + cb(level, file, line, message); } - } -} - -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 {} -); - -pub struct KeyCertIter<'a> { - key_cert: Option<&'a KeyCert>, -} -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"), - ) - }) + self.dbg_callback = Some(Arc::new(cb)); + unsafe { ssl_conf_dbg(self.into(), Some(dbg_callback::), &**self.dbg_callback.as_mut().unwrap() as *const _ as *mut c_void) } } } diff --git a/mbedtls/src/ssl/context.rs b/mbedtls/src/ssl/context.rs index cbc17534a..f40a31f15 100644 --- a/mbedtls/src/ssl/context.rs +++ b/mbedtls/src/ssl/context.rs @@ -6,42 +6,38 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ + +use core::any::Any; +use core::result::Result as StdResult; #[cfg(not(feature = "std"))] -use core_io::{self as io, Read, Write}; +use core_io::{Read, Write, Result as IoResult}; +#[cfg(feature = "std")] +use std::io::{Read, Write, Result as IoResult}; #[cfg(feature = "std")] -use std::io::{self, Read, Write}; +use std::sync::Arc; 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 core::result::Result as StdResult; +use crate::alloc::{List as MbedtlsList}; +#[cfg(not(feature = "std"))] +use crate::alloc_prelude::*; +use crate::error::{Error, Result, IntoResult}; +use crate::pk::Pk; use crate::private::UnsafeFrom; -use crate::ssl::config::{AuthMode, Config, Version}; -use crate::x509::{Crl, LinkedCertificate, VerifyError}; - -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; +use crate::ssl::config::{Config, Version, AuthMode}; +use crate::x509::{Certificate, Crl, VerifyError}; + +pub trait IoCallback : Any { + 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; } -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 +49,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 { @@ -74,59 +66,83 @@ impl IoCallback for IO { } } + define!( #[c_ty(ssl_context)] - struct Context<'config>; - const init: fn() -> Self = ssl_init; - const drop: fn(&mut Self) = ssl_free; + #[repr(C)] + struct Context { + // config is used read-only for mutliple contexts and is immutable once configured. + config: Arc, + + // Must be held in heap and pointer to it as pointer is sent to MbedSSL and can't be re-allocated. + io: Option>, + + handshake_ca_cert: Option>>, + handshake_crl: Option>, + + handshake_cert: Vec>>, + handshake_pk: Vec>, + }; impl<'a> Into {} + + // Only use this when you know the type you are casting is originally a rust allocated 'Context'. impl<'a> UnsafeFrom {} ); -pub struct Session<'ctx> { - inner: &'ctx mut ssl_context, -} +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()); + }; -#[cfg(feature = "threading")] -unsafe impl<'ctx> Send for Session<'ctx> {} + Context { + inner, + config: config.clone(), + io: None, -pub struct HandshakeContext<'ctx> { - inner: &'ctx mut ssl_context, -} - -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) + 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<()> { 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); + + self.handshake_cert.clear(); + self.handshake_pk.clear(); + self.handshake_ca_cert = None; + self.handshake_crl = None; + + 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, - }), } } } @@ -141,14 +157,10 @@ impl<'config> Context<'config> { #[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 +170,31 @@ 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") } - } -} - -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>, - ) { - 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()), - ) - } + pub fn config(&self) -> &Arc { + &self.config } - - /// 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<()> { + + pub fn close(&mut self) { unsafe { - ssl_set_hs_own_cert(self.inner, chain.into().into(), key.into()) - .into_result() - .map(|_| ()) + ssl_close_notify(self.into()); + ssl_set_bio(self.into(), ::core::ptr::null_mut(), None, None, None); + self.io = None; } } -} - -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") } + pub fn io(&self) -> Option<&dyn Any> { + self.io.as_ref().map(|v| &**v) } -} - -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 }) + pub fn io_mut(&mut self) -> Option<&mut dyn Any> { + self.io.as_mut().map(|v| &mut **v) } -} - -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 +208,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 +224,45 @@ 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 { - if self.inner.session == ::core::ptr::null_mut() { - 0 - } else { - unsafe { self.inner.session.as_ref().unwrap().ciphersuite as u16 } + pub fn ciphersuite(&self) -> Result { + if self.inner.session.is_null() { + 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)) } + pub fn peer_cert(&self) -> Result>> { + if self.inner.session.is_null() { + return Err(Error::SslBadInputData); + } + + unsafe { + // We cannot call the peer cert function as we need a pointer to a pointer to create the MbedtlsList, we need something in the heap / cannot use any local variable for that. + let peer_cert : &MbedtlsList = UnsafeFrom::from(&((*self.inner.session).peer_cert) as *const *mut x509_crt as *const *const x509_crt).ok_or(Error::SslBadInputData)?; + Ok(Some(peer_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 { + self.close(); + 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]) -> IoResult { + 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 +270,102 @@ 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]) -> IoResult { + 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) -> IoResult<()> { 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(crate) 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(()) + } + + 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_close_notify(self.inner); - ssl_set_bio(self.inner, ::core::ptr::null_mut(), None, None, None); + ssl_set_hs_ca_chain( + self.context.into(), + chain.inner_ffi_mut(), + crl.as_ref().map(|crl| crl.inner_ffi_mut()).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. + 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_set_hs_own_cert(self.context.into(), chain.inner_ffi_mut(), key.inner_ffi_mut()).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..3c7db39ba 100644 --- a/mbedtls/src/ssl/ticket.rs +++ b/mbedtls/src/ssl/ticket.rs @@ -6,12 +6,21 @@ * option. This file may not be copied, modified, or distributed except * according to those terms. */ -use crate::cipher::raw::CipherType; -use crate::error::{IntoResult, Result}; +#[cfg(feature = "std")] +use std::sync::Arc; + +use mbedtls_sys::*; use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void}; use mbedtls_sys::types::size_t; -use mbedtls_sys::*; +#[cfg(not(feature = "std"))] +use crate::alloc_prelude::*; +use crate::cipher::raw::CipherType; +use crate::error::{IntoResult, Result}; +use crate::rng::RngCallback; + + +#[cfg(not(feature = "threading"))] pub trait TicketCallback { unsafe extern "C" fn call_write( p_ticket: *mut c_void, @@ -20,46 +29,78 @@ 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; } +#[cfg(feature = "threading")] +pub trait TicketCallback : Sync { + unsafe extern "C" fn call_write( + p_ticket: *mut c_void, + session: *const ssl_session, + start: *mut c_uchar, + end: *const c_uchar, + tlen: *mut size_t, + lifetime: *mut u32, + ) -> 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 where Self: Sized; + + fn data_ptr(&self) -> *mut c_void; +} + + define!( #[c_ty(ssl_ticket_context)] - struct TicketContext<'rng>; - const init: fn() -> Self = ssl_ticket_init; + #[repr(C)] + struct TicketContext { + // 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, + }; const drop: fn(&mut Self) = ssl_ticket_free; + impl<'a> Into {} ); -impl<'rng> TicketContext<'rng> { - pub fn new( - rng: &'rng mut F, +#[cfg(feature = "threading")] +unsafe impl Sync for TicketContext {} + +impl TicketContext { + pub fn new( + rng: Arc, cipher: CipherType, lifetime: u32, - ) -> Result> { - let mut ret = Self::init(); + ) -> Result { + + let mut ret = TicketContext { inner: ssl_ticket_context::default(), rng }; + unsafe { + ssl_ticket_init(&mut ret.inner); ssl_ticket_setup( &mut ret.inner, - Some(F::call), - rng.data_ptr(), + Some(T::call), + ret.rng.data_ptr(), cipher.into(), lifetime, - ) + ).into_result()?; } - .into_result() - .map(|_| ret) + + Ok(ret) } } -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 +121,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.handle() as *const _ as *mut _ } } diff --git a/mbedtls/src/wrapper_macros.rs b/mbedtls/src/wrapper_macros.rs index dba58ea33..1c65d39b0 100644 --- a/mbedtls/src/wrapper_macros.rs +++ b/mbedtls/src/wrapper_macros.rs @@ -15,48 +15,101 @@ 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($($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; + pub trait $n : Sync { + 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: 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: 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 _ + } + } + }; + ($t:ident: $($bound:tt)*) => { + #[cfg(not(feature = "threading"))] + pub trait $t: $($bound)* {} + #[cfg(feature = "threading")] + pub trait $t: $($bound)* + Sync {} + + #[cfg(not(feature = "threading"))] + impl $t for F {} + #[cfg(feature = "threading")] + impl $t for F {} }; } 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); + // When using members, careful with UnsafeFrom, the data casted back must have been allocated on rust side. + { #[c_ty($inner:ident)] $(#[$m:meta])* struct $name:ident$(<$l:tt>)* $({ $($(#[$mm:meta])* $member:ident: $member_type:ty,)* })?; $($defs:tt)* } => { + define_struct!(define $(#[$m])* struct $name $(lifetime $l)* inner $inner members $($($(#[$mm])* $member: $member_type,)*)*); + define_struct!(<< $name $(lifetime $l)* inner $inner >> $($defs)*); + }; + // Do not use UnsafeFrom with 'c_box_ty'. That is currently not supported as its not needed anywhere, support may be added in the future if needed anywhere. + { #[c_box_ty($inner:ident)] $(#[$m:meta])* struct $name:ident$(<$l:tt>)* $({ $($(#[$mm:meta])* $member:ident: $member_type:ty,)* })?; $($defs:tt)* } => { + define_struct!(define_box $(#[$m])* struct $name $(lifetime $l)* inner $inner members $($($(#[$mm])* $member: $member_type,)*)*); define_struct!(<< $name $(lifetime $l)* inner $inner >> $($defs)*); }; { #[c_ty($raw:ty)] $(#[$m:meta])* enum $n:ident { $(#[$doc:meta] $rust:ident = $c:ident,)* } } => { define_enum!( $(#[$m])* enum $n ty $raw : $(doc ($doc) rust $rust c $c),*); }; @@ -102,13 +155,14 @@ macro_rules! define_enum { } macro_rules! define_struct { - { define $(#[$m:meta])* struct $name:ident $(lifetime $l:tt)* inner $inner:ident } => { + { define $(#[$m:meta])* struct $name:ident $(lifetime $l:tt)* inner $inner:ident members $($(#[$mm:meta])* $member:ident: $member_type:ty,)* } => { as_item!( #[allow(dead_code)] $(#[$m])* pub struct $name<$($l)*> { inner: ::mbedtls_sys::$inner, $(r: ::core::marker::PhantomData<&$l ()>,)* + $($(#[$mm])* $member: $member_type,)* } ); @@ -137,15 +191,45 @@ macro_rules! define_struct { ); }; - { << $name:ident $(lifetime $l:tt)* inner $inner:ident >> const init: fn() -> Self = $ctor:ident; $($defs:tt)* } => { - define_struct!(init $name () init $ctor $(lifetime $l)* ); + { define_box $(#[$m:meta])* struct $name:ident $(lifetime $l:tt)* inner $inner:ident members $($(#[$mm:meta])* $member:ident: $member_type:ty,)* } => { + as_item!( + #[allow(dead_code)] + $(#[$m])* + pub struct $name<$($l)*> { + inner: Box<::mbedtls_sys::$inner>, + $(r: ::core::marker::PhantomData<&$l ()>,)* + $($(#[$mm])* $member: $member_type,)* + } + ); + + as_item!( + #[allow(dead_code)] + impl<$($l)*> $name<$($l)*> { + pub(crate) fn handle(&self) -> &::mbedtls_sys::$inner { + &*self.inner + } + + pub(crate) fn handle_mut(&mut self) -> &mut ::mbedtls_sys::$inner { + &mut *self.inner + } + } + ); + + as_item!( + #[cfg(feature="threading")] + unsafe impl<$($l)*> Send for $name<$($l)*> {} + ); + }; + + { << $name:ident $(lifetime $l:tt)* inner $inner:ident >> const init: fn() -> Self = $ctor:ident $({ $($member:ident: $member_init:expr,)* })?; $($defs:tt)* } => { + define_struct!(init $name () init $ctor $(lifetime $l)* members $($($member: $member_init,)*)* ); define_struct!(<< $name $(lifetime $l)* inner $inner >> $($defs)*); }; - { << $name:ident $(lifetime $l:tt)* inner $inner:ident >> pub const new: fn() -> Self = $ctor:ident; $($defs:tt)* } => { - define_struct!(init $name (pub) new $ctor $(lifetime $l)* ); + { << $name:ident $(lifetime $l:tt)* inner $inner:ident >> pub const new: fn() -> Self = $ctor:ident $({ $($member:ident: $member_init:expr,)* })?; $($defs:tt)* } => { + define_struct!(init $name (pub) new $ctor $(lifetime $l)* members $($($member: $member_init,)*)* ); define_struct!(<< $name $(lifetime $l)* inner $inner >> $($defs)*); }; - { init $name:ident ($($vis:tt)*) $new:ident $ctor:ident $(lifetime $l:tt)* } => { + { init $name:ident ($($vis:tt)*) $new:ident $ctor:ident $(lifetime $l:tt)* members $($member:ident: $member_init:expr,)* } => { as_item!( #[allow(dead_code)] impl<$($l)*> $name<$($l)*> { @@ -158,6 +242,7 @@ macro_rules! define_struct { $name{ inner:inner, $(r: ::core::marker::PhantomData::<&$l _>,)* + $($member: $member_init,)* } } } @@ -172,7 +257,7 @@ macro_rules! define_struct { as_item!( impl<$($l)*> Drop for $name<$($l)*> { fn drop(&mut self) { - unsafe{::mbedtls_sys::$dtor(&mut self.inner)}; + unsafe{::mbedtls_sys::$dtor(self.handle_mut())}; } } ); @@ -186,7 +271,7 @@ macro_rules! define_struct { as_item!( impl<$l2,$($l),*> Into<*const $inner> for &$l2 $name<$($l)*> { fn into(self) -> *const $inner { - &self.inner + self.handle() } } ); @@ -194,7 +279,17 @@ macro_rules! define_struct { as_item!( impl<$l2,$($l),*> Into<*mut $inner> for &$l2 mut $name<$($l)*> { fn into(self) -> *mut $inner { - &mut self.inner + self.handle_mut() + } + } + ); + as_item!( + impl<$($l),*> $name<$($l)*> { + /// Needed for compatibility with mbedtls - where we could pass + /// `*const` but function signature requires `*mut` + #[allow(dead_code)] + pub(crate) unsafe fn inner_ffi_mut(&self) -> *mut $inner { + self.handle() as *const _ as *mut $inner } } ); @@ -230,29 +325,11 @@ 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())} + unsafe{::mbedtls_sys::$cfn(self.into(),$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])* @@ -263,7 +340,129 @@ macro_rules! getter { { $(#[$m:meta])* $rfn:ident() -> $rty:ty = fn $cfn:ident } => { $(#[$m])* pub fn $rfn(&self) -> $rty { - unsafe{::mbedtls_sys::$cfn(&self.inner).into()} + unsafe{::mbedtls_sys::$cfn(self.into()).into()} } }; } + + + +#[cfg(test)] +mod tests { + #[allow(dead_code)] + /// Utilities for testing whether types implement certain traits. + /// + /// For each trait `Trait` that you want to be able to test, you should + /// implement: + /// ```ignore + /// impl Testable for T {} + /// ``` + /// + /// Then, to test whether a type `Type` implements `Trait`, call: + /// ```ignore + /// TestTrait::::new().impls_trait() + /// ``` + /// This returns a `bool` indicating whether the trait is implemented. + // This relies on auto-deref to distinguish between types that do and don't + // implement the trait. + mod testtrait { + use core::marker::PhantomData; + + pub struct NonImplTrait { + inner: PhantomData + } + + pub struct TestTrait { + non_impl: NonImplTrait, + phantom: PhantomData<*const TraitObj>, + } + + pub trait Testable {} + + impl TestTrait { + pub fn new() -> Self { + TestTrait { non_impl: NonImplTrait { inner: PhantomData }, phantom: PhantomData } + } + } + + impl> TestTrait { + pub fn impls_trait(&self) -> bool { + true + } + } + + impl NonImplTrait { + pub fn impls_trait(&self) -> bool { + false + } + } + + impl core::ops::Deref for TestTrait { + type Target = NonImplTrait; + + fn deref(&self) -> &NonImplTrait { + &self.non_impl + } + } + } + + use testtrait::{TestTrait, Testable}; + + callback!(RustTest: Fn() -> ()); + callback!(NativeTestMut,NativeTest() -> ()); + + impl Testable for T {} + impl Testable for T {} + impl Testable for T {} + impl Testable for T {} + + #[test] + #[cfg(feature = "threading")] + fn callback_sync_with_threading() { + fn test_closure() { + assert!(TestTrait::::new().impls_trait(), "RustTest should be Sync"); + } + fn test_native_closure() { + assert!(TestTrait::::new().impls_trait(), "NativeTest should be Sync"); + } + fn test_native_mut_closure() { + assert!(TestTrait::::new().impls_trait(), "NativeTestMut should be Sync"); + } + + test_closure::()>(); + test_native_closure::()>(); + test_native_mut_closure::()>(); + + assert!(!TestTrait::()>::new().impls_trait(), "non-Sync closure shouldn't be RustTest"); + assert!(TestTrait::() + Sync)>::new().impls_trait(), "Sync closure should be RustTest"); + assert!(!TestTrait::()>::new().impls_trait(), "non-Sync closure shouldn't be NativeTest"); + assert!(TestTrait::() + Sync)>::new().impls_trait(), "Sync closure should be NativeTest"); + assert!(!TestTrait::()>::new().impls_trait(), "non-Sync closure shouldn't be NativeTestMut"); + assert!(TestTrait::() + Sync)>::new().impls_trait(), "Sync closure should be NativeTestMut"); + } + + #[test] + #[cfg(not(feature = "threading"))] + fn callback_sync_without_threading() { + fn test_closure() { + assert!(!TestTrait::::new().impls_trait(), "RustTest shouldn't be Sync"); + } + fn test_native_closure() { + assert!(!TestTrait::::new().impls_trait(), "NativeTest shouldn't be Sync"); + } + fn test_native_mut_closure() { + assert!(!TestTrait::::new().impls_trait(), "NativeTestMut shouldn't be Sync"); + } + + test_closure::()>(); + test_native_closure::()>(); + test_native_mut_closure::()>(); + + assert!(TestTrait::()>::new().impls_trait(), "non-Sync closure should be RustTest"); + assert!(TestTrait::() + Sync)>::new().impls_trait(), "Sync closure should be RustTest"); + assert!(TestTrait::()>::new().impls_trait(), "non-Sync closure should be NativeTest"); + assert!(TestTrait::() + Sync)>::new().impls_trait(), "Sync closure should be NativeTest"); + assert!(TestTrait::()>::new().impls_trait(), "non-Sync closure should be NativeTestMut"); + assert!(TestTrait::() + Sync)>::new().impls_trait(), "Sync closure should be NativeTestMut"); + } +} diff --git a/mbedtls/src/x509/certificate.rs b/mbedtls/src/x509/certificate.rs index 65506557f..6bd3dad5b 100644 --- a/mbedtls/src/x509/certificate.rs +++ b/mbedtls/src/x509/certificate.rs @@ -7,25 +7,29 @@ * according to those terms. */ use core::fmt; -use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; -use core::ptr; +use core::iter::FromIterator; +use core::ptr::NonNull; +use mbedtls_sys::*; +use mbedtls_sys::types::raw_types::c_char; + +use crate::alloc::{List as MbedtlsList, Box as MbedtlsBox}; #[cfg(not(feature = "std"))] use crate::alloc_prelude::*; +use crate::error::{Error, IntoResult, Result}; +use crate::hash::Type as MdType; +use crate::pk::Pk; +use crate::private::UnsafeFrom; +use crate::rng::Random; +use crate::x509::Time; -use mbedtls_sys::types::raw_types::c_char; -use mbedtls_sys::*; +extern "C" { + pub(crate) fn forward_mbedtls_calloc(n: mbedtls_sys::types::size_t, size: mbedtls_sys::types::size_t) -> *mut mbedtls_sys::types::raw_types::c_void; +} #[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; - #[derive(Debug,Copy,Clone,Eq,PartialEq)] pub enum CertificateVersion { V1, @@ -33,13 +37,6 @@ 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; -); - #[cfg(feature = "std")] #[derive(Debug, Clone, Eq, PartialEq)] pub struct Extension { @@ -60,92 +57,18 @@ 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) - } - - /// 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) - } - - /// Input must be NULL-terminated - #[cfg(buggy)] - pub fn from_pem_multiple(pem: &[u8]) -> Result> { - let mut vec; - 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()?; - - // then allocate enough certs with our allocator - vec = Vec::new(); - let mut cur: *mut _ = &mut dummy.inner; - while cur != ::core::ptr::null_mut() { - vec.push(Certificate::init()); - cur = (*cur).next; - } - - // link them together, they will become unlinked again when List drops - let list = List::from_vec(&mut vec).unwrap(); - - // 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) - } -} - -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 Clone for Certificate { - fn clone(&self) -> Certificate { - let mut ret = Self::init(); - unsafe { - x509_crt_parse_der(&mut ret.inner, self.inner.raw.p, self.inner.raw.len) - .into_result() - .unwrap() - }; - ret - } -} -impl Deref for Certificate { - type Target = LinkedCertificate; - fn deref(&self) -> &LinkedCertificate { - unsafe { UnsafeFrom::from(&self.inner as *const _).unwrap() } - } -} - -impl DerefMut for Certificate { - fn deref_mut(&mut self) -> &mut LinkedCertificate { - unsafe { UnsafeFrom::from(&mut self.inner as *mut _).unwrap() } - } -} - -#[repr(C)] -pub struct LinkedCertificate { - inner: x509_crt, -} +define!( + #[c_ty(x509_crt)] + #[repr(transparent)] + struct Certificate; + const drop: fn(&mut Self) = x509_crt_free; + impl<'a> Into {} + impl<'a> UnsafeFrom {} +); fn x509_buf_to_vec(buf: &x509_buf) -> Vec { - if buf.p == core::ptr::null_mut() || buf.len == 0 { + if buf.p.is_null() || buf.len == 0 { return vec![]; } @@ -153,16 +76,46 @@ 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