Use boringssl prf for tls1.2
This commit is contained in:
parent
bd80bfc4d7
commit
d38412a3bd
9 changed files with 285 additions and 7 deletions
|
|
@ -2,6 +2,8 @@
|
||||||
members = [
|
members = [
|
||||||
# things that should probably be in boring crate
|
# things that should probably be in boring crate
|
||||||
"boring-additions",
|
"boring-additions",
|
||||||
|
# things that should probably be in boring-sys crate
|
||||||
|
"boring-sys-additions",
|
||||||
# the main library and tests
|
# the main library and tests
|
||||||
"boring-rustls-provider",
|
"boring-rustls-provider",
|
||||||
# tests and example code
|
# tests and example code
|
||||||
|
|
|
||||||
20
Readme.md
20
Readme.md
|
|
@ -17,6 +17,18 @@ AES_256_GCM_SHA384
|
||||||
CHACHA20_POLY1305_SHA256
|
CHACHA20_POLY1305_SHA256
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TLS 1.2 prepared for (doesn't work yet):
|
||||||
|
```
|
||||||
|
ECDHE_ECDSA_AES128_GCM_SHA256
|
||||||
|
ECDHE_RSA_AES128_GCM_SHA256
|
||||||
|
|
||||||
|
ECDHE_ECDSA_AES256_GCM_SHA384
|
||||||
|
ECDHE_RSA_AES256_GCM_SHA384
|
||||||
|
|
||||||
|
ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
||||||
|
ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
||||||
|
```
|
||||||
|
|
||||||
### Key Exchange Algorithms
|
### Key Exchange Algorithms
|
||||||
|
|
||||||
`ECDHE` with curves:
|
`ECDHE` with curves:
|
||||||
|
|
@ -37,10 +49,10 @@ ffdhe2048
|
||||||
### Signature Generation / Verification
|
### Signature Generation / Verification
|
||||||
|
|
||||||
```
|
```
|
||||||
RSA_PKCS1_SHA256,
|
RSA_PKCS1_SHA256
|
||||||
RSA_PKCS1_SHA384,
|
RSA_PKCS1_SHA384
|
||||||
RSA_PKCS1_SHA512,
|
RSA_PKCS1_SHA512
|
||||||
RSA_PSS_SHA256,
|
RSA_PSS_SHA256
|
||||||
RSA_PSS_SHA384
|
RSA_PSS_SHA384
|
||||||
RSA_PSS_SHA512
|
RSA_PSS_SHA512
|
||||||
ECDSA_NISTP256_SHA256
|
ECDSA_NISTP256_SHA256
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ aead = {version = "0.5", default_features = false, features = ["alloc"] }
|
||||||
boring = { workspace = true }
|
boring = { workspace = true }
|
||||||
boring-additions = { path = "../boring-additions" }
|
boring-additions = { path = "../boring-additions" }
|
||||||
boring-sys = { workspace = true }
|
boring-sys = { workspace = true }
|
||||||
|
boring-sys-additions = { path = "../boring-sys-additions" }
|
||||||
foreign-types = "0.5"
|
foreign-types = "0.5"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
log = { version = "0.4.4", optional = true }
|
log = { version = "0.4.4", optional = true }
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ use crate::helper::{cvt, cvt_p};
|
||||||
/// A SHA256-based Hmac
|
/// A SHA256-based Hmac
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub const SHA256: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA256);
|
pub const SHA256: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA256);
|
||||||
|
|
||||||
/// A SHA384-based Hmac
|
/// A SHA384-based Hmac
|
||||||
|
#[allow(unused)]
|
||||||
pub const SHA384: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA384);
|
pub const SHA384: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA384);
|
||||||
|
|
||||||
struct BoringHmac(pub boring::nid::Nid);
|
struct BoringHmac(pub boring::nid::Nid);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ mod helper;
|
||||||
mod hkdf;
|
mod hkdf;
|
||||||
mod hmac;
|
mod hmac;
|
||||||
mod kx;
|
mod kx;
|
||||||
|
#[cfg(feature = "tls12")]
|
||||||
|
mod prf;
|
||||||
mod sign;
|
mod sign;
|
||||||
#[cfg(feature = "tls12")]
|
#[cfg(feature = "tls12")]
|
||||||
mod tls12;
|
mod tls12;
|
||||||
|
|
|
||||||
222
boring-rustls-provider/src/prf.rs
Normal file
222
boring-rustls-provider/src/prf.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use boring::error::ErrorStack;
|
||||||
|
use rustls::crypto;
|
||||||
|
|
||||||
|
use crate::helper::{cvt, log_and_map};
|
||||||
|
|
||||||
|
pub struct PrfTls1WithDigest(pub boring::nid::Nid);
|
||||||
|
|
||||||
|
pub struct MySecret(Vec<u8>);
|
||||||
|
|
||||||
|
impl crypto::tls12::Prf for PrfTls1WithDigest {
|
||||||
|
fn for_key_exchange(
|
||||||
|
&self,
|
||||||
|
output: &mut [u8],
|
||||||
|
kx: Box<dyn crypto::ActiveKeyExchange>,
|
||||||
|
peer_pub_key: &[u8],
|
||||||
|
label: &[u8],
|
||||||
|
seed: &[u8],
|
||||||
|
) -> Result<(), rustls::Error> {
|
||||||
|
let digest = boring::hash::MessageDigest::from_nid(self.0)
|
||||||
|
.ok_or(rustls::Error::General("invalid digest for prf".into()))?;
|
||||||
|
|
||||||
|
let secret = kx.complete(peer_pub_key)?;
|
||||||
|
|
||||||
|
let secret: MySecret = unsafe {
|
||||||
|
// I don't see another way to get to the secret...
|
||||||
|
std::mem::transmute(secret)
|
||||||
|
};
|
||||||
|
|
||||||
|
prf(digest, output, &secret.0, label, seed)
|
||||||
|
.map_err(|e| log_and_map("prf", e, rustls::Error::General("failed on prf".into())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]) {
|
||||||
|
let digest = boring::hash::MessageDigest::from_nid(self.0).expect("failed getting digest");
|
||||||
|
prf(digest, output, secret, label, seed).expect("failed calculating prf")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prf(
|
||||||
|
digest: boring::hash::MessageDigest,
|
||||||
|
output: &mut [u8],
|
||||||
|
secret: &[u8],
|
||||||
|
label: &[u8],
|
||||||
|
seed: &[u8],
|
||||||
|
) -> Result<(), ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
// seed is already concatenated from the randoms, so we
|
||||||
|
// can simply pass it in as a single seed
|
||||||
|
cvt(boring_sys_additions::CRYPTO_tls1_prf(
|
||||||
|
digest.as_ptr(),
|
||||||
|
output.as_mut_ptr(),
|
||||||
|
output.len(),
|
||||||
|
secret.as_ptr(),
|
||||||
|
secret.len(),
|
||||||
|
label.as_ptr(),
|
||||||
|
label.len(),
|
||||||
|
seed.as_ptr(),
|
||||||
|
seed.len(),
|
||||||
|
ptr::null(),
|
||||||
|
0,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use hex_literal::hex;
|
||||||
|
|
||||||
|
use crate::prf::prf;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tls12_prf() {
|
||||||
|
struct TestVector {
|
||||||
|
test_name: &'static str,
|
||||||
|
digest: boring::nid::Nid,
|
||||||
|
secret: &'static [u8],
|
||||||
|
label: &'static [u8],
|
||||||
|
seed: &'static [u8],
|
||||||
|
expected_output: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
// test vectors taken from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/
|
||||||
|
let inputs = &[
|
||||||
|
TestVector {
|
||||||
|
test_name: "88 bytes of pseudo-randomness using TLS1.2PRF-SHA224",
|
||||||
|
digest: boring::nid::Nid::SHA224,
|
||||||
|
secret: &hex!("e1 88 28 74 03 52 b5 30 d6 9b 34 c6 59 7d ea 2e"),
|
||||||
|
label: b"test label",
|
||||||
|
seed: &hex!("f5 a3 fe 6d 34 e2 e2 85 60 fd ca f6 82 3f 90 91"),
|
||||||
|
expected_output: &hex!(
|
||||||
|
"
|
||||||
|
22 4d 8a f3 c0 45 33 93
|
||||||
|
a9 77 97 89 d2 1c f7 da
|
||||||
|
5e e6 2a e6 b6 17 87 3d
|
||||||
|
48 94 28 ef c8 dd 58 d1
|
||||||
|
56 6e 70 29 e2 ca 3a 5e
|
||||||
|
cd 35 5d c6 4d 4d 92 7e
|
||||||
|
2f bd 78 c4 23 3e 86 04
|
||||||
|
b1 47 49 a7 7a 92 a7 0f
|
||||||
|
dd f6 14 bc 0d f6 23 d7
|
||||||
|
98 60 4e 4c a5 51 27 94
|
||||||
|
d8 02 a2 58 e8 2f 86 cf
|
||||||
|
"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
test_name: "100 bytes of pseudo-randomness using TLS1.2PRF-SHA256",
|
||||||
|
digest: boring::nid::Nid::SHA256,
|
||||||
|
secret: &hex!("9b be 43 6b a9 40 f0 17 b1 76 52 84 9a 71 db 35"),
|
||||||
|
label: b"test label",
|
||||||
|
seed: &hex!("a0 ba 9f 93 6c da 31 18 27 a6 f7 96 ff d5 19 8c"),
|
||||||
|
|
||||||
|
expected_output: &hex!(
|
||||||
|
"
|
||||||
|
e3 f2 29 ba 72 7b e1 7b
|
||||||
|
8d 12 26 20 55 7c d4 53
|
||||||
|
c2 aa b2 1d 07 c3 d4 95
|
||||||
|
32 9b 52 d4 e6 1e db 5a
|
||||||
|
6b 30 17 91 e9 0d 35 c9
|
||||||
|
c9 a4 6b 4e 14 ba f9 af
|
||||||
|
0f a0 22 f7 07 7d ef 17
|
||||||
|
ab fd 37 97 c0 56 4b ab
|
||||||
|
4f bc 91 66 6e 9d ef 9b
|
||||||
|
97 fc e3 4f 79 67 89 ba
|
||||||
|
a4 80 82 d1 22 ee 42 c5
|
||||||
|
a7 2e 5a 51 10 ff f7 01
|
||||||
|
87 34 7b 66
|
||||||
|
"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
test_name: "196 bytes of pseudo-randomness using TLS1.2PRF-SHA512",
|
||||||
|
digest: boring::nid::Nid::SHA512,
|
||||||
|
secret: &hex!("b0 32 35 23 c1 85 35 99 58 4d 88 56 8b bb 05 eb"),
|
||||||
|
label: b"test label",
|
||||||
|
seed: &hex!("d4 64 0e 12 e4 bc db fb 43 7f 03 e6 ae 41 8e e5"),
|
||||||
|
expected_output: &hex!(
|
||||||
|
"
|
||||||
|
12 61 f5 88 c7 98 c5 c2
|
||||||
|
01 ff 03 6e 7a 9c b5 ed
|
||||||
|
cd 7f e3 f9 4c 66 9a 12
|
||||||
|
2a 46 38 d7 d5 08 b2 83
|
||||||
|
04 2d f6 78 98 75 c7 14
|
||||||
|
7e 90 6d 86 8b c7 5c 45
|
||||||
|
e2 0e b4 0c 1c f4 a1 71
|
||||||
|
3b 27 37 1f 68 43 25 92
|
||||||
|
f7 dc 8e a8 ef 22 3e 12
|
||||||
|
ea 85 07 84 13 11 bf 68
|
||||||
|
65 3d 0c fc 40 56 d8 11
|
||||||
|
f0 25 c4 5d df a6 e6 fe
|
||||||
|
c7 02 f0 54 b4 09 d6 f2
|
||||||
|
8d d0 a3 23 3e 49 8d a4
|
||||||
|
1a 3e 75 c5 63 0e ed be
|
||||||
|
22 fe 25 4e 33 a1 b0 e9
|
||||||
|
f6 b9 82 66 75 be c7 d0
|
||||||
|
1a 84 56 58 dc 9c 39 75
|
||||||
|
45 40 1d 40 b9 f4 6c 7a
|
||||||
|
40 0e e1 b8 f8 1c a0 a6
|
||||||
|
0d 1a 39 7a 10 28 bf f5
|
||||||
|
d2 ef 50 66 12 68 42 fb
|
||||||
|
8d a4 19 76 32 bd b5 4f
|
||||||
|
f6 63 3f 86 bb c8 36 e6
|
||||||
|
40 d4 d8 98
|
||||||
|
"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
test_name: "148 bytes of pseudo-randomness using TLS1.2PRF-SHA384",
|
||||||
|
digest: boring::nid::Nid::SHA384,
|
||||||
|
secret: &hex!("b8 0b 73 3d 6c ee fc dc 71 56 6e a4 8e 55 67 df"),
|
||||||
|
label: b"test label",
|
||||||
|
seed: &hex!("cd 66 5c f6 a8 44 7d d6 ff 8b 27 55 5e db 74 65"),
|
||||||
|
expected_output: &hex!(
|
||||||
|
"
|
||||||
|
7b 0c 18 e9 ce d4 10 ed
|
||||||
|
18 04 f2 cf a3 4a 33 6a
|
||||||
|
1c 14 df fb 49 00 bb 5f
|
||||||
|
d7 94 21 07 e8 1c 83 cd
|
||||||
|
e9 ca 0f aa 60 be 9f e3
|
||||||
|
4f 82 b1 23 3c 91 46 a0
|
||||||
|
e5 34 cb 40 0f ed 27 00
|
||||||
|
88 4f 9d c2 36 f8 0e dd
|
||||||
|
8b fa 96 11 44 c9 e8 d7
|
||||||
|
92 ec a7 22 a7 b3 2f c3
|
||||||
|
d4 16 d4 73 eb c2 c5 fd
|
||||||
|
4a bf da d0 5d 91 84 25
|
||||||
|
9b 5b f8 cd 4d 90 fa 0d
|
||||||
|
31 e2 de c4 79 e4 f1 a2
|
||||||
|
60 66 f2 ee a9 a6 92 36
|
||||||
|
a3 e5 26 55 c9 e9 ae e6
|
||||||
|
91 c8 f3 a2 68 54 30 8d
|
||||||
|
5e aa 3b e8 5e 09 90 70
|
||||||
|
3d 73 e5 6f
|
||||||
|
"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for input in inputs {
|
||||||
|
let digest = boring::hash::MessageDigest::from_nid(input.digest).unwrap();
|
||||||
|
let mut calculated_output = vec![0u8; input.expected_output.len()];
|
||||||
|
prf(
|
||||||
|
digest,
|
||||||
|
calculated_output.as_mut(),
|
||||||
|
input.secret,
|
||||||
|
input.label,
|
||||||
|
input.seed,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
calculated_output.as_slice(),
|
||||||
|
input.expected_output,
|
||||||
|
"test: {} failed",
|
||||||
|
input.test_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use rustls::{crypto, SignatureScheme, Tls12CipherSuite};
|
use rustls::{crypto, SignatureScheme, Tls12CipherSuite};
|
||||||
|
|
||||||
use crate::{aead, hash, hmac};
|
use crate::{aead, hash, prf};
|
||||||
|
|
||||||
static ALL_ECDSA_SCHEMES: &[SignatureScheme] = &[
|
static ALL_ECDSA_SCHEMES: &[SignatureScheme] = &[
|
||||||
SignatureScheme::ECDSA_NISTP256_SHA256,
|
SignatureScheme::ECDSA_NISTP256_SHA256,
|
||||||
|
|
@ -19,8 +19,8 @@ static ALL_RSA_SCHEMES: &[SignatureScheme] = &[
|
||||||
SignatureScheme::RSA_PSS_SHA512,
|
SignatureScheme::RSA_PSS_SHA512,
|
||||||
];
|
];
|
||||||
|
|
||||||
const PRF_SHA256: crypto::tls12::PrfUsingHmac<'_> = crypto::tls12::PrfUsingHmac(hmac::SHA256);
|
const PRF_SHA256: prf::PrfTls1WithDigest = prf::PrfTls1WithDigest(boring::nid::Nid::SHA256);
|
||||||
const PRF_SHA384: crypto::tls12::PrfUsingHmac<'_> = crypto::tls12::PrfUsingHmac(hmac::SHA384);
|
const PRF_SHA384: prf::PrfTls1WithDigest = prf::PrfTls1WithDigest(boring::nid::Nid::SHA384);
|
||||||
|
|
||||||
pub static ECDHE_ECDSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite {
|
pub static ECDHE_ECDSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite {
|
||||||
common: rustls::CipherSuiteCommon {
|
common: rustls::CipherSuiteCommon {
|
||||||
|
|
|
||||||
15
boring-sys-additions/Cargo.toml
Normal file
15
boring-sys-additions/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "boring-sys-additions"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Jan Rüth <boring-rustls-provider@djiehmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT"
|
||||||
|
description = "Boring-sys additions"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
boring-sys = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
22
boring-sys-additions/src/lib.rs
Normal file
22
boring-sys-additions/src/lib.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
use std::ffi;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
/// Calculates `out_len` bytes of the TLS PDF, using `digest`, and
|
||||||
|
/// writes them to `out`. It returns one on success and zero on error.
|
||||||
|
///
|
||||||
|
/// This isn't part of the public headers in `BoringSSL` but it is exported
|
||||||
|
/// in `crypto/fipsmodule/tls/internal.h` :)
|
||||||
|
pub fn CRYPTO_tls1_prf(
|
||||||
|
digest: *const boring_sys::EVP_MD,
|
||||||
|
out: *mut u8,
|
||||||
|
out_len: usize,
|
||||||
|
secret: *const u8,
|
||||||
|
secret_len: usize,
|
||||||
|
label: *const u8,
|
||||||
|
label_len: usize,
|
||||||
|
seed1: *const u8,
|
||||||
|
seed1_len: usize,
|
||||||
|
seed2: *const u8,
|
||||||
|
seed2_len: usize,
|
||||||
|
) -> ffi::c_int;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue