nss/pk11/
context.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::{
6    error::*,
7    pk11::{
8        sym_key::import_sym_key,
9        types::{Context, SymKey},
10    },
11    util::{assert_nss_initialized, map_nss_secstatus, ScopedPtr},
12};
13use std::ptr;
14
15#[derive(Copy, Clone, Debug)]
16#[repr(u8)]
17pub enum HashAlgorithm {
18    SHA256,
19    SHA384,
20}
21
22impl HashAlgorithm {
23    fn result_len(&self) -> u32 {
24        match self {
25            HashAlgorithm::SHA256 => nss_sys::SHA256_LENGTH,
26            HashAlgorithm::SHA384 => nss_sys::SHA384_LENGTH,
27        }
28    }
29
30    fn as_hmac_mechanism(&self) -> u32 {
31        match self {
32            HashAlgorithm::SHA256 => nss_sys::CKM_SHA256_HMAC,
33            HashAlgorithm::SHA384 => nss_sys::CKM_SHA384_HMAC,
34        }
35    }
36
37    pub(crate) fn as_hkdf_mechanism(&self) -> u32 {
38        match self {
39            HashAlgorithm::SHA256 => nss_sys::CKM_NSS_HKDF_SHA256,
40            HashAlgorithm::SHA384 => nss_sys::CKM_NSS_HKDF_SHA384,
41        }
42    }
43}
44
45impl From<&HashAlgorithm> for nss_sys::SECOidTag {
46    fn from(alg: &HashAlgorithm) -> Self {
47        match alg {
48            HashAlgorithm::SHA256 => nss_sys::SECOidTag::SEC_OID_SHA256,
49            HashAlgorithm::SHA384 => nss_sys::SECOidTag::SEC_OID_SHA384,
50        }
51    }
52}
53
54pub fn hash_buf(algorithm: &HashAlgorithm, data: &[u8]) -> Result<Vec<u8>> {
55    assert_nss_initialized();
56    let result_len = usize::try_from(algorithm.result_len())?;
57    let mut out = vec![0u8; result_len];
58    let data_len = i32::try_from(data.len())?;
59    map_nss_secstatus(|| unsafe {
60        nss_sys::PK11_HashBuf(
61            Into::<nss_sys::SECOidTag>::into(algorithm) as u32,
62            out.as_mut_ptr(),
63            data.as_ptr(),
64            data_len,
65        )
66    })?;
67    Ok(out)
68}
69
70pub fn hmac_sign(digest_alg: &HashAlgorithm, sym_key_bytes: &[u8], data: &[u8]) -> Result<Vec<u8>> {
71    let mech = digest_alg.as_hmac_mechanism();
72    let sym_key = import_sym_key(mech.into(), nss_sys::CKA_SIGN.into(), sym_key_bytes)?;
73    let context = create_context_by_sym_key(mech.into(), nss_sys::CKA_SIGN.into(), &sym_key)?;
74    hash_buf_with_context(&context, data)
75}
76
77/// Similar to hash_buf except the consumer has to provide the digest context.
78fn hash_buf_with_context(context: &Context, data: &[u8]) -> Result<Vec<u8>> {
79    assert_nss_initialized();
80    map_nss_secstatus(|| unsafe { nss_sys::PK11_DigestBegin(context.as_mut_ptr()) })?;
81    let data_len = u32::try_from(data.len())?;
82    map_nss_secstatus(|| unsafe {
83        nss_sys::PK11_DigestOp(context.as_mut_ptr(), data.as_ptr(), data_len)
84    })?;
85    // We allocate the maximum possible length for the out buffer then we'll
86    // slice it after nss fills `out_len`.
87    let mut out_len: u32 = 0;
88    let mut out = vec![0u8; nss_sys::HASH_LENGTH_MAX as usize];
89    map_nss_secstatus(|| unsafe {
90        nss_sys::PK11_DigestFinal(
91            context.as_mut_ptr(),
92            out.as_mut_ptr(),
93            &mut out_len,
94            nss_sys::HASH_LENGTH_MAX,
95        )
96    })?;
97    out.truncate(usize::try_from(out_len)?);
98    Ok(out)
99}
100
101/// Safe wrapper around PK11_CreateContextBySymKey that
102/// de-allocates memory when the context goes out of
103/// scope.
104pub fn create_context_by_sym_key(
105    mechanism: nss_sys::CK_MECHANISM_TYPE,
106    operation: nss_sys::CK_ATTRIBUTE_TYPE,
107    sym_key: &SymKey,
108) -> Result<Context> {
109    assert_nss_initialized();
110    let param = nss_sys::SECItem {
111        type_: nss_sys::SECItemType::siBuffer as u32,
112        data: ptr::null_mut(),
113        len: 0,
114    };
115    unsafe {
116        Context::from_ptr(nss_sys::PK11_CreateContextBySymKey(
117            mechanism,
118            operation,
119            sym_key.as_mut_ptr(),
120            &param,
121        ))
122    }
123}