Merge pull request #4 from str4d/inspection-commands
Inspection commands
This commit is contained in:
@@ -8,10 +8,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.41.0
|
||||
toolchain: 1.44.0
|
||||
override: true
|
||||
- name: Install build dependencies
|
||||
run: sudo apt install libpcsclite-dev
|
||||
@@ -49,10 +49,10 @@ jobs:
|
||||
os: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.41.0
|
||||
toolchain: 1.44.0
|
||||
override: true
|
||||
- name: Install build dependencies
|
||||
run: sudo apt install ${{ matrix.build_deps }}
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
|
||||
Generated
+650
-4
@@ -14,12 +14,12 @@ name = "age-core"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/str4d/rage.git?rev=d8fd951e059d9f7116b2b9dd0d176798a11b49f3#d8fd951e059d9f7116b2b9dd0d176798a11b49f3"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.12.3",
|
||||
"c2-chacha",
|
||||
"chacha20poly1305",
|
||||
"cookie-factory",
|
||||
"hkdf",
|
||||
"nom",
|
||||
"nom 5.1.2",
|
||||
"rand",
|
||||
"secrecy",
|
||||
"sha2",
|
||||
@@ -42,7 +42,14 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"age-core",
|
||||
"age-plugin",
|
||||
"bech32",
|
||||
"console",
|
||||
"elliptic-curve",
|
||||
"gumdrop",
|
||||
"p256",
|
||||
"sha2",
|
||||
"x509-parser 0.9.0",
|
||||
"yubikey-piv",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -51,6 +58,12 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
@@ -63,6 +76,12 @@ version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.7.2"
|
||||
@@ -75,6 +94,29 @@ version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "0.18.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2838fdd79e8776dbe07a106c784b0f8dda571a21b2750a092cc4cbaa653c8e"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium 0.4.1",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "0.19.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium 0.5.3",
|
||||
"tap",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
@@ -84,6 +126,12 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
|
||||
|
||||
[[package]]
|
||||
name = "c2-chacha"
|
||||
version = "0.3.0"
|
||||
@@ -140,6 +188,27 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cc80946b3480f421c2f17ed1cb841753a371c7c5104f51d507e13f532c856aa"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"regex",
|
||||
"terminal_size",
|
||||
"unicode-width",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2d9162b7289a46e86208d6af2c686ca5bfde445878c41a458a9fac706252d0b"
|
||||
|
||||
[[package]]
|
||||
name = "cookie-factory"
|
||||
version = "0.3.1"
|
||||
@@ -168,6 +237,75 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993a608597367c6377b258c25d7120740f00ed23a2252b729b1932dd7866f908"
|
||||
|
||||
[[package]]
|
||||
name = "der-oid-macro"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e66558629d772c3be040566b7be07be8c8f5aecee95e4a092dfe2efc313277ad"
|
||||
dependencies = [
|
||||
"nom 5.1.2",
|
||||
"num-bigint 0.3.1",
|
||||
"num-traits",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der-oid-macro"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd17d13ecf875e704369fdbde242483ac769fc18f6af21e43d5a692a079732fc"
|
||||
dependencies = [
|
||||
"nom 6.0.1",
|
||||
"num-bigint 0.3.1",
|
||||
"num-traits",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der-parser"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caca07c50eaae94d43e21f4d14eca5543b6f5f5ce64715e9b7665ac5f5185b4e"
|
||||
dependencies = [
|
||||
"der-oid-macro 0.2.0",
|
||||
"nom 5.1.2",
|
||||
"num-bigint 0.3.1",
|
||||
"num-traits",
|
||||
"proc-macro-hack",
|
||||
"rusticata-macros 2.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der-parser"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb4b1e27396f46037881c39d821660f2ff48797aaa7152a45ded7a93b368a819"
|
||||
dependencies = [
|
||||
"der-oid-macro 0.3.0",
|
||||
"nom 6.0.1",
|
||||
"num-bigint 0.3.1",
|
||||
"num-traits",
|
||||
"proc-macro-hack",
|
||||
"rusticata-macros 3.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "des"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b24e7c748888aa2fa8bce21d8c64a52efc810663285315ac7476f7197a982fae"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cipher",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
@@ -177,6 +315,44 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396db09c483e7fca5d4fdb9112685632b3e76c9a607a2649c1bf904404a01366"
|
||||
dependencies = [
|
||||
"bitvec 0.18.4",
|
||||
"const-oid",
|
||||
"ff",
|
||||
"generic-array",
|
||||
"group",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01646e077d4ebda82b73f1bca002ea1e91561a77df2431a9e79729bcc31950ef"
|
||||
dependencies = [
|
||||
"bitvec 0.18.4",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
@@ -198,6 +374,17 @@ dependencies = [
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc11f9f5fbf1943b48ae7c2bf6846e7d827a512d1be4f23af708f5ca5d01dde1"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop"
|
||||
version = "0.8.0"
|
||||
@@ -238,6 +425,15 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.7.4"
|
||||
@@ -257,6 +453,21 @@ version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
@@ -274,13 +485,77 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "6.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88034cfd6b4a0d54dd14f4a507eceee36c0b70e5a02236c4e4df571102be17f0"
|
||||
dependencies = [
|
||||
"bitvec 0.19.4",
|
||||
"lexical-core",
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7",
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"libm",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.0.1",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
@@ -290,15 +565,99 @@ version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oid-registry"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2508c8f170e55be68508b1113956a760a82684f42022f8834fb16ca198621211"
|
||||
dependencies = [
|
||||
"der-parser 5.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "p256"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "280ed58e7e5f3052b6e2f596fa40c7eff4c27c4b6b6deecb5d685ba5c2080980"
|
||||
dependencies = [
|
||||
"elliptic-curve",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p384"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06de0548166c258c22bb6bdcff3074eac4b07125040aa74db3f61db87fe5f275"
|
||||
dependencies = [
|
||||
"elliptic-curve",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3b8c0d71734018084da0c0354193a5edfb81b20d2d57a92c5b154aefc554a4a"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"crypto-mac",
|
||||
"hmac",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"sha2",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pcsc"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88e09a8d8705a2c9b1ffe1f9dd9580efe3f8e80c19fc9f99038fe99b7bb56c83"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"pcsc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pcsc-sys"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1b7bfecba2c0f1b5efb0e7caf7533ab1c295024165bcbb066231f60d33e23ea"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c220d01f863d13d96ca82359d1e81e64a7c6bf0637bcde7b2349630addf0c6"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.6.2"
|
||||
@@ -315,6 +674,12 @@ version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
@@ -333,6 +698,18 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64de9a0c5361e034f1aefc9f71a86871ec870e766fe31a009734a989b329286a"
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
@@ -374,6 +751,67 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"digest",
|
||||
"lazy_static",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"pem",
|
||||
"rand",
|
||||
"sha2",
|
||||
"simple_asn1",
|
||||
"subtle",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusticata-macros"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8a9050636e8a1b487ba1fbe99114021cd7594dde3ce6ed95bfc1691e5b5367b"
|
||||
dependencies = [
|
||||
"nom 5.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusticata-macros"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7390af60e66c44130b4c5ea85f2555b7ace835d73b4b889c704dc3cb4c0468c8"
|
||||
dependencies = [
|
||||
"nom 6.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
@@ -389,6 +827,25 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce3cdf1b5e620a498ee6f2a171885ac7e22f0e12089ec4b3d22b84921792507c"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if 1.0.0",
|
||||
"cpuid-bool 0.1.2",
|
||||
"digest",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.2"
|
||||
@@ -402,6 +859,29 @@ dependencies = [
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple_asn1"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"num-bigint 0.2.6",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@@ -414,6 +894,15 @@ version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
|
||||
|
||||
[[package]]
|
||||
name = "subtle-encoding"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.58"
|
||||
@@ -425,6 +914,54 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e"
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bd2d183bd3fac5f5fe38ddbeb4dc9aec4a39a9d7d59e7491d900302da01cbe1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
@@ -442,6 +979,12 @@ version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
@@ -498,8 +1041,111 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
|
||||
|
||||
[[package]]
|
||||
name = "x509"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9335b8ff50b6a0de184b3eeb11fdce74224e3af90ca7265012512e73fc999d1a"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"cookie-factory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x509-parser"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a76245c48460d72a3e17ad3a01855c3cae98601bb992091c1c1421c77d1cb27c"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"chrono",
|
||||
"data-encoding",
|
||||
"der-oid-macro 0.2.0",
|
||||
"der-parser 4.1.0",
|
||||
"lazy_static",
|
||||
"nom 5.1.2",
|
||||
"num-bigint 0.3.1",
|
||||
"rusticata-macros 2.1.0",
|
||||
"rustversion",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x509-parser"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b22c80f083d860f8e77f44762e9df8c92de7defeb70219ec37f32968cab53e90"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"chrono",
|
||||
"data-encoding",
|
||||
"der-oid-macro 0.3.0",
|
||||
"der-parser 5.0.0",
|
||||
"lazy_static",
|
||||
"nom 6.0.1",
|
||||
"num-bigint 0.3.1",
|
||||
"oid-registry",
|
||||
"rusticata-macros 3.0.1",
|
||||
"rustversion",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yubikey-piv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "568f3f194d91d4f5bd624983d371927c4d72c1d63be2e702cab2d09cb630a28f"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"cookie-factory",
|
||||
"der-parser 4.1.0",
|
||||
"des",
|
||||
"elliptic-curve",
|
||||
"getrandom",
|
||||
"hmac",
|
||||
"log",
|
||||
"nom 5.1.2",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"p256",
|
||||
"p384",
|
||||
"pbkdf2",
|
||||
"pcsc",
|
||||
"rsa",
|
||||
"secrecy",
|
||||
"sha-1",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"subtle-encoding",
|
||||
"x509",
|
||||
"x509-parser 0.8.2",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -13,7 +13,14 @@ edition = "2018"
|
||||
[dependencies]
|
||||
age-core = "0.5"
|
||||
age-plugin = "0.0"
|
||||
bech32 = "0.7.2"
|
||||
console = "0.14"
|
||||
elliptic-curve = "0.6"
|
||||
gumdrop = "0.8"
|
||||
p256 = "0.5"
|
||||
sha2 = "0.9"
|
||||
x509-parser = "0.9"
|
||||
yubikey-piv = { version = "0.1", features = ["untested"] }
|
||||
|
||||
[patch.crates-io]
|
||||
age-core = { git = "https://github.com/str4d/rage.git", rev = "d8fd951e059d9f7116b2b9dd0d176798a11b49f3" }
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use yubikey_piv::{key::RetiredSlotId, Serial};
|
||||
|
||||
use crate::USABLE_SLOTS;
|
||||
|
||||
pub enum Error {
|
||||
InvalidSlot(u8),
|
||||
Io(io::Error),
|
||||
MultipleCommands,
|
||||
MultipleIdentities,
|
||||
MultipleYubiKeys,
|
||||
NoIdentities,
|
||||
NoMatchingSerial(Serial),
|
||||
SlotHasNoIdentity(RetiredSlotId),
|
||||
TimedOut,
|
||||
YubiKey(yubikey_piv::Error),
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
@@ -12,16 +23,61 @@ impl From<io::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<yubikey_piv::error::Error> for Error {
|
||||
fn from(e: yubikey_piv::error::Error) -> Self {
|
||||
Error::YubiKey(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Rust only supports `fn main() -> Result<(), E: Debug>`, so we implement `Debug`
|
||||
// manually to provide the error output we want.
|
||||
impl fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::InvalidSlot(slot) => writeln!(
|
||||
f,
|
||||
"Invalid slot '{}' (expected number between 1 and 20).",
|
||||
slot
|
||||
)?,
|
||||
Error::Io(e) => writeln!(f, "Failed to set up YubiKey: {}", e)?,
|
||||
Error::MultipleCommands => writeln!(
|
||||
f,
|
||||
"Only one of --generate, --identity, --list, --list-all can be specified."
|
||||
)?,
|
||||
Error::MultipleIdentities => writeln!(
|
||||
f,
|
||||
"This YubiKey has multiple age identities. Use --slot to select a single identity."
|
||||
)?,
|
||||
Error::MultipleYubiKeys => writeln!(
|
||||
f,
|
||||
"Multiple YubiKeys are plugged in. Use --serial to select a single YubiKey."
|
||||
)?,
|
||||
Error::NoIdentities => {
|
||||
writeln!(f, "This YubiKey does not contain any age identities.")?
|
||||
}
|
||||
Error::NoMatchingSerial(serial) => {
|
||||
writeln!(f, "Could not find YubiKey with serial {}.", serial)?
|
||||
}
|
||||
Error::SlotHasNoIdentity(slot) => writeln!(
|
||||
f,
|
||||
"Slot {} does not contain an age identity or compatible key.",
|
||||
USABLE_SLOTS.iter().position(|s| s == slot).unwrap() + 1
|
||||
)?,
|
||||
Error::TimedOut => {
|
||||
writeln!(f, "Timed out while waiting for a YubiKey to be inserted.")?
|
||||
}
|
||||
Error::YubiKey(e) => match e {
|
||||
yubikey_piv::error::Error::NotFound => {
|
||||
writeln!(f, "Please insert the YubiKey you want to set up")?
|
||||
}
|
||||
e => {
|
||||
writeln!(f, "Error while communicating with YubiKey: {}", e)?;
|
||||
use std::error::Error;
|
||||
if let Some(inner) = e.source() {
|
||||
writeln!(f, "Cause: {}", inner)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
writeln!(f)?;
|
||||
writeln!(
|
||||
|
||||
+165
-3
@@ -1,11 +1,46 @@
|
||||
use age_plugin::run_state_machine;
|
||||
use gumdrop::Options;
|
||||
use yubikey_piv::{
|
||||
certificate::PublicKeyInfo,
|
||||
key::{RetiredSlotId, SlotId},
|
||||
Key, Readers,
|
||||
};
|
||||
|
||||
mod error;
|
||||
mod p256;
|
||||
mod plugin;
|
||||
mod util;
|
||||
mod yubikey;
|
||||
|
||||
use error::Error;
|
||||
|
||||
const PLUGIN_NAME: &str = "age-plugin-yubikey";
|
||||
const RECIPIENT_PREFIX: &str = "age1yubikey";
|
||||
const IDENTITY_PREFIX: &str = "age-plugin-yubikey-";
|
||||
|
||||
const USABLE_SLOTS: [RetiredSlotId; 20] = [
|
||||
RetiredSlotId::R1,
|
||||
RetiredSlotId::R2,
|
||||
RetiredSlotId::R3,
|
||||
RetiredSlotId::R4,
|
||||
RetiredSlotId::R5,
|
||||
RetiredSlotId::R6,
|
||||
RetiredSlotId::R7,
|
||||
RetiredSlotId::R8,
|
||||
RetiredSlotId::R9,
|
||||
RetiredSlotId::R10,
|
||||
RetiredSlotId::R11,
|
||||
RetiredSlotId::R12,
|
||||
RetiredSlotId::R13,
|
||||
RetiredSlotId::R14,
|
||||
RetiredSlotId::R15,
|
||||
RetiredSlotId::R16,
|
||||
RetiredSlotId::R17,
|
||||
RetiredSlotId::R18,
|
||||
RetiredSlotId::R19,
|
||||
RetiredSlotId::R20,
|
||||
];
|
||||
|
||||
#[derive(Debug, Options)]
|
||||
struct PluginOptions {
|
||||
#[options(help = "Print this help message and exit.")]
|
||||
@@ -29,6 +64,133 @@ struct PluginOptions {
|
||||
|
||||
#[options(help = "List all YubiKey keys that are compatible with age.", no_short)]
|
||||
list_all: bool,
|
||||
|
||||
#[options(
|
||||
help = "Specify which YubiKey to use, if more than one is plugged in.",
|
||||
no_short
|
||||
)]
|
||||
serial: Option<u32>,
|
||||
|
||||
#[options(
|
||||
help = "Specify which slot to use. Defaults to first usable slot.",
|
||||
no_short
|
||||
)]
|
||||
slot: Option<u8>,
|
||||
}
|
||||
|
||||
fn identity(opts: PluginOptions) -> Result<(), Error> {
|
||||
let serial = opts.serial.map(|s| s.into());
|
||||
let slot = opts
|
||||
.slot
|
||||
.map(|slot| {
|
||||
USABLE_SLOTS
|
||||
.get(slot as usize - 1)
|
||||
.cloned()
|
||||
.ok_or(Error::InvalidSlot(slot))
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let mut yubikey = yubikey::open(serial)?;
|
||||
|
||||
let mut keys = Key::list(&mut yubikey)?.into_iter().filter_map(|key| {
|
||||
// - We only use the retired slots.
|
||||
// - Only P-256 keys are compatible with us.
|
||||
match (key.slot(), key.certificate().subject_pki()) {
|
||||
(SlotId::Retired(slot), PublicKeyInfo::EcP256(pubkey)) => {
|
||||
p256::Recipient::from_pubkey(*pubkey).map(|r| (key, slot, r))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
|
||||
let (key, slot, recipient) = if let Some(slot) = slot {
|
||||
keys.find(|(_, s, _)| s == &slot)
|
||||
.ok_or(Error::SlotHasNoIdentity(slot))
|
||||
} else {
|
||||
let mut keys = keys.filter(|(key, _, _)| {
|
||||
let cert = x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||
.map(|(_, cert)| cert)
|
||||
.ok();
|
||||
match cert
|
||||
.as_ref()
|
||||
.and_then(|cert| cert.subject().iter_organization().next())
|
||||
{
|
||||
Some(org) => org.as_str() == Ok(PLUGIN_NAME),
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
match (keys.next(), keys.next()) {
|
||||
(None, None) => Err(Error::NoIdentities),
|
||||
(Some(key), None) => Ok(key),
|
||||
(Some(_), Some(_)) => Err(Error::MultipleIdentities),
|
||||
(None, Some(_)) => unreachable!(),
|
||||
}
|
||||
}?;
|
||||
|
||||
let stub = yubikey::Stub::new(yubikey.serial(), slot, &recipient);
|
||||
let created = x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||
.ok()
|
||||
.map(|(_, cert)| cert.validity().not_before.to_rfc2822())
|
||||
.unwrap_or_else(|| "Unknown".to_owned());
|
||||
|
||||
util::print_identity(stub, recipient, &created);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list(all: bool) -> Result<(), Error> {
|
||||
let mut readers = Readers::open()?;
|
||||
|
||||
for reader in readers.iter()? {
|
||||
let mut yubikey = reader.open()?;
|
||||
|
||||
for key in Key::list(&mut yubikey)? {
|
||||
// We only use the retired slots.
|
||||
let slot = match key.slot() {
|
||||
SlotId::Retired(slot) => slot,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
// Only P-256 keys are compatible with us.
|
||||
let recipient = match key.certificate().subject_pki() {
|
||||
PublicKeyInfo::EcP256(pubkey) => match p256::Recipient::from_pubkey(*pubkey) {
|
||||
Some(recipient) => recipient,
|
||||
None => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let ((name, pin_policy, touch_policy), created) =
|
||||
match x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||
.ok()
|
||||
.and_then(|(_, cert)| {
|
||||
util::extract_name_and_policies(&mut yubikey, &key, &cert, all)
|
||||
.map(|res| (res, cert.validity().not_before.to_rfc2822()))
|
||||
}) {
|
||||
Some(res) => res,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
println!(
|
||||
"# Serial: {}, Slot: {}",
|
||||
yubikey.serial(),
|
||||
// Use 1-indexing in the UI for niceness
|
||||
USABLE_SLOTS.iter().position(|s| s == &slot).unwrap() + 1,
|
||||
);
|
||||
println!("# Name: {}", name);
|
||||
println!("# Created: {}", created);
|
||||
println!("# PIN policy: {}", util::pin_policy_to_str(pin_policy));
|
||||
println!(
|
||||
"# Touch policy: {}",
|
||||
util::touch_policy_to_str(touch_policy)
|
||||
);
|
||||
println!("{}", recipient.to_string());
|
||||
println!();
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
@@ -53,11 +215,11 @@ fn main() -> Result<(), Error> {
|
||||
} else if opts.generate {
|
||||
todo!()
|
||||
} else if opts.identity {
|
||||
todo!()
|
||||
identity(opts)
|
||||
} else if opts.list {
|
||||
todo!()
|
||||
list(false)
|
||||
} else if opts.list_all {
|
||||
todo!()
|
||||
list(true)
|
||||
} else {
|
||||
// TODO: CLI identity generation
|
||||
Ok(())
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
use bech32::ToBase32;
|
||||
use elliptic_curve::sec1::EncodedPoint;
|
||||
use p256::NistP256;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
|
||||
use crate::RECIPIENT_PREFIX;
|
||||
|
||||
pub(crate) const TAG_BYTES: usize = 4;
|
||||
|
||||
/// Wrapper around a compressed secp256r1 curve point.
|
||||
#[derive(Clone)]
|
||||
pub struct Recipient(EncodedPoint<NistP256>);
|
||||
|
||||
impl fmt::Debug for Recipient {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Recipient({:?})", self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Recipient {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(
|
||||
bech32::encode(RECIPIENT_PREFIX, self.as_bytes().to_base32())
|
||||
.expect("HRP is valid")
|
||||
.as_str(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Recipient {
|
||||
/// Attempts to parse a valid secp256r1 public key from its SEC-1 encoding.
|
||||
pub(crate) fn from_pubkey(pubkey: EncodedPoint<NistP256>) -> Option<Self> {
|
||||
if pubkey.is_compressed() {
|
||||
if pubkey.decompress().is_some().into() {
|
||||
Some(Recipient(pubkey))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some(Recipient(pubkey.compress()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the compressed SEC-1 encoding of this public key.
|
||||
pub(crate) fn as_bytes(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
|
||||
pub(crate) fn tag(&self) -> [u8; TAG_BYTES] {
|
||||
let tag = Sha256::digest(self.to_string().as_bytes());
|
||||
(&tag[0..TAG_BYTES]).try_into().expect("length is correct")
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
use x509_parser::{certificate::X509Certificate, der_parser::oid::Oid};
|
||||
use yubikey_piv::{
|
||||
policy::{PinPolicy, TouchPolicy},
|
||||
Key, YubiKey,
|
||||
};
|
||||
|
||||
use crate::{p256::Recipient, yubikey::Stub, PLUGIN_NAME};
|
||||
|
||||
const POLICY_EXTENSION_OID: &[u64] = &[1, 3, 6, 1, 4, 1, 41482, 3, 8];
|
||||
|
||||
pub(crate) fn pin_policy_to_str(policy: Option<PinPolicy>) -> &'static str {
|
||||
match policy {
|
||||
Some(PinPolicy::Always) => "Always (A PIN is required for every decryption, if set)",
|
||||
Some(PinPolicy::Once) => "Once (A PIN is required once per session, if set)",
|
||||
Some(PinPolicy::Never) => "Never (A PIN is NOT required to decrypt)",
|
||||
_ => "Unknown",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn touch_policy_to_str(policy: Option<TouchPolicy>) -> &'static str {
|
||||
match policy {
|
||||
Some(TouchPolicy::Always) => "Always (A physical touch is required for every decryption)",
|
||||
Some(TouchPolicy::Cached) => {
|
||||
"Cached (A physical touch is required for decryption, and is cached for 15 seconds)"
|
||||
}
|
||||
Some(TouchPolicy::Never) => "Never (A physical touch is NOT required to decrypt)",
|
||||
_ => "Unknown",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn extract_name(cert: &X509Certificate, all: bool) -> Option<(String, bool)> {
|
||||
// Look at Subject Organization to determine if we created this.
|
||||
match cert.subject().iter_organization().next() {
|
||||
Some(org) if org.as_str() == Ok(PLUGIN_NAME) => {
|
||||
// We store the identity name as a Common Name attribute.
|
||||
let name = cert
|
||||
.subject()
|
||||
.iter_common_name()
|
||||
.next()
|
||||
.and_then(|cn| cn.as_str().ok())
|
||||
.map(|s| s.to_owned())
|
||||
.unwrap_or_default(); // TODO: This should always be present.
|
||||
|
||||
Some((name, true))
|
||||
}
|
||||
_ => {
|
||||
// Not one of ours, but we've already filtered for compatibility.
|
||||
if !all {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Display the entire subject.
|
||||
let name = cert.subject().to_string();
|
||||
|
||||
Some((name, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn extract_name_and_policies(
|
||||
yubikey: &mut YubiKey,
|
||||
key: &Key,
|
||||
cert: &X509Certificate,
|
||||
all: bool,
|
||||
) -> Option<(String, Option<PinPolicy>, Option<TouchPolicy>)> {
|
||||
// We store the PIN and touch policies for identities in their certificates
|
||||
// using the same certificate extension as PIV attestations.
|
||||
// https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
|
||||
let policies = |c: &X509Certificate| {
|
||||
c.extensions()
|
||||
.get(&Oid::from(POLICY_EXTENSION_OID).unwrap())
|
||||
// If the encoded extension doesn't have 2 bytes, we assume it is invalid.
|
||||
.filter(|policy| policy.value.len() >= 2)
|
||||
.map(|policy| {
|
||||
// We should only ever see one of three values for either policy, but
|
||||
// handle unknown values just in case.
|
||||
let pin_policy = match policy.value[0] {
|
||||
0x01 => Some(PinPolicy::Never),
|
||||
0x02 => Some(PinPolicy::Once),
|
||||
0x03 => Some(PinPolicy::Always),
|
||||
_ => None,
|
||||
};
|
||||
let touch_policy = match policy.value[1] {
|
||||
0x01 => Some(TouchPolicy::Never),
|
||||
0x02 => Some(TouchPolicy::Always),
|
||||
0x03 => Some(TouchPolicy::Cached),
|
||||
_ => None,
|
||||
};
|
||||
(pin_policy, touch_policy)
|
||||
})
|
||||
.unwrap_or((None, None))
|
||||
};
|
||||
|
||||
extract_name(cert, all).map(|(name, ours)| {
|
||||
if ours {
|
||||
let (pin_policy, touch_policy) = policies(&cert);
|
||||
(name, pin_policy, touch_policy)
|
||||
} else {
|
||||
// We can extract the PIN and touch policies via an attestation. This
|
||||
// is slow, but the user has asked for all compatible keys, so...
|
||||
let (pin_policy, touch_policy) = yubikey_piv::key::attest(yubikey, key.slot())
|
||||
.ok()
|
||||
.and_then(|buf| {
|
||||
x509_parser::parse_x509_certificate(&buf)
|
||||
.map(|(_, c)| policies(&c))
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or((None, None));
|
||||
|
||||
(name, pin_policy, touch_policy)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn print_identity(stub: Stub, recipient: Recipient, created: &str) {
|
||||
let recipient = recipient.to_string();
|
||||
if !console::user_attended() {
|
||||
eprintln!("Recipient: {}", recipient);
|
||||
}
|
||||
|
||||
println!("# created: {}", created);
|
||||
println!("# recipient: {}", recipient);
|
||||
println!("{}", stub.to_string());
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
//! Structs for handling YubiKeys.
|
||||
|
||||
use bech32::ToBase32;
|
||||
use std::fmt;
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use yubikey_piv::{key::RetiredSlotId, yubikey::Serial, Readers, YubiKey};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
p256::{Recipient, TAG_BYTES},
|
||||
IDENTITY_PREFIX,
|
||||
};
|
||||
|
||||
const ONE_SECOND: Duration = Duration::from_secs(1);
|
||||
const FIFTEEN_SECONDS: Duration = Duration::from_secs(15);
|
||||
|
||||
pub(crate) fn wait_for_readers() -> Result<Readers, Error> {
|
||||
// Start a 15-second timer waiting for a YubiKey to be inserted (if necessary).
|
||||
let start = SystemTime::now();
|
||||
loop {
|
||||
let mut readers = Readers::open()?;
|
||||
if readers.iter()?.len() > 0 {
|
||||
break Ok(readers);
|
||||
}
|
||||
|
||||
match SystemTime::now().duration_since(start) {
|
||||
Ok(end) if end >= FIFTEEN_SECONDS => return Err(Error::TimedOut),
|
||||
_ => sleep(ONE_SECOND),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn open(serial: Option<Serial>) -> Result<YubiKey, Error> {
|
||||
if Readers::open()?.iter()?.len() == 0 {
|
||||
if let Some(serial) = serial {
|
||||
eprintln!("⏳ Please insert the YubiKey with serial {}.", serial);
|
||||
} else {
|
||||
eprintln!("⏳ Please insert the YubiKey.");
|
||||
}
|
||||
}
|
||||
let mut readers = wait_for_readers()?;
|
||||
let mut readers_iter = readers.iter()?;
|
||||
|
||||
// --serial selects the YubiKey to use. If not provided, and more than one YubiKey is
|
||||
// connected, an error is returned.
|
||||
let yubikey = match (readers_iter.len(), serial) {
|
||||
(0, _) => unreachable!(),
|
||||
(1, None) => readers_iter.next().unwrap().open()?,
|
||||
(1, Some(serial)) => {
|
||||
let yubikey = readers_iter.next().unwrap().open()?;
|
||||
if yubikey.serial() != serial {
|
||||
return Err(Error::NoMatchingSerial(serial));
|
||||
}
|
||||
yubikey
|
||||
}
|
||||
(_, Some(serial)) => {
|
||||
let reader = readers_iter
|
||||
.find(|reader| match reader.open() {
|
||||
Ok(yk) => yk.serial() == serial,
|
||||
_ => false,
|
||||
})
|
||||
.ok_or(Error::NoMatchingSerial(serial))?;
|
||||
reader.open()?
|
||||
}
|
||||
(_, None) => return Err(Error::MultipleYubiKeys),
|
||||
};
|
||||
|
||||
Ok(yubikey)
|
||||
}
|
||||
|
||||
/// A reference to an age key stored in a YubiKey.
|
||||
#[derive(Debug)]
|
||||
pub struct Stub {
|
||||
pub(crate) serial: Serial,
|
||||
pub(crate) slot: RetiredSlotId,
|
||||
pub(crate) tag: [u8; TAG_BYTES],
|
||||
identity_index: usize,
|
||||
}
|
||||
|
||||
impl fmt::Display for Stub {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(
|
||||
bech32::encode(IDENTITY_PREFIX, self.to_bytes().to_base32())
|
||||
.expect("HRP is valid")
|
||||
.to_uppercase()
|
||||
.as_str(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stub {
|
||||
/// Returns a key stub and recipient for this `(Serial, SlotId, PublicKey)` tuple.
|
||||
///
|
||||
/// Does not check that the `PublicKey` matches the given `(Serial, SlotId)` tuple;
|
||||
/// this is checked at decryption time.
|
||||
pub(crate) fn new(serial: Serial, slot: RetiredSlotId, recipient: &Recipient) -> Self {
|
||||
Stub {
|
||||
serial,
|
||||
slot,
|
||||
tag: recipient.tag(),
|
||||
identity_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = Vec::with_capacity(9);
|
||||
bytes.extend_from_slice(&self.serial.0.to_le_bytes());
|
||||
bytes.push(self.slot.into());
|
||||
bytes.extend_from_slice(&self.tag);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user