Add from/to SubjectPublicKeyInfo conversion to ed25519.
And run `cargo fmt`.
Change-Id: Iff0ad50ffc8fb02454b22b82050c605620a201f8
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/76647
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/rust/bssl-crypto/src/ed25519.rs b/rust/bssl-crypto/src/ed25519.rs
index 6644aa2..73c90fb 100644
--- a/rust/bssl-crypto/src/ed25519.rs
+++ b/rust/bssl-crypto/src/ed25519.rs
@@ -34,7 +34,10 @@
//! assert!(public_key.verify(signed_message, &sig).is_ok());
//! ```
-use crate::{FfiMutSlice, FfiSlice, InvalidSignatureError};
+use crate::{
+ cbb_to_buffer, parse_with_cbs, scoped, with_output_array, Buffer, FfiMutSlice, FfiSlice,
+ InvalidSignatureError,
+};
/// The length in bytes of an Ed25519 public key.
pub const PUBLIC_KEY_LEN: usize = bssl_sys::ED25519_PUBLIC_KEY_LEN as usize;
@@ -149,6 +152,66 @@
&self.0
}
+ /// Parse a public key in SubjectPublicKeyInfo format.
+ pub fn from_der_subject_public_key_info(spki: &[u8]) -> Option<Self> {
+ let mut pkey = scoped::EvpPkey::from_ptr(parse_with_cbs(
+ spki,
+ // Safety: `pkey` is a non-null result from `EVP_parse_public_key` here.
+ |pkey| unsafe { bssl_sys::EVP_PKEY_free(pkey) },
+ // Safety: cbs is valid per `parse_with_cbs`.
+ |cbs| unsafe { bssl_sys::EVP_parse_public_key(cbs) },
+ )?);
+
+ let mut out_len = 0;
+ // When the out buffer is null, `out_len` is set to the size of the raw public key.
+ // Safety: the arguments are valid.
+ let result = unsafe {
+ bssl_sys::EVP_PKEY_get_raw_public_key(
+ pkey.as_ffi_ptr(),
+ core::ptr::null_mut(),
+ &mut out_len,
+ )
+ };
+ if result != 1 {
+ return None;
+ }
+ if out_len != PUBLIC_KEY_LEN {
+ return None;
+ }
+
+ // When the out buffer is not null, the raw public key is written into it.
+ // Safety: the arguments are valid.
+ let raw_pkey: [u8; PUBLIC_KEY_LEN] = unsafe {
+ with_output_array(|out, _| {
+ assert_eq!(
+ 1,
+ bssl_sys::EVP_PKEY_get_raw_public_key(pkey.as_ffi_ptr(), out, &mut out_len)
+ );
+ })
+ };
+ Some(PublicKey(raw_pkey))
+ }
+
+ /// Serialize this key in SubjectPublicKeyInfo format.
+ pub fn to_der_subject_public_key_info(&self) -> Buffer {
+ // Safety: this only copies from the `self.0` buffer.
+ let mut pkey = scoped::EvpPkey::from_ptr(unsafe {
+ bssl_sys::EVP_PKEY_new_raw_public_key(
+ bssl_sys::EVP_PKEY_ED25519,
+ /*unused=*/ core::ptr::null_mut(),
+ self.0.as_ffi_ptr(),
+ PUBLIC_KEY_LEN,
+ )
+ });
+ assert!(!pkey.as_ffi_ptr().is_null());
+
+ cbb_to_buffer(PUBLIC_KEY_LEN + 32, |cbb| unsafe {
+ // The arguments are valid so this will only fail if out of memory,
+ // which this crate doesn't handle.
+ assert_eq!(1, bssl_sys::EVP_marshal_public_key(cbb, pkey.as_ffi_ptr()));
+ })
+ }
+
/// Verifies that `signature` is a valid signature, by this key, of `msg`.
pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), InvalidSignatureError> {
let ret = unsafe {
@@ -183,6 +246,29 @@
}
#[test]
+ fn der_subject_public_key_info() {
+ let priv_key = PrivateKey::generate();
+ let msg = [0u8; 0];
+ let sig = priv_key.sign(&msg);
+
+ let pub_key = priv_key.to_public();
+ assert!(pub_key.verify(&msg, &sig).is_ok());
+
+ let pub_key_der = pub_key.to_der_subject_public_key_info();
+ let pub_key_from_der =
+ PublicKey::from_der_subject_public_key_info(pub_key_der.as_ref()).unwrap();
+ assert_eq!(pub_key.as_bytes(), pub_key_from_der.as_bytes());
+ assert!(pub_key_from_der.verify(&msg, &sig).is_ok());
+
+ assert!(PublicKey::from_der_subject_public_key_info(
+ &pub_key_from_der.as_bytes()[0..PUBLIC_KEY_LEN / 2]
+ )
+ .is_none());
+
+ assert!(PublicKey::from_der_subject_public_key_info(b"").is_none());
+ }
+
+ #[test]
fn empty_msg() {
// Test Case 1 from RFC test vectors: https://www.rfc-editor.org/rfc/rfc8032#section-7.1
let pk = test_helpers::decode_hex(
diff --git a/rust/bssl-crypto/src/hkdf.rs b/rust/bssl-crypto/src/hkdf.rs
index 24343ae..968e644 100644
--- a/rust/bssl-crypto/src/hkdf.rs
+++ b/rust/bssl-crypto/src/hkdf.rs
@@ -184,9 +184,7 @@
evp_md: *const bssl_sys::EVP_MD,
}
-#[allow(clippy::let_unit_value,
- clippy::unwrap_used,
-)]
+#[allow(clippy::let_unit_value, clippy::unwrap_used)]
impl Prk {
/// Creates a Prk from bytes.
pub fn new<MD: digest::Algorithm>(prk_bytes: &[u8]) -> Option<Self> {
@@ -210,10 +208,11 @@
/// Returns the bytes of the pseudorandom key.
pub fn as_bytes(&self) -> &[u8] {
- self.prk.get(..self.len)
- // unwrap:`self.len` must be less than the length of `self.prk` thus
- // this is always in bounds.
- .unwrap()
+ self.prk
+ .get(..self.len)
+ // unwrap:`self.len` must be less than the length of `self.prk` thus
+ // this is always in bounds.
+ .unwrap()
}
/// Derive key material for the given info parameter. Attempting
diff --git a/rust/bssl-crypto/src/hpke.rs b/rust/bssl-crypto/src/hpke.rs
index 2259140..12010ac 100644
--- a/rust/bssl-crypto/src/hpke.rs
+++ b/rust/bssl-crypto/src/hpke.rs
@@ -95,7 +95,6 @@
}
}
-
fn from_rfc_id(n: u16) -> Option<Kem> {
match n {
n if n == Kem::P256HkdfSha256 as u16 => Some(Self::P256HkdfSha256),