diff --git a/src/test.rs b/src/test.rs index 2eeebdd0e..e2a4216b8 100644 --- a/src/test.rs +++ b/src/test.rs @@ -193,8 +193,15 @@ impl TestCase { /// even number of hex digits, or as a double-quoted UTF-8 string. The /// empty (zero-length) value is represented as "". pub fn consume_bytes(&mut self, key: &str) -> Vec { - let s = self.consume_string(key); - if s.starts_with('\"') { + self.consume_optional_bytes(key) + .unwrap_or_else(|| panic!("No attribute named \"{}\"", key)) + } + + /// Like `consume_bytes()` except it returns `None` if the test case + /// doesn't have the attribute. + pub fn consume_optional_bytes(&mut self, key: &str) -> Option> { + let s = self.consume_optional_string(key)?; + let result = if s.starts_with('\"') { // The value is a quoted UTF-8 string. let mut bytes = Vec::with_capacity(s.as_bytes().len() - 2); @@ -243,7 +250,8 @@ impl TestCase { panic!("{} in {}", err_str, s); } } - } + }; + Some(result) } /// Returns the value of an attribute that is an integer, in decimal diff --git a/tests/ed25519_from_pkcs8_tests.txt b/tests/ed25519_from_pkcs8_tests.txt index 46e9ab0cc..eb3d5558a 100644 --- a/tests/ed25519_from_pkcs8_tests.txt +++ b/tests/ed25519_from_pkcs8_tests.txt @@ -1,53 +1,87 @@ +# v1. An Ed25519 private key. (This is from BoringSSL's tests.) +Input = 302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 +Result-Checked = VersionNotSupported +Result-Maybe-Unchecked = OK +Public = d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a + +# v1. The same as the above, but with an invalid NULL parameter. (This is from BoringSSL's tests.) +Input = 3030020100300706032b65700500042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 +Result-Checked = WrongAlgorithm +Result-Maybe-Unchecked = WrongAlgorithm + +# v1. Sample private key from draft-ietf-curdle-pkix-04. +Input = 302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842 +Result-Checked = VersionNotSupported +Result-Maybe-Unchecked = OK +Public = 19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1 + +# v1. valid except it includes publicKey. +Input = 3053020100300506032b657004220420a22efdb713f0e1600d2a5ce948e321ca3a18137c47f15091a12c7126c1749a00a1230321001aeb8e3ee5ba5afd91113466d19f4ea77fa0feffbd8c5adcb499927f12535f77 +Result-Checked = VersionNotSupported +Result-Maybe-Unchecked = InvalidEncoding + # v2. The private key ends with a zero byte. Input = 3053020101300506032b657004220420a22efdb713f0e1600d2a5ce948e321ca3a18137c47f15091a12c7126c1749a00a1230321001aeb8e3ee5ba5afd91113466d19f4ea77fa0feffbd8c5adcb499927f12535f77 -Result = OK +Result-Checked = OK +Result-Maybe-Unchecked = OK Public = 1aeb8e3ee5ba5afd91113466d19f4ea77fa0feffbd8c5adcb499927f12535f77 # v2. The private key's last byte, zero, is omitted. Input = 3052020101300506032b65700421041fa22efdb713f0e1600d2a5ce948e321ca3a18137c47f15091a12c7126c1749aa1230321001aeb8e3ee5ba5afd91113466d19f4ea77fa0feffbd8c5adcb499927f12535f77 -Result = InvalidEncoding +Result-Checked = InvalidEncoding +Result-Maybe-Unchecked = InvalidEncoding # v2. The private key starts with a zero byte. Input = 3053020101300506032b65700422042000b1a7c20b2b4ed9c78f3686db82f854734cdc95be51def304d98e0cd30bf490a12303210063457cd4dfdd0e98a53796265831d46ac6a5a685f2a54c9697a38b2c800d60ba -Result = OK +Result-Checked = OK +Result-Maybe-Unchecked = OK Public = 63457cd4dfdd0e98a53796265831d46ac6a5a685f2a54c9697a38b2c800d60ba # v2. The private key's first byte, zero, is omitted. Input = 3052020101300506032b65700421041fb1a7c20b2b4ed9c78f3686db82f854734cdc95be51def304d98e0cd30bf490a12303210063457cd4dfdd0e98a53796265831d46ac6a5a685f2a54c9697a38b2c800d60ba -Result = InvalidEncoding +Result-Checked = InvalidEncoding +Result-Maybe-Unchecked = InvalidEncoding # v2. The public key's first byte is zero. Input = 3053020101300506032b6570042204202dc67de5186d9193021c0b104d9c6ef24bee2bd395ccb5ed5a2db5f37a2fc1f0a12303210000c17e4d8bbff27c1fb618c23fce988703c7efa3cd590aacac12d3f1e3c90c8c -Result = OK +Result-Checked = OK +Result-Maybe-Unchecked = OK Public = 00c17e4d8bbff27c1fb618c23fce988703c7efa3cd590aacac12d3f1e3c90c8c # v2. The public key's first byte, zero, is omitted. Input = 3052020101300506032b6570042204202dc67de5186d9193021c0b104d9c6ef24bee2bd395ccb5ed5a2db5f37a2fc1f0a122032000c17e4d8bbff27c1fb618c23fce988703c7efa3cd590aacac12d3f1e3c90c8c -Result = InvalidEncoding +Result-Checked = InvalidEncoding +Result-Maybe-Unchecked = InvalidEncoding # v2. The public key's last byte is zero. Input = 3053020101300506032b657004220420b2579f555a2eabdabac8d46997b1c08fe8ce63858df124efc29c60dfbb86c349a1230321009d421270ce2fcc08672c41e427214876245c9b0f14ab671b8bb9d266a492e400 -Result = OK +Result-Checked = OK +Result-Maybe-Unchecked = OK Public = 9d421270ce2fcc08672c41e427214876245c9b0f14ab671b8bb9d266a492e400 # v2. The public key's last byte, zero, is omitted (valid ASN.1 DER). Input = 3052020101300506032b657004220420b2579f555a2eabdabac8d46997b1c08fe8ce63858df124efc29c60dfbb86c349a1220320009d421270ce2fcc08672c41e427214876245c9b0f14ab671b8bb9d266a492e4 -Result = InvalidEncoding +Result-Checked = InvalidEncoding +Result-Maybe-Unchecked = InvalidEncoding # v2. The public key's last byte, zero, has been truncated (invalid ASN.1 DER). Input = 3053020101300506032b657004220420b2579f555a2eabdabac8d46997b1c08fe8ce63858df124efc29c60dfbb86c349a1230321009d421270ce2fcc08672c41e427214876245c9b0f14ab671b8bb9d266a492e4 -Result = InvalidEncoding +Result-Checked = InvalidEncoding +Result-Maybe-Unchecked = InvalidEncoding # v2. The public key's high bit has been flipped. Ed25519 public keys don't # have their high bit masked, so this is wrong. Input = 3053020101300506032b6570042204202dc67de5186d9193021c0b104d9c6ef24bee2bd395ccb5ed5a2db5f37a2fc1f0a12303210000c17e4d8bbff27c1fb618c23fce988703c7efa3cd590aacac12d3f1e3c90c0c -Result = InconsistentComponents +Result-Checked = InconsistentComponents +Result-Maybe-Unchecked = InconsistentComponents # v2. Valid except the public key field is missing. Input = 302e020101300506032b657004220420a22efdb713f0e1600d2a5ce948e321ca3a18137c47f15091a12c7126c1749a00 -Result = PublicKeyIsMissing +Result-Checked = PublicKeyIsMissing +Result-Maybe-Unchecked = PublicKeyIsMissing # v2. Valid except the public key is encoded as [0] instead of [1]; i.e. the # attributes are invalid and the public key is missing. Input = 3053020101300506032b657004220420a22efdb713f0e1600d2a5ce948e321ca3a18137c47f15091a12c7126c1749a00a0230321001aeb8e3ee5ba5afd91113466d19f4ea77fa0feffbd8c5adcb499927f12535f77 -Result = PublicKeyIsMissing +Result-Checked = PublicKeyIsMissing +Result-Maybe-Unchecked = PublicKeyIsMissing diff --git a/tests/ed25519_from_pkcs8_unchecked_tests.txt b/tests/ed25519_from_pkcs8_unchecked_tests.txt deleted file mode 100644 index bd49ed306..000000000 --- a/tests/ed25519_from_pkcs8_unchecked_tests.txt +++ /dev/null @@ -1,17 +0,0 @@ -# An Ed25519 private key. (This is from BoringSSL's tests.) -Input = 302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 -Result = OK -Public = d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a - -# The same as the above, but with an invalid NULL parameter. (This is from BoringSSL's tests.) -Input = 3030020100300706032b65700500042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 -Result = WrongAlgorithm - -# Sample private key from draft-ietf-curdle-pkix-04. -Input = 302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842 -Result = OK -Public = 19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1 - -# v1. valid except it includes publicKey. -Input = 3053020100300506032b657004220420a22efdb713f0e1600d2a5ce948e321ca3a18137c47f15091a12c7126c1749a00a1230321001aeb8e3ee5ba5afd91113466d19f4ea77fa0feffbd8c5adcb499927f12535f77 -Result = InvalidEncoding diff --git a/tests/ed25519_tests.rs b/tests/ed25519_tests.rs index d1e918319..29faed1e9 100644 --- a/tests/ed25519_tests.rs +++ b/tests/ed25519_tests.rs @@ -112,60 +112,73 @@ fn test_ed25519_from_seed_and_public_key_misuse() { assert!(Ed25519KeyPair::from_seed_and_public_key(PUBLIC_KEY, PRIVATE_KEY).is_err()); } +enum FromPkcs8Variant { + Checked, + MaybeUnchecked, +} + #[test] fn test_ed25519_from_pkcs8_unchecked() { test_ed25519_from_pkcs8_( - test_file!("ed25519_from_pkcs8_unchecked_tests.txt"), + FromPkcs8Variant::MaybeUnchecked, Ed25519KeyPair::from_pkcs8_maybe_unchecked, ) } #[test] fn test_ed25519_from_pkcs8() { - test_ed25519_from_pkcs8_( - test_file!("ed25519_from_pkcs8_tests.txt"), - Ed25519KeyPair::from_pkcs8, - ) + test_ed25519_from_pkcs8_(FromPkcs8Variant::Checked, Ed25519KeyPair::from_pkcs8) } fn test_ed25519_from_pkcs8_( - test_file: test::File, + variant: FromPkcs8Variant, f: impl Fn(&[u8]) -> Result, ) { // Just test that we can parse the input. - test::run(test_file, |section, test_case| { - assert_eq!(section, ""); - let input = test_case.consume_bytes("Input"); - let expected_error = { - let expected_result = test_case.consume_string("Result"); - if expected_result == "OK" { - None - } else { - Some(expected_result) - } - }; - let expected_public = if expected_error.is_none() { - Some(test_case.consume_bytes("Public")) - } else { - None - }; - - match f(&input) { - Ok(keypair) => { - assert_eq!(expected_error, None); - assert_eq!( - expected_public.as_deref(), - Some(keypair.public_key().as_ref()) - ); - } - Err(actual_error) => { - assert_eq!(expected_error, Some(format!("{}", actual_error))); - assert_eq!(expected_public, None); + test::run( + test_file!("ed25519_from_pkcs8_tests.txt"), + |section, test_case| { + assert_eq!(section, ""); + let input = test_case.consume_bytes("Input"); + let expected_error = { + let expected_checked = test_case.consume_string("Result-Checked"); + let expected_maybe_unchecked = test_case.consume_string("Result-Maybe-Unchecked"); + let expected_result = match variant { + FromPkcs8Variant::Checked => expected_checked, + FromPkcs8Variant::MaybeUnchecked => expected_maybe_unchecked, + }; + if expected_result == "OK" { + None + } else { + Some(expected_result) + } + }; + let expected_public = { + let expected_if_no_error = test_case.consume_optional_bytes("Public"); + if expected_error.is_none() { + Some(expected_if_no_error.unwrap()) + } else { + None + } + }; + + match f(&input) { + Ok(keypair) => { + assert_eq!(expected_error, None); + assert_eq!( + expected_public.as_deref(), + Some(keypair.public_key().as_ref()) + ); + } + Err(actual_error) => { + assert_eq!(expected_error, Some(format!("{}", actual_error))); + assert_eq!(expected_public, None); + } } - } - Ok(()) - }); + Ok(()) + }, + ); } #[test]