Use x509-cert certificate builder (#495)
Co-authored-by: Carl Wallace <carl@redhoundsoftware.com>
This commit is contained in:
Generated
+58
-221
@@ -20,45 +20,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asn1-rs"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf6690c370453db30743b373a60ba498fc0d6d83b11f4abfd87a84a075db5dd4"
|
||||
dependencies = [
|
||||
"asn1-rs-derive",
|
||||
"asn1-rs-impl",
|
||||
"displaydoc",
|
||||
"nom",
|
||||
"num-traits",
|
||||
"rusticata-macros",
|
||||
"thiserror",
|
||||
"time 0.3.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asn1-rs-derive"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asn1-rs-impl"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@@ -71,12 +32,6 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.5.3"
|
||||
@@ -132,7 +87,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time 0.1.45",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
@@ -172,7 +127,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -200,12 +155,6 @@ version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
|
||||
|
||||
[[package]]
|
||||
name = "cookie-factory"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
@@ -267,7 +216,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -284,38 +233,32 @@ checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.3"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed"
|
||||
checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"der_derive",
|
||||
"flagset",
|
||||
"pem-rfc7468",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der-parser"
|
||||
version = "8.1.0"
|
||||
name = "der_derive"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1"
|
||||
checksum = "114792ba6b7545d3f3dd693794aed3a312a67795cd577fcc725c148d84fabe32"
|
||||
dependencies = [
|
||||
"asn1-rs",
|
||||
"displaydoc",
|
||||
"nom",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rusticata-macros",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -339,34 +282,25 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.16.1"
|
||||
version = "0.16.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1b0a1222f8072619e8a6b667a854020a03d363738303203c09468b3424a420a"
|
||||
checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428"
|
||||
dependencies = [
|
||||
"der",
|
||||
"digest",
|
||||
"elliptic-curve",
|
||||
"rfc6979",
|
||||
"signature",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.13.2"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea5a92946e8614bb585254898bb7dd1ddad241ace60c52149e3765e34cc039d"
|
||||
checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"crypto-bigint",
|
||||
@@ -427,6 +361,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flagset"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.6"
|
||||
@@ -554,12 +494,6 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.60"
|
||||
@@ -636,17 +570,6 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.2"
|
||||
@@ -696,15 +619,6 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oid-registry"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff"
|
||||
dependencies = [
|
||||
"asn1-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.0"
|
||||
@@ -830,7 +744,7 @@ dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@@ -847,18 +761,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.49"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
|
||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -922,9 +836,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.0"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dd2017d3e6d67384f301f8b06fbf4567afc576430a61624d845eb04d2b30a72"
|
||||
checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"const-oid",
|
||||
@@ -936,20 +850,13 @@ dependencies = [
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"sha2",
|
||||
"signature",
|
||||
"spki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusticata-macros"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.6"
|
||||
@@ -1023,9 +930,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d"
|
||||
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
@@ -1045,9 +952,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e"
|
||||
checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
@@ -1077,15 +984,14 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.6"
|
||||
name = "syn"
|
||||
version = "2.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1097,26 +1003,6 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
@@ -1128,33 +1014,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
@@ -1173,12 +1032,6 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.2.2"
|
||||
@@ -1227,7 +1080,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -1249,7 +1102,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -1349,31 +1202,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
|
||||
[[package]]
|
||||
name = "x509"
|
||||
version = "0.2.0"
|
||||
name = "x509-cert"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3cec94c3999f31341553f358ef55f65fc031291a022cd42ec0ce7219560c76"
|
||||
checksum = "077a1672d8ecfa5c1fe69fa7c5d043962e4e32866d4375495536261c0b4781f5"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"cookie-factory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x509-parser"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8"
|
||||
dependencies = [
|
||||
"asn1-rs",
|
||||
"base64",
|
||||
"data-encoding",
|
||||
"der-parser",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"oid-registry",
|
||||
"rusticata-macros",
|
||||
"thiserror",
|
||||
"time 0.3.17",
|
||||
"const-oid",
|
||||
"der",
|
||||
"sha1",
|
||||
"signature",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1382,9 +1220,9 @@ version = "0.8.0-pre.0"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"chrono",
|
||||
"cookie-factory",
|
||||
"der-parser",
|
||||
"der",
|
||||
"des",
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"env_logger",
|
||||
"hmac",
|
||||
@@ -1406,8 +1244,7 @@ dependencies = [
|
||||
"signature",
|
||||
"subtle",
|
||||
"uuid",
|
||||
"x509",
|
||||
"x509-parser",
|
||||
"x509-cert",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -1422,7 +1259,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"sha2",
|
||||
"termcolor",
|
||||
"x509-parser",
|
||||
"x509-cert",
|
||||
"yubikey",
|
||||
]
|
||||
|
||||
|
||||
+8
-5
@@ -19,10 +19,12 @@ rust-version = "1.65"
|
||||
[workspace]
|
||||
members = [".", "cli"]
|
||||
|
||||
[workspace.dependencies]
|
||||
x509-cert = { version = "0.2.3", features = [ "builder", "hazmat" ] }
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.23"
|
||||
cookie-factory = "0.3"
|
||||
der-parser = "8"
|
||||
der = "0.7.1"
|
||||
des = "0.8"
|
||||
elliptic-curve = "0.13"
|
||||
hex = { package = "base16ct", version = "0.2", features = ["alloc"] }
|
||||
@@ -32,19 +34,20 @@ nom = "7"
|
||||
num-bigint-dig = { version = "0.8", features = ["rand"] }
|
||||
num-traits = "0.2"
|
||||
num-integer = "0.1"
|
||||
ecdsa = { version = "0.16.7", features = ["digest", "pem"] }
|
||||
p256 = "0.13"
|
||||
p384 = "0.13"
|
||||
pbkdf2 = { version = "0.12", default-features = false, features = ["hmac"] }
|
||||
pcsc = "2.3.1"
|
||||
rand_core = { version = "0.6", features = ["std"] }
|
||||
rsa = "0.9"
|
||||
rsa = { version = "0.9.2", features = ["sha2"] }
|
||||
secrecy = "0.8"
|
||||
sha1 = { version = "0.10", features = ["oid"] }
|
||||
sha2 = { version = "0.10", features = ["oid"] }
|
||||
signature = "2.0.0"
|
||||
subtle = "2"
|
||||
uuid = { version = "1.2", features = ["v4"] }
|
||||
x509 = "0.2"
|
||||
x509-parser = "0.14"
|
||||
x509-cert.workspace = true
|
||||
zeroize = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
+1
-1
@@ -22,5 +22,5 @@ log = "0.4"
|
||||
once_cell = "1"
|
||||
sha2 = "0.10"
|
||||
termcolor = "1"
|
||||
x509-parser = "0.14"
|
||||
x509-cert.workspace = true
|
||||
yubikey = { version = "0.8.0-pre.0", path = ".." }
|
||||
|
||||
+23
-45
@@ -9,7 +9,7 @@ use std::{
|
||||
sync::Mutex,
|
||||
};
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, StandardStreamLock, WriteColor};
|
||||
use x509_parser::parse_x509_certificate;
|
||||
use x509_cert::der::Encode;
|
||||
use yubikey::{certificate::Certificate, piv::*, YubiKey};
|
||||
|
||||
/// Print a success status message (in green if colors are enabled)
|
||||
@@ -180,52 +180,30 @@ pub fn print_cert_info(
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let buf = cert.into_buffer();
|
||||
let cert = &cert.cert;
|
||||
|
||||
if !buf.is_empty() {
|
||||
let fingerprint = Sha256::digest(&buf);
|
||||
let slot_id: u8 = slot.into();
|
||||
print_cert_attr(stream, "Slot", format!("{:x}", slot_id))?;
|
||||
match parse_x509_certificate(&buf) {
|
||||
Ok((_rem, cert)) => {
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Algorithm",
|
||||
cert.tbs_certificate.subject_pki.algorithm.algorithm,
|
||||
)?;
|
||||
let fingerprint = Sha256::digest(&cert.to_der().unwrap());
|
||||
let slot_id: u8 = slot.into();
|
||||
print_cert_attr(stream, "Slot", format!("{:x}", slot_id))?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Algorithm",
|
||||
cert.tbs_certificate.subject_public_key_info.algorithm.oid,
|
||||
)?;
|
||||
|
||||
print_cert_attr(stream, "Subject", cert.tbs_certificate.subject)?;
|
||||
print_cert_attr(stream, "Issuer", cert.tbs_certificate.issuer)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Fingerprint",
|
||||
&hex::upper::encode_string(&fingerprint),
|
||||
)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Not Before",
|
||||
cert.tbs_certificate
|
||||
.validity
|
||||
.not_before
|
||||
.to_rfc2822()
|
||||
.unwrap(),
|
||||
)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Not After",
|
||||
cert.tbs_certificate
|
||||
.validity
|
||||
.not_after
|
||||
.to_rfc2822()
|
||||
.unwrap(),
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
println!("Failed to parse certificate");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
}
|
||||
print_cert_attr(stream, "Subject", &cert.tbs_certificate.subject)?;
|
||||
print_cert_attr(stream, "Issuer", &cert.tbs_certificate.issuer)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Fingerprint",
|
||||
&hex::upper::encode_string(&fingerprint),
|
||||
)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Not Before",
|
||||
cert.tbs_certificate.validity.not_before,
|
||||
)?;
|
||||
print_cert_attr(stream, "Not After", cert.tbs_certificate.validity.not_after)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+258
-498
@@ -33,90 +33,27 @@
|
||||
use crate::{
|
||||
consts::CB_OBJ_MAX,
|
||||
error::{Error, Result},
|
||||
piv::{sign_data, AlgorithmId, SlotId},
|
||||
piv::SlotId,
|
||||
serialization::*,
|
||||
transaction::Transaction,
|
||||
yubikey::YubiKey,
|
||||
Buffer,
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use elliptic_curve::sec1::EncodedPoint as EcPublicKey;
|
||||
use log::error;
|
||||
use num_bigint_dig::BigUint;
|
||||
use p256::NistP256;
|
||||
use p384::NistP384;
|
||||
use rsa::{traits::PublicKeyParts, RsaPublicKey};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::fmt::Display;
|
||||
use std::{fmt, ops::DerefMut};
|
||||
use x509::{der::Oid, RelativeDistinguishedName};
|
||||
use x509_parser::{parse_x509_certificate, x509::SubjectPublicKeyInfo};
|
||||
use x509_cert::{
|
||||
builder::{Builder, CertificateBuilder, Profile},
|
||||
der::{self, referenced::OwnedToRef, Decode, Encode},
|
||||
name::Name,
|
||||
serial_number::SerialNumber,
|
||||
spki::{SubjectPublicKeyInfoOwned, SubjectPublicKeyInfoRef},
|
||||
time::Validity,
|
||||
};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
// TODO: Make these der_parser::oid::Oid constants when it has const fn support.
|
||||
const OID_RSA_ENCRYPTION: &str = "1.2.840.113549.1.1.1";
|
||||
const OID_EC_PUBLIC_KEY: &str = "1.2.840.10045.2.1";
|
||||
const OID_NIST_P256: &str = "1.2.840.10045.3.1.7";
|
||||
const OID_NIST_P384: &str = "1.3.132.0.34";
|
||||
|
||||
const TAG_CERT: u8 = 0x70;
|
||||
const TAG_CERT_COMPRESS: u8 = 0x71;
|
||||
const TAG_CERT_LRC: u8 = 0xFE;
|
||||
|
||||
/// A serial number for a [`Certificate`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Serial(BigUint);
|
||||
|
||||
impl From<BigUint> for Serial {
|
||||
fn from(num: BigUint) -> Serial {
|
||||
Serial(num)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 20]> for Serial {
|
||||
fn from(bytes: [u8; 20]) -> Serial {
|
||||
Serial(BigUint::from_bytes_be(&bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Serial {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Serial> {
|
||||
if bytes.len() <= 20 {
|
||||
Ok(Serial(BigUint::from_bytes_be(bytes)))
|
||||
} else {
|
||||
Err(Error::ParseError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serial {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
self.0.to_bytes_be()
|
||||
}
|
||||
/// Returns itself formatted as x509 compatible hex string
|
||||
pub fn as_x509_hex(&self) -> String {
|
||||
let data = self.to_bytes();
|
||||
let raw_hex_string = format!("{:02X?}", data);
|
||||
raw_hex_string
|
||||
.replace(", ", ":")
|
||||
.replace([']', '['], "")
|
||||
.to_lowercase()
|
||||
}
|
||||
/// Returns itself formatted as x509 compatible int string
|
||||
pub fn as_x509_int(&self) -> String {
|
||||
let Serial(buint) = self;
|
||||
format!("{}", buint)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Serial {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&self.as_x509_hex())
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about how a [`Certificate`] is stored within a YubiKey.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum CertInfo {
|
||||
@@ -148,210 +85,11 @@ impl From<CertInfo> for u8 {
|
||||
}
|
||||
}
|
||||
|
||||
impl x509::AlgorithmIdentifier for AlgorithmId {
|
||||
type AlgorithmOid = &'static [u64];
|
||||
|
||||
fn algorithm(&self) -> Self::AlgorithmOid {
|
||||
match self {
|
||||
// RSA encryption
|
||||
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => &[1, 2, 840, 113_549, 1, 1, 1],
|
||||
// EC Public Key
|
||||
AlgorithmId::EccP256 | AlgorithmId::EccP384 => &[1, 2, 840, 10045, 2, 1],
|
||||
}
|
||||
}
|
||||
|
||||
fn parameters<W: std::io::Write>(
|
||||
&self,
|
||||
w: cookie_factory::WriteContext<W>,
|
||||
) -> cookie_factory::GenResult<W> {
|
||||
use x509::der::write::der_oid;
|
||||
|
||||
// From [RFC 5480](https://tools.ietf.org/html/rfc5480#section-2.1.1):
|
||||
// ```text
|
||||
// ECParameters ::= CHOICE {
|
||||
// namedCurve OBJECT IDENTIFIER
|
||||
// -- implicitCurve NULL
|
||||
// -- specifiedCurve SpecifiedECDomain
|
||||
// }
|
||||
// ```
|
||||
match self {
|
||||
AlgorithmId::EccP256 => der_oid(&[1, 2, 840, 10045, 3, 1, 7][..])(w),
|
||||
AlgorithmId::EccP384 => der_oid(&[1, 3, 132, 0, 34][..])(w),
|
||||
_ => Ok(w),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about a public key within a [`Certificate`].
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub enum PublicKeyInfo {
|
||||
/// RSA keys
|
||||
Rsa {
|
||||
/// RSA algorithm
|
||||
algorithm: AlgorithmId,
|
||||
|
||||
/// Public key
|
||||
pubkey: RsaPublicKey,
|
||||
},
|
||||
|
||||
/// EC P-256 keys
|
||||
EcP256(EcPublicKey<NistP256>),
|
||||
|
||||
/// EC P-384 keys
|
||||
EcP384(EcPublicKey<NistP384>),
|
||||
}
|
||||
|
||||
impl fmt::Debug for PublicKeyInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "PublicKeyInfo({:?})", self.algorithm())
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicKeyInfo {
|
||||
fn parse(subject_pki: &SubjectPublicKeyInfo<'_>) -> Result<Self> {
|
||||
match subject_pki.algorithm.algorithm.to_string().as_str() {
|
||||
OID_RSA_ENCRYPTION => {
|
||||
let pubkey = read_pki::rsa_pubkey(&subject_pki.subject_public_key.data)?;
|
||||
|
||||
Ok(PublicKeyInfo::Rsa {
|
||||
algorithm: match pubkey.n().bits() {
|
||||
1024 => AlgorithmId::Rsa1024,
|
||||
2048 => AlgorithmId::Rsa2048,
|
||||
_ => return Err(Error::AlgorithmError),
|
||||
},
|
||||
pubkey,
|
||||
})
|
||||
}
|
||||
OID_EC_PUBLIC_KEY => {
|
||||
let key_bytes = &subject_pki.subject_public_key.data;
|
||||
let algorithm_parameters = subject_pki
|
||||
.algorithm
|
||||
.parameters
|
||||
.as_ref()
|
||||
.ok_or(Error::InvalidObject)?;
|
||||
|
||||
match read_pki::ec_parameters(algorithm_parameters)? {
|
||||
AlgorithmId::EccP256 => EcPublicKey::<NistP256>::from_bytes(key_bytes)
|
||||
.map(PublicKeyInfo::EcP256)
|
||||
.map_err(|_| Error::InvalidObject),
|
||||
AlgorithmId::EccP384 => EcPublicKey::<NistP384>::from_bytes(key_bytes)
|
||||
.map(PublicKeyInfo::EcP384)
|
||||
.map_err(|_| Error::InvalidObject),
|
||||
_ => Err(Error::AlgorithmError),
|
||||
}
|
||||
}
|
||||
_ => Err(Error::InvalidObject),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the algorithm that this public key can be used with.
|
||||
pub fn algorithm(&self) -> AlgorithmId {
|
||||
match self {
|
||||
PublicKeyInfo::Rsa { algorithm, .. } => *algorithm,
|
||||
PublicKeyInfo::EcP256(_) => AlgorithmId::EccP256,
|
||||
PublicKeyInfo::EcP384(_) => AlgorithmId::EccP384,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl x509::SubjectPublicKeyInfo for PublicKeyInfo {
|
||||
type AlgorithmId = AlgorithmId;
|
||||
type SubjectPublicKey = Vec<u8>;
|
||||
|
||||
fn algorithm_id(&self) -> AlgorithmId {
|
||||
self.algorithm()
|
||||
}
|
||||
|
||||
fn public_key(&self) -> Vec<u8> {
|
||||
match self {
|
||||
PublicKeyInfo::Rsa { pubkey, .. } => {
|
||||
cookie_factory::gen_simple(write_pki::rsa_pubkey(pubkey), vec![])
|
||||
.expect("can write to Vec")
|
||||
}
|
||||
PublicKeyInfo::EcP256(pubkey) => pubkey.as_bytes().to_vec(),
|
||||
PublicKeyInfo::EcP384(pubkey) => pubkey.as_bytes().to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Digest algorithms.
|
||||
///
|
||||
/// See RFC 4055 and RFC 8017.
|
||||
enum DigestId {
|
||||
/// Secure Hash Algorithm 256 (SHA256)
|
||||
Sha256,
|
||||
}
|
||||
|
||||
impl x509::AlgorithmIdentifier for DigestId {
|
||||
type AlgorithmOid = &'static [u64];
|
||||
|
||||
fn algorithm(&self) -> Self::AlgorithmOid {
|
||||
match self {
|
||||
// See https://tools.ietf.org/html/rfc4055#section-2.1
|
||||
DigestId::Sha256 => &[2, 16, 840, 1, 101, 3, 4, 2, 1],
|
||||
}
|
||||
}
|
||||
|
||||
fn parameters<W: std::io::Write>(
|
||||
&self,
|
||||
w: cookie_factory::WriteContext<W>,
|
||||
) -> cookie_factory::GenResult<W> {
|
||||
// Parameters are an explicit NULL
|
||||
// See https://tools.ietf.org/html/rfc8017#appendix-A.2.4
|
||||
x509::der::write::der_null()(w)
|
||||
}
|
||||
}
|
||||
|
||||
enum SignatureId {
|
||||
/// Public-Key Cryptography Standards (PKCS) #1 version 1.5 signature algorithm with
|
||||
/// Secure Hash Algorithm 256 (SHA256) and Rivest, Shamir and Adleman (RSA) encryption
|
||||
///
|
||||
/// See RFC 4055 and RFC 8017.
|
||||
Sha256WithRsaEncryption,
|
||||
|
||||
/// Elliptic Curve Digital Signature Algorithm (DSA) coupled with the Secure Hash
|
||||
/// Algorithm 256 (SHA256) algorithm
|
||||
///
|
||||
/// See RFC 5758.
|
||||
EcdsaWithSha256,
|
||||
}
|
||||
|
||||
impl x509::AlgorithmIdentifier for SignatureId {
|
||||
type AlgorithmOid = &'static [u64];
|
||||
|
||||
fn algorithm(&self) -> Self::AlgorithmOid {
|
||||
match self {
|
||||
SignatureId::Sha256WithRsaEncryption => &[1, 2, 840, 113_549, 1, 1, 11],
|
||||
SignatureId::EcdsaWithSha256 => &[1, 2, 840, 10045, 4, 3, 2],
|
||||
}
|
||||
}
|
||||
|
||||
fn parameters<W: std::io::Write>(
|
||||
&self,
|
||||
w: cookie_factory::WriteContext<W>,
|
||||
) -> cookie_factory::GenResult<W> {
|
||||
// No parameters for any SignatureId
|
||||
Ok(w)
|
||||
}
|
||||
}
|
||||
|
||||
/// Certificates
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Certificate {
|
||||
serial: Serial,
|
||||
#[allow(dead_code)]
|
||||
issuer: String,
|
||||
subject: String,
|
||||
subject_pki: PublicKeyInfo,
|
||||
data: Buffer,
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a [u8]> for Certificate {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(bytes: &'a [u8]) -> Result<Self> {
|
||||
Self::from_bytes(bytes.to_vec())
|
||||
}
|
||||
/// Inner certificate
|
||||
pub cert: x509_cert::Certificate,
|
||||
}
|
||||
|
||||
impl Certificate {
|
||||
@@ -360,112 +98,35 @@ impl Certificate {
|
||||
///
|
||||
/// `extensions` is optional; if empty, no extensions will be included. Due to the
|
||||
/// need for an `O: Oid` type parameter, users who do not have any extensions should
|
||||
/// use the workaround `let extensions: &[x509::Extension<'_, &[u64]>] = &[];`.
|
||||
pub fn generate_self_signed<O: Oid>(
|
||||
/// use the workaround `let extensions: &[x509_cert::Extension<'_, &[u64]>] = &[];`.
|
||||
pub fn generate_self_signed<F, KT: yubikey_signer::KeyType>(
|
||||
yubikey: &mut YubiKey,
|
||||
key: SlotId,
|
||||
serial: impl Into<Serial>,
|
||||
not_after: Option<DateTime<Utc>>,
|
||||
subject: &[RelativeDistinguishedName<'_>],
|
||||
subject_pki: PublicKeyInfo,
|
||||
extensions: &[x509::Extension<'_, O>],
|
||||
) -> Result<Self> {
|
||||
let serial = serial.into();
|
||||
|
||||
let mut tbs_cert = Buffer::new(Vec::with_capacity(CB_OBJ_MAX));
|
||||
|
||||
let signature_algorithm = match subject_pki.algorithm() {
|
||||
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => SignatureId::Sha256WithRsaEncryption,
|
||||
AlgorithmId::EccP256 | AlgorithmId::EccP384 => SignatureId::EcdsaWithSha256,
|
||||
};
|
||||
|
||||
cookie_factory::gen(
|
||||
x509::write::tbs_certificate(
|
||||
&serial.to_bytes(),
|
||||
&signature_algorithm,
|
||||
// Issuer and subject are the same in self-signed certificates.
|
||||
subject,
|
||||
Utc::now(),
|
||||
not_after,
|
||||
subject,
|
||||
&subject_pki,
|
||||
extensions,
|
||||
),
|
||||
tbs_cert.deref_mut(),
|
||||
)
|
||||
.expect("can serialize to Vec");
|
||||
|
||||
let signature = match signature_algorithm {
|
||||
SignatureId::Sha256WithRsaEncryption => {
|
||||
use cookie_factory::{combinator::slice, sequence::tuple};
|
||||
use x509::{
|
||||
der::write::{der_octet_string, der_sequence},
|
||||
write::algorithm_identifier,
|
||||
};
|
||||
|
||||
let em_len = if let AlgorithmId::Rsa1024 = subject_pki.algorithm() {
|
||||
128
|
||||
} else {
|
||||
256
|
||||
};
|
||||
|
||||
let h = Sha256::digest(&tbs_cert);
|
||||
|
||||
let t = cookie_factory::gen_simple(
|
||||
der_sequence((
|
||||
algorithm_identifier(&DigestId::Sha256),
|
||||
der_octet_string(&h),
|
||||
)),
|
||||
vec![],
|
||||
)
|
||||
.expect("can serialize into Vec");
|
||||
|
||||
let em = cookie_factory::gen_simple(
|
||||
tuple((
|
||||
slice(&[0x00, 0x01]),
|
||||
slice(&vec![0xff; em_len - t.len() - 3]),
|
||||
slice(&[0x00]),
|
||||
slice(t),
|
||||
)),
|
||||
vec![],
|
||||
)
|
||||
.expect("can serialize to Vec");
|
||||
|
||||
sign_data(yubikey, &em, subject_pki.algorithm(), key)
|
||||
}
|
||||
SignatureId::EcdsaWithSha256 => sign_data(
|
||||
yubikey,
|
||||
&Sha256::digest(&tbs_cert),
|
||||
subject_pki.algorithm(),
|
||||
key,
|
||||
),
|
||||
}?;
|
||||
|
||||
let mut data = Buffer::new(Vec::with_capacity(CB_OBJ_MAX));
|
||||
|
||||
cookie_factory::gen(
|
||||
x509::write::certificate(&tbs_cert, &signature_algorithm, &signature),
|
||||
data.deref_mut(),
|
||||
)
|
||||
.expect("can serialize to Vec");
|
||||
|
||||
let (issuer, subject) = parse_x509_certificate(&data)
|
||||
.map(|(_, cert)| {
|
||||
(
|
||||
cert.tbs_certificate.issuer.to_string(),
|
||||
cert.tbs_certificate.subject.to_string(),
|
||||
)
|
||||
})
|
||||
.expect("We just serialized this correctly");
|
||||
|
||||
let cert = Certificate {
|
||||
serial: SerialNumber,
|
||||
validity: Validity,
|
||||
subject: Name,
|
||||
subject_pki: SubjectPublicKeyInfoOwned,
|
||||
extensions: F,
|
||||
) -> Result<Self>
|
||||
where
|
||||
F: FnOnce(&mut CertificateBuilder<'_, yubikey_signer::Signer<'_, KT>>) -> der::Result<()>,
|
||||
{
|
||||
let signer = yubikey_signer::Signer::new(yubikey, key, subject_pki.owned_to_ref())?;
|
||||
let mut builder = CertificateBuilder::new(
|
||||
Profile::Manual { issuer: None },
|
||||
serial,
|
||||
issuer,
|
||||
validity,
|
||||
subject,
|
||||
subject_pki,
|
||||
data,
|
||||
};
|
||||
&signer,
|
||||
)
|
||||
.map_err(|_| Error::KeyError)?;
|
||||
|
||||
// Add custom extensions
|
||||
extensions(&mut builder)?;
|
||||
|
||||
let cert = builder.build().map_err(|_| Error::KeyError)?;
|
||||
let cert = Self { cert };
|
||||
cert.write(yubikey, key, CertInfo::Uncompressed)?;
|
||||
|
||||
Ok(cert)
|
||||
@@ -480,13 +141,14 @@ impl Certificate {
|
||||
return Err(Error::InvalidObject);
|
||||
}
|
||||
|
||||
Certificate::from_bytes(buf)
|
||||
Self::from_bytes(buf)
|
||||
}
|
||||
|
||||
/// Write this certificate into the YubiKey in the given slot
|
||||
pub fn write(&self, yubikey: &mut YubiKey, slot: SlotId, certinfo: CertInfo) -> Result<()> {
|
||||
let txn = yubikey.begin_transaction()?;
|
||||
write_certificate(&txn, slot, Some(&self.data), certinfo)
|
||||
let data = self.cert.to_der().map_err(|_| Error::InvalidObject)?;
|
||||
write_certificate(&txn, slot, Some(&data), certinfo)
|
||||
}
|
||||
|
||||
/// Delete a certificate located at the given slot of the given YubiKey
|
||||
@@ -506,55 +168,27 @@ impl Certificate {
|
||||
return Err(Error::SizeError);
|
||||
}
|
||||
|
||||
let parsed_cert = match parse_x509_certificate(&cert) {
|
||||
Ok((_, cert)) => cert,
|
||||
_ => return Err(Error::InvalidObject),
|
||||
};
|
||||
|
||||
let serial = Serial::try_from(parsed_cert.tbs_certificate.serial.to_bytes_be().as_slice())
|
||||
.map_err(|_| Error::InvalidObject)?;
|
||||
let issuer = parsed_cert.tbs_certificate.issuer.to_string();
|
||||
let subject = parsed_cert.tbs_certificate.subject.to_string();
|
||||
let subject_pki = PublicKeyInfo::parse(&parsed_cert.tbs_certificate.subject_pki)?;
|
||||
|
||||
Ok(Certificate {
|
||||
serial,
|
||||
issuer,
|
||||
subject,
|
||||
subject_pki,
|
||||
data: cert,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the serial number of the certificate.
|
||||
pub fn serial(&self) -> &Serial {
|
||||
&self.serial
|
||||
x509_cert::Certificate::from_der(&cert)
|
||||
.map(|cert| Self { cert })
|
||||
.map_err(|_| Error::InvalidObject)
|
||||
}
|
||||
|
||||
/// Returns the Issuer field of the certificate.
|
||||
pub fn issuer(&self) -> &str {
|
||||
&self.issuer
|
||||
pub fn issuer(&self) -> String {
|
||||
self.cert.tbs_certificate.issuer.to_string()
|
||||
}
|
||||
|
||||
/// Returns the SubjectName field of the certificate.
|
||||
pub fn subject(&self) -> &str {
|
||||
&self.subject
|
||||
pub fn subject(&self) -> String {
|
||||
self.cert.tbs_certificate.subject.to_string()
|
||||
}
|
||||
|
||||
/// Returns the SubjectPublicKeyInfo field of the certificate.
|
||||
pub fn subject_pki(&self) -> &PublicKeyInfo {
|
||||
&self.subject_pki
|
||||
}
|
||||
|
||||
/// Extract the inner buffer
|
||||
pub fn into_buffer(self) -> Buffer {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Certificate {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.data.as_ref()
|
||||
pub fn subject_pki(&self) -> SubjectPublicKeyInfoRef<'_> {
|
||||
self.cert
|
||||
.tbs_certificate
|
||||
.subject_public_key_info
|
||||
.owned_to_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,97 +240,223 @@ pub(crate) fn write_certificate(
|
||||
txn.save_object(object_id, &buf[..offset])
|
||||
}
|
||||
|
||||
mod read_pki {
|
||||
use der_parser::{
|
||||
asn1_rs::Any,
|
||||
ber::BerObjectContent,
|
||||
der::{parse_der_integer, parse_der_sequence_defined_g, DerObject},
|
||||
error::BerError,
|
||||
pub mod yubikey_signer {
|
||||
//! Signer implementation for yubikey
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
piv::AlgorithmId,
|
||||
piv::{sign_data, SlotId},
|
||||
YubiKey,
|
||||
};
|
||||
use der::{
|
||||
asn1::{Any, OctetString},
|
||||
oid::db::rfc5912,
|
||||
Encode, Sequence,
|
||||
};
|
||||
use sha2::{Digest, Sha256, Sha384};
|
||||
use signature::Keypair;
|
||||
use std::{cell::RefCell, fmt, io::Write, marker::PhantomData};
|
||||
use x509_cert::spki::{
|
||||
self, AlgorithmIdentifierOwned, DynSignatureAlgorithmIdentifier, EncodePublicKey,
|
||||
SignatureBitStringEncoding, SubjectPublicKeyInfoRef,
|
||||
};
|
||||
use nom::{combinator, sequence::pair, IResult};
|
||||
use rsa::{BigUint, RsaPublicKey};
|
||||
|
||||
use super::{OID_NIST_P256, OID_NIST_P384};
|
||||
use crate::{piv::AlgorithmId, Error, Result};
|
||||
type SigResult<T> = core::result::Result<T, signature::Error>;
|
||||
|
||||
/// From [RFC 8017](https://tools.ietf.org/html/rfc8017#appendix-A.1.1):
|
||||
/// ```text
|
||||
/// RSAPublicKey ::= SEQUENCE {
|
||||
/// modulus INTEGER, -- n
|
||||
/// publicExponent INTEGER -- e
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn rsa_pubkey(encoded: &[u8]) -> Result<RsaPublicKey> {
|
||||
fn parse_rsa_pubkey(i: &[u8]) -> IResult<&[u8], (DerObject<'_>, DerObject<'_>), BerError> {
|
||||
parse_der_sequence_defined_g(|i, _| pair(parse_der_integer, parse_der_integer)(i))(i)
|
||||
}
|
||||
/// Key to be used to sign certificates
|
||||
pub trait KeyType {
|
||||
/// Error returned when working with signature
|
||||
type Error: Into<signature::Error> + fmt::Debug;
|
||||
/// The signature type returned by the signer
|
||||
type Signature: SignatureBitStringEncoding
|
||||
+ for<'s> TryFrom<&'s [u8], Error = Self::Error>
|
||||
+ fmt::Debug;
|
||||
/// The public key used to verify signature
|
||||
type VerifyingKey: EncodePublicKey
|
||||
+ DynSignatureAlgorithmIdentifier
|
||||
+ Clone
|
||||
+ From<Self::PublicKey>;
|
||||
/// Public key type used to load the SPKI formatted key
|
||||
type PublicKey: for<'a> TryFrom<SubjectPublicKeyInfoRef<'a>, Error = spki::Error>;
|
||||
|
||||
fn rsa_pubkey_parts(i: &[u8]) -> IResult<&[u8], (BigUint, BigUint), BerError> {
|
||||
combinator::map(parse_rsa_pubkey, |(modulus, public_exponent)| {
|
||||
let n = match modulus.content {
|
||||
BerObjectContent::Integer(s) => BigUint::from_bytes_be(s),
|
||||
_ => panic!("expected DER integer"),
|
||||
};
|
||||
let e = match public_exponent.content {
|
||||
BerObjectContent::Integer(s) => BigUint::from_bytes_be(s),
|
||||
_ => panic!("expected DER integer"),
|
||||
};
|
||||
/// The algorithm used when talking with the yubikey
|
||||
const ALGORITHM: AlgorithmId;
|
||||
|
||||
(n, e)
|
||||
})(i)
|
||||
}
|
||||
|
||||
let (n, e) = match rsa_pubkey_parts(encoded) {
|
||||
Ok((_, res)) => res,
|
||||
_ => return Err(Error::InvalidObject),
|
||||
};
|
||||
|
||||
RsaPublicKey::new(n, e).map_err(|_| Error::InvalidObject)
|
||||
/// Prepare buffer before submitting it for signature
|
||||
fn prepare(input: &[u8]) -> SigResult<Vec<u8>>;
|
||||
/// Read back the signature from the device
|
||||
fn read_signature(input: &[u8]) -> SigResult<Self::Signature>;
|
||||
}
|
||||
|
||||
/// From [RFC 5480](https://tools.ietf.org/html/rfc5480#section-2.1.1):
|
||||
/// ```text
|
||||
/// ECParameters ::= CHOICE {
|
||||
/// namedCurve OBJECT IDENTIFIER
|
||||
/// -- implicitCurve NULL
|
||||
/// -- specifiedCurve SpecifiedECDomain
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn ec_parameters(parameters: &Any<'_>) -> Result<AlgorithmId> {
|
||||
let curve_oid = parameters.as_oid().map_err(|_| Error::InvalidObject)?;
|
||||
impl KeyType for p256::NistP256 {
|
||||
const ALGORITHM: AlgorithmId = AlgorithmId::EccP256;
|
||||
type Error = ecdsa::Error;
|
||||
type Signature = p256::ecdsa::DerSignature;
|
||||
type VerifyingKey = p256::ecdsa::VerifyingKey;
|
||||
type PublicKey = p256::ecdsa::VerifyingKey;
|
||||
|
||||
match curve_oid.to_string().as_str() {
|
||||
OID_NIST_P256 => Ok(AlgorithmId::EccP256),
|
||||
OID_NIST_P384 => Ok(AlgorithmId::EccP384),
|
||||
_ => Err(Error::AlgorithmError),
|
||||
fn prepare(input: &[u8]) -> SigResult<Vec<u8>> {
|
||||
Ok(Sha256::digest(input).to_vec())
|
||||
}
|
||||
|
||||
fn read_signature(input: &[u8]) -> SigResult<Self::Signature> {
|
||||
Self::Signature::from_bytes(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyType for p384::NistP384 {
|
||||
const ALGORITHM: AlgorithmId = AlgorithmId::EccP384;
|
||||
type Error = ecdsa::Error;
|
||||
type Signature = p384::ecdsa::DerSignature;
|
||||
type VerifyingKey = p384::ecdsa::VerifyingKey;
|
||||
type PublicKey = p384::ecdsa::VerifyingKey;
|
||||
|
||||
fn prepare(input: &[u8]) -> SigResult<Vec<u8>> {
|
||||
Ok(Sha384::digest(input).to_vec())
|
||||
}
|
||||
|
||||
fn read_signature(input: &[u8]) -> SigResult<Self::Signature> {
|
||||
Self::Signature::from_bytes(input)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used to handle subtypes of RSA keys
|
||||
pub trait RsaLength {
|
||||
/// The length of the RSA key in bits
|
||||
const BIT_LENGTH: usize;
|
||||
/// The algorithm to use when talking with the Yubikey.
|
||||
const ALGORITHM: AlgorithmId;
|
||||
}
|
||||
|
||||
/// RSA 1024 bits key
|
||||
pub struct Rsa1024;
|
||||
|
||||
impl RsaLength for Rsa1024 {
|
||||
const BIT_LENGTH: usize = 1024;
|
||||
const ALGORITHM: AlgorithmId = AlgorithmId::Rsa1024;
|
||||
}
|
||||
|
||||
/// RSA 2048 bits key
|
||||
pub struct Rsa2048;
|
||||
|
||||
impl RsaLength for Rsa2048 {
|
||||
const BIT_LENGTH: usize = 2048;
|
||||
const ALGORITHM: AlgorithmId = AlgorithmId::Rsa2048;
|
||||
}
|
||||
|
||||
/// RSA keys used to sign certificates
|
||||
pub struct YubiRsa<N: RsaLength> {
|
||||
_len: PhantomData<N>,
|
||||
}
|
||||
|
||||
impl<N: RsaLength> KeyType for YubiRsa<N> {
|
||||
type Error = signature::Error;
|
||||
type Signature = rsa::pkcs1v15::Signature;
|
||||
type VerifyingKey = rsa::pkcs1v15::VerifyingKey<Sha256>;
|
||||
type PublicKey = rsa::RsaPublicKey;
|
||||
const ALGORITHM: AlgorithmId = N::ALGORITHM;
|
||||
|
||||
fn prepare(input: &[u8]) -> SigResult<Vec<u8>> {
|
||||
let hashed = Sha256::digest(input).to_vec();
|
||||
|
||||
OctetString::new(hashed)
|
||||
.map_err(|e| e.into())
|
||||
.and_then(Self::emsa_pkcs1_1_5)
|
||||
.map_err(signature::Error::from_source)
|
||||
}
|
||||
|
||||
fn read_signature(input: &[u8]) -> SigResult<Self::Signature> {
|
||||
Self::Signature::try_from(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: RsaLength> YubiRsa<N> {
|
||||
/// https://www.rfc-editor.org/rfc/rfc8017#section-9.2
|
||||
fn emsa_pkcs1_1_5(digest: OctetString) -> Result<Vec<u8>> {
|
||||
/// https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.4
|
||||
#[derive(Debug, Sequence)]
|
||||
struct DigestInfo {
|
||||
digest_algorithm: AlgorithmIdentifierOwned,
|
||||
digest: OctetString,
|
||||
}
|
||||
|
||||
let em_len = N::BIT_LENGTH / 8;
|
||||
|
||||
let null = Any::null();
|
||||
|
||||
let t = DigestInfo {
|
||||
digest_algorithm: AlgorithmIdentifierOwned {
|
||||
oid: rfc5912::ID_SHA_256,
|
||||
parameters: Some(null),
|
||||
},
|
||||
digest,
|
||||
};
|
||||
let t = t.to_der()?;
|
||||
|
||||
let ps = vec![0xff; em_len - t.len() - 3];
|
||||
assert!(ps.len() >= 8, "spec violation");
|
||||
|
||||
let mut out = Vec::with_capacity(em_len);
|
||||
out.write(&[0x00, 0x01]).map_err(|_| Error::MemoryError)?;
|
||||
out.write(&ps).map_err(|_| Error::MemoryError)?;
|
||||
out.write(&[0x00]).map_err(|_| Error::MemoryError)?;
|
||||
out.write(&t).map_err(|_| Error::MemoryError)?;
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
/// The entrypoint to sign data with the yubikey.
|
||||
pub struct Signer<'y, KT: KeyType> {
|
||||
yubikey: RefCell<&'y mut YubiKey>,
|
||||
key: SlotId,
|
||||
public_key: KT::VerifyingKey,
|
||||
}
|
||||
|
||||
impl<'y, KT: KeyType> Signer<'y, KT> {
|
||||
/// Create new Signer
|
||||
pub fn new(
|
||||
yubikey: &'y mut YubiKey,
|
||||
key: SlotId,
|
||||
subject_pki: SubjectPublicKeyInfoRef<'_>,
|
||||
) -> Result<Self> {
|
||||
let public_key = KT::PublicKey::try_from(subject_pki).map_err(|_| Error::ParseError)?;
|
||||
let public_key = public_key.into();
|
||||
|
||||
Ok(Self {
|
||||
yubikey: RefCell::new(yubikey),
|
||||
key,
|
||||
public_key,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'y, KT: KeyType> Keypair for Signer<'y, KT> {
|
||||
type VerifyingKey = KT::VerifyingKey;
|
||||
fn verifying_key(&self) -> <Self as Keypair>::VerifyingKey {
|
||||
self.public_key.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'y, KT: KeyType> DynSignatureAlgorithmIdentifier for Signer<'y, KT> {
|
||||
fn signature_algorithm_identifier(&self) -> spki::Result<AlgorithmIdentifierOwned> {
|
||||
self.verifying_key().signature_algorithm_identifier()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'y, KT: KeyType> signature::Signer<KT::Signature> for Signer<'y, KT> {
|
||||
fn try_sign(&self, msg: &[u8]) -> SigResult<KT::Signature> {
|
||||
let data = KT::prepare(msg)?;
|
||||
|
||||
let out = sign_data(
|
||||
&mut self.yubikey.borrow_mut(),
|
||||
&data,
|
||||
KT::ALGORITHM,
|
||||
self.key,
|
||||
)
|
||||
.map_err(signature::Error::from_source)?;
|
||||
let out = KT::read_signature(&out)?;
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod write_pki {
|
||||
use cookie_factory::{SerializeFn, WriteContext};
|
||||
use rsa::{traits::PublicKeyParts, BigUint, RsaPublicKey};
|
||||
use std::io::Write;
|
||||
use x509::der::write::{der_integer, der_sequence};
|
||||
|
||||
/// Encodes a usize as an ASN.1 integer using DER.
|
||||
fn der_integer_biguint<'a, W: Write + 'a>(num: &'a BigUint) -> impl SerializeFn<W> + 'a {
|
||||
move |w: WriteContext<W>| der_integer(&num.to_bytes_be())(w)
|
||||
}
|
||||
|
||||
/// From [RFC 8017](https://tools.ietf.org/html/rfc8017#appendix-A.1.1):
|
||||
/// ```text
|
||||
/// RSAPublicKey ::= SEQUENCE {
|
||||
/// modulus INTEGER, -- n
|
||||
/// publicExponent INTEGER -- e
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn rsa_pubkey<'a, W: Write + 'a>(
|
||||
pubkey: &'a RsaPublicKey,
|
||||
) -> impl SerializeFn<W> + 'a {
|
||||
der_sequence((
|
||||
der_integer_biguint(pubkey.n()),
|
||||
der_integer_biguint(pubkey.e()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,3 +179,9 @@ impl std::error::Error for Error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<x509_cert::der::Error> for Error {
|
||||
fn from(_err: x509_cert::der::Error) -> Error {
|
||||
Error::ParseError
|
||||
}
|
||||
}
|
||||
|
||||
+34
-23
@@ -44,7 +44,7 @@
|
||||
|
||||
use crate::{
|
||||
apdu::{Ins, StatusWords},
|
||||
certificate::{self, Certificate, PublicKeyInfo},
|
||||
certificate::{self, Certificate},
|
||||
consts::CB_OBJ_MAX,
|
||||
error::{Error, Result},
|
||||
policy::{PinPolicy, TouchPolicy},
|
||||
@@ -53,15 +53,16 @@ use crate::{
|
||||
yubikey::YubiKey,
|
||||
Buffer, ObjectId,
|
||||
};
|
||||
use elliptic_curve::sec1::EncodedPoint as EcPublicKey;
|
||||
use elliptic_curve::{sec1::EncodedPoint as EcPublicKey, PublicKey};
|
||||
use log::{debug, error, warn};
|
||||
use p256::NistP256;
|
||||
use p384::NistP384;
|
||||
use rsa::{BigUint, RsaPublicKey};
|
||||
use rsa::{pkcs8::EncodePublicKey, BigUint, RsaPublicKey};
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
use x509_cert::{der::Decode, spki::SubjectPublicKeyInfoOwned};
|
||||
|
||||
#[cfg(feature = "untested")]
|
||||
use {
|
||||
@@ -441,10 +442,11 @@ impl ManagementSlotId {
|
||||
}
|
||||
|
||||
/// Personal Identity Verification (PIV) key slots
|
||||
pub const SLOTS: [SlotId; 27] = [
|
||||
pub const SLOTS: [SlotId; 28] = [
|
||||
SlotId::Authentication,
|
||||
SlotId::Signature,
|
||||
SlotId::KeyManagement,
|
||||
SlotId::Attestation,
|
||||
SlotId::Retired(RetiredSlotId::R1),
|
||||
SlotId::Retired(RetiredSlotId::R2),
|
||||
SlotId::Retired(RetiredSlotId::R3),
|
||||
@@ -591,7 +593,7 @@ pub fn generate(
|
||||
algorithm: AlgorithmId,
|
||||
pin_policy: PinPolicy,
|
||||
touch_policy: TouchPolicy,
|
||||
) -> Result<PublicKeyInfo> {
|
||||
) -> Result<SubjectPublicKeyInfoOwned> {
|
||||
// Keygen messages
|
||||
// TODO(tarcieri): extract these into an I18N-handling type?
|
||||
const SZ_SETTING_ROCA: &str = "Enable_Unsafe_Keygen_ROCA";
|
||||
@@ -955,7 +957,7 @@ pub struct SlotMetadata {
|
||||
/// Imported or generated key
|
||||
pub origin: Option<Origin>,
|
||||
/// Pub key of the key
|
||||
pub public: Option<PublicKeyInfo>,
|
||||
pub public: Option<SubjectPublicKeyInfoOwned>,
|
||||
/// Whether PIN PUK and management key are default
|
||||
pub default: Option<bool>,
|
||||
/// Number of retries left
|
||||
@@ -1110,7 +1112,7 @@ fn read_public_key(
|
||||
algorithm: AlgorithmId,
|
||||
input: &[u8],
|
||||
skip_asn1_tag: bool,
|
||||
) -> Result<PublicKeyInfo> {
|
||||
) -> Result<SubjectPublicKeyInfoOwned> {
|
||||
// TODO(str4d): Response is wrapped in an ASN.1 TLV:
|
||||
//
|
||||
// 0x7f 0x49 -> Application | Constructed | 0x49
|
||||
@@ -1159,14 +1161,17 @@ fn read_public_key(
|
||||
}
|
||||
let exp = exp_tlv.value.to_vec();
|
||||
|
||||
Ok(PublicKeyInfo::Rsa {
|
||||
algorithm,
|
||||
pubkey: RsaPublicKey::new(
|
||||
BigUint::from_bytes_be(&modulus),
|
||||
BigUint::from_bytes_be(&exp),
|
||||
)
|
||||
.map_err(|_| Error::InvalidObject)?,
|
||||
})
|
||||
let pubkey = RsaPublicKey::new(
|
||||
BigUint::from_bytes_be(&modulus),
|
||||
BigUint::from_bytes_be(&exp),
|
||||
)
|
||||
.map_err(|_| Error::InvalidObject)?;
|
||||
Ok(SubjectPublicKeyInfoOwned::from_der(
|
||||
pubkey
|
||||
.to_public_key_der()
|
||||
.map_err(|_| Error::ParseError)?
|
||||
.as_bytes(),
|
||||
)?)
|
||||
}
|
||||
AlgorithmId::EccP256 | AlgorithmId::EccP384 => {
|
||||
// 2-byte ASN.1 tag, 1-byte length (because all supported EC pubkey lengths
|
||||
@@ -1194,16 +1199,22 @@ fn read_public_key(
|
||||
|
||||
let point = tlv.value.to_vec();
|
||||
|
||||
match algorithm {
|
||||
AlgorithmId::EccP256 => {
|
||||
EcPublicKey::<NistP256>::from_bytes(point).map(PublicKeyInfo::EcP256)
|
||||
}
|
||||
AlgorithmId::EccP384 => {
|
||||
EcPublicKey::<NistP384>::from_bytes(point).map(PublicKeyInfo::EcP384)
|
||||
}
|
||||
let pubkey = match algorithm {
|
||||
AlgorithmId::EccP256 => PublicKey::<NistP256>::try_from(
|
||||
EcPublicKey::<NistP256>::from_bytes(point).map_err(|_| Error::InvalidObject)?,
|
||||
)
|
||||
.map_err(|_| Error::InvalidObject)?
|
||||
.to_public_key_der(),
|
||||
AlgorithmId::EccP384 => PublicKey::<NistP384>::try_from(
|
||||
EcPublicKey::<NistP384>::from_bytes(point).map_err(|_| Error::InvalidObject)?,
|
||||
)
|
||||
.map_err(|_| Error::InvalidObject)?
|
||||
.to_public_key_der(),
|
||||
_ => return Err(Error::AlgorithmError),
|
||||
}
|
||||
.map_err(|_| Error::InvalidObject)
|
||||
.map_err(|_| Error::InvalidObject)?;
|
||||
|
||||
Ok(SubjectPublicKeyInfoOwned::from_der(pubkey.as_bytes())?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-71
@@ -6,14 +6,15 @@
|
||||
use log::trace;
|
||||
use once_cell::sync::Lazy;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use rsa::pkcs1v15;
|
||||
use rsa::{pkcs1v15, RsaPublicKey};
|
||||
use sha2::{Digest, Sha256};
|
||||
use signature::hazmat::PrehashVerifier;
|
||||
use std::{env, str::FromStr, sync::Mutex};
|
||||
use x509::RelativeDistinguishedName;
|
||||
use std::{env, str::FromStr, sync::Mutex, time::Duration};
|
||||
use x509_cert::{der::Encode, name::Name, serial_number::SerialNumber, time::Validity};
|
||||
use yubikey::{
|
||||
certificate,
|
||||
certificate::{Certificate, PublicKeyInfo},
|
||||
certificate::yubikey_signer,
|
||||
certificate::Certificate,
|
||||
piv::{self, AlgorithmId, Key, ManagementSlotId, RetiredSlotId, SlotId},
|
||||
Error, MgmKey, PinPolicy, Serial, TouchPolicy, YubiKey,
|
||||
};
|
||||
@@ -147,7 +148,7 @@ fn test_set_mgmkey() {
|
||||
// Certificate support
|
||||
//
|
||||
|
||||
fn generate_self_signed_cert(algorithm: AlgorithmId) -> Certificate {
|
||||
fn generate_self_signed_cert<KT: yubikey_signer::KeyType>() -> Certificate {
|
||||
let mut yubikey = YUBIKEY.lock().unwrap();
|
||||
|
||||
assert!(yubikey.verify_pin(b"123456").is_ok());
|
||||
@@ -159,25 +160,28 @@ fn generate_self_signed_cert(algorithm: AlgorithmId) -> Certificate {
|
||||
let generated = piv::generate(
|
||||
&mut yubikey,
|
||||
slot,
|
||||
algorithm,
|
||||
KT::ALGORITHM,
|
||||
PinPolicy::Default,
|
||||
TouchPolicy::Default,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut serial = [0u8; 20];
|
||||
// 0x80 0x00 ... (20bytes) is invalid because of high MSB (serial will keep the sign)
|
||||
// we'll limit ourselves to 19 bytes serial.
|
||||
let mut serial = [0u8; 19];
|
||||
OsRng.fill_bytes(&mut serial);
|
||||
let serial = SerialNumber::new(&serial[..]).expect("serial can't be more than 20 bytes long");
|
||||
let validity = Validity::from_now(Duration::new(500000, 0)).unwrap();
|
||||
|
||||
// Generate a self-signed certificate for the new key.
|
||||
let extensions: &[x509::Extension<'_, &[u64]>] = &[];
|
||||
let cert_result = Certificate::generate_self_signed(
|
||||
let cert_result = Certificate::generate_self_signed::<_, KT>(
|
||||
&mut yubikey,
|
||||
slot,
|
||||
serial,
|
||||
None,
|
||||
&[RelativeDistinguishedName::common_name("testSubject")],
|
||||
validity,
|
||||
Name::from_str("CN=testSubject").expect("parse name"),
|
||||
generated,
|
||||
extensions,
|
||||
|_builder| Ok(()),
|
||||
);
|
||||
|
||||
assert!(cert_result.is_ok());
|
||||
@@ -189,18 +193,16 @@ fn generate_self_signed_cert(algorithm: AlgorithmId) -> Certificate {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn generate_self_signed_rsa_cert() {
|
||||
let cert = generate_self_signed_cert(AlgorithmId::Rsa1024);
|
||||
let cert = generate_self_signed_cert::<yubikey_signer::YubiRsa<yubikey_signer::Rsa1024>>();
|
||||
|
||||
//
|
||||
// Verify that the certificate is signed correctly
|
||||
//
|
||||
|
||||
let pubkey = match cert.subject_pki() {
|
||||
PublicKeyInfo::Rsa { pubkey, .. } => pkcs1v15::VerifyingKey::<Sha256>::from(pubkey.clone()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let pubkey = RsaPublicKey::try_from(cert.subject_pki()).expect("valid rsa key");
|
||||
let pubkey = pkcs1v15::VerifyingKey::<Sha256>::new(pubkey);
|
||||
|
||||
let data = cert.as_ref();
|
||||
let data = cert.cert.to_der().expect("serialize certificate");
|
||||
let tbs_cert_len = u16::from_be_bytes(data[6..8].try_into().unwrap()) as usize;
|
||||
let msg = &data[4..8 + tbs_cert_len];
|
||||
let sig = pkcs1v15::Signature::try_from(&data[data.len() - 128..]).unwrap();
|
||||
@@ -212,24 +214,20 @@ fn generate_self_signed_rsa_cert() {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn generate_self_signed_ec_cert() {
|
||||
let cert = generate_self_signed_cert(AlgorithmId::EccP256);
|
||||
let cert = generate_self_signed_cert::<p256::NistP256>();
|
||||
|
||||
//
|
||||
// Verify that the certificate is signed correctly
|
||||
//
|
||||
|
||||
let pubkey = match cert.subject_pki() {
|
||||
PublicKeyInfo::EcP256(pubkey) => pubkey,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let vk = p256::ecdsa::VerifyingKey::try_from(cert.subject_pki()).expect("ecdsa key expected");
|
||||
|
||||
let data = cert.as_ref();
|
||||
let data = cert.cert.to_der().expect("serialize certificate");
|
||||
let tbs_cert_len = data[6] as usize;
|
||||
let sig_algo_len = data[7 + tbs_cert_len + 1] as usize;
|
||||
let sig_start = 7 + tbs_cert_len + 2 + sig_algo_len + 3;
|
||||
let msg = &data[4..7 + tbs_cert_len];
|
||||
let sig = p256::ecdsa::Signature::from_der(&data[sig_start..]).unwrap();
|
||||
let vk = p256::ecdsa::VerifyingKey::from_sec1_bytes(pubkey.as_bytes()).unwrap();
|
||||
|
||||
use p256::ecdsa::signature::Verifier;
|
||||
assert!(vk.verify(msg, &sig).is_ok());
|
||||
@@ -269,11 +267,11 @@ fn test_slot_id_display() {
|
||||
|
||||
assert_eq!(
|
||||
format!("{}", SlotId::Management(ManagementSlotId::Pin)),
|
||||
"PIN"
|
||||
"Pin"
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", SlotId::Management(ManagementSlotId::Puk)),
|
||||
"PUK"
|
||||
"Puk"
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", SlotId::Management(ManagementSlotId::Management)),
|
||||
@@ -310,50 +308,6 @@ fn test_read_metadata() {
|
||||
assert_eq!(metadata.public, Some(generated));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_serial_string_conversions() {
|
||||
//2^152+1
|
||||
let serial: [u8; 20] = [
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
];
|
||||
|
||||
let s = certificate::Serial::from(serial);
|
||||
assert_eq!(
|
||||
s.as_x509_int(),
|
||||
"5708990770823839524233143877797980545530986497"
|
||||
);
|
||||
assert_eq!(
|
||||
s.as_x509_hex(),
|
||||
"01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:01"
|
||||
);
|
||||
|
||||
let serial2: [u8; 20] = [
|
||||
0xA1, 0xF3, 0x02, 0x30, 0x76, 0x01, 0x32, 0x48, 0x09, 0x9C, 0x10, 0xAA, 0x3F, 0xA0, 0x54,
|
||||
0x0D, 0xC0, 0xB7, 0x65, 0x01,
|
||||
];
|
||||
|
||||
let s2 = certificate::Serial::from(serial2);
|
||||
assert_eq!(
|
||||
s2.as_x509_int(),
|
||||
"924566785900861696177829411010986812227211191553"
|
||||
);
|
||||
assert_eq!(
|
||||
s2.as_x509_hex(),
|
||||
"a1:f3:02:30:76:01:32:48:09:9c:10:aa:3f:a0:54:0d:c0:b7:65:01"
|
||||
);
|
||||
|
||||
let serial3: [u8; 20] = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x3F, 0xA0, 0x54,
|
||||
0x0D, 0xC0, 0xB7, 0x65, 0x01,
|
||||
];
|
||||
|
||||
let s3 = certificate::Serial::from(serial3);
|
||||
assert_eq!(s3.as_x509_int(), "3140531249369331492097");
|
||||
assert_eq!(s3.as_x509_hex(), "aa:3f:a0:54:0d:c0:b7:65:01");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_parse_cert_from_der() {
|
||||
|
||||
Reference in New Issue
Block a user