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>
This commit is contained in:
committed by
Boringssl LUCI CQ
parent
0c59e9e55b
commit
daa03aac8d
@@ -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 @@ impl PublicKey {
|
||||
&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 {
|
||||
@@ -182,6 +245,29 @@ mod test {
|
||||
assert_eq!(private_key.0, new_private_key.0);
|
||||
}
|
||||
|
||||
#[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
|
||||
|
||||
@@ -184,9 +184,7 @@ pub struct Prk {
|
||||
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 @@ impl Prk {
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -95,7 +95,6 @@ impl Kem {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn from_rfc_id(n: u16) -> Option<Kem> {
|
||||
match n {
|
||||
n if n == Kem::P256HkdfSha256 as u16 => Some(Self::P256HkdfSha256),
|
||||
|
||||
Reference in New Issue
Block a user