sequoia-keystore-openpgp-card-0.2.0/.cargo_vcs_info.json0000644000000001520000000000100167170ustar { "git": { "sha1": "e90057ef8bc242a4c3fe8dc2c00ae972b381f575" }, "path_in_vcs": "openpgp-card" }sequoia-keystore-openpgp-card-0.2.0/Cargo.lock0000644000001772140000000000100147100ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", "generic-array 0.14.7", ] [[package]] name = "aes" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", ] [[package]] name = "aes-gcm" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", "cipher", "ctr", "ghash", "subtle", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstream" version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", ] [[package]] name = "anyhow" version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" [[package]] name = "argon2" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" dependencies = [ "base64ct", "blake2", "cpufeatures", "password-hash", ] [[package]] name = "ascii-canvas" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" dependencies = [ "term", ] [[package]] name = "async-trait" version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide 0.7.4", "object", "rustc-demangle", ] [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bindgen" version = "0.68.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", "lazy_static", "lazycell", "peeking_take_while", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn", ] [[package]] name = "bit-set" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake2" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ "digest", ] [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array 0.14.7", ] [[package]] name = "block-padding" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ "generic-array 0.14.7", ] [[package]] name = "buffered-reader" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db26bf1f092fd5e05b5ab3be2f290915aeb6f3f20c4e9f86ce0f07f336c2412f" dependencies = [ "bzip2", "flate2", "libc", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "bzip2" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ "bzip2-sys", "libc", ] [[package]] name = "bzip2-sys" version = "0.1.11+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" dependencies = [ "cc", "libc", "pkg-config", ] [[package]] name = "card-backend" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd3ee3a298842065dc489180c34a4fe4bbbb8643bb422009d79558a099fb42e5" dependencies = [ "thiserror", ] [[package]] name = "card-backend-pcsc" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68bb0b707b1b6b058ed93abd70ef65703ed6fd4150d32a0d735b78cfa61cbb35" dependencies = [ "card-backend", "iso7816-tlv", "log", "pcsc", ] [[package]] name = "cc" version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ "shlex", ] [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-targets 0.52.6", ] [[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", "zeroize", ] [[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "cmac" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" dependencies = [ "cipher", "dbl", "digest", ] [[package]] name = "colorchoice" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] [[package]] name = "crc32fast" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.7", "rand_core", "typenum", ] [[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] [[package]] name = "curve25519-dalek" version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest", "fiat-crypto", "rustc_version", "subtle", "zeroize", ] [[package]] name = "curve25519-dalek-derive" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "dbl" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" dependencies = [ "generic-array 0.14.7", ] [[package]] name = "der" version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", ] [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "const-oid", "crypto-common", "subtle", ] [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-next" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ "cfg-if", "dirs-sys-next", ] [[package]] name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", "redox_users", "windows-sys 0.48.0", ] [[package]] name = "dirs-sys-next" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "dyn-clone" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "eax" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" dependencies = [ "aead", "cipher", "cmac", "ctr", "subtle", ] [[package]] name = "ed25519" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", "rand_core", "serde", "sha2", "subtle", "zeroize", ] [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "ena" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] [[package]] name = "env_filter" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", ] [[package]] name = "env_logger" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", "env_filter", "humantime", "log", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "fastrand" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fd-lock" version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" dependencies = [ "cfg-if", "rustix", "windows-sys 0.52.0", ] [[package]] name = "fiat-crypto" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fixedbitset" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", ] [[package]] name = "futures" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "futures-sink" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", ] [[package]] name = "generic-array" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96512db27971c2c3eece70a1e106fbe6c87760234e31e8f7e5634912fe52794a" dependencies = [ "typenum", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[package]] name = "ghash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", "polyval", ] [[package]] name = "gimli" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex-slice" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5491a308e0214554f07a81d8944abe45f552871c12e3c3c6e7e5d354039a6c4c" [[package]] name = "hkdf" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ "digest", ] [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "idna" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indexmap" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "inout" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ "block-padding", "generic-array 0.14.7", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "iso7816-tlv" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7660d28d24a831d690228a275d544654a30f3b167a8e491cf31af5fe5058b546" dependencies = [ "untrusted", ] [[package]] name = "itertools" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "lalrpop" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" dependencies = [ "ascii-canvas", "bit-set", "ena", "itertools", "lalrpop-util", "petgraph", "regex", "regex-syntax 0.8.4", "string_cache", "term", "tiny-keccak", "unicode-xid", "walkdir", ] [[package]] name = "lalrpop-util" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ "regex-automata 0.4.7", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ "spin", ] [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", "windows-targets 0.52.6", ] [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", ] [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ "regex-automata 0.1.10", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memsec" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "miniz_oxide" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", ] [[package]] name = "mio" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", ] [[package]] name = "nettle" version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44e6ff4a94e5d34a1fd5abbd39418074646e2fa51b257198701330f22fcd6936" dependencies = [ "getrandom", "libc", "nettle-sys", "thiserror", "typenum", ] [[package]] name = "nettle-sys" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b495053a10a19a80e3a26bf1212e92e29350797b5f5bdc58268c3f3f818e66ec" dependencies = [ "bindgen", "cc", "libc", "pkg-config", "tempfile", "vcpkg", ] [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "num-bigint-dig" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ "byteorder", "lazy_static", "libm", "num-integer", "num-iter", "num-traits", "smallvec", ] [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-iter" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "object" version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] [[package]] name = "ocb3" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" dependencies = [ "aead", "cipher", "ctr", "subtle", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openpgp-card" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e80b16bc0178ae2c4af372c986721385ddee2df4b9622612911b5f4e3ffb4c1" dependencies = [ "card-backend", "chrono", "hex-slice", "log", "nom", "secrecy", "sha2", "thiserror", ] [[package]] name = "openpgp-cert-d" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd47b0b6df1022ca8a9a06791261c3153028abef191fe53aa326b7f443f2d6" dependencies = [ "anyhow", "dirs", "fd-lock", "libc", "sha1collisiondetection", "sha2", "tempfile", "thiserror", "walkdir", ] [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets 0.52.6", ] [[package]] name = "password-hash" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core", "subtle", ] [[package]] name = "pcsc" version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45ed9d7f816b7d9ce9ddb0062dd2f393b3af31411a95a35411809b4b9116ea08" dependencies = [ "bitflags 1.3.2", "pcsc-sys", ] [[package]] name = "pcsc-sys" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b09e9ba80f2c4d167f936d27594f7248bca3295921ffbfa44a24b339b6cb7403" dependencies = [ "pkg-config", ] [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "petgraph" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", ] [[package]] name = "phf_shared" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs8" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", ] [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polyval" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", "opaque-debug", "universal-hash", ] [[package]] name = "precomputed-hash" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "redox_syscall" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", "thiserror", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.7", "regex-syntax 0.8.4", ] [[package]] name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ "regex-syntax 0.6.29", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax 0.8.4", ] [[package]] name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] [[package]] name = "rustix" version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustversion" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "secrecy" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ "zeroize", ] [[package]] name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "sequoia-keystore-backend" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c55b047f9b6412c34dc7a26a42f278205cbf1e29516feab1228edccca215f500" dependencies = [ "anyhow", "async-trait", "env_logger", "futures", "log", "sequoia-openpgp", "tempfile", "thiserror", "tokio", ] [[package]] name = "sequoia-keystore-openpgp-card" version = "0.2.0" dependencies = [ "anyhow", "async-trait", "card-backend-pcsc", "env_logger", "futures", "log", "openpgp-card", "openpgp-cert-d", "sequoia-keystore-backend", "sequoia-openpgp", "serde", "serde_json", "tokio", "tracing", "tracing-subscriber", ] [[package]] name = "sequoia-openpgp" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "015e5fc3d023418b9db98ca9a7f3e90b305872eeafe5ca45c5c32b5eb335c1e8" dependencies = [ "aes-gcm", "anyhow", "argon2", "base64", "buffered-reader", "bzip2", "chrono", "cipher", "dyn-clone", "eax", "ed25519", "ed25519-dalek", "flate2", "getrandom", "hkdf", "idna", "lalrpop", "lalrpop-util", "libc", "memsec", "nettle", "num-bigint-dig", "ocb3", "rand_core", "regex", "regex-syntax 0.8.4", "sha1collisiondetection", "sha2", "thiserror", "win-crypto-ng", "winapi", "xxhash-rust", ] [[package]] name = "serde" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "sha1collisiondetection" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f606421e4a6012877e893c399822a4ed4b089164c5969424e1b9d1e66e6964b" dependencies = [ "digest", "generic-array 1.1.0", ] [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signature" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "rand_core", ] [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", ] [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "string_cache" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", "parking_lot", "phf_shared", "precomputed-hash", ] [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tempfile" version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", "once_cell", "rustix", "windows-sys 0.59.0", ] [[package]] name = "term" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ "dirs-next", "rustversion", "winapi", ] [[package]] name = "thiserror" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "tiny-keccak" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ "crunchy", ] [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "tokio" version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", "libc", "mio", "pin-project-lite", "socket2", "tokio-macros", "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "once_cell", "regex", "thread_local", "tracing", "tracing-core", ] [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-xid" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "universal-hash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", "subtle", ] [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "win-crypto-ng" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99abfb435a71e54ab2971d8d8c32f1a7e006cdbf527f71743b1d45b93517bb92" dependencies = [ "cipher", "doc-comment", "rand_core", "winapi", "zeroize", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "xxhash-rust" version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" [[package]] name = "yoke" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", "syn", ] sequoia-keystore-openpgp-card-0.2.0/Cargo.toml0000644000000050270000000000100147230ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.79" name = "sequoia-keystore-openpgp-card" version = "0.2.0" authors = ["Neal H. Walfield "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "An OpenPGP card backend for Sequoia's private key store." homepage = "https://sequoia-pgp.org/" readme = "README.md" keywords = [ "cryptography", "openpgp", ] categories = ["cryptography"] license = "LGPL-2.0-or-later" repository = "https://gitlab.com/sequoia-pgp/sequoia-keystore" [package.metadata.docs.rs] features = ["sequoia-openpgp/default"] [badges.maintenance] status = "actively-developed" [lib] name = "sequoia_keystore_openpgp_card" path = "src/lib.rs" [dependencies.anyhow] version = "1.0.18" [dependencies.async-trait] version = "0.1" [dependencies.card-backend-pcsc] version = "0.5" [dependencies.futures] version = "0.3" [dependencies.log] version = "0.4.17" [dependencies.openpgp-card] version = "0.5" [dependencies.openpgp-cert-d] version = "0.3.4" default-features = false [dependencies.sequoia-keystore-backend] version = "0.7" [dependencies.sequoia-openpgp] version = "2" default-features = false [dependencies.tokio] version = "1.19" features = [ "rt-multi-thread", "io-util", "net", ] [dev-dependencies.env_logger] version = ">=0.10, <0.12" [dev-dependencies.sequoia-openpgp] version = "2" features = ["compression"] default-features = false [dev-dependencies.serde] version = "1" features = ["derive"] [dev-dependencies.serde_json] version = "1" [dev-dependencies.tracing] version = "0.1" default-features = false [dev-dependencies.tracing-subscriber] version = "0.3" features = ["env-filter"] default-features = false [target."cfg(not(windows))".dev-dependencies.sequoia-openpgp] version = "2" features = [ "crypto-nettle", "__implicit-crypto-backend-for-tests", ] default-features = false [target."cfg(windows)".dev-dependencies.sequoia-openpgp] version = "2" features = [ "crypto-cng", "__implicit-crypto-backend-for-tests", ] default-features = false sequoia-keystore-openpgp-card-0.2.0/Cargo.toml.orig000064400000000000000000000036571046102023000204130ustar 00000000000000[package] name = "sequoia-keystore-openpgp-card" description = "An OpenPGP card backend for Sequoia's private key store." version = "0.2.0" authors = ["Neal H. Walfield "] homepage = "https://sequoia-pgp.org/" repository = "https://gitlab.com/sequoia-pgp/sequoia-keystore" readme = "README.md" keywords = ["cryptography", "openpgp"] categories = ["cryptography"] license = "LGPL-2.0-or-later" edition = "2021" rust-version = "1.79" [badges] maintenance = { status = "actively-developed" } [dependencies] anyhow = "1.0.18" async-trait = "0.1" card-backend-pcsc = "0.5" futures = "0.3" log = "0.4.17" openpgp-card = "0.5" # XXX: openpgp-card-sequoia is deprecated. We've copied what we # need, but we should fork it. # openpgp-card-sequoia = "0.2" openpgp-cert-d = { version = "0.3.4", default-features = false } sequoia-keystore-backend = { path = "../backend", version = "0.7" } sequoia-openpgp = { version = "2", default-features = false } tokio = { version = "1.19", features = [ "rt-multi-thread", "io-util", "net" ] } [dev-dependencies] env_logger = ">=0.10, <0.12" # rsa = "0.9" sequoia-openpgp = { version = "2", default-features = false, features = ["compression"] } serde = { version = "1", features = ["derive"] } serde_json = "1" tracing = {version = "0.1", default-features = false} tracing-subscriber = {version = "0.3", default-features = false, features = ["env-filter"]} [target.'cfg(not(windows))'.dev-dependencies] # Enables a crypto backend for the tests: sequoia-openpgp = { version = "2", default-features = false, features = ["crypto-nettle", "__implicit-crypto-backend-for-tests"] } [target.'cfg(windows)'.dev-dependencies] # Enables a crypto backend for the tests: sequoia-openpgp = { version = "2", default-features = false, features = ["crypto-cng", "__implicit-crypto-backend-for-tests"] } # Enables a crypto backend for the docs.rs generation: [package.metadata.docs.rs] features = ["sequoia-openpgp/default"] sequoia-keystore-openpgp-card-0.2.0/README.md000064400000000000000000000011621046102023000167700ustar 00000000000000An openpgp card backend for Sequoia's private key store. The `sequoia-keystore` crate implements a server that manages secret keys. Secret key material can be stored in files, on hardware devices like smartcards, or accessed via the network. `sequoia-keystore` doesn't implement these access methods. This is taken care of by various backends. This crate includes a backend that exposes the secret keys managed by OpenPGP cards. It uses PCSC in order to access the cards. On Linux distributions, this means that you'll need to install a PCSC service like PC/CS Lite. On Debian this is provided by the `pcscd` package. sequoia-keystore-openpgp-card-0.2.0/src/certd.rs000064400000000000000000000077321046102023000177600ustar 00000000000000use std::collections::HashMap; use std::path::Path; use futures::lock::Mutex; use futures::lock::MutexGuard; use sequoia_openpgp as openpgp; use openpgp::cert::raw::RawCert; use openpgp::Fingerprint; use openpgp::packet::Key; use openpgp::packet::key::PublicParts; use openpgp::packet::key::UnspecifiedRole; use openpgp::parse::Parse; use openpgp_cert_d as cert_d; use crate::Result; struct CertDCache { certd_tag: Option, // A cache of fingerprints to keys. keys: HashMap>, } pub struct CertD { certd: cert_d::CertD, cache: Mutex, } impl CertD { /// Opens the default cert-d. pub fn new() -> Result { Ok(CertD { certd: cert_d::CertD::new()?, cache: Mutex::new(CertDCache { certd_tag: None, keys: HashMap::default(), }), }) } /// Opens the specified cert-d. pub fn open

(path: P) -> Result where P: AsRef { Ok(CertD { certd: cert_d::CertD::with_base_dir(path.as_ref())?, cache: Mutex::new(CertDCache { certd_tag: None, keys: HashMap::default(), }), }) } /// Returns a reference to the underlying cert-d. pub fn certd(&self) -> &cert_d::CertD { &self.certd } // Check that the in-memory cache is up to date, and rebuild it if // necessary. fn rescan<'a>(&self, mut cache: MutexGuard<'a, CertDCache>) -> MutexGuard<'a, CertDCache> { let certd_tag = self.certd.tag(); if let Some(tag) = cache.certd_tag.as_ref() { if tag == &certd_tag { // Up to date. return cache; } } // Rebuild the cache. // // We should probably parallelize this, but we are only // dealing with raw certificates, so even for 1000s of // certificates this is pretty fast. let mut items = Vec::with_capacity(128); for item in self.certd.iter_files() { let (fingerprint, f) = match item { Ok(r) => r, Err(err) => { log::debug!("Reading certd: {}", err); continue; } }; let cert = match RawCert::from_reader(f) { Ok(cert) => cert, Err(err) => { log::debug!("Parsing certificate for {}: {}", fingerprint, err); continue; } }; for key in cert.keys() { items.push((key.fingerprint(), key.clone())); } } cache.certd_tag = Some(certd_tag); cache.keys = HashMap::from_iter(items.into_iter()); cache } /// Look up certificates by their fingerprint. pub async fn find_one(&self, fingerprint: &Fingerprint) -> Option> { let cache = self.cache.lock().await; // To avoid blocking the current thread, we run the rescan // function on a separate thread. It signals that it is done // by sending the result via a one-shot channel, which we can // asynchronously wait on. This avoids blocking the main // thread. let (sender, receiver) = futures::channel::oneshot::channel::<_>(); std::thread::scope(|s| { s.spawn(move || { sender.send(self.rescan(cache)) }); }); let cache = receiver.await.ok()?; if let Some(key) = cache.keys.get(fingerprint) { log::trace!("Found {} in cert-d", fingerprint); Some(key.clone()) } else { log::debug!("{} unusable: can't find the public key \ (try searching for it: sq network fetch {})", fingerprint, fingerprint); None } } } sequoia-keystore-openpgp-card-0.2.0/src/lib.rs000064400000000000000000001265351046102023000174300ustar 00000000000000use std::collections::HashMap; use std::collections::hash_map::Entry; use std::path::Path; use std::sync::Arc; use std::sync::Weak; use std::time::Duration; use std::time::SystemTime; use futures::lock::Mutex; use card_backend_pcsc; use openpgp_card::ocard::crypto::Cryptogram; use openpgp_card::ocard::data::KeyStatus; use openpgp_card::ocard::KeyType; use openpgp_card::ocard::Transaction; use sequoia_openpgp as openpgp; use openpgp::Cert; use openpgp::Fingerprint; use openpgp::Result; use openpgp::crypto::mem::Protected; use openpgp::crypto::ecdh; use openpgp::crypto::mpi; use openpgp::crypto::Password; use openpgp::crypto::SessionKey; use openpgp::packet; use openpgp::types::Curve; use openpgp::types::HashAlgorithm; use openpgp::types::PublicKeyAlgorithm; use sequoia_keystore_backend as backend; use backend::Error; use backend::ImportStatus; use backend::PasswordSource; use backend::Protection; use backend::utils::Directory; mod certd; // XXX: openpgp-card-sequoia is deprecated. We've copied what we // need, but we should fork it. #[cfg(test)] mod privkey; #[derive(Clone)] pub struct Backend { inner: Arc>, } struct BackendInternal { home: Directory, // False if the backend is disabled. enabled: bool, // OpenPGP cards don't store the OpenPGP key data structures nor // do they (always) have all the information required to // reconstruct them (in particular, it's missing the ECC algorithm // parameters). Since looking up a key by subkey means doing a // full scan, we cache the results. certd: Arc, // One device per OpenPGP card. // XXX: Make this a HashMap keyed on the card id. devices: Vec, last_scan: Option, } /// A Device exposes the (usable) keys managed by a particular /// OpenPGP Card. /// /// A key is usable if we have the OpenPGP data structure. If we /// don't have the OpenPGP key, we ignore the key. #[derive(Clone)] pub struct Device { // "application identifier". id: String, inner: Arc> } impl Device { /// Creates a new `WeakDevice` from this `Device`. fn downgrade(&self) -> WeakDevice { WeakDevice { id: self.id.clone(), inner: Arc::downgrade(&self.inner), } } } /// A `Device`, but with a weak reference to the data. /// /// Before you use this, you need to upgrade this to a `Device`. #[derive(Clone)] pub struct WeakDevice { id: String, inner: Weak>, } impl WeakDevice { /// Upgrades the `WeakDevice` to a `Device`, if possible. fn upgrade(&self) -> Option { Some(Device { id: self.id.clone(), inner: self.inner.upgrade()?, }) } } struct DeviceInternal { /// The "application identifier". /// /// This is of the form `FFFE:43233446`. It identifies both a /// card and the OpenPGP application. id: String, /// The opened card. /// /// The card is open in shared mode so that other applications can /// use it. card: openpgp_card::Card, /// Whether the card has a pinpad. pinpad: bool, /// A map from id (fingerprint) to key. keys: HashMap, } #[derive(Clone)] pub struct Key { // The fingerprint is also the id. fpr: Fingerprint, inner: Arc>, } /// A secret key. struct KeyInternal { device: WeakDevice, fingerprint: Fingerprint, public_key: packet::Key, /// The cached password. /// /// OpenPGP cards can have up to three passwords: an admin /// password, a user password, and an optional signing password. /// The user password unlocks the decryption and authentication /// slots. If configured, the signing password unlocks the /// signing slot. Otherwise, the user password unlocks the /// signing slot. /// /// We simplify things by having a per-slot password. This means /// that occasionally we'll ask for a password even though we know /// it (e.g., we've cached the password for the decryption key, /// and we're trying to use the authentication key), but that's /// not a big deal. password: Option, /// The key's slot. slot: openpgp_card::ocard::KeyType, } impl Backend { /// Initializes an openpgp card backend. /// /// `home` is the directory where the backend will look for its /// configuration, e.g., `$HOME/.sq/keystore/openpgp-card`. /// /// If `default` is true, this backend uses the cards managed by /// PCSC. Otherwise, the backend is disabled. pub async fn init>(home: P, default: bool) -> Result { log::trace!("Backend::init"); let home = Directory::from(home.as_ref()); let certd = Arc::new(certd::CertD::new()?); Ok(Backend { inner: Arc::new(Mutex::new(BackendInternal { home, enabled: default, certd, devices: vec![], last_scan: None, })) }) } /// Initializes an ephemeral OpenPGP card backend. /// /// This is primarily useful for testing. pub async fn init_ephemeral() -> Result { log::trace!("Backend::init_ephemeral"); let home = Directory::ephemeral()?; // XXX: default should be false, not true Self::init(home, true).await } } impl BackendInternal { async fn scan_internal(&mut self, force: bool) -> Result<()> { log::trace!("Backend::scan"); if ! self.enabled { log::debug!("OpenPGP Card backend is disabled"); return Ok(()); } if ! force { // Don't scan too often. Rate limit it to once every few seconds. if let Some(last_scan) = self.last_scan { if let Ok(duration) = SystemTime::now().duration_since(last_scan) { if duration < Duration::new(3, 0) { return Ok(()) } } } } let certd = Arc::clone(&self.certd); let card_backends = match card_backend_pcsc::PcscBackend::cards(None) { Ok(card_backends) => card_backends.collect(), Err(err) => { log::debug!("Listing openpgp cards using PC/SC: {}", err); Vec::new() } }; // XXX: Remove keys and devices that are not longer available. for card_backend in card_backends.into_iter() { let card_backend = match card_backend { Ok(card_backend) => card_backend, Err(err) => { log::debug!("Opening openpgp card backend: {}", err); continue; } }; let mut card = match openpgp_card::Card::new(card_backend) { Ok(card) => card, Err(err) => { log::debug!("Opening openpgp card: {}", err); continue; } }; let mut tx = match card.transaction() { Ok(tx) => tx, Err(err) => { log::debug!("Starting transaction on openpgp card: {}", err); continue; } }; // The device's identifier. let id = match tx.application_identifier() { Ok(id) => id, Err(err) => { log::debug!("Getting application id from openpgp card: {}", err); continue; } }; let id = id.ident(); // Gather information about the keys. let keyinfo = match tx.key_information() { Ok(keyinfo) => keyinfo, Err(err) => { log::debug!("Getting key information from openpgp card: {}", err); continue; } }; let present = if let Some(keyinfo) = keyinfo { [ keyinfo.sig_status() != KeyStatus::NotPresent, keyinfo.dec_status() != KeyStatus::NotPresent, keyinfo.aut_status() != KeyStatus::NotPresent ] } else { [false, false, false] }; let fprs = match tx.fingerprints() { Ok(tx) => tx, Err(err) => { log::debug!("Getting fingerprints from openpgp card: {}", err); continue; } }; let pinpad = tx.feature_pinpad_verify(); drop(tx); // See if we already know about this device. let mut device = None; for d in self.devices.iter_mut() { if d.id == id { device = Some(d); } } let device = if let Some(device) = device { // Already known. device } else { // Create a new device. let device = Device { id: id.clone(), inner: Arc::new(Mutex::new(DeviceInternal { id: id.clone(), keys: HashMap::new(), card: card, pinpad, })), }; self.devices.push(device); self.devices.last_mut().unwrap() }; let mut device_internal = device.inner.lock().await; let fprs = &[ (fprs.signature(), KeyType::Signing), (fprs.decryption(), KeyType::Decryption), (fprs.authentication(), KeyType::Authentication), ][..]; for ((fpr, slot), present) in fprs.into_iter().zip(present.into_iter()) { let Some(fpr) = fpr else { continue }; // Convert from an // openpgp_card::ocard::data::Fingerprint to a // sequoia_openpgp::Fingerprint. let fpr = Fingerprint::from_bytes(4, fpr.as_bytes())?; log::trace!("{}: {}present", fpr, if present { "" } else { "NOT " }); match device_internal.keys.entry(fpr.clone()) { Entry::Occupied(_oe) => { // Already have it. } Entry::Vacant(ve) => { // Need to add it. log::debug!("Found key {}", fpr); if let Some(pk) = certd.find_one(&fpr).await { let key = Key { fpr: fpr.clone(), inner: Arc::new(Mutex::new(KeyInternal { device: device.downgrade(), fingerprint: fpr, // XXX public_key: pk, password: None, slot: slot.clone(), })), }; ve.insert(key); } else { log::debug!("Ignoring {}: no public key available", fpr); } } } } } self.last_scan = Some(SystemTime::now()); Ok(()) } } #[async_trait::async_trait] impl backend::Backend for Backend { fn id(&self) -> String { "openpgp-card".into() } async fn scan(&mut self) -> Result<()> { let mut backend = self.inner.lock().await; backend.scan_internal(false).await } async fn list<'a>(&'a self) -> Box> + Send + Sync + 'a> { log::trace!("Backend::list"); let mut backend = self.inner.lock().await; if let Err(err) = backend.scan_internal(false).await { log::debug!("Scanning OpenPGP Cards: {}", err); } Box::new( backend.devices.iter() .map(|device| { Box::new(device.clone()) as Box }) .collect::>() .into_iter()) } async fn find_device<'a>(&self, id: &str) -> Result> { log::trace!("Backend::find_device"); let mut backend = self.inner.lock().await; // The first time through we look for the key without // scanning. If we don't find it, then we rescan. for scan in [false, true] { if scan { log::trace!("Rescanning"); if let Err(err) = backend.scan_internal(true).await { log::debug!("Scanning OpenPGP Cards: {}", err); } } for device in backend.devices.iter() { if device.id == id { return Ok(Box::new(device.clone()) as Box); } } } Err(Error::NotFound(id.into()).into()) } async fn find_key<'a>(&self, id: &str) -> Result> { log::trace!("Backend::find_key"); let mut backend = self.inner.lock().await; // The first time through we look for the key without // scanning. If we don't find it, then we rescan. for scan in [false, true] { if scan { log::trace!("Rescanning"); if let Err(err) = backend.scan_internal(true).await { log::debug!("Scanning OpenPGP Cards: {}", err); } } for device in backend.devices.iter() { let device = device.inner.lock().await; for (key_id, key) in device.keys.iter() { if &key_id.to_string() == id { return Ok(Box::new(key.clone()) as Box); } } } } Err(Error::NotFound(id.into()).into()) } async fn import<'a>(&self, _cert: Cert) -> Result)>> { log::trace!("Backend::import"); Err(Error::ExternalImportRequired(Some( "To import a key into an OpenPGP Card, use something like: \ oct admin --card ABCD:01234567 import key.priv".into())).into()) } } #[async_trait::async_trait] impl backend::DeviceHandle for Device { fn id(&self) -> String { log::trace!("Device::id"); self.id.clone() } async fn available(&self) -> bool { log::trace!("Device::available"); // XXX: Right now, we only support plugged-in cards. Change // this when we support registering OpenPGP cards. true } async fn configured(&self) -> bool { log::trace!("Device::configured"); // XXX: Right now, we only support plugged-in cards. Change // this when we support registering OpenPGP cards. true } async fn registered(&self) -> bool { log::trace!("Device::registered"); // XXX: Right now, we only support plugged-in cards. Change // this when we support registering OpenPGP cards. true } async fn lock(&mut self) -> Result<()> { log::trace!("Device::lock"); // We manage passwords at the slot level. let device = self.inner.lock().await; for key in device.keys.values() { let mut key_internal = key.inner.lock().await; key_internal.password = None; } Ok(()) } async fn list<'a>(&'a self) -> Box> + Send + Sync + 'a> { log::trace!("Device::list"); let device = self.inner.lock().await; let keys = device.keys.values() .map(|key| { Box::new(key.clone()) as Box }) .collect::>(); Box::new(keys.into_iter()) } } #[async_trait::async_trait] impl backend::KeyHandle for Key { fn id(&self) -> String { log::trace!("Key::id"); self.fpr.to_string() } fn fingerprint(&self) -> Fingerprint { log::trace!("Key::fingerprint"); self.fpr.clone() } async fn device<'a>(&self) -> Box { log::trace!("Key::device"); let key_internal = self.inner.lock().await; // Get the device that the key is on. let device = match key_internal.device.upgrade() { Some(device) => device, None => panic!("Device disappeared"), }; Box::new(device) } /// Returns whether the key is available. /// /// A key managed by an OpenPGP card is considered to *not* be /// available if: /// /// - It is not present /// - The smartcard is not inserted. async fn available(&self) -> bool { log::trace!("Key::available"); // XXX: Right now, we only support plugged-in cards. Change // this when we support registering OpenPGP cards. true } async fn locked(&self) -> Protection { log::trace!("Key::locked"); // We pessimistically consider a slot to be locked if we // haven't cached a password for the slot. On some cards, we // could use [`Card::check_user_verified`], but on other cards // that increase the pin's error count, which is a bit of a // disaster. // // [`Card::check_user_verified`]: https://docs.rs/openpgp-card/latest/openpgp_card/struct.Card.html#method.check_user_verified // Due to the locking order requirements, in order to get the // device, we have to drop the lock on the key. We copy what // we need from the key, and then get the device. let key_internal = self.inner.lock().await; let slot = key_internal.slot; let slot_str = || { match slot { KeyType::Signing => "signing".to_string(), KeyType::Decryption => "decryption".to_string(), KeyType::Authentication => "authentication".to_string(), s => format!("{:?}", s), } }; if key_internal.password.is_some() { return Protection::Unlocked; } // Get the device that the key is on. let device = match key_internal.device.upgrade() { Some(device) => device, None => { return Protection::ExternalOther( Some("Card disappeared".into())); } }; // Now we drop the lock on key and take the lock on device. drop(key_internal); let mut device_internal = device.inner.lock().await; if device_internal.pinpad { return Protection::ExternalPassword(None); } let mut tx = match device_internal.card.transaction() { Ok(tx) => tx, Err(err) => { log::debug!("Starting transaction on openpgp card: {}", err); return Protection::ExternalOther(Some( "Communication with card failed".into())); } }; match tx.user_interaction_flag(slot) { Ok(uif) => { if let Some(uif) = uif { if uif.touch_policy().touch_required() { return Protection::ExternalTouch(Some( format!("Touch the OpenPGP card to unlock the {} key", slot_str()))); } } } Err(err) => { log::debug!("Getting user interaction flags: {}", err); } } Protection::Password(Some( format!("Enter PIN to unlock the {} key", slot_str()))) } async fn password_source(&self) -> PasswordSource { log::trace!("Key::password_source"); // Due to the locking order requirements, in order to get the // device, we have to drop the lock on the key. let key_internal = self.inner.lock().await; // Get the device that the key is on. let device = match key_internal.device.upgrade() { Some(device) => device, None => { // We don't have a way to return an error. return PasswordSource::ExternalSideEffect; } }; // Now we drop the lock on key and take the lock on device. drop(key_internal); let mut device_internal = device.inner.lock().await; // Retake the key lock. let key_internal = self.inner.lock().await; if device_internal.pinpad { // XXX: Is ExternalOnDemand more accurate? return PasswordSource::ExternalSideEffect; } let mut tx = match device_internal.card.transaction() { Ok(tx) => tx, Err(err) => { log::debug!("Starting transaction on openpgp card: {}", err); // We don't have a way to return an error. return PasswordSource::ExternalSideEffect; } }; match tx.user_interaction_flag(key_internal.slot) { Ok(uif) => { if let Some(uif) = uif { if uif.touch_policy().touch_required() { return PasswordSource::InlineWithConfirmation; } } } Err(err) => { log::debug!("Getting user interaction flags: {}", err); } } PasswordSource::Inline } async fn decryption_capable(&self) -> bool { log::trace!("Key::decryption_capable"); let key_internal = self.inner.lock().await; match key_internal.slot { KeyType::Signing => false, KeyType::Decryption => true, KeyType::Authentication => false, _ => false, } } async fn signing_capable(&self) -> bool { log::trace!("Key::signing_capable"); let key_internal = self.inner.lock().await; match key_internal.slot { KeyType::Signing => true, KeyType::Decryption => false, KeyType::Authentication => true, _ => false, } } async fn unlock(&mut self, password: Option<&Password>) -> Result<()> { log::trace!("Key::unlock"); // Due to the locking order requirements, in order to get the // device, we have to drop the lock on the key. let key_internal = self.inner.lock().await; if key_internal.password.is_some() { return Err(Error::AlreadyUnlocked( "Key is already unlocked".into()).into()); } // Get the device that the key is on. let device = match key_internal.device.upgrade() { Some(device) => device, None => { return Err(anyhow::anyhow!("Card disappeared")); } }; // Now we drop the lock on key and take the lock on device. drop(key_internal); let mut device_internal = device.inner.lock().await; // Retake the key lock. let mut key_internal = self.inner.lock().await; // Prompt the user for the password. let pinpad = device_internal.pinpad; let mut tx = match device_internal.card.transaction() { Ok(tx) => tx, Err(err) => { log::debug!("Starting transaction on openpgp card: {}", err); // XXX: Turn it into a real error. return Err(err.into()); } }; if let Some(password) = password { // The user supplied a password. if pinpad { // We can't use the password: we need to use the pin // pad. return Err(Error::NoInlinePassword(None).into()); } let p = password.map(|p| String::from_utf8(p.to_vec()))?; if key_internal.slot == KeyType::Signing { tx.verify_user_signing_pin(p.into())?; } else { tx.verify_user_pin(p.into())?; } key_internal.password = Some(password.clone()); } else { // The user didn't supply a password. This means we are // supposed to unlock the slot using the pin pad. if ! pinpad { return Err(Error::NoExternalPassword( Some("Cannot prompt user for password".into())).into()); } fn cb() {} if key_internal.slot == KeyType::Signing { tx.verify_user_signing_pinpad(&cb)?; } else { tx.verify_user_pinpad(&cb)?; } } Ok(()) } async fn lock(&mut self) -> Result<()> { log::trace!("Key::lock"); let mut key_internal = self.inner.lock().await; key_internal.password = None; // XXX: We should also lock the slot. Currently the // openpgp-card library doesn't (appear to) support that. Ok(()) } async fn public_key(&self) -> packet::Key { log::trace!("Key::public_key"); let key = self.inner.lock().await; key.public_key.clone() } // XXX: Use plaintext_len. async fn decrypt_ciphertext(&mut self, ciphertext: &mpi::Ciphertext, _plaintext_len: Option) -> Result { log::trace!("Key::decrypt_ciphertext"); // Due to the locking order requirements, in order to get the // device, we have to drop the lock on the key. We copy what // we need from the key, and then get the device. let key_internal = self.inner.lock().await; // Copy what we need. let public_key = key_internal.public_key.clone(); let password = key_internal.password.clone(); // Get the device that the key is on. let device = match key_internal.device.upgrade() { Some(device) => device, None => { return Err(anyhow::anyhow!("Card disappeared")); } }; // Now we drop the lock on key and take the lock on device. drop(key_internal); let mut device_internal = device.inner.lock().await; let mut tx = match device_internal.card.transaction() { Ok(tx) => tx, Err(err) => { log::debug!("Starting transaction on openpgp card: {}", err); // XXX: Turn it into a real error. return Err(err.into()); } }; // The rest of this function is derived from // openpgp-card-sequoia's [CardDecryptor::decrypt]. // // [CardDecryptor::decrypt]: https://gitlab.com/openpgp-card/openpgp-card/-/blob/fa3e2e5c/openpgp-card-sequoia/src/decryptor.rs // // The file has the following copyright notice: // // SPDX-FileCopyrightText: 2021-2022 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 let unlock = || -> Result<()> { if let Some(password) = password { let password = password.map(|p| String::from_utf8(p.to_vec()))?; tx.verify_user_pin(password.into())?; } Ok(()) }; // Delegate a decryption operation to the OpenPGP card. // // This fn prepares the data structures that openpgp-card needs to // perform the decryption operation. // // (7.2.11 PSO: DECIPHER) match (ciphertext, public_key.mpis()) { (mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => { let dm = Cryptogram::RSA(ct.value()); unlock()?; let dec = tx.card().decipher(dm)?; let sk = SessionKey::from(&dec[..]); Ok(sk) } (mpi::Ciphertext::ECDH { ref e, .. }, mpi::PublicKey::ECDH { ref curve, .. }) => { let dm = if curve == &Curve::Cv25519 { assert_eq!( e.value()[0], 0x40, "Unexpected shape of decrypted Cv25519 data" ); // Ephemeral key without header byte 0x40 Cryptogram::ECDH(&e.value()[1..]) } else { // NIST curves: ephemeral key with header byte Cryptogram::ECDH(e.value()) }; // Decryption operation on the card unlock()?; let mut dec = tx.card().decipher(dm)?; // Specifically handle return value format like Gnuk's // (Gnuk returns a leading '0x04' byte and // an additional 32 trailing bytes) if curve == &Curve::NistP256 && dec.len() == 65 { assert_eq!(dec[0], 0x04, "Unexpected shape of decrypted NistP256 data"); // see Gnuk src/call-ec.c:82 dec = dec[1..33].to_vec(); } #[allow(non_snake_case)] let S: Protected = dec.into(); Ok(ecdh::decrypt_unwrap(&public_key, &S, ciphertext, None /* XXX */)?) } (ciphertext, public) => Err(anyhow::anyhow!( "Unsupported combination of ciphertext {:?} \ and public key {:?} ", ciphertext, public )), } } async fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) -> Result<(PublicKeyAlgorithm, mpi::Signature)> { log::trace!("Key::sign"); // Due to the locking order requirements, in order to get the // device, we have to drop the lock on the key. We copy what // we need from the key, and then get the device. let key_internal = self.inner.lock().await; // Copy what we need. let public_key = key_internal.public_key.clone(); let password = key_internal.password.clone(); let slot = key_internal.slot; // Get the device that the key is on. let device = match key_internal.device.upgrade() { Some(device) => device, None => { return Err(anyhow::anyhow!("Card disappeared")); } }; // Now we drop the lock on key and take the lock on device. drop(key_internal); let mut device_internal = device.inner.lock().await; let mut tx = match device_internal.card.transaction() { Ok(tx) => tx, Err(err) => { log::debug!("Starting transaction on openpgp card: {}", err); // XXX: Turn it into a real error. return Err(err.into()); } }; let unlock = || -> Result<()> { if let Some(password) = password { log::trace!("Unlocking key with password"); let password = password.map(|p| String::from_utf8(p.to_vec()))?; tx.verify_user_signing_pin(password.into())?; log::trace!("Successfully unlocked slot"); } else { log::debug!("Not unlocking slot; no password cached"); } Ok(()) }; // The rest of this function is derived from // openpgp-card-sequoia's [CardSigner::sign]. // // [CardDecryptor::decrypt]: https://gitlab.com/openpgp-card/openpgp-card/-/blob/fa3e2e5c/openpgp-card-sequoia/src/signer.rs // // The file has the following copyright notice: // // SPDX-FileCopyrightText: 2021-2022 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 let sig_fn = if slot == KeyType::Signing { Transaction::signature_for_hash } else { Transaction::authenticate_for_hash }; // Delegate a signing (or auth) operation to the OpenPGP card. // // This fn prepares the data structures that openpgp-card needs to // perform the signing operation. // // (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) // or (7.2.13 INTERNAL AUTHENTICATE) use openpgp_card::ocard::crypto::Hash; let sig = match (public_key.pk_algo(), public_key.mpis()) { #[allow(deprecated)] (PublicKeyAlgorithm::RSASign, mpi::PublicKey::RSA { .. }) | (PublicKeyAlgorithm::RSAEncryptSign, mpi::PublicKey::RSA { .. }) => { let hash = match hash_algo { sequoia_openpgp::types::HashAlgorithm::SHA256 => Hash::SHA256( digest .try_into() .map_err(|_| anyhow::anyhow!("invalid slice length"))?, ), sequoia_openpgp::types::HashAlgorithm::SHA384 => Hash::SHA384( digest .try_into() .map_err(|_| anyhow::anyhow!("invalid slice length"))?, ), sequoia_openpgp::types::HashAlgorithm::SHA512 => Hash::SHA512( digest .try_into() .map_err(|_| anyhow::anyhow!("invalid slice length"))?, ), _ => { return Err(anyhow::anyhow!( "Unsupported hash algorithm for RSA {:?}", hash_algo )); } }; unlock()?; let sig = sig_fn(tx.card(), hash)?; let mpi = mpi::MPI::new(&sig[..]); mpi::Signature::RSA { s: mpi } } (PublicKeyAlgorithm::EdDSA, mpi::PublicKey::EdDSA { .. }) => { let hash = Hash::EdDSA(digest); unlock()?; let sig = sig_fn(tx.card(), hash)?; let r = mpi::MPI::new(&sig[..32]); let s = mpi::MPI::new(&sig[32..]); mpi::Signature::EdDSA { r, s } } (PublicKeyAlgorithm::ECDSA, mpi::PublicKey::ECDSA { curve, .. }) => { let hash = match curve { Curve::NistP256 => Hash::ECDSA(&digest[..32]), Curve::NistP384 => Hash::ECDSA(&digest[..48]), Curve::NistP521 => Hash::ECDSA(&digest[..64]), _ => Hash::ECDSA(digest), }; unlock()?; let sig = sig_fn(tx.card(), hash)?; let len_2 = sig.len() / 2; let r = mpi::MPI::new(&sig[..len_2]); let s = mpi::MPI::new(&sig[len_2..]); mpi::Signature::ECDSA { r, s } } // FIXME: implement NIST etc (pk_algo, _) => return Err(anyhow::anyhow!( "Unsupported combination of algorithm {:?} and pubkey {:?}", pk_algo, public_key )), }; log::trace!("Returned a {} signature", public_key.pk_algo()); Ok((public_key.pk_algo(), sig)) } async fn export(&mut self) -> Result> { Err(Error::OperationNotSupported( "Keys cannot be exported from OpenPGP cards.".into()).into()) } async fn change_password(&mut self, password: Option<&Password>) -> Result<()> { log::trace!("KeyHandle::change_password({}, {})", self.fingerprint(), if let Some(password) = password { if password.map(|p| p.is_empty()) { "clear password" } else { "set password" } } else { "ask for password" }); Err(Error::OperationNotSupported( "Use an external tool to manage OpenPGP cards.".into()).into()) } async fn delete_secret_key_material(&mut self) -> Result<()> { log::trace!("KeyHandle::delete_secret_key_material"); Err(Error::OperationNotSupported( "Use an external tool to manage OpenPGP cards.".into()).into()) } } #[cfg(test)] mod tests { use super::*; use openpgp::KeyHandle; use openpgp::cert::amalgamation::key::ValidKeyAmalgamation; use openpgp::parse::Parse; use openpgp::policy::StandardPolicy; use openpgp::serialize::Serialize; const P: &StandardPolicy = &StandardPolicy::new(); use backend::test_framework; use backend::Backend as _; /// This is the ID and PINs for the opcard-rs virtual smart card. const TEST_CARD_ID: &str = "0000:00000000"; const TEST_CARD_ADMIN_PIN: &str = "12345678"; const TEST_CARD_USER_PIN: &str = "123456"; fn get_test_card() -> Option> { let card_backends = match card_backend_pcsc::PcscBackend::cards(None) { Ok(card_backends) => card_backends.collect(), Err(err) => { log::debug!("Listing openpgp cards using PC/SC: {}", err); Vec::new() } }; let mut test_card = None; for card_backend in card_backends.into_iter() { let card_backend = match card_backend { Ok(card_backend) => card_backend, Err(err) => { log::debug!("Opening openpgp card backend: {}", err); continue; } }; let mut card = match openpgp_card::Card::new(card_backend) { Ok(card) => card, Err(err) => { log::debug!("Opening openpgp card: {}", err); continue; } }; let tx = match card.transaction() { Ok(tx) => tx, Err(err) => { log::debug!("Starting transaction on openpgp card: {}", err); continue; } }; let id = match tx.application_identifier() { Ok(id) => id, Err(err) => { log::debug!("Getting application id from openpgp card: {}", err); continue; } }; let id = id.ident(); if id == TEST_CARD_ID { drop(tx); test_card = Some(card); break; } else { eprintln!("Found card {}", id); } } test_card } fn preinit() -> bool { // Don't run the tests if the test card is not available. get_test_card().is_some() } async fn init_backend() -> Backend { let backend = Backend::init_ephemeral().await.expect("can init backend"); let mut card = if let Some(card) = get_test_card() { card } else { panic!("Test card ({}) not available", TEST_CARD_ID); }; // Reset the card so that it is empty. let mut tx = card.transaction().expect("can start a transaction"); tx.factory_reset().expect("can factory reset"); backend } async fn import_cert(backend: &mut Backend, cert: &Cert) { let vc = cert.with_policy(P, None).expect("valid cert"); eprintln!("Importing cert {}'s subkeys", cert.fingerprint()); for ka in vc.keys().subkeys() { eprintln!(" - {}, secret: {}, key flags: {:?}", ka.key().fingerprint(), ka.key().has_secret(), ka.key_flags()); } let signing_key = vc.keys().subkeys().for_signing().secret().next(); let auth_key = vc.keys().subkeys().for_authentication().secret().next(); let encryption_key = vc.keys().subkeys().for_transport_encryption().secret().next(); assert!(signing_key.is_some() || auth_key.is_some() || encryption_key.is_some(), "Expect at least one subkey with secret key material"); let mut card = if let Some(card) = get_test_card() { card } else { panic!("Test card ({}) not available", TEST_CARD_ID); }; let mut tx = card.transaction().expect("can start a transaction"); tx.verify_admin_pin(TEST_CARD_ADMIN_PIN.to_string().into()) .expect("can use admin pin"); let mut admin = tx.to_admin_card(None) .expect("can access admin functionality"); // Import the keys. let mut import_key = |key: Option>, slot: KeyType| { if let Some(key) = key { eprintln!("Importing key {} to {:?} slot", key.key().fingerprint(), slot); assert!(key.key().has_unencrypted_secret()); let key = Box::new(privkey::SequoiaKey::new(key.into(), None)); //let key = openpgp_card_sequoia::util::vka_as_uploadable_key( // key.into(), None); admin.import_key(key, slot) .expect("can import key"); } else { eprintln!("No {:?} key to import", slot); } }; import_key(signing_key, KeyType::Signing); import_key(auth_key, KeyType::Authentication); import_key(encryption_key, KeyType::Decryption); // And insert the certificate into our local certd so that we // can find the OpenPGP keys. backend.inner.lock().await.certd.certd().insert( &cert.fingerprint().to_string(), (), false, |(), disk| { let cert_; let cert = if let Some(disk) = disk { // Merge. let disk = Cert::from_bytes(disk).expect("valid cert"); cert_ = cert.clone().merge_public(disk).expect("can merge"); &cert_ } else { // New. cert }; let mut bytes = Vec::new(); cert.serialize(&mut bytes).expect("can serialize to a vec"); Ok(bytes.into()) }) .expect("inserted"); } sequoia_keystore_backend::generate_tests!( preinit, true, // Serialize tests. Backend, init_backend, import_cert, false, // Can import encrypted secret key material. Some(1), // Supported key sets. Some(TEST_CARD_USER_PIN), // Default password. false, // Can export. false, // Can change password. false // Can delete secret key material. ); } sequoia-keystore-openpgp-card-0.2.0/src/privkey.rs000064400000000000000000000371361046102023000203510ustar 00000000000000// SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 // Copied from // https://gitlab.com/openpgp-card/openpgp-card/-/blob/fa3e2e5c/openpgp-card-sequoia/src/privkey.rs use std::convert::TryFrom; use std::convert::TryInto; use std::path::PathBuf; use openpgp_card::ocard::crypto::{CardUploadableKey, EccKey, EccType, PrivateKeyMaterial, RSAKey}; use openpgp_card::ocard::data::{Fingerprint, KeyGenerationTime}; use openpgp_card::Error; use sequoia_openpgp as openpgp; use sequoia_openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation; use sequoia_openpgp::crypto::{mpi, mpi::ProtectedMPI, mpi::MPI}; use sequoia_openpgp::packet::{ key, key::{SecretParts, UnspecifiedRole}, Key, }; use sequoia_openpgp::types::{Curve, Timestamp}; /// A SequoiaKey represents the private cryptographic key material of an /// OpenPGP (sub)key to be uploaded to an OpenPGP card. pub(crate) struct SequoiaKey { key: Key, public: mpi::PublicKey, password: Option, } impl SequoiaKey { /// A `SequoiaKey` wraps a Sequoia PGP private (sub)key data /// (i.e. a ValidErasedKeyAmalgamation) in a form that can be uploaded /// by the openpgp-card crate. pub(crate) fn new( vka: ValidErasedKeyAmalgamation, password: Option, ) -> Self { let public = vka.key().mpis().clone(); Self { key: vka.key().clone(), public, password, } } } /// Implement the `CardUploadableKey` trait that openpgp-card uses to /// upload (sub)keys to a card. impl CardUploadableKey for SequoiaKey { fn private_key(&self) -> Result { // Decrypt key with password, if set let key = match &self.password { None => self.key.clone(), Some(pw) => self .key .clone() .decrypt_secret(&sequoia_openpgp::crypto::Password::from(pw.as_str())) .map_err(|e| Error::InternalError(format!("sequoia decrypt failed {e:?}")))?, }; // Get private cryptographic material let unenc = if let Some(key::SecretKeyMaterial::Unencrypted(ref u)) = key.optional_secret() { u } else { panic!("can't get private key material"); }; let secret_key_material = unenc.map(|mpis| mpis.clone()); match (self.public.clone(), secret_key_material) { (mpi::PublicKey::RSA { e, n }, mpi::SecretKeyMaterial::RSA { d, p, q, u: _ }) => { let sq_rsa = SqRSA::new(self.key.fingerprint(), e, d, n, p, q)?; Ok(PrivateKeyMaterial::R(Box::new(sq_rsa))) } (mpi::PublicKey::ECDH { curve, q, .. }, mpi::SecretKeyMaterial::ECDH { scalar }) => { let sq_ecc = SqEccKey::new(curve, scalar, q, EccType::ECDH); Ok(PrivateKeyMaterial::E(Box::new(sq_ecc))) } (mpi::PublicKey::ECDSA { curve, q, .. }, mpi::SecretKeyMaterial::ECDSA { scalar }) => { let sq_ecc = SqEccKey::new(curve, scalar, q, EccType::ECDSA); Ok(PrivateKeyMaterial::E(Box::new(sq_ecc))) } (mpi::PublicKey::EdDSA { curve, q, .. }, mpi::SecretKeyMaterial::EdDSA { scalar }) => { let sq_ecc = SqEccKey::new(curve, scalar, q, EccType::EdDSA); Ok(PrivateKeyMaterial::E(Box::new(sq_ecc))) } (p, s) => { Err(Error::InternalError(format!( "Unexpected algorithms: public {:?}, secret {:?}", p, s))) } } } /// Number of non-leap seconds since January 1, 1970 0:00:00 UTC /// (aka "UNIX timestamp") fn timestamp(&self) -> KeyGenerationTime { let ts: Timestamp = Timestamp::try_from(self.key.creation_time()) .expect("Creation time cannot be converted into u32 timestamp"); let ts: u32 = ts.into(); ts.into() } fn fingerprint(&self) -> Result { let fp = self.key.fingerprint(); fp.as_bytes().try_into() } } /// RSA-specific data-structure to hold private (sub)key material for upload /// with the `openpgp-card` crate. #[derive(serde::Serialize, serde::Deserialize)] struct SqRSA { #[serde(with = "serde_mpi")] e: MPI, #[serde(with = "serde_mpi")] n: MPI, #[serde(with = "serde_protected_mpi")] p: ProtectedMPI, #[serde(with = "serde_protected_mpi")] q: ProtectedMPI, #[serde(with = "serde_protected_mpi")] pq: ProtectedMPI, #[serde(with = "serde_protected_mpi")] dp1: ProtectedMPI, #[serde(with = "serde_protected_mpi")] dq1: ProtectedMPI, } impl SqRSA { #[allow(clippy::many_single_char_names)] fn new( fipr: openpgp::Fingerprint, e: MPI, d: ProtectedMPI, n: MPI, p: ProtectedMPI, q: ProtectedMPI, ) -> Result { Self::load(fipr, e, d, n, p, q) //Self::generate(fipr, e, d, n, p, q) } /// Loads RSA parameters from the test data set. /// /// If this ever gets outdated, for example because new test /// certificates are added, the files in /// `backend/tests/data/keys/rsa-parameters` need to be /// regenerated. /// /// To do that, do the following: /// /// - enable the `rsa` dev dependency of this crate /// - uncomment `SqRSA::generate` /// - change `SqRSA::new` to use `generate` instead of `load` /// - run the tests /// - commit any changes and new files in /// `backend/tests/data/keys/rsa-parameters` #[allow(clippy::many_single_char_names)] fn load( fipr: openpgp::Fingerprint, _e: MPI, _d: ProtectedMPI, _n: MPI, _p: ProtectedMPI, _q: ProtectedMPI, ) -> Result { let data = sequoia_keystore_backend::test_framework::data::try_key( &Self::path(fipr).display().to_string()) .expect("test data needs to be updated, see \ openpgp-card/src/privkey.rs"); Ok(serde_json::from_slice(data).unwrap()) } fn path(fipr: openpgp::Fingerprint) -> PathBuf { PathBuf::from("rsa-parameters") .join(fipr.to_string()) .with_extension("json") } //#[allow(clippy::many_single_char_names)] //fn generate( // fipr: openpgp::Fingerprint, // e: MPI, // d: ProtectedMPI, // n: MPI, // p: ProtectedMPI, // q: ProtectedMPI, //) -> Result { // use rsa::traits::PrivateKeyParts; // // fn mpi_to_biguint(mpi: &MPI) -> rsa::BigUint { // slice_to_biguint(mpi.value()) // } // // fn slice_to_biguint(bytes: &[u8]) -> rsa::BigUint { // rsa::BigUint::from_bytes_be(bytes) // } // // let key = rsa::RsaPrivateKey::from_components( // mpi_to_biguint(&n), // mpi_to_biguint(&e), // slice_to_biguint(d.value()), // vec![slice_to_biguint(p.value()), slice_to_biguint(q.value())], // ) // .map_err(|e| Error::InternalError(format!("rsa error {e:?}")))?; // // let pq = key // .qinv() // .ok_or_else(|| Error::InternalError("pq value missing".into()))? // .to_biguint() // .ok_or_else(|| Error::InternalError("conversion to bigunit failed".into()))? // .to_bytes_be() // .into(); // // let dp1 = key // .dp() // .ok_or_else(|| Error::InternalError("dp1 value missing".into()))? // .to_bytes_be() // .into(); // // let dq1 = key // .dq() // .ok_or_else(|| Error::InternalError("dq1 value missing".into()))? // .to_bytes_be() // .into(); // // let rsa = Self { // e, // n, // p, // q, // pq, // dp1, // dq1, // }; // // let path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) // .parent().unwrap() // .join("backend").join("tests").join("data").join("keys") // .join(Self::path(fipr)); // let mut sink = std::fs::File::create(path).unwrap(); // serde_json::to_writer_pretty(&mut sink, &rsa).unwrap(); // // Ok(rsa) //} } impl RSAKey for SqRSA { fn e(&self) -> &[u8] { self.e.value() } fn p(&self) -> &[u8] { self.p.value() } fn q(&self) -> &[u8] { self.q.value() } fn pq(&self) -> Box<[u8]> { self.pq.value().into() } fn dp1(&self) -> Box<[u8]> { self.dp1.value().into() } fn dq1(&self) -> Box<[u8]> { self.dq1.value().into() } fn n(&self) -> &[u8] { self.n.value() } } /// ECC-specific data-structure to hold private (sub)key material for upload /// with the `openpgp-card` crate. struct SqEccKey { curve: Curve, private: ProtectedMPI, public: MPI, ecc_type: EccType, } impl SqEccKey { fn new(curve: Curve, private: ProtectedMPI, public: MPI, ecc_type: EccType) -> Self { SqEccKey { curve, private, public, ecc_type, } } } impl EccKey for SqEccKey { fn oid(&self) -> &[u8] { self.curve.oid() } fn private(&self) -> Vec { match self.curve { Curve::NistP256 => self.private.value_padded(0x20).to_vec(), Curve::NistP384 => self.private.value_padded(0x30).to_vec(), Curve::NistP521 => self.private.value_padded(0x42).to_vec(), Curve::Cv25519 | Curve::Ed25519 => self.private.value_padded(0x20).to_vec(), _ => self.private.value().to_vec(), } } fn public(&self) -> Vec { // FIXME: padding? self.public.value().to_vec() } fn ecc_type(&self) -> EccType { self.ecc_type } } mod serde_mpi { use serde::{Deserialize, Deserializer, Serializer}; use sequoia_openpgp::fmt::hex; use super::*; pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { use serde::de::Error; String::deserialize(de) .and_then(|s| hex::decode(&s) .map_err(|e| Error::custom(e.to_string()))) .map(Into::into) } pub fn serialize(v: &MPI, ser: S) -> Result where S: Serializer, { ser.serialize_str(&hex::encode(v.value())) } } mod serde_protected_mpi { use serde::{Deserialize, Deserializer, Serializer}; use sequoia_openpgp::fmt::hex; use super::*; pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { use serde::de::Error; String::deserialize(de) .and_then(|s| hex::decode(&s) .map_err(|e| Error::custom(e.to_string()))) .map(Into::into) } pub fn serialize(v: &ProtectedMPI, ser: S) -> Result where S: Serializer, { ser.serialize_str(&hex::encode(v.value())) } } // #[cfg(test)] // mod tests { // use openpgp::cert::Cert; // use openpgp::crypto::mpi::PublicKey; // use openpgp::packet::key::SecretKeyMaterial; // use openpgp::parse::Parse; // use sequoia_openpgp as openpgp; // use testresult::TestResult; // // use super::*; // // #[test] // fn parsing_rsa_key() -> TestResult { // let cert = Cert::from_bytes( // r#"-----BEGIN PGP PRIVATE KEY BLOCK----- // // lQHYBGPmItUBBADp/S0sPqOQF6oBEQf558E5HeVtRP0qyWaVT0/fl7gj2jMSu6kF // de1jbr7AdeQxa7RiOo7m/ob8ZzKIzFNMLVfKsfo4mn5QjYulnadl+dyl87Jj1TlN // iEmeVvKbJUzXf7p4B4zFBFwIoCWtGZMTuUOgvi11Gbt00QwNUZdB10VjNwARAQAB // AAP/dH22pR3kSWL2oMRNX8XZJSn0pENh9RDCsRgE0HDU3IiPv8ZMviq5TjT+44tt // 2YrhCbxUk7zpEDUCbCepWrYCS7Q7pMCJul2AdymJBDkNwzrPjNdzPwx1mOIudDFp // uosokjzx/bDNb9c8rdQpB5Oz9f9qZ9WhmfittQvBFPmBjyUCAPHWyhSVt86Wc3Dd // /1nQRLwMHVJK6VszIMO0EYgGvaFN9WXh6VUue9DXnAkHejUDNpsOlJfiAHMDU0fS // PnBX4D0CAPewtqGyIyluZ+S/+MJQBOUqLPzqHHr6smGmbOYFG52RFv17LhQH/02h // sLkd6qXXNUFSOF02XiYV9RywhnSadIMCALP4oM2YGCQL+B5bj3bT1uwoF8O0gwuW // FAc6Sz3ESpaI11ABLOv2wPNS3OcUyyIUe/DPVbekaKswvO57Ddzw5iait7QFQUJD // REWIzgQTAQgAOBYhBBCVR7AQd8pmtyaMetgkYA0A8AOABQJj5iLVAhsBBQsJCAcC // BhUKCQgLAgQWAgMBAh4BAheAAAoJENgkYA0A8AOA5W4EAMGuqrRLFjonYYS97Ypx // zo7HUpOALrLVgfwKoxX2/DdC4FWOQ61cog63KKOiM/DjF/TimLD7R4wls6pbELyD // T038FOlGoWtmtQuf3iUsBKdAYPPiqInaDU9XCy/hm1f7xOz70kpUXVG8K6c6my+b // /fGkli/zcEWR55dOMPeoZ6zF // =QZJ9 // -----END PGP PRIVATE KEY BLOCK-----"#, // )?; // if let Key::V4(key) = cert.primary_key().key().clone().parts_into_secret()? { // let (e, n) = if let PublicKey::RSA { e, n } = key.mpis() { // (e, n) // } else { // unreachable!(); // }; // if let Some(SecretKeyMaterial::Unencrypted(secret)) = key.optional_secret() { // assert!(secret.map(|secret| { // if let openpgp::crypto::mpi::SecretKeyMaterial::RSA { d, p, q, .. } = secret { // let rsa = SqRSA::new(e.clone(), d.clone(), n.clone(), p.clone(), q.clone()) // .unwrap(); // assert_eq!( // rsa.pq(), // vec![ // 66, 30, 140, 169, 99, 220, 224, 43, 7, 176, 133, 35, 251, 25, 162, // 178, 14, 200, 188, 60, 82, 126, 134, 117, 184, 10, 186, 28, 162, // 177, 225, 3, 147, 218, 96, 195, 182, 159, 32, 48, 87, 141, 182, 73, // 232, 37, 154, 152, 123, 11, 1, 86, 188, 224, 157, 35, 125, 4, 210, // 229, 233, 121, 207, 14 // ] // .into() // ); // assert_eq!( // rsa.dp1(), // vec![ // 19, 67, 44, 109, 95, 79, 120, 160, 251, 40, 238, 69, 188, 125, 158, // 59, 236, 43, 25, 182, 229, 199, 97, 215, 38, 63, 93, 118, 28, 51, // 86, 121, 195, 38, 14, 76, 107, 128, 124, 84, 50, 24, 55, 143, 228, // 231, 252, 13, 137, 100, 43, 233, 189, 18, 148, 22, 155, 183, 136, // 195, 120, 103, 71, 113 // ] // .into() // ); // assert_eq!( // rsa.dq1(), // vec![ // 29, 192, 92, 47, 143, 246, 41, 67, 217, 182, 224, 88, 64, 254, 219, // 151, 171, 57, 60, 39, 226, 195, 226, 217, 10, 97, 179, 50, 237, // 234, 35, 67, 10, 63, 232, 75, 224, 156, 21, 78, 125, 221, 124, 94, // 219, 144, 144, 9, 21, 143, 138, 181, 167, 146, 39, 128, 251, 176, // 54, 131, 239, 253, 157, 129 // ] // .into() // ); // true // } else { // false // } // })) // } else { // unreachable!(); // } // } else { // unreachable!(); // } // // Ok(()) // } // }