Coverage Report

Created: 2026-05-18 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/git/checkouts/nss-rs-71e20fe79ef91440/9b94ca3/src/hmac.rs
Line
Count
Source
1
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4
// option. This file may not be copied, modified, or distributed
5
// except according to those terms.
6
7
#![allow(non_camel_case_types)]
8
9
use std::{convert::TryFrom as _, ptr};
10
11
use pkcs11_bindings::CKA_SIGN;
12
13
use crate::{
14
    Error, SECItemBorrowed,
15
    err::IntoResult as _,
16
    hash::{self, HashAlgorithm},
17
    p11::{
18
        self, PK11_CreateContextBySymKey, PK11_DigestFinal, PK11_DigestOp, PK11_ImportSymKey,
19
        PK11Origin, SECOidTag, Slot,
20
    },
21
};
22
23
//
24
// Constants
25
//
26
27
pub enum HmacAlgorithm {
28
    HMAC_SHA2_256,
29
    HMAC_SHA2_384,
30
    HMAC_SHA2_512,
31
}
32
33
#[allow(clippy::allow_attributes)]
34
#[allow(clippy::useless_conversion)]
35
0
fn hmac_alg_to_ckm(alg: &HmacAlgorithm) -> p11::CK_MECHANISM_TYPE {
36
0
    match alg {
37
0
        HmacAlgorithm::HMAC_SHA2_256 => p11::CKM_SHA256_HMAC.into(),
38
0
        HmacAlgorithm::HMAC_SHA2_384 => p11::CKM_SHA384_HMAC.into(),
39
0
        HmacAlgorithm::HMAC_SHA2_512 => p11::CKM_SHA512_HMAC.into(),
40
    }
41
0
}
42
43
#[must_use]
44
0
pub const fn hmac_alg_to_hash_alg(alg: &HmacAlgorithm) -> HashAlgorithm {
45
0
    match alg {
46
0
        HmacAlgorithm::HMAC_SHA2_256 => HashAlgorithm::SHA2_256,
47
0
        HmacAlgorithm::HMAC_SHA2_384 => HashAlgorithm::SHA2_384,
48
0
        HmacAlgorithm::HMAC_SHA2_512 => HashAlgorithm::SHA2_512,
49
    }
50
0
}
51
52
#[must_use]
53
0
pub(crate) const fn hmac_alg_to_prf_oid(alg: &HmacAlgorithm) -> SECOidTag::Type {
54
0
    match alg {
55
0
        HmacAlgorithm::HMAC_SHA2_256 => SECOidTag::SEC_OID_HMAC_SHA256,
56
0
        HmacAlgorithm::HMAC_SHA2_384 => SECOidTag::SEC_OID_HMAC_SHA384,
57
0
        HmacAlgorithm::HMAC_SHA2_512 => SECOidTag::SEC_OID_HMAC_SHA512,
58
    }
59
0
}
60
61
#[must_use]
62
0
pub const fn hmac_alg_to_hmac_len(alg: &HmacAlgorithm) -> usize {
63
0
    let hash_alg = hmac_alg_to_hash_alg(alg);
64
0
    hash::hash_alg_to_hash_len(&hash_alg)
65
0
}
66
67
#[expect(clippy::cast_possible_truncation)]
68
0
pub fn hmac(alg: &HmacAlgorithm, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Error> {
69
0
    crate::init()?;
70
71
0
    let Ok(data_len) = u32::try_from(data.len()) else {
72
0
        return Err(Error::Internal);
73
    };
74
75
0
    let slot = Slot::internal()?;
76
0
    let sym_key = unsafe {
77
0
        PK11_ImportSymKey(
78
0
            *slot,
79
0
            hmac_alg_to_ckm(alg),
80
            PK11Origin::PK11_OriginUnwrap,
81
            CKA_SIGN,
82
0
            SECItemBorrowed::wrap(key)?.as_mut(),
83
0
            ptr::null_mut(),
84
        )
85
0
        .into_result()?
86
    };
87
0
    let param = SECItemBorrowed::make_empty();
88
0
    let context = unsafe {
89
0
        PK11_CreateContextBySymKey(hmac_alg_to_ckm(alg), CKA_SIGN, *sym_key, param.as_ref())
90
0
            .into_result()?
91
    };
92
    unsafe {
93
0
        PK11_DigestOp(*context, data.as_ptr(), data_len).into_result()?;
94
    }
95
0
    let expected_len = hmac_alg_to_hmac_len(alg);
96
0
    let mut digest = vec![0u8; expected_len];
97
0
    let mut digest_len = 0u32;
98
    unsafe {
99
0
        PK11_DigestFinal(
100
0
            *context,
101
0
            digest.as_mut_ptr(),
102
0
            &raw mut digest_len,
103
0
            digest.len() as u32,
104
        )
105
0
        .into_result()?;
106
    }
107
0
    assert_eq!(digest_len as usize, expected_len);
108
0
    Ok(digest)
109
0
}