diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d70a71d..efce126b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,12 +17,14 @@ SPDX-License-Identifier: CC0-1.0 - Fix the length of the Digital signature counter DO 0x93 ([#76][]) - PSO:CDS: Increment the signature counter ([#78][]) +- Fix endianness of curve25519 key import([#89][]) [#64]: https://github.com/Nitrokey/opcard-rs/pull/64 [#60]: https://github.com/Nitrokey/opcard-rs/pull/60 [#63]: https://github.com/Nitrokey/opcard-rs/pull/63 [#76]: https://github.com/Nitrokey/opcard-rs/pull/76 [#78]: https://github.com/Nitrokey/opcard-rs/pull/78 +[#89]: https://github.com/Nitrokey/opcard-rs/pull/89 ## v0.1.0 (2022-10-12) diff --git a/src/command/private_key_template.rs b/src/command/private_key_template.rs index 8f13b8c3..6622fbf4 100644 --- a/src/command/private_key_template.rs +++ b/src/command/private_key_template.rs @@ -128,9 +128,27 @@ fn put_ec( Status::IncorrectDataParameter })?; + // GPG stores scalars as big endian when X25519 specifies them to be little endian + // See https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html + let mut data: [u8; 32]; + let message; + if matches!(curve, CurveAlgo::X255) { + data = private_key_data.try_into().map_err(|_| { + warn!( + "Bad private key length for x25519: {}", + private_key_data.len() + ); + Status::IncorrectDataParameter + })?; + data.reverse(); + message = data.as_slice(); + } else { + message = private_key_data; + } + let key = try_syscall!(ctx.backend.client_mut().unsafe_inject_key( curve.mechanism(), - private_key_data, + message, Location::Internal, KeySerialization::Raw )) diff --git a/tests/crypto-gpg-import.rs b/tests/crypto-gpg-import.rs index 0f664157..601f1608 100644 --- a/tests/crypto-gpg-import.rs +++ b/tests/crypto-gpg-import.rs @@ -187,17 +187,24 @@ fn gpg_255() { let custom2 = format!(r"{temp_name} \(no comment\) <{temp_email}>"); gnupg_test( &[DEFAULT_PW1], - &[vec![ - r"\[GNUPG:\] ENC_TO [a-fA-F0-9]{16} \d* \d*", - r"\[GNUPG:\] DECRYPTION_KEY [a-fA-F0-9]{40} [a-fA-F0-9]{40} u", - r"\[GNUPG:\] BEGIN_DECRYPTION", - r"\[GNUPG:\] DECRYPTION_INFO \d \d \d", - r"\[GNUPG:\] PLAINTEXT \d* \d* Cargo.toml", - r"\[GNUPG:\] PLAINTEXT_LENGTH \d*", - r"\[GNUPG:\] DECRYPTION_OKAY", - r"\[GNUPG:\] GOODMDC", - r"\[GNUPG:\] END_DECRYPTION", - ]] + &[ + vec![ + r"\[GNUPG:\] ENC_TO [a-fA-F0-9]{16} \d* \d*", + &custom1, + r"\[GNUPG:\] NEED_PASSPHRASE [a-fA-F0-9]{16} [a-fA-F0-9]{16} 18 0", + ], + virt::gpg_inquire_pin(), + vec![ + r"\[GNUPG:\] DECRYPTION_KEY [a-fA-F0-9]{40} [a-fA-F0-9]{40} u", + r"\[GNUPG:\] BEGIN_DECRYPTION", + r"\[GNUPG:\] DECRYPTION_INFO \d \d \d", + r"\[GNUPG:\] PLAINTEXT \d* \d* Cargo.toml", + r"\[GNUPG:\] PLAINTEXT_LENGTH \d*", + r"\[GNUPG:\] DECRYPTION_OKAY", + r"\[GNUPG:\] GOODMDC", + r"\[GNUPG:\] END_DECRYPTION", + ], + ] .into_iter() .flatten() .collect::>(),