mirror of
https://github.com/fluencelabs/trust-graph
synced 2024-12-04 23:30:19 +00:00
Identity rework (#6)
This commit is contained in:
parent
443e9af784
commit
1d451379b5
189
Cargo.lock
generated
189
Cargo.lock
generated
@ -18,10 +18,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.38"
|
||||
name = "aho-corasick"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
|
||||
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
@ -130,9 +139,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.2"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
@ -189,9 +198,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06d4a9551359071d1890820e3571252b91229e0712e7c36b08940e603c5a8fc"
|
||||
checksum = "e9d6ddad5866bb2170686ed03f6839d31a76e5407d80b1c334a2c24618543ffa"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@ -199,9 +208,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b443e5fb0ddd56e0c9bfa47dc060c5306ee500cb731f2b91432dd65589a77684"
|
||||
checksum = "a9ced1fd13dc386d5a8315899de465708cf34ee2a6d9394654515214e67bb846"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
@ -213,9 +222,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0220073ce504f12a70efc4e7cdaea9e9b1b324872e7ad96a208056d7a638b81"
|
||||
checksum = "0a7a1445d54b2f9792e3b31a3e715feabbace393f38dc4ffd49d94ee9bc487d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
@ -288,6 +297,16 @@ version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
@ -325,8 +344,7 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
|
||||
[[package]]
|
||||
name = "fluence-fork-libp2p-core"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "735c96afd9c133fead34204dff9df0b9f0a86e1bb8e6c32faf8b9f60427ce0cd"
|
||||
source = "git+https://github.com/fluencelabs/rust-libp2p?branch=identity_rework#2d785558cfc9908cbfe54c0750e660c001cb2c3b"
|
||||
dependencies = [
|
||||
"asn1_der",
|
||||
"bs58 0.4.0",
|
||||
@ -342,7 +360,7 @@ dependencies = [
|
||||
"log",
|
||||
"multihash",
|
||||
"parking_lot",
|
||||
"pin-project 1.0.5",
|
||||
"pin-project 1.0.6",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"rand 0.7.3",
|
||||
@ -360,13 +378,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "fluence-fork-multistream-select"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08cb5798accfd52dc9a104d7928f379e93d8432ac03201f5a16ed6dc2af1520d"
|
||||
source = "git+https://github.com/fluencelabs/rust-libp2p?branch=identity_rework#2d785558cfc9908cbfe54c0750e660c001cb2c3b"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures",
|
||||
"log",
|
||||
"pin-project 1.0.5",
|
||||
"pin-project 1.0.6",
|
||||
"smallvec",
|
||||
"unsigned-varint 0.7.0",
|
||||
]
|
||||
@ -374,8 +391,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "fluence-fork-parity-multiaddr"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e42d11a2d1e7b50e91c947f1a480004ed5f207bb6c8f8a69dbc083588f8419c1"
|
||||
source = "git+https://github.com/fluencelabs/rust-libp2p?branch=identity_rework#2d785558cfc9908cbfe54c0750e660c001cb2c3b"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bs58 0.4.0",
|
||||
@ -393,16 +409,24 @@ dependencies = [
|
||||
name = "fluence-identity"
|
||||
version = "0.2.7"
|
||||
dependencies = [
|
||||
"asn1_der",
|
||||
"bs58 0.3.1",
|
||||
"ed25519",
|
||||
"ed25519-dalek",
|
||||
"fluence-fork-libp2p-core",
|
||||
"lazy_static",
|
||||
"libsecp256k1",
|
||||
"quickcheck",
|
||||
"rand 0.7.3",
|
||||
"ring",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"sha2 0.9.3",
|
||||
"signature",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -631,9 +655,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.1"
|
||||
version = "1.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
|
||||
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
@ -665,9 +689,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.48"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
|
||||
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@ -680,9 +704,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.87"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213"
|
||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||
|
||||
[[package]]
|
||||
name = "libsecp256k1"
|
||||
@ -702,9 +726,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
|
||||
checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
@ -769,9 +793,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333"
|
||||
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
@ -850,27 +874,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.27"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15"
|
||||
checksum = "918192b5c59119d51e0cd221f4d49dde9112824ba717369e903c97d076083d0f"
|
||||
dependencies = [
|
||||
"pin-project-internal 0.4.27",
|
||||
"pin-project-internal 0.4.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63"
|
||||
checksum = "bc174859768806e91ae575187ada95c91a29e96a98dc5d2cd9a1fed039501ba6"
|
||||
dependencies = [
|
||||
"pin-project-internal 1.0.5",
|
||||
"pin-project-internal 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.27"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895"
|
||||
checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -879,9 +903,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b"
|
||||
checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -953,9 +977,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@ -1011,6 +1035,18 @@ dependencies = [
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quickcheck"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
@ -1130,6 +1166,23 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
@ -1167,7 +1220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"pin-project 0.4.27",
|
||||
"pin-project 0.4.28",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
@ -1320,9 +1373,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.61"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5"
|
||||
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1377,9 +1430,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.1.1"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
|
||||
checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@ -1409,9 +1462,11 @@ dependencies = [
|
||||
"failure",
|
||||
"fluence-fork-libp2p-core",
|
||||
"fluence-identity",
|
||||
"libsecp256k1",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"ref-cast",
|
||||
"ring",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
@ -1421,15 +1476,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
|
||||
dependencies = [
|
||||
"matches",
|
||||
]
|
||||
@ -1487,9 +1542,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
@ -1511,9 +1566,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.71"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7"
|
||||
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@ -1521,9 +1576,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.71"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8"
|
||||
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
@ -1536,9 +1591,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.71"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b"
|
||||
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -1546,9 +1601,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.71"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e"
|
||||
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1559,15 +1614,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.71"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1"
|
||||
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.48"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b"
|
||||
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -1575,12 +1630,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.0.2"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef"
|
||||
checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe"
|
||||
dependencies = [
|
||||
"either",
|
||||
"libc",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -8,10 +8,10 @@ license = "Apache-2.0"
|
||||
repository = "https://github.com/fluencelabs/trust-graph"
|
||||
|
||||
[dependencies]
|
||||
libp2p-core = { package = "fluence-fork-libp2p-core", version = "0.27.1" }
|
||||
libp2p-core = { git = "https://github.com/fluencelabs/rust-libp2p", branch = "identity_rework", package = "fluence-fork-libp2p-core" }
|
||||
serde = { version = "=1.0.118", features = ["derive"] }
|
||||
|
||||
fluence-identity = { version = "0.2", path = "identity" }
|
||||
fluence-identity = {path = "./identity"}
|
||||
serde_json = "1.0.58"
|
||||
bs58 = "0.3.1"
|
||||
failure = "0.1.6"
|
||||
@ -23,3 +23,10 @@ rand = "0.7.0"
|
||||
signature = "1.3.0"
|
||||
serde_with = "1.6.0"
|
||||
thiserror = "1.0.23"
|
||||
libsecp256k1 = "0.3.5"
|
||||
ring = "0.16.20"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"identity"
|
||||
]
|
||||
|
@ -8,13 +8,23 @@ license = "Apache-2.0"
|
||||
repository = "https://github.com/fluencelabs/trust-graph"
|
||||
|
||||
[dependencies]
|
||||
libp2p-core = { package = "fluence-fork-libp2p-core", version = "0.27.1" }
|
||||
serde = { version = "=1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.58"
|
||||
bs58 = "0.3.1"
|
||||
ed25519-dalek = { version = "1.0.1", features = ["serde"] }
|
||||
ed25519-dalek = { version = "1.0.1", features = ["serde", "std"] }
|
||||
rand = "0.7.0"
|
||||
signature = "1.3.0"
|
||||
ed25519 = "1.0.3"
|
||||
serde_with = "1.6.0"
|
||||
thiserror = "1.0.23"
|
||||
lazy_static = "1.2"
|
||||
libsecp256k1 = "0.3.5"
|
||||
ring = { version = "0.16.9", features = ["alloc", "std"], default-features = false }
|
||||
asn1_der = "0.6.1"
|
||||
sha2 = "0.9.1"
|
||||
zeroize = "1"
|
||||
serde_bytes = "0.11"
|
||||
libp2p-core = { git = "https://github.com/fluencelabs/rust-libp2p", branch = "identity_rework", package = "fluence-fork-libp2p-core" }
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.9.0"
|
||||
|
239
identity/src/ed25519.rs
Normal file
239
identity/src/ed25519.rs
Normal file
@ -0,0 +1,239 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
//! Ed25519 keys.
|
||||
use crate::error::{DecodingError, SigningError};
|
||||
use ed25519_dalek::{self as ed25519, Signer as _, Verifier as _};
|
||||
use rand::RngCore;
|
||||
use std::convert::TryFrom;
|
||||
use zeroize::Zeroize;
|
||||
use core::fmt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An Ed25519 keypair.
|
||||
pub struct Keypair(ed25519::Keypair);
|
||||
|
||||
impl Keypair {
|
||||
/// Generate a new Ed25519 keypair.
|
||||
pub fn generate() -> Self {
|
||||
Keypair::from(SecretKey::generate())
|
||||
}
|
||||
|
||||
/// Encode the keypair into a byte array by concatenating the bytes
|
||||
/// of the secret scalar and the compressed public point,
|
||||
/// an informal standard for encoding Ed25519 keypairs.
|
||||
pub fn encode(&self) -> [u8; 64] {
|
||||
self.0.to_bytes()
|
||||
}
|
||||
|
||||
/// Decode a keypair from the format produced by `encode`,
|
||||
/// zeroing the input on success.
|
||||
pub fn decode(kp: &mut [u8]) -> Result<Self, DecodingError> {
|
||||
ed25519::Keypair::from_bytes(kp)
|
||||
.map(|k| {
|
||||
kp.zeroize();
|
||||
Keypair(k)
|
||||
})
|
||||
.map_err(DecodingError::Ed25519)
|
||||
}
|
||||
|
||||
/// Sign a message using the private key of this keypair.
|
||||
pub fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, SigningError> {
|
||||
Ok(self.0.try_sign(msg)?.to_bytes().to_vec())
|
||||
}
|
||||
|
||||
/// Get the public key of this keypair.
|
||||
pub fn public(&self) -> PublicKey {
|
||||
PublicKey(self.0.public)
|
||||
}
|
||||
|
||||
/// Get the secret key of this keypair.
|
||||
pub fn secret(&self) -> SecretKey {
|
||||
SecretKey::from_bytes(&mut self.0.secret.to_bytes())
|
||||
.expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Keypair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Keypair").field("public", &self.0.public).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Keypair {
|
||||
fn clone(&self) -> Self {
|
||||
let mut sk_bytes = self.0.secret.to_bytes();
|
||||
let secret = SecretKey::from_bytes(&mut sk_bytes)
|
||||
.expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k").0;
|
||||
let public = ed25519::PublicKey::from_bytes(&self.0.public.to_bytes())
|
||||
.expect("ed25519::PublicKey::from_bytes(to_bytes(k)) != k");
|
||||
Keypair(ed25519::Keypair { secret, public })
|
||||
}
|
||||
}
|
||||
|
||||
/// Build keypair from existing ed25519 keypair
|
||||
impl From<ed25519::Keypair> for Keypair {
|
||||
fn from(kp: ed25519::Keypair) -> Self {
|
||||
Keypair(kp)
|
||||
}
|
||||
}
|
||||
|
||||
/// Demote an Ed25519 keypair to a secret key.
|
||||
impl From<Keypair> for SecretKey {
|
||||
fn from(kp: Keypair) -> Self {
|
||||
SecretKey(kp.0.secret)
|
||||
}
|
||||
}
|
||||
|
||||
/// Promote an Ed25519 secret key into a keypair.
|
||||
impl From<SecretKey> for Keypair {
|
||||
fn from(sk: SecretKey) -> Self {
|
||||
let secret: ed25519::ExpandedSecretKey = (&sk.0).into();
|
||||
let public = ed25519::PublicKey::from(&secret);
|
||||
Keypair(ed25519::Keypair { secret: sk.0, public })
|
||||
}
|
||||
}
|
||||
|
||||
/// An Ed25519 public key.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct PublicKey(ed25519::PublicKey);
|
||||
|
||||
impl PublicKey {
|
||||
/// Verify the Ed25519 signature on a message using the public key.
|
||||
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> Result<(), SigningError> {
|
||||
ed25519::Signature::try_from(sig).and_then(|s| self.0.verify(msg, &s)).map_err(SigningError::Ed25519)
|
||||
}
|
||||
|
||||
/// Encode the public key into a byte array in compressed form, i.e.
|
||||
/// where one coordinate is represented by a single bit.
|
||||
pub fn encode(&self) -> [u8; 32] {
|
||||
self.0.to_bytes()
|
||||
}
|
||||
|
||||
/// Decode a public key from a byte array as produced by `encode`.
|
||||
pub fn decode(bytes: &[u8]) -> Result<Self, DecodingError> {
|
||||
ed25519::PublicKey::from_bytes(bytes)
|
||||
.map_err(DecodingError::Ed25519)
|
||||
.map(PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
/// An Ed25519 secret key.
|
||||
pub struct SecretKey(ed25519::SecretKey);
|
||||
|
||||
/// View the bytes of the secret key.
|
||||
impl AsRef<[u8]> for SecretKey {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for SecretKey {
|
||||
fn clone(&self) -> Self {
|
||||
let mut sk_bytes = self.0.to_bytes();
|
||||
Self::from_bytes(&mut sk_bytes)
|
||||
.expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SecretKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SecretKey")
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretKey {
|
||||
/// Generate a new Ed25519 secret key.
|
||||
pub fn generate() -> Self {
|
||||
let mut bytes = [0u8; 32];
|
||||
rand::thread_rng().fill_bytes(&mut bytes);
|
||||
SecretKey(ed25519::SecretKey::from_bytes(&bytes)
|
||||
.expect("this returns `Err` only if the length is wrong; the length is correct; qed"))
|
||||
}
|
||||
|
||||
/// Create an Ed25519 secret key from a byte slice, zeroing the input on success.
|
||||
/// If the bytes do not constitute a valid Ed25519 secret key, an error is
|
||||
/// returned.
|
||||
pub fn from_bytes(mut sk_bytes: impl AsMut<[u8]>) -> Result<Self, DecodingError> {
|
||||
let sk_bytes = sk_bytes.as_mut();
|
||||
let secret = ed25519::SecretKey::from_bytes(&*sk_bytes)
|
||||
.map_err(DecodingError::Ed25519)?;
|
||||
sk_bytes.zeroize();
|
||||
Ok(SecretKey(secret))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct Signature(pub Vec<u8>);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use quickcheck::*;
|
||||
|
||||
fn eq_keypairs(kp1: &Keypair, kp2: &Keypair) -> bool {
|
||||
kp1.public() == kp2.public()
|
||||
&&
|
||||
kp1.0.secret.as_bytes() == kp2.0.secret.as_bytes()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ed25519_keypair_encode_decode() {
|
||||
fn prop() -> bool {
|
||||
let kp1 = Keypair::generate();
|
||||
let mut kp1_enc = kp1.encode();
|
||||
let kp2 = Keypair::decode(&mut kp1_enc).unwrap();
|
||||
eq_keypairs(&kp1, &kp2)
|
||||
&&
|
||||
kp1_enc.iter().all(|b| *b == 0)
|
||||
}
|
||||
QuickCheck::new().tests(10).quickcheck(prop as fn() -> _);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ed25519_keypair_from_secret() {
|
||||
fn prop() -> bool {
|
||||
let kp1 = Keypair::generate();
|
||||
let mut sk = kp1.0.secret.to_bytes();
|
||||
let kp2 = Keypair::from(SecretKey::from_bytes(&mut sk).unwrap());
|
||||
eq_keypairs(&kp1, &kp2)
|
||||
&&
|
||||
sk == [0u8; 32]
|
||||
}
|
||||
QuickCheck::new().tests(10).quickcheck(prop as fn() -> _);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ed25519_signature() {
|
||||
let kp = Keypair::generate();
|
||||
let pk = kp.public();
|
||||
|
||||
let msg = "hello world".as_bytes();
|
||||
let sig = kp.sign(msg).unwrap();
|
||||
assert!(pk.verify(msg, &sig).is_ok());
|
||||
|
||||
let mut invalid_sig = sig.clone();
|
||||
invalid_sig[3..6].copy_from_slice(&[10, 23, 42]);
|
||||
assert!(pk.verify(msg, &invalid_sig).is_err());
|
||||
|
||||
let invalid_msg = "h3ll0 w0rld".as_bytes();
|
||||
assert!(pk.verify(invalid_msg, &sig).is_err());
|
||||
}
|
||||
}
|
69
identity/src/error.rs
Normal file
69
identity/src/error.rs
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
//! Errors during identity key operations.
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
/// An error during decoding of key material.
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum Error {
|
||||
#[error("{0} Key format is not supported")]
|
||||
InvalidKeyFormat(String),
|
||||
}
|
||||
|
||||
/// An error during decoding of key material.
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum DecodingError {
|
||||
#[error("Failed to decode with ed25519: {0}")]
|
||||
Ed25519(
|
||||
#[from]
|
||||
#[source]
|
||||
ed25519_dalek::ed25519::Error
|
||||
),
|
||||
#[error("Failed to decode with RSA")]
|
||||
Rsa,
|
||||
#[error("Failed to decode with secp256k1")]
|
||||
Secp256k1,
|
||||
#[error("RSA keypair decoding is not supported yet")]
|
||||
KeypairDecodingIsNotSupported,
|
||||
#[error("Invalid type prefix")]
|
||||
InvalidTypeByte,
|
||||
#[error("Cannot decode public key from base58 :{0}")]
|
||||
Base58DecodeError(#[source] bs58::decode::Error),
|
||||
}
|
||||
|
||||
/// An error during signing of a message.
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum SigningError {
|
||||
#[error("Failed to sign with ed25519: {0}")]
|
||||
Ed25519(
|
||||
#[from]
|
||||
#[source]
|
||||
ed25519_dalek::ed25519::Error
|
||||
),
|
||||
#[error("Failed to sign with RSA")]
|
||||
Rsa,
|
||||
#[error("Failed to sign with secp256k1: {0}")]
|
||||
Secp256k1(
|
||||
#[from]
|
||||
#[source]
|
||||
secp256k1::Error
|
||||
),
|
||||
}
|
@ -1,168 +1,224 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::ed25519::Keypair as Libp2pKeyPair;
|
||||
//! A node's network identity keys.
|
||||
use crate::ed25519;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::rsa;
|
||||
use crate::secp256k1;
|
||||
use crate::public_key::PublicKey;
|
||||
use crate::secret_key::SecretKey;
|
||||
use crate::signature::Signature;
|
||||
use ed25519_dalek::SignatureError;
|
||||
use ed25519_dalek::Signer;
|
||||
use crate::error::{Error, DecodingError, SigningError};
|
||||
use std::str::FromStr;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use rand::rngs::OsRng;
|
||||
use std::fmt;
|
||||
/// Identity keypair of a node.
|
||||
///
|
||||
/// # Example: Generating RSA keys with OpenSSL
|
||||
///
|
||||
/// ```text
|
||||
/// openssl genrsa -out private.pem 2048
|
||||
/// openssl pkcs8 -in private.pem -inform PEM -topk8 -out private.pk8 -outform DER -nocrypt
|
||||
/// rm private.pem # optional
|
||||
/// ```
|
||||
///
|
||||
/// Loading the keys:
|
||||
///
|
||||
/// ```text
|
||||
/// let mut bytes = std::fs::read("private.pk8").unwrap();
|
||||
/// let keypair = Keypair::rsa_from_pkcs8(&mut bytes);
|
||||
/// ```
|
||||
///
|
||||
|
||||
/// An Ed25519 keypair.
|
||||
#[derive(Debug)]
|
||||
pub struct KeyPair {
|
||||
key_pair: ed25519_dalek::Keypair,
|
||||
|
||||
pub enum KeyFormat {
|
||||
Ed25519,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa,
|
||||
Secp256k1,
|
||||
}
|
||||
|
||||
impl FromStr for KeyFormat {
|
||||
type Err = Error;
|
||||
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ed25519" => Ok(KeyFormat::Ed25519),
|
||||
"secp256k1" => Ok(KeyFormat::Secp256k1),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
"rsa" => Ok(KeyFormat::Rsa),
|
||||
_ => Err(Error::InvalidKeyFormat(s.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for KeyFormat {
|
||||
type Error = DecodingError;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(KeyFormat::Ed25519),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
1 => Ok(KeyFormat::Rsa),
|
||||
2 => Ok(KeyFormat::Secp256k1),
|
||||
_ => Err(DecodingError::InvalidTypeByte)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyFormat> for u8 {
|
||||
fn from(kf: KeyFormat) -> Self {
|
||||
match kf {
|
||||
KeyFormat::Ed25519 => 0,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
KeyFormat::Rsa => 1,
|
||||
KeyFormat::Secp256k1 => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum KeyPair {
|
||||
/// An Ed25519 keypair.
|
||||
Ed25519(ed25519::Keypair),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
/// An RSA keypair.
|
||||
Rsa(rsa::Keypair),
|
||||
/// A Secp256k1 keypair.
|
||||
Secp256k1(secp256k1::Keypair),
|
||||
}
|
||||
|
||||
impl KeyPair {
|
||||
pub fn generate(format: KeyFormat) -> KeyPair {
|
||||
match format {
|
||||
KeyFormat::Ed25519 => KeyPair::generate_ed25519(),
|
||||
KeyFormat::Secp256k1 => KeyPair::generate_secp256k1(),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
KeyFormat::Rsa => todo!("rsa generation is not supported yet!"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a new Ed25519 keypair.
|
||||
#[allow(dead_code)]
|
||||
pub fn generate() -> Self {
|
||||
let mut csprng = OsRng {};
|
||||
let kp = ed25519_dalek::Keypair::generate(&mut csprng);
|
||||
kp.into()
|
||||
pub fn generate_ed25519() -> KeyPair {
|
||||
KeyPair::Ed25519(ed25519::Keypair::generate())
|
||||
}
|
||||
|
||||
pub fn public(&self) -> PublicKey {
|
||||
PublicKey(self.key_pair.public)
|
||||
/// Generate a new Secp256k1 keypair.
|
||||
pub fn generate_secp256k1() -> KeyPair {
|
||||
KeyPair::Secp256k1(secp256k1::Keypair::generate())
|
||||
}
|
||||
|
||||
pub fn secret(&self) -> SecretKey {
|
||||
let b = self.key_pair.secret.to_bytes();
|
||||
SecretKey::from_bytes(&b).expect("SecretKey::from_bytes(to_bytes(k)) != k")
|
||||
/// Decode an keypair from a DER-encoded secret key in PKCS#8 PrivateKeyInfo
|
||||
/// format (i.e. unencrypted) as defined in [RFC5208].
|
||||
///
|
||||
/// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn rsa_from_pkcs8(pkcs8_der: &mut [u8]) -> Result<KeyPair, DecodingError> {
|
||||
rsa::Keypair::from_pkcs8(pkcs8_der).map(KeyPair::Rsa)
|
||||
}
|
||||
|
||||
pub fn from_bytes(sk_bytes: &[u8]) -> Result<Self, SignatureError> {
|
||||
let kp = ed25519_dalek::Keypair::from_bytes(sk_bytes)?;
|
||||
Ok(KeyPair { key_pair: kp })
|
||||
/// Decode a keypair from a DER-encoded Secp256k1 secret key in an ECPrivateKey
|
||||
/// structure as defined in [RFC5915].
|
||||
///
|
||||
/// [RFC5915]: https://tools.ietf.org/html/rfc5915
|
||||
pub fn secp256k1_from_der(der: &mut [u8]) -> Result<KeyPair, DecodingError> {
|
||||
secp256k1::SecretKey::from_der(der)
|
||||
.map(|sk| KeyPair::Secp256k1(secp256k1::Keypair::from(sk)))
|
||||
}
|
||||
|
||||
/// Encode the keypair into a byte array by concatenating the bytes
|
||||
/// of the secret scalar and the compressed public point/
|
||||
#[allow(dead_code)]
|
||||
pub fn encode(&self) -> [u8; 64] {
|
||||
self.key_pair.to_bytes()
|
||||
}
|
||||
|
||||
/// Decode a keypair from the format produced by `encode`.
|
||||
#[allow(dead_code)]
|
||||
pub fn decode(kp: &[u8]) -> Result<KeyPair, SignatureError> {
|
||||
let kp = ed25519_dalek::Keypair::from_bytes(kp)?;
|
||||
Ok(Self { key_pair: kp })
|
||||
/// Sign a message using the private key of this keypair, producing
|
||||
/// a signature that can be verified using the corresponding public key.
|
||||
pub fn sign(&self, msg: &[u8]) -> Result<Signature, SigningError> {
|
||||
use KeyPair::*;
|
||||
match self {
|
||||
Ed25519(ref pair) => Ok(Signature::Ed25519(ed25519::Signature(pair.sign(msg)?))),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(ref pair) => Ok(Signature::Rsa(rsa::Signature(pair.sign(msg)?))),
|
||||
Secp256k1(ref pair) => Ok(Signature::Secp256k1(secp256k1::Signature(pair.secret().sign(msg)?)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the public key of this keypair.
|
||||
#[allow(dead_code)]
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
PublicKey(self.key_pair.public)
|
||||
}
|
||||
|
||||
/// Sign a message using the private key of this keypair.
|
||||
pub fn sign(&self, msg: &[u8]) -> Signature {
|
||||
Signature(self.key_pair.sign(msg))
|
||||
}
|
||||
|
||||
/// Verify the Ed25519 signature on a message using the public key.
|
||||
pub fn verify(pk: &PublicKey, msg: &[u8], signature: &Signature) -> Result<(), SignatureError> {
|
||||
// let signature = ed25519_dalek::Signature::from_bytes(signature)
|
||||
// .map_err(|err| format!("Cannot convert bytes to a signature: {:?}", err))?;
|
||||
pk.verify_strict(msg, signature)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Libp2pKeyPair> for KeyPair {
|
||||
fn from(kp: Libp2pKeyPair) -> Self {
|
||||
// TODO: this is a hack. Convert directly. Maybe use mem::transmute?
|
||||
let kp = ed25519_dalek::Keypair::from_bytes(&kp.encode()).unwrap();
|
||||
Self { key_pair: kp }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ed25519_dalek::Keypair> for KeyPair {
|
||||
fn from(kp: ed25519_dalek::Keypair) -> Self {
|
||||
Self { key_pair: kp }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyPair> for ed25519_dalek::Keypair {
|
||||
fn from(kp: KeyPair) -> Self {
|
||||
kp.key_pair
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyPair> for Libp2pKeyPair {
|
||||
fn from(kp: KeyPair) -> Self {
|
||||
Libp2pKeyPair::from(kp.key_pair)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement serde::Deserialize for KeyPair
|
||||
impl<'de> serde::Deserialize<'de> for KeyPair {
|
||||
fn deserialize<D>(deserializer: D) -> Result<KeyPair, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
use serde::de::{Error, Unexpected, Visitor};
|
||||
|
||||
struct KeyPairVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for KeyPairVisitor {
|
||||
type Value = KeyPair;
|
||||
|
||||
/// Error message stating what was expected
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("byte array or base58 string")
|
||||
}
|
||||
|
||||
/// Implement deserialization from base58 string
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
bs58::decode(s)
|
||||
.into_vec()
|
||||
.map_err(|_| Error::invalid_value(Unexpected::Str(s), &self))
|
||||
.and_then(|v| self.visit_bytes(v.as_slice()))
|
||||
}
|
||||
|
||||
/// Implement deserialization from bytes
|
||||
fn visit_bytes<E>(self, b: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
KeyPair::decode(b).map_err(|_| Error::invalid_value(Unexpected::Bytes(b), &self))
|
||||
}
|
||||
pub fn public(&self) -> PublicKey {
|
||||
use KeyPair::*;
|
||||
match self {
|
||||
Ed25519(pair) => PublicKey::Ed25519(pair.public()),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(pair) => PublicKey::Rsa(pair.public()),
|
||||
Secp256k1(pair) => PublicKey::Secp256k1(pair.public().clone()),
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(KeyPairVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for KeyPair {
|
||||
fn clone(&self) -> KeyPair {
|
||||
let sk_bytes = self.key_pair.secret.to_bytes();
|
||||
let secret = ed25519_dalek::SecretKey::from_bytes(&sk_bytes)
|
||||
.expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k");
|
||||
let public = ed25519_dalek::PublicKey::from_bytes(&self.key_pair.public.to_bytes())
|
||||
.expect("ed25519::PublicKey::from_bytes(to_bytes(k)) != k");
|
||||
KeyPair {
|
||||
key_pair: ed25519_dalek::Keypair { secret, public },
|
||||
/// Verify the signature on a message using the public key.
|
||||
pub fn verify(pk: &PublicKey, msg: &[u8], signature: &Signature) -> Result<(), SigningError> {
|
||||
pk.verify(msg, signature)
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
use KeyPair::*;
|
||||
match self {
|
||||
Ed25519(kp) => kp.encode().to_vec(),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(_) => todo!("rsa encoding is not supported yet!"),
|
||||
Secp256k1(kp) => kp.secret().to_bytes().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_vec(mut bytes: Vec<u8>, format: KeyFormat) -> Result<Self, DecodingError> {
|
||||
use KeyPair::*;
|
||||
|
||||
match format {
|
||||
KeyFormat::Ed25519 => Ok(Ed25519(ed25519::Keypair::decode(&mut bytes)?)),
|
||||
KeyFormat::Secp256k1 => Ok(Secp256k1(secp256k1::SecretKey::from_bytes(bytes)?.into())),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
KeyFormat::Rsa => Err(DecodingError::KeypairDecodingIsNotSupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<libp2p_core::identity::Keypair> for KeyPair {
|
||||
fn from(key: libp2p_core::identity::Keypair) -> Self {
|
||||
use libp2p_core::identity::Keypair::*;
|
||||
|
||||
match key {
|
||||
Ed25519(kp) => KeyPair::Ed25519(ed25519::Keypair::decode(&mut kp.encode()).unwrap()),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
// safety: these Keypair structures are identical
|
||||
Rsa(kp) => KeyPair::Rsa(unsafe { std::mem::transmute::<libp2p_core::identity::rsa::Keypair, rsa::Keypair>(kp) }),
|
||||
Secp256k1(kp) => KeyPair::Secp256k1(secp256k1::Keypair::from(secp256k1::SecretKey::from_bytes(kp.secret().to_bytes()).unwrap())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyPair> for libp2p_core::identity::Keypair {
|
||||
fn from(key: KeyPair) -> Self {
|
||||
use KeyPair::*;
|
||||
use libp2p_core::identity::Keypair;
|
||||
use libp2p_core::identity;
|
||||
|
||||
match key {
|
||||
Ed25519(kp) => Keypair::Ed25519(identity::ed25519::Keypair::decode(kp.encode().to_vec().as_mut_slice()).unwrap()),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(kp) => Keypair::Rsa(unsafe { std::mem::transmute::<rsa::Keypair, libp2p_core::identity::rsa::Keypair>(kp) }),
|
||||
Secp256k1(kp) => Keypair::Secp256k1(identity::secp256k1::Keypair::from(identity::secp256k1::SecretKey::from_bytes(kp.secret().to_bytes()).unwrap())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,14 +26,16 @@
|
||||
unreachable_patterns
|
||||
)]
|
||||
|
||||
mod secp256k1;
|
||||
mod ed25519;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod rsa;
|
||||
pub mod key_pair;
|
||||
pub mod error;
|
||||
pub mod public_key;
|
||||
pub mod secret_key;
|
||||
pub mod signature;
|
||||
|
||||
pub use crate::key_pair::KeyPair;
|
||||
pub use key_pair::KeyPair;
|
||||
pub use key_pair::KeyFormat;
|
||||
pub use crate::public_key::PublicKey;
|
||||
pub use crate::secret_key::SecretKey;
|
||||
pub use crate::signature::Signature;
|
||||
|
||||
pub(crate) use libp2p_core::identity::ed25519;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
* Copyright 2021 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -13,63 +13,125 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::public_key::PKError::{FromBase58Error, FromBytesError};
|
||||
use crate::ed25519;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::rsa;
|
||||
use crate::secp256k1;
|
||||
use crate::error::{DecodingError, SigningError};
|
||||
use crate::signature::Signature;
|
||||
|
||||
use core::fmt::Debug;
|
||||
use ed25519_dalek::SignatureError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error as ThisError;
|
||||
use libp2p_core::identity;
|
||||
use crate::key_pair::KeyFormat;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum PKError {
|
||||
#[error("Cannot decode public key from bytes: {0}")]
|
||||
FromBytesError(#[source] SignatureError),
|
||||
#[error("Cannot decode public key from base58 format: {0}")]
|
||||
FromBase58Error(#[source] bs58::decode::Error),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PublicKey(pub(crate) ed25519_dalek::PublicKey);
|
||||
|
||||
impl Debug for PublicKey {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
/// The public key of a node's identity keypair.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum PublicKey {
|
||||
/// A public Ed25519 key.
|
||||
Ed25519(ed25519::PublicKey),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
/// A public RSA key.
|
||||
Rsa(rsa::PublicKey),
|
||||
/// A public Secp256k1 key.
|
||||
Secp256k1(secp256k1::PublicKey),
|
||||
}
|
||||
|
||||
impl PublicKey {
|
||||
pub fn verify_strict(
|
||||
&self,
|
||||
message: &[u8],
|
||||
signature: &Signature,
|
||||
) -> Result<(), SignatureError> {
|
||||
self.0.verify_strict(message, &signature.0)
|
||||
/// Verify a signature for a message using this public key, i.e. check
|
||||
/// that the signature has been produced by the corresponding
|
||||
/// private key (authenticity), and that the message has not been
|
||||
/// tampered with (integrity).
|
||||
pub fn verify(&self, msg: &[u8], sig: &Signature) -> Result<(), SigningError> {
|
||||
use PublicKey::*;
|
||||
match self {
|
||||
Ed25519(pk) => pk.verify(msg, sig.to_vec()),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(pk) => pk.verify(msg, sig.to_vec()),
|
||||
Secp256k1(pk) => pk.verify(msg, sig.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_base58(str: &str) -> Result<PublicKey, PKError> {
|
||||
let bytes = bs58::decode(str).into_vec().map_err(FromBase58Error)?;
|
||||
Self::from_bytes(&bytes)
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
use PublicKey::*;
|
||||
let mut result: Vec<u8> = vec![self.get_prefix()];
|
||||
|
||||
match self {
|
||||
Ed25519(pk) => result.extend(pk.encode().to_vec()),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(pk) => result.extend(pk.to_pkcs1()),
|
||||
Secp256k1(pk) => result.extend(pk.encode().to_vec()),
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, PKError> {
|
||||
let pk = ed25519_dalek::PublicKey::from_bytes(bytes).map_err(FromBytesError)?;
|
||||
Ok(PublicKey(pk))
|
||||
pub fn decode(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
|
||||
match KeyFormat::try_from(bytes[0])? {
|
||||
KeyFormat::Ed25519 => Ok(PublicKey::Ed25519(ed25519::PublicKey::decode(&bytes[1..])?)),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
KeyFormat::Rsa => Ok(PublicKey::Rsa(rsa::PublicKey::from_pkcs1(bytes[1..].to_owned())?)),
|
||||
KeyFormat::Secp256k1 => Ok(PublicKey::Secp256k1(secp256k1::PublicKey::decode(&bytes[1..])?)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; ed25519_dalek::PUBLIC_KEY_LENGTH] {
|
||||
self.0.to_bytes()
|
||||
fn get_prefix(&self) -> u8 {
|
||||
use PublicKey::*;
|
||||
match self {
|
||||
Ed25519(_) => KeyFormat::Ed25519.into(),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(_) => KeyFormat::Rsa.into(),
|
||||
Secp256k1(_) => KeyFormat::Secp256k1.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_libp2p(pk: &identity::ed25519::PublicKey) -> Result<Self, PKError> {
|
||||
Self::from_bytes(&pk.encode())
|
||||
pub fn from_base58(str: &str) -> Result<PublicKey, DecodingError> {
|
||||
let bytes = bs58::decode(str).into_vec().map_err(DecodingError::Base58DecodeError)?;
|
||||
Self::decode(&bytes)
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
use PublicKey::*;
|
||||
|
||||
match self {
|
||||
Ed25519(pk) => pk.encode().to_vec(),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(pk) => pk.to_pkcs1().to_vec(),
|
||||
Secp256k1(pk) => pk.encode().to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PublicKey> for ed25519_dalek::PublicKey {
|
||||
fn from(key: PublicKey) -> Self {
|
||||
key.0
|
||||
impl From<libp2p_core::identity::PublicKey> for PublicKey {
|
||||
fn from(key: libp2p_core::identity::PublicKey) -> Self {
|
||||
use libp2p_core::identity::PublicKey::*;
|
||||
|
||||
match key {
|
||||
Ed25519(key) => PublicKey::Ed25519(ed25519::PublicKey::decode(&key.encode()[..]).unwrap()),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(key) => PublicKey::Rsa(rsa::PublicKey::from_pkcs1(key.encode_pkcs1()).unwrap()),
|
||||
Secp256k1(key) => PublicKey::Secp256k1(secp256k1::PublicKey::decode(&key.encode()[..]).unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::KeyPair;
|
||||
|
||||
#[test]
|
||||
fn public_key_encode_decode_ed25519() {
|
||||
let kp = KeyPair::generate_ed25519();
|
||||
let pk = kp.public();
|
||||
let encoded_pk = pk.encode();
|
||||
assert_eq!(pk, PublicKey::decode(&encoded_pk).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_key_encode_decode_secp256k1() {
|
||||
let kp = KeyPair::generate_secp256k1();
|
||||
let pk = kp.public();
|
||||
let encoded_pk = pk.encode();
|
||||
assert_eq!(pk, PublicKey::decode(&encoded_pk).unwrap());
|
||||
}
|
||||
}
|
||||
|
278
identity/src/rsa.rs
Normal file
278
identity/src/rsa.rs
Normal file
@ -0,0 +1,278 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
//! RSA keys.
|
||||
use crate::error::{DecodingError, SigningError};
|
||||
|
||||
use asn1_der::{Asn1Der, FromDerObject, IntoDerObject, DerObject, DerTag, DerValue, Asn1DerError};
|
||||
use lazy_static::lazy_static;
|
||||
use ring::rand::SystemRandom;
|
||||
use ring::signature::{self, RsaKeyPair, RSA_PKCS1_SHA256, RSA_PKCS1_2048_8192_SHA256};
|
||||
use ring::signature::KeyPair;
|
||||
use std::{fmt::{self, Write}, sync::Arc};
|
||||
use zeroize::Zeroize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An RSA keypair.
|
||||
#[derive(Clone)]
|
||||
pub struct Keypair(Arc<RsaKeyPair>);
|
||||
|
||||
impl Keypair {
|
||||
/// Decode an RSA keypair from a DER-encoded private key in PKCS#8 PrivateKeyInfo
|
||||
/// format (i.e. unencrypted) as defined in [RFC5208].
|
||||
///
|
||||
/// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
|
||||
pub fn from_pkcs8(der: &mut [u8]) -> Result<Self, DecodingError> {
|
||||
let kp = RsaKeyPair::from_pkcs8(&der)
|
||||
.map_err(|_| DecodingError::Rsa)?;
|
||||
der.zeroize();
|
||||
Ok(Keypair(Arc::new(kp)))
|
||||
}
|
||||
|
||||
/// Get the public key from the keypair.
|
||||
pub fn public(&self) -> PublicKey {
|
||||
PublicKey(self.0.public_key().as_ref().to_vec())
|
||||
}
|
||||
|
||||
/// Sign a message with this keypair.
|
||||
pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SigningError> {
|
||||
let mut signature = vec![0; self.0.public_modulus_len()];
|
||||
let rng = SystemRandom::new();
|
||||
match self.0.sign(&RSA_PKCS1_SHA256, &rng, &data, &mut signature) {
|
||||
Ok(()) => Ok(signature),
|
||||
Err(_) => Err(SigningError::Rsa)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An RSA public key.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PublicKey(Vec<u8>);
|
||||
|
||||
impl PublicKey {
|
||||
/// Verify an RSA signature on a message using the public key.
|
||||
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> Result<(), SigningError> {
|
||||
let key = signature::UnparsedPublicKey::new(&RSA_PKCS1_2048_8192_SHA256, &self.0);
|
||||
key.verify(msg, sig).map_err(|_| SigningError::Rsa)
|
||||
}
|
||||
|
||||
/// Encode the RSA public key in DER as a PKCS#1 RSAPublicKey structure,
|
||||
/// as defined in [RFC3447].
|
||||
///
|
||||
/// [RFC3447]: https://tools.ietf.org/html/rfc3447#appendix-A.1.1
|
||||
pub fn to_pkcs1(&self) -> &[u8] {
|
||||
// This is the encoding currently used in-memory, so it is trivial.
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn from_pkcs1(pk: Vec<u8>) -> Result<Self, DecodingError> {
|
||||
Ok(PublicKey(pk))
|
||||
}
|
||||
|
||||
/// Encode the RSA public key in DER as a X.509 SubjectPublicKeyInfo structure,
|
||||
/// as defined in [RFC5280].
|
||||
///
|
||||
/// [RFC5280]: https://tools.ietf.org/html/rfc5280#section-4.1
|
||||
pub fn encode_x509(&self) -> Vec<u8> {
|
||||
let spki = Asn1SubjectPublicKeyInfo {
|
||||
algorithmIdentifier: Asn1RsaEncryption {
|
||||
algorithm: Asn1OidRsaEncryption(),
|
||||
parameters: (),
|
||||
},
|
||||
subjectPublicKey: Asn1SubjectPublicKey(self.clone()),
|
||||
};
|
||||
let mut buf = vec![0u8; spki.serialized_len()];
|
||||
spki.serialize(buf.iter_mut()).map(|_| buf)
|
||||
.expect("RSA X.509 public key encoding failed.")
|
||||
}
|
||||
|
||||
/// Decode an RSA public key from a DER-encoded X.509 SubjectPublicKeyInfo
|
||||
/// structure. See also `encode_x509`.
|
||||
pub fn decode_x509(pk: &[u8]) -> Result<Self, DecodingError> {
|
||||
Asn1SubjectPublicKeyInfo::deserialize(pk.iter())
|
||||
.map_err(|_| DecodingError::Rsa)
|
||||
.map(|spki| spki.subjectPublicKey.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let bytes = &self.0;
|
||||
let mut hex = String::with_capacity(bytes.len() * 2);
|
||||
|
||||
for byte in bytes {
|
||||
write!(hex, "{:02x}", byte).expect("Can't fail on writing to string");
|
||||
}
|
||||
|
||||
f.debug_struct("PublicKey")
|
||||
.field("pkcs1", &hex)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// DER encoding / decoding of public keys
|
||||
//
|
||||
// Primer: http://luca.ntop.org/Teaching/Appunti/asn1.html
|
||||
// Playground: https://lapo.it/asn1js/
|
||||
|
||||
lazy_static! {
|
||||
/// The DER encoding of the object identifier (OID) 'rsaEncryption' for
|
||||
/// RSA public keys defined for X.509 in [RFC-3279] and used in
|
||||
/// SubjectPublicKeyInfo structures defined in [RFC-5280].
|
||||
///
|
||||
/// [RFC-3279]: https://tools.ietf.org/html/rfc3279#section-2.3.1
|
||||
/// [RFC-5280]: https://tools.ietf.org/html/rfc5280#section-4.1
|
||||
static ref OID_RSA_ENCRYPTION_DER: DerObject =
|
||||
DerObject {
|
||||
tag: DerTag::x06,
|
||||
value: DerValue {
|
||||
data: vec![ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 ]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// The ASN.1 OID for "rsaEncryption".
|
||||
#[derive(Clone)]
|
||||
struct Asn1OidRsaEncryption();
|
||||
|
||||
impl IntoDerObject for Asn1OidRsaEncryption {
|
||||
fn into_der_object(self) -> DerObject {
|
||||
OID_RSA_ENCRYPTION_DER.clone()
|
||||
}
|
||||
fn serialized_len(&self) -> usize {
|
||||
OID_RSA_ENCRYPTION_DER.serialized_len()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromDerObject for Asn1OidRsaEncryption {
|
||||
fn from_der_object(o: DerObject) -> Result<Self, Asn1DerError> {
|
||||
if o.tag != DerTag::x06 {
|
||||
return Err(Asn1DerError::InvalidTag);
|
||||
}
|
||||
if o.value != OID_RSA_ENCRYPTION_DER.value {
|
||||
return Err(Asn1DerError::InvalidEncoding);
|
||||
}
|
||||
Ok(Asn1OidRsaEncryption())
|
||||
}
|
||||
}
|
||||
|
||||
/// The ASN.1 AlgorithmIdentifier for "rsaEncryption".
|
||||
#[derive(Asn1Der)]
|
||||
struct Asn1RsaEncryption {
|
||||
algorithm: Asn1OidRsaEncryption,
|
||||
parameters: (),
|
||||
}
|
||||
|
||||
/// The ASN.1 SubjectPublicKey inside a SubjectPublicKeyInfo,
|
||||
/// i.e. encoded as a DER BIT STRING.
|
||||
struct Asn1SubjectPublicKey(PublicKey);
|
||||
|
||||
impl IntoDerObject for Asn1SubjectPublicKey {
|
||||
fn into_der_object(self) -> DerObject {
|
||||
let pk_der = (self.0).0;
|
||||
let mut bit_string = Vec::with_capacity(pk_der.len() + 1);
|
||||
// The number of bits in pk_der is trivially always a multiple of 8,
|
||||
// so there are always 0 "unused bits" signaled by the first byte.
|
||||
bit_string.push(0u8);
|
||||
bit_string.extend(pk_der);
|
||||
DerObject::new(DerTag::x03, bit_string.into())
|
||||
}
|
||||
fn serialized_len(&self) -> usize {
|
||||
DerObject::compute_serialized_len((self.0).0.len() + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromDerObject for Asn1SubjectPublicKey {
|
||||
fn from_der_object(o: DerObject) -> Result<Self, Asn1DerError> {
|
||||
if o.tag != DerTag::x03 {
|
||||
return Err(Asn1DerError::InvalidTag);
|
||||
}
|
||||
let pk_der: Vec<u8> = o.value.data.into_iter().skip(1).collect();
|
||||
// We don't parse pk_der further as an ASN.1 RsaPublicKey, since
|
||||
// we only need the DER encoding for `verify`.
|
||||
Ok(Asn1SubjectPublicKey(PublicKey(pk_der)))
|
||||
}
|
||||
}
|
||||
|
||||
/// ASN.1 SubjectPublicKeyInfo
|
||||
#[derive(Asn1Der)]
|
||||
#[allow(non_snake_case)]
|
||||
struct Asn1SubjectPublicKeyInfo {
|
||||
algorithmIdentifier: Asn1RsaEncryption,
|
||||
subjectPublicKey: Asn1SubjectPublicKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Signature(pub Vec<u8>);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use quickcheck::*;
|
||||
use rand::seq::SliceRandom;
|
||||
use std::fmt;
|
||||
|
||||
const KEY1: &'static [u8] = include_bytes!("test/rsa-2048.pk8");
|
||||
const KEY2: &'static [u8] = include_bytes!("test/rsa-3072.pk8");
|
||||
const KEY3: &'static [u8] = include_bytes!("test/rsa-4096.pk8");
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SomeKeypair(Keypair);
|
||||
|
||||
impl fmt::Debug for SomeKeypair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SomeKeypair")
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for SomeKeypair {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> SomeKeypair {
|
||||
let mut key = [KEY1, KEY2, KEY3].choose(g).unwrap().to_vec();
|
||||
SomeKeypair(Keypair::from_pkcs8(&mut key).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_from_pkcs8() {
|
||||
assert!(Keypair::from_pkcs8(&mut KEY1.to_vec()).is_ok());
|
||||
assert!(Keypair::from_pkcs8(&mut KEY2.to_vec()).is_ok());
|
||||
assert!(Keypair::from_pkcs8(&mut KEY3.to_vec()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_x509_encode_decode() {
|
||||
fn prop(SomeKeypair(kp): SomeKeypair) -> Result<bool, String> {
|
||||
let pk = kp.public();
|
||||
PublicKey::decode_x509(&pk.encode_x509())
|
||||
.map_err(|e| e.to_string())
|
||||
.map(|pk2| pk2 == pk)
|
||||
}
|
||||
QuickCheck::new().tests(10).quickcheck(prop as fn(_) -> _);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_sign_verify() {
|
||||
fn prop(SomeKeypair(kp): SomeKeypair, msg: Vec<u8>) -> Result<bool, SigningError> {
|
||||
kp.sign(&msg).map(|s| kp.public().verify(&msg, &s).is_ok())
|
||||
}
|
||||
QuickCheck::new().tests(10).quickcheck(prop as fn(_, _) -> _);
|
||||
}
|
||||
}
|
230
identity/src/secp256k1.rs
Normal file
230
identity/src/secp256k1.rs
Normal file
@ -0,0 +1,230 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
//! Secp256k1 keys.
|
||||
use crate::error::{DecodingError, SigningError};
|
||||
|
||||
use asn1_der::{FromDerObject, DerObject};
|
||||
use rand::RngCore;
|
||||
use sha2::{Digest as ShaDigestTrait, Sha256};
|
||||
use secp256k1::Message;
|
||||
use zeroize::Zeroize;
|
||||
use core::fmt;
|
||||
use serde::{Deserialize, Serialize, Serializer, Deserializer};
|
||||
use serde::de::Error as SerdeError;
|
||||
use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf};
|
||||
|
||||
/// A Secp256k1 keypair.
|
||||
#[derive(Clone)]
|
||||
pub struct Keypair {
|
||||
secret: SecretKey,
|
||||
public: PublicKey,
|
||||
}
|
||||
|
||||
impl Keypair {
|
||||
/// Generate a new sec256k1 `Keypair`.
|
||||
pub fn generate() -> Self {
|
||||
Keypair::from(SecretKey::generate())
|
||||
}
|
||||
|
||||
/// Get the public key of this keypair.
|
||||
pub fn public(&self) -> &PublicKey {
|
||||
&self.public
|
||||
}
|
||||
|
||||
/// Get the secret key of this keypair.
|
||||
pub fn secret(&self) -> &SecretKey {
|
||||
&self.secret
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Keypair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Keypair").field("public", &self.public).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Promote a Secp256k1 secret key into a keypair.
|
||||
impl From<SecretKey> for Keypair {
|
||||
fn from(secret: SecretKey) -> Self {
|
||||
let public = PublicKey(secp256k1::PublicKey::from_secret_key(&secret.0));
|
||||
Keypair { secret, public }
|
||||
}
|
||||
}
|
||||
|
||||
/// Demote a Secp256k1 keypair into a secret key.
|
||||
impl From<Keypair> for SecretKey {
|
||||
fn from(kp: Keypair) -> Self {
|
||||
kp.secret
|
||||
}
|
||||
}
|
||||
|
||||
/// A Secp256k1 secret key.
|
||||
#[derive(Clone)]
|
||||
pub struct SecretKey(secp256k1::SecretKey);
|
||||
|
||||
impl fmt::Debug for SecretKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SecretKey")
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretKey {
|
||||
/// Generate a new Secp256k1 secret key.
|
||||
pub fn generate() -> Self {
|
||||
let mut r = rand::thread_rng();
|
||||
let mut b = [0; secp256k1::util::SECRET_KEY_SIZE];
|
||||
// This is how it is done in `secp256k1::SecretKey::random` which
|
||||
// we do not use here because it uses `rand::Rng` from rand-0.4.
|
||||
loop {
|
||||
r.fill_bytes(&mut b);
|
||||
if let Ok(k) = secp256k1::SecretKey::parse(&b) {
|
||||
return SecretKey(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a secret key from a byte slice, zeroing the slice on success.
|
||||
/// If the bytes do not constitute a valid Secp256k1 secret key, an
|
||||
/// error is returned.
|
||||
pub fn from_bytes(mut sk: impl AsMut<[u8]>) -> Result<Self, DecodingError> {
|
||||
let sk_bytes = sk.as_mut();
|
||||
let secret = secp256k1::SecretKey::parse_slice(&*sk_bytes)
|
||||
.map_err(|_| DecodingError::Secp256k1)?;
|
||||
sk_bytes.zeroize();
|
||||
Ok(SecretKey(secret))
|
||||
}
|
||||
|
||||
/// Decode a DER-encoded Secp256k1 secret key in an ECPrivateKey
|
||||
/// structure as defined in [RFC5915].
|
||||
///
|
||||
/// [RFC5915]: https://tools.ietf.org/html/rfc5915
|
||||
pub fn from_der(mut der: impl AsMut<[u8]>) -> Result<SecretKey, DecodingError> {
|
||||
// TODO: Stricter parsing.
|
||||
let der_obj = der.as_mut();
|
||||
let obj: Vec<DerObject> = FromDerObject::deserialize((&*der_obj).iter())
|
||||
.map_err(|_| DecodingError::Secp256k1)?;
|
||||
der_obj.zeroize();
|
||||
let sk_obj = obj.into_iter().nth(1)
|
||||
.ok_or(DecodingError::Secp256k1)?;
|
||||
let mut sk_bytes: Vec<u8> = FromDerObject::from_der_object(sk_obj)
|
||||
.map_err(|_| DecodingError::Secp256k1)?;
|
||||
let sk = SecretKey::from_bytes(&mut sk_bytes)?;
|
||||
sk_bytes.zeroize();
|
||||
Ok(sk)
|
||||
}
|
||||
|
||||
/// Sign a message with this secret key, producing a DER-encoded
|
||||
/// ECDSA signature, as defined in [RFC3278].
|
||||
///
|
||||
/// [RFC3278]: https://tools.ietf.org/html/rfc3278#section-8.2
|
||||
pub fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, SigningError> {
|
||||
self.sign_hashed(Sha256::digest(msg).as_ref())
|
||||
}
|
||||
|
||||
/// Returns the raw bytes of the secret key.
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
self.0.serialize()
|
||||
}
|
||||
|
||||
/// Sign a raw message of length 256 bits with this secret key, produces a DER-encoded
|
||||
/// ECDSA signature.
|
||||
pub fn sign_hashed(&self, msg: &[u8]) -> Result<Vec<u8>, SigningError> {
|
||||
let m = Message::parse_slice(msg)
|
||||
.map_err(SigningError::Secp256k1)?;
|
||||
Ok(secp256k1::sign(&m, &self.0).0.serialize_der().as_ref().into())
|
||||
}
|
||||
}
|
||||
|
||||
/// A Secp256k1 public key.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct PublicKey(secp256k1::PublicKey);
|
||||
|
||||
impl PublicKey {
|
||||
/// Verify the Secp256k1 signature on a message using the public key.
|
||||
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> Result<(), SigningError> {
|
||||
self.verify_hashed(Sha256::digest(msg).as_ref(), sig)
|
||||
}
|
||||
|
||||
/// Verify the Secp256k1 DER-encoded signature on a raw 256-bit message using the public key.
|
||||
pub fn verify_hashed(&self, msg: &[u8], sig: &[u8]) -> Result<(), SigningError> {
|
||||
Message::parse_slice(msg)
|
||||
.and_then(|m| secp256k1::Signature::parse_der(sig).map(|s| secp256k1::verify(&m, &s, &self.0)))
|
||||
.map_err(SigningError::Secp256k1).map(|_| ())
|
||||
}
|
||||
|
||||
/// Encode the public key in compressed form, i.e. with one coordinate
|
||||
/// represented by a single bit.
|
||||
pub fn encode(&self) -> [u8; 33] {
|
||||
self.0.serialize_compressed()
|
||||
}
|
||||
|
||||
/// Encode the public key in uncompressed form.
|
||||
pub fn encode_uncompressed(&self) -> [u8; 65] {
|
||||
self.0.serialize()
|
||||
}
|
||||
|
||||
/// Decode a public key from a byte slice in the the format produced
|
||||
/// by `encode`.
|
||||
pub fn decode(bytes: &[u8]) -> Result<Self, DecodingError> {
|
||||
secp256k1::PublicKey::parse_slice(bytes, Some(secp256k1::PublicKeyFormat::Compressed))
|
||||
.map_err(|_| DecodingError::Secp256k1)
|
||||
.map(PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Serialize for PublicKey {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
SerdeBytes::new(self.encode().to_vec().as_slice()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Deserialize<'d> for PublicKey {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'d>,
|
||||
{
|
||||
let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
|
||||
PublicKey::decode(bytes.as_slice()).map_err(SerdeError::custom)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Signature(pub Vec<u8>);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn secp256k1_secret_from_bytes() {
|
||||
let sk1 = SecretKey::generate();
|
||||
let mut sk_bytes = [0; 32];
|
||||
sk_bytes.copy_from_slice(&sk1.0.serialize()[..]);
|
||||
let sk2 = SecretKey::from_bytes(&mut sk_bytes).unwrap();
|
||||
assert_eq!(sk1.0.serialize(), sk2.0.serialize());
|
||||
assert_eq!(sk_bytes, [0; 32]);
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use ed25519_dalek::SignatureError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SecretKey(ed25519_dalek::SecretKey);
|
||||
|
||||
impl SecretKey {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<SecretKey, SignatureError> {
|
||||
let pk = ed25519_dalek::SecretKey::from_bytes(bytes)?;
|
||||
|
||||
Ok(SecretKey(pk))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for SecretKey {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
}
|
@ -13,40 +13,88 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::ed25519;
|
||||
use crate::secp256k1;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::rsa;
|
||||
use crate::error::DecodingError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use signature::Error as SigError;
|
||||
use signature::Signature as SigSignature;
|
||||
use thiserror::Error as ThisError;
|
||||
use crate::key_pair::KeyFormat;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum SignatureError {
|
||||
#[error("{0}")]
|
||||
Error(
|
||||
#[from]
|
||||
#[source]
|
||||
SigError,
|
||||
),
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub enum Signature {
|
||||
Ed25519(ed25519::Signature),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(rsa::Signature),
|
||||
Secp256k1(secp256k1::Signature),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Signature(pub ed25519_dalek::Signature);
|
||||
|
||||
pub const SIGNATURE_LENGTH: usize = 64;
|
||||
|
||||
impl Signature {
|
||||
/// Create a new signature from a byte array
|
||||
pub fn new(bytes: [u8; SIGNATURE_LENGTH]) -> Self {
|
||||
Signature(ed25519_dalek::Signature::from(bytes))
|
||||
fn get_prefix(&self) -> u8 {
|
||||
use Signature::*;
|
||||
match self {
|
||||
Ed25519(_) => KeyFormat::Ed25519.into(),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(_) => KeyFormat::Rsa.into(),
|
||||
Secp256k1(_) => KeyFormat::Secp256k1.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the inner byte array
|
||||
pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
|
||||
self.0.to_bytes()
|
||||
/// encode keypair type in first byte and signature as byte array
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
use Signature::*;
|
||||
|
||||
let mut result: Vec<u8> = vec![self.get_prefix()];
|
||||
|
||||
match self {
|
||||
Ed25519(sig) => result.extend(sig.0.clone()),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(sig) => result.extend(sig.0.clone()),
|
||||
Secp256k1(sig) => result.extend(sig.0.clone()),
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, SignatureError> {
|
||||
let sig = ed25519_dalek::Signature::from_bytes(bytes)?;
|
||||
Ok(Signature(sig))
|
||||
/// decode with first byte set as keypair type
|
||||
pub fn decode(bytes: Vec<u8>) -> Result<Self, DecodingError> {
|
||||
match KeyFormat::try_from(bytes[0])? {
|
||||
KeyFormat::Ed25519 => Ok(Signature::Ed25519(ed25519::Signature(bytes[1..].to_vec()))),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
KeyFormat::Rsa => Ok(Signature::Rsa(rsa::Signature(bytes[1..].to_vec()))),
|
||||
KeyFormat::Secp256k1 => Ok(Signature::Secp256k1(secp256k1::Signature(bytes[1..].to_vec()))),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> &[u8] {
|
||||
use Signature::*;
|
||||
|
||||
match self {
|
||||
Ed25519(sig) => &sig.0,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Rsa(sig) => &sig.0,
|
||||
Secp256k1(sig) => &sig.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn signature_encode_decode() {
|
||||
let bytes: Vec<u8> = (0..10).collect();
|
||||
let ed25519_sig = Signature::Ed25519(crate::ed25519::Signature(bytes.clone()));
|
||||
let secp256k1_sig = Signature::Secp256k1(crate::secp256k1::Signature(bytes.clone()));
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let rsa_sig = Signature::Rsa(crate::rsa::Signature(bytes.clone()));
|
||||
|
||||
assert_eq!(Signature::decode(ed25519_sig.encode()).unwrap(), ed25519_sig);
|
||||
assert_eq!(Signature::decode(secp256k1_sig.encode()).unwrap(), secp256k1_sig);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
assert_eq!(Signature::decode(rsa_sig.encode()).unwrap(), rsa_sig);
|
||||
}
|
||||
}
|
||||
|
BIN
identity/src/test/rsa-2048.pk8
Normal file
BIN
identity/src/test/rsa-2048.pk8
Normal file
Binary file not shown.
BIN
identity/src/test/rsa-3072.pk8
Normal file
BIN
identity/src/test/rsa-3072.pk8
Normal file
Binary file not shown.
BIN
identity/src/test/rsa-4096.pk8
Normal file
BIN
identity/src/test/rsa-4096.pk8
Normal file
Binary file not shown.
@ -15,11 +15,11 @@
|
||||
*/
|
||||
|
||||
use crate::certificate::CertificateError::{
|
||||
CertificateLengthError, DecodeError, DecodeTrustError, ExpirationError, IncorrectByteLength,
|
||||
CertificateLengthError, DecodeError, DecodeTrustError, ExpirationError,
|
||||
IncorrectCertificateFormat, KeyInCertificateError, MalformedRoot, NoTrustedRoot,
|
||||
VerificationError,
|
||||
};
|
||||
use crate::trust::{Trust, TrustError, TRUST_LEN};
|
||||
use crate::trust::{Trust, TrustError};
|
||||
use fluence_identity::key_pair::KeyPair;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use std::str::FromStr;
|
||||
@ -32,6 +32,7 @@ const FORMAT: &[u8; 2] = &[0, 0];
|
||||
/// Serialization format version of a certificate.
|
||||
/// TODO
|
||||
const VERSION: &[u8; 4] = &[0, 0, 0, 0];
|
||||
const TRUST_NUMBER_LEN: usize = 1;
|
||||
|
||||
/// Chain of trusts started from self-signed root trust.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -83,7 +84,7 @@ impl Certificate {
|
||||
) -> Self {
|
||||
let root_expiration = Duration::from_secs(u64::max_value());
|
||||
|
||||
let root_trust = Trust::create(root_kp, root_kp.public_key(), root_expiration, issued_at);
|
||||
let root_trust = Trust::create(root_kp, root_kp.public(), root_expiration, issued_at);
|
||||
|
||||
let trust = Trust::create(root_kp, for_pk, expires_at, issued_at);
|
||||
|
||||
@ -109,9 +110,9 @@ impl Certificate {
|
||||
}
|
||||
|
||||
// first, verify given certificate
|
||||
Certificate::verify(extend_cert, &[extend_cert.chain[0].issued_for], cur_time)?;
|
||||
Certificate::verify(extend_cert, &[extend_cert.chain[0].issued_for.clone()], cur_time)?;
|
||||
|
||||
let issued_by_pk = issued_by.public_key();
|
||||
let issued_by_pk = issued_by.public();
|
||||
|
||||
// check if `issued_by_pk` is allowed to issue a certificate (i.e., there’s a trust for it in a chain)
|
||||
let mut previous_trust_num: i32 = -1;
|
||||
@ -172,46 +173,60 @@ impl Certificate {
|
||||
}
|
||||
|
||||
/// Convert certificate to byte format
|
||||
/// 2 format + 4 version + (64 signature + 32 public key + 8 expiration) * number of trusts
|
||||
/// 2 format + 4 version + 1 trusts number + ((1 trust size byte + trust) for each trust)
|
||||
#[allow(dead_code)]
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let mut encoded =
|
||||
Vec::with_capacity(FORMAT.len() + VERSION.len() + TRUST_LEN * self.chain.len());
|
||||
let mut encoded = Vec::new();
|
||||
encoded.extend_from_slice(FORMAT);
|
||||
encoded.extend_from_slice(VERSION);
|
||||
encoded.push(self.chain.len() as u8);
|
||||
|
||||
for t in &self.chain {
|
||||
encoded.extend(t.encode());
|
||||
let trust = t.encode();
|
||||
encoded.push(trust.len() as u8);
|
||||
encoded.extend(trust);
|
||||
}
|
||||
|
||||
encoded
|
||||
}
|
||||
|
||||
fn check_arr_len(arr: &[u8], check_len: usize) -> Result<(), CertificateError> {
|
||||
if arr.len() < check_len {
|
||||
Err(CertificateLengthError)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn decode(arr: &[u8]) -> Result<Self, CertificateError> {
|
||||
let trusts_offset = arr.len() - 2 - 4;
|
||||
if trusts_offset % TRUST_LEN != 0 {
|
||||
return Err(IncorrectByteLength);
|
||||
}
|
||||
// TODO do match different formats and versions
|
||||
Self::check_arr_len(arr, FORMAT.len() + VERSION.len() + TRUST_NUMBER_LEN)?;
|
||||
let mut offset = 0;
|
||||
let _format = &arr[offset..offset + FORMAT.len()];
|
||||
offset += FORMAT.len();
|
||||
|
||||
let number_of_trusts = trusts_offset / TRUST_LEN;
|
||||
let _version = &arr[offset..offset + VERSION.len()];
|
||||
offset += VERSION.len();
|
||||
|
||||
let number_of_trusts = arr[offset] as usize;
|
||||
offset += TRUST_NUMBER_LEN;
|
||||
|
||||
if number_of_trusts < 2 {
|
||||
return Err(CertificateLengthError);
|
||||
}
|
||||
|
||||
// TODO do match different formats and versions
|
||||
let _format = &arr[0..1];
|
||||
let _version = &arr[2..5];
|
||||
|
||||
let mut chain = Vec::with_capacity(number_of_trusts);
|
||||
|
||||
for i in 0..number_of_trusts {
|
||||
let from = i * TRUST_LEN + 6;
|
||||
let to = (i + 1) * TRUST_LEN + 6;
|
||||
for _ in 0..number_of_trusts {
|
||||
Self::check_arr_len(arr, offset + 1)?;
|
||||
let trust_len = arr[offset] as usize;
|
||||
let from = offset + 1;
|
||||
let to = from + trust_len;
|
||||
Self::check_arr_len(arr, to)?;
|
||||
let slice = &arr[from..to];
|
||||
let t = Trust::decode(slice).map_err(DecodeError)?;
|
||||
chain.push(t);
|
||||
offset += 1 + trust_len;
|
||||
}
|
||||
|
||||
Ok(Self { chain })
|
||||
@ -253,7 +268,7 @@ impl FromStr for Certificate {
|
||||
str_lines[i + 2],
|
||||
str_lines[i + 3],
|
||||
)
|
||||
.map_err(|e| DecodeTrustError(i, e))?;
|
||||
.map_err(|e| DecodeTrustError(i, e))?;
|
||||
|
||||
trusts.push(trust);
|
||||
}
|
||||
@ -282,12 +297,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_string_encoding_decoding() {
|
||||
pub fn test_string_encoding_decoding_ed25519() {
|
||||
let (_root_kp, second_kp, cert) = generate_root_cert();
|
||||
|
||||
let cur_time = current_time();
|
||||
|
||||
let third_kp = KeyPair::generate();
|
||||
let third_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let new_cert = Certificate::issue(
|
||||
&second_kp,
|
||||
@ -297,7 +312,7 @@ mod tests {
|
||||
cur_time,
|
||||
cur_time,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
|
||||
let serialized = new_cert.to_string();
|
||||
let deserialized = Certificate::from_str(&serialized);
|
||||
@ -309,12 +324,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_serialization_deserialization() {
|
||||
pub fn test_serialization_deserialization_ed25519() {
|
||||
let (_root_kp, second_kp, cert) = generate_root_cert();
|
||||
|
||||
let cur_time = current_time();
|
||||
|
||||
let third_kp = KeyPair::generate();
|
||||
let third_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let new_cert = Certificate::issue(
|
||||
&second_kp,
|
||||
@ -324,7 +339,7 @@ mod tests {
|
||||
cur_time,
|
||||
cur_time,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
|
||||
let serialized = new_cert.encode();
|
||||
let deserialized = Certificate::decode(serialized.as_slice());
|
||||
@ -336,7 +351,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_small_chain() {
|
||||
fn test_small_chain_ed25519() {
|
||||
let bad_cert = Certificate { chain: Vec::new() };
|
||||
|
||||
let check = Certificate::verify(&bad_cert, &[], current_time());
|
||||
@ -344,8 +359,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn generate_root_cert() -> (KeyPair, KeyPair, Certificate) {
|
||||
let root_kp = KeyPair::generate();
|
||||
let second_kp = KeyPair::generate();
|
||||
let root_kp = KeyPair::generate_ed25519();
|
||||
let second_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let cur_time = current_time();
|
||||
|
||||
@ -354,7 +369,7 @@ mod tests {
|
||||
second_kp.clone(),
|
||||
Certificate::issue_root(
|
||||
&root_kp,
|
||||
second_kp.public_key(),
|
||||
second_kp.public(),
|
||||
cur_time.checked_add(one_year()).unwrap(),
|
||||
cur_time,
|
||||
),
|
||||
@ -362,9 +377,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_issue_cert() {
|
||||
fn test_issue_cert_ed25519() {
|
||||
let (root_kp, second_kp, cert) = generate_root_cert();
|
||||
let trusted_roots = [root_kp.public_key()];
|
||||
let trusted_roots = [root_kp.public()];
|
||||
|
||||
// we don't need nanos for serialization, etc
|
||||
let cur_time = Duration::from_secs(
|
||||
@ -374,7 +389,7 @@ mod tests {
|
||||
.as_secs() as u64,
|
||||
);
|
||||
|
||||
let third_kp = KeyPair::generate();
|
||||
let third_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let new_cert = Certificate::issue(
|
||||
&second_kp,
|
||||
@ -387,37 +402,22 @@ mod tests {
|
||||
assert_eq!(new_cert.is_ok(), true);
|
||||
let new_cert = new_cert.unwrap();
|
||||
|
||||
println!(
|
||||
"root_kp:\n\tprivate: {}\n\tpublic: {}",
|
||||
bs58::encode(root_kp.clone().secret()).into_string(),
|
||||
bs58::encode(&root_kp.public().to_bytes().to_vec()).into_string()
|
||||
);
|
||||
println!(
|
||||
"second_kp:\n\tprivate: {}\n\tpublic: {}",
|
||||
bs58::encode(second_kp.clone().secret()).into_string(),
|
||||
bs58::encode(&second_kp.public().to_bytes().to_vec()).into_string()
|
||||
);
|
||||
println!(
|
||||
"third_kp:\n\tprivate: {}\n\tpublic: {}",
|
||||
bs58::encode(third_kp.clone().secret()).into_string(),
|
||||
bs58::encode(&third_kp.public().to_bytes().to_vec()).into_string()
|
||||
);
|
||||
println!("cert is\n{}", new_cert.to_string());
|
||||
|
||||
assert_eq!(new_cert.chain.len(), 3);
|
||||
assert_eq!(new_cert.chain[0].issued_for, root_kp.public_key());
|
||||
assert_eq!(new_cert.chain[1].issued_for, second_kp.public_key());
|
||||
assert_eq!(new_cert.chain[2].issued_for, third_kp.public_key());
|
||||
assert_eq!(new_cert.chain[0].issued_for, root_kp.public());
|
||||
assert_eq!(new_cert.chain[1].issued_for, second_kp.public());
|
||||
assert_eq!(new_cert.chain[2].issued_for, third_kp.public());
|
||||
assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cert_expiration() {
|
||||
fn test_cert_expiration_ed25519() {
|
||||
let (root_kp, second_kp, cert) = generate_root_cert();
|
||||
let trusted_roots = [root_kp.public_key()];
|
||||
let trusted_roots = [root_kp.public()];
|
||||
let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
|
||||
let third_kp = KeyPair::generate();
|
||||
let third_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let new_cert = Certificate::issue(
|
||||
&second_kp,
|
||||
@ -427,19 +427,19 @@ mod tests {
|
||||
cur_time.checked_sub(one_minute()).unwrap(),
|
||||
cur_time,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
|
||||
assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_issue_in_chain_tail() {
|
||||
fn test_issue_in_chain_tail_ed25519() {
|
||||
let (root_kp, second_kp, cert) = generate_root_cert();
|
||||
let trusted_roots = [root_kp.public_key()];
|
||||
let trusted_roots = [root_kp.public()];
|
||||
let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
|
||||
let third_kp = KeyPair::generate();
|
||||
let fourth_kp = KeyPair::generate();
|
||||
let third_kp = KeyPair::generate_ed25519();
|
||||
let fourth_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let new_cert = Certificate::issue(
|
||||
&second_kp,
|
||||
@ -449,7 +449,7 @@ mod tests {
|
||||
cur_time,
|
||||
cur_time,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
let new_cert = Certificate::issue(
|
||||
&third_kp,
|
||||
fourth_kp.public(),
|
||||
@ -463,21 +463,21 @@ mod tests {
|
||||
let new_cert = new_cert.unwrap();
|
||||
|
||||
assert_eq!(new_cert.chain.len(), 4);
|
||||
assert_eq!(new_cert.chain[0].issued_for, root_kp.public_key());
|
||||
assert_eq!(new_cert.chain[1].issued_for, second_kp.public_key());
|
||||
assert_eq!(new_cert.chain[2].issued_for, third_kp.public_key());
|
||||
assert_eq!(new_cert.chain[3].issued_for, fourth_kp.public_key());
|
||||
assert_eq!(new_cert.chain[0].issued_for, root_kp.public());
|
||||
assert_eq!(new_cert.chain[1].issued_for, second_kp.public());
|
||||
assert_eq!(new_cert.chain[2].issued_for, third_kp.public());
|
||||
assert_eq!(new_cert.chain[3].issued_for, fourth_kp.public());
|
||||
assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_issue_in_chain_body() {
|
||||
fn test_issue_in_chain_body_ed25519() {
|
||||
let (root_kp, second_kp, cert) = generate_root_cert();
|
||||
let trusted_roots = [root_kp.public_key()];
|
||||
let trusted_roots = [root_kp.public()];
|
||||
let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
|
||||
let third_kp = KeyPair::generate();
|
||||
let fourth_kp = KeyPair::generate();
|
||||
let third_kp = KeyPair::generate_ed25519();
|
||||
let fourth_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let new_cert = Certificate::issue(
|
||||
&second_kp,
|
||||
@ -487,7 +487,7 @@ mod tests {
|
||||
cur_time,
|
||||
cur_time,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
let new_cert = Certificate::issue(
|
||||
&second_kp,
|
||||
fourth_kp.public(),
|
||||
@ -501,18 +501,18 @@ mod tests {
|
||||
let new_cert = new_cert.unwrap();
|
||||
|
||||
assert_eq!(new_cert.chain.len(), 3);
|
||||
assert_eq!(new_cert.chain[0].issued_for, root_kp.public_key());
|
||||
assert_eq!(new_cert.chain[1].issued_for, second_kp.public_key());
|
||||
assert_eq!(new_cert.chain[2].issued_for, fourth_kp.public_key());
|
||||
assert_eq!(new_cert.chain[0].issued_for, root_kp.public());
|
||||
assert_eq!(new_cert.chain[1].issued_for, second_kp.public());
|
||||
assert_eq!(new_cert.chain[2].issued_for, fourth_kp.public());
|
||||
assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_cert_in_chain() {
|
||||
fn test_no_cert_in_chain_ed25519() {
|
||||
let (_root_kp, _second_kp, cert) = generate_root_cert();
|
||||
let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
|
||||
let bad_kp = KeyPair::generate();
|
||||
let bad_kp = KeyPair::generate_ed25519();
|
||||
let new_cert_bad = Certificate::issue(
|
||||
&bad_kp,
|
||||
bad_kp.public(),
|
||||
@ -529,7 +529,7 @@ mod tests {
|
||||
let (_root_kp, second_kp, cert) = generate_root_cert();
|
||||
let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
|
||||
let trusted_roots = [second_kp.public_key()];
|
||||
let trusted_roots = [second_kp.public()];
|
||||
assert!(Certificate::verify(&cert, &trusted_roots, cur_time).is_err());
|
||||
assert!(Certificate::verify(&cert, &[], cur_time).is_err());
|
||||
}
|
||||
@ -538,7 +538,7 @@ mod tests {
|
||||
fn test_forged_cert() {
|
||||
let (root_kp, _second_kp, cert) = generate_root_cert();
|
||||
let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let trusted_roots = [root_kp.public_key()];
|
||||
let trusted_roots = [root_kp.public()];
|
||||
|
||||
// forged cert
|
||||
let mut bad_chain = cert.chain;
|
||||
@ -553,11 +553,11 @@ mod tests {
|
||||
let (root_kp, second_kp, cert) = generate_root_cert();
|
||||
let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
|
||||
let trusted_roots = [root_kp.public_key()];
|
||||
let trusted_roots = [root_kp.public()];
|
||||
|
||||
assert_eq!(cert.chain.len(), 2);
|
||||
assert_eq!(cert.chain[0].issued_for, root_kp.public_key());
|
||||
assert_eq!(cert.chain[1].issued_for, second_kp.public_key());
|
||||
assert_eq!(cert.chain[0].issued_for, root_kp.public());
|
||||
assert_eq!(cert.chain[1].issued_for, second_kp.public());
|
||||
assert!(Certificate::verify(&cert, &trusted_roots, cur_time).is_ok());
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use fluence_identity::public_key::{PKError, PublicKey};
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
|
||||
use core::fmt;
|
||||
use ref_cast::RefCast;
|
||||
@ -33,7 +33,7 @@ pub struct PublicKeyHashable(PublicKey);
|
||||
#[allow(clippy::derive_hash_xor_eq)]
|
||||
impl Hash for PublicKeyHashable {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
state.write(&self.0.to_bytes());
|
||||
state.write(&self.0.encode());
|
||||
state.finish();
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ impl Hash for PublicKeyHashable {
|
||||
// TODO check for overflow
|
||||
let mut bytes: Vec<u8> = Vec::with_capacity(data.len() * 32);
|
||||
for d in data {
|
||||
bytes.extend_from_slice(&d.0.to_bytes())
|
||||
bytes.extend_from_slice(&d.0.encode())
|
||||
}
|
||||
state.write(bytes.as_slice());
|
||||
state.finish();
|
||||
@ -77,12 +77,12 @@ impl AsRef<PublicKeyHashable> for PublicKey {
|
||||
|
||||
impl Display for PublicKeyHashable {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", bs58::encode(self.0.to_bytes()).into_string())
|
||||
write!(f, "{}", bs58::encode(self.0.encode()).into_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PublicKeyHashable {
|
||||
type Err = PKError;
|
||||
type Err = fluence_identity::error::DecodingError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let pk = PublicKey::from_base58(s)?;
|
||||
@ -95,7 +95,7 @@ impl serde::Serialize for PublicKeyHashable {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_bytes(&self.0.to_bytes())
|
||||
serializer.serialize_bytes(&self.0.encode())
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ impl<'de> serde::Deserialize<'de> for PublicKeyHashable {
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let pk = PublicKey::from_bytes(b)
|
||||
let pk = PublicKey::decode(b)
|
||||
.map_err(|err| Error::custom(format!("Invalid bytes {:?}: {}", b, err)))?;
|
||||
Ok(PublicKeyHashable::from(pk))
|
||||
}
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
|
||||
use crate::revoke::RevokeError::IncorrectSignature;
|
||||
use crate::trust::{EXPIRATION_LEN, PK_LEN};
|
||||
use ed25519_dalek::SignatureError;
|
||||
use fluence_identity::key_pair::KeyPair;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use fluence_identity::signature::Signature;
|
||||
@ -27,12 +25,16 @@ use thiserror::Error as ThisError;
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum RevokeError {
|
||||
#[error("Signature is incorrect: {0}")]
|
||||
IncorrectSignature(#[source] SignatureError),
|
||||
IncorrectSignature(
|
||||
#[from]
|
||||
#[source]
|
||||
fluence_identity::error::SigningError
|
||||
),
|
||||
}
|
||||
|
||||
/// "A document" that cancels trust created before.
|
||||
/// TODO delete pk from Revoke (it is already in a trust node)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Revoke {
|
||||
/// who is revoked
|
||||
pub pk: PublicKey,
|
||||
@ -64,14 +66,16 @@ impl Revoke {
|
||||
#[allow(dead_code)]
|
||||
pub fn create(revoker: &KeyPair, to_revoke: PublicKey, revoked_at: Duration) -> Self {
|
||||
let msg = Revoke::signature_bytes(&to_revoke, revoked_at);
|
||||
let signature = revoker.sign(&msg);
|
||||
let signature = revoker.sign(&msg).unwrap();
|
||||
|
||||
Revoke::new(to_revoke, revoker.public_key(), revoked_at, signature)
|
||||
Revoke::new(to_revoke, revoker.public(), revoked_at, signature)
|
||||
}
|
||||
|
||||
fn signature_bytes(pk: &PublicKey, revoked_at: Duration) -> Vec<u8> {
|
||||
let mut msg = Vec::with_capacity(PK_LEN + EXPIRATION_LEN);
|
||||
msg.extend_from_slice(&pk.to_bytes());
|
||||
let mut msg = Vec::new();
|
||||
let pk_bytes = &pk.encode();
|
||||
msg.push(pk_bytes.len() as u8);
|
||||
msg.extend(pk_bytes);
|
||||
msg.extend_from_slice(&(revoked_at.as_secs() as u64).to_le_bytes());
|
||||
|
||||
msg
|
||||
@ -83,41 +87,39 @@ impl Revoke {
|
||||
|
||||
revoke
|
||||
.revoked_by
|
||||
.verify_strict(msg.as_slice(), &revoke.signature)
|
||||
.map_err(IncorrectSignature)
|
||||
.verify(msg.as_slice(), &revoke.signature).map_err(IncorrectSignature)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_gen_revoke_and_validate() {
|
||||
let revoker = KeyPair::generate();
|
||||
let to_revoke = KeyPair::generate();
|
||||
fn test_gen_revoke_and_validate_ed25519() {
|
||||
let revoker = KeyPair::generate_ed25519();
|
||||
let to_revoke = KeyPair::generate_ed25519();
|
||||
|
||||
let duration = Duration::new(100, 0);
|
||||
|
||||
let revoke = Revoke::create(&revoker, to_revoke.public_key(), duration);
|
||||
let revoke = Revoke::create(&revoker, to_revoke.public(), duration);
|
||||
|
||||
assert_eq!(Revoke::verify(&revoke).is_ok(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_corrupted_revoke() {
|
||||
let revoker = KeyPair::generate();
|
||||
let to_revoke = KeyPair::generate();
|
||||
fn test_validate_corrupted_revoke_ed25519() {
|
||||
let revoker = KeyPair::generate_ed25519();
|
||||
let to_revoke = KeyPair::generate_ed25519();
|
||||
|
||||
let duration = Duration::new(100, 0);
|
||||
|
||||
let revoke = Revoke::create(&revoker, to_revoke.public_key(), duration);
|
||||
let revoke = Revoke::create(&revoker, to_revoke.public(), duration);
|
||||
|
||||
let duration2 = Duration::new(95, 0);
|
||||
let corrupted_revoke = Revoke::new(
|
||||
to_revoke.public_key(),
|
||||
revoker.public_key(),
|
||||
to_revoke.public(),
|
||||
revoker.public(),
|
||||
duration2,
|
||||
revoke.signature,
|
||||
);
|
||||
|
140
src/trust.rs
140
src/trust.rs
@ -14,29 +14,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::trust::TrustError::{
|
||||
Base58DecodeError, DecodePublicKeyError, IncorrectTrustLength, ParseError, SignatureError,
|
||||
};
|
||||
use crate::trust::TrustError::{Base58DecodeError, DecodePublicKeyError, ParseError, SignatureError, DecodeErrorInvalidSize};
|
||||
use derivative::Derivative;
|
||||
use fluence_identity::key_pair::KeyPair;
|
||||
use fluence_identity::public_key::{PKError, PublicKey};
|
||||
use fluence_identity::signature::{Signature, SignatureError as SigError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use fluence_identity::signature::Signature;
|
||||
use std::convert::TryInto;
|
||||
use std::num::ParseIntError;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const SIG_LEN: usize = 64;
|
||||
pub const PK_LEN: usize = 32;
|
||||
pub const EXPIRATION_LEN: usize = 8;
|
||||
pub const ISSUED_LEN: usize = 8;
|
||||
pub const METADATA_LEN: usize = PK_LEN + EXPIRATION_LEN + ISSUED_LEN;
|
||||
pub const TRUST_LEN: usize = SIG_LEN + PK_LEN + EXPIRATION_LEN + ISSUED_LEN;
|
||||
|
||||
/// One element in chain of trust in a certificate.
|
||||
/// TODO delete pk from Trust (it is already in a trust node)
|
||||
#[derive(Clone, PartialEq, Derivative, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Derivative, Eq, Deserialize, Serialize)]
|
||||
#[derivative(Debug)]
|
||||
pub struct Trust {
|
||||
/// For whom this certificate is issued
|
||||
@ -53,11 +47,11 @@ pub struct Trust {
|
||||
}
|
||||
|
||||
fn show_pubkey(key: &PublicKey, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{}", bs58::encode(&key.to_bytes()).into_string())
|
||||
write!(f, "{}", bs58::encode(&key.encode()).into_string())
|
||||
}
|
||||
|
||||
fn show_sig(sig: &Signature, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{}", bs58::encode(&sig.to_bytes()).into_string())
|
||||
write!(f, "{}", bs58::encode(&sig.encode()).into_string())
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
@ -66,17 +60,17 @@ pub enum TrustError {
|
||||
#[error("Trust is expired at: '{0:?}', current time: '{1:?}'")]
|
||||
Expired(Duration, Duration),
|
||||
|
||||
/// Errors occured on signature verification
|
||||
/// Errors occurred on signature verification
|
||||
#[error("{0}")]
|
||||
SignatureError(
|
||||
#[from]
|
||||
#[source]
|
||||
ed25519_dalek::SignatureError,
|
||||
fluence_identity::error::SigningError,
|
||||
),
|
||||
|
||||
/// Errors occured on trust decoding from differrent formats
|
||||
/// Errors occurred on trust decoding from different formats
|
||||
#[error("Cannot decode the public key: {0} in the trust: {1}")]
|
||||
DecodePublicKeyError(String, #[source] PKError),
|
||||
DecodePublicKeyError(String, #[source] fluence_identity::error::DecodingError),
|
||||
|
||||
#[error("Cannot parse `{0}` field in the trust '{1}': {2}")]
|
||||
ParseError(String, String, #[source] ParseIntError),
|
||||
@ -84,20 +78,15 @@ pub enum TrustError {
|
||||
#[error("Cannot decode `{0}` from base58 format in the trust '{1}': {2}")]
|
||||
Base58DecodeError(String, String, #[source] bs58::decode::Error),
|
||||
|
||||
#[error("Cannot decode a signature from bytes: {0}")]
|
||||
SignatureFromBytesError(#[from] SigError),
|
||||
|
||||
#[error("{0}")]
|
||||
PublicKeyError(
|
||||
#[from]
|
||||
#[source]
|
||||
PKError,
|
||||
fluence_identity::error::DecodingError,
|
||||
),
|
||||
|
||||
#[error(
|
||||
"Trust length should be 104: public key(32) + signature(64) + expiration date(8), was: {0}"
|
||||
)]
|
||||
IncorrectTrustLength(usize),
|
||||
#[error("Cannot decode `{0}` field in the trust: invalid size")]
|
||||
DecodeErrorInvalidSize(String),
|
||||
}
|
||||
|
||||
impl Trust {
|
||||
@ -124,7 +113,7 @@ impl Trust {
|
||||
) -> Self {
|
||||
let msg = Self::metadata_bytes(&issued_for, expires_at, issued_at);
|
||||
|
||||
let signature = issued_by.sign(&msg);
|
||||
let signature = issued_by.sign(msg.as_slice()).unwrap();
|
||||
|
||||
Self {
|
||||
issued_for,
|
||||
@ -147,22 +136,18 @@ impl Trust {
|
||||
let msg: &[u8] =
|
||||
&Self::metadata_bytes(&trust.issued_for, trust.expires_at, trust.issued_at);
|
||||
|
||||
KeyPair::verify(issued_by, msg, &trust.signature).map_err(SignatureError)?;
|
||||
|
||||
Ok(())
|
||||
KeyPair::verify(issued_by, msg, &trust.signature).map_err(SignatureError)
|
||||
}
|
||||
|
||||
fn metadata_bytes(pk: &PublicKey, expires_at: Duration, issued_at: Duration) -> [u8; 48] {
|
||||
let pk_encoded = pk.to_bytes();
|
||||
fn metadata_bytes(pk: &PublicKey, expires_at: Duration, issued_at: Duration) -> Vec<u8> {
|
||||
let pk_encoded = pk.encode();
|
||||
let expires_at_encoded: [u8; EXPIRATION_LEN] = (expires_at.as_secs() as u64).to_le_bytes();
|
||||
let issued_at_encoded: [u8; ISSUED_LEN] = (issued_at.as_secs() as u64).to_le_bytes();
|
||||
let mut metadata = [0; METADATA_LEN];
|
||||
let mut metadata = Vec::new();
|
||||
|
||||
metadata[..PK_LEN].clone_from_slice(&pk_encoded[..PK_LEN]);
|
||||
metadata[PK_LEN..PK_LEN + EXPIRATION_LEN]
|
||||
.clone_from_slice(&expires_at_encoded[0..EXPIRATION_LEN]);
|
||||
metadata[PK_LEN + EXPIRATION_LEN..METADATA_LEN]
|
||||
.clone_from_slice(&issued_at_encoded[0..ISSUED_LEN]);
|
||||
metadata.extend(pk_encoded);
|
||||
metadata.extend_from_slice(&expires_at_encoded[0..EXPIRATION_LEN]);
|
||||
metadata.extend_from_slice(&issued_at_encoded[0..ISSUED_LEN]);
|
||||
|
||||
metadata
|
||||
}
|
||||
@ -170,32 +155,55 @@ impl Trust {
|
||||
/// Encode the trust into a byte array
|
||||
#[allow(dead_code)]
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let mut vec = Vec::with_capacity(TRUST_LEN);
|
||||
vec.extend_from_slice(&self.issued_for.to_bytes());
|
||||
vec.extend_from_slice(&self.signature.to_bytes());
|
||||
let mut vec = Vec::new();
|
||||
let mut issued_for = self.issued_for.encode();
|
||||
let mut signature = self.signature.encode();
|
||||
vec.push(issued_for.len() as u8);
|
||||
vec.append(&mut issued_for);
|
||||
vec.push(signature.len() as u8);
|
||||
vec.append(&mut signature);
|
||||
vec.extend_from_slice(&(self.expires_at.as_secs() as u64).to_le_bytes());
|
||||
vec.extend_from_slice(&(self.issued_at.as_secs() as u64).to_le_bytes());
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
fn check_arr_len(arr: &[u8], field_name: &str, check_len: usize) -> Result<(), TrustError> {
|
||||
if arr.len() < check_len {
|
||||
Err(DecodeErrorInvalidSize(field_name.to_string()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode a trust from a byte array as produced by `encode`.
|
||||
#[allow(dead_code)]
|
||||
pub fn decode(arr: &[u8]) -> Result<Self, TrustError> {
|
||||
if arr.len() != TRUST_LEN {
|
||||
return Err(IncorrectTrustLength(arr.len()));
|
||||
}
|
||||
Self::check_arr_len(arr, "public_key_len", 1)?;
|
||||
let pk_len = arr[0] as usize;
|
||||
let mut offset = 1;
|
||||
|
||||
let pk = PublicKey::from_bytes(&arr[0..PK_LEN])?;
|
||||
Self::check_arr_len(arr, "public_key", offset + pk_len)?;
|
||||
let pk = PublicKey::decode(&arr[offset..offset + pk_len])?;
|
||||
offset += pk_len;
|
||||
|
||||
let signature = &arr[PK_LEN..PK_LEN + SIG_LEN];
|
||||
let signature = Signature::from_bytes(signature)?;
|
||||
Self::check_arr_len(arr, "signature_size", offset + 1)?;
|
||||
let signature_len = arr[offset] as usize;
|
||||
offset += 1;
|
||||
|
||||
let expiration_bytes = &arr[PK_LEN + SIG_LEN..PK_LEN + SIG_LEN + EXPIRATION_LEN];
|
||||
Self::check_arr_len(arr, "signature", offset + signature_len)?;
|
||||
let signature = &arr[offset..offset + signature_len];
|
||||
let signature = Signature::decode(signature.to_vec())?;
|
||||
offset += signature_len;
|
||||
|
||||
Self::check_arr_len(arr, "expiration", offset + EXPIRATION_LEN)?;
|
||||
let expiration_bytes = &arr[offset..offset + EXPIRATION_LEN];
|
||||
let expiration_date = u64::from_le_bytes(expiration_bytes.try_into().unwrap());
|
||||
let expiration_date = Duration::from_secs(expiration_date);
|
||||
offset += EXPIRATION_LEN;
|
||||
|
||||
let issued_bytes = &arr[PK_LEN + SIG_LEN + EXPIRATION_LEN..TRUST_LEN];
|
||||
Self::check_arr_len(arr, "issued", offset + ISSUED_LEN)?;
|
||||
let issued_bytes = &arr[offset..];
|
||||
let issued_date = u64::from_le_bytes(issued_bytes.try_into().unwrap());
|
||||
let issued_date = Duration::from_secs(issued_date);
|
||||
|
||||
@ -228,12 +236,12 @@ impl Trust {
|
||||
) -> Result<Self, TrustError> {
|
||||
// PublicKey
|
||||
let issued_for_bytes = Self::bs58_str_to_vec(issued_for, "issued_for")?;
|
||||
let issued_for = PublicKey::from_bytes(issued_for_bytes.as_slice())
|
||||
let issued_for = PublicKey::decode(&issued_for_bytes)
|
||||
.map_err(|e| DecodePublicKeyError(issued_for.to_string(), e))?;
|
||||
|
||||
// 64 bytes signature
|
||||
let signature = Self::bs58_str_to_vec(signature, "signature")?;
|
||||
let signature = Signature::from_bytes(&signature)?;
|
||||
let signature = Signature::decode(signature.to_vec())?;
|
||||
|
||||
// Duration
|
||||
let expires_at = Self::str_to_duration(expires_at, "expires_at")?;
|
||||
@ -247,8 +255,8 @@ impl Trust {
|
||||
|
||||
impl ToString for Trust {
|
||||
fn to_string(&self) -> String {
|
||||
let issued_for = bs58::encode(self.issued_for.to_bytes()).into_string();
|
||||
let signature = bs58::encode(self.signature.to_bytes()).into_string();
|
||||
let issued_for = bs58::encode(self.issued_for.encode()).into_string();
|
||||
let signature = bs58::encode(self.signature.encode()).into_string();
|
||||
let expires_at = (self.expires_at.as_secs() as u64).to_string();
|
||||
let issued_at = (self.issued_at.as_secs() as u64).to_string();
|
||||
|
||||
@ -264,31 +272,31 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_gen_revoke_and_validate() {
|
||||
let truster = KeyPair::generate();
|
||||
let trusted = KeyPair::generate();
|
||||
fn test_gen_revoke_and_validate_ed25519() {
|
||||
let truster = KeyPair::generate_ed25519();
|
||||
let trusted = KeyPair::generate_ed25519();
|
||||
|
||||
let current = Duration::new(100, 0);
|
||||
let duration = Duration::new(1000, 0);
|
||||
let issued_at = Duration::new(10, 0);
|
||||
|
||||
let trust = Trust::create(&truster, trusted.public_key(), duration, issued_at);
|
||||
let trust = Trust::create(&truster, trusted.public(), duration, issued_at);
|
||||
|
||||
assert_eq!(
|
||||
Trust::verify(&trust, &truster.public_key(), current).is_ok(),
|
||||
Trust::verify(&trust, &truster.public(), current).is_ok(),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_corrupted_revoke() {
|
||||
let truster = KeyPair::generate();
|
||||
let trusted = KeyPair::generate();
|
||||
fn test_validate_corrupted_revoke_ed25519() {
|
||||
let truster = KeyPair::generate_ed25519();
|
||||
let trusted = KeyPair::generate_ed25519();
|
||||
|
||||
let current = Duration::new(1000, 0);
|
||||
let issued_at = Duration::new(10, 0);
|
||||
|
||||
let trust = Trust::create(&truster, trusted.public_key(), current, issued_at);
|
||||
let trust = Trust::create(&truster, trusted.public(), current, issued_at);
|
||||
|
||||
let corrupted_duration = Duration::new(1234, 0);
|
||||
let corrupted_trust = Trust::new(
|
||||
@ -298,18 +306,18 @@ mod tests {
|
||||
trust.signature,
|
||||
);
|
||||
|
||||
assert!(Trust::verify(&corrupted_trust, &truster.public_key(), current).is_err());
|
||||
assert!(Trust::verify(&corrupted_trust, &truster.public(), current).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_decode() {
|
||||
let truster = KeyPair::generate();
|
||||
let trusted = KeyPair::generate();
|
||||
fn test_encode_decode_ed25519() {
|
||||
let truster = KeyPair::generate_ed25519();
|
||||
let trusted = KeyPair::generate_ed25519();
|
||||
|
||||
let current = Duration::new(1000, 0);
|
||||
let issued_at = Duration::new(10, 0);
|
||||
|
||||
let trust = Trust::create(&truster, trusted.public_key(), current, issued_at);
|
||||
let trust = Trust::create(&truster, trusted.public(), current, issued_at);
|
||||
|
||||
let encoded = trust.encode();
|
||||
let decoded = Trust::decode(encoded.as_slice()).unwrap();
|
||||
|
@ -123,10 +123,10 @@ where
|
||||
|
||||
// Insert new TrustNode for this root_pk if there wasn't one
|
||||
if self.storage.get(&root_pk)?.is_none() {
|
||||
let mut trust_node = TrustNode::new(root_trust.issued_for, cur_time);
|
||||
let mut trust_node = TrustNode::new(root_trust.issued_for.clone(), cur_time);
|
||||
let root_auth = Auth {
|
||||
trust: root_trust.clone(),
|
||||
issued_by: root_trust.issued_for,
|
||||
issued_by: root_trust.issued_for.clone(),
|
||||
};
|
||||
trust_node.update_auth(root_auth);
|
||||
self.storage.insert(root_pk, trust_node)?;
|
||||
@ -139,7 +139,7 @@ where
|
||||
|
||||
let auth = Auth {
|
||||
trust: trust.clone(),
|
||||
issued_by: previous_trust.issued_for,
|
||||
issued_by: previous_trust.issued_for.clone(),
|
||||
};
|
||||
|
||||
self.storage
|
||||
@ -169,7 +169,7 @@ where
|
||||
|
||||
// get all possible certificates from the given public key to all roots in the graph
|
||||
let certs = self.get_all_certs(pk, roots.as_slice())?;
|
||||
Ok(self.certificates_weight(certs)?)
|
||||
self.certificates_weight(certs)
|
||||
}
|
||||
|
||||
/// Calculate weight from given certificates
|
||||
@ -347,8 +347,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn generate_root_cert() -> (KeyPair, KeyPair, Certificate) {
|
||||
let root_kp = KeyPair::generate();
|
||||
let second_kp = KeyPair::generate();
|
||||
let root_kp = KeyPair::generate_ed25519();
|
||||
let second_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let cur_time = current_time();
|
||||
|
||||
@ -357,7 +357,7 @@ mod tests {
|
||||
second_kp.clone(),
|
||||
Certificate::issue_root(
|
||||
&root_kp,
|
||||
second_kp.public_key(),
|
||||
second_kp.public(),
|
||||
cur_time.checked_add(one_minute()).unwrap(),
|
||||
cur_time,
|
||||
),
|
||||
@ -373,20 +373,20 @@ mod tests {
|
||||
) -> Result<(Vec<KeyPair>, Certificate), TrustGraphError> {
|
||||
assert!(len > 2);
|
||||
|
||||
let root_kp = KeyPair::generate();
|
||||
let second_kp = KeyPair::generate();
|
||||
let root_kp = KeyPair::generate_ed25519();
|
||||
let second_kp = KeyPair::generate_ed25519();
|
||||
|
||||
let mut cert =
|
||||
Certificate::issue_root(&root_kp, second_kp.public_key(), expires_at, issued_at);
|
||||
Certificate::issue_root(&root_kp, second_kp.public(), expires_at, issued_at);
|
||||
|
||||
let mut key_pairs = vec![root_kp, second_kp];
|
||||
|
||||
for idx in 2..len {
|
||||
let kp = keys.get(&idx).unwrap_or(&KeyPair::generate()).clone();
|
||||
let kp = keys.get(&idx).unwrap_or(&KeyPair::generate_ed25519()).clone();
|
||||
let previous_kp = &key_pairs[idx - 1];
|
||||
cert = Certificate::issue(
|
||||
&previous_kp,
|
||||
kp.public_key(),
|
||||
kp.public(),
|
||||
&cert,
|
||||
expires_at,
|
||||
// TODO: why `issued_at = issued_at - 60 seconds`?
|
||||
@ -434,12 +434,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_certs_with_same_trusts_and_different_expirations() {
|
||||
fn test_add_certs_with_same_trusts_and_different_expirations_ed25519() {
|
||||
let cur_time = current_time();
|
||||
let far_future = cur_time + Duration::from_secs(10);
|
||||
let far_far_future = cur_time + Duration::from_secs(900);
|
||||
let key_pair1 = KeyPair::generate();
|
||||
let key_pair2 = KeyPair::generate();
|
||||
let key_pair1 = KeyPair::generate_ed25519();
|
||||
let key_pair2 = KeyPair::generate_ed25519();
|
||||
|
||||
// Use key_pair1 and key_pair2 for 5th and 6th trust in the cert chain
|
||||
let mut chain_keys = HashMap::new();
|
||||
@ -459,26 +459,26 @@ mod tests {
|
||||
|
||||
let st = InMemoryStorage::new();
|
||||
let mut graph = TrustGraph::new(st);
|
||||
let root1_pk = key_pairs1[0].public_key();
|
||||
let root2_pk = key_pairs2[0].public_key();
|
||||
let root1_pk = key_pairs1[0].public();
|
||||
let root2_pk = key_pairs2[0].public();
|
||||
graph.add_root_weight(root1_pk.into(), 1).unwrap();
|
||||
graph.add_root_weight(root2_pk.into(), 0).unwrap();
|
||||
graph.add(cert1, cur_time).unwrap();
|
||||
|
||||
let node2 = graph.get(key_pair2.public_key()).unwrap().unwrap();
|
||||
let node2 = graph.get(key_pair2.public()).unwrap().unwrap();
|
||||
let auth_by_kp1 = node2
|
||||
.authorizations()
|
||||
.find(|a| a.issued_by == key_pair1.public_key())
|
||||
.find(|a| a.issued_by == key_pair1.public())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(auth_by_kp1.trust.expires_at, far_future * 2);
|
||||
|
||||
graph.add(cert2, cur_time).unwrap();
|
||||
|
||||
let node2 = graph.get(key_pair2.public_key()).unwrap().unwrap();
|
||||
let node2 = graph.get(key_pair2.public()).unwrap().unwrap();
|
||||
let auth_by_kp1 = node2
|
||||
.authorizations()
|
||||
.find(|a| a.issued_by == key_pair1.public_key())
|
||||
.find(|a| a.issued_by == key_pair1.public())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(auth_by_kp1.trust.expires_at, far_far_future * 2);
|
||||
@ -492,21 +492,21 @@ mod tests {
|
||||
let st = InMemoryStorage::new();
|
||||
let mut graph = TrustGraph::new(st);
|
||||
|
||||
let root_pk = key_pairs[0].public_key();
|
||||
let root_pk = key_pairs[0].public();
|
||||
graph.add_root_weight(root_pk.into(), 1).unwrap();
|
||||
|
||||
graph.add(cert1, current_time()).unwrap();
|
||||
|
||||
let w1 = graph.weight(key_pairs[0].public_key()).unwrap().unwrap();
|
||||
let w1 = graph.weight(key_pairs[0].public()).unwrap().unwrap();
|
||||
assert_eq!(w1, 1);
|
||||
|
||||
let w2 = graph.weight(key_pairs[1].public_key()).unwrap().unwrap();
|
||||
let w2 = graph.weight(key_pairs[1].public()).unwrap().unwrap();
|
||||
assert_eq!(w2, 2);
|
||||
|
||||
let w3 = graph.weight(key_pairs[9].public_key()).unwrap().unwrap();
|
||||
let w3 = graph.weight(key_pairs[9].public()).unwrap().unwrap();
|
||||
assert_eq!(w3, 10);
|
||||
|
||||
let node = graph.get(key_pairs[9].public_key()).unwrap().unwrap();
|
||||
let node = graph.get(key_pairs[9].public()).unwrap().unwrap();
|
||||
let auths: Vec<&Auth> = node.authorizations().collect();
|
||||
|
||||
assert_eq!(auths.len(), 1);
|
||||
@ -515,9 +515,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_cycles_in_graph() {
|
||||
let key_pair1 = KeyPair::generate();
|
||||
let key_pair2 = KeyPair::generate();
|
||||
let key_pair3 = KeyPair::generate();
|
||||
let key_pair1 = KeyPair::generate_ed25519();
|
||||
let key_pair2 = KeyPair::generate_ed25519();
|
||||
let key_pair3 = KeyPair::generate_ed25519();
|
||||
|
||||
let mut chain_keys = HashMap::new();
|
||||
chain_keys.insert(3, key_pair1.clone());
|
||||
@ -535,8 +535,8 @@ mod tests {
|
||||
|
||||
let st = InMemoryStorage::new();
|
||||
let mut graph = TrustGraph::new(st);
|
||||
let root1_pk = key_pairs1[0].public_key();
|
||||
let root2_pk = key_pairs2[0].public_key();
|
||||
let root1_pk = key_pairs1[0].public();
|
||||
let root2_pk = key_pairs2[0].public();
|
||||
graph.add_root_weight(root1_pk.into(), 1).unwrap();
|
||||
graph.add_root_weight(root2_pk.into(), 0).unwrap();
|
||||
|
||||
@ -546,15 +546,15 @@ mod tests {
|
||||
graph.add(cert1, current_time()).unwrap();
|
||||
graph.add(cert2, current_time()).unwrap();
|
||||
|
||||
let revoke1 = Revoke::create(&key_pairs1[3], key_pairs1[4].public_key(), current_time());
|
||||
let revoke1 = Revoke::create(&key_pairs1[3], key_pairs1[4].public(), current_time());
|
||||
graph.revoke(revoke1).unwrap();
|
||||
let revoke2 = Revoke::create(&key_pairs2[5], key_pairs2[6].public_key(), current_time());
|
||||
let revoke2 = Revoke::create(&key_pairs2[5], key_pairs2[6].public(), current_time());
|
||||
graph.revoke(revoke2).unwrap();
|
||||
|
||||
let w1 = graph.weight(key_pair1.public_key()).unwrap().unwrap();
|
||||
let w1 = graph.weight(key_pair1.public()).unwrap().unwrap();
|
||||
// all upper trusts are revoked for this public key
|
||||
let w2 = graph.weight(key_pair2.public_key()).unwrap();
|
||||
let w3 = graph.weight(key_pair3.public_key()).unwrap().unwrap();
|
||||
let w2 = graph.weight(key_pair2.public()).unwrap();
|
||||
let w3 = graph.weight(key_pair3.public()).unwrap().unwrap();
|
||||
let w_last1 = graph.weight(last_pk1).unwrap().unwrap();
|
||||
let w_last2 = graph.weight(last_pk2).unwrap().unwrap();
|
||||
|
||||
@ -571,13 +571,13 @@ mod tests {
|
||||
|
||||
let st = InMemoryStorage::new();
|
||||
let mut graph = TrustGraph::new(st);
|
||||
let root1_pk = key_pairs[0].public_key();
|
||||
let root1_pk = key_pairs[0].public();
|
||||
graph.add_root_weight(root1_pk.clone().into(), 1).unwrap();
|
||||
|
||||
graph.add(cert.clone(), current_time()).unwrap();
|
||||
|
||||
let certs = graph
|
||||
.get_all_certs(key_pairs.last().unwrap().public_key(), &[root1_pk])
|
||||
.get_all_certs(key_pairs.last().unwrap().public(), &[root1_pk])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(certs.len(), 1);
|
||||
@ -605,9 +605,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_find_certs() {
|
||||
let key_pair1 = KeyPair::generate();
|
||||
let key_pair2 = KeyPair::generate();
|
||||
let key_pair3 = KeyPair::generate();
|
||||
let key_pair1 = KeyPair::generate_ed25519();
|
||||
let key_pair2 = KeyPair::generate_ed25519();
|
||||
let key_pair3 = KeyPair::generate_ed25519();
|
||||
|
||||
let mut chain_keys = HashMap::new();
|
||||
chain_keys.insert(2, key_pair1.clone());
|
||||
@ -632,9 +632,9 @@ mod tests {
|
||||
|
||||
let st = InMemoryStorage::new();
|
||||
let mut graph = TrustGraph::new(st);
|
||||
let root1_pk = key_pairs1[0].public_key();
|
||||
let root2_pk = key_pairs2[0].public_key();
|
||||
let root3_pk = key_pairs3[0].public_key();
|
||||
let root1_pk = key_pairs1[0].public();
|
||||
let root2_pk = key_pairs2[0].public();
|
||||
let root3_pk = key_pairs3[0].public();
|
||||
graph.add_root_weight(root1_pk.clone().into(), 1).unwrap();
|
||||
graph.add_root_weight(root2_pk.clone().into(), 0).unwrap();
|
||||
graph.add_root_weight(root3_pk.clone().into(), 0).unwrap();
|
||||
@ -646,21 +646,21 @@ mod tests {
|
||||
let roots_values = [root1_pk, root2_pk, root3_pk];
|
||||
|
||||
let certs1 = graph
|
||||
.get_all_certs(key_pair1.public_key(), &roots_values)
|
||||
.get_all_certs(key_pair1.public(), &roots_values)
|
||||
.unwrap();
|
||||
let lenghts1: Vec<usize> = certs1.iter().map(|c| c.chain.len()).collect();
|
||||
let check_lenghts1: Vec<usize> = vec![3, 4, 4, 5, 5];
|
||||
assert_eq!(lenghts1, check_lenghts1);
|
||||
|
||||
let certs2 = graph
|
||||
.get_all_certs(key_pair2.public_key(), &roots_values)
|
||||
.get_all_certs(key_pair2.public(), &roots_values)
|
||||
.unwrap();
|
||||
let lenghts2: Vec<usize> = certs2.iter().map(|c| c.chain.len()).collect();
|
||||
let check_lenghts2: Vec<usize> = vec![4, 4, 4, 5, 5];
|
||||
assert_eq!(lenghts2, check_lenghts2);
|
||||
|
||||
let certs3 = graph
|
||||
.get_all_certs(key_pair3.public_key(), &roots_values)
|
||||
.get_all_certs(key_pair3.public(), &roots_values)
|
||||
.unwrap();
|
||||
let lenghts3: Vec<usize> = certs3.iter().map(|c| c.chain.len()).collect();
|
||||
let check_lenghts3: Vec<usize> = vec![3, 3, 5];
|
||||
|
@ -116,7 +116,7 @@ impl Storage for InMemoryStorage {
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut trust_node = TrustNode::new(*issued_for, cur_time);
|
||||
let mut trust_node = TrustNode::new(issued_for.clone(), cur_time);
|
||||
trust_node.update_auth(auth);
|
||||
self.nodes.insert(pk.clone(), trust_node);
|
||||
Ok(())
|
||||
|
@ -160,47 +160,47 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_auth_and_revoke_trust_node() {
|
||||
let kp = KeyPair::generate();
|
||||
let kp = KeyPair::generate_ed25519();
|
||||
|
||||
let now = Duration::new(50, 0);
|
||||
let past = Duration::new(5, 0);
|
||||
let future = Duration::new(500, 0);
|
||||
|
||||
let mut trust_node = TrustNode {
|
||||
pk: kp.public_key(),
|
||||
pk: kp.public(),
|
||||
trust_relations: HashMap::new(),
|
||||
verified_at: now,
|
||||
};
|
||||
|
||||
let truster = KeyPair::generate();
|
||||
let truster = KeyPair::generate_ed25519();
|
||||
|
||||
let revoke = Revoke::create(&truster, kp.public_key(), now);
|
||||
let revoke = Revoke::create(&truster, kp.public(), now);
|
||||
|
||||
trust_node.update_revoke(revoke);
|
||||
|
||||
assert!(trust_node.get_revoke(truster.public_key()).is_some());
|
||||
assert!(trust_node.get_revoke(truster.public()).is_some());
|
||||
|
||||
let old_trust = Trust::create(&truster, kp.public_key(), Duration::new(60, 0), past);
|
||||
let old_trust = Trust::create(&truster, kp.public(), Duration::new(60, 0), past);
|
||||
|
||||
let old_auth = Auth {
|
||||
trust: old_trust,
|
||||
issued_by: truster.public_key(),
|
||||
issued_by: truster.public(),
|
||||
};
|
||||
|
||||
trust_node.update_auth(old_auth);
|
||||
|
||||
assert!(trust_node.get_revoke(truster.public_key()).is_some());
|
||||
assert!(trust_node.get_auth(truster.public_key()).is_none());
|
||||
assert!(trust_node.get_revoke(truster.public()).is_some());
|
||||
assert!(trust_node.get_auth(truster.public()).is_none());
|
||||
|
||||
let trust = Trust::create(&truster, kp.public_key(), Duration::new(60, 0), future);
|
||||
let trust = Trust::create(&truster, kp.public(), Duration::new(60, 0), future);
|
||||
let auth = Auth {
|
||||
trust,
|
||||
issued_by: truster.public_key(),
|
||||
issued_by: truster.public(),
|
||||
};
|
||||
|
||||
trust_node.update_auth(auth);
|
||||
|
||||
assert!(trust_node.get_auth(truster.public_key()).is_some());
|
||||
assert!(trust_node.get_revoke(truster.public_key()).is_none());
|
||||
assert!(trust_node.get_auth(truster.public()).is_some());
|
||||
assert!(trust_node.get_revoke(truster.public()).is_none());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user