Merge pull request #4 from str4d/inspection-commands

Inspection commands
This commit is contained in:
str4d
2021-01-12 15:42:17 +13:00
committed by GitHub
8 changed files with 1176 additions and 13 deletions
+6 -6
View File
@@ -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
View File
@@ -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",
]
+7
View File
@@ -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" }
+56
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
}