diff --git a/Cargo.lock b/Cargo.lock index 7288b7c..9fb7bf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,11 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anyhow" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayvec" version = "0.4.12" @@ -99,6 +104,11 @@ dependencies = [ "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bumpalo" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byte-tools" version = "0.3.1" @@ -127,6 +137,16 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -135,6 +155,11 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cookie-factory" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crypto-mac" version = "0.7.0" @@ -261,6 +286,14 @@ dependencies = [ "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hmac" version = "0.7.1" @@ -278,6 +311,14 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "js-sys" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -326,6 +367,15 @@ name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nom" version = "5.0.1" @@ -344,6 +394,7 @@ dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -541,6 +592,20 @@ name = "regex-syntax" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ring" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rsa" version = "0.2.0" @@ -642,6 +707,11 @@ name = "smallvec" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "sourcefile" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "spin" version = "0.5.2" @@ -722,11 +792,21 @@ name = "typenum" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "untrusted" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.1.5" @@ -737,6 +817,90 @@ name = "wasi" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasm-bindgen" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasm-bindgen-webidl" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "web-sys" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "weedle" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.3.8" @@ -773,6 +937,15 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x509" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie-factory 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "x509-parser" version = "0.6.0" @@ -801,6 +974,8 @@ dependencies = [ name = "yubikey-piv" version = "0.0.3" dependencies = [ + "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie-factory 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "der-parser 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "elliptic-curve 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -810,13 +985,18 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "pcsc 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", "rsa 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "secrecy 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "subtle-encoding 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x509 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "x509-parser 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -842,6 +1022,7 @@ dependencies = [ [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" @@ -853,12 +1034,15 @@ dependencies = [ "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum cookie-factory 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2b81f8a9b8f5ffa2ed91a82c53392837eab151baf682acf8322c909b6d4fe9" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum der-parser 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "537a7d6becb8c3cae3bab31439c248a12d43267ccc0b1a0333362b7cefb61c3e" "checksum des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74ba5f1b5aee9772379c2670ba81306e65a93c0ee3caade7a1d22b188d88a3af" @@ -873,8 +1057,10 @@ dependencies = [ "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum gumdrop 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee50908bc1beeac1f2902e0b4e0cd0d844e716f5ebdc6f0cfc1163fe5e10bcde" "checksum gumdrop_derive 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90454ce4de40b7ca6a8968b5ef367bdab48413962588d0d2b1638d60090c35d7" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +"checksum js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "1c840fdb2167497b0bd0db43d6dfe61e91637fa72f9d061f8bd17ddc44ba6414" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" @@ -882,6 +1068,7 @@ dependencies = [ "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca" "checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" "checksum num-bigint-dig 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3d03c330f9f7a2c19e3c0b42698e48141d0809c78cd9b6219f85bd7d7e892aa" @@ -907,6 +1094,7 @@ dependencies = [ "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6747f8da1f2b1fabbee1aaa4eb8a11abf9adef0bf58a41cee45db5d59cecdfac" "checksum rsa 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ed8692d8e0ea3baae03f0f32ecfc13a6c6f1f85fcd6d9fdefcdf364e70f4df9" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -920,6 +1108,7 @@ dependencies = [ "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" +"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" @@ -931,14 +1120,25 @@ dependencies = [ "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60369ef7a31de49bcb3f6ca728d4ba7300d9a1658f94c727d4cab8c8d9f4aece" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "29ae32af33bacd663a9a28241abecf01f2be64e6a185c6139b04f18b6385c5f2" +"checksum wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "1845584bd3593442dc0de6e6d9f84454a59a057722f36f005e44665d6ab19d85" +"checksum wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "87fcc747e6b73c93d22c947a6334644d22cfec5abd8b66238484dc2b0aeb9fe4" +"checksum wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc4b3f2c4078c8c4a5f363b92fcf62604c5913cbd16c6ff5aaf0f74ec03f570" +"checksum wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ca0b78d6d3be8589b95d1d49cdc0794728ca734adf36d7c9f07e6459508bb53d" +"checksum wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3126356474ceb717c8fb5549ae387c9fbf4872818454f4d87708bee997214bb5" +"checksum web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "98405c0a2e722ed3db341b4c5b70eb9fe0021621f7350bab76df93b09b649bbf" +"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" +"checksum x509 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eddce2e179aee785295bff6e72e6f36cc7dc3011e01231100270b6b25de9ec60" "checksum x509-parser 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b86b92815858495482b74dab17c0b2b2399f7582b6e7ca621b87aebf8fd00e9" "checksum zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" "checksum zeroize_derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" diff --git a/Cargo.toml b/Cargo.toml index d6e840f..c802505 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ members = [".", "cli"] maintenance = { status = "experimental" } [dependencies] +chrono = "0.4" +cookie-factory = "0.3" der-parser = "3" des = "0.3" elliptic-curve = "0.2" @@ -29,18 +31,23 @@ getrandom = "0.1" hmac = "0.7" log = "0.4" nom = "5" +num-bigint = { version = "0.2", features = ["rand"] } pbkdf2 = "0.3" pcsc = "2" rsa = "0.2.0" secrecy = "0.6" sha-1 = "0.8" +sha2 = "0.8" subtle = "2" subtle-encoding = "0.5" +x509 = "0.1.1" x509-parser = "0.6" zeroize = "1" [dev-dependencies] env_logger = "0.7" +rand = "0.5" +ring = "0.16.9" lazy_static = "1" [features] diff --git a/src/apdu.rs b/src/apdu.rs index beb9c69..96da0b8 100644 --- a/src/apdu.rs +++ b/src/apdu.rs @@ -276,7 +276,6 @@ impl Response { } /// Get the raw [`StatusWords`] code for this response. - #[cfg(feature = "untested")] pub fn code(&self) -> u16 { self.status_words.code() } diff --git a/src/certificate.rs b/src/certificate.rs index fb8261b..b358cc5 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -32,24 +32,27 @@ use crate::{ error::Error, - key::{AlgorithmId, SlotId}, + key::{sign_data, AlgorithmId, SlotId}, serialization::*, transaction::Transaction, yubikey::YubiKey, Buffer, }; +use chrono::{DateTime, Utc}; use elliptic_curve::weierstrass::{ curve::{NistP256, NistP384}, PublicKey as EcPublicKey, }; use log::error; +use num_bigint::BigUint; use rsa::{PublicKey, RSAPublicKey}; +use sha2::{Digest, Sha256}; use std::convert::TryFrom; use std::fmt; +use std::ops::DerefMut; use x509_parser::{parse_x509_der, x509::SubjectPublicKeyInfo}; use zeroize::Zeroizing; -#[cfg(feature = "untested")] use crate::CB_OBJ_MAX; // TODO: Make these der_parser::oid::Oid constants when it has const fn support. @@ -59,11 +62,43 @@ const OID_NIST_P256: &str = "1.2.840.10045.3.1.7"; const OID_NIST_P384: &str = "1.3.132.0.34"; const TAG_CERT: u8 = 0x70; -#[cfg(feature = "untested")] const TAG_CERT_COMPRESS: u8 = 0x71; -#[cfg(feature = "untested")] const TAG_CERT_LRC: u8 = 0xFE; +/// A serial number for a [`Certificate`]. +#[derive(Clone, Debug)] +pub struct Serial(BigUint); + +impl From for Serial { + fn from(num: BigUint) -> Serial { + Serial(num) + } +} + +impl From<[u8; 20]> for Serial { + fn from(bytes: [u8; 20]) -> Serial { + Serial(BigUint::from_bytes_be(&bytes)) + } +} + +impl TryFrom<&[u8]> for Serial { + type Error = (); + + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() <= 20 { + Ok(Serial(BigUint::from_bytes_be(&bytes))) + } else { + Err(()) + } + } +} + +impl Serial { + fn to_bytes(&self) -> Vec { + self.0.to_bytes_be() + } +} + /// Information about how a [`Certificate`] is stored within a YubiKey. #[derive(Clone, Copy, Debug, PartialEq)] pub enum CertInfo { @@ -95,6 +130,40 @@ impl From for u8 { } } +impl x509::AlgorithmIdentifier for AlgorithmId { + type AlgorithmOid = &'static [u64]; + + fn algorithm(&self) -> Self::AlgorithmOid { + match self { + // RSA encryption + AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => &[1, 2, 840, 113_549, 1, 1, 1], + // EC Public Key + AlgorithmId::EccP256 | AlgorithmId::EccP384 => &[1, 2, 840, 10045, 2, 1], + } + } + + fn parameters( + &self, + w: cookie_factory::WriteContext, + ) -> cookie_factory::GenResult { + use x509::der::write::der_oid; + + // From [RFC 5480](https://tools.ietf.org/html/rfc5480#section-2.1.1): + // ```text + // ECParameters ::= CHOICE { + // namedCurve OBJECT IDENTIFIER + // -- implicitCurve NULL + // -- specifiedCurve SpecifiedECDomain + // } + // ``` + match self { + AlgorithmId::EccP256 => der_oid(&[1, 2, 840, 10045, 3, 1, 7][..])(w), + AlgorithmId::EccP384 => der_oid(&[1, 3, 132, 0, 34][..])(w), + _ => Ok(w), + } + } +} + /// Information about a public key within a [`Certificate`]. #[derive(Clone, Eq, PartialEq)] pub enum PublicKeyInfo { @@ -161,9 +230,92 @@ impl PublicKeyInfo { } } +impl x509::SubjectPublicKeyInfo for PublicKeyInfo { + type AlgorithmId = AlgorithmId; + type SubjectPublicKey = Vec; + + fn algorithm_id(&self) -> AlgorithmId { + self.algorithm() + } + + fn public_key(&self) -> Vec { + match self { + PublicKeyInfo::Rsa { pubkey, .. } => { + cookie_factory::gen_simple(write_pki::rsa_pubkey(pubkey), vec![]) + .expect("can write to Vec") + } + PublicKeyInfo::EcP256(pubkey) => pubkey.as_bytes().to_vec(), + PublicKeyInfo::EcP384(pubkey) => pubkey.as_bytes().to_vec(), + } + } +} + +/// Digest algorithms. +/// +/// See RFC 4055 and RFC 8017. +enum DigestId { + /// Secure Hash Algorithm 256 (SHA256) + Sha256, +} + +impl x509::AlgorithmIdentifier for DigestId { + type AlgorithmOid = &'static [u64]; + + fn algorithm(&self) -> Self::AlgorithmOid { + match self { + // See https://tools.ietf.org/html/rfc4055#section-2.1 + DigestId::Sha256 => &[2, 16, 840, 1, 101, 3, 4, 2, 1], + } + } + + fn parameters( + &self, + w: cookie_factory::WriteContext, + ) -> cookie_factory::GenResult { + // Parameters are an explicit NULL + // See https://tools.ietf.org/html/rfc8017#appendix-A.2.4 + x509::der::write::der_null()(w) + } +} + +enum SignatureId { + /// Public-Key Cryptography Standards (PKCS) #1 version 1.5 signature algorithm with + /// Secure Hash Algorithm 256 (SHA256) and Rivest, Shamir and Adleman (RSA) encryption + /// + /// See RFC 4055 and RFC 8017. + Sha256WithRsaEncryption, + + /// Elliptic Curve Digital Signature Algorithm (DSA) coupled with the Secure Hash + /// Algorithm 256 (SHA256) algorithm + /// + /// See RFC 5758. + EcdsaWithSha256, +} + +impl x509::AlgorithmIdentifier for SignatureId { + type AlgorithmOid = &'static [u64]; + + fn algorithm(&self) -> Self::AlgorithmOid { + match self { + SignatureId::Sha256WithRsaEncryption => &[1, 2, 840, 113_549, 1, 1, 11], + SignatureId::EcdsaWithSha256 => &[1, 2, 840, 10045, 4, 3, 2], + } + } + + fn parameters( + &self, + w: cookie_factory::WriteContext, + ) -> cookie_factory::GenResult { + // No parameters for any SignatureId + Ok(w) + } +} + /// Certificates #[derive(Clone, Debug)] pub struct Certificate { + serial: Serial, + issuer: String, subject: String, subject_pki: PublicKeyInfo, data: Buffer, @@ -178,6 +330,109 @@ impl<'a> TryFrom<&'a [u8]> for Certificate { } impl Certificate { + /// Creates a new self-signed certificate for the given key. Writes the resulting + /// certificate to the slot before returning it. + pub fn generate_self_signed( + yubikey: &mut YubiKey, + key: SlotId, + serial: impl Into, + not_after: Option>, + subject: String, + subject_pki: PublicKeyInfo, + ) -> Result { + let serial = serial.into(); + + // Issuer and subject are the same in self-signed certificates + let issuer = subject.clone(); + + let mut tbs_cert = Buffer::new(Vec::with_capacity(CB_OBJ_MAX)); + + let signature_algorithm = match subject_pki.algorithm() { + AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => SignatureId::Sha256WithRsaEncryption, + AlgorithmId::EccP256 | AlgorithmId::EccP384 => SignatureId::EcdsaWithSha256, + }; + + cookie_factory::gen( + x509::write::tbs_certificate( + &serial.to_bytes(), + &signature_algorithm, + &issuer, + Utc::now(), + not_after, + &subject, + &subject_pki, + ), + tbs_cert.deref_mut(), + ) + .expect("can serialize to Vec"); + + let signature = match signature_algorithm { + SignatureId::Sha256WithRsaEncryption => { + use cookie_factory::{combinator::slice, sequence::tuple}; + use x509::{ + der::write::{der_octet_string, der_sequence}, + write::algorithm_identifier, + }; + + let em_len = if let AlgorithmId::Rsa1024 = subject_pki.algorithm() { + 128 + } else { + 256 + }; + + let h = Sha256::digest(&tbs_cert); + + let t = cookie_factory::gen_simple( + der_sequence(( + algorithm_identifier(&DigestId::Sha256), + der_octet_string(&h), + )), + vec![], + ) + .expect("can serialize into Vec"); + + let em = cookie_factory::gen_simple( + tuple(( + slice(&[0x00, 0x01]), + slice(&vec![0xff; em_len - t.len() - 3]), + slice(&[0x00]), + slice(t), + )), + vec![], + ) + .expect("can serialize to Vec"); + + sign_data(yubikey, &em, subject_pki.algorithm(), key) + } + SignatureId::EcdsaWithSha256 => sign_data( + yubikey, + &Sha256::digest(&tbs_cert), + subject_pki.algorithm(), + key, + ), + }?; + + let mut data = Buffer::new(Vec::with_capacity(CB_OBJ_MAX)); + + cookie_factory::gen( + x509::write::certificate(&tbs_cert, &signature_algorithm, &signature), + data.deref_mut(), + ) + .expect("can serialize to Vec"); + + let cert = Certificate { + serial, + issuer, + subject, + subject_pki, + data, + }; + + cert.write(yubikey, key, CertInfo::Uncompressed)?; + + Ok(cert) + } + /// Read a certificate from the given slot in the YubiKey pub fn read(yubikey: &mut YubiKey, slot: SlotId) -> Result { let txn = yubikey.begin_transaction()?; @@ -191,7 +446,6 @@ impl Certificate { } /// Write this certificate into the YubiKey in the given slot - #[cfg(feature = "untested")] pub fn write( &self, yubikey: &mut YubiKey, @@ -223,16 +477,30 @@ impl Certificate { _ => return Err(Error::InvalidObject), }; - let subject = format!("{}", parsed_cert.tbs_certificate.subject); + let serial = parsed_cert.tbs_certificate.serial.into(); + let issuer = parsed_cert.tbs_certificate.issuer.to_string(); + let subject = parsed_cert.tbs_certificate.subject.to_string(); let subject_pki = PublicKeyInfo::parse(&parsed_cert.tbs_certificate.subject_pki)?; Ok(Certificate { + serial, + issuer, subject, subject_pki, data: cert, }) } + /// Returns the serial number of the certificate. + pub fn serial(&self) -> &Serial { + &self.serial + } + + /// Returns the Issuer field of the certificate. + pub fn issuer(&self) -> &str { + &self.subject + } + /// Returns the SubjectName field of the certificate. pub fn subject(&self) -> &str { &self.subject @@ -279,7 +547,6 @@ pub(crate) fn read_certificate(txn: &Transaction<'_>, slot: SlotId) -> Result, slot: SlotId, @@ -298,8 +565,8 @@ pub(crate) fn write_certificate( let mut offset = Tlv::write(&mut buf, TAG_CERT, data)?; // write compression info and LRC trailer - offset += Tlv::write(&mut buf, TAG_CERT_COMPRESS, &[certinfo.into()])?; - offset += Tlv::write(&mut buf, TAG_CERT_LRC, &[])?; + offset += Tlv::write(&mut buf[offset..], TAG_CERT_COMPRESS, &[certinfo.into()])?; + offset += Tlv::write(&mut buf[offset..], TAG_CERT_LRC, &[])?; txn.save_object(object_id, &buf[..offset]) } @@ -378,3 +645,31 @@ mod read_pki { } } } + +mod write_pki { + use cookie_factory::{SerializeFn, WriteContext}; + use rsa::{BigUint, PublicKey, RSAPublicKey}; + use std::io::Write; + use x509::der::write::{der_integer, der_sequence}; + + /// Encodes a usize as an ASN.1 integer using DER. + fn der_integer_biguint<'a, W: Write + 'a>(num: &'a BigUint) -> impl SerializeFn + 'a { + move |w: WriteContext| der_integer(&num.to_bytes_be())(w) + } + + /// From [RFC 8017](https://tools.ietf.org/html/rfc8017#appendix-A.1.1): + /// ```text + /// RSAPublicKey ::= SEQUENCE { + /// modulus INTEGER, -- n + /// publicExponent INTEGER -- e + /// } + /// ``` + pub(super) fn rsa_pubkey<'a, W: Write + 'a>( + pubkey: &'a RSAPublicKey, + ) -> impl SerializeFn + 'a { + der_sequence(( + der_integer_biguint(pubkey.n()), + der_integer_biguint(pubkey.e()), + )) + } +} diff --git a/src/key.rs b/src/key.rs index fcd37e7..4be5278 100644 --- a/src/key.rs +++ b/src/key.rs @@ -38,8 +38,11 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ + apdu::{Ins, StatusWords}, certificate::{self, Certificate}, error::Error, + serialization::*, + settings, yubikey::YubiKey, ObjectId, }; @@ -47,32 +50,23 @@ use log::debug; use std::convert::TryFrom; #[cfg(feature = "untested")] +use crate::CB_OBJ_MAX; use crate::{ - apdu::{Ins, StatusWords}, certificate::PublicKeyInfo, policy::{PinPolicy, TouchPolicy}, - serialization::*, - settings, Buffer, CB_OBJ_MAX, + Buffer, }; -#[cfg(feature = "untested")] use elliptic_curve::weierstrass::PublicKey as EcPublicKey; -#[cfg(feature = "untested")] use log::{error, warn}; -#[cfg(feature = "untested")] use rsa::{BigUint, RSAPublicKey}; #[cfg(feature = "untested")] use zeroize::Zeroizing; -#[cfg(feature = "untested")] const CB_ECC_POINTP256: usize = 65; -#[cfg(feature = "untested")] const CB_ECC_POINTP384: usize = 97; -#[cfg(feature = "untested")] const TAG_RSA_MODULUS: u8 = 0x81; -#[cfg(feature = "untested")] const TAG_RSA_EXP: u8 = 0x82; -#[cfg(feature = "untested")] const TAG_ECC_POINT: u8 = 0x86; /// Slot identifiers. @@ -381,7 +375,6 @@ impl From for u8 { } } -#[cfg(feature = "untested")] impl AlgorithmId { /// Writes the `AlgorithmId` in the format the YubiKey expects during key generation. pub(crate) fn write(self, buf: &mut [u8]) -> Result { @@ -435,7 +428,6 @@ impl Key { } /// Generate key -#[cfg(feature = "untested")] #[allow(clippy::cognitive_complexity)] pub fn generate( yubikey: &mut YubiKey, @@ -758,7 +750,6 @@ pub fn attest(yubikey: &mut YubiKey, key: SlotId) -> Result { } /// Sign data using a PIV key -#[cfg(feature = "untested")] pub fn sign_data( yubikey: &mut YubiKey, raw_in: &[u8], diff --git a/src/lib.rs b/src/lib.rs index 5c2d38b..17bdd87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,7 +151,6 @@ pub mod msroots; pub mod policy; pub mod readers; mod serialization; -#[cfg(feature = "untested")] pub mod settings; mod transaction; pub mod yubikey; @@ -174,7 +173,6 @@ pub(crate) type Buffer = zeroize::Zeroizing>; pub(crate) const CB_BUF_MAX: usize = 3072; /// YubiKey max object size -#[cfg(feature = "untested")] pub(crate) const CB_OBJ_MAX: usize = CB_BUF_MAX - 9; pub(crate) const CB_OBJ_TAG_MIN: usize = 2; // 1 byte tag + 1 byte len #[cfg(feature = "untested")] diff --git a/src/mgm.rs b/src/mgm.rs index 75ecacb..ec6e72a 100644 --- a/src/mgm.rs +++ b/src/mgm.rs @@ -41,7 +41,6 @@ use crate::{ metadata, yubikey::YubiKey, CB_BUF_MAX, CB_OBJ_MAX, TAG_ADMIN, TAG_ADMIN_FLAGS_1, TAG_ADMIN_SALT, TAG_PROTECTED, TAG_PROTECTED_MGM, }; -#[cfg(feature = "untested")] use des::{ block_cipher_trait::{generic_array::GenericArray, BlockCipher}, TdesEde3, @@ -282,7 +281,6 @@ impl MgmKey { } /// Encrypt with 3DES key - #[cfg(feature = "untested")] #[allow(clippy::trivially_copy_pass_by_ref)] pub(crate) fn encrypt(&self, input: &[u8; DES_LEN_DES]) -> [u8; DES_LEN_DES] { let mut output = input.to_owned(); @@ -292,7 +290,6 @@ impl MgmKey { } /// Decrypt with 3DES key - #[cfg(feature = "untested")] #[allow(clippy::trivially_copy_pass_by_ref)] pub(crate) fn decrypt(&self, input: &[u8; DES_LEN_DES]) -> [u8; DES_LEN_DES] { let mut output = input.to_owned(); diff --git a/src/policy.rs b/src/policy.rs index 07fd4ce..b67674e 100644 --- a/src/policy.rs +++ b/src/policy.rs @@ -1,6 +1,5 @@ //! Enums representing key policies. -#[cfg(feature = "untested")] use crate::{error::Error, serialization::Tlv}; /// Specifies how often the PIN needs to be entered for access to the credential in a @@ -38,7 +37,6 @@ impl From for u8 { impl PinPolicy { /// Writes the `PinPolicy` in the format the YubiKey expects during key generation or /// importation. - #[cfg(feature = "untested")] pub(crate) fn write(self, buf: &mut [u8]) -> Result { match self { PinPolicy::Default => Ok(0), @@ -83,7 +81,6 @@ impl From for u8 { impl TouchPolicy { /// Writes the `TouchPolicy` in the format the YubiKey expects during key generation /// or importation. - #[cfg(feature = "untested")] pub(crate) fn write(self, buf: &mut [u8]) -> Result { match self { TouchPolicy::Default => Ok(0), diff --git a/src/serialization.rs b/src/serialization.rs index e36f171..9bde6e4 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -79,7 +79,6 @@ impl<'a> Tlv<'a> { } /// Writes a TLV to the given buffer. - #[cfg(feature = "untested")] pub(crate) fn write(buffer: &mut [u8], tag: u8, value: &[u8]) -> Result { if buffer.len() < CB_OBJ_TAG_MIN { return Err(Error::SizeError); @@ -99,7 +98,6 @@ impl<'a> Tlv<'a> { /// Writes a TLV to the given buffer. /// /// `value` is guaranteed to be called with a mutable slice of length `length`. - #[cfg(feature = "untested")] pub(crate) fn write_as( buffer: &mut [u8], tag: u8, @@ -126,7 +124,6 @@ impl<'a> Tlv<'a> { } /// Set length -#[cfg(feature = "untested")] pub(crate) fn set_length(buffer: &mut [u8], length: usize) -> Result { if length < 0x80 { if buffer.is_empty() { diff --git a/src/transaction.rs b/src/transaction.rs index d2dd9d9..a5cefb4 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -4,20 +4,17 @@ use crate::{ apdu::Response, apdu::{Ins, StatusWords, APDU}, error::Error, + key::{AlgorithmId, SlotId}, serialization::*, yubikey::*, - Buffer, ObjectId, CB_BUF_MAX, PIV_AID, YK_AID, + Buffer, ObjectId, CB_BUF_MAX, CB_OBJ_MAX, PIV_AID, YK_AID, }; use log::{error, trace}; use std::convert::TryInto; use zeroize::Zeroizing; #[cfg(feature = "untested")] -use crate::{ - key::{AlgorithmId, SlotId}, - mgm::{MgmKey, DES_LEN_3DES}, - CB_OBJ_MAX, -}; +use crate::mgm::{MgmKey, DES_LEN_3DES}; const CB_PIN_MAX: usize = 8; @@ -252,7 +249,6 @@ impl<'tx> Transaction<'tx> { /// This is the common backend for all public key encryption and signing /// operations. // TODO(tarcieri): refactor this to be less gross/coupled. - #[cfg(feature = "untested")] #[allow(clippy::too_many_arguments)] pub(crate) fn authenticated_command( &self, @@ -472,7 +468,6 @@ impl<'tx> Transaction<'tx> { } /// Save an object. - #[cfg(feature = "untested")] pub fn save_object(&self, object_id: ObjectId, indata: &[u8]) -> Result<(), Error> { let templ = [0, Ins::PutData.code(), 0x3f, 0xff]; diff --git a/src/yubikey.rs b/src/yubikey.rs index ba90d81..1c7fffc 100644 --- a/src/yubikey.rs +++ b/src/yubikey.rs @@ -31,48 +31,41 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ + apdu::{Ins, APDU}, cccid::CCC, chuid::CHUID, config::Config, error::Error, + mgm::MgmKey, readers::{Reader, Readers}, transaction::Transaction, }; use log::{error, info}; use pcsc::Card; use std::{ - convert::TryFrom, + convert::{TryFrom, TryInto}, fmt::{self, Display}, str::FromStr, }; #[cfg(feature = "untested")] use crate::{ - apdu::{Ins, StatusWords, APDU}, - metadata, - mgm::MgmKey, - Buffer, ObjectId, CB_BUF_MAX, CB_OBJ_MAX, MGMT_AID, TAG_ADMIN, TAG_ADMIN_FLAGS_1, - TAG_ADMIN_TIMESTAMP, + apdu::StatusWords, metadata, Buffer, ObjectId, CB_BUF_MAX, CB_OBJ_MAX, MGMT_AID, TAG_ADMIN, + TAG_ADMIN_FLAGS_1, TAG_ADMIN_TIMESTAMP, }; -#[cfg(feature = "untested")] use getrandom::getrandom; #[cfg(feature = "untested")] use secrecy::ExposeSecret; #[cfg(feature = "untested")] -use std::{ - convert::TryInto, - time::{SystemTime, UNIX_EPOCH}, -}; +use std::time::{SystemTime, UNIX_EPOCH}; /// Flag for PUK blocked pub(crate) const ADMIN_FLAGS_1_PUK_BLOCKED: u8 = 0x01; /// 3DES authentication -#[cfg(feature = "untested")] pub(crate) const ALGO_3DES: u8 = 0x03; /// Card management key -#[cfg(feature = "untested")] pub(crate) const KEY_CARDMGM: u8 = 0x9b; #[cfg(feature = "untested")] @@ -82,7 +75,6 @@ pub(crate) const CHREF_ACT_UNBLOCK_PIN: i32 = 1; #[cfg(feature = "untested")] pub(crate) const CHREF_ACT_CHANGE_PUK: i32 = 2; -#[cfg(feature = "untested")] const TAG_DYN_AUTH: u8 = 0x7c; /// Cached YubiKey PIN @@ -274,7 +266,6 @@ impl YubiKey { } /// Authenticate to the card using the provided management key (MGM). - #[cfg(feature = "untested")] pub fn authenticate(&mut self, mgm_key: MgmKey) -> Result<(), Error> { let txn = self.begin_transaction()?; diff --git a/tests/integration.rs b/tests/integration.rs index 2527f92..b50abca 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -5,8 +5,18 @@ use lazy_static::lazy_static; use log::trace; +use num_bigint::RandBigInt; +use rand::rngs::OsRng; +use rsa::{hash::Hashes::SHA2_256, PaddingScheme, PublicKey}; +use sha2::{Digest, Sha256}; +use std::convert::TryInto; use std::{env, sync::Mutex}; -use yubikey_piv::{key::Key, Error, YubiKey}; +use yubikey_piv::{ + certificate::{Certificate, PublicKeyInfo}, + key::{self, AlgorithmId, Key, RetiredSlotId, SlotId}, + policy::{PinPolicy, TouchPolicy}, + Error, MgmKey, YubiKey, +}; lazy_static! { /// Provide thread-safe access to a YubiKey @@ -96,3 +106,95 @@ fn test_verify_pin() { assert!(yubikey.verify_pin(b"000000").is_err()); assert!(yubikey.verify_pin(b"123456").is_ok()); } + +// +// Certificate support +// + +fn generate_self_signed_cert(algorithm: AlgorithmId) -> Certificate { + let mut yubikey = YUBIKEY.lock().unwrap(); + + assert!(yubikey.verify_pin(b"123456").is_ok()); + assert!(yubikey.authenticate(MgmKey::default()).is_ok()); + + let slot = SlotId::Retired(RetiredSlotId::R1); + + // Generate a new key in the selected slot. + let generated = key::generate( + &mut yubikey, + slot, + algorithm, + PinPolicy::Default, + TouchPolicy::Default, + ) + .unwrap(); + + let mut rng = OsRng::new().unwrap(); + + // Generate a self-signed certificate for the new key. + let cert_result = Certificate::generate_self_signed( + &mut yubikey, + slot, + rng.gen_biguint(20 * 8), + None, + "testSubject".to_owned(), + generated, + ); + + assert!(cert_result.is_ok()); + let cert = cert_result.unwrap(); + trace!("cert: {:?}", cert); + cert +} + +#[test] +#[ignore] +fn generate_self_signed_rsa_cert() { + let cert = generate_self_signed_cert(AlgorithmId::Rsa1024); + + // + // Verify that the certificate is signed correctly + // + + let pubkey = match cert.subject_pki() { + PublicKeyInfo::Rsa { pubkey, .. } => pubkey, + _ => unreachable!(), + }; + + let data = cert.as_ref(); + let tbs_cert_len = u16::from_be_bytes(data[6..8].try_into().unwrap()) as usize; + let msg = &data[4..8 + tbs_cert_len]; + let sig = &data[data.len() - 128..]; + + let hash = Sha256::digest(msg); + + assert!(pubkey + .verify(PaddingScheme::PKCS1v15, Some(&SHA2_256), &hash, sig) + .is_ok()); +} + +#[test] +#[ignore] +fn generate_self_signed_ec_cert() { + let cert = generate_self_signed_cert(AlgorithmId::EccP256); + + // + // Verify that the certificate is signed correctly + // + + let pubkey = match cert.subject_pki() { + PublicKeyInfo::EcP256(pubkey) => pubkey, + _ => unreachable!(), + }; + + let data = cert.as_ref(); + let tbs_cert_len = data[6] as usize; + let sig_algo_len = data[7 + tbs_cert_len + 1] as usize; + let sig_start = 7 + tbs_cert_len + 2 + sig_algo_len + 3; + let msg = &data[4..7 + tbs_cert_len]; + let sig = &data[sig_start..]; + + use ring::signature::{UnparsedPublicKey, ECDSA_P256_SHA256_ASN1}; + let ring_pk = UnparsedPublicKey::new(&ECDSA_P256_SHA256_ASN1, pubkey.as_bytes()); + assert!(ring_pk.verify(msg, sig).is_ok()); +}