Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose TLS PRF key derivation #2329

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions openssl-sys/src/evp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub const EVP_PKEY_CMAC: c_int = NID_cmac;
pub const EVP_PKEY_POLY1305: c_int = NID_poly1305;
#[cfg(any(ossl110, libressl360))]
pub const EVP_PKEY_HKDF: c_int = NID_hkdf;
#[cfg(ossl110)]
pub const EVP_PKEY_TLS1_PRF: c_int = NID_tls1_prf;

#[cfg(ossl102)]
pub const EVP_CIPHER_CTX_FLAG_WRAP_ALLOW: c_int = 0x1;
Expand Down Expand Up @@ -241,6 +243,13 @@ pub const EVP_PKEY_CTRL_HKDF_INFO: c_int = EVP_PKEY_ALG_CTRL + 6;
#[cfg(any(ossl111, libressl360))]
pub const EVP_PKEY_CTRL_HKDF_MODE: c_int = EVP_PKEY_ALG_CTRL + 7;

#[cfg(ossl110)]
pub const EVP_PKEY_CTRL_TLS_MD: c_int = EVP_PKEY_ALG_CTRL;
#[cfg(ossl110)]
pub const EVP_PKEY_CTRL_TLS_SECRET: c_int = EVP_PKEY_ALG_CTRL + 1;
#[cfg(ossl110)]
pub const EVP_PKEY_CTRL_TLS_SEED: c_int = EVP_PKEY_ALG_CTRL + 2;

#[cfg(any(all(ossl111, not(ossl300)), libressl360))]
pub unsafe fn EVP_PKEY_CTX_set_hkdf_mode(ctx: *mut EVP_PKEY_CTX, mode: c_int) -> c_int {
EVP_PKEY_CTX_ctrl(
Expand Down Expand Up @@ -340,3 +349,47 @@ pub unsafe fn EVP_PKEY_assign_DH(pkey: *mut EVP_PKEY, dh: *mut DH) -> c_int {
pub unsafe fn EVP_PKEY_assign_EC_KEY(pkey: *mut EVP_PKEY, ec_key: *mut EC_KEY) -> c_int {
EVP_PKEY_assign(pkey, EVP_PKEY_EC, ec_key as *mut c_void)
}

#[cfg(all(ossl110, not(ossl300)))]
pub unsafe fn EVP_PKEY_CTX_set_tls1_prf_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int {
EVP_PKEY_CTX_ctrl(
ctx,
-1,
EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_TLS_MD,
0,
md as *mut c_void,
)
}

#[cfg(all(ossl110, not(ossl300)))]
pub unsafe fn EVP_PKEY_CTX_set1_tls1_prf_secret(
ctx: *mut EVP_PKEY_CTX,
key: *const u8,
keylen: c_int,
) -> c_int {
EVP_PKEY_CTX_ctrl(
ctx,
-1,
EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_TLS_SECRET,
keylen,
key as *mut c_void,
)
}

#[cfg(all(ossl110, not(ossl300)))]
pub unsafe fn EVP_PKEY_CTX_add1_tls1_prf_seed(
ctx: *mut EVP_PKEY_CTX,
seed: *const u8,
seedlen: c_int,
) -> c_int {
EVP_PKEY_CTX_ctrl(
ctx,
-1,
EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_TLS_SEED,
seedlen,
seed as *mut c_void,
)
}
11 changes: 11 additions & 0 deletions openssl-sys/src/handwritten/kdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ cfg_if! {
pub fn EVP_KDF_derive(ctx: *mut EVP_KDF_CTX, key: *mut u8, keylen: size_t, params: *const OSSL_PARAM) -> c_int;
pub fn EVP_KDF_fetch(ctx: *mut OSSL_LIB_CTX, algorithm: *const c_char, properties: *const c_char) -> *mut EVP_KDF;
pub fn EVP_KDF_free(kdf: *mut EVP_KDF);
pub fn EVP_PKEY_CTX_set_tls1_prf_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int;
pub fn EVP_PKEY_CTX_set1_tls1_prf_secret(
ctx: *mut EVP_PKEY_CTX,
secret: *const u8,
secretlen: c_int,
) -> c_int;
pub fn EVP_PKEY_CTX_add1_tls1_prf_seed(
ctx: *mut EVP_PKEY_CTX,
seed: *const u8,
seedlen: c_int,
) -> c_int;
}

}
Expand Down
2 changes: 2 additions & 0 deletions openssl-sys/src/obj_mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,3 +1021,5 @@ cfg_if! {
pub const NID_ac_auditEntity: c_int = 287;
}
}
#[cfg(ossl110)]
pub const NID_tls1_prf: c_int = 1021;
3 changes: 3 additions & 0 deletions openssl/src/pkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ impl Id {
#[cfg(any(ossl110, boringssl, libressl360))]
pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);

#[cfg(ossl110)]
pub const TLS1_PRF: Id = Id(ffi::EVP_PKEY_TLS1_PRF);

#[cfg(any(ossl111, boringssl, libressl370))]
pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
#[cfg(ossl111)]
Expand Down
107 changes: 107 additions & 0 deletions openssl/src/pkey_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,67 @@ impl<T> PkeyCtxRef<T> {
Ok(())
}

/// Sets the digest used for TLS1 PRF derivation.
///
/// Requires OpenSSL 1.1.0 or newer.
#[corresponds(EVP_PKEY_CTX_set_tls1_prf_md)]
#[cfg(ossl110)]
#[inline]
pub fn set_tls1_prf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_tls1_prf_md(
self.as_ptr(),
digest.as_ptr(),
))?;
}

Ok(())
}

/// Sets the secret value for TLS PRF derivation.
///
/// Any existing secret value is replaced and any seed is reset.
///
/// Requires OpenSSL 1.1.0 or newer.
#[corresponds(EVP_PKEY_CTX_set1_tls1_prf_secret)]
#[cfg(ossl110)]
#[inline]
pub fn set_tls1_prf_secret(&mut self, secret: &[u8]) -> Result<(), ErrorStack> {
let len = c_int::try_from(secret.len()).unwrap();

unsafe {
cvt(ffi::EVP_PKEY_CTX_set1_tls1_prf_secret(
self.as_ptr(),
secret.as_ptr(),
len,
))?;
}

Ok(())
}

/// Adds a seed for TLS PRF derivation.
///
/// If a seed is already set, the new seed is appended to the existing seed.
///
/// Requires OpenSSL 1.1.0 or newer.
#[corresponds(EVP_PKEY_CTX_add1_tls1_prf_seed)]
#[cfg(ossl110)]
#[inline]
pub fn add_tls1_prf_seed(&mut self, seed: &[u8]) -> Result<(), ErrorStack> {
let len = c_int::try_from(seed.len()).unwrap();

unsafe {
cvt(ffi::EVP_PKEY_CTX_add1_tls1_prf_seed(
self.as_ptr(),
seed.as_ptr(),
len,
))?;
}

Ok(())
}

/// Derives a shared secret between two keys.
///
/// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned.
Expand Down Expand Up @@ -1107,4 +1168,50 @@ n9Q=
assert_eq!(output, expected_output);
assert!(ErrorStack::get().errors().is_empty());
}

#[test]
#[cfg(ossl111)]
fn tls1_prf_sha256() {
// SHA256 PRF test vectors from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/
let mut ctx = PkeyCtx::new_id(Id::TLS1_PRF).unwrap();
ctx.derive_init().unwrap();
ctx.set_tls1_prf_md(Md::sha256()).unwrap();
ctx.set_tls1_prf_secret(&hex::decode("9bbe436ba940f017b17652849a71db35").unwrap())
.unwrap();
ctx.add_tls1_prf_seed(&hex::decode("74657374206c6162656c").unwrap())
.unwrap();
ctx.add_tls1_prf_seed(&hex::decode("a0ba9f936cda311827a6f796ffd5198c").unwrap())
.unwrap();
let mut out = [0u8; 100];
ctx.derive(Some(&mut out)).unwrap();

assert_eq!(
&out[..],
hex::decode("e3f229ba727be17b8d122620557cd453c2aab21d07c3d495329b52d4e61edb5a6b301791e90d35c9c9a46b4e14baf9af0fa022f7077def17abfd3797c0564bab4fbc91666e9def9b97fce34f796789baa48082d122ee42c5a72e5a5110fff70187347b66")
.unwrap()
);
}

#[test]
#[cfg(ossl111)]
fn tls1_prf_sha384() {
// SHA384 PRF test vectors from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/
let mut ctx = PkeyCtx::new_id(Id::TLS1_PRF).unwrap();
ctx.derive_init().unwrap();
ctx.set_tls1_prf_md(Md::sha384()).unwrap();
ctx.set_tls1_prf_secret(&hex::decode("b80b733d6ceefcdc71566ea48e5567df").unwrap())
.unwrap();
ctx.add_tls1_prf_seed(&hex::decode("74657374206c6162656c").unwrap())
.unwrap();
ctx.add_tls1_prf_seed(&hex::decode("cd665cf6a8447dd6ff8b27555edb7465").unwrap())
.unwrap();
let mut out = [0u8; 148];
ctx.derive(Some(&mut out)).unwrap();

assert_eq!(
&out[..],
hex::decode("7b0c18e9ced410ed1804f2cfa34a336a1c14dffb4900bb5fd7942107e81c83cde9ca0faa60be9fe34f82b1233c9146a0e534cb400fed2700884f9dc236f80edd8bfa961144c9e8d792eca722a7b32fc3d416d473ebc2c5fd4abfdad05d9184259b5bf8cd4d90fa0d31e2dec479e4f1a26066f2eea9a69236a3e52655c9e9aee691c8f3a26854308d5eaa3be85e0990703d73e56f")
.unwrap()
);
}
}
Loading