44// option. This file may not be copied, modified, or distributed
55// except according to those terms.
66
7+ #[ cfg( not( feature = "disable-encryption" ) ) ]
8+ use std:: os:: raw:: { c_char, c_uint} ;
9+ #[ cfg( not( feature = "disable-encryption" ) ) ]
10+ use std:: ptr:: null;
711use std:: { os:: raw:: c_int, ptr:: null_mut} ;
812
913#[ cfg( feature = "disable-encryption" ) ]
1014pub use recprot:: AEAD_NULL_TAG ;
1115pub use recprot:: RecordProtection ;
1216
1317use crate :: {
14- SECItemBorrowed , SymKey ,
15- err:: { Error , Res } ,
18+ Cipher , SECItemBorrowed , SymKey ,
19+ constants:: { TLS_AES_128_GCM_SHA256 , TLS_AES_256_GCM_SHA384 , TLS_CHACHA20_POLY1305_SHA256 } ,
20+ err:: { Error , Res , sec:: SEC_ERROR_BAD_DATA } ,
1621 p11:: {
1722 self , CK_ATTRIBUTE_TYPE , CK_GENERATOR_FUNCTION , CK_MECHANISM_TYPE , CKA_DECRYPT ,
1823 CKA_ENCRYPT , CKA_NSS_MESSAGE , CKG_GENERATE_COUNTER_XOR , CKG_NO_GENERATE , CKM_AES_GCM ,
1924 CKM_CHACHA20_POLY1305 , Context , PK11_AEADOp , PK11_CreateContextBySymKey ,
2025 } ,
2126 secstatus_to_res,
2227} ;
28+ #[ cfg( not( feature = "disable-encryption" ) ) ]
29+ use crate :: {
30+ Version ,
31+ hp:: SSL_HkdfExpandLabelWithMech ,
32+ p11:: { CKM_HKDF_DATA , PK11SymKey } ,
33+ } ;
34+
35+ #[ cfg( all( feature = "blapi" , feature = "disable-encryption" ) ) ]
36+ compile_error ! ( "`blapi` and `disable-encryption` are mutually exclusive features" ) ;
37+
38+ /// Shared API contract for all `RecordProtection` backends.
39+ ///
40+ /// Implemented by each cfg-selected `recprot*.rs` backend so that a
41+ /// signature change in one backend is caught at compile time across all.
42+ /// Import this trait to call AEAD methods on `RecordProtection`.
43+ pub trait RecordProtectionOps {
44+ /// Get the expansion size (authentication tag length) for this AEAD.
45+ #[ must_use]
46+ fn expansion ( & self ) -> usize ;
47+
48+ /// Encrypt plaintext with associated data.
49+ ///
50+ /// # Errors
51+ ///
52+ /// Returns `Error` when encryption fails.
53+ fn encrypt < ' a > (
54+ & self ,
55+ count : u64 ,
56+ aad : & [ u8 ] ,
57+ input : & [ u8 ] ,
58+ output : & ' a mut [ u8 ] ,
59+ ) -> Res < & ' a [ u8 ] > ;
60+
61+ /// Encrypt plaintext in place with associated data.
62+ ///
63+ /// # Errors
64+ ///
65+ /// Returns `Error` when encryption fails.
66+ fn encrypt_in_place ( & self , count : u64 , aad : & [ u8 ] , data : & mut [ u8 ] ) -> Res < usize > ;
67+
68+ /// Decrypt ciphertext with associated data.
69+ ///
70+ /// # Errors
71+ ///
72+ /// Returns `Error` when decryption or authentication fails.
73+ fn decrypt < ' a > (
74+ & self ,
75+ count : u64 ,
76+ aad : & [ u8 ] ,
77+ input : & [ u8 ] ,
78+ output : & ' a mut [ u8 ] ,
79+ ) -> Res < & ' a [ u8 ] > ;
80+
81+ /// Decrypt ciphertext in place with associated data.
82+ ///
83+ /// # Errors
84+ ///
85+ /// Returns `Error` when decryption or authentication fails.
86+ fn decrypt_in_place ( & self , count : u64 , aad : & [ u8 ] , data : & mut [ u8 ] ) -> Res < usize > ;
87+ }
2388
2489#[ cfg_attr( feature = "disable-encryption" , path = "recprot_null.rs" ) ]
25- #[ cfg_attr( not( feature = "disable-encryption" ) , path = "recprot.rs" ) ]
90+ #[ cfg_attr(
91+ all( not( feature = "disable-encryption" ) , feature = "blapi" ) ,
92+ path = "recprot_blapi.rs"
93+ ) ]
94+ #[ cfg_attr(
95+ all( not( feature = "disable-encryption" ) , not( feature = "blapi" ) ) ,
96+ path = "recprot.rs"
97+ ) ]
2698mod recprot;
2799
100+ #[ cfg( not( feature = "disable-encryption" ) ) ]
101+ fn expand_label (
102+ version : Version ,
103+ cipher : Cipher ,
104+ secret : & SymKey ,
105+ label : & str ,
106+ mech : CK_MECHANISM_TYPE ,
107+ key_len : c_uint ,
108+ ) -> Res < SymKey > {
109+ let mut ptr: * mut PK11SymKey = null_mut ( ) ;
110+ unsafe {
111+ SSL_HkdfExpandLabelWithMech (
112+ version,
113+ cipher,
114+ * * secret,
115+ null ( ) ,
116+ 0 ,
117+ label. as_ptr ( ) . cast :: < c_char > ( ) ,
118+ c_uint:: try_from ( label. len ( ) ) ?,
119+ mech,
120+ key_len,
121+ & raw mut ptr,
122+ )
123+ } ?;
124+ SymKey :: from_ptr ( ptr)
125+ }
126+
127+ #[ cfg( not( feature = "disable-encryption" ) ) ]
128+ fn expand_hkdf_label (
129+ version : Version ,
130+ cipher : Cipher ,
131+ secret : & SymKey ,
132+ label : & str ,
133+ key_len : c_uint ,
134+ ) -> Res < SymKey > {
135+ expand_label (
136+ version,
137+ cipher,
138+ secret,
139+ label,
140+ CK_MECHANISM_TYPE :: from ( CKM_HKDF_DATA ) ,
141+ key_len,
142+ )
143+ }
144+
28145/// All the nonces are the same length. Exploit that.
29146pub const NONCE_LEN : usize = 12 ;
30147
@@ -46,6 +163,18 @@ fn xor_nonce(base: &[u8; NONCE_LEN], count: SequenceNumber) -> [u8; NONCE_LEN] {
46163/// All of the AEAD functions here have a tag of this length, so use a fixed offset.
47164const TAG_LEN : usize = 16 ;
48165
166+ /// Split `data` into `(ct_len, tag)`, returning `SEC_ERROR_BAD_DATA` if it is
167+ /// too short to contain a tag.
168+ fn split_tag ( data : & [ u8 ] ) -> Res < ( usize , [ u8 ; TAG_LEN ] ) > {
169+ let ct_len = data
170+ . len ( )
171+ . checked_sub ( TAG_LEN )
172+ . ok_or_else ( || Error :: from ( SEC_ERROR_BAD_DATA ) ) ?;
173+ let mut tag = [ 0u8 ; TAG_LEN ] ;
174+ tag. copy_from_slice ( & data[ ct_len..] ) ;
175+ Ok ( ( ct_len, tag) )
176+ }
177+
49178pub type SequenceNumber = u64 ;
50179
51180/// All the lengths used by `PK11_AEADOp` are signed. This converts to that.
@@ -82,20 +211,43 @@ pub enum AeadAlgorithms {
82211 ChaCha20Poly1305 ,
83212}
84213
214+ impl AeadAlgorithms {
215+ #[ must_use]
216+ pub const fn key_len ( self ) -> usize {
217+ match self {
218+ Self :: Aes128Gcm => 16 ,
219+ Self :: Aes256Gcm | Self :: ChaCha20Poly1305 => 32 ,
220+ }
221+ }
222+
223+ #[ must_use]
224+ pub fn p11_mech ( self ) -> CK_MECHANISM_TYPE {
225+ CK_MECHANISM_TYPE :: from ( match self {
226+ Self :: Aes128Gcm | Self :: Aes256Gcm => CKM_AES_GCM ,
227+ Self :: ChaCha20Poly1305 => CKM_CHACHA20_POLY1305 ,
228+ } )
229+ }
230+ }
231+
232+ impl TryFrom < Cipher > for AeadAlgorithms {
233+ type Error = Error ;
234+ fn try_from ( cipher : Cipher ) -> Res < Self > {
235+ match cipher {
236+ TLS_AES_128_GCM_SHA256 => Ok ( Self :: Aes128Gcm ) ,
237+ TLS_AES_256_GCM_SHA384 => Ok ( Self :: Aes256Gcm ) ,
238+ TLS_CHACHA20_POLY1305_SHA256 => Ok ( Self :: ChaCha20Poly1305 ) ,
239+ _ => Err ( Error :: UnsupportedCipher ) ,
240+ }
241+ }
242+ }
243+
85244pub struct Aead {
86245 mode : Mode ,
87246 ctx : Context ,
88247 nonce_base : [ u8 ; NONCE_LEN ] ,
89248}
90249
91250impl Aead {
92- fn mech ( algorithm : AeadAlgorithms ) -> CK_MECHANISM_TYPE {
93- CK_MECHANISM_TYPE :: from ( match algorithm {
94- AeadAlgorithms :: Aes128Gcm | AeadAlgorithms :: Aes256Gcm => CKM_AES_GCM ,
95- AeadAlgorithms :: ChaCha20Poly1305 => CKM_CHACHA20_POLY1305 ,
96- } )
97- }
98-
99251 pub fn import_key ( algorithm : AeadAlgorithms , key : & [ u8 ] ) -> Result < SymKey , Error > {
100252 let slot = p11:: Slot :: internal ( ) . map_err ( |_| Error :: Internal ) ?;
101253
@@ -105,7 +257,7 @@ impl Aead {
105257 let ptr = unsafe {
106258 p11:: PK11_ImportSymKey (
107259 * slot,
108- Self :: mech ( algorithm) ,
260+ algorithm. p11_mech ( ) ,
109261 p11:: PK11Origin :: PK11_OriginUnwrap ,
110262 CK_ATTRIBUTE_TYPE :: from ( CKA_ENCRYPT | CKA_DECRYPT ) ,
111263 key_item_ptr,
@@ -125,7 +277,7 @@ impl Aead {
125277
126278 let ptr = unsafe {
127279 PK11_CreateContextBySymKey (
128- Self :: mech ( algorithm) ,
280+ algorithm. p11_mech ( ) ,
129281 mode. p11mode ( ) ,
130282 * * key,
131283 SECItemBorrowed :: wrap ( & nonce_base[ ..] ) ?. as_ref ( ) ,
0 commit comments