Skip to content

Commit 2c6b08f

Browse files
committed
Add support for PKey raw byte representation
1 parent c65d85a commit 2c6b08f

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed

openssl/src/pkey.rs

+181
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,34 @@ where
250250
{
251251
unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
252252
}
253+
254+
/// Raw byte representation of a public key
255+
///
256+
/// This function only works for algorithms that support raw public keys.
257+
/// Currently this is: X25519, ED25519, X448 or ED448
258+
///
259+
/// This corresponds to [`EVP_PKEY_get_raw_public_key`].
260+
///
261+
/// [`EVP_PKEY_get_raw_public_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_get_raw_public_key.html
262+
#[cfg(ossl111)]
263+
pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
264+
unsafe {
265+
let mut len = 0;
266+
cvt(ffi::EVP_PKEY_get_raw_public_key(
267+
self.as_ptr(),
268+
ptr::null_mut(),
269+
&mut len,
270+
))?;
271+
let mut buf = vec![0u8; len];
272+
cvt(ffi::EVP_PKEY_get_raw_public_key(
273+
self.as_ptr(),
274+
buf.as_mut_ptr(),
275+
&mut len,
276+
))?;
277+
buf.truncate(len);
278+
Ok(buf)
279+
}
280+
}
253281
}
254282

255283
impl<T> PKeyRef<T>
@@ -285,6 +313,34 @@ where
285313
private_key_to_der,
286314
ffi::i2d_PrivateKey
287315
}
316+
317+
/// Raw byte representation of a private key
318+
///
319+
/// This function only works for algorithms that support raw private keys.
320+
/// Currently this is: HMAC, X25519, ED25519, X448 or ED448
321+
///
322+
/// This corresponds to [`EVP_PKEY_get_raw_private_key`].
323+
///
324+
/// [`EVP_PKEY_get_raw_private_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_get_raw_private_key.html
325+
#[cfg(ossl111)]
326+
pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
327+
unsafe {
328+
let mut len = 0;
329+
cvt(ffi::EVP_PKEY_get_raw_private_key(
330+
self.as_ptr(),
331+
ptr::null_mut(),
332+
&mut len,
333+
))?;
334+
let mut buf = vec![0u8; len];
335+
cvt(ffi::EVP_PKEY_get_raw_private_key(
336+
self.as_ptr(),
337+
buf.as_mut_ptr(),
338+
&mut len,
339+
))?;
340+
buf.truncate(len);
341+
Ok(buf)
342+
}
343+
}
288344
}
289345

290346
impl<T> fmt::Debug for PKey<T> {
@@ -627,6 +683,30 @@ impl PKey<Private> {
627683
.map(|p| PKey::from_ptr(p))
628684
}
629685
}
686+
687+
/// Creates a private key from its raw byte representation
688+
///
689+
/// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448
690+
///
691+
/// This corresponds to [`EVP_PKEY_new_raw_private_key`].
692+
///
693+
/// [`EVP_PKEY_new_raw_private_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_private_key.html
694+
#[cfg(ossl111)]
695+
pub fn private_key_from_raw_bytes(
696+
bytes: &[u8],
697+
key_type: Id,
698+
) -> Result<PKey<Private>, ErrorStack> {
699+
unsafe {
700+
ffi::init();
701+
cvt_p(ffi::EVP_PKEY_new_raw_private_key(
702+
key_type.as_raw(),
703+
ptr::null_mut(),
704+
bytes.as_ptr(),
705+
bytes.len(),
706+
))
707+
.map(|p| PKey::from_ptr(p))
708+
}
709+
}
630710
}
631711

632712
impl PKey<Public> {
@@ -653,6 +733,30 @@ impl PKey<Public> {
653733
PKey<Public>,
654734
ffi::d2i_PUBKEY
655735
}
736+
737+
/// Creates a public key from its raw byte representation
738+
///
739+
/// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448
740+
///
741+
/// This corresponds to [`EVP_PKEY_new_raw_public_key`].
742+
///
743+
/// [`EVP_PKEY_new_raw_public_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_public_key.html
744+
#[cfg(ossl111)]
745+
pub fn public_key_from_raw_bytes(
746+
bytes: &[u8],
747+
key_type: Id,
748+
) -> Result<PKey<Public>, ErrorStack> {
749+
unsafe {
750+
ffi::init();
751+
cvt_p(ffi::EVP_PKEY_new_raw_public_key(
752+
key_type.as_raw(),
753+
ptr::null_mut(),
754+
bytes.as_ptr(),
755+
bytes.len(),
756+
))
757+
.map(|p| PKey::from_ptr(p))
758+
}
759+
}
656760
}
657761

658762
cfg_if! {
@@ -749,6 +853,9 @@ mod tests {
749853

750854
use super::*;
751855

856+
#[cfg(ossl111)]
857+
use crate::rand::rand_bytes;
858+
752859
#[test]
753860
fn test_to_password() {
754861
let rsa = Rsa::generate(2048).unwrap();
@@ -908,4 +1015,78 @@ mod tests {
9081015
assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap()));
9091016
assert_eq!(&g, dh_.generator());
9101017
}
1018+
1019+
#[cfg(ossl111)]
1020+
fn test_raw_public_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
1021+
// Generate a new key
1022+
let key = gen().unwrap();
1023+
1024+
// Get the raw bytes, and create a new key from the raw bytes
1025+
let raw = key.raw_public_key().unwrap();
1026+
let from_raw = PKey::public_key_from_raw_bytes(&raw, key_type).unwrap();
1027+
1028+
// Compare the der encoding of the original and raw / restored public key
1029+
assert_eq!(
1030+
key.public_key_to_der().unwrap(),
1031+
from_raw.public_key_to_der().unwrap()
1032+
);
1033+
}
1034+
1035+
#[cfg(ossl111)]
1036+
fn test_raw_private_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
1037+
// Generate a new key
1038+
let key = gen().unwrap();
1039+
1040+
// Get the raw bytes, and create a new key from the raw bytes
1041+
let raw = key.raw_private_key().unwrap();
1042+
let from_raw = PKey::private_key_from_raw_bytes(&raw, key_type).unwrap();
1043+
1044+
// Compare the der encoding of the original and raw / restored public key
1045+
assert_eq!(
1046+
key.private_key_to_der().unwrap(),
1047+
from_raw.private_key_to_der().unwrap()
1048+
);
1049+
}
1050+
1051+
#[cfg(ossl111)]
1052+
#[test]
1053+
fn test_raw_public_key_bytes() {
1054+
test_raw_public_key(PKey::generate_x25519, Id::X25519);
1055+
test_raw_public_key(PKey::generate_ed25519, Id::ED25519);
1056+
test_raw_public_key(PKey::generate_x448, Id::X448);
1057+
test_raw_public_key(PKey::generate_ed448, Id::ED448);
1058+
}
1059+
1060+
#[cfg(ossl111)]
1061+
#[test]
1062+
fn test_raw_private_key_bytes() {
1063+
test_raw_private_key(PKey::generate_x25519, Id::X25519);
1064+
test_raw_private_key(PKey::generate_ed25519, Id::ED25519);
1065+
test_raw_private_key(PKey::generate_x448, Id::X448);
1066+
test_raw_private_key(PKey::generate_ed448, Id::ED448);
1067+
}
1068+
1069+
#[cfg(ossl111)]
1070+
#[test]
1071+
fn test_raw_hmac() {
1072+
let mut test_bytes = vec![0u8; 32];
1073+
rand_bytes(&mut test_bytes).unwrap();
1074+
1075+
let hmac_key = PKey::hmac(&test_bytes).unwrap();
1076+
assert!(hmac_key.raw_public_key().is_err());
1077+
1078+
let key_bytes = hmac_key.raw_private_key().unwrap();
1079+
assert_eq!(key_bytes, test_bytes);
1080+
}
1081+
1082+
#[cfg(ossl111)]
1083+
#[test]
1084+
fn test_raw_key_fail() {
1085+
// Getting a raw byte representation will not work with Nist curves
1086+
let group = crate::ec::EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
1087+
let ec_key = EcKey::generate(&group).unwrap();
1088+
let pkey = PKey::from_ec_key(ec_key).unwrap();
1089+
assert!(pkey.raw_private_key().is_err());
1090+
assert!(pkey.raw_public_key().is_err());
1091+
}
9111092
}

0 commit comments

Comments
 (0)