Skip to content

Commit bc04d95

Browse files
committed
Expose TLS PRF key derivation
1 parent 6a45982 commit bc04d95

File tree

5 files changed

+176
-0
lines changed

5 files changed

+176
-0
lines changed

openssl-sys/src/evp.rs

+53
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub const EVP_PKEY_CMAC: c_int = NID_cmac;
3030
pub const EVP_PKEY_POLY1305: c_int = NID_poly1305;
3131
#[cfg(any(ossl110, libressl360))]
3232
pub const EVP_PKEY_HKDF: c_int = NID_hkdf;
33+
#[cfg(ossl110)]
34+
pub const EVP_PKEY_TLS1_PRF: c_int = NID_tls1_prf;
3335

3436
#[cfg(ossl102)]
3537
pub const EVP_CIPHER_CTX_FLAG_WRAP_ALLOW: c_int = 0x1;
@@ -241,6 +243,13 @@ pub const EVP_PKEY_CTRL_HKDF_INFO: c_int = EVP_PKEY_ALG_CTRL + 6;
241243
#[cfg(any(ossl111, libressl360))]
242244
pub const EVP_PKEY_CTRL_HKDF_MODE: c_int = EVP_PKEY_ALG_CTRL + 7;
243245

246+
#[cfg(ossl110)]
247+
pub const EVP_PKEY_CTRL_TLS_MD: c_int = EVP_PKEY_ALG_CTRL;
248+
#[cfg(ossl110)]
249+
pub const EVP_PKEY_CTRL_TLS_SECRET: c_int = EVP_PKEY_ALG_CTRL + 1;
250+
#[cfg(ossl110)]
251+
pub const EVP_PKEY_CTRL_TLS_SEED: c_int = EVP_PKEY_ALG_CTRL + 2;
252+
244253
#[cfg(any(all(ossl111, not(ossl300)), libressl360))]
245254
pub unsafe fn EVP_PKEY_CTX_set_hkdf_mode(ctx: *mut EVP_PKEY_CTX, mode: c_int) -> c_int {
246255
EVP_PKEY_CTX_ctrl(
@@ -340,3 +349,47 @@ pub unsafe fn EVP_PKEY_assign_DH(pkey: *mut EVP_PKEY, dh: *mut DH) -> c_int {
340349
pub unsafe fn EVP_PKEY_assign_EC_KEY(pkey: *mut EVP_PKEY, ec_key: *mut EC_KEY) -> c_int {
341350
EVP_PKEY_assign(pkey, EVP_PKEY_EC, ec_key as *mut c_void)
342351
}
352+
353+
#[cfg(all(ossl110, not(ossl300)))]
354+
pub unsafe fn EVP_PKEY_CTX_set_tls1_prf_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int {
355+
EVP_PKEY_CTX_ctrl(
356+
ctx,
357+
-1,
358+
EVP_PKEY_OP_DERIVE,
359+
EVP_PKEY_CTRL_TLS_MD,
360+
0,
361+
md as *mut c_void,
362+
)
363+
}
364+
365+
#[cfg(all(ossl110, not(ossl300)))]
366+
pub unsafe fn EVP_PKEY_CTX_set1_tls1_prf_secret(
367+
ctx: *mut EVP_PKEY_CTX,
368+
key: *const u8,
369+
keylen: c_int,
370+
) -> c_int {
371+
EVP_PKEY_CTX_ctrl(
372+
ctx,
373+
-1,
374+
EVP_PKEY_OP_DERIVE,
375+
EVP_PKEY_CTRL_TLS_SECRET,
376+
keylen,
377+
key as *mut c_void,
378+
)
379+
}
380+
381+
#[cfg(all(ossl110, not(ossl300)))]
382+
pub unsafe fn EVP_PKEY_CTX_add1_tls1_prf_seed(
383+
ctx: *mut EVP_PKEY_CTX,
384+
seed: *const u8,
385+
seedlen: c_int,
386+
) -> c_int {
387+
EVP_PKEY_CTX_ctrl(
388+
ctx,
389+
-1,
390+
EVP_PKEY_OP_DERIVE,
391+
EVP_PKEY_CTRL_TLS_SEED,
392+
seedlen,
393+
seed as *mut c_void,
394+
)
395+
}

openssl-sys/src/handwritten/kdf.rs

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ cfg_if! {
2828
pub fn EVP_KDF_derive(ctx: *mut EVP_KDF_CTX, key: *mut u8, keylen: size_t, params: *const OSSL_PARAM) -> c_int;
2929
pub fn EVP_KDF_fetch(ctx: *mut OSSL_LIB_CTX, algorithm: *const c_char, properties: *const c_char) -> *mut EVP_KDF;
3030
pub fn EVP_KDF_free(kdf: *mut EVP_KDF);
31+
pub fn EVP_PKEY_CTX_set_tls1_prf_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int;
32+
pub fn EVP_PKEY_CTX_set1_tls1_prf_secret(
33+
ctx: *mut EVP_PKEY_CTX,
34+
secret: *const u8,
35+
secretlen: c_int,
36+
) -> c_int;
37+
pub fn EVP_PKEY_CTX_add1_tls1_prf_seed(
38+
ctx: *mut EVP_PKEY_CTX,
39+
seed: *const u8,
40+
seedlen: c_int,
41+
) -> c_int;
3142
}
3243

3344
}

openssl-sys/src/obj_mac.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1021,3 +1021,5 @@ cfg_if! {
10211021
pub const NID_ac_auditEntity: c_int = 287;
10221022
}
10231023
}
1024+
#[cfg(ossl110)]
1025+
pub const NID_tls1_prf: c_int = 1021;

openssl/src/pkey.rs

+3
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ impl Id {
9696
#[cfg(any(ossl110, boringssl, libressl360, awslc))]
9797
pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);
9898

99+
#[cfg(ossl110)]
100+
pub const TLS1_PRF: Id = Id(ffi::EVP_PKEY_TLS1_PRF);
101+
99102
#[cfg(any(ossl111, boringssl, libressl370, awslc))]
100103
pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
101104
#[cfg(ossl111)]

openssl/src/pkey_ctx.rs

+107
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,67 @@ impl<T> PkeyCtxRef<T> {
696696
Ok(())
697697
}
698698

699+
/// Sets the digest used for TLS1 PRF derivation.
700+
///
701+
/// Requires OpenSSL 1.1.0 or newer.
702+
#[corresponds(EVP_PKEY_CTX_set_tls1_prf_md)]
703+
#[cfg(ossl110)]
704+
#[inline]
705+
pub fn set_tls1_prf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> {
706+
unsafe {
707+
cvt(ffi::EVP_PKEY_CTX_set_tls1_prf_md(
708+
self.as_ptr(),
709+
digest.as_ptr(),
710+
))?;
711+
}
712+
713+
Ok(())
714+
}
715+
716+
/// Sets the secret value for TLS PRF derivation.
717+
///
718+
/// Any existing secret value is replaced and any seed is reset.
719+
///
720+
/// Requires OpenSSL 1.1.0 or newer.
721+
#[corresponds(EVP_PKEY_CTX_set1_tls1_prf_secret)]
722+
#[cfg(ossl110)]
723+
#[inline]
724+
pub fn set_tls1_prf_secret(&mut self, secret: &[u8]) -> Result<(), ErrorStack> {
725+
let len = c_int::try_from(secret.len()).unwrap();
726+
727+
unsafe {
728+
cvt(ffi::EVP_PKEY_CTX_set1_tls1_prf_secret(
729+
self.as_ptr(),
730+
secret.as_ptr(),
731+
len,
732+
))?;
733+
}
734+
735+
Ok(())
736+
}
737+
738+
/// Adds a seed for TLS PRF derivation.
739+
///
740+
/// If a seed is already set, the new seed is appended to the existing seed.
741+
///
742+
/// Requires OpenSSL 1.1.0 or newer.
743+
#[corresponds(EVP_PKEY_CTX_add1_tls1_prf_seed)]
744+
#[cfg(ossl110)]
745+
#[inline]
746+
pub fn add_tls1_prf_seed(&mut self, seed: &[u8]) -> Result<(), ErrorStack> {
747+
let len = c_int::try_from(seed.len()).unwrap();
748+
749+
unsafe {
750+
cvt(ffi::EVP_PKEY_CTX_add1_tls1_prf_seed(
751+
self.as_ptr(),
752+
seed.as_ptr(),
753+
len,
754+
))?;
755+
}
756+
757+
Ok(())
758+
}
759+
699760
/// Derives a shared secret between two keys.
700761
///
701762
/// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned.
@@ -1107,4 +1168,50 @@ mxJ7imIrEg9nIQ==
11071168
assert_eq!(output, expected_output);
11081169
assert!(ErrorStack::get().errors().is_empty());
11091170
}
1171+
1172+
#[test]
1173+
#[cfg(ossl111)]
1174+
fn tls1_prf_sha256() {
1175+
// SHA256 PRF test vectors from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/
1176+
let mut ctx = PkeyCtx::new_id(Id::TLS1_PRF).unwrap();
1177+
ctx.derive_init().unwrap();
1178+
ctx.set_tls1_prf_md(Md::sha256()).unwrap();
1179+
ctx.set_tls1_prf_secret(&hex::decode("9bbe436ba940f017b17652849a71db35").unwrap())
1180+
.unwrap();
1181+
ctx.add_tls1_prf_seed(&hex::decode("74657374206c6162656c").unwrap())
1182+
.unwrap();
1183+
ctx.add_tls1_prf_seed(&hex::decode("a0ba9f936cda311827a6f796ffd5198c").unwrap())
1184+
.unwrap();
1185+
let mut out = [0u8; 100];
1186+
ctx.derive(Some(&mut out)).unwrap();
1187+
1188+
assert_eq!(
1189+
&out[..],
1190+
hex::decode("e3f229ba727be17b8d122620557cd453c2aab21d07c3d495329b52d4e61edb5a6b301791e90d35c9c9a46b4e14baf9af0fa022f7077def17abfd3797c0564bab4fbc91666e9def9b97fce34f796789baa48082d122ee42c5a72e5a5110fff70187347b66")
1191+
.unwrap()
1192+
);
1193+
}
1194+
1195+
#[test]
1196+
#[cfg(ossl111)]
1197+
fn tls1_prf_sha384() {
1198+
// SHA384 PRF test vectors from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/
1199+
let mut ctx = PkeyCtx::new_id(Id::TLS1_PRF).unwrap();
1200+
ctx.derive_init().unwrap();
1201+
ctx.set_tls1_prf_md(Md::sha384()).unwrap();
1202+
ctx.set_tls1_prf_secret(&hex::decode("b80b733d6ceefcdc71566ea48e5567df").unwrap())
1203+
.unwrap();
1204+
ctx.add_tls1_prf_seed(&hex::decode("74657374206c6162656c").unwrap())
1205+
.unwrap();
1206+
ctx.add_tls1_prf_seed(&hex::decode("cd665cf6a8447dd6ff8b27555edb7465").unwrap())
1207+
.unwrap();
1208+
let mut out = [0u8; 148];
1209+
ctx.derive(Some(&mut out)).unwrap();
1210+
1211+
assert_eq!(
1212+
&out[..],
1213+
hex::decode("7b0c18e9ced410ed1804f2cfa34a336a1c14dffb4900bb5fd7942107e81c83cde9ca0faa60be9fe34f82b1233c9146a0e534cb400fed2700884f9dc236f80edd8bfa961144c9e8d792eca722a7b32fc3d416d473ebc2c5fd4abfdad05d9184259b5bf8cd4d90fa0d31e2dec479e4f1a26066f2eea9a69236a3e52655c9e9aee691c8f3a26854308d5eaa3be85e0990703d73e56f")
1214+
.unwrap()
1215+
);
1216+
}
11101217
}

0 commit comments

Comments
 (0)