CTAP library move (#602)
* Moves all CTAP logic into its own library * workflows fix test * more coveralls workflow tests
This commit is contained in:
3
libraries/opensk/fuzz/.gitignore
vendored
Normal file
3
libraries/opensk/fuzz/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/artifacts/
|
||||
/corpus/
|
||||
/target/
|
||||
71
libraries/opensk/fuzz/Cargo.toml
Normal file
71
libraries/opensk/fuzz/Cargo.toml
Normal file
@@ -0,0 +1,71 @@
|
||||
[package]
|
||||
name = "opensk-fuzz"
|
||||
version = "0.0.0"
|
||||
authors = ["Automatically generated"]
|
||||
publish = false
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = { version = "0.3" }
|
||||
fuzz_helper = { path = "fuzz_helper" }
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
[workspace]
|
||||
members = ["."]
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap_command"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap_command.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap1"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap1.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap2_client_pin"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap2_client_pin.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap2_client_pin_structured"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap2_client_pin_structured.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap2_get_assertion"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap2_get_assertion.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap2_get_assertion_structured"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap2_get_assertion_structured.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap2_make_credential"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap2_make_credential.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_process_ctap2_make_credential_structured"
|
||||
path = "fuzz_targets/fuzz_target_process_ctap2_make_credential_structured.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_split_assemble"
|
||||
path = "fuzz_targets/fuzz_target_split_assemble.rs"
|
||||
test = false
|
||||
doc = false
|
||||
152
libraries/opensk/fuzz/ctap2_commands_parameters_corpus.json
Normal file
152
libraries/opensk/fuzz/ctap2_commands_parameters_corpus.json
Normal file
@@ -0,0 +1,152 @@
|
||||
[
|
||||
{
|
||||
"hex": "1903e8",
|
||||
"cbor": "unsigned(1000)",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "3829",
|
||||
"cbor": "negative(41)",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "c349010000000000000000",
|
||||
"cbor": "-18446744073709551617",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "f90000",
|
||||
"cbor": "primitive(0)",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "f90001",
|
||||
"cbor": "primitive(1) = 5.960464477539063e-8",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "fa7fc00000",
|
||||
"cbor": "primitive(2143289344) = NaN",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "f818",
|
||||
"cbor": "simple(24)",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "d74401020304",
|
||||
"cbor": "tag 23(h'01020304')",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "6449455446",
|
||||
"cbor": "IETF",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "62225c",
|
||||
"cbor": "\"\\",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "41a8",
|
||||
"cbor": "bytes(a8)",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "623a41",
|
||||
"cbor": "text(:A)",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "83019f0203ff820405",
|
||||
"cbor": "array [1, [2, 3], [4, 5]]",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "9f018202039f0405ffff",
|
||||
"cbor": "indefinite length array [1, [2, 3], [4, 5]]",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "5f44aabbccdd43eeff99ff",
|
||||
"cbor": "indefinite byte string (_ h'AABBCCDD', h'EEFF99')",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "7f657374726561646d696e67ff",
|
||||
"cbor": "indefinite byte string (_ \"strea\", \"ming\")",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "a26161016162820203",
|
||||
"cbor": "map {\"a\": 1, \"b\": [2, 3]}",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "bf6346756ef563416d7421ff",
|
||||
"cbor": "indefinite length map {\"Fun\": true, \"Amt\": -2}",
|
||||
"description": "cbor value"
|
||||
},
|
||||
{
|
||||
"hex": "a4015820cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd02a14269645770696E5F616273656E63652E6578616D706C652E636F6D03a262696458201D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D646e616d65644164616d0481a263616c672664747970656a7075626C69632D6B6579",
|
||||
"cbor": "{1: h'CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD', 2: {\"id\": \"pin_absence.example.com\"}, 3: {\"id\": h'1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D', \"name\": \"Adam\"}, 4: [{\"alg\": -7, \"type\": \"public-key\"}]}",
|
||||
"description": "make credential parameter 1"
|
||||
},
|
||||
{
|
||||
"hex": "a9015820687134968222ec17202e42505f8ed2b16ae22f16bb05b88c25db9e602645f14102a3626964781a6d616b655f6261645f74797065732e6578616d706c652e636f6d6469636f6e6f687474703a2f2f69636f6e2e706e67646e616d65676578616d706c6503a462696458201d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d6469636f6e6f687474703a2f2f69636f6e2e706e67646e616d65684a6f686e20446f656b646973706c61794e616d65624a440481a263616c672664747970656a7075626c69632d6b65790581a26269644064747970656a7075626c69632d6b657906a007a362726bf4627570f5627576f40850610c58506c864a708e26dd0ccf4be3d90901",
|
||||
"cbor": "{1: h'687134968222EC17202E42505F8ED2B16AE22F16BB05B88C25DB9E602645F141', 2: {\"id\": \"make_bad_types.example.com\", \"icon\": \"http://icon.png\", \"name\": \"example\"}, 3: {\"id\": h'1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D', \"icon\": \"http://icon.png\", \"name\": \"John Doe\", \"displayName\": \"JD\"}, 4: [{\"alg\": -7, \"type\": \"public-key\"}], 5: [{\"id\": h'', \"type\": \"public-key\"}], 6: {}, 7: {\"rk\": false, \"up\": true, \"uv\": false}, 8: h'610C58506C864A708E26DD0CCF4BE3D9', 9: 1}",
|
||||
"description": "make credential parameters 2"
|
||||
},
|
||||
{
|
||||
"hex": "a9015820cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd02a3626964781a6d616b655f6261645f74797065732e6578616d706c652e636f6d6469636f6e6f687474703a2f2f69636f6e2e706e67646e616d65646A6F686E03a462696458201d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d6469636f6e6f687474703a2f2f69636f6e2e706e67646e616d65684a6f686e20446f656b646973706c61794e616d65624a440481a263616c672664747970656a7075626c69632d6b65790581a26269644064747970656a7075626c69632d6b657906a007a362726bf4627570f5627576f40850610c58506c864a708e26dd0ccf4be3d90901",
|
||||
"cbor": "{1: h'CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD', 2: {\"id\": \"make_bad_types.example.com\", \"icon\": \"http://icon.png\", \"name\": \"john\"}, 3: {\"id\": h'1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D', \"icon\": \"http://icon.png\", \"name\": \"John Doe\", \"displayName\": \"JD\"}, 4: [{\"alg\": -7, \"type\": \"public-key\"}], 5: [{\"id\": h'', \"type\": \"public-key\"}], 6: {}, 7: {\"rk\": false, \"up\": true, \"uv\": false}, 8: h'610C58506C864A708E26DD0CCF4BE3D9', 9: 1}",
|
||||
"description": "make credential parameters 3"
|
||||
},
|
||||
{
|
||||
"hex": "a5015820687134968222ec17202e42505f8ed2b16ae22f16bb05b88c25db9e602645f14102a26269646b6578616d706c652e636f6d646e616d656441636d6503a462696458203082019330820138a0030201023082019330820138a0030201023082019330826469636f6e782b68747470733a2f2f706963732e6578616d706c652e636f6d2f30302f702f61426a6a6a707150622e706e67646e616d65766a6f686e70736d697468406578616d706c652e636f6d6b646973706c61794e616d656d4a6f686e20502e20536d6974680482a263616c672664747970656a7075626C69632D6B6579a263616c6739010064747970656a7075626C69632D6B657907a162726bf5",
|
||||
"cbor": "{1: h'687134968222EC17202E42505F8ED2B16AE22F16BB05B88C25DB9E602645F141', 2: {\"id\": \"example.com\", \"name\": \"Acme\"}, 3: {\"id\": h'3082019330820138A0030201023082019330820138A003020102308201933082', \"icon\": \"https://pics.example.com/00/p/aBjjjpqPb.png\", \"name\": \"johnpsmith@example.com\", \"displayName\": \"John P. Smith\"}, 4: [{\"alg\": -7, \"type\": \"public-key\"}, {\"alg\": -257, \"type\": \"public-key\"}], 7: {\"rk\": true}}",
|
||||
"description": "make credential parameters 4 (ex 4)"
|
||||
},
|
||||
{
|
||||
"hex": "a301667061636b65640258f49d04bd8a43be42e45b38aee975ed4ff0b525e745051ac08014260bc12c86e7dd4100000000e00f21f9fc624cf200000000000000000070a148e03e8a315920691cead2a56117675a35857539dc16b51cc12a3acb525baeb124377f38026c29bf42f5b840285c1cf4b81783f3279f224b52dbff40523df87cc2a391a3ab888356002a5c7478385c9cc74fd0aea2a721247fb9023b3e4f6b080c59ebf62f2faa8345693dcb481932a50102032620012158202e3deacb152877fccbdc3bb03694178ba1c48fdd3943d49701c30a65144405202258204cdb1d0b76685e2652dfec4b5558e7e6dbf093dac0139919f9e14de98d0825cd03a263616c67266373696758453043022034870247c8292052f01ed3be4eccd22bb0ebb0344affce83733e2ac978f0d48b021f7f955405cb09b60f005c1c243f492865e2ca70871aeb35c7791365430ad4bd",
|
||||
"cbor": "{1: \"packed\", 2: h'9D04BD8A43BE42E45B38AEE975ED4FF0B525E745051AC08014260BC12C86E7DD4100000000E00F21F9FC624CF200000000000000000070A148E03E8A315920691CEAD2A56117675A35857539DC16B51CC12A3ACB525BAEB124377F38026C29BF42F5B840285C1CF4B81783F3279F224B52DBFF40523DF87CC2A391A3AB888356002A5C7478385C9CC74FD0AEA2A721247FB9023B3E4F6B080C59EBF62F2FAA8345693DCB481932A50102032620012158202E3DEACB152877FCCBDC3BB03694178BA1C48FDD3943D49701C30A65144405202258204CDB1D0B76685E2652DFEC4B5558E7E6DBF093DAC0139919F9E14DE98D0825CD', 3: {\"alg\": -7, \"sig\": h'3043022034870247C8292052F01ED3BE4ECCD22BB0EBB0344AFFCE83733E2AC978F0D48B021F7F955405CB09B60F005C1C243F492865E2CA70871AEB35C7791365430AD4BD'}}",
|
||||
"description": "get assertion parameters 1"
|
||||
},
|
||||
{
|
||||
"hex": "a70178196765745f6261645f74797065732e6578616d706c652e636f6d025820cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd0381a262696458701c0746a765e28acf5305ed91025263648e4b95fe94b19ecc63fa01e2a5b83a933755ca8d7e4c460c6cca9be1bba428c8b3079920e4f5bf4abd327abeb0bc731fedd34f7fe15ad2e45290945122d38f9b1462618a186abd66209aebb8886fad71ae1e83429b628b096b7f2db0c157c00e64747970656a7075626c69632d6b657904a005a2627570f4627576f40650610c58506c864a708e26dd0ccf4be3d90701",
|
||||
"cbor": "{1: \"get_bad_types.example.com\", 2: h'CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD', 3: [{\"id\": h'1C0746A765E28ACF5305ED91025263648E4B95FE94B19ECC63FA01E2A5B83A933755CA8D7E4C460C6CCA9BE1BBA428C8B3079920E4F5BF4ABD327ABEB0BC731FEDD34F7FE15AD2E45290945122D38F9B1462618A186ABD66209AEBB8886FAD71AE1E83429B628B096B7F2DB0C157C00E', \"type\": \"public-key\"}], 4: {}, 5: {\"up\": false, \"uv\": false}, 6: h'610C58506C864A708E26DD0CCF4BE3D9', 7: 1}",
|
||||
"description": "get assertion parameters 2"
|
||||
},
|
||||
{
|
||||
"hex": "a70178196765745f6261645f74797065732e6578616d706c652e636f6d025820cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd0381a262696458701c0746a765e28acf5305ed91025263648e4b95fe94b19ecc63fa01e2a5b83a933755ca8d7e4c460c6cca9be1bba428c8b3079920e4f5bf4abd327abeb0bc731fedd34f7fe15ad2e45290945122d38f9b1462618a186abd66209aebb8886fad71ae1e83429b628b096b7f2db0c157c00e64747970656a7075626c69632d6b657904a00650610c58506c864a708e26dd0ccf4be3d90701",
|
||||
"cbor": "{1: \"get_bad_types.example.com\", 2: h'CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD', 3: [{\"id\": h'1C0746A765E28ACF5305ED91025263648E4B95FE94B19ECC63FA01E2A5B83A933755CA8D7E4C460C6CCA9BE1BBA428C8B3079920E4F5BF4ABD327ABEB0BC731FEDD34F7FE15AD2E45290945122D38F9B1462618A186ABD66209AEBB8886FAD71AE1E83429B628B096B7F2DB0C157C00E', \"type\": \"public-key\"}], 4: {},6: h'610C58506C864A708E26DD0CCF4BE3D9', 7: 1}",
|
||||
"description": "get assertion parameters 3 (no key 5)"
|
||||
},
|
||||
{
|
||||
"hex": "a4016b6578616d706c652e636f6d025820687134968222ec17202e42505f8ed2b1687134968222ec17202e42505f8ed2b10382a26269645840f22006de4f905af68a43942f024f2a5ece603d9c6d4b3df8be08ed01fc442646d034858ac75bed3fd580bf9808d94fcbee82b9b2ef6677af0adcc35852ea6b9e64747970656a7075626C69632D6B6579a26269645832030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030364747970656a7075626C69632D6B657905a1627576f5",
|
||||
"cbor": "{1: \"example.com\", 2: h'687134968222EC17202E42505F8ED2B1687134968222EC17202E42505F8ED2B1', 3: [{\"id\": h'F22006DE4F905AF68A43942F024F2A5ECE603D9C6D4B3DF8BE08ED01FC442646D034858AC75BED3FD580BF9808D94FCBEE82B9B2EF6677AF0ADCC35852EA6B9E', \"type\": \"public-key\"}, {\"id\": h'0303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303', \"type\": \"public-key\"}], 5: {\"uv\": true}}",
|
||||
"description": "get assertion parameters 4 (ex 5)"
|
||||
},
|
||||
{
|
||||
"hex": "a201010202",
|
||||
"cbor": "{1: 1, 2: 2}",
|
||||
"description": "client pin parameters 1 (only key 1,2)"
|
||||
},
|
||||
{
|
||||
"hex": "a50101020303a501020338182001215820b20717fbc7c82517f511027d9e80888abd33a1837ce835a50ceffd4dea14337b2258209d132823edd852dcc21e4923168df96fe69ea591e1c2d13e98e4920673ec31b004400540",
|
||||
"cbor": "{1: 1, 2: 3, 3: {1: 2, 3: -25, -1: 1, -2: h'B20717FBC7C82517F511027D9E80888ABD33A1837CE835A50CEFFD4DEA14337B', -3: h'9D132823EDD852DCC21E4923168DF96FE69EA591E1C2D13E98E4920673EC31B0'}, 4: h'', 5: h''}",
|
||||
"description": "client pin parameters 2"
|
||||
},
|
||||
{
|
||||
"hex": "a50101020303a50102033818200121582060a086e3e9d1d95618826e706000a66b0809fadd29fbc50bb430d1fd21512f89225820c7d8411433be1e2728a397c66cca8d8b36b738cda54ee027d5efaf72c0db050a04504518a1ba83801245c6f8cad90952cda5055840a9eed54033b9f8fad7f76c69c8469f69c2e623ccb7819a31520b4da7756fc9bd1d4d4fc8d82df3284e9b3f600f03e994c6492a75fc2ed660a33ad343917aa7e2",
|
||||
"cbor": "{1: 1, 2: 3, 3: {1: 2, 3: -25, -1: 1, -2: h'60A086E3E9D1D95618826E706000A66B0809FADD29FBC50BB430D1FD21512F89', -3: h'C7D8411433BE1E2728A397C66CCA8D8B36B738CDA54EE027D5EFAF72C0DB050A'}, 4: h'4518A1BA83801245C6F8CAD90952CDA5', 5: h'A9EED54033B9F8FAD7F76C69C8469F69C2E623CCB7819A31520B4DA7756FC9BD1D4D4FC8D82DF3284E9B3F600F03E994C6492A75FC2ED660A33AD343917AA7E2'}",
|
||||
"description": "client pin parameters 3"
|
||||
},
|
||||
{
|
||||
"hex": "a40101020503a50102033818200121582060a086e3e9d1d95618826e706000a66b0809fadd29fbc50bb430d1fd21512f89225820c7d8411433be1e2728a397c66cca8d8b36b738cda54ee027d5efaf72c0db050a06509cac212d435c7f03d0ffa29caedf0e35",
|
||||
"cbor": "{1: 1, 2: 5, 3: {1: 2, 3: -25, -1: 1, -2: h'60A086E3E9D1D95618826E706000A66B0809FADD29FBC50BB430D1FD21512F89', -3: h'C7D8411433BE1E2728A397C66CCA8D8B36B738CDA54EE027D5EFAF72C0DB050A'}, 6: h'9CAC212D435C7F03D0FFA29CAEDF0E35'}",
|
||||
"description": "client pin parameters 4"
|
||||
}
|
||||
]
|
||||
14
libraries/opensk/fuzz/fuzz_helper/Cargo.toml
Normal file
14
libraries/opensk/fuzz/fuzz_helper/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "fuzz_helper"
|
||||
version = "0.1.0"
|
||||
authors = ["Mingxiao Guo <mingxguo@google.com>"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
arrayref = "0.3.6"
|
||||
opensk = { path = "../..", features = ["fuzz"] }
|
||||
crypto = { path = "../../../crypto", features = ['std'] }
|
||||
rng256 = { path = "../../../rng256", features = ['std'] }
|
||||
sk-cbor = { path = "../../../cbor" }
|
||||
arbitrary = { version = "0.4.7", features = ["derive"] }
|
||||
276
libraries/opensk/fuzz/fuzz_helper/src/lib.rs
Normal file
276
libraries/opensk/fuzz/fuzz_helper/src/lib.rs
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use arbitrary::{Arbitrary, Unstructured};
|
||||
use arrayref::array_ref;
|
||||
use core::convert::TryFrom;
|
||||
use opensk::api::customization::is_valid;
|
||||
use opensk::ctap::command::{
|
||||
AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters,
|
||||
AuthenticatorMakeCredentialParameters, Command,
|
||||
};
|
||||
use opensk::ctap::data_formats::EnterpriseAttestationMode;
|
||||
use opensk::ctap::hid::{
|
||||
ChannelID, CtapHidCommand, HidPacket, HidPacketIterator, Message, MessageAssembler,
|
||||
};
|
||||
use opensk::ctap::{cbor_read, Channel, CtapState};
|
||||
use opensk::env::test::customization::TestCustomization;
|
||||
use opensk::env::test::TestEnv;
|
||||
use opensk::{test_helpers, Ctap, Transport};
|
||||
|
||||
const CHANNEL_BROADCAST: ChannelID = [0xFF, 0xFF, 0xFF, 0xFF];
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum InputType {
|
||||
CborMakeCredentialParameter,
|
||||
CborGetAssertionParameter,
|
||||
CborClientPinParameter,
|
||||
Ctap1,
|
||||
}
|
||||
|
||||
pub enum FuzzError {
|
||||
ArbitraryError(arbitrary::Error),
|
||||
InvalidCustomization,
|
||||
}
|
||||
|
||||
pub type FuzzResult<T> = Result<T, FuzzError>;
|
||||
|
||||
impl From<arbitrary::Error> for FuzzError {
|
||||
fn from(err: arbitrary::Error) -> Self {
|
||||
Self::ArbitraryError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a byte slice into Message
|
||||
fn raw_to_message(data: &[u8]) -> Message {
|
||||
if data.len() <= 4 {
|
||||
let mut cid = [0; 4];
|
||||
cid[..data.len()].copy_from_slice(data);
|
||||
Message {
|
||||
cid,
|
||||
// Arbitrary command.
|
||||
cmd: CtapHidCommand::Cbor,
|
||||
payload: vec![],
|
||||
}
|
||||
} else {
|
||||
Message {
|
||||
cid: array_ref!(data, 0, 4).clone(),
|
||||
cmd: CtapHidCommand::from(data[4]),
|
||||
payload: data[5..].to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an initialized ctap state, hid and the allocated cid
|
||||
// after processing the init command.
|
||||
fn initialize(ctap: &mut Ctap<TestEnv>) -> ChannelID {
|
||||
let nonce = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
|
||||
let message = Message {
|
||||
cid: CHANNEL_BROADCAST,
|
||||
cmd: CtapHidCommand::Init,
|
||||
payload: nonce,
|
||||
};
|
||||
let mut assembler_reply = MessageAssembler::default();
|
||||
let mut result_cid: ChannelID = Default::default();
|
||||
for pkt_request in HidPacketIterator::new(message).unwrap() {
|
||||
for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid) {
|
||||
if let Ok(Some(result)) = assembler_reply.parse_packet(ctap.env(), &pkt_reply) {
|
||||
result_cid.copy_from_slice(&result.payload[8..12]);
|
||||
}
|
||||
}
|
||||
}
|
||||
result_cid
|
||||
}
|
||||
|
||||
// Checks whether the given data can be interpreted as the given type.
|
||||
fn is_type(data: &[u8], input_type: InputType) -> bool {
|
||||
if input_type == InputType::Ctap1 {
|
||||
return true;
|
||||
}
|
||||
match cbor_read(data) {
|
||||
Err(_) => false,
|
||||
Ok(decoded_cbor) => match input_type {
|
||||
InputType::CborMakeCredentialParameter => {
|
||||
AuthenticatorMakeCredentialParameters::try_from(decoded_cbor).is_ok()
|
||||
}
|
||||
InputType::CborGetAssertionParameter => {
|
||||
AuthenticatorGetAssertionParameters::try_from(decoded_cbor).is_ok()
|
||||
}
|
||||
InputType::CborClientPinParameter => {
|
||||
AuthenticatorClientPinParameters::try_from(decoded_cbor).is_ok()
|
||||
}
|
||||
_ => true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Interprets the raw data as a complete message (with channel id, command type and payload) and
|
||||
// invokes message splitting, packet processing at CTAP HID level and response assembling.
|
||||
fn process_message(data: &[u8], ctap: &mut Ctap<TestEnv>) {
|
||||
let message = raw_to_message(data);
|
||||
if let Some(hid_packet_iterator) = HidPacketIterator::new(message) {
|
||||
let mut assembler_reply = MessageAssembler::default();
|
||||
for pkt_request in hid_packet_iterator {
|
||||
for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid) {
|
||||
// Only checks for assembling crashes, not for semantics.
|
||||
let _ = assembler_reply.parse_packet(ctap.env(), &pkt_reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interprets the raw data as any ctap command (including the command byte) and
|
||||
// invokes message splitting, packet processing at CTAP HID level and response assembling
|
||||
// using an initialized and allocated channel.
|
||||
pub fn process_ctap_any_type(data: &[u8]) -> arbitrary::Result<()> {
|
||||
let mut unstructured = Unstructured::new(data);
|
||||
|
||||
let mut env = TestEnv::default();
|
||||
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
|
||||
|
||||
let data = unstructured.take_rest();
|
||||
// Initialize ctap state and hid and get the allocated cid.
|
||||
let mut ctap = Ctap::new(env);
|
||||
let cid = initialize(&mut ctap);
|
||||
// Wrap input as message with the allocated cid.
|
||||
let mut command = cid.to_vec();
|
||||
command.extend(data);
|
||||
process_message(&command, &mut ctap);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_customization(
|
||||
unstructured: &mut Unstructured,
|
||||
customization: &mut TestCustomization,
|
||||
) -> FuzzResult<()> {
|
||||
customization.setup_enterprise_attestation(
|
||||
Option::<EnterpriseAttestationMode>::arbitrary(unstructured)?,
|
||||
// TODO: Generate arbitrary rp_id_list (but with some dummies because content doesn't
|
||||
// matter), and use the rp ids in commands.
|
||||
None,
|
||||
);
|
||||
if !is_valid(customization) {
|
||||
return Err(FuzzError::InvalidCustomization);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_state(
|
||||
unstructured: &mut Unstructured,
|
||||
state: &mut CtapState<TestEnv>,
|
||||
env: &mut TestEnv,
|
||||
) -> FuzzResult<()> {
|
||||
if bool::arbitrary(unstructured)? {
|
||||
test_helpers::enable_enterprise_attestation(state, env).ok();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Interprets the raw data as of the given input type and
|
||||
// invokes message splitting, packet processing at CTAP HID level and response assembling
|
||||
// using an initialized and allocated channel.
|
||||
pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) -> arbitrary::Result<()> {
|
||||
let mut unstructured = Unstructured::new(data);
|
||||
|
||||
let mut env = TestEnv::default();
|
||||
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
|
||||
|
||||
let data = unstructured.take_rest();
|
||||
if !is_type(data, input_type) {
|
||||
return Ok(());
|
||||
}
|
||||
// Initialize ctap state and hid and get the allocated cid.
|
||||
let mut ctap = Ctap::new(env);
|
||||
let cid = initialize(&mut ctap);
|
||||
// Wrap input as message with allocated cid and command type.
|
||||
let mut command = cid.to_vec();
|
||||
match input_type {
|
||||
InputType::CborMakeCredentialParameter => {
|
||||
command.extend(&[0x10, 0x01]);
|
||||
}
|
||||
InputType::CborGetAssertionParameter => {
|
||||
command.extend(&[0x10, 0x02]);
|
||||
}
|
||||
InputType::CborClientPinParameter => {
|
||||
command.extend(&[0x10, 0x06]);
|
||||
}
|
||||
InputType::Ctap1 => {
|
||||
command.extend(&[0x03]);
|
||||
}
|
||||
}
|
||||
command.extend(data);
|
||||
process_message(&command, &mut ctap);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> FuzzResult<()> {
|
||||
let unstructured = &mut Unstructured::new(data);
|
||||
|
||||
let mut env = TestEnv::default();
|
||||
env.rng().seed_from_u64(u64::arbitrary(unstructured)?);
|
||||
setup_customization(unstructured, env.customization_mut())?;
|
||||
|
||||
let mut state = CtapState::new(&mut env);
|
||||
setup_state(unstructured, &mut state, &mut env)?;
|
||||
|
||||
let command = match input_type {
|
||||
InputType::CborMakeCredentialParameter => Command::AuthenticatorMakeCredential(
|
||||
AuthenticatorMakeCredentialParameters::arbitrary(unstructured)?,
|
||||
),
|
||||
InputType::CborGetAssertionParameter => Command::AuthenticatorGetAssertion(
|
||||
AuthenticatorGetAssertionParameters::arbitrary(unstructured)?,
|
||||
),
|
||||
InputType::CborClientPinParameter => Command::AuthenticatorClientPin(
|
||||
AuthenticatorClientPinParameters::arbitrary(unstructured)?,
|
||||
),
|
||||
InputType::Ctap1 => {
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
|
||||
state
|
||||
.process_parsed_command(
|
||||
&mut env,
|
||||
command,
|
||||
Channel::MainHid(ChannelID::arbitrary(unstructured)?),
|
||||
)
|
||||
.ok();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Splits the given data as HID packets and reassembles it, verifying that the original input message is reconstructed.
|
||||
pub fn split_assemble_hid_packets(data: &[u8]) -> arbitrary::Result<()> {
|
||||
let mut unstructured = Unstructured::new(data);
|
||||
|
||||
let mut env = TestEnv::default();
|
||||
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
|
||||
|
||||
let data = unstructured.take_rest();
|
||||
let message = raw_to_message(data);
|
||||
if let Some(hid_packet_iterator) = HidPacketIterator::new(message.clone()) {
|
||||
let mut assembler = MessageAssembler::default();
|
||||
let packets: Vec<HidPacket> = hid_packet_iterator.collect();
|
||||
if let Some((last_packet, first_packets)) = packets.split_last() {
|
||||
for packet in first_packets {
|
||||
assert_eq!(assembler.parse_packet(&mut env, packet), Ok(None));
|
||||
}
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, last_packet),
|
||||
Ok(Some(message))
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::{process_ctap_specific_type, InputType};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzz inputs as CTAP1 U2F raw messages.
|
||||
// For a more generic fuzz target including all CTAP commands, you can use
|
||||
// fuzz_target_process_ctap_command.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_specific_type(data, InputType::Ctap1).ok();
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::{process_ctap_specific_type, InputType};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzz inputs as CTAP2 client pin command parameters encoded in cbor.
|
||||
// For a more generic fuzz target including all CTAP commands, you can use
|
||||
// fuzz_target_process_ctap_command.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_specific_type(data, InputType::CborClientPinParameter).ok();
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::{process_ctap_structured, InputType};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzz inputs as CTAP2 client pin command parameters.
|
||||
// The inputs will used to construct arbitrary client pin parameters.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_structured(data, InputType::CborClientPinParameter).ok();
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::{process_ctap_specific_type, InputType};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzz inputs as CTAP2 get assertion command parameters encoded in cbor.
|
||||
// For a more generic fuzz target including all CTAP commands, you can use
|
||||
// fuzz_target_process_ctap_command.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_specific_type(data, InputType::CborGetAssertionParameter).ok();
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::{process_ctap_structured, InputType};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzz inputs as CTAP2 get assertion command parameters.
|
||||
// The inputs will used to construct arbitrary get assertion parameters.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_structured(data, InputType::CborGetAssertionParameter).ok();
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::{process_ctap_specific_type, InputType};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzz inputs as CTAP2 make credential command parameters encoded in cbor.
|
||||
// For a more generic fuzz target including all CTAP commands, you can use
|
||||
// fuzz_target_process_ctap_command.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_specific_type(data, InputType::CborMakeCredentialParameter).ok();
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::{process_ctap_structured, InputType};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzz inputs as CTAP2 make credential command parameters.
|
||||
// The inputs will used to construct arbitrary make credential parameters.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_structured(data, InputType::CborMakeCredentialParameter).ok();
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::process_ctap_any_type;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Generically fuzz inputs as CTAP commands.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
process_ctap_any_type(data).ok();
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
#![no_main]
|
||||
|
||||
use fuzz_helper::split_assemble_hid_packets;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
// Fuzzing HID packets splitting and assembling functions.
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
split_assemble_hid_packets(data).ok();
|
||||
});
|
||||
60
libraries/opensk/fuzz/make_corpus.py
Normal file
60
libraries/opensk/fuzz/make_corpus.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""Creates a directory containing seed inputs from a json file having
|
||||
the following structure:
|
||||
[
|
||||
{
|
||||
"hex": "a901a1182a182a02a3626964781a6d616b655f6261645f7...",
|
||||
"cbor": "{1: h'42', 2: {\"id\": \"make.example.com\", ...",
|
||||
"description": "make credential parameters"
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
Usage:
|
||||
- pass the resulting corpus directory path as the first argument
|
||||
- pass the json file path to make the corpus from as the second argument
|
||||
Example:
|
||||
python make_corpus.py ./corpus ./corpus_file.json
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os.path
|
||||
|
||||
|
||||
# Creates a corpus directory to the given path from the given json file.
|
||||
def make_corpus(corpus_dir, corpus_json):
|
||||
if not os.path.exists(corpus_dir):
|
||||
os.makedirs(corpus_dir)
|
||||
elif not os.path.isdir(corpus_dir):
|
||||
raise NotADirectoryError
|
||||
|
||||
if os.path.isfile(corpus_json) and \
|
||||
os.path.splitext(corpus_json)[-1] == ".json":
|
||||
with open(corpus_json, encoding="utf-8") as corpus_file:
|
||||
corpus = json.load(corpus_file)
|
||||
else:
|
||||
raise TypeError
|
||||
|
||||
for i, seed_file in enumerate(corpus):
|
||||
seed_file_name = "seed_file_" + str(i)
|
||||
raw_hex = seed_file["hex"].decode("hex")
|
||||
with open(os.path.join(corpus_dir, seed_file_name), "wb") as f:
|
||||
f.write(raw_hex)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"corpus_directory", help="the resulting corpus directory path")
|
||||
parser.add_argument(
|
||||
"corpus_json", help="the json file path to make the corpus from")
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
make_corpus(args.corpus_directory, args.corpus_json)
|
||||
except NotADirectoryError:
|
||||
print(args.corpus_directory, " is not a directory.\n")
|
||||
except TypeError:
|
||||
print(args.corpus_json, " must be a json file.\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user