From 92f15489a4bf6a922bb8963d938982bba80e9a14 Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 30 Sep 2023 02:19:37 -0500 Subject: [PATCH] keyfork-derive-openpgp: initial proof of concept --- Cargo.lock | 892 ++++++++++++++++++++++++- Cargo.toml | 1 + keyfork-derive-openpgp/Cargo.toml | 13 + keyfork-derive-openpgp/src/main.rs | 207 ++++++ keyfork-derive-util/src/index.rs | 2 +- keyfork-derive-util/src/path.rs | 44 +- keyfork-derive-util/src/private_key.rs | 4 - keyfork-derive-util/src/public_key.rs | 6 +- keyfork-derive-util/src/request.rs | 60 +- keyforkd-client/Cargo.toml | 7 +- 10 files changed, 1203 insertions(+), 33 deletions(-) create mode 100644 keyfork-derive-openpgp/Cargo.toml create mode 100644 keyfork-derive-openpgp/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 23a30e8..756d91d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,6 +74,27 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "backtrace" version = "0.3.69" @@ -95,6 +116,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" + [[package]] name = "base64ct" version = "1.6.0" @@ -110,6 +137,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.63.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", +] + [[package]] name = "bip39" version = "2.0.0" @@ -121,12 +168,39 @@ dependencies = [ "unicode-normalization", ] +[[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 = "bitcoin_hashes" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.10.4" @@ -136,12 +210,51 @@ dependencies = [ "generic-array", ] +[[package]] +name = "buffered-reader" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d3bea5bcc3ecc38fe5388e6bc35e6fe7bd665eb3ae9a44283e15b91ad3867d" +dependencies = [ + "bzip2", + "flate2", + "lazy_static", + "libc", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[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 = "cc" version = "1.0.83" @@ -151,12 +264,43 @@ dependencies = [ "libc", ] +[[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.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "js-sys", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.4.2" @@ -188,7 +332,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -230,6 +374,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +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-bigint" version = "0.5.2" @@ -261,7 +420,7 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest", + "digest 0.10.7", "fiat-crypto", "platforms", "rustc_version", @@ -277,7 +436,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -290,6 +449,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" @@ -301,6 +475,33 @@ dependencies = [ "subtle", ] +[[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-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dyn-clone" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" + [[package]] name = "ecdsa" version = "0.16.8" @@ -309,10 +510,19 @@ checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ "der", "elliptic-curve", - "signature", + "signature 2.1.0", "spki", ] +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + [[package]] name = "ed25519" version = "2.2.2" @@ -320,7 +530,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ "pkcs8", - "signature", + "signature 2.1.0", ] [[package]] @@ -330,12 +540,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek", - "ed25519", + "ed25519 2.2.2", "serde", "sha2", "zeroize", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "elliptic-curve" version = "0.13.5" @@ -344,7 +560,7 @@ checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", @@ -355,12 +571,54 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "ff" version = "0.13.0" @@ -377,6 +635,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +[[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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -418,6 +692,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -425,8 +712,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -435,6 +724,12 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "group" version = "0.13.0" @@ -446,6 +741,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "hashbrown" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" + [[package]] name = "heck" version = "0.4.1" @@ -476,7 +777,27 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown", ] [[package]] @@ -492,12 +813,41 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "k256" version = "0.13.1" @@ -539,11 +889,22 @@ dependencies = [ "tokio", ] +[[package]] +name = "keyfork-derive-openpgp" +version = "0.1.0" +dependencies = [ + "ed25519-dalek", + "keyfork-derive-util", + "keyforkd-client", + "sequoia-openpgp", + "thiserror", +] + [[package]] name = "keyfork-derive-util" version = "0.1.0" dependencies = [ - "digest", + "digest 0.10.7", "ed25519-dalek", "hex-literal", "hmac", @@ -632,24 +993,84 @@ dependencies = [ "tokio", ] +[[package]] +name = "lalrpop" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.6.29", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[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.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" @@ -671,6 +1092,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memsec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa0916b001582d253822171bd23f4a0229d32b9507fae236f5da8cad515ba7c" + +[[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.1" @@ -687,10 +1120,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] +[[package]] +name = "nettle" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fdccf3eae7b161910d2daa2f0155ca35041322e8fe5c5f1f2c9d0b12356336" +dependencies = [ + "getrandom 0.2.10", + "libc", + "nettle-sys", + "thiserror", + "typenum", +] + +[[package]] +name = "nettle-sys" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e81c347b9002da0b6b0c4060993c280e99eb14b42ecf65a2fefcd6eb3d8a73" +dependencies = [ + "bindgen", + "cc", + "libc", + "pkg-config", + "tempfile", + "vcpkg", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[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 = "nu-ansi-term" version = "0.46.0" @@ -701,6 +1177,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -732,6 +1217,54 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "smallvec", + "windows-targets 0.48.5", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +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" version = "1.1.3" @@ -749,7 +1282,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -774,12 +1307,30 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + [[package]] name = "platforms" version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[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.66" @@ -811,6 +1362,29 @@ dependencies = [ "winapi", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -826,13 +1400,31 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -844,6 +1436,35 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.10", + "redox_syscall 0.2.16", + "thiserror", +] + [[package]] name = "regex" version = "1.9.3" @@ -903,7 +1524,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -912,6 +1533,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[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" @@ -921,12 +1548,37 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "sec1" version = "0.7.3" @@ -947,6 +1599,37 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +[[package]] +name = "sequoia-openpgp" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a16854c0f6297de6db4df195e28324dfbc2429802f0e48cd04007db8e3049709" +dependencies = [ + "anyhow", + "base64", + "buffered-reader", + "bzip2", + "chrono", + "dyn-clone", + "ed25519 1.5.3", + "flate2", + "getrandom 0.2.10", + "idna", + "lalrpop", + "lalrpop-util", + "lazy_static", + "libc", + "memsec", + "nettle", + "once_cell", + "rand 0.7.3", + "regex", + "regex-syntax 0.6.29", + "sha1collisiondetection", + "thiserror", + "xxhash-rust", +] + [[package]] name = "serde" version = "1.0.188" @@ -964,7 +1647,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -978,6 +1661,16 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1collisiondetection" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b20793cf8330b2c7da4c438116660fed24e380bcb8a1bcfff2581b5593a0b38e" +dependencies = [ + "digest 0.9.0", + "generic-array", +] + [[package]] name = "sha2" version = "0.10.7" @@ -986,7 +1679,7 @@ checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -998,6 +1691,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1007,6 +1706,12 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[package]] name = "signature" version = "2.1.0" @@ -1022,6 +1727,12 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "smallvec" version = "1.11.0" @@ -1052,6 +1763,19 @@ dependencies = [ "der", ] +[[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 = "strsim" version = "0.10.0" @@ -1064,6 +1788,17 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.29" @@ -1081,10 +1816,34 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" dependencies = [ - "rand", + "rand 0.4.6", "remove_dir_all", ] +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.48.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.49" @@ -1102,7 +1861,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -1115,6 +1874,15 @@ dependencies = [ "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 = "tinyvec" version = "1.6.0" @@ -1157,7 +1925,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -1209,7 +1977,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] @@ -1267,6 +2035,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.11" @@ -1282,6 +2056,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "utf8parse" version = "0.2.1" @@ -1294,18 +2074,84 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[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.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[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.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.29", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + [[package]] name = "winapi" version = "0.3.9" @@ -1460,6 +2306,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "xxhash-rust" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9828b178da53440fa9c766a3d2f73f7cf5d0ac1fe3980c1e5018d899fd19e07b" + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 274e5ea..1afe7a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "keyfork", "keyfork-derive-util", "keyfork-derive-key", + "keyfork-derive-openpgp", "keyfork-entropy", "keyfork-frame", "keyfork-mnemonic-from-seed", diff --git a/keyfork-derive-openpgp/Cargo.toml b/keyfork-derive-openpgp/Cargo.toml new file mode 100644 index 0000000..ac73cc4 --- /dev/null +++ b/keyfork-derive-openpgp/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "keyfork-derive-openpgp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ed25519-dalek = "2.0.0" +keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util", default-features = false, features = ["ed25519"] } +keyforkd-client = { version = "0.1.0", path = "../keyforkd-client", default-features = false, features = ["ed25519"] } +sequoia-openpgp = { version = "1.16.1", features = ["ed25519"] } +thiserror = "1.0.49" diff --git a/keyfork-derive-openpgp/src/main.rs b/keyfork-derive-openpgp/src/main.rs new file mode 100644 index 0000000..c7d8a2c --- /dev/null +++ b/keyfork-derive-openpgp/src/main.rs @@ -0,0 +1,207 @@ +use std::{ + env, + str::FromStr, + time::{Duration, SystemTime}, +}; + +use ed25519_dalek::SigningKey; +use keyfork_derive_util::{ + request::{DerivationAlgorithm, DerivationRequest}, + DerivationIndex, DerivationPath, ExtendedPrivateKey, PrivateKey, +}; +use keyforkd_client::Client; +use sequoia_openpgp::{ + packet::{ + key::{Key4, PrimaryRole, SubordinateRole}, + signature::SignatureBuilder, + Key, UserID, + }, + types::{KeyFlags, SignatureType}, + Cert, Packet, +}; + +#[derive(Debug, thiserror::Error)] +enum Error { + #[error("Bad character: {0}")] + BadChar(char), +} + +#[derive(Debug)] +struct KeyType { + _inner: KeyFlags, +} + +impl Default for KeyType { + fn default() -> Self { + Self { + _inner: KeyFlags::empty(), + } + } +} + +impl KeyType { + fn certify(mut self) -> Self { + self._inner = self._inner.set_certification(); + self + } + + fn sign(mut self) -> Self { + self._inner = self._inner.set_signing(); + self + } + + fn encrypt(mut self) -> Self { + self._inner = self._inner.set_transport_encryption(); + self._inner = self._inner.set_storage_encryption(); + self + } + + fn authenticate(mut self) -> Self { + self._inner = self._inner.set_authentication(); + self + } + + fn inner(&self) -> &KeyFlags { + &self._inner + } +} + +impl FromStr for KeyType { + type Err = Error; + + fn from_str(s: &str) -> Result { + s.chars().try_fold(Self::default(), |s, ch| match ch { + 'C' | 'c' => Ok(s.certify()), + 'S' | 's' => Ok(s.sign()), + 'E' | 'e' => Ok(s.encrypt()), + 'A' | 'a' => Ok(s.authenticate()), + ch => Err(Error::BadChar(ch)), + }) + } +} + +fn validate( + path: &str, + subkey_format: &str, + default_userid: &str, +) -> Result<(DerivationPath, Vec, UserID), Box> { + let mut pgp_u32 = [0u8; 4]; + pgp_u32[1..].copy_from_slice(&"pgp".bytes().collect::>()); + let index = DerivationIndex::new(u32::from_be_bytes(pgp_u32), true)?; + + let path = DerivationPath::from_str(path)?; + assert_eq!(2, path.len(), "Expected path of m/{index}/account_id'"); + + let given_index = path.iter().next().expect("checked .len() above"); + assert_eq!( + &index, given_index, + "Expected derivation path starting with m/{index}, got: {given_index}", + ); + + let subkey_format = subkey_format + .split(',') + .map(KeyType::from_str) + .collect::, Error>>()?; + assert!( + subkey_format[0].inner().for_certification(), + "First key must be able to certify" + ); + + Ok((path, subkey_format, UserID::from(default_userid))) +} + +fn main() -> Result<(), Box> { + let mut args = env::args(); + let program_name = args.next().expect("program name"); + let args = args.collect::>(); + let (path, subkey_format, default_userid) = match args.as_slice() { + [path, subkey_format, default_userid] => validate(path, subkey_format, default_userid)?, + _ => panic!("Usage: {program_name} path subkey_format default_userid"), + }; + + let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path); + let derived_data = Client::discover_socket()?.request(&request)?; + let xprv = ExtendedPrivateKey::::try_from(&derived_data)?; + + let derived_key = xprv.derive_child(&DerivationIndex::new(0, true)?)?; + let epoch = SystemTime::UNIX_EPOCH + Duration::from_secs(1); + let one_day = SystemTime::now() + Duration::from_secs(60 * 60 * 24); + let primary_key = Key::from( + Key4::<_, PrimaryRole>::import_secret_ed25519( + &PrivateKey::to_bytes(derived_key.private_key()), + epoch, + ) + .unwrap(), + ); + + let cert = + Cert::from_packets(vec![Packet::SecretKey(primary_key.clone())].into_iter()).unwrap(); + let builder = SignatureBuilder::new(SignatureType::PositiveCertification) + .set_signature_creation_time(epoch)? + .set_key_flags(subkey_format[0].inner().clone())?; + let binding = default_userid.bind(&mut primary_key.clone().into_keypair()?, &cert, builder)?; + let cert = cert.insert_packets(vec![Packet::from(default_userid), binding.into()])?; + + let policy = sequoia_openpgp::policy::StandardPolicy::new(); + let mut keypair = cert + .primary_key() + .key() + .clone() + .parts_into_secret()? + .into_keypair()?; + let signatures = cert.set_expiration_time(&policy, None, &mut keypair, Some(one_day))?; + let mut cert = cert.insert_packets(signatures)?; + + for (index, subkey_flags) in subkey_format.iter().enumerate().skip(1) { + let index = u32::try_from(index)?; + let derived_key = xprv.derive_child(&DerivationIndex::new(index, true)?)?; + let subkey = Key::from( + Key4::<_, SubordinateRole>::import_secret_ed25519( + &PrivateKey::to_bytes(derived_key.private_key()), + epoch, + ) + .unwrap(), + ); + let builder = if subkey_flags.inner().for_signing() { + SignatureBuilder::new(SignatureType::SubkeyBinding) + .set_key_flags(subkey_flags.inner().clone())? + .set_signature_creation_time(epoch)? + .set_key_validity_period(one_day.duration_since(epoch)?)? + .set_embedded_signature( + SignatureBuilder::new(SignatureType::PrimaryKeyBinding) + .set_signature_creation_time(epoch)? + .sign_primary_key_binding( + &mut subkey.clone().into_keypair()?, + &primary_key, + &subkey, + )?, + )? + } else { + SignatureBuilder::new(SignatureType::SubkeyBinding) + .set_key_flags(subkey_flags.inner().clone())? + .set_signature_creation_time(epoch)? + .set_key_validity_period(one_day.duration_since(epoch)?)? + }; + let binding = + builder.sign_subkey_binding(&mut primary_key.clone().into_keypair()?, None, &subkey)?; + cert = cert.insert_packets(vec![ + Packet::SecretSubkey(subkey.clone()), + Packet::Signature(binding), + ])?; + } + + use sequoia_openpgp::{ + armor::{Kind, Writer}, + serialize::Marshal, + }; + + let mut w = Writer::new(std::io::stdout(), Kind::Message)?; + + for packet in cert.into_packets() { + packet.serialize(&mut w)?; + } + + w.finalize()?; + + Ok(()) +} diff --git a/keyfork-derive-util/src/index.rs b/keyfork-derive-util/src/index.rs index 29fbee0..71ba6f0 100644 --- a/keyfork-derive-util/src/index.rs +++ b/keyfork-derive-util/src/index.rs @@ -16,7 +16,7 @@ pub enum Error { type Result = std::result::Result; /// Index for a given extended private key. -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct DerivationIndex(pub(crate) u32); impl DerivationIndex { diff --git a/keyfork-derive-util/src/path.rs b/keyfork-derive-util/src/path.rs index 431513c..0fa69a5 100644 --- a/keyfork-derive-util/src/path.rs +++ b/keyfork-derive-util/src/path.rs @@ -24,7 +24,7 @@ type Result = std::result::Result; const PREFIX: &str = "m"; /// A fully qualified path to derive a key. -#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct DerivationPath { pub(crate) path: Vec, } @@ -71,6 +71,26 @@ impl std::fmt::Display for DerivationPath { } } +impl std::ops::Add for DerivationPath { + type Output = DerivationPath; + + fn add(self, rhs: DerivationIndex) -> Self::Output { + let mut output = self.clone(); + output.path.push(rhs); + output + } +} + +impl std::ops::Add<&[DerivationIndex]> for DerivationPath { + type Output = DerivationPath; + + fn add(self, rhs: &[DerivationIndex]) -> Self::Output { + let mut output = self.clone(); + output.path.extend(rhs.iter().cloned()); + output + } +} + #[cfg(test)] mod tests { use super::*; @@ -90,4 +110,26 @@ mod tests { } Ok(()) } + + #[test] + fn add() -> Result<(), Box> { + let path = DerivationPath::from_str("m")?; + let path = path + DerivationIndex::new(72, true)?; + let path = path + DerivationIndex::new(47, false)?; + let path = path + DerivationIndex::new((i32::MAX) as u32, false)?; + assert_eq!(path, DerivationPath::from_str("m/72'/47/2147483647")?); + + Ok(()) + } + + + #[test] + fn add_vec() -> Result<(), Box> { + let path = DerivationPath::from_str("m")?; + let other_path = [DerivationIndex::new(72, true)?, DerivationIndex::new(47, false)?, DerivationIndex::new((i32::MAX) as u32, false)?]; + let path = path + &other_path[..]; + assert_eq!(path, DerivationPath::from_str("m/72'/47/2147483647")?); + + Ok(()) + } } diff --git a/keyfork-derive-util/src/private_key.rs b/keyfork-derive-util/src/private_key.rs index d985e07..d0dc3f9 100644 --- a/keyfork-derive-util/src/private_key.rs +++ b/keyfork-derive-util/src/private_key.rs @@ -54,10 +54,6 @@ pub enum PrivateKeyError { /// For the given algorithm, the private key must be nonzero. #[error("The provided private key must be nonzero, but is not")] NonZero, - - /// Unable to convert a point to a key. - #[error("Unable to convert point to key")] - PointToKey(#[from] k256::elliptic_curve::Error), } #[cfg(feature = "secp256k1")] diff --git a/keyfork-derive-util/src/public_key.rs b/keyfork-derive-util/src/public_key.rs index 0c16b5a..9e3e4a9 100644 --- a/keyfork-derive-util/src/public_key.rs +++ b/keyfork-derive-util/src/public_key.rs @@ -47,10 +47,6 @@ pub enum PublicKeyError { #[error("The provided public key must be nonzero, but is not")] NonZero, - /// Unable to convert a point to a key. - #[error("Unable to convert point to key")] - PointToKey(#[from] k256::elliptic_curve::Error), - /// Public key derivation is unsupported for this algorithm. #[error("Public key derivation is unsupported for this algorithm")] DerivationUnsupported, @@ -87,7 +83,7 @@ impl PublicKey for k256::PublicKey { .expect("Should have been able to get a NonZeroScalar"); let point = self.to_projective() + (AffinePoint::generator() * *scalar); - Self::from_affine(point.into()).map_err(From::from) + Ok(Self::from_affine(point.into()).expect("Could not from_affine after scalar arithmetic")) } } diff --git a/keyfork-derive-util/src/request.rs b/keyfork-derive-util/src/request.rs index a752603..255069e 100644 --- a/keyfork-derive-util/src/request.rs +++ b/keyfork-derive-util/src/request.rs @@ -68,7 +68,10 @@ pub struct DerivationRequest { impl DerivationRequest { pub fn new(algorithm: DerivationAlgorithm, path: &DerivationPath) -> Self { - Self { algorithm, path: path.clone() } + Self { + algorithm, + path: path.clone(), + } } pub fn path(&self) -> &DerivationPath { @@ -105,3 +108,58 @@ impl DerivationResponse { } } } + +#[derive(Debug, thiserror::Error)] +pub enum TryFromDerivationResponseError { + #[error("incorrect algorithm provided")] + Algorithm, + + #[error("{0}")] + ExtendedPrivateKey(#[from] XPrvError), +} + +#[cfg(feature = "secp256k1")] +impl TryFrom<&DerivationResponse> for ExtendedPrivateKey { + type Error = TryFromDerivationResponseError; + + fn try_from(value: &DerivationResponse) -> std::result::Result { + match value.algorithm { + DerivationAlgorithm::Secp256k1 => { + Self::new_from_parts(&value.data, value.depth, value.chain_code).map_err(From::from) + } + _ => Err(Self::Error::Algorithm), + } + } +} + +#[cfg(feature = "secp256k1")] +impl TryFrom for ExtendedPrivateKey { + type Error = TryFromDerivationResponseError; + + fn try_from(value: DerivationResponse) -> std::result::Result { + ExtendedPrivateKey::::try_from(&value) + } +} + +#[cfg(feature = "ed25519")] +impl TryFrom<&DerivationResponse> for ExtendedPrivateKey { + type Error = TryFromDerivationResponseError; + + fn try_from(value: &DerivationResponse) -> std::result::Result { + match value.algorithm { + DerivationAlgorithm::Ed25519 => { + Self::new_from_parts(&value.data, value.depth, value.chain_code).map_err(From::from) + } + _ => Err(Self::Error::Algorithm), + } + } +} + +#[cfg(feature = "ed25519")] +impl TryFrom for ExtendedPrivateKey { + type Error = TryFromDerivationResponseError; + + fn try_from(value: DerivationResponse) -> std::result::Result { + ExtendedPrivateKey::::try_from(&value) + } +} diff --git a/keyforkd-client/Cargo.toml b/keyforkd-client/Cargo.toml index 260fe0e..35da19f 100644 --- a/keyforkd-client/Cargo.toml +++ b/keyforkd-client/Cargo.toml @@ -5,9 +5,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["ed25519", "secp256k1"] +ed25519 = ["keyfork-derive-util/ed25519"] +secp256k1 = ["keyfork-derive-util/secp256k1"] + [dependencies] bincode = "1.3.3" -keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util" } +keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util", default-features = false } keyfork-frame = { version = "0.1.0", path = "../keyfork-frame" } thiserror = "1.0.49"