boring 5.1.0

BoringSSL bindings
Documentation
//! TLS pseudo-random function helpers.
//!
//! This module exposes the TLS 1.2 PRF as defined in RFC 5246, Section 5.
//!
//! # Example
//!
//! ```
//! use boring::hash::MessageDigest;
//!
//! let mut out = [0u8; 48];
//! boring::prf::tls1_prf(
//!     MessageDigest::sha256(),
//!     &mut out,
//!     b"secret",
//!     b"label",
//!     b"seed",
//! )
//! .unwrap();
//! ```

use std::ptr;

use openssl_macros::corresponds;

use crate::cvt;
use crate::error::ErrorStack;
use crate::ffi;
use crate::hash::MessageDigest;

/// Computes TLS 1.2 PRF output using `digest`.
///
/// `seed` should contain the full PRF seed for the calling protocol. In TLS
/// 1.2 this is often a concatenation of random values.
#[corresponds(CRYPTO_tls1_prf)]
pub fn tls1_prf(
    digest: MessageDigest,
    out: &mut [u8],
    secret: &[u8],
    label: &[u8],
    seed: &[u8],
) -> Result<(), ErrorStack> {
    unsafe {
        ffi::init();

        cvt(ffi::internal::CRYPTO_tls1_prf(
            digest.as_ptr(),
            out.as_mut_ptr(),
            out.len(),
            secret.as_ptr(),
            secret.len(),
            label.as_ptr(),
            label.len(),
            seed.as_ptr(),
            seed.len(),
            ptr::null(),
            0,
        ))
    }
}

#[cfg(test)]
mod tests {
    use hex::FromHex;

    use crate::hash::MessageDigest;

    #[test]
    fn tls12_prf_vectors() {
        struct TestVector {
            name: &'static str,
            digest: fn() -> MessageDigest,
            secret: &'static str,
            label: &'static [u8],
            seed: &'static str,
            expected: &'static str,
        }

        // Test vectors from:
        // https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/
        let vectors = [
            TestVector {
                name: "TLS1.2 PRF-SHA224",
                digest: MessageDigest::sha224,
                secret: "e1 88 28 74 03 52 b5 30 d6 9b 34 c6 59 7d ea 2e",
                label: b"test label",
                seed: "f5 a3 fe 6d 34 e2 e2 85 60 fd ca f6 82 3f 90 91",
                expected: "
                    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 {
                name: "TLS1.2 PRF-SHA256",
                digest: MessageDigest::sha256,
                secret: "9b be 43 6b a9 40 f0 17 b1 76 52 84 9a 71 db 35",
                label: b"test label",
                seed: "a0 ba 9f 93 6c da 31 18 27 a6 f7 96 ff d5 19 8c",
                expected: "
                    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 {
                name: "TLS1.2 PRF-SHA512",
                digest: MessageDigest::sha512,
                secret: "b0 32 35 23 c1 85 35 99 58 4d 88 56 8b bb 05 eb",
                label: b"test label",
                seed: "d4 64 0e 12 e4 bc db fb 43 7f 03 e6 ae 41 8e e5",
                expected: "
                    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 {
                name: "TLS1.2 PRF-SHA384",
                digest: MessageDigest::sha384,
                secret: "b8 0b 73 3d 6c ee fc dc 71 56 6e a4 8e 55 67 df",
                label: b"test label",
                seed: "cd 66 5c f6 a8 44 7d d6 ff 8b 27 55 5e db 74 65",
                expected: "
                    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 vector in vectors {
            let secret = decode_hex(vector.secret);
            let seed = decode_hex(vector.seed);
            let expected = decode_hex(vector.expected);
            let mut out = vec![0u8; expected.len()];

            super::tls1_prf(
                (vector.digest)(),
                out.as_mut_slice(),
                secret.as_slice(),
                vector.label,
                seed.as_slice(),
            )
            .unwrap();

            assert_eq!(out, expected, "{}", vector.name);
        }
    }

    fn decode_hex(input: &str) -> Vec<u8> {
        let compact: String = input.chars().filter(|c| !c.is_whitespace()).collect();
        Vec::from_hex(compact).unwrap()
    }
}