From a555d5290a8eeadd96e8258c9967a7e517cd6d26 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 12 Jan 2026 13:40:21 -0500 Subject: [PATCH 01/27] Rust wrapper: add HMAC-BLAKE2[bs] wrappers --- wrapper/rust/wolfssl-wolfcrypt/build.rs | 2 + wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs | 271 +++++++++++++++++- .../wolfssl-wolfcrypt/tests/test_blake2.rs | 117 ++++++++ 3 files changed, 389 insertions(+), 1 deletion(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 78adbbc3b2..608c100e27 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/build.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/build.rs @@ -128,7 +128,9 @@ fn scan_cfg() -> Result<()> { /* blake2 */ check_cfg(&binding, "wc_InitBlake2b", "blake2b"); + check_cfg(&binding, "wc_Blake2bHmac", "blake2b_hmac"); check_cfg(&binding, "wc_InitBlake2s", "blake2s"); + check_cfg(&binding, "wc_Blake2sHmac", "blake2s_hmac"); /* chacha20_poly1305 */ check_cfg(&binding, "wc_ChaCha20Poly1305_Encrypt", "chacha20_poly1305"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs b/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs index 9a4478c478..afd36bf623 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs @@ -167,6 +167,141 @@ impl BLAKE2b { } } + +/// Context for HMAC-BLAKE2b computation. +#[cfg(blake2b_hmac)] +pub struct BLAKE2bHmac { + wc_blake2b: sys::Blake2b, +} + +#[cfg(blake2b_hmac)] +impl BLAKE2bHmac { + /// Build a new BLAKE2bHmac instance. + /// + /// # Parameters + /// + /// * `key`: Key to use for HMAC-BLAKE2b computation. + /// + /// # Returns + /// + /// Returns either Ok(hmac_blake2b) or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// use wolfssl_wolfcrypt::blake2::BLAKE2bHmac; + /// let key = [42u8, 43, 44]; + /// let hmac_blake2b = BLAKE2bHmac::new(&key).expect("Error with new()"); + /// ``` + pub fn new(key: &[u8]) -> Result { + let mut wc_blake2b: MaybeUninit = MaybeUninit::uninit(); + let rc = unsafe { + sys::wc_Blake2bHmacInit(wc_blake2b.as_mut_ptr(), key.as_ptr(), key.len()) + }; + if rc != 0 { + return Err(rc); + } + let wc_blake2b = unsafe { wc_blake2b.assume_init() }; + let hmac_blake2b = BLAKE2bHmac { wc_blake2b }; + Ok(hmac_blake2b) + } + + /// Update the HMAC-BLAKE2b computation with the input data. + /// + /// This method may be called several times and then the finalize() + /// method should be called to retrieve the final MAC. + /// + /// # Parameters + /// + /// * `data`: Input data to hash. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// use wolfssl_wolfcrypt::blake2::BLAKE2bHmac; + /// let key = [42u8, 43, 44]; + /// let mut hmac_blake2b = BLAKE2bHmac::new(&key).expect("Error with new()"); + /// let data = [33u8, 34, 35]; + /// hmac_blake2b.update(&data).expect("Error with update()"); + /// ``` + pub fn update(&mut self, data: &[u8]) -> Result<(), i32> { + let rc = unsafe { + sys::wc_Blake2bHmacUpdate(&mut self.wc_blake2b, data.as_ptr(), data.len()) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } + + /// Compute and retrieve the final HMAC-BLAKE2b MAC. + /// + /// # Parameters + /// + /// * `key`: Key to use for HMAC-BLAKE2b computation. + /// * `mac`: Output buffer in which to store the computed HMAC-BLAKE2b MAC. + /// It must be 64 bytes long. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// use wolfssl_wolfcrypt::blake2::BLAKE2bHmac; + /// let key = [42u8, 43, 44]; + /// let mut hmac_blake2b = BLAKE2bHmac::new(&key).expect("Error with new()"); + /// let data = [33u8, 34, 35]; + /// hmac_blake2b.update(&data).expect("Error with update()"); + /// let mut mac = [0u8; 64]; + /// hmac_blake2b.finalize(&key, &mut mac).expect("Error with finalize()"); + /// ``` + pub fn finalize(&mut self, key: &[u8], mac: &mut [u8]) -> Result<(), i32> { + let rc = unsafe { + sys::wc_Blake2bHmacFinal(&mut self.wc_blake2b, + key.as_ptr(), key.len(), mac.as_mut_ptr(), mac.len()) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } + + /// Compute the HMAC-BLAKE2b message authentication code of the given + /// input data using the given key (one-shot API). + /// + /// # Parameters + /// + /// * `data`: Input data to create MAC from. + /// * `key`: Key to use for MAC creation. + /// * `out`: Buffer in which to store the computed MAC. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + #[cfg(blake2b_hmac)] + pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8]) -> Result<(), i32> { + let rc = unsafe { + sys::wc_Blake2bHmac(data.as_ptr(), data.len(), key.as_ptr(), + key.len(), out.as_mut_ptr(), out.len()) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } +} + + /// Context for BLAKE2s computation. #[cfg(blake2s)] pub struct BLAKE2s { @@ -291,7 +426,7 @@ impl BLAKE2s { /// use wolfssl_wolfcrypt::blake2::BLAKE2s; /// let mut blake2s = BLAKE2s::new(32).expect("Error with new()"); /// blake2s.update(&[0u8; 16]).expect("Error with update()"); - /// let mut hash = [0u8; 64]; + /// let mut hash = [0u8; 32]; /// blake2s.finalize(&mut hash).expect("Error with finalize()"); /// ``` pub fn finalize(&mut self, hash: &mut [u8]) -> Result<(), i32> { @@ -305,3 +440,137 @@ impl BLAKE2s { Ok(()) } } + + +/// Context for HMAC-BLAKE2s computation. +#[cfg(blake2s_hmac)] +pub struct BLAKE2sHmac { + wc_blake2s: sys::Blake2s, +} + +#[cfg(blake2s_hmac)] +impl BLAKE2sHmac { + /// Build a new BLAKE2sHmac instance. + /// + /// # Parameters + /// + /// * `key`: Key to use for HMAC-BLAKE2s computation. + /// + /// # Returns + /// + /// Returns either Ok(hmac_blake2s) or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// use wolfssl_wolfcrypt::blake2::BLAKE2sHmac; + /// let key = [42u8, 43, 44]; + /// let hmac_blake2s = BLAKE2sHmac::new(&key).expect("Error with new()"); + /// ``` + pub fn new(key: &[u8]) -> Result { + let mut wc_blake2s: MaybeUninit = MaybeUninit::uninit(); + let rc = unsafe { + sys::wc_Blake2sHmacInit(wc_blake2s.as_mut_ptr(), key.as_ptr(), key.len()) + }; + if rc != 0 { + return Err(rc); + } + let wc_blake2s = unsafe { wc_blake2s.assume_init() }; + let hmac_blake2s = BLAKE2sHmac { wc_blake2s }; + Ok(hmac_blake2s) + } + + /// Update the HMAC-BLAKE2s computation with the input data. + /// + /// This method may be called several times and then the finalize() + /// method should be called to retrieve the final MAC. + /// + /// # Parameters + /// + /// * `data`: Input data to hash. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// use wolfssl_wolfcrypt::blake2::BLAKE2sHmac; + /// let key = [42u8, 43, 44]; + /// let mut hmac_blake2s = BLAKE2sHmac::new(&key).expect("Error with new()"); + /// let data = [33u8, 34, 35]; + /// hmac_blake2s.update(&data).expect("Error with update()"); + /// ``` + pub fn update(&mut self, data: &[u8]) -> Result<(), i32> { + let rc = unsafe { + sys::wc_Blake2sHmacUpdate(&mut self.wc_blake2s, data.as_ptr(), data.len()) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } + + /// Compute and retrieve the final HMAC-BLAKE2s MAC. + /// + /// # Parameters + /// + /// * `key`: Key to use for HMAC-BLAKE2s computation. + /// * `mac`: Output buffer in which to store the computed HMAC-BLAKE2s MAC. + /// It must be 32 bytes long. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// use wolfssl_wolfcrypt::blake2::BLAKE2sHmac; + /// let key = [42u8, 43, 44]; + /// let mut hmac_blake2s = BLAKE2sHmac::new(&key).expect("Error with new()"); + /// let data = [33u8, 34, 35]; + /// hmac_blake2s.update(&data).expect("Error with update()"); + /// let mut mac = [0u8; 32]; + /// hmac_blake2s.finalize(&key, &mut mac).expect("Error with finalize()"); + /// ``` + pub fn finalize(&mut self, key: &[u8], mac: &mut [u8]) -> Result<(), i32> { + let rc = unsafe { + sys::wc_Blake2sHmacFinal(&mut self.wc_blake2s, + key.as_ptr(), key.len(), mac.as_mut_ptr(), mac.len()) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } + + /// Compute the HMAC-BLAKE2s message authentication code of the given + /// input data using the given key (one-shot API). + /// + /// # Parameters + /// + /// * `data`: Input data to create MAC from. + /// * `key`: Key to use for MAC creation. + /// * `out`: Buffer in which to store the computed MAC. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + #[cfg(blake2s_hmac)] + pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8]) -> Result<(), i32> { + let rc = unsafe { + sys::wc_Blake2sHmac(data.as_ptr(), data.len(), key.as_ptr(), + key.len(), out.as_mut_ptr(), out.len()) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2.rs index 5891ea5968..4b8bff27fe 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2.rs @@ -50,6 +50,70 @@ fn test_blake2b() { } } +#[test] +#[cfg(blake2b_hmac)] +fn test_blake2b_hmac() { + let key1 = [0x41u8, 0x42, 0x43, 0x44]; + let message1 = [0x48u8, 0x65, 0x6c, 0x6c, 0x6f]; + let expected1 = [ + 0x46u8, 0x76, 0xbb, 0x0e, 0xf8, 0xa1, 0x56, 0x33, + 0xde, 0xdc, 0x44, 0xe3, 0x2b, 0xf3, 0xee, 0x5b, + 0x5f, 0x7f, 0x04, 0x00, 0x2c, 0xaa, 0xd4, 0x93, + 0xc6, 0xa6, 0xb4, 0xf3, 0x14, 0x8d, 0x6d, 0x9c, + 0x6a, 0x12, 0x02, 0x85, 0x66, 0xed, 0x9b, 0x5d, + 0x8d, 0x0e, 0x3d, 0xf4, 0x78, 0xee, 0x5a, 0xf6, + 0x2f, 0x97, 0xa5, 0x77, 0x88, 0x8c, 0xc4, 0x66, + 0x46, 0xb1, 0xba, 0x51, 0x29, 0x19, 0xd7, 0xaa, + ]; + let key2 = [ + 0x30u8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33 + ]; + let message2 = [ + 0x61u8, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, 0x64, 0x65, 0x66, + 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69, + 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b, 0x69, 0x6a, 0x6b, 0x6c, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f, + 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71 + ]; + let expected2 = [ + 0x2au8, 0xda, 0xf6, 0x94, 0x79, 0xce, 0xe2, 0xd2, + 0x5d, 0x89, 0x8b, 0xd7, 0x0d, 0xbc, 0x11, 0x1f, + 0x98, 0x99, 0xe0, 0x17, 0x7c, 0x5b, 0x8f, 0x94, + 0xf5, 0x95, 0xbc, 0x1b, 0xb1, 0x95, 0xe8, 0x60, + 0xbb, 0x29, 0xa4, 0xd9, 0x27, 0x2e, 0x00, 0xea, + 0xba, 0xc3, 0x3e, 0xe6, 0x9c, 0xc7, 0xd7, 0x8d, + 0x69, 0xc7, 0xb4, 0xf7, 0x31, 0x4a, 0xb1, 0xf0, + 0x3c, 0xed, 0x06, 0x49, 0x6f, 0x46, 0x99, 0xea, + ]; + + let mut out1 = [0u8; 64]; + BLAKE2bHmac::hmac(&message1, &key1, &mut out1).expect("Error with hmac()"); + assert_eq!(out1, expected1); + + let mut out2 = [0u8; 64]; + BLAKE2bHmac::hmac(&message2, &key2, &mut out2).expect("Error with hmac()"); + assert_eq!(out2, expected2); + + let mut hmac_blake2b = BLAKE2bHmac::new(&key1).expect("Error with new()"); + hmac_blake2b.update(&message1[0..4]).expect("Error with update()"); + hmac_blake2b.update(&message1[4..]).expect("Error with update()"); + let mut out1 = [0u8; 64]; + hmac_blake2b.finalize(&key1, &mut out1).expect("Error with finalize()"); + assert_eq!(out1, expected1); + + let mut hmac_blake2b = BLAKE2bHmac::new(&key2).expect("Error with new()"); + hmac_blake2b.update(&message2[0..48]).expect("Error with update()"); + hmac_blake2b.update(&message2[48..]).expect("Error with update()"); + let mut out2 = [0u8; 64]; + hmac_blake2b.finalize(&key2, &mut out2).expect("Error with finalize()"); + assert_eq!(out2, expected2); +} + #[test] #[cfg(blake2s)] fn test_blake2s() { @@ -86,3 +150,56 @@ fn test_blake2s() { assert_eq!(hash, *expected_hash); } } + +#[test] +#[cfg(blake2s_hmac)] +fn test_blake2s_hmac() { + let key1 = [0x41u8, 0x42, 0x43, 0x44]; + let message1 = [0x48u8, 0x65, 0x6c, 0x6c, 0x6f]; + let expected1 = [ + 0x96u8, 0xca, 0x1d, 0xaa, 0x9a, 0x33, 0x97, 0x3d, + 0xc5, 0x95, 0x3e, 0xce, 0x49, 0x93, 0x75, 0xc1, + 0x2a, 0x7c, 0x8f, 0x5b, 0xf0, 0x28, 0xef, 0xc3, + 0xfb, 0xc5, 0x97, 0xcd, 0xcc, 0x74, 0x44, 0x68, + ]; + let key2 = [ + 0x30u8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, + ]; + let message2 = [ + 0x61u8, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, 0x64, 0x65, 0x66, + 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69, + 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b, 0x69, 0x6a, 0x6b, 0x6c, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f, + 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71 + ]; + let expected2 = [ + 0xc4u8, 0x63, 0xdb, 0x28, 0x97, 0x60, 0x6a, 0xa7, + 0x1e, 0xe6, 0xcf, 0x93, 0x85, 0x3c, 0x90, 0x71, + 0xea, 0x76, 0x7f, 0x6a, 0xa7, 0x20, 0x80, 0x35, + 0xe1, 0x68, 0x95, 0xfe, 0x65, 0x65, 0x43, 0x76, + ]; + + let mut out1 = [0u8; 32]; + BLAKE2sHmac::hmac(&message1, &key1, &mut out1).expect("Error with hmac()"); + assert_eq!(out1, expected1); + + let mut out2 = [0u8; 32]; + BLAKE2sHmac::hmac(&message2, &key2, &mut out2).expect("Error with hmac()"); + assert_eq!(out2, expected2); + + let mut hmac_blake2s = BLAKE2sHmac::new(&key1).expect("Error with new()"); + hmac_blake2s.update(&message1[0..4]).expect("Error with update()"); + hmac_blake2s.update(&message1[4..]).expect("Error with update()"); + let mut out1 = [0u8; 32]; + hmac_blake2s.finalize(&key1, &mut out1).expect("Error with finalize()"); + assert_eq!(out1, expected1); + + let mut hmac_blake2s = BLAKE2sHmac::new(&key2).expect("Error with new()"); + hmac_blake2s.update(&message2[0..48]).expect("Error with update()"); + hmac_blake2s.update(&message2[48..]).expect("Error with update()"); + let mut out2 = [0u8; 32]; + hmac_blake2s.finalize(&key2, &mut out2).expect("Error with finalize()"); + assert_eq!(out2, expected2); +} From af0fd013a16e3d858642a420104e0618c90e7fae Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 20 Jan 2026 08:14:02 -0500 Subject: [PATCH 02/27] HMAC-BLAKE2b: avoid coverity complaints about accessing x_key out of range --- wolfcrypt/src/blake2b.c | 8 ++++++-- wolfcrypt/src/blake2s.c | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/blake2b.c b/wolfcrypt/src/blake2b.c index 7aab2e40f8..37acb97446 100644 --- a/wolfcrypt/src/blake2b.c +++ b/wolfcrypt/src/blake2b.c @@ -534,7 +534,9 @@ int wc_Blake2bHmacInit(Blake2b* b2b, const byte* key, size_t key_len) ret = wc_Blake2bFinal(b2b, x_key, 0); } else { XMEMCPY(x_key, key, key_len); - XMEMSET(x_key + key_len, 0, BLAKE2B_BLOCKBYTES - key_len); + if (key_len < BLAKE2B_BLOCKBYTES) { + XMEMSET(x_key + key_len, 0, BLAKE2B_BLOCKBYTES - key_len); + } } if (ret == 0) { @@ -581,7 +583,9 @@ int wc_Blake2bHmacFinal(Blake2b* b2b, const byte* key, size_t key_len, ret = wc_Blake2bFinal(b2b, x_key, 0); } else { XMEMCPY(x_key, key, key_len); - XMEMSET(x_key + key_len, 0, BLAKE2B_BLOCKBYTES - key_len); + if (key_len < BLAKE2B_BLOCKBYTES) { + XMEMSET(x_key + key_len, 0, BLAKE2B_BLOCKBYTES - key_len); + } } if (ret == 0) { diff --git a/wolfcrypt/src/blake2s.c b/wolfcrypt/src/blake2s.c index 6f5d1d2e99..b38d12a933 100644 --- a/wolfcrypt/src/blake2s.c +++ b/wolfcrypt/src/blake2s.c @@ -528,7 +528,9 @@ int wc_Blake2sHmacInit(Blake2s* b2s, const byte* key, size_t key_len) ret = wc_Blake2sFinal(b2s, x_key, 0); } else { XMEMCPY(x_key, key, key_len); - XMEMSET(x_key + key_len, 0, BLAKE2S_BLOCKBYTES - key_len); + if (key_len < BLAKE2S_BLOCKBYTES) { + XMEMSET(x_key + key_len, 0, BLAKE2S_BLOCKBYTES - key_len); + } } if (ret == 0) { @@ -575,7 +577,9 @@ int wc_Blake2sHmacFinal(Blake2s* b2s, const byte* key, size_t key_len, ret = wc_Blake2sFinal(b2s, x_key, 0); } else { XMEMCPY(x_key, key, key_len); - XMEMSET(x_key + key_len, 0, BLAKE2S_BLOCKBYTES - key_len); + if (key_len < BLAKE2S_BLOCKBYTES) { + XMEMSET(x_key + key_len, 0, BLAKE2S_BLOCKBYTES - key_len); + } } if (ret == 0) { From 91d9389b9ff79e37c8668c22ca58043df53fd971 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 20 Jan 2026 10:21:12 -0800 Subject: [PATCH 03/27] Fixes for RSA with no RNG --- wolfcrypt/src/rsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 6cfb368f1e..0d2e25afea 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -3886,7 +3886,7 @@ int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key) { WC_RNG* rng; int ret; -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) if (key == NULL) { return BAD_FUNC_ARG; } @@ -3997,7 +3997,7 @@ int wc_RsaPSS_VerifyInline_ex(byte* in, word32 inLen, byte** out, { WC_RNG* rng; int ret; -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) if (key == NULL) { return BAD_FUNC_ARG; } @@ -4055,7 +4055,7 @@ int wc_RsaPSS_Verify_ex(const byte* in, word32 inLen, byte* out, word32 outLen, { WC_RNG* rng; int ret; -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) if (key == NULL) { return BAD_FUNC_ARG; } From e59ddb95c7101a20e637445d9690ed3fa1614136 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 20 Jan 2026 14:56:55 -0500 Subject: [PATCH 04/27] Rust blake2: remove unnecessary cfg guards --- wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs b/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs index afd36bf623..4659329033 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs @@ -288,7 +288,6 @@ impl BLAKE2bHmac { /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. - #[cfg(blake2b_hmac)] pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2bHmac(data.as_ptr(), data.len(), key.as_ptr(), @@ -562,7 +561,6 @@ impl BLAKE2sHmac { /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. - #[cfg(blake2s_hmac)] pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2sHmac(data.as_ptr(), data.len(), key.as_ptr(), From 4a92ee31bb70e53ff5503d4b54ae49e466cb3caf Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 20 Jan 2026 15:31:58 -0500 Subject: [PATCH 05/27] Rust HMAC-BLAKE2: require exact output buffer size --- wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs b/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs index 4659329033..4b8daeb395 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs @@ -176,6 +176,9 @@ pub struct BLAKE2bHmac { #[cfg(blake2b_hmac)] impl BLAKE2bHmac { + /// HMAC-BLAKE2b digest size. + pub const DIGEST_SIZE: usize = sys::WC_BLAKE2B_DIGEST_SIZE as usize; + /// Build a new BLAKE2bHmac instance. /// /// # Parameters @@ -264,7 +267,7 @@ impl BLAKE2bHmac { /// let mut mac = [0u8; 64]; /// hmac_blake2b.finalize(&key, &mut mac).expect("Error with finalize()"); /// ``` - pub fn finalize(&mut self, key: &[u8], mac: &mut [u8]) -> Result<(), i32> { + pub fn finalize(&mut self, key: &[u8], mac: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2bHmacFinal(&mut self.wc_blake2b, key.as_ptr(), key.len(), mac.as_mut_ptr(), mac.len()) @@ -282,13 +285,14 @@ impl BLAKE2bHmac { /// /// * `data`: Input data to create MAC from. /// * `key`: Key to use for MAC creation. - /// * `out`: Buffer in which to store the computed MAC. + /// * `out`: Buffer in which to store the computed MAC. It must be 64 bytes + /// long. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. - pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8]) -> Result<(), i32> { + pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2bHmac(data.as_ptr(), data.len(), key.as_ptr(), key.len(), out.as_mut_ptr(), out.len()) @@ -449,6 +453,9 @@ pub struct BLAKE2sHmac { #[cfg(blake2s_hmac)] impl BLAKE2sHmac { + /// HMAC-BLAKE2s digest size. + pub const DIGEST_SIZE: usize = sys::WC_BLAKE2S_DIGEST_SIZE as usize; + /// Build a new BLAKE2sHmac instance. /// /// # Parameters @@ -537,7 +544,7 @@ impl BLAKE2sHmac { /// let mut mac = [0u8; 32]; /// hmac_blake2s.finalize(&key, &mut mac).expect("Error with finalize()"); /// ``` - pub fn finalize(&mut self, key: &[u8], mac: &mut [u8]) -> Result<(), i32> { + pub fn finalize(&mut self, key: &[u8], mac: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2sHmacFinal(&mut self.wc_blake2s, key.as_ptr(), key.len(), mac.as_mut_ptr(), mac.len()) @@ -555,13 +562,14 @@ impl BLAKE2sHmac { /// /// * `data`: Input data to create MAC from. /// * `key`: Key to use for MAC creation. - /// * `out`: Buffer in which to store the computed MAC. + /// * `out`: Buffer in which to store the computed MAC. It must be 32 bytes + /// long. /// /// # Returns /// /// Returns either Ok(()) on success or Err(e) containing the wolfSSL /// library error code value. - pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8]) -> Result<(), i32> { + pub fn hmac(data: &[u8], key: &[u8], out: &mut [u8; Self::DIGEST_SIZE]) -> Result<(), i32> { let rc = unsafe { sys::wc_Blake2sHmac(data.as_ptr(), data.len(), key.as_ptr(), key.len(), out.as_mut_ptr(), out.len()) From ba53051457d771c279185023eea0be03ffb7ca7a Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 20 Jan 2026 15:07:44 -0600 Subject: [PATCH 06/27] add linuxkm/patches/5.14.0-570.58.1.el9_6/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v14-570v58v1-el9_6.patch --- linuxkm/include.am | 1 + ...RANDOM_CALLBACKS-5v14-570v58v1-el9_6.patch | 462 ++++++++++++++++++ 2 files changed, 463 insertions(+) create mode 100644 linuxkm/patches/5.14.0-570.58.1.el9_6/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v14-570v58v1-el9_6.patch diff --git a/linuxkm/include.am b/linuxkm/include.am index 63ffc5a58b..87cfae72e9 100644 --- a/linuxkm/include.am +++ b/linuxkm/include.am @@ -23,6 +23,7 @@ EXTRA_DIST += m4/ax_linuxkm.m4 \ linuxkm/wolfcrypt.lds \ linuxkm/patches/5.10.17/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v10v17.patch \ linuxkm/patches/5.10.236/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v10v236.patch \ + linuxkm/patches/5.14.0-570.58.1.el9_6/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v14-570v58v1-el9_6.patch \ linuxkm/patches/5.15/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v15.patch \ linuxkm/patches/5.17/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v17.patch \ linuxkm/patches/5.17-ubuntu-jammy-tegra/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v17-ubuntu-jammy-tegra.patch \ diff --git a/linuxkm/patches/5.14.0-570.58.1.el9_6/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v14-570v58v1-el9_6.patch b/linuxkm/patches/5.14.0-570.58.1.el9_6/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v14-570v58v1-el9_6.patch new file mode 100644 index 0000000000..aa1d1b6c68 --- /dev/null +++ b/linuxkm/patches/5.14.0-570.58.1.el9_6/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v14-570v58v1-el9_6.patch @@ -0,0 +1,462 @@ +--- 5.14.0-570.58.1.el9_6/drivers/char/random.c.dist 2026-01-12 10:50:48.537243229 -0600 ++++ 5.14.0-570.58.1.el9_6/drivers/char/random.c 2026-01-12 11:17:45.002091787 -0600 +@@ -63,6 +63,260 @@ + #include + #include + ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ ++#include ++ ++static atomic_long_t random_bytes_cb_owner = ++ ATOMIC_INIT((long)NULL); ++static atomic_t random_bytes_cb_refcnt = ++ ATOMIC_INIT(0); /* 0 if unregistered, 1 if no calls in flight. */ ++static _get_random_bytes_cb_t _get_random_bytes_cb = NULL; ++static get_random_bytes_user_cb_t get_random_bytes_user_cb = NULL; ++static crng_ready_cb_t crng_ready_cb = NULL; ++static mix_pool_bytes_cb_t mix_pool_bytes_cb = NULL; ++static credit_init_bits_cb_t credit_init_bits_cb = NULL; ++static crng_reseed_cb_t crng_reseed_cb = NULL; ++ ++int wolfssl_linuxkm_register_random_bytes_handlers( ++ struct module *new_random_bytes_cb_owner, ++ const struct wolfssl_linuxkm_random_bytes_handlers *handlers) ++{ ++ if ((! new_random_bytes_cb_owner) || ++ (! handlers) || ++ (! handlers->_get_random_bytes) || ++ (! handlers->get_random_bytes_user)) ++ { ++ return -EINVAL; ++ } ++ ++ /* random_bytes_cb_owner is used to enforce serialization of ++ * wolfssl_register_random_bytes_handlers() and ++ * wolfssl_unregister_random_bytes_handlers(). ++ */ ++ if (atomic_long_cmpxchg(&random_bytes_cb_owner, ++ (long)NULL, ++ (long)new_random_bytes_cb_owner) ++ != (long)NULL) ++ { ++ return -EBUSY; ++ } ++ ++ { ++ int current_random_bytes_cb_refcnt = atomic_read(&random_bytes_cb_refcnt); ++ if (current_random_bytes_cb_refcnt) { ++ pr_err("BUG: random_bytes_cb_refcnt == %d with null random_bytes_cb_owner", current_random_bytes_cb_refcnt); ++ atomic_long_set(&random_bytes_cb_owner, (long)NULL); ++ return -EFAULT; ++ } ++ } ++ ++ if (! try_module_get(new_random_bytes_cb_owner)) { ++ atomic_long_set(&random_bytes_cb_owner, (long)NULL); ++ return -ENODEV; ++ } ++ ++ _get_random_bytes_cb = handlers->_get_random_bytes; ++ get_random_bytes_user_cb = handlers->get_random_bytes_user; ++ crng_ready_cb = handlers->crng_ready; ++ mix_pool_bytes_cb = handlers->mix_pool_bytes; ++ credit_init_bits_cb = handlers->credit_init_bits; ++ crng_reseed_cb = handlers->crng_reseed; ++ ++ barrier(); ++ atomic_set_release(&random_bytes_cb_refcnt, 1); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(wolfssl_linuxkm_register_random_bytes_handlers); ++ ++int wolfssl_linuxkm_unregister_random_bytes_handlers(void) ++{ ++ int current_random_bytes_cb_refcnt; ++ int n_tries; ++ if (! atomic_long_read(&random_bytes_cb_owner)) ++ return -ENODEV; ++ ++ /* we're racing the kernel at large to try to catch random_bytes_cb_refcnt ++ * with no callers in flight -- retry and relax up to 100 times. ++ */ ++ for (n_tries = 0; n_tries < 100; ++n_tries) { ++ current_random_bytes_cb_refcnt = atomic_cmpxchg(&random_bytes_cb_refcnt, 1, 0); ++ if (current_random_bytes_cb_refcnt == 1) ++ break; ++ if (current_random_bytes_cb_refcnt < 0) { ++ pr_err("BUG: random_bytes_cb_refcnt is %d in wolfssl_linuxkm_unregister_random_bytes_handlers.", current_random_bytes_cb_refcnt); ++ break; ++ } ++ if (msleep_interruptible(10) != 0) ++ return -EINTR; ++ } ++ if (current_random_bytes_cb_refcnt != 1) { ++ pr_warn("WARNING: wolfssl_unregister_random_bytes_handlers called with random_bytes_cb_refcnt == %d", current_random_bytes_cb_refcnt); ++ return -EBUSY; ++ } ++ ++ _get_random_bytes_cb = NULL; ++ get_random_bytes_user_cb = NULL; ++ crng_ready_cb = NULL; ++ mix_pool_bytes_cb = NULL; ++ credit_init_bits_cb = NULL; ++ crng_reseed_cb = NULL; ++ ++ module_put((struct module *)atomic_long_read(&random_bytes_cb_owner)); ++ barrier(); ++ atomic_long_set(&random_bytes_cb_owner, (long)NULL); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(wolfssl_linuxkm_unregister_random_bytes_handlers); ++ ++static __always_inline int reserve_random_bytes_cb(void) { ++ int current_random_bytes_cb_refcnt = ++ atomic_read_acquire(&random_bytes_cb_refcnt); ++ ++ if (! current_random_bytes_cb_refcnt) ++ return -ENODEV; ++ ++ if (current_random_bytes_cb_refcnt < 0) { ++ pr_err("BUG: random_bytes_cb_refcnt is %d in reserve_random_bytes_cb.", current_random_bytes_cb_refcnt); ++ return -EFAULT; ++ } ++ ++ for (;;) { ++ int orig_random_bytes_cb_refcnt = ++ atomic_cmpxchg( ++ &random_bytes_cb_refcnt, ++ current_random_bytes_cb_refcnt, ++ current_random_bytes_cb_refcnt + 1); ++ if (orig_random_bytes_cb_refcnt == current_random_bytes_cb_refcnt) ++ return 0; ++ else if (! orig_random_bytes_cb_refcnt) ++ return -ENODEV; ++ else ++ current_random_bytes_cb_refcnt = orig_random_bytes_cb_refcnt; ++ } ++ ++ __builtin_unreachable(); ++} ++ ++static __always_inline void release_random_bytes_cb(void) { ++ atomic_dec(&random_bytes_cb_refcnt); ++} ++ ++static inline int call__get_random_bytes_cb(void *buf, size_t len) ++{ ++ int ret; ++ ++ if (! _get_random_bytes_cb) ++ return -ENODEV; ++ ++ ret = reserve_random_bytes_cb(); ++ if (ret) ++ return ret; ++ ++ ret = _get_random_bytes_cb(buf, len); ++ ++ release_random_bytes_cb(); ++ ++ return ret; ++} ++ ++static inline ssize_t call_get_random_bytes_user_cb(struct iov_iter *iter) ++{ ++ ssize_t ret; ++ ++ if (! get_random_bytes_user_cb) ++ return -ECANCELED; ++ ++ ret = (ssize_t)reserve_random_bytes_cb(); ++ if (ret) ++ return ret; ++ ++ ret = get_random_bytes_user_cb(iter); ++ ++ release_random_bytes_cb(); ++ ++ return ret; ++} ++ ++static inline bool call_crng_ready_cb(void) ++{ ++ bool ret; ++ ++ /* Null crng_ready_cb signifies that the DRBG is always ready, i.e. that if ++ * called, it will always have or obtain sufficient entropy to fulfill the ++ * call. ++ */ ++ if (! crng_ready_cb) ++ return 1; ++ ++ if (reserve_random_bytes_cb() != 0) ++ return 0; ++ ++ ret = crng_ready_cb(); ++ ++ release_random_bytes_cb(); ++ ++ return ret; ++} ++ ++static inline int call_mix_pool_bytes_cb(const void *buf, size_t len) ++{ ++ int ret; ++ ++ if (! mix_pool_bytes_cb) ++ return -ENODEV; ++ ++ ret = reserve_random_bytes_cb(); ++ if (ret) ++ return ret; ++ ++ ret = mix_pool_bytes_cb(buf, len); ++ ++ release_random_bytes_cb(); ++ ++ return ret; ++} ++ ++static inline int call_credit_init_bits_cb(size_t bits) ++{ ++ int ret; ++ ++ if (! credit_init_bits_cb) ++ return -ENODEV; ++ ++ ret = reserve_random_bytes_cb(); ++ if (ret) ++ return ret; ++ ++ ret = credit_init_bits_cb(bits); ++ ++ release_random_bytes_cb(); ++ ++ return ret; ++} ++ ++static inline int call_crng_reseed_cb(void) ++{ ++ int ret; ++ ++ if (! crng_reseed_cb) ++ return -ENODEV; ++ ++ ret = reserve_random_bytes_cb(); ++ if (ret) ++ return ret; ++ ++ ret = crng_reseed_cb(); ++ ++ release_random_bytes_cb(); ++ ++ return ret; ++} ++ ++#endif /* WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS */ ++ + /********************************************************************* + * + * Initialization and readiness waiting. +@@ -83,7 +337,15 @@ static enum { + CRNG_READY = 2 /* Fully initialized with POOL_READY_BITS collected */ + } crng_init __read_mostly = CRNG_EMPTY; + static DEFINE_STATIC_KEY_FALSE(crng_is_ready); ++ + #define crng_ready() (static_branch_likely(&crng_is_ready) || crng_init >= CRNG_READY) ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ #define crng_ready_by_cb() (atomic_read(&random_bytes_cb_refcnt) && call_crng_ready_cb()) ++ #define crng_ready_maybe_cb() (atomic_read(&random_bytes_cb_refcnt) ? (call_crng_ready_cb() || crng_ready()) : crng_ready()) ++#else ++ #define crng_ready_maybe_cb() crng_ready() ++#endif ++ + /* Various types of waiters for crng_init->CRNG_READY transition. */ + static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait); + static struct fasync_struct *fasync; +@@ -108,7 +370,7 @@ MODULE_PARM_DESC(ratelimit_disable, "Dis + */ + bool rng_is_initialized(void) + { +- return crng_ready(); ++ return crng_ready_maybe_cb(); + } + EXPORT_SYMBOL(rng_is_initialized); + +@@ -132,11 +394,11 @@ static void try_to_generate_entropy(void + */ + int wait_for_random_bytes(void) + { +- while (!crng_ready()) { ++ while (!crng_ready_maybe_cb()) { + int ret; + + try_to_generate_entropy(); +- ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ); ++ ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready_maybe_cb(), HZ); + if (ret) + return ret > 0 ? 0 : ret; + } +@@ -165,7 +427,7 @@ int __cold execute_with_initialized_rng( + } + + #define warn_unseeded_randomness() \ +- if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \ ++ if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready_maybe_cb()) \ + printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n", \ + __func__, (void *)_RET_IP_, crng_init) + +@@ -388,6 +650,14 @@ static void _get_random_bytes(void *buf, + if (!len) + return; + ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ /* If call__get_random_bytes_cb() doesn't succeed, flow falls through to ++ * the native implementation. _get_random_bytes() must succeed. ++ */ ++ if (call__get_random_bytes_cb(buf, len) == 0) ++ return; ++#endif ++ + first_block_len = min_t(size_t, 32, len); + crng_make_state(chacha_state, buf, first_block_len); + len -= first_block_len; +@@ -434,6 +704,18 @@ static ssize_t get_random_bytes_user(str + if (unlikely(!iov_iter_count(iter))) + return 0; + ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ { ++ ssize_t cb_ret = call_get_random_bytes_user_cb(iter); ++ /* If the callback returns -ECANCELED, that signals that iter is ++ * still intact, and flow can safely fall through to the native ++ * implementation. ++ */ ++ if (cb_ret != -ECANCELED) ++ return cb_ret; ++ } ++#endif ++ + /* + * Immediately overwrite the ChaCha key at index 4 with random + * bytes, in case userspace causes copy_to_iter() below to sleep +@@ -510,7 +792,7 @@ type get_random_ ##type(void) \ + \ + warn_unseeded_randomness(); \ + \ +- if (!crng_ready()) { \ ++ if (!crng_ready_maybe_cb()) { \ + _get_random_bytes(&ret, sizeof(ret)); \ + return ret; \ + } \ +@@ -649,6 +931,11 @@ static void mix_pool_bytes(const void *b + { + unsigned long flags; + ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ (void)call_mix_pool_bytes_cb(buf, len); ++ /* fall through to mix into native pool too. */ ++#endif ++ + spin_lock_irqsave(&input_pool.lock, flags); + _mix_pool_bytes(buf, len); + spin_unlock_irqrestore(&input_pool.lock, flags); +@@ -708,7 +995,11 @@ static void extract_entropy(void *buf, s + memzero_explicit(&block, sizeof(block)); + } + ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++#define credit_init_bits(bits) do { (void)call_credit_init_bits_cb(bits); if (!crng_ready()) _credit_init_bits(bits); } while (0) ++#else + #define credit_init_bits(bits) if (!crng_ready()) _credit_init_bits(bits) ++#endif + + static void __cold _credit_init_bits(size_t bits) + { +@@ -1419,7 +1710,7 @@ SYSCALL_DEFINE3(getrandom, char __user * + return ret; + } + +- if (!crng_ready() && !(flags & GRND_INSECURE)) { ++ if (!crng_ready_maybe_cb() && !(flags & GRND_INSECURE)) { + if (flags & GRND_NONBLOCK) + return -EAGAIN; + ret = wait_for_random_bytes(); +@@ -1435,6 +1726,10 @@ SYSCALL_DEFINE3(getrandom, char __user * + + static __poll_t random_poll(struct file *file, poll_table *wait) + { ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ if (crng_ready_by_cb()) ++ return EPOLLIN | EPOLLRDNORM; ++#endif + poll_wait(file, &crng_init_wait, wait); + return crng_ready() ? EPOLLIN | EPOLLRDNORM : EPOLLOUT | EPOLLWRNORM; + } +@@ -1490,7 +1785,7 @@ static ssize_t urandom_read_iter(struct + if (!crng_ready()) + try_to_generate_entropy(); + +- if (!crng_ready()) { ++ if (!crng_ready_maybe_cb()) { + if (!ratelimit_disable && maxwarn <= 0) + ++urandom_warning.missed; + else if (ratelimit_disable || __ratelimit(&urandom_warning)) { +@@ -1573,6 +1868,14 @@ static long random_ioctl(struct file *f, + case RNDRESEEDCRNG: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; ++#ifdef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ /* fall through to reseed native crng too. */ ++ if (call_crng_reseed_cb() == 0) { ++ if (crng_ready()) ++ crng_reseed(NULL); ++ return 0; ++ } ++#endif + if (!crng_ready()) + return -ENODATA; + crng_reseed(NULL); +--- 5.14.0-570.58.1.el9_6/include/linux/random.h.dist 2026-01-12 10:50:57.004413581 -0600 ++++ 5.14.0-570.58.1.el9_6/include/linux/random.h 2026-01-12 10:56:29.124034816 -0600 +@@ -175,4 +175,37 @@ int random_online_cpu(unsigned int cpu); + extern const struct file_operations random_fops, urandom_fops; + #endif + ++#ifndef WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS ++ #define WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS 1 ++#endif ++ ++typedef int (*_get_random_bytes_cb_t)(void *buf, size_t len); ++struct iov_iter; ++/* kernels >= 5.17.0 use get_random_bytes_user() */ ++typedef ssize_t (*get_random_bytes_user_cb_t)(struct iov_iter *iter); ++/* kernels < 5.17.0 use extract_crng_user(), though some LTS kernels, ++ * e.g. 5.10.236, have the 5.17+ architecture backported. ++ */ ++typedef ssize_t (*extract_crng_user_cb_t)(void __user *buf, size_t nbytes); ++typedef bool (*crng_ready_cb_t)(void); ++typedef int (*mix_pool_bytes_cb_t)(const void *buf, size_t len); ++typedef int (*credit_init_bits_cb_t)(size_t bits); ++typedef int (*crng_reseed_cb_t)(void); ++ ++struct wolfssl_linuxkm_random_bytes_handlers { ++ _get_random_bytes_cb_t _get_random_bytes; ++ get_random_bytes_user_cb_t get_random_bytes_user; ++ extract_crng_user_cb_t extract_crng_user; ++ crng_ready_cb_t crng_ready; ++ mix_pool_bytes_cb_t mix_pool_bytes; ++ credit_init_bits_cb_t credit_init_bits; ++ crng_reseed_cb_t crng_reseed; ++}; ++ ++int wolfssl_linuxkm_register_random_bytes_handlers( ++ struct module *new_random_bytes_cb_owner, ++ const struct wolfssl_linuxkm_random_bytes_handlers *handlers); ++ ++int wolfssl_linuxkm_unregister_random_bytes_handlers(void); ++ + #endif /* _LINUX_RANDOM_H */ From b91272c9a5cf8ee4cbfafe37f632b35fac9b1884 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 20 Jan 2026 15:24:43 -0600 Subject: [PATCH 07/27] wolfcrypt/src/random.c: add sanity check in wc_GenerateSeed_IntelRD() to work around buggy RDSEED by disabling it if it generates three identical 64 bit words consecutively; wolfssl/wolfcrypt/settings.h: if DEBUG_WOLFSSL && !WC_NO_VERBOSE_RNG, set WC_VERBOSE_RNG, and add WOLFSSL_NO_DEBUG_CERTS to allow inhibition of WOLFSSL_DEBUG_CERTS. --- .wolfssl_known_macro_extras | 1 + wolfcrypt/src/random.c | 34 ++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/settings.h | 16 +++++++++++++--- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 56eb6a0dfd..c2b7bdf78d 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -802,6 +802,7 @@ WOLFSSL_NO_COPY_KEY WOLFSSL_NO_CRL_DATE_CHECK WOLFSSL_NO_CRL_NEXT_DATE WOLFSSL_NO_CT_MAX_MIN +WOLFSSL_NO_DEBUG_CERTS WOLFSSL_NO_DECODE_EXTRA WOLFSSL_NO_DER_TO_PEM WOLFSSL_NO_DH186 diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 4a50de6cbb..78b569972e 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1935,12 +1935,46 @@ static int wc_GenerateSeed_IntelRD(OS_Seed* os, byte* output, word32 sz) { int ret; word64 rndTmp; + static int rdseed_sanity_status = 0; (void)os; if (!IS_INTEL_RDSEED(intel_flags)) return -1; + if (rdseed_sanity_status == 0) { + static word64 sanity_words[2] = {0, 0}; + + ret = IntelRDseed64_r(&sanity_words[0]); + if (ret != 0) + return ret; + + ret = IntelRDseed64_r(&sanity_words[1]); + if (ret != 0) + return ret; + + if (sanity_words[0] == sanity_words[1]) { + ret = IntelRDseed64_r(&sanity_words[0]); + if (ret != 0) + return ret; + + if (sanity_words[0] == sanity_words[1]) { + rdseed_sanity_status = -1; +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "WARNING: RDSEED disabled due to repeating word 0x%lx -- " + "check CPU microcode version.", sanity_words[1]); +#endif + return -1; + } + } + + rdseed_sanity_status = 1; + } + else if (rdseed_sanity_status < 0) { + return -1; + } + for (; (sz / sizeof(word64)) > 0; sz -= sizeof(word64), output += sizeof(word64)) { ret = IntelRDseed64_r((word64*)output); diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 3b2ebf72ec..8ba9e9a225 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -369,12 +369,22 @@ #warning "No configuration for wolfSSL detected, check header order" #endif -/* Ensure WOLFSSL_DEBUG_CERTS is always set when DEBUG_WOLFSSL is enabled */ -#ifdef DEBUG_WOLFSSL - #undef WOLFSSL_DEBUG_CERTS +/* Ensure WOLFSSL_DEBUG_CERTS is set when DEBUG_WOLFSSL is enabled, unless + * expressly requested otherwise. + */ +#if defined(DEBUG_WOLFSSL) && !defined(WOLFSSL_NO_DEBUG_CERTS) && \ + !defined(WOLFSSL_DEBUG_CERTS) #define WOLFSSL_DEBUG_CERTS #endif +/* Ensure WC_VERBOSE_RNG is set when DEBUG_WOLFSSL is enabled, unless expressly + * requested otherwise. + */ +#if defined(DEBUG_WOLFSSL) && !defined(WC_NO_VERBOSE_RNG) && \ + !defined(WC_VERBOSE_RNG) + #define WC_VERBOSE_RNG +#endif + #include /*------------------------------------------------------------*/ From 4550814e663a59695f8b5464ec670f0d0b17723e Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Tue, 20 Jan 2026 16:37:20 -0500 Subject: [PATCH 08/27] wc_XChaCha20Poly1305_Init: NULL check aead, not ad --- wolfcrypt/src/chacha20_poly1305.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 94eb5ea89b..75f522e877 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -313,7 +313,7 @@ int wc_XChaCha20Poly1305_Init( byte authKey[CHACHA20_POLY1305_AEAD_KEYSIZE]; int ret; - if ((ad == NULL) || (nonce == NULL) || (key == NULL)) + if ((aead == NULL) || (nonce == NULL) || (key == NULL)) return BAD_FUNC_ARG; if ((key_len != CHACHA20_POLY1305_AEAD_KEYSIZE) || From 7048fa80d485cd5e339e67bf7e1e1e7d938ff44a Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 20 Jan 2026 16:48:21 -0600 Subject: [PATCH 09/27] wolfcrypt/src/random.c and wolfssl/wolfcrypt/settings.h: fixes from CI and peer review: * in wc_GenerateSeed_IntelRD(), use stack/register allocation for sanity_word{1,2}, and * don't set WC_VERBOSE_RNG if WOLFSSL_DEBUG_PRINTF is missing. --- wolfcrypt/src/random.c | 21 ++++++++++++--------- wolfssl/wolfcrypt/settings.h | 6 +++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 78b569972e..5934c14df5 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1942,29 +1942,32 @@ static int wc_GenerateSeed_IntelRD(OS_Seed* os, byte* output, word32 sz) if (!IS_INTEL_RDSEED(intel_flags)) return -1; + /* Note, access to rdseed_sanity_status is benignly racey on multithreaded + * targets. + */ if (rdseed_sanity_status == 0) { - static word64 sanity_words[2] = {0, 0}; + word64 sanity_word1 = 0, sanity_word2 = 0; - ret = IntelRDseed64_r(&sanity_words[0]); + ret = IntelRDseed64_r(&sanity_word1); if (ret != 0) return ret; - ret = IntelRDseed64_r(&sanity_words[1]); + ret = IntelRDseed64_r(&sanity_word2); if (ret != 0) return ret; - if (sanity_words[0] == sanity_words[1]) { - ret = IntelRDseed64_r(&sanity_words[0]); + if (sanity_word1 == sanity_word2) { + ret = IntelRDseed64_r(&sanity_word1); if (ret != 0) return ret; - if (sanity_words[0] == sanity_words[1]) { - rdseed_sanity_status = -1; + if (sanity_word1 == sanity_word2) { #ifdef WC_VERBOSE_RNG WOLFSSL_DEBUG_PRINTF( - "WARNING: RDSEED disabled due to repeating word 0x%lx -- " - "check CPU microcode version.", sanity_words[1]); + "WARNING: disabling RDSEED due to repeating word 0x%lx -- " + "check CPU microcode version.", sanity_word2); #endif + rdseed_sanity_status = -1; return -1; } } diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 8ba9e9a225..a7a70060ac 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -378,10 +378,10 @@ #endif /* Ensure WC_VERBOSE_RNG is set when DEBUG_WOLFSSL is enabled, unless expressly - * requested otherwise. + * requested otherwise. Relies on a working WOLFSSL_DEBUG_PRINTF. */ -#if defined(DEBUG_WOLFSSL) && !defined(WC_NO_VERBOSE_RNG) && \ - !defined(WC_VERBOSE_RNG) +#if defined(DEBUG_WOLFSSL) && defined(WOLFSSL_DEBUG_PRINTF) && \ + !defined(WC_NO_VERBOSE_RNG) && !defined(WC_VERBOSE_RNG) #define WC_VERBOSE_RNG #endif From 22ed7472b4c4b83d8194e363f344f338a9951e43 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Wed, 21 Jan 2026 08:59:28 +0900 Subject: [PATCH 10/27] fix qt unit test include asn.h for SN_xxx definitions --- wolfssl/openssl/obj_mac.h | 3 +++ wolfssl/wolfcrypt/asn.h | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/wolfssl/openssl/obj_mac.h b/wolfssl/openssl/obj_mac.h index 78b11f1f79..6865779d6d 100644 --- a/wolfssl/openssl/obj_mac.h +++ b/wolfssl/openssl/obj_mac.h @@ -23,6 +23,9 @@ #ifndef WOLFSSL_OBJ_MAC_H_ #define WOLFSSL_OBJ_MAC_H_ +/* include SN_xxx definitions from asn.h */ +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 6ebbb45ff4..3b3779cb32 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -37,7 +37,8 @@ that can be serialized and deserialized in a cross-platform way. #include #if !defined(NO_ASN) || !defined(NO_PWDBASED) - +/* included openssl/obj_mac.h directly for SN_xxx definitions */ +#if !defined(WOLFSSL_OBJ_MAC_H_) #if !defined(NO_ASN_TIME) && defined(NO_TIME_H) #define NO_ASN_TIME /* backwards compatibility with NO_TIME_H */ #endif @@ -880,8 +881,10 @@ extern const WOLFSSL_ObjectInfo wolfssl_object_info[]; #else #define WC_MAX_CERT_VERIFY_SZ 1024 /* max default */ #endif - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +#endif /* !NO_ASN */ +#endif /* !WOLFSSL_OBJ_MAC_H_ */ +#if defined(WOLFSSL_OBJ_MAC_H_) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* short names */ #define WC_SN_md4 "MD4" #define WC_SN_md5 "MD5" @@ -1178,8 +1181,9 @@ extern const WOLFSSL_ObjectInfo wolfssl_object_info[]; #endif /* !OPENSSL_COEXIST */ -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - +#endif /* WOLFSSL_OBJ_MAC_H_ || OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ +#if !defined(WOLFSSL_OBJ_MAC_H_) +#if !defined(NO_ASN) enum ECC_TYPES { ECC_PREFIX_0 = 160, @@ -2998,6 +3002,7 @@ enum PKCSTypes { } /* extern "C" */ #endif +#endif /* WOLFSSL_OBJ_MAC_H_ */ #endif /* !NO_ASN || !NO_PWDBASED */ #endif /* WOLF_CRYPT_ASN_H */ From 8902afdcea1a277011f31788a9899c6c8e225eca Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 21 Jan 2026 10:00:38 +1000 Subject: [PATCH 11/27] TLS: more sanity checks on message order Add more checks on message ordering for TLS 1.2 and below. Reformat code. --- src/internal.c | 150 +++++++++++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 60 deletions(-) diff --git a/src/internal.c b/src/internal.c index 49020d3d4b..f9609612b4 100644 --- a/src/internal.c +++ b/src/internal.c @@ -17609,7 +17609,9 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) if (ssl->msgsReceived.got_certificate_status || ssl->msgsReceived.got_server_key_exchange || ssl->msgsReceived.got_certificate_request || - ssl->msgsReceived.got_server_hello_done) { + ssl->msgsReceived.got_server_hello_done || + ssl->msgsReceived.got_change_cipher || + ssl->msgsReceived.got_finished) { WOLFSSL_MSG("Cert received in wrong order"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; @@ -17650,19 +17652,21 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) return DUPLICATE_MSG_E; } - if (ssl->msgsReceived.got_certificate == 0) { + if (!ssl->msgsReceived.got_certificate) { WOLFSSL_MSG("No Certificate before CertificateStatus"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; } - if (ssl->msgsReceived.got_server_key_exchange != 0) { + if (ssl->msgsReceived.got_server_key_exchange) { WOLFSSL_MSG("CertificateStatus after ServerKeyExchange"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; } if (ssl->msgsReceived.got_server_key_exchange || ssl->msgsReceived.got_certificate_request || - ssl->msgsReceived.got_server_hello_done) { + ssl->msgsReceived.got_server_hello_done || + ssl->msgsReceived.got_change_cipher || + ssl->msgsReceived.got_finished) { WOLFSSL_MSG("CertificateStatus received in wrong order"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; @@ -17686,13 +17690,25 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_ERROR_VERBOSE(DUPLICATE_MSG_E); return DUPLICATE_MSG_E; } - if (ssl->msgsReceived.got_server_hello == 0) { + if (!ssl->msgsReceived.got_server_hello) { WOLFSSL_MSG("No ServerHello before ServerKeyExchange"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; } + if (!ssl->msgsReceived.got_certificate) { + if (ssl->specs.kea != psk_kea && + ssl->specs.kea != dhe_psk_kea && + ssl->specs.kea != ecdhe_psk_kea && + !ssl->options.usingAnon_cipher) { + WOLFSSL_MSG("No Certificate before ServerKeyExchange"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + } if (ssl->msgsReceived.got_certificate_request || - ssl->msgsReceived.got_server_hello_done) { + ssl->msgsReceived.got_server_hello_done || + ssl->msgsReceived.got_change_cipher || + ssl->msgsReceived.got_finished) { WOLFSSL_MSG("ServerKeyExchange received in wrong order"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; @@ -17716,11 +17732,16 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_ERROR_VERBOSE(DUPLICATE_MSG_E); return DUPLICATE_MSG_E; } - if (ssl->msgsReceived.got_server_hello == 0) { + if (!ssl->msgsReceived.got_server_hello) { WOLFSSL_MSG("No ServerHello before CertificateRequest"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; } + if (!ssl->msgsReceived.got_certificate) { + WOLFSSL_MSG("No Certificate before CertificateRequest"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } if (!ssl->options.resuming && ssl->specs.kea != rsa_kea && (ssl->specs.kea != ecc_diffie_hellman_kea || !ssl->specs.static_ecdh) && @@ -17730,12 +17751,9 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; } - if (!ssl->msgsReceived.got_certificate) { - WOLFSSL_MSG("No Certificate before CertificateRequest"); - WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); - return OUT_OF_ORDER_E; - } - if (ssl->msgsReceived.got_server_hello_done) { + if (ssl->msgsReceived.got_server_hello_done || + ssl->msgsReceived.got_change_cipher || + ssl->msgsReceived.got_finished) { WOLFSSL_MSG("CertificateRequest received in wrong order"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; @@ -17761,7 +17779,7 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) } ssl->msgsReceived.got_server_hello_done = 1; - if (ssl->msgsReceived.got_certificate == 0) { + if (!ssl->msgsReceived.got_certificate) { if (ssl->specs.kea == psk_kea || ssl->specs.kea == dhe_psk_kea || ssl->specs.kea == ecdhe_psk_kea || @@ -17774,7 +17792,7 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) return OUT_OF_ORDER_E; } } - if (ssl->msgsReceived.got_server_key_exchange == 0) { + if (!ssl->msgsReceived.got_server_key_exchange) { int pskNoServerHint = 0; /* not required in this case */ #ifndef NO_PSK @@ -17796,7 +17814,7 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) } #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) - if (ssl->msgsReceived.got_certificate_status == 0) { + if (!ssl->msgsReceived.got_certificate_status) { int csrRet = 0; #ifdef HAVE_CERTIFICATE_STATUS_REQUEST if (csrRet == 0 && ssl->status_request) { @@ -17842,6 +17860,12 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) } } #endif + if (ssl->msgsReceived.got_change_cipher || + ssl->msgsReceived.got_finished) { + WOLFSSL_MSG("ServerHelloDone received in wrong order"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } break; #endif @@ -17859,7 +17883,12 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_ERROR_VERBOSE(DUPLICATE_MSG_E); return DUPLICATE_MSG_E; } - if ( ssl->msgsReceived.got_certificate == 0) { + if (!ssl->msgsReceived.got_client_key_exchange) { + WOLFSSL_MSG("No ClientKeyExchange before CertVerify"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + if (!ssl->msgsReceived.got_certificate) { WOLFSSL_MSG("No Cert before CertVerify"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; @@ -17888,7 +17917,7 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_ERROR_VERBOSE(DUPLICATE_MSG_E); return DUPLICATE_MSG_E; } - if (ssl->msgsReceived.got_client_hello == 0) { + if (!ssl->msgsReceived.got_client_hello) { WOLFSSL_MSG("No ClientHello before ClientKeyExchange"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; @@ -17919,7 +17948,7 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) } } #endif - if (ssl->msgsReceived.got_change_cipher == 0) { + if (!ssl->msgsReceived.got_change_cipher) { WOLFSSL_MSG("Finished received before ChangeCipher"); WOLFSSL_ERROR_VERBOSE(NO_CHANGE_CIPHER_E); return NO_CHANGE_CIPHER_E; @@ -17940,62 +17969,63 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_CLIENT if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (!ssl->msgsReceived.got_server_hello) { + WOLFSSL_MSG("ChangeCipherSpec received in wrong order"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } if (!ssl->options.resuming) { - if (ssl->msgsReceived.got_server_hello_done == 0) { + if (!ssl->msgsReceived.got_server_hello_done) { WOLFSSL_MSG("No ServerHelloDone before ChangeCipher"); WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; } } - else { - if (ssl->msgsReceived.got_server_hello == 0) { - WOLFSSL_MSG("No ServerHello before ChangeCipher on " - "Resume"); - WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); - return OUT_OF_ORDER_E; - } + #ifdef HAVE_SESSION_TICKET + if (ssl->expect_session_ticket) { + WOLFSSL_MSG("Expected session ticket missing"); + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + #endif + WOLFSSL_ERROR_VERBOSE(SESSION_TICKET_EXPECT_E); + return SESSION_TICKET_EXPECT_E; } - #ifdef HAVE_SESSION_TICKET - if (ssl->expect_session_ticket) { - WOLFSSL_MSG("Expected session ticket missing"); + #endif + } +#endif +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { + if (!ssl->msgsReceived.got_client_hello) { + WOLFSSL_MSG("ChangeCipherSpec received in wrong order"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + if (!ssl->options.resuming && + !ssl->msgsReceived.got_client_key_exchange) { + WOLFSSL_MSG("No ClientKeyExchange before ChangeCipher"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + #ifndef NO_CERTS + if (ssl->options.verifyPeer && + ssl->options.havePeerCert) { + if (!ssl->options.havePeerVerify || + !ssl->msgsReceived.got_certificate_verify) { + WOLFSSL_MSG("client didn't send cert verify"); #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); return OUT_OF_ORDER_E; } #endif - WOLFSSL_ERROR_VERBOSE(SESSION_TICKET_EXPECT_E); - return SESSION_TICKET_EXPECT_E; + WOLFSSL_ERROR_VERBOSE(NO_PEER_VERIFY); + return NO_PEER_VERIFY; } - #endif - } -#endif -#ifndef NO_WOLFSSL_SERVER - if (ssl->options.side == WOLFSSL_SERVER_END) { - if (!ssl->options.resuming && - ssl->msgsReceived.got_client_key_exchange == 0) { - WOLFSSL_MSG("No ClientKeyExchange before ChangeCipher"); - WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); - return OUT_OF_ORDER_E; } - #ifndef NO_CERTS - if (ssl->options.verifyPeer && - ssl->options.havePeerCert) { - - if (!ssl->options.havePeerVerify || - !ssl->msgsReceived.got_certificate_verify) { - WOLFSSL_MSG("client didn't send cert verify"); - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); - return OUT_OF_ORDER_E; - } - #endif - WOLFSSL_ERROR_VERBOSE(NO_PEER_VERIFY); - return NO_PEER_VERIFY; - } - } - #endif + #endif } #endif /* !NO_WOLFSSL_SERVER */ if (ssl->options.dtls) From a4c2398265254341dbd80659d2cea86e685ad3ab Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 6 Jan 2026 14:41:36 -0800 Subject: [PATCH 12/27] Add STSAFE-A120 Support --- .wolfssl_known_macro_extras | 3 + wolfcrypt/src/port/st/README.md | 185 +++- wolfcrypt/src/port/st/stsafe.c | 1647 ++++++++++++++++++++++------ wolfcrypt/src/wc_port.c | 10 +- wolfssl/wolfcrypt/port/st/stsafe.h | 130 ++- 5 files changed, 1642 insertions(+), 333 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 56eb6a0dfd..d11b35a043 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -513,6 +513,9 @@ SQRTMOD_USE_MOD_EXP SSL_SNIFFER_EXPORTS SSN_BUILDING_LIBYASSL STATIC_CHUNKS_ONLY +STSAFE_HOST_KEY_CIPHER +STSAFE_HOST_KEY_MAC +STSAFE_I2C_BUS STM32F107xC STM32F207xx STM32F217xx diff --git a/wolfcrypt/src/port/st/README.md b/wolfcrypt/src/port/st/README.md index 1dae1036ff..fc5baf42a8 100644 --- a/wolfcrypt/src/port/st/README.md +++ b/wolfcrypt/src/port/st/README.md @@ -9,7 +9,9 @@ Support for the STM32 PKA on WB55, H7, MP13 and other devices with on-board public-key acceleration: - ECC192/ECC224/ECC256/ECC384 -Support for the STSAFE-A100 crypto hardware accelerator co-processor via I2C for ECC supporting NIST or Brainpool 256-bit and 384-bit curves. It requires the ST-Safe SDK including wolfSSL's `stsafe_interface.c/.h` files. Please contact us at support@wolfssl.com to get this code. +Support for the STSAFE-A secure element family via I2C for ECC supporting NIST P-256/P-384 and Brainpool 256/384-bit curves: + - **STSAFE-A100/A110**: Uses ST's proprietary STSAFE-A1xx middleware. Contact us at support@wolfssl.com for integration assistance. + - **STSAFE-A120**: Uses ST's open-source [STSELib](https://github.com/STMicroelectronics/STSELib) (BSD-3 license). For details see our [wolfSSL ST](https://www.wolfssl.com/docs/stm32/) page. @@ -65,29 +67,69 @@ To enable support define the following When the support is enabled, the ECC operations will be accelerated using the PKA crypto co-processor. -## STSAFE-A100 ECC Acceleration +## STSAFE-A ECC Acceleration -Using the wolfSSL PK callbacks and the reference ST Safe reference API's we support an ECC only cipher suite such as ECDHE-ECDSA-AES128-SHA256 for TLS client or server. +Using the wolfSSL PK callbacks or Crypto callbacks with the ST-Safe reference API's we support ECC operations for TLS client/server: + - **ECDSA Sign/Verify**: P-256 and P-384 (NIST and Brainpool curves) + - **ECDH Key Agreement**: For TLS key exchange + - **ECC Key Generation**: Ephemeral keys for TLS -At the wolfCrypt level we also support ECC native API's for `wc_ecc_*` using the ST-Safe. +At the wolfCrypt level we also support ECC native API's for `wc_ecc_*` using the ST-Safe via Crypto Callbacks. + +### Supported Hardware + +| Model | Macro | SDK | +|-------|-------|-----| +| STSAFE-A100/A110 | `WOLFSSL_STSAFEA100` | ST STSAFE-A1xx Middleware (proprietary) | +| STSAFE-A120 | `WOLFSSL_STSAFEA120` | [STSELib](https://github.com/STMicroelectronics/STSELib) (BSD-3, open source) | ### Building -`./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_STSAFEA100"` +For STSAFE-A100/A110 (legacy): -or +``` +./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_STSAFEA100" +``` -`#define HAVE_PK_CALLBACKS` -`#define WOLFSSL_STSAFEA100` +or in `user_settings.h`: +```c +#define HAVE_PK_CALLBACKS +#define WOLFSSL_STSAFEA100 +``` + +For STSAFE-A120 with STSELib: + +``` +./configure --enable-pkcallbacks CFLAGS="-DWOLFSSL_STSAFEA120" +``` + +or in `user_settings.h`: + +```c +#define HAVE_PK_CALLBACKS +#define WOLFSSL_STSAFEA120 +``` + +To use Crypto Callbacks (recommended for wolfCrypt-level ECC operations): + +```c +#define WOLF_CRYPTO_CB +#define WOLFSSL_STSAFEA120 /* or WOLFSSL_STSAFEA100 */ +``` ### Coding +#### Using PK Callbacks (TLS) + Setup the PK callbacks for TLS using: -``` -/* Setup PK Callbacks for STSAFE-A100 */ +```c +/* Setup PK Callbacks for STSAFE */ WOLFSSL_CTX* ctx; +SSL_STSAFE_SetupPkCallbacks(ctx); + +/* Or manually: */ wolfSSL_CTX_SetEccKeyGenCb(ctx, SSL_STSAFE_CreateKeyCb); wolfSSL_CTX_SetEccSignCb(ctx, SSL_STSAFE_SignCertificateCb); wolfSSL_CTX_SetEccVerifyCb(ctx, SSL_STSAFE_VerifyPeerCertCb); @@ -95,20 +137,131 @@ wolfSSL_CTX_SetEccSharedSecretCb(ctx, SSL_STSAFE_SharedSecretCb); wolfSSL_CTX_SetDevId(ctx, 0); /* enables wolfCrypt `wc_ecc_*` ST-Safe use */ ``` -The reference STSAFE-A100 PK callback functions are located in the `wolfcrypt/src/port/st/stsafe.c` file. +The reference STSAFE PK callback functions are located in the `wolfcrypt/src/port/st/stsafe.c` file. Adding a custom context to the callbacks: -``` +```c /* Setup PK Callbacks context */ WOLFSSL* ssl; void* myOwnCtx; -wolfSSL_SetEccKeyGenCtx(ssl, myOwnCtx); -wolfSSL_SetEccVerifyCtx(ssl, myOwnCtx); -wolfSSL_SetEccSignCtx(ssl, myOwnCtx); -wolfSSL_SetEccSharedSecretCtx(ssl, myOwnCtx); +SSL_STSAFE_SetupPkCallbackCtx(ssl, myOwnCtx); ``` +#### Using Crypto Callbacks (wolfCrypt) + +For direct wolfCrypt ECC operations using the hardware: + +```c +#include + +/* Register the crypto callback */ +wolfSTSAFE_CryptoCb_Ctx stsafeCtx; +stsafeCtx.devId = WOLF_STSAFE_DEVID; +wc_CryptoCb_RegisterDevice(WOLF_STSAFE_DEVID, wolfSSL_STSAFE_CryptoDevCb, &stsafeCtx); + +/* Use with ECC operations */ +ecc_key key; +wc_ecc_init_ex(&key, NULL, WOLF_STSAFE_DEVID); +/* ECC operations will now use STSAFE hardware */ +``` + +### Implementation Details + +The STSAFE support is self-contained in `wolfcrypt/src/port/st/stsafe.c` with SDK-specific implementations selected at compile time: + +| Macro | SDK | Description | +|-------|-----|-------------| +| `WOLFSSL_STSAFEA100` | STSAFE-A1xx Middleware | ST's proprietary SDK for A100/A110 | +| `WOLFSSL_STSAFEA120` | [STSELib](https://github.com/STMicroelectronics/STSELib) | ST's open-source SDK for A120 (BSD-3) | + +#### External Interface (Backwards Compatibility) + +For customers with existing custom implementations, define `WOLFSSL_STSAFE_INTERFACE_EXTERNAL` to use an external `stsafe_interface.h` file instead of the built-in implementation: + +```c +#define WOLFSSL_STSAFEA100 /* or WOLFSSL_STSAFEA120 */ +#define WOLFSSL_STSAFE_INTERFACE_EXTERNAL +``` + +When `WOLFSSL_STSAFE_INTERFACE_EXTERNAL` is defined, the customer must provide a `stsafe_interface.h` header that defines: + +| Item | Type | Description | +|------|------|-------------| +| `stsafe_curve_id_t` | typedef | Curve identifier type | +| `stsafe_slot_t` | typedef | Key slot identifier type | +| `STSAFE_ECC_CURVE_P256` | macro | P-256 curve ID value | +| `STSAFE_ECC_CURVE_P384` | macro | P-384 curve ID value | +| `STSAFE_KEY_SLOT_0/1/EPHEMERAL` | macros | Key slot values | +| `STSAFE_A_OK` | macro | Success return code | +| `STSAFE_MAX_KEY_LEN` | macro | Max key size in bytes (48) | +| `STSAFE_MAX_PUBKEY_RAW_LEN` | macro | Max public key size (96) | +| `STSAFE_MAX_SIG_LEN` | macro | Max signature size (96) | + +And provide implementations for these internal interface functions: +- `int stsafe_interface_init(void)` +- `int stsafe_create_key(stsafe_slot_t*, stsafe_curve_id_t, uint8_t*)` +- `int stsafe_sign(stsafe_slot_t, stsafe_curve_id_t, uint8_t*, uint8_t*)` +- `int stsafe_verify(stsafe_curve_id_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*, int32_t*)` +- `int stsafe_shared_secret(stsafe_slot_t, stsafe_curve_id_t, uint8_t*, uint8_t*, uint8_t*, int32_t*)` +- `int stsafe_read_certificate(uint8_t**, uint32_t*)` +- `int stsafe_get_random(uint8_t*, uint32_t)` (if `USE_STSAFE_RNG_SEED` defined) + +When **NOT** defined (default behavior): All code is self-contained in `stsafe.c` using the appropriate SDK automatically. + +The implementation provides these internal operations: + +| Operation | Description | +|-----------|-------------| +| `stsafe_interface_init()` | Initialize the STSAFE device (called by `wolfCrypt_Init()`) | +| `stsafe_sign()` | ECDSA signature generation (P-256/P-384) | +| `stsafe_verify()` | ECDSA signature verification (P-256/P-384) | +| `stsafe_create_key()` | Generate ECC key pair on device | +| `stsafe_shared_secret()` | ECDH shared secret computation | +| `stsafe_read_certificate()` | Read device certificate from secure storage | + +### STSELib Setup (A120) + +For STSAFE-A120, you need to include the STSELib library: + +1. Clone STSELib as a submodule or add to your project: + ```bash + git submodule add https://github.com/STMicroelectronics/STSELib.git lib/stselib + ``` + +2. Add STSELib headers to your include path + +3. Implement the platform abstraction files required by STSELib: + - `stse_conf.h` - Configuration (target device, features) + - `stse_platform_generic.h` - Platform callbacks (I2C, timing) + +4. See STSELib documentation for platform-specific integration details + +### Raspberry Pi with STSAFE-A120 + +For testing on a Raspberry Pi with an STSAFE-A120 connected via I2C: + +1. **Enable I2C** on the Raspberry Pi: + ```bash + sudo raspi-config + # Navigate to: Interface Options -> I2C -> Enable + ``` + +2. **Verify the STSAFE device is detected** (default I2C address is 0x20): + ```bash + sudo i2cdetect -y 1 + ``` + +3. **Build wolfSSL with STSAFE-A120 support**: + ```bash + ./configure --enable-pkcallbacks --enable-cryptocb \ + CFLAGS="-DWOLFSSL_STSAFEA120 -I/path/to/STSELib" + make + sudo make install + ``` + +4. **Platform abstraction**: Implement the STSELib I2C callbacks using the Linux I2C driver (`/dev/i2c-1`). + ### Benchmarks and Memory Use Software only implementation (STM32L4 120Mhz, Cortex-M4, Fast Math): diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 832b702148..7296974e4d 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -28,48 +28,927 @@ #include #ifndef STSAFE_INTERFACE_PRINTF -#define STSAFE_INTERFACE_PRINTF(...) WC_DO_NOTHING + #define STSAFE_INTERFACE_PRINTF(...) WC_DO_NOTHING #endif -#ifdef WOLFSSL_STSAFEA100 +/* Combined STSAFE macro - set in stsafe.h when either A100/A120 is defined */ +#ifdef WOLFSSL_STSAFE -int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, - word32* pRawCertificateLen) +/* ========================================================================== */ +/* Internal Implementation (when NOT using external stsafe_interface.h) */ +/* ========================================================================== */ + +/* When WOLFSSL_STSAFE_INTERFACE_EXTERNAL is defined, all internal + * implementation is skipped and the customer provides their own + * stsafe_interface.h with custom implementations. This maintains + * backwards compatibility with older integration approaches. */ +#ifndef WOLFSSL_STSAFE_INTERFACE_EXTERNAL + +/* ========================================================================== */ +/* SDK-Specific Includes */ +/* ========================================================================== */ + +#ifdef WOLFSSL_STSAFEA120 + /* STSELib includes for A120 */ + #include "stselib.h" +#else /* WOLFSSL_STSAFEA100 */ + /* Legacy STSAFE-A1xx SDK includes */ + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +/* ========================================================================== */ +/* Global State */ +/* ========================================================================== */ + +#ifdef WOLFSSL_STSAFEA120 + /* STSELib handler */ + static stse_Handler_t g_stse_handler; + static int g_stse_initialized = 0; +#else /* WOLFSSL_STSAFEA100 */ + /* Legacy SDK handle */ + static void* g_stsafe_handle = NULL; + + /* Host MAC and Cipher Keys for secure communication */ + /* NOTE: These are example keys + * - real implementations should store securely */ + #ifndef STSAFE_HOST_KEY_MAC + static const uint8_t g_host_mac_key[16] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + #endif + #ifndef STSAFE_HOST_KEY_CIPHER + static const uint8_t g_host_cipher_key[16] = { + 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44, + 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, 0x88, 0x88 + }; + #endif +#endif + +/* Current curve mode for signing operations */ +static stsafe_curve_id_t g_stsafe_curve_mode = STSAFE_DEFAULT_CURVE; + + +/* ========================================================================== */ +/* Internal Helper Functions */ +/* ========================================================================== */ + +/** + * \brief Get key size in bytes for a given curve + */ +static int stsafe_get_key_size(stsafe_curve_id_t curve_id) { - int err; + switch (curve_id) { + case STSAFE_ECC_CURVE_P256: + #ifdef STSAFE_ECC_CURVE_BP256 + case STSAFE_ECC_CURVE_BP256: + #endif + return 32; + case STSAFE_ECC_CURVE_P384: + #ifdef STSAFE_ECC_CURVE_BP384 + case STSAFE_ECC_CURVE_BP384: + #endif + return 48; + default: + break; + } + return 0; +} - if (pRawCertificate == NULL || pRawCertificateLen == NULL) { - return BAD_FUNC_ARG; +/** + * \brief Convert wolfSSL ECC curve ID to STSAFE curve ID + */ +static stsafe_curve_id_t stsafe_get_ecc_curve_id(int ecc_curve) +{ + switch (ecc_curve) { + case ECC_SECP256R1: + return STSAFE_ECC_CURVE_P256; + case ECC_SECP384R1: + return STSAFE_ECC_CURVE_P384; + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP256) + case ECC_BRAINPOOLP256R1: + return STSAFE_ECC_CURVE_BP256; + #endif + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP384) + case ECC_BRAINPOOLP384R1: + return STSAFE_ECC_CURVE_BP384; + #endif + default: + break; + } + return STSAFE_DEFAULT_CURVE; +} + +/** + * \brief Convert STSAFE curve ID to wolfSSL ECC curve ID + */ +#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS) +static int stsafe_get_ecc_curve(stsafe_curve_id_t curve_id) +{ + switch (curve_id) { + case STSAFE_ECC_CURVE_P256: + return ECC_SECP256R1; + case STSAFE_ECC_CURVE_P384: + return ECC_SECP384R1; + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP256) + case STSAFE_ECC_CURVE_BP256: + return ECC_BRAINPOOLP256R1; + #endif + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP384) + case STSAFE_ECC_CURVE_BP384: + return ECC_BRAINPOOLP384R1; + #endif + default: + break; + } + return ECC_SECP256R1; +} +#endif + +/** + * \brief Get current curve mode for signing + */ +static stsafe_curve_id_t stsafe_get_curve_mode(void) +{ + return g_stsafe_curve_mode; +} + +/** + * \brief Set current curve mode for signing + */ +static int stsafe_set_curve_mode(stsafe_curve_id_t curve_id) +{ + g_stsafe_curve_mode = curve_id; + return 0; +} + +/* Unused function workaround for some compilers */ +#ifdef __GNUC__ +__attribute__((unused)) +#endif +static void stsafe_unused_funcs(void) +{ +#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS) + (void)stsafe_get_ecc_curve; +#endif + (void)stsafe_set_curve_mode; +} + +/* ========================================================================== */ +/* Internal Interface Functions - SDK Specific Implementations */ +/* ========================================================================== */ + +#ifdef WOLFSSL_STSAFEA120 +/* -------------------------------------------------------------------------- */ +/* STSELib (A120) Implementation */ +/* -------------------------------------------------------------------------- */ + +/** + * \brief Initialize STSAFE-A120 device using STSELib + */ +int stsafe_interface_init(void) +{ + int rc = 0; + stse_ReturnCode_t ret; + + if (g_stse_initialized) { + return 0; /* Already initialized */ + } + + /* Set default handler values */ + ret = stse_set_default_handler_value(&g_stse_handler); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_set_default_handler_value error: %d\n", + ret); + rc = -1; + } + + if (rc == 0) { + /* Configure for STSAFE-A120 on I2C bus 1 */ + g_stse_handler.device_type = STSAFE_A120; + #ifdef STSAFE_I2C_BUS + g_stse_handler.io.busID = STSAFE_I2C_BUS; + #else + g_stse_handler.io.busID = 1; + #endif + g_stse_handler.io.BusSpeed = 400; /* 400 kHz */ + + /* Initialize STSELib - this sets up I2C communication */ + ret = stse_init(&g_stse_handler); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_init error: %d\n", ret); + rc = -1; + } + } + + if (rc == 0) { + g_stse_initialized = 1; + #ifdef USE_STSAFE_VERBOSE + WOLFSSL_MSG("STSAFE-A120 (STSELib) initialized"); + #endif + } + + return rc; +} + +/** + * \brief Generate ECC key pair on STSAFE-A120 + */ +static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyRaw) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Ephemeral slot */ + + /* Generate key pair - public key is X||Y concatenated */ + ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, curve_id, + 255, /* usage_limit */ + pPubKeyRaw); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair error: %d\n", ret); + rc = (int)ret; + } + + if (rc == STSAFE_A_OK && pSlot != NULL) { + *pSlot = slot; + } + + return rc; +} + +/** + * \brief ECDSA sign using STSAFE-A120 + */ +static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pHash, uint8_t* pSigRS) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + int key_sz = stsafe_get_key_size(curve_id); + + /* Sign hash - output is R || S concatenated */ + ret = stse_ecc_generate_signature(&g_stse_handler, slot, curve_id, + pHash, (uint16_t)key_sz, pSigRS); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_ecc_generate_signature error: %d\n", ret); + rc = (int)ret; + } + + return rc; +} + +/** + * \brief ECDSA verify using STSAFE-A120 + */ +static int stsafe_verify(stsafe_curve_id_t curve_id, uint8_t* pHash, + uint8_t* pSigRS, uint8_t* pPubKeyX, uint8_t* pPubKeyY, + int32_t* pResult) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + int key_sz = stsafe_get_key_size(curve_id); + uint8_t pubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; + uint8_t validity = 0; + + /* Combine X and Y into single buffer (X||Y) */ + XMEMCPY(pubKey, pPubKeyX, key_sz); + XMEMCPY(pubKey + key_sz, pPubKeyY, key_sz); + + /* Verify signature - pMessage is the hash, pSignature is R||S */ + ret = stse_ecc_verify_signature(&g_stse_handler, curve_id, + pubKey, /* public key X||Y */ + pSigRS, /* signature R||S */ + pHash, /* message (hash) */ + (uint16_t)key_sz, /* message length */ + 0, /* eddsa_variant (0 for non-EdDSA) */ + &validity); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_ecc_verify_signature error: %d\n", ret); + *pResult = 0; + rc = (int)ret; + } + + if (rc == STSAFE_A_OK) { + *pResult = (validity != 0) ? 1 : 0; + } + + return rc; +} + +/** + * \brief ECDH shared secret using STSAFE-A120 + */ +static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyX, uint8_t* pPubKeyY, + uint8_t* pSharedSecret, + int32_t* pSharedSecretLen) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + int key_sz = stsafe_get_key_size(curve_id); + uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; + + /* Combine peer X and Y (X||Y format) */ + XMEMCPY(peerPubKey, pPubKeyX, key_sz); + XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); + + /* Compute shared secret */ + ret = stse_ecc_establish_shared_secret(&g_stse_handler, slot, curve_id, + peerPubKey, pSharedSecret); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret error: %d\n", + ret); + rc = (int)ret; + } + + if (rc == STSAFE_A_OK) { + *pSharedSecretLen = (int32_t)key_sz; + } + + return rc; +} + +/** + * \brief Read device certificate from STSAFE-A120 + */ +static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) +{ +#ifdef WOLFSSL_NO_MALLOC + /* Certificate reading requires dynamic allocation */ + (void)ppCert; + (void)pCertLen; + return NOT_COMPILED_IN; +#else + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + uint16_t certLen = 0; + uint8_t certZone = 0; /* Certificate zone 0 */ + + /* First, get certificate size */ + ret = stse_get_device_certificate_size(&g_stse_handler, certZone, &certLen); + if (ret != STSE_OK || certLen == 0) { + STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size error: %d\n", + ret); + rc = (int)ret; + } + + /* Allocate buffer */ + if (rc == STSAFE_A_OK) { + *ppCert = (uint8_t*)XMALLOC(certLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*ppCert == NULL) { + rc = MEMORY_E; + } + } + + /* Read certificate */ + if (rc == STSAFE_A_OK) { + ret = stse_get_device_certificate(&g_stse_handler, certZone, certLen, + *ppCert); + if (ret != STSE_OK) { + XFREE(*ppCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *ppCert = NULL; + STSAFE_INTERFACE_PRINTF("stse_get_device_certificate error: %d\n", + ret); + rc = (int)ret; + } + } + + if (rc == STSAFE_A_OK) { + *pCertLen = certLen; + } + + return rc; +#endif /* WOLFSSL_NO_MALLOC */ +} + +#if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED) +/** + * \brief Get random bytes from STSAFE-A120 + */ +static int stsafe_get_random(uint8_t* pRandom, uint32_t size) +{ + int rc; + stse_ReturnCode_t ret; + uint16_t len = (size > 0xFFFF) ? 0xFFFF : (uint16_t)size; + + ret = stse_generate_random(&g_stse_handler, pRandom, len); + if (ret != STSE_OK) { + rc = -1; + } + else { + rc = (int)len; + } + + return rc; +} +#endif + +#else /* WOLFSSL_STSAFEA100 */ +/* -------------------------------------------------------------------------- */ +/* Legacy STSAFE-A1xx SDK (A100/A110) Implementation */ +/* -------------------------------------------------------------------------- */ + +/** + * \brief Set host keys for secure communication + */ +static void stsafe_set_host_keys(void* handle) +{ + StSafeA_SetHostMacKey(handle, g_host_mac_key); + StSafeA_SetHostCipherKey(handle, g_host_cipher_key); +} + +/** + * \brief Check and initialize host keys + */ +static int stsafe_check_host_keys(void* handle) +{ + uint8_t status_code; + StSafeA_HostKeySlotBuffer* pHostKeySlot; + + status_code = StSafeA_HostKeySlotQuery(handle, &pHostKeySlot, + STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && !pHostKeySlot->HostKeyPresenceFlag) { + /* Host keys not set, initialize them */ + uint8_t hostKeys[32]; + XMEMCPY(hostKeys, g_host_mac_key, 16); + XMEMCPY(hostKeys + 16, g_host_cipher_key, 16); + + status_code = StSafeA_PutAttribute(handle, STSAFE_A_HOST_KEY_SLOT_TAG, + hostKeys, sizeof(hostKeys), STSAFE_A_NO_MAC); + } + + return status_code; +} + +/** + * \brief Initialize STSAFE-A100/A110 device + */ +int stsafe_interface_init(void) +{ + int rc = 0; + uint8_t status_code; + const uint8_t echo_data[3] = {0x01, 0x02, 0x03}; + StSafeA_EchoBuffer* echo_resp = NULL; + + if (g_stsafe_handle != NULL) { + return 0; /* Already initialized */ + } + + /* Create handle */ + status_code = StSafeA_CreateHandle(&g_stsafe_handle, STSAFE_I2C_ADDR); + if (status_code != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("StSafeA_CreateHandle error: %d\n", + status_code); + rc = -1; + } + + /* Echo test to verify communication */ + if (rc == 0) { + status_code = StSafeA_Echo(g_stsafe_handle, (uint8_t*)echo_data, 3, + &echo_resp, STSAFE_A_NO_MAC); + if (status_code != STSAFE_A_OK || + XMEMCMP(echo_data, echo_resp->Data, 3) != 0) { + STSAFE_INTERFACE_PRINTF("StSafeA_Echo error: %d\n", status_code); + rc = -1; + } + XFREE(echo_resp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + + /* Check/initialize host keys */ + if (rc == 0) { + status_code = stsafe_check_host_keys(g_stsafe_handle); + if (status_code != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_check_host_keys error: %d\n", + status_code); + rc = -1; + } } #ifdef USE_STSAFE_VERBOSE - WOLFSSL_MSG("SSL_STSAFE_LoadDeviceCertificate"); + if (rc == 0) { + WOLFSSL_MSG("STSAFE-A100/A110 initialized"); + } #endif - /* Try reading device certificate from ST-SAFE Zone 0 */ - err = stsafe_interface_read_device_certificate_raw( - pRawCertificate, (uint32_t*)pRawCertificateLen); - if (err == STSAFE_A_OK) { - #if 0 - /* example for loading into WOLFSSL_CTX */ - err = wolfSSL_CTX_use_certificate_buffer(ctx, - *pRawCertificate, *pRawCertificateLen, SSL_FILETYPE_ASN1); - if (err != WOLFSSL_SUCCESS) { - /* failed */ - } - /* can free now */ - XFREE(*pRawCertificate, NULL, DYNAMIC_TEMP_BUFFER); - *pRawCertificate = NULL; - #endif + return rc; +} + +/** + * \brief Generate ECC key pair on STSAFE-A100/A110 + */ +static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyRaw) +{ + int rc; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); + stsafe_slot_t slot = STSAFE_KEY_SLOT_1; + StSafeA_CoordinateBuffer* pubX = NULL; + StSafeA_CoordinateBuffer* pubY = NULL; + uint8_t* pointRepId = NULL; + + stsafe_set_host_keys(g_stsafe_handle); + + status_code = StSafeA_GenerateKeyPair(g_stsafe_handle, slot, 0xFFFF, 1, + (StSafeA_KeyUsageAuthorizationFlags)( + STSAFE_A_COMMAND_RESPONSE_SIGNATURE | + STSAFE_A_MESSAGE_DIGEST_SIGNATURE | + STSAFE_A_KEY_ESTABLISHMENT), + curve_id, &pointRepId, &pubX, &pubY, STSAFE_A_HOST_C_MAC); + + if (status_code == STSAFE_A_OK && pointRepId != NULL && + *pointRepId == STSAFE_A_POINT_REPRESENTATION_ID) { + XMEMCPY(pPubKeyRaw, pubX->Data, pubX->Length); + XMEMCPY(pPubKeyRaw + key_sz, pubY->Data, pubY->Length); + rc = STSAFE_A_OK; } else { - err = WC_HW_E; + rc = (int)(uint8_t)-1; + } + + /* Free SDK-allocated buffers */ + XFREE(pubX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (rc == STSAFE_A_OK && pSlot != NULL) { + *pSlot = slot; + } + + return rc; +} + +/** + * \brief ECDSA sign using STSAFE-A100/A110 + */ +static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pHash, uint8_t* pSigRS) +{ + int rc; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); + StSafeA_SignatureBuffer* signature = NULL; + StSafeA_HashTypes hashType; + size_t r_length, s_length; + + hashType = (curve_id == STSAFE_ECC_CURVE_P384 || + curve_id == STSAFE_ECC_CURVE_BP384) ? + STSAFE_HASH_SHA384 : STSAFE_HASH_SHA256; + + status_code = StSafeA_GenerateSignature(g_stsafe_handle, slot, pHash, + hashType, &signature, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && signature != NULL) { + /* Parse signature - format is: len(2) || R || len(2) || S */ + r_length = ((uint16_t)signature->Data[0] << 8) | signature->Data[1]; + s_length = ((uint16_t)signature->Data[2 + r_length] << 8) | + signature->Data[3 + r_length]; + + /* Copy R and S to output (zero-padded) */ + XMEMSET(pSigRS, 0, key_sz * 2); + XMEMCPY(pSigRS + (key_sz - r_length), &signature->Data[2], r_length); + XMEMCPY(pSigRS + key_sz + (key_sz - s_length), + &signature->Data[4 + r_length], s_length); + rc = STSAFE_A_OK; + } + else { + rc = (int)status_code; + } + + /* Free SDK-allocated buffer */ + XFREE(signature, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return rc; +} + +/** + * \brief ECDSA verify using STSAFE-A100/A110 + */ +static int stsafe_verify(stsafe_curve_id_t curve_id, uint8_t* pHash, + uint8_t* pSigRS, uint8_t* pPubKeyX, uint8_t* pPubKeyY, + int32_t* pResult) +{ + int rc = (int)(uint8_t)-1; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + StSafeA_CoordinateBuffer* X = NULL; + StSafeA_CoordinateBuffer* Y = NULL; + StSafeA_SignatureBuffer* R = NULL; + StSafeA_SignatureBuffer* S = NULL; + StSafeA_SignatureBuffer* Hash = NULL; +#else + /* Stack buffers: 2 bytes for Length + STSAFE_MAX_KEY_LEN for Data */ + byte R_buf[2 + STSAFE_MAX_KEY_LEN]; + byte S_buf[2 + STSAFE_MAX_KEY_LEN]; + byte Hash_buf[2 + STSAFE_MAX_KEY_LEN]; + byte X_buf[2 + STSAFE_MAX_KEY_LEN]; + byte Y_buf[2 + STSAFE_MAX_KEY_LEN]; + StSafeA_SignatureBuffer* R = (StSafeA_SignatureBuffer*)R_buf; + StSafeA_SignatureBuffer* S = (StSafeA_SignatureBuffer*)S_buf; + StSafeA_SignatureBuffer* Hash = (StSafeA_SignatureBuffer*)Hash_buf; + StSafeA_CoordinateBuffer* X = (StSafeA_CoordinateBuffer*)X_buf; + StSafeA_CoordinateBuffer* Y = (StSafeA_CoordinateBuffer*)Y_buf; +#endif + StSafeA_VerifySignatureBuffer* Verif = NULL; + + *pResult = 0; + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + /* Allocate buffers */ + R = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + S = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + Hash = (StSafeA_SignatureBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + X = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + Y = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (X == NULL || Y == NULL || R == NULL || S == NULL || Hash == NULL) { + XFREE(R, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(S, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Hash, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(X, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Y, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + R->Length = key_sz; + S->Length = key_sz; + Hash->Length = key_sz; + X->Length = key_sz; + Y->Length = key_sz; + + XMEMCPY(R->Data, pSigRS, key_sz); + XMEMCPY(S->Data, pSigRS + key_sz, key_sz); + XMEMCPY(Hash->Data, pHash, key_sz); + XMEMCPY(X->Data, pPubKeyX, key_sz); + XMEMCPY(Y->Data, pPubKeyY, key_sz); + + status_code = StSafeA_VerifyMessageSignature(g_stsafe_handle, + curve_id, X, Y, R, S, Hash, &Verif, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && Verif != NULL) { + *pResult = Verif->SignatureValidity ? 1 : 0; + if (Verif->SignatureValidity) { + rc = STSAFE_A_OK; + } + } +#ifndef WOLFSSL_NO_MALLOC + /* Free SDK-allocated buffer */ + XFREE(Verif, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(R, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(S, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Hash, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(X, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Y, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return rc; +} + +/** + * \brief ECDH shared secret using STSAFE-A100/A110 + */ +static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, + uint8_t* pPubKeyX, uint8_t* pPubKeyY, + uint8_t* pSharedSecret, + int32_t* pSharedSecretLen) +{ + int rc = (int)(uint8_t)-1; + uint8_t status_code; + int key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + StSafeA_CoordinateBuffer* peerX = NULL; + StSafeA_CoordinateBuffer* peerY = NULL; +#else + /* Stack buffers: 2 bytes for Length + STSAFE_MAX_KEY_LEN for Data */ + byte peerX_buf[2 + STSAFE_MAX_KEY_LEN]; + byte peerY_buf[2 + STSAFE_MAX_KEY_LEN]; + StSafeA_CoordinateBuffer* peerX = (StSafeA_CoordinateBuffer*)peerX_buf; + StSafeA_CoordinateBuffer* peerY = (StSafeA_CoordinateBuffer*)peerY_buf; +#endif + StSafeA_SharedSecretBuffer* sharedSecret = NULL; + + stsafe_set_host_keys(g_stsafe_handle); + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + peerX = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + peerY = (StSafeA_CoordinateBuffer*)XMALLOC(key_sz + 2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (peerX == NULL || peerY == NULL) { + XFREE(peerX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(peerY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + peerX->Length = key_sz; + peerY->Length = key_sz; + XMEMCPY(peerX->Data, pPubKeyX, key_sz); + XMEMCPY(peerY->Data, pPubKeyY, key_sz); + + status_code = StSafeA_EstablishKey(g_stsafe_handle, slot, + peerX, peerY, &sharedSecret, STSAFE_A_HOST_C_MAC); + + if (status_code == STSAFE_A_OK && sharedSecret != NULL) { + *pSharedSecretLen = sharedSecret->SharedSecret.Length; + XMEMCPY(pSharedSecret, sharedSecret->SharedSecret.Data, + sharedSecret->SharedSecret.Length); + rc = STSAFE_A_OK; + } +#ifndef WOLFSSL_NO_MALLOC + /* Free SDK-allocated buffer */ + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(peerX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(peerY, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return rc; +} + +/** + * \brief Read device certificate from STSAFE-A100/A110 + */ +static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) +{ +#ifdef WOLFSSL_NO_MALLOC + /* Certificate reading requires dynamic allocation */ + (void)ppCert; + (void)pCertLen; + return NOT_COMPILED_IN; +#else + int rc = STSAFE_A_OK; + uint8_t status_code; + StSafeA_ReadBuffer* readBuf = NULL; + struct stsafe_a* stsafe_a = (struct stsafe_a*)g_stsafe_handle; + uint8_t step; + uint16_t i; + + *pCertLen = 0; + + /* Read first 4 bytes to determine certificate length */ + status_code = StSafeA_Read(g_stsafe_handle, 0, 0, STSAFE_A_ALWAYS, + 0, 0, 4, &readBuf, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && readBuf->Length == 4 && + readBuf->Data[0] == 0x30) { + /* Parse ASN.1 length */ + switch (readBuf->Data[1]) { + case 0x81: + *pCertLen = readBuf->Data[2] + 3; + break; + case 0x82: + *pCertLen = ((uint16_t)readBuf->Data[2] << 8) + + readBuf->Data[3] + 4; + break; + default: + if (readBuf->Data[1] < 0x81) { + *pCertLen = readBuf->Data[1] + 2; + } + break; + } + } + else { + rc = (int)status_code; + } + XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + readBuf = NULL; + + if (rc == STSAFE_A_OK && *pCertLen > 0) { + *ppCert = (uint8_t*)XMALLOC(*pCertLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (*ppCert == NULL) { + rc = (int)(uint8_t)-1; + } + } + + if (rc == STSAFE_A_OK && *pCertLen > 0) { + step = 223 - (stsafe_a->CrcSupport ? 2 : 0); + + for (i = 0; rc == STSAFE_A_OK && i < *pCertLen / step; i++) { + status_code = StSafeA_Read(g_stsafe_handle, 0, 0, + STSAFE_A_ALWAYS, 0, i * step, step, &readBuf, + STSAFE_A_NO_MAC); + if (status_code == STSAFE_A_OK) { + XMEMCPY(*ppCert + (i * step), readBuf->Data, readBuf->Length); + } + else { + rc = (int)status_code; + } + XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + readBuf = NULL; + } + + if (rc == STSAFE_A_OK && (*pCertLen % step)) { + status_code = StSafeA_Read(g_stsafe_handle, 0, 0, + STSAFE_A_ALWAYS, 0, i * step, *pCertLen % step, + &readBuf, STSAFE_A_NO_MAC); + if (status_code == STSAFE_A_OK) { + XMEMCPY(*ppCert + (i * step), readBuf->Data, readBuf->Length); + } + else { + rc = (int)status_code; + } + XFREE(readBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + readBuf = NULL; + } + } + + return rc; +#endif /* WOLFSSL_NO_MALLOC */ +} + +#if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED) +/** + * \brief Get random bytes from STSAFE-A100/A110 + */ +static int stsafe_get_random(uint8_t* pRandom, uint32_t size) +{ + int rc; + uint8_t status_code; + StSafeA_GenerateRandomBuffer* rndBuf = NULL; + uint8_t reqSize = (size > 255) ? 255 : (uint8_t)size; + + status_code = StSafeA_GenerateRandom(g_stsafe_handle, STSAFE_A_EPHEMERAL, + reqSize, &rndBuf, STSAFE_A_NO_MAC); + + if (status_code == STSAFE_A_OK && rndBuf != NULL) { + rc = (int)rndBuf->Length; + XMEMCPY(pRandom, rndBuf->Data, rndBuf->Length); + } + else { + rc = -1; + } + + XFREE(rndBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return rc; +} +#endif + +#endif /* WOLFSSL_STSAFEA120 */ + +#endif /* !WOLFSSL_STSAFE_INTERFACE_EXTERNAL */ + + +/* ========================================================================== */ +/* Public API Functions */ +/* ========================================================================== */ + +/** + * \brief Load device certificate from STSAFE + */ +int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, + word32* pRawCertificateLen) +{ + int err = 0; + + if (pRawCertificate == NULL || pRawCertificateLen == NULL) { + err = BAD_FUNC_ARG; + } + +#ifdef USE_STSAFE_VERBOSE + if (err == 0) { + WOLFSSL_MSG("SSL_STSAFE_LoadDeviceCertificate"); + } +#endif + + if (err == 0) { + err = stsafe_read_certificate(pRawCertificate, pRawCertificateLen); + if (err != STSAFE_A_OK) { + err = WC_HW_E; + } } return err; } -#ifdef HAVE_PK_CALLBACKS + +/* ========================================================================== */ +/* PK Callbacks */ +/* ========================================================================== */ + +#if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS) /** * \brief Key Gen Callback (used by TLS server) @@ -77,10 +956,14 @@ int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, int ecc_curve, void* ctx) { - int err; + int err = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* pubKeyRaw = NULL; +#else byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; - StSafeA_KeySlotNumber slot; - StSafeA_CurveId curve_id; +#endif + stsafe_slot_t slot; + stsafe_curve_id_t curve_id; (void)ssl; (void)ctx; @@ -89,28 +972,38 @@ int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, WOLFSSL_MSG("CreateKeyCb: STSAFE"); #endif - /* get curve */ - curve_id = stsafe_get_ecc_curve_id(ecc_curve); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (pubKeyRaw == NULL) { + err = MEMORY_E; + } +#endif - /* generate new ephemeral key on device */ - err = stsafe_interface_create_key(&slot, curve_id, (uint8_t*)&pubKeyRaw[0]); - if (err != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_create_key error: %d\n", err); - #endif - err = WC_HW_E; - return err; + if (err == 0) { + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + + err = stsafe_create_key(&slot, curve_id, pubKeyRaw); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", err); + err = WC_HW_E; + } } - /* load generated public key into key, used by wolfSSL */ - err = wc_ecc_import_unsigned(key, &pubKeyRaw[0], &pubKeyRaw[keySz], - NULL, ecc_curve); + if (err == 0) { + err = wc_ecc_import_unsigned(key, pubKeyRaw, &pubKeyRaw[keySz], + NULL, ecc_curve); + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif return err; } /** - * \brief Verify Peer Cert Callback. + * \brief Verify Peer Cert Callback */ int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl, const unsigned char* sig, unsigned int sigSz, @@ -118,42 +1011,63 @@ int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl, const unsigned char* keyDer, unsigned int keySz, int* result, void* ctx) { - int err; + int err = 0; + int eccKeyInit = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* sigRS = NULL; + byte* pubKeyX = NULL; + byte* pubKeyY = NULL; +#else byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r = NULL, *s = NULL; - word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; byte pubKeyX[STSAFE_MAX_PUBKEY_RAW_LEN/2]; byte pubKeyY[STSAFE_MAX_PUBKEY_RAW_LEN/2]; - word32 pubKeyX_len = sizeof(pubKeyX); - word32 pubKeyY_len = sizeof(pubKeyY); - ecc_key key; +#endif + byte* r = NULL; + byte* s = NULL; + word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; + word32 pubKeyX_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + word32 pubKeyY_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + ecc_key eccKey; word32 inOutIdx = 0; - StSafeA_CurveId curve_id = STSAFE_A_NIST_P_256; + stsafe_curve_id_t curve_id = STSAFE_ECC_CURVE_P256; int ecc_curve; int key_sz = 0; (void)ssl; (void)ctx; + (void)hashSz; #ifdef USE_STSAFE_VERBOSE WOLFSSL_MSG("VerifyPeerCertCB: STSAFE"); #endif - err = wc_ecc_init(&key); - if (err != 0) { - return err; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + pubKeyX = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyY = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (sigRS == NULL || pubKeyX == NULL || pubKeyY == NULL) { + err = MEMORY_E; + } +#endif + + if (err == 0) { + err = wc_ecc_init(&eccKey); + if (err == 0) { + eccKeyInit = 1; + } } - /* Decode the public key */ - err = wc_EccPublicKeyDecode(keyDer, &inOutIdx, &key, keySz); if (err == 0) { - /* Extract Raw X and Y coordinates of the public key */ - err = wc_ecc_export_public_raw(&key, pubKeyX, &pubKeyX_len, + err = wc_EccPublicKeyDecode(keyDer, &inOutIdx, &eccKey, keySz); + } + if (err == 0) { + err = wc_ecc_export_public_raw(&eccKey, pubKeyX, &pubKeyX_len, pubKeyY, &pubKeyY_len); } if (err == 0) { - /* determine curve */ - ecc_curve = key.dp->id; + ecc_curve = eccKey.dp->id; curve_id = stsafe_get_ecc_curve_id(ecc_curve); key_sz = stsafe_get_key_size(curve_id); if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) { @@ -161,113 +1075,139 @@ int SSL_STSAFE_VerifyPeerCertCb(WOLFSSL* ssl, } } if (err == 0) { - /* Extract R and S from signature */ - XMEMSET(sigRS, 0, sizeof(sigRS)); + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); r = &sigRS[0]; s = &sigRS[key_sz]; err = wc_ecc_sig_to_rs(sig, sigSz, r, &r_len, s, &s_len); } if (err == 0) { - /* make sure R and S are not too large */ - if (r_len > key_sz || s_len > key_sz) { + if ((int)r_len > key_sz || (int)s_len > key_sz) { err = BAD_FUNC_ARG; } } if (err == 0) { - /* make sure R and S are zero padded on front */ - XMEMMOVE(&sigRS[key_sz-r_len], r, r_len); - XMEMSET(&sigRS[0], 0, key_sz-r_len); - XMEMMOVE(&sigRS[key_sz + (key_sz-s_len)], s, s_len); - XMEMSET(&sigRS[key_sz], 0, key_sz-s_len); + /* Zero-pad R and S */ + XMEMMOVE(&sigRS[key_sz - r_len], r, r_len); + XMEMSET(&sigRS[0], 0, key_sz - r_len); + XMEMMOVE(&sigRS[key_sz + (key_sz - s_len)], s, s_len); + XMEMSET(&sigRS[key_sz], 0, key_sz - s_len); - /* Verify signature */ - err = stsafe_interface_verify(curve_id, (uint8_t*)hash, sigRS, + err = stsafe_verify(curve_id, (uint8_t*)hash, sigRS, pubKeyX, pubKeyY, (int32_t*)result); if (err != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_verify error: %d\n", err); - #endif - err = -err; + STSAFE_INTERFACE_PRINTF("stsafe_verify error: %d\n", err); + err = WC_HW_E; } } - wc_ecc_free(&key); + if (eccKeyInit) { + wc_ecc_free(&eccKey); + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return err; } /** - * \brief Sign Certificate Callback. + * \brief Sign Certificate Callback */ int SSL_STSAFE_SignCertificateCb(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx) { - int err; + int err = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* digest = NULL; + byte* sigRS = NULL; +#else byte digest[STSAFE_MAX_KEY_LEN]; byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r, *s; - StSafeA_CurveId curve_id; +#endif + byte* r; + byte* s; + stsafe_curve_id_t curve_id; int key_sz; (void)ssl; (void)ctx; + (void)key; + (void)keySz; #ifdef USE_STSAFE_VERBOSE WOLFSSL_MSG("SignCertificateCb: STSAFE"); #endif - curve_id = stsafe_get_curve_mode(); - key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + digest = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (digest == NULL || sigRS == NULL) { + err = MEMORY_E; + } +#endif - /* Build input digest */ - if (inSz > key_sz) - inSz = key_sz; - XMEMSET(&digest[0], 0, sizeof(digest)); - XMEMCPY(&digest[key_sz - inSz], in, inSz); + if (err == 0) { + curve_id = stsafe_get_curve_mode(); + key_sz = stsafe_get_key_size(curve_id); - /* Sign using slot 0: Result is R then S */ - /* Sign will always use the curve type in slot 0 (the TLS curve needs to match) */ - XMEMSET(sigRS, 0, sizeof(sigRS)); - err = stsafe_interface_sign(STSAFE_A_SLOT_0, curve_id, digest, sigRS); - if (err != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_sign error: %d\n", err); - #endif - err = WC_HW_E; - return err; + if ((int)inSz > key_sz) + inSz = key_sz; + + XMEMSET(digest, 0, STSAFE_MAX_KEY_LEN); + XMEMCPY(&digest[key_sz - inSz], in, inSz); + + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); + err = stsafe_sign(STSAFE_KEY_SLOT_0, curve_id, digest, sigRS); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_sign error: %d\n", err); + err = WC_HW_E; + } } - /* Convert R and S to signature */ - r = &sigRS[0]; - s = &sigRS[key_sz]; - err = wc_ecc_rs_raw_to_sig((const byte*)r, key_sz, (const byte*)s, key_sz, - out, outSz); - if (err != 0) { - #ifdef USE_STSAFE_VERBOSE - WOLFSSL_MSG("Error converting RS to Signature"); - #endif + if (err == 0) { + r = &sigRS[0]; + s = &sigRS[key_sz]; + err = wc_ecc_rs_raw_to_sig(r, key_sz, s, key_sz, out, outSz); + if (err != 0) { + WOLFSSL_MSG("Error converting RS to Signature"); + } } +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return err; } - /** - * \brief Create pre master secret using peer's public key and self private key. + * \brief Shared Secret Callback (ECDH) */ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, unsigned char* pubKeyDer, unsigned int* pubKeySz, unsigned char* out, unsigned int* outlen, int side, void* ctx) { - int err; + int err = 0; + int tmpKeyInit = 0; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* otherKeyX = NULL; + byte* otherKeyY = NULL; + byte* pubKeyRaw = NULL; +#else byte otherKeyX[STSAFE_MAX_KEY_LEN]; byte otherKeyY[STSAFE_MAX_KEY_LEN]; - word32 otherKeyX_len = sizeof(otherKeyX); - word32 otherKeyY_len = sizeof(otherKeyY); byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; - StSafeA_KeySlotNumber slot = STSAFE_A_SLOT_0; - StSafeA_CurveId curve_id; +#endif + word32 otherKeyX_len = STSAFE_MAX_KEY_LEN; + word32 otherKeyY_len = STSAFE_MAX_KEY_LEN; + stsafe_slot_t slot = STSAFE_KEY_SLOT_0; + stsafe_curve_id_t curve_id; ecc_key tmpKey; int ecc_curve; int key_sz; @@ -279,92 +1219,102 @@ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, WOLFSSL_MSG("SharedSecretCb: STSAFE"); #endif - err = wc_ecc_init(&tmpKey); - if (err != 0) { - return err; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + otherKeyX = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + otherKeyY = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (otherKeyX == NULL || otherKeyY == NULL || pubKeyRaw == NULL) { + err = MEMORY_E; } +#endif - /* set curve */ - ecc_curve = otherKey->dp->id; - curve_id = stsafe_get_ecc_curve_id(ecc_curve); - key_sz = stsafe_get_key_size(curve_id); - - /* for client: create and export public key */ - if (side == WOLFSSL_CLIENT_END) { - /* Export otherKey raw X and Y */ - err = wc_ecc_export_public_raw(otherKey, - &otherKeyX[0], (word32*)&otherKeyX_len, - &otherKeyY[0], (word32*)&otherKeyY_len); - if (err != 0) { - return err; - } - - err = stsafe_interface_create_key(&slot, curve_id, (uint8_t*)&pubKeyRaw[0]); - if (err != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_create_key error: %d\n", err); - #endif - err = WC_HW_E; - return err; - } - - /* convert raw unsigned public key to X.963 format for TLS */ + if (err == 0) { err = wc_ecc_init(&tmpKey); if (err == 0) { - err = wc_ecc_import_unsigned(&tmpKey, &pubKeyRaw[0], &pubKeyRaw[key_sz], - NULL, ecc_curve); + tmpKeyInit = 1; + } + } + + if (err == 0) { + ecc_curve = otherKey->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + if (side == WOLFSSL_CLIENT_END) { + err = wc_ecc_export_public_raw(otherKey, otherKeyX, &otherKeyX_len, + otherKeyY, &otherKeyY_len); + + if (err == 0) { + err = stsafe_create_key(&slot, curve_id, pubKeyRaw); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", + err); + err = WC_HW_E; + } + } + + if (err == 0) { + err = wc_ecc_import_unsigned(&tmpKey, pubKeyRaw, + &pubKeyRaw[key_sz], NULL, ecc_curve); + } if (err == 0) { err = wc_ecc_export_x963(&tmpKey, pubKeyDer, pubKeySz); } - wc_ecc_free(&tmpKey); + } + else if (side == WOLFSSL_SERVER_END) { + err = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, + ecc_curve); + if (err == 0) { + err = wc_ecc_export_public_raw(&tmpKey, otherKeyX, + &otherKeyX_len, otherKeyY, &otherKeyY_len); + } + } + else { + err = BAD_FUNC_ARG; } } - /* for server: import public key */ - else if (side == WOLFSSL_SERVER_END) { - /* import peer's key and export as raw unsigned for hardware */ - err = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, ecc_curve); - if (err == 0) { - err = wc_ecc_export_public_raw(&tmpKey, otherKeyX, &otherKeyX_len, - otherKeyY, &otherKeyY_len); + + if (err == 0) { + err = stsafe_shared_secret(slot, curve_id, otherKeyX, otherKeyY, + out, (int32_t*)outlen); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", err); + err = WC_HW_E; } } - else { - err = BAD_FUNC_ARG; + + if (tmpKeyInit) { + wc_ecc_free(&tmpKey); } - wc_ecc_free(&tmpKey); - - if (err != 0) { - return err; - } - - /* Compute shared secret */ - err = stsafe_interface_shared_secret( -#ifdef WOLFSSL_STSAFE_TAKES_SLOT - slot, +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(otherKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(otherKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif - curve_id, &otherKeyX[0], &otherKeyY[0], - out, (int32_t*)outlen); - if (err != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_shared_secret error: %d\n", err); - #endif - err = WC_HW_E; - } return err; } +/** + * \brief Setup PK callbacks for STSAFE + */ int SSL_STSAFE_SetupPkCallbacks(WOLFSSL_CTX* ctx) { wolfSSL_CTX_SetEccKeyGenCb(ctx, SSL_STSAFE_CreateKeyCb); wolfSSL_CTX_SetEccSignCb(ctx, SSL_STSAFE_SignCertificateCb); wolfSSL_CTX_SetEccVerifyCb(ctx, SSL_STSAFE_VerifyPeerCertCb); wolfSSL_CTX_SetEccSharedSecretCb(ctx, SSL_STSAFE_SharedSecretCb); - wolfSSL_CTX_SetDevId(ctx, 0); /* enables wolfCrypt `wc_ecc_*` ST-Safe use */ + wolfSSL_CTX_SetDevId(ctx, 0); return 0; } +/** + * \brief Setup PK callback context + */ int SSL_STSAFE_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx) { wolfSSL_SetEccKeyGenCtx(ssl, user_ctx); @@ -374,9 +1324,13 @@ int SSL_STSAFE_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx) return 0; } - #endif /* HAVE_PK_CALLBACKS */ + +/* ========================================================================== */ +/* Crypto Callbacks */ +/* ========================================================================== */ + #ifdef WOLF_CRYPTO_CB int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) @@ -384,212 +1338,293 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) int rc = CRYPTOCB_UNAVAILABLE; wolfSTSAFE_CryptoCb_Ctx* stsCtx = (wolfSTSAFE_CryptoCb_Ctx*)ctx; - if (info == NULL || ctx == NULL) - return BAD_FUNC_ARG; + if (info == NULL || ctx == NULL) { + rc = BAD_FUNC_ARG; + } (void)devId; (void)stsCtx; - if (info->algo_type == WC_ALGO_TYPE_SEED) { - /* use the STSAFE hardware for RNG seed */ + if (rc != BAD_FUNC_ARG && info->algo_type == WC_ALGO_TYPE_SEED) { #if !defined(WC_NO_RNG) && defined(USE_STSAFE_RNG_SEED) - while (info->seed.sz > 0) { - rc = stsafe_interface_getrandom(info->seed.seed, info->seed.sz); - if (rc < 0) { - return rc; - } - info->seed.seed += rc; - info->seed.sz -= rc; - } rc = 0; + while (rc == 0 && info->seed.sz > 0) { + int len = stsafe_get_random(info->seed.seed, info->seed.sz); + if (len < 0) { + rc = len; + } + else { + info->seed.seed += len; + info->seed.sz -= len; + } + } #else rc = CRYPTOCB_UNAVAILABLE; #endif } #ifdef HAVE_ECC - else if (info->algo_type == WC_ALGO_TYPE_PK) { + else if (rc != BAD_FUNC_ARG && info->algo_type == WC_ALGO_TYPE_PK) { #ifdef USE_STSAFE_VERBOSE STSAFE_INTERFACE_PRINTF("STSAFE Pk: Type %d\n", info->pk.type); #endif if (info->pk.type == WC_PK_TYPE_EC_KEYGEN) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* pubKeyRaw = NULL; + #else byte pubKeyRaw[STSAFE_MAX_PUBKEY_RAW_LEN]; - StSafeA_KeySlotNumber slot; - StSafeA_CurveId curve_id; + #endif + stsafe_slot_t slot; + stsafe_curve_id_t curve_id; int ecc_curve, key_sz; WOLFSSL_MSG("STSAFE: ECC KeyGen"); - /* get curve */ - ecc_curve = info->pk.eckg.curveId; - curve_id = stsafe_get_ecc_curve_id(ecc_curve); - key_sz = stsafe_get_key_size(curve_id); + rc = 0; + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + pubKeyRaw = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (pubKeyRaw == NULL) { + rc = MEMORY_E; + } + #endif - /* generate new ephemeral key on device */ - rc = stsafe_interface_create_key(&slot, curve_id, - (uint8_t*)pubKeyRaw); - if (rc != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_create_key error: %d\n", rc); - #endif - rc = WC_HW_E; - return rc; + if (rc == 0) { + ecc_curve = info->pk.eckg.curveId; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + + rc = stsafe_create_key(&slot, curve_id, pubKeyRaw); + if (rc != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", + rc); + rc = WC_HW_E; + } } - /* load generated public key into key, used by wolfSSL */ - rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, - &pubKeyRaw[key_sz], NULL, ecc_curve); + if (rc == 0) { + rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, + &pubKeyRaw[key_sz], NULL, ecc_curve); + } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } else if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* digest = NULL; + byte* sigRS = NULL; + #else byte digest[STSAFE_MAX_KEY_LEN]; byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r, *s; - StSafeA_CurveId curve_id; + #endif + byte* r; + byte* s; + stsafe_curve_id_t curve_id; + int ecc_curve; word32 inSz = info->pk.eccsign.inlen; int key_sz; WOLFSSL_MSG("STSAFE: ECC Sign"); - curve_id = stsafe_get_curve_mode(); - key_sz = stsafe_get_key_size(curve_id); + rc = 0; + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + digest = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (digest == NULL || sigRS == NULL) { + rc = MEMORY_E; + } + #endif - /* truncate input to match key size */ - if (inSz > key_sz) - inSz = key_sz; + if (rc == 0) { + /* Get curve from signing key */ + if (info->pk.eccsign.key != NULL && + info->pk.eccsign.key->dp != NULL) { + ecc_curve = info->pk.eccsign.key->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + } else { + curve_id = stsafe_get_curve_mode(); + } + key_sz = stsafe_get_key_size(curve_id); - /* Build input digest */ - XMEMSET(&digest[0], 0, sizeof(digest)); - XMEMCPY(&digest[key_sz - inSz], info->pk.eccsign.in, inSz); + if ((int)inSz > key_sz) + inSz = key_sz; - /* Sign using slot 0: Result is R then S */ - /* Sign will always use the curve type in slot 0 - (the TLS curve needs to match) */ - XMEMSET(sigRS, 0, sizeof(sigRS)); - rc = stsafe_interface_sign(STSAFE_A_SLOT_0, curve_id, - (uint8_t*)info->pk.eccsign.in, sigRS); - if (rc != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_sign error: %d\n", rc); - #endif - rc = WC_HW_E; - return rc; + XMEMSET(digest, 0, STSAFE_MAX_KEY_LEN); + XMEMCPY(&digest[key_sz - inSz], info->pk.eccsign.in, inSz); + + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); + /* Use slot 1 where keys are generated */ + rc = stsafe_sign(STSAFE_KEY_SLOT_1, curve_id, digest, sigRS); + if (rc != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_sign error: %d\n", rc); + rc = WC_HW_E; + } } - /* Convert R and S to signature */ - r = &sigRS[0]; - s = &sigRS[key_sz]; - rc = wc_ecc_rs_raw_to_sig((const byte*)r, key_sz, (const byte*)s, - key_sz, info->pk.eccsign.out, info->pk.eccsign.outlen); - if (rc != 0) { - WOLFSSL_MSG("Error converting RS to Signature"); + if (rc == 0) { + r = &sigRS[0]; + s = &sigRS[key_sz]; + rc = wc_ecc_rs_raw_to_sig(r, key_sz, s, key_sz, + info->pk.eccsign.out, info->pk.eccsign.outlen); + if (rc != 0) { + WOLFSSL_MSG("Error converting RS to Signature"); + } } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } else if (info->pk.type == WC_PK_TYPE_ECDSA_VERIFY) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* sigRS = NULL; + byte* pubKeyX = NULL; + byte* pubKeyY = NULL; + #else byte sigRS[STSAFE_MAX_SIG_LEN]; - byte *r = NULL, *s = NULL; - word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; byte pubKeyX[STSAFE_MAX_PUBKEY_RAW_LEN/2]; byte pubKeyY[STSAFE_MAX_PUBKEY_RAW_LEN/2]; - word32 pubKeyX_len = sizeof(pubKeyX); - word32 pubKeyY_len = sizeof(pubKeyY); - StSafeA_CurveId curve_id; + #endif + byte* r = NULL; + byte* s = NULL; + word32 r_len = STSAFE_MAX_SIG_LEN/2, s_len = STSAFE_MAX_SIG_LEN/2; + word32 pubKeyX_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + word32 pubKeyY_len = STSAFE_MAX_PUBKEY_RAW_LEN/2; + stsafe_curve_id_t curve_id; int ecc_curve, key_sz; WOLFSSL_MSG("STSAFE: ECC Verify"); + rc = 0; if (info->pk.eccverify.key == NULL || info->pk.eccverify.key->dp == NULL) { - return BAD_FUNC_ARG; + rc = BAD_FUNC_ARG; } - /* determine curve */ - ecc_curve = info->pk.eccverify.key->dp->id; - curve_id = stsafe_get_ecc_curve_id(ecc_curve); - key_sz = stsafe_get_key_size(curve_id); - if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) { - return BAD_FUNC_ARG; - } - - /* Extract Raw X and Y coordinates of the public key */ - rc = wc_ecc_export_public_raw(info->pk.eccverify.key, - pubKeyX, &pubKeyX_len, - pubKeyY, &pubKeyY_len); + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) if (rc == 0) { - /* Extract R and S from signature */ - XMEMSET(sigRS, 0, sizeof(sigRS)); + sigRS = (byte*)XMALLOC(STSAFE_MAX_SIG_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyX = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + pubKeyY = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN/2, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (sigRS == NULL || pubKeyX == NULL || pubKeyY == NULL) { + rc = MEMORY_E; + } + } + #endif + + if (rc == 0) { + ecc_curve = info->pk.eccverify.key->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + key_sz = stsafe_get_key_size(curve_id); + if (key_sz <= 0 || key_sz > STSAFE_MAX_KEY_LEN) { + rc = BAD_FUNC_ARG; + } + } + + if (rc == 0) { + rc = wc_ecc_export_public_raw(info->pk.eccverify.key, + pubKeyX, &pubKeyX_len, pubKeyY, &pubKeyY_len); + } + if (rc == 0) { + XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); r = &sigRS[0]; s = &sigRS[key_sz]; rc = wc_ecc_sig_to_rs(info->pk.eccverify.sig, info->pk.eccverify.siglen, r, &r_len, s, &s_len); } if (rc == 0) { - /* make sure R and S are not too large */ - if (r_len > key_sz || s_len > key_sz) { + if ((int)r_len > key_sz || (int)s_len > key_sz) { rc = BAD_FUNC_ARG; } } if (rc == 0) { - /* make sure R and S are zero padded on front */ - XMEMMOVE(&sigRS[key_sz-r_len], r, r_len); - XMEMSET(&sigRS[0], 0, key_sz-r_len); - XMEMMOVE(&sigRS[key_sz + (key_sz-s_len)], s, s_len); - XMEMSET(&sigRS[key_sz], 0, key_sz-s_len); + XMEMMOVE(&sigRS[key_sz - r_len], r, r_len); + XMEMSET(&sigRS[0], 0, key_sz - r_len); + XMEMMOVE(&sigRS[key_sz + (key_sz - s_len)], s, s_len); + XMEMSET(&sigRS[key_sz], 0, key_sz - s_len); - /* Verify signature */ - rc = stsafe_interface_verify(curve_id, - (uint8_t*)info->pk.eccverify.hash, sigRS, pubKeyX, pubKeyY, - (int32_t*)info->pk.eccverify.res); + rc = stsafe_verify(curve_id, (uint8_t*)info->pk.eccverify.hash, + sigRS, pubKeyX, pubKeyY, (int32_t*)info->pk.eccverify.res); if (rc != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_verify error: %d\n", rc); - #endif - rc = -rc; - } - } - } - else if (info->pk.type == WC_PK_TYPE_ECDH) { - byte otherKeyX[STSAFE_MAX_KEY_LEN]; - byte otherKeyY[STSAFE_MAX_KEY_LEN]; - word32 otherKeyX_len = sizeof(otherKeyX); - word32 otherKeyY_len = sizeof(otherKeyY); - StSafeA_CurveId curve_id; - int ecc_curve; - - WOLFSSL_MSG("STSAFE: PMS"); - - if (info->pk.ecdh.public_key == NULL) - return BAD_FUNC_ARG; - - /* get curve */ - ecc_curve = info->pk.ecdh.public_key->dp->id; - curve_id = stsafe_get_ecc_curve_id(ecc_curve); - - /* Export otherKey raw X and Y */ - rc = wc_ecc_export_public_raw(info->pk.ecdh.public_key, - &otherKeyX[0], (word32*)&otherKeyX_len, - &otherKeyY[0], (word32*)&otherKeyY_len); - if (rc == 0) { - /* Compute shared secret */ - *info->pk.ecdh.outlen = 0; - rc = stsafe_interface_shared_secret( - #ifdef WOLFSSL_STSAFE_TAKES_SLOT - STSAFE_A_SLOT_0, - #endif - curve_id, - otherKeyX, otherKeyY, - info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen); - if (rc != STSAFE_A_OK) { - #ifdef USE_STSAFE_VERBOSE - STSAFE_INTERFACE_PRINTF("stsafe_interface_shared_secret error: %d\n", rc); - #endif + STSAFE_INTERFACE_PRINTF("stsafe_verify error: %d\n", rc); rc = WC_HW_E; } } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(sigRS, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pubKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + } + else if (info->pk.type == WC_PK_TYPE_ECDH) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* otherKeyX = NULL; + byte* otherKeyY = NULL; + #else + byte otherKeyX[STSAFE_MAX_KEY_LEN]; + byte otherKeyY[STSAFE_MAX_KEY_LEN]; + #endif + word32 otherKeyX_len = STSAFE_MAX_KEY_LEN; + word32 otherKeyY_len = STSAFE_MAX_KEY_LEN; + stsafe_curve_id_t curve_id; + int ecc_curve; + + WOLFSSL_MSG("STSAFE: ECDH"); + + rc = 0; + if (info->pk.ecdh.public_key == NULL) { + rc = BAD_FUNC_ARG; + } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + if (rc == 0) { + otherKeyX = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + otherKeyY = (byte*)XMALLOC(STSAFE_MAX_KEY_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (otherKeyX == NULL || otherKeyY == NULL) { + rc = MEMORY_E; + } + } + #endif + + if (rc == 0) { + ecc_curve = info->pk.ecdh.public_key->dp->id; + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + + rc = wc_ecc_export_public_raw(info->pk.ecdh.public_key, + otherKeyX, &otherKeyX_len, otherKeyY, &otherKeyY_len); + } + if (rc == 0) { + *info->pk.ecdh.outlen = 0; + /* Use slot 1 where keys are generated */ + rc = stsafe_shared_secret(STSAFE_KEY_SLOT_1, curve_id, + otherKeyX, otherKeyY, + info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen); + if (rc != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", + rc); + rc = WC_HW_E; + } + } + + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(otherKeyX, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(otherKeyY, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } } #endif /* HAVE_ECC */ - /* need to return negative here for error */ if (rc != 0 && rc != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { WOLFSSL_MSG("STSAFE: CryptoCb failed"); #ifdef USE_STSAFE_VERBOSE @@ -603,4 +1638,4 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) #endif /* WOLF_CRYPTO_CB */ -#endif /* WOLFSSL_STSAFEA100 */ +#endif /* WOLFSSL_STSAFE */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index dddcfc9967..08838cdcee 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -68,7 +68,7 @@ #if defined(WOLFSSL_RENESAS_RX64_HASH) #include #endif -#if defined(WOLFSSL_STSAFEA100) +#if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) #include #endif @@ -303,8 +303,12 @@ int wolfCrypt_Init(void) return ret; } #endif - #if defined(WOLFSSL_STSAFEA100) - stsafe_interface_init(); + #if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) + ret = stsafe_interface_init(); + if (ret != 0) { + WOLFSSL_MSG("STSAFE init failed"); + return ret; + } #endif #if defined(WOLFSSL_TROPIC01) ret = Tropic01_Init(); diff --git a/wolfssl/wolfcrypt/port/st/stsafe.h b/wolfssl/wolfcrypt/port/st/stsafe.h index 08e39f08e8..452298115f 100644 --- a/wolfssl/wolfcrypt/port/st/stsafe.h +++ b/wolfssl/wolfcrypt/port/st/stsafe.h @@ -23,6 +23,7 @@ #define _WOLFPORT_STSAFE_H_ #include +#include #include #include @@ -34,22 +35,135 @@ #include #endif -#ifdef WOLFSSL_STSAFEA100 +/* Combined STSAFE macro - enables when either A100 or A120 is defined */ +#if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) + #undef WOLFSSL_STSAFE + #define WOLFSSL_STSAFE +#endif -/* The wolf STSAFE interface layer */ -/* Please contact wolfSSL for the STSAFE port files */ -#include "stsafe_interface.h" +#ifdef WOLFSSL_STSAFE + +/* -------------------------------------------------------------------------- */ +/* External Interface Support (Backwards Compatibility) */ +/* -------------------------------------------------------------------------- */ + +/* Define WOLFSSL_STSAFE_INTERFACE_EXTERNAL to use an external stsafe_ + * interface.h file that provides customer-specific implementations. + * This maintains backwards compatibility with older integrations that + * used a separate interface file. + * + * When NOT defined (default): All code is self-contained in stsafe.c using + * the appropriate SDK (STSELib for A120, STSAFE-A1xx SDK for A100/A110). + * + * When defined: Include customer-provided stsafe_interface.h which must define: + * - stsafe_curve_id_t, stsafe_slot_t types + * - STSAFE_ECC_CURVE_P256, STSAFE_ECC_CURVE_P384 macros + * - STSAFE_KEY_SLOT_0, STSAFE_KEY_SLOT_1, STSAFE_KEY_SLOT_EPHEMERAL macros + * - STSAFE_A_OK return code macro + * - STSAFE_MAX_KEY_LEN, STSAFE_MAX_PUBKEY_RAW_LEN, STSAFE_MAX_SIG_LEN macros + * - Function prototypes for interface functions (see stsafe.c) + */ +#ifdef WOLFSSL_STSAFE_INTERFACE_EXTERNAL + #include "stsafe_interface.h" +#else + +/* -------------------------------------------------------------------------- */ +/* STSAFE SDK Type Abstractions */ +/* -------------------------------------------------------------------------- */ + +#ifdef WOLFSSL_STSAFEA120 + /* STSAFE-A120 uses STSELib (open source BSD-3) */ + /* Note: stselib.h is included in stsafe.c to avoid warnings in headers */ + + /* Type mappings for STSELib - using byte for curve ID to avoid + * including full STSELib headers which have strict-prototype warnings */ + typedef byte stsafe_curve_id_t; + typedef byte stsafe_slot_t; + + /* Curve ID mappings - values depend on stse_conf.h settings! + * With only NIST P-256 and P-384 enabled: + * STSE_ECC_KT_NIST_P_256 = 0, STSE_ECC_KT_NIST_P_384 = 1 + * NOTE: If other curves are enabled, these values change! */ + #define STSAFE_ECC_CURVE_P256 0 /* STSE_ECC_KT_NIST_P_256 */ + #define STSAFE_ECC_CURVE_P384 1 /* STSE_ECC_KT_NIST_P_384 */ + /* Brainpool curves - only defined when enabled in stse_conf.h */ + /* #define STSAFE_ECC_CURVE_BP256 2 */ /* STSE_ECC_KT_BP_P_256 */ + /* #define STSAFE_ECC_CURVE_BP384 3 */ /* STSE_ECC_KT_BP_P_384 */ + + /* Slot mappings */ + #define STSAFE_KEY_SLOT_0 0 + #define STSAFE_KEY_SLOT_1 1 + #define STSAFE_KEY_SLOT_EPHEMERAL 0xFF + + /* Return codes */ + #define STSAFE_A_OK 0 /* STSE_OK */ + + /* Hash types - must match stse_hash_algorithm_t values in STSELib */ + #define STSAFE_HASH_SHA256 0 /* STSE_SHA_256 */ + #define STSAFE_HASH_SHA384 1 /* STSE_SHA_384 */ + +#else /* WOLFSSL_STSAFEA100 */ + /* STSAFE-A100/A110 uses legacy ST STSAFE-A1xx SDK */ + /* User must provide path to STSAFE-A1xx SDK headers */ + #include + + /* Type mappings for legacy SDK */ + typedef StSafeA_CurveId stsafe_curve_id_t; + typedef StSafeA_KeySlotNumber stsafe_slot_t; + + /* Curve ID mappings */ + #define STSAFE_ECC_CURVE_P256 STSAFE_A_NIST_P_256 + #define STSAFE_ECC_CURVE_P384 STSAFE_A_NIST_P_384 + #define STSAFE_ECC_CURVE_BP256 STSAFE_A_BRAINPOOL_P_256 + #define STSAFE_ECC_CURVE_BP384 STSAFE_A_BRAINPOOL_P_384 + + /* Slot mappings */ + #define STSAFE_KEY_SLOT_0 STSAFE_A_SLOT_0 + #define STSAFE_KEY_SLOT_1 STSAFE_A_SLOT_1 + #define STSAFE_KEY_SLOT_EPHEMERAL STSAFE_A_SLOT_EPHEMERAL + + /* Return codes - STSAFE_A_OK already defined in SDK */ + + /* Hash types */ + #define STSAFE_HASH_SHA256 STSAFE_A_SHA_256 + #define STSAFE_HASH_SHA384 STSAFE_A_SHA_384 + +#endif /* WOLFSSL_STSAFEA120 */ + +/* -------------------------------------------------------------------------- */ +/* Common Definitions */ +/* -------------------------------------------------------------------------- */ #ifndef STSAFE_MAX_KEY_LEN - #define STSAFE_MAX_KEY_LEN ((uint32_t)48) /* for up to 384-bit keys */ + #define STSAFE_MAX_KEY_LEN 48 /* for up to 384-bit keys */ #endif #ifndef STSAFE_MAX_PUBKEY_RAW_LEN - #define STSAFE_MAX_PUBKEY_RAW_LEN ((uint32_t)STSAFE_MAX_KEY_LEN * 2) /* x/y */ + #define STSAFE_MAX_PUBKEY_RAW_LEN (STSAFE_MAX_KEY_LEN * 2) /* x/y */ #endif #ifndef STSAFE_MAX_SIG_LEN - #define STSAFE_MAX_SIG_LEN ((uint32_t)STSAFE_MAX_KEY_LEN * 2) /* r/s */ + #define STSAFE_MAX_SIG_LEN (STSAFE_MAX_KEY_LEN * 2) /* r/s */ #endif +/* Default I2C address */ +#ifndef STSAFE_I2C_ADDR + #define STSAFE_I2C_ADDR 0x20 +#endif + +/* Default curve mode (for signing operations) */ +#ifndef STSAFE_DEFAULT_CURVE + #define STSAFE_DEFAULT_CURVE STSAFE_ECC_CURVE_P256 +#endif + +#endif /* !WOLFSSL_STSAFE_INTERFACE_EXTERNAL */ + +/* -------------------------------------------------------------------------- */ +/* Public API Functions */ +/* -------------------------------------------------------------------------- */ + +/* Initialize STSAFE device - called automatically by wolfCrypt_Init() */ +WOLFSSL_API int stsafe_interface_init(void); + +/* Load device certificate from STSAFE secure storage */ WOLFSSL_API int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, word32* pRawCertificateLen); @@ -94,6 +208,6 @@ WOLFSSL_API int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, #endif /* WOLF_CRYPTO_CB */ -#endif /* WOLFSSL_STSAFEA100 */ +#endif /* WOLFSSL_STSAFE */ #endif /* _WOLFPORT_STSAFE_H_ */ From c7ca035baf65eb11336732cff60f240378890ed3 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 6 Jan 2026 14:55:59 -0800 Subject: [PATCH 13/27] Cleanup WOLFSL_STSAFE and fix issue with multi-test macros --- .wolfssl_known_macro_extras | 6 +++--- wolfcrypt/src/wc_port.c | 4 ++-- wolfssl/wolfcrypt/port/st/stsafe.h | 8 +------- wolfssl/wolfcrypt/settings.h | 6 ++++++ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index d11b35a043..01d989177a 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -513,9 +513,6 @@ SQRTMOD_USE_MOD_EXP SSL_SNIFFER_EXPORTS SSN_BUILDING_LIBYASSL STATIC_CHUNKS_ONLY -STSAFE_HOST_KEY_CIPHER -STSAFE_HOST_KEY_MAC -STSAFE_I2C_BUS STM32F107xC STM32F207xx STM32F217xx @@ -548,6 +545,9 @@ STM32WL55xx STM32_AESGCM_PARTIAL STM32_HW_CLOCK_AUTO STM32_NUTTX_RNG +STSAFE_HOST_KEY_CIPHER +STSAFE_HOST_KEY_MAC +STSAFE_I2C_BUS TASK_EXTRA_STACK_SIZE TCP_NODELAY TFM_ALREADY_SET diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 08838cdcee..4bc487e75f 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -68,7 +68,7 @@ #if defined(WOLFSSL_RENESAS_RX64_HASH) #include #endif -#if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) +#ifdef WOLFSSL_STSAFE #include #endif @@ -303,7 +303,7 @@ int wolfCrypt_Init(void) return ret; } #endif - #if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) + #ifdef WOLFSSL_STSAFE ret = stsafe_interface_init(); if (ret != 0) { WOLFSSL_MSG("STSAFE init failed"); diff --git a/wolfssl/wolfcrypt/port/st/stsafe.h b/wolfssl/wolfcrypt/port/st/stsafe.h index 452298115f..83b02c6053 100644 --- a/wolfssl/wolfcrypt/port/st/stsafe.h +++ b/wolfssl/wolfcrypt/port/st/stsafe.h @@ -35,12 +35,6 @@ #include #endif -/* Combined STSAFE macro - enables when either A100 or A120 is defined */ -#if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) - #undef WOLFSSL_STSAFE - #define WOLFSSL_STSAFE -#endif - #ifdef WOLFSSL_STSAFE /* -------------------------------------------------------------------------- */ @@ -52,7 +46,7 @@ * This maintains backwards compatibility with older integrations that * used a separate interface file. * - * When NOT defined (default): All code is self-contained in stsafe.c using + * When NOT set (the default): All code is self-contained in stsafe.c using * the appropriate SDK (STSELib for A120, STSAFE-A1xx SDK for A100/A110). * * When defined: Include customer-provided stsafe_interface.h which must define: diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 3b2ebf72ec..ac334105ae 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2139,6 +2139,12 @@ extern void uITRON4_free(void *p) ; #endif /* WOLFSSL_MAXQ1065 || WOLFSSL_MAXQ108X */ +/* Combined STSAFE macro - enables when either A100 or A120 is defined */ +#if defined(WOLFSSL_STSAFEA100) || defined(WOLFSSL_STSAFEA120) + #undef WOLFSSL_STSAFE + #define WOLFSSL_STSAFE +#endif + #if defined(WOLFSSL_STM32F2) || defined(WOLFSSL_STM32F4) || \ defined(WOLFSSL_STM32F7) || defined(WOLFSSL_STM32F1) || \ defined(WOLFSSL_STM32L4) || defined(WOLFSSL_STM32L5) || \ From 09c75f25de62e9d35b33f44ce6cb7d72ed446609 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 12 Jan 2026 12:35:57 -0800 Subject: [PATCH 14/27] Fixes for peer review. --- wolfcrypt/src/port/st/stsafe.c | 72 +++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 7296974e4d..6d26098989 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -26,6 +26,9 @@ #include #include #include +#ifndef NO_ASN + #include +#endif #ifndef STSAFE_INTERFACE_PRINTF #define STSAFE_INTERFACE_PRINTF(...) WC_DO_NOTHING @@ -609,15 +612,30 @@ static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id, if (status_code == STSAFE_A_OK && signature != NULL) { /* Parse signature - format is: len(2) || R || len(2) || S */ r_length = ((uint16_t)signature->Data[0] << 8) | signature->Data[1]; - s_length = ((uint16_t)signature->Data[2 + r_length] << 8) | - signature->Data[3 + r_length]; - /* Copy R and S to output (zero-padded) */ - XMEMSET(pSigRS, 0, key_sz * 2); - XMEMCPY(pSigRS + (key_sz - r_length), &signature->Data[2], r_length); - XMEMCPY(pSigRS + key_sz + (key_sz - s_length), - &signature->Data[4 + r_length], s_length); - rc = STSAFE_A_OK; + /* Bounds check: r_length must be valid and fit within signature buffer */ + if (r_length > key_sz || r_length == 0 || + (size_t)(2 + r_length + 2) > signature->Length) { + rc = ASN_PARSE_E; + } + else { + s_length = ((uint16_t)signature->Data[2 + r_length] << 8) | + signature->Data[3 + r_length]; + + /* Bounds check: s_length must be valid and fit within signature buffer */ + if (s_length > key_sz || s_length == 0 || + (size_t)(4 + r_length + s_length) > signature->Length) { + rc = ASN_PARSE_E; + } + else { + /* Copy R and S to output (zero-padded) */ + XMEMSET(pSigRS, 0, key_sz * 2); + XMEMCPY(pSigRS + (key_sz - r_length), &signature->Data[2], r_length); + XMEMCPY(pSigRS + key_sz + (key_sz - s_length), + &signature->Data[4 + r_length], s_length); + rc = STSAFE_A_OK; + } + } } else { rc = (int)status_code; @@ -811,22 +829,26 @@ static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) status_code = StSafeA_Read(g_stsafe_handle, 0, 0, STSAFE_A_ALWAYS, 0, 0, 4, &readBuf, STSAFE_A_NO_MAC); - if (status_code == STSAFE_A_OK && readBuf->Length == 4 && - readBuf->Data[0] == 0x30) { - /* Parse ASN.1 length */ - switch (readBuf->Data[1]) { - case 0x81: - *pCertLen = readBuf->Data[2] + 3; - break; - case 0x82: - *pCertLen = ((uint16_t)readBuf->Data[2] << 8) + + if (status_code == STSAFE_A_OK && readBuf->Length == 4) { + /* Parse ASN.1 DER certificate header */ + /* 0x30 = ASN_SEQUENCE | ASN_CONSTRUCTED (certificate is a SEQUENCE) */ + if (readBuf->Data[0] == (ASN_SEQUENCE | ASN_CONSTRUCTED)) { + /* Parse ASN.1 length encoding */ + switch (readBuf->Data[1]) { + case (ASN_LONG_LENGTH | 0x01): /* Length encoded in 1 byte */ + *pCertLen = readBuf->Data[2] + 3; + break; + case (ASN_LONG_LENGTH | 0x02): /* Length encoded in 2 bytes */ + *pCertLen = ((uint16_t)readBuf->Data[2] << 8) + readBuf->Data[3] + 4; - break; - default: - if (readBuf->Data[1] < 0x81) { - *pCertLen = readBuf->Data[1] + 2; - } - break; + break; + default: + /* Short form: length < 128, encoded directly */ + if (readBuf->Data[1] < ASN_LONG_LENGTH) { + *pCertLen = readBuf->Data[1] + 2; + } + break; + } } } else { @@ -843,6 +865,10 @@ static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) } if (rc == STSAFE_A_OK && *pCertLen > 0) { + /* STSAFE-A100/A110 maximum read size is 225 bytes per command. + * When CRC is supported, 2 bytes are used for CRC, leaving 223 bytes + * for data. Without CRC, we can read up to 225 bytes, but use 223 + * for consistency and to leave room for protocol overhead. */ step = 223 - (stsafe_a->CrcSupport ? 2 : 0); for (i = 0; rc == STSAFE_A_OK && i < *pCertLen / step; i++) { From 02c3086e00cefbbc9b10f3113265ffee5f092299 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 12 Jan 2026 22:56:13 +0000 Subject: [PATCH 15/27] Added ECDHE support --- wolfcrypt/src/port/st/stsafe.c | 314 ++++++++++++++++++++++++++++++--- 1 file changed, 289 insertions(+), 25 deletions(-) diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 6d26098989..4beeb4c417 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -103,6 +103,16 @@ static stsafe_curve_id_t g_stsafe_curve_mode = STSAFE_DEFAULT_CURVE; /* Internal Helper Functions */ /* ========================================================================== */ +/** + * \brief Helper macros to store/retrieve slot number in devCtx + * \details Slot number is stored directly in devCtx as void* to avoid + * dynamic memory allocation. Slot values are small (0, 1, 0xFF) + * so safe to cast to/from void*. + */ +#define STSAFE_SLOT_TO_DEVCXT(slot) ((void*)(uintptr_t)(slot)) +#define STSAFE_DEVCXT_TO_SLOT(devCtx) ((stsafe_slot_t)(uintptr_t)(devCtx)) + + /** * \brief Get key size in bytes for a given curve */ @@ -263,16 +273,21 @@ int stsafe_interface_init(void) /** * \brief Generate ECC key pair on STSAFE-A120 + * \details Uses dedicated key slot (slot 1) for persistent keys. + * For ephemeral ECDHE keys, use stsafe_create_ecdhe_key() instead. */ static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, uint8_t* pPubKeyRaw) { int rc = STSAFE_A_OK; stse_ReturnCode_t ret; - stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Ephemeral slot */ + stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Use dedicated key slot for persistent keys */ - /* Generate key pair - public key is X||Y concatenated */ - ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, curve_id, + /* Generate key pair - public key is X||Y concatenated + * Note: stse_generate_ecc_key_pair expects stse_ecc_key_type_t, + * but stsafe_curve_id_t values match stse_ecc_key_type_t enum values */ + ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, + (stse_ecc_key_type_t)curve_id, 255, /* usage_limit */ pPubKeyRaw); if (ret != STSE_OK) { @@ -287,6 +302,34 @@ static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, return rc; } +/** + * \brief Generate ECDHE ephemeral key pair on STSAFE-A120 + * \details Uses stse_generate_ECDHE_key_pair() which generates truly + * ephemeral keys (not stored in slots). The private key remains + * in STSE internal memory for use with shared secret computation. + * Public key is returned in X||Y format (same as stse_generate_ecc_key_pair). + */ +static int stsafe_create_ecdhe_key(stsafe_curve_id_t curve_id, + uint8_t* pPubKeyRaw) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + + if (pPubKeyRaw == NULL) { + return BAD_FUNC_ARG; + } + + /* Generate ECDHE ephemeral key pair - public key returned as X||Y */ + ret = stse_generate_ECDHE_key_pair(&g_stse_handler, + (stse_ecc_key_type_t)curve_id, pPubKeyRaw); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_generate_ECDHE_key_pair error: %d\n", ret); + rc = (int)ret; + } + + return rc; +} + /** * \brief ECDSA sign using STSAFE-A120 */ @@ -363,11 +406,57 @@ static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, XMEMCPY(peerPubKey, pPubKeyX, key_sz); XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); - /* Compute shared secret */ - ret = stse_ecc_establish_shared_secret(&g_stse_handler, slot, curve_id, - peerPubKey, pSharedSecret); + /* Compute shared secret + * Note: stse_ecc_establish_shared_secret expects stse_ecc_key_type_t. + * For STSAFE-A120, stsafe_curve_id_t values match stse_ecc_key_type_t enum values: + * STSAFE_ECC_CURVE_P256 (0) = STSE_ECC_KT_NIST_P_256 (0) + * STSAFE_ECC_CURVE_P384 (1) = STSE_ECC_KT_NIST_P_384 (1) */ + ret = stse_ecc_establish_shared_secret(&g_stse_handler, slot, + (stse_ecc_key_type_t)curve_id, peerPubKey, pSharedSecret); if (ret != STSE_OK) { - STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret error: %d\n", + STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret error: %d (slot: %d, curve_id: %d)\n", + ret, slot, curve_id); + rc = (int)ret; + } + + if (rc == STSAFE_A_OK) { + *pSharedSecretLen = (int32_t)key_sz; + } + + return rc; +} + +/** + * \brief ECDHE shared secret using STSAFE-A120 + * \details Computes shared secret using the ephemeral ECDHE private key + * that was generated by stsafe_create_ecdhe_key(). The ephemeral + * private key is stored internally in the STSE device. + */ +static int stsafe_shared_secret_ecdhe(stsafe_curve_id_t curve_id, + uint8_t* pPubKeyX, uint8_t* pPubKeyY, + uint8_t* pSharedSecret, + int32_t* pSharedSecretLen) +{ + int rc = STSAFE_A_OK; + stse_ReturnCode_t ret; + int key_sz = stsafe_get_key_size(curve_id); + uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; + + if (pPubKeyX == NULL || pPubKeyY == NULL || pSharedSecret == NULL || + pSharedSecretLen == NULL || key_sz == 0) { + return BAD_FUNC_ARG; + } + + /* Combine peer X and Y (X||Y format) */ + XMEMCPY(peerPubKey, pPubKeyX, key_sz); + XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); + + /* Compute shared secret using ephemeral slot (0xFF) + * The ephemeral private key was generated by stse_generate_ECDHE_key_pair() */ + ret = stse_ecc_establish_shared_secret(&g_stse_handler, + STSAFE_KEY_SLOT_EPHEMERAL, curve_id, peerPubKey, pSharedSecret); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret (ECDHE) error: %d\n", ret); rc = (int)ret; } @@ -977,7 +1066,7 @@ int SSL_STSAFE_LoadDeviceCertificate(byte** pRawCertificate, #if !defined(WOLFCRYPT_ONLY) && defined(HAVE_PK_CALLBACKS) /** - * \brief Key Gen Callback (used by TLS server) + * \brief Key Gen Callback (used by TLS server for ECDHE) */ int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, int ecc_curve, void* ctx) @@ -995,7 +1084,7 @@ int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, (void)ctx; #ifdef USE_STSAFE_VERBOSE - WOLFSSL_MSG("CreateKeyCb: STSAFE"); + WOLFSSL_MSG("CreateKeyCb: STSAFE (ECDHE)"); #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) @@ -1009,11 +1098,23 @@ int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, if (err == 0) { curve_id = stsafe_get_ecc_curve_id(ecc_curve); +#ifdef WOLFSSL_STSAFEA120 + /* Use ECDHE ephemeral key generation for A120 */ + err = stsafe_create_ecdhe_key(curve_id, pubKeyRaw); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_ecdhe_key error: %d\n", err); + err = WC_HW_E; + } + /* For ECDHE, slot is not used (ephemeral key stored internally) */ + slot = STSAFE_KEY_SLOT_EPHEMERAL; +#else + /* Legacy A100/A110 uses slot-based key generation */ err = stsafe_create_key(&slot, curve_id, pubKeyRaw); if (err != STSAFE_A_OK) { STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", err); err = WC_HW_E; } +#endif } if (err == 0) { @@ -1025,6 +1126,8 @@ int SSL_STSAFE_CreateKeyCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif + (void)slot; /* May be unused for A120 ECDHE */ + return err; } @@ -1212,7 +1315,7 @@ int SSL_STSAFE_SignCertificateCb(WOLFSSL* ssl, const byte* in, } /** - * \brief Shared Secret Callback (ECDH) + * \brief Shared Secret Callback (ECDHE) */ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, unsigned char* pubKeyDer, unsigned int* pubKeySz, @@ -1242,7 +1345,7 @@ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, (void)ctx; #ifdef USE_STSAFE_VERBOSE - WOLFSSL_MSG("SharedSecretCb: STSAFE"); + WOLFSSL_MSG("SharedSecretCb: STSAFE (ECDHE)"); #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) @@ -1274,12 +1377,24 @@ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, otherKeyY, &otherKeyY_len); if (err == 0) { +#ifdef WOLFSSL_STSAFEA120 + /* Use ECDHE ephemeral key generation for A120 */ + err = stsafe_create_ecdhe_key(curve_id, pubKeyRaw); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_create_ecdhe_key error: %d\n", + err); + err = WC_HW_E; + } + slot = STSAFE_KEY_SLOT_EPHEMERAL; +#else + /* Legacy A100/A110 uses slot-based key generation */ err = stsafe_create_key(&slot, curve_id, pubKeyRaw); if (err != STSAFE_A_OK) { STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", err); err = WC_HW_E; } +#endif } if (err == 0) { @@ -1304,12 +1419,23 @@ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, } if (err == 0) { +#ifdef WOLFSSL_STSAFEA120 + /* Use ECDHE shared secret computation for A120 */ + err = stsafe_shared_secret_ecdhe(curve_id, otherKeyX, otherKeyY, + out, (int32_t*)outlen); + if (err != STSAFE_A_OK) { + STSAFE_INTERFACE_PRINTF("stsafe_shared_secret_ecdhe error: %d\n", err); + err = WC_HW_E; + } +#else + /* Legacy A100/A110 uses slot-based shared secret */ err = stsafe_shared_secret(slot, curve_id, otherKeyX, otherKeyY, out, (int32_t*)outlen); if (err != STSAFE_A_OK) { STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", err); err = WC_HW_E; } +#endif } if (tmpKeyInit) { @@ -1420,7 +1546,29 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) curve_id = stsafe_get_ecc_curve_id(ecc_curve); key_sz = stsafe_get_key_size(curve_id); + /* For A120, generate keys in slot 1 (persistent slot) by default for ECDSA signing. + * For ECDH operations, ephemeral keys will be generated on-demand in the ECDH callback + * if needed (see WC_PK_TYPE_ECDH handling below). */ +#ifdef WOLFSSL_STSAFEA120 + stse_ReturnCode_t ret; + slot = STSAFE_KEY_SLOT_1; /* Use persistent slot for ECDSA signing */ + ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, + (stse_ecc_key_type_t)curve_id, + 255, /* usage_limit for persistent keys */ + pubKeyRaw); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (slot 1) error: %d\n", ret); + rc = (int)ret; + } else { + rc = STSAFE_A_OK; + } + if (rc != STSAFE_A_OK) { + rc = WC_HW_E; + } +#else + /* Legacy A100/A110 uses slot-based key generation */ rc = stsafe_create_key(&slot, curve_id, pubKeyRaw); +#endif if (rc != STSAFE_A_OK) { STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", rc); @@ -1429,8 +1577,19 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } if (rc == 0) { + /* Store slot number directly in devCtx (no dynamic allocation) */ + info->pk.eckg.key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot); + } + + if (rc == 0) { + /* Import public key - preserve devCtx */ + void* saved_devCtx = info->pk.eckg.key->devCtx; rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, &pubKeyRaw[key_sz], NULL, ecc_curve); + /* Restore devCtx in case import cleared it */ + if (saved_devCtx != NULL && info->pk.eckg.key->devCtx != saved_devCtx) { + info->pk.eckg.key->devCtx = saved_devCtx; + } } #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) @@ -1483,8 +1642,15 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) XMEMCPY(&digest[key_sz - inSz], info->pk.eccsign.in, inSz); XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); - /* Use slot 1 where keys are generated */ - rc = stsafe_sign(STSAFE_KEY_SLOT_1, curve_id, digest, sigRS); + /* Retrieve slot from devCtx if available, otherwise use default */ + stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Default fallback */ + if (info->pk.eccsign.key != NULL && info->pk.eccsign.key->devCtx != NULL) { + slot = STSAFE_DEVCXT_TO_SLOT(info->pk.eccsign.key->devCtx); + STSAFE_INTERFACE_PRINTF("STSAFE: Using slot %d from devCtx for signing\n", slot); + } else { + WOLFSSL_MSG("STSAFE: Warning: devCtx not found, using default slot 1"); + } + rc = stsafe_sign(slot, curve_id, digest, sigRS); if (rc != STSAFE_A_OK) { STSAFE_INTERFACE_PRINTF("stsafe_sign error: %d\n", rc); rc = WC_HW_E; @@ -1624,22 +1790,120 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) #endif if (rc == 0) { - ecc_curve = info->pk.ecdh.public_key->dp->id; - curve_id = stsafe_get_ecc_curve_id(ecc_curve); + /* Get curve from private_key (hardware key), not public_key (peer key) */ + if (info->pk.ecdh.private_key != NULL && + info->pk.ecdh.private_key->dp != NULL) { + ecc_curve = info->pk.ecdh.private_key->dp->id; + } else if (info->pk.ecdh.public_key != NULL && + info->pk.ecdh.public_key->dp != NULL) { + /* Fallback to public_key if private_key not available */ + ecc_curve = info->pk.ecdh.public_key->dp->id; + } else { + rc = BAD_FUNC_ARG; + } + if (rc == 0) { + curve_id = stsafe_get_ecc_curve_id(ecc_curve); + /* Note: STSAFE_ECC_CURVE_P256 is 0, so we can't use STSAFE_DEFAULT_CURVE check. + * Instead, verify the curve_id is valid by checking it's one of the supported curves */ + if (curve_id != STSAFE_ECC_CURVE_P256 && curve_id != STSAFE_ECC_CURVE_P384) { + rc = BAD_FUNC_ARG; + } + } - rc = wc_ecc_export_public_raw(info->pk.ecdh.public_key, - otherKeyX, &otherKeyX_len, otherKeyY, &otherKeyY_len); + if (rc == 0) { + rc = wc_ecc_export_public_raw(info->pk.ecdh.public_key, + otherKeyX, &otherKeyX_len, otherKeyY, &otherKeyY_len); + } } if (rc == 0) { *info->pk.ecdh.outlen = 0; - /* Use slot 1 where keys are generated */ - rc = stsafe_shared_secret(STSAFE_KEY_SLOT_1, curve_id, - otherKeyX, otherKeyY, - info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen); - if (rc != STSAFE_A_OK) { - STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", - rc); - rc = WC_HW_E; + + /* Check if private key is software but public key is hardware. + * In this case, we can't use hardware for computation since the + * private key is not in a slot. Return CRYPTOCB_UNAVAILABLE to + * let software handle it (but software path may also fail if + * public key export fails). */ + if (info->pk.ecdh.private_key == NULL || + info->pk.ecdh.private_key->devId == INVALID_DEVID) { + if (info->pk.ecdh.public_key != NULL && + info->pk.ecdh.public_key->devId != INVALID_DEVID) { + WOLFSSL_MSG("STSAFE: Private key is software, public key is hardware - cannot use hardware"); + rc = CRYPTOCB_UNAVAILABLE; + } + } + + if (rc == 0) { + /* For ECDH operations, use ephemeral slot (0xFF). + * Keys are generated in slot 1 by default (for ECDSA signing). + * If the key is in slot 1, generate a new ephemeral key for ECDH. + * If the key is already in the ephemeral slot, use it directly. */ + stsafe_slot_t slot; + stsafe_slot_t original_slot = STSAFE_KEY_SLOT_1; + int need_ephemeral_key = 0; + + if (info->pk.ecdh.private_key != NULL && + info->pk.ecdh.private_key->devCtx != NULL) { + original_slot = STSAFE_DEVCXT_TO_SLOT(info->pk.ecdh.private_key->devCtx); + + /* If key is in slot 1 (for ECDSA), we need to generate ephemeral key for ECDH */ + if (original_slot == STSAFE_KEY_SLOT_1) { + need_ephemeral_key = 1; + } + } + + if (need_ephemeral_key) { + /* Key is in slot 1 (for ECDSA), but ECDH requires ephemeral slot. + * Generate ephemeral key pair for ECDH. Note: This will overwrite any + * existing key in ephemeral slot, so for bidirectional ECDH, both keys + * should be generated in ephemeral slot from the start. */ + stse_ReturnCode_t ret; + byte ephemeralPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; + int key_sz = stsafe_get_key_size(curve_id); + slot = STSAFE_KEY_SLOT_EPHEMERAL; + + ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, + (stse_ecc_key_type_t)curve_id, + STSAFEA_EPHEMERAL_KEY_USAGE_LIMIT, + ephemeralPubKey); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret); + rc = (int)ret; + } else { + WOLFSSL_MSG("STSAFE: Generated ephemeral key for ECDH"); + /* Update devCtx to reflect ephemeral slot for this key */ + if (info->pk.ecdh.private_key != NULL) { + info->pk.ecdh.private_key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot); + } + /* Update the public key in the key structure to match the new ephemeral key */ + if (info->pk.ecdh.private_key != NULL && rc == 0) { + void* saved_devCtx = info->pk.ecdh.private_key->devCtx; + rc = wc_ecc_import_unsigned(info->pk.ecdh.private_key, + ephemeralPubKey, &ephemeralPubKey[key_sz], + NULL, ecc_curve); + /* Restore devCtx in case import cleared it */ + if (saved_devCtx != NULL && info->pk.ecdh.private_key->devCtx != saved_devCtx) { + info->pk.ecdh.private_key->devCtx = saved_devCtx; + } + } + } + } else { + /* Key is already in ephemeral slot, use it */ + slot = STSAFE_KEY_SLOT_EPHEMERAL; + } + + if (rc == 0) { + STSAFE_INTERFACE_PRINTF("STSAFE: Computing shared secret with ephemeral slot %d, curve_id %d\n", + slot, curve_id); + rc = stsafe_shared_secret(slot, curve_id, + otherKeyX, otherKeyY, + info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen); + if (rc != STSAFE_A_OK) { + WOLFSSL_MSG("STSAFE: stsafe_shared_secret failed"); + STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d (slot: %d, curve_id: %d)\n", + rc, slot, curve_id); + rc = WC_HW_E; + } + } } } From 654901782cd4765f8e57fd65e36ea541f3f7332a Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Jan 2026 00:14:28 +0000 Subject: [PATCH 16/27] Peer review cleanups. ECDHE improvements. --- wolfcrypt/src/port/st/stsafe.c | 14 +++++++++++--- wolfssl/wolfcrypt/port/st/stsafe.h | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 4beeb4c417..be8f41e9bd 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -288,7 +288,7 @@ static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, * but stsafe_curve_id_t values match stse_ecc_key_type_t enum values */ ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, (stse_ecc_key_type_t)curve_id, - 255, /* usage_limit */ + STSAFE_PERSISTENT_KEY_USAGE_LIMIT, pPubKeyRaw); if (ret != STSE_OK) { STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair error: %d\n", ret); @@ -454,7 +454,7 @@ static int stsafe_shared_secret_ecdhe(stsafe_curve_id_t curve_id, /* Compute shared secret using ephemeral slot (0xFF) * The ephemeral private key was generated by stse_generate_ECDHE_key_pair() */ ret = stse_ecc_establish_shared_secret(&g_stse_handler, - STSAFE_KEY_SLOT_EPHEMERAL, curve_id, peerPubKey, pSharedSecret); + STSAFE_KEY_SLOT_EPHEMERAL, (stse_ecc_key_type_t)curve_id, peerPubKey, pSharedSecret); if (ret != STSE_OK) { STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret (ECDHE) error: %d\n", ret); @@ -1554,7 +1554,7 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) slot = STSAFE_KEY_SLOT_1; /* Use persistent slot for ECDSA signing */ ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, (stse_ecc_key_type_t)curve_id, - 255, /* usage_limit for persistent keys */ + STSAFE_PERSISTENT_KEY_USAGE_LIMIT, pubKeyRaw); if (ret != STSE_OK) { STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (slot 1) error: %d\n", ret); @@ -1852,6 +1852,7 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } if (need_ephemeral_key) { +#ifdef WOLFSSL_STSAFEA120 /* Key is in slot 1 (for ECDSA), but ECDH requires ephemeral slot. * Generate ephemeral key pair for ECDH. Note: This will overwrite any * existing key in ephemeral slot, so for bidirectional ECDH, both keys @@ -1886,6 +1887,13 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } } } +#else /* WOLFSSL_STSAFEA100 */ + /* For A100/A110, ephemeral key generation in ECDH callback + * is not supported. Keys must be generated in ephemeral slot + * from the start for ECDH operations. */ + WOLFSSL_MSG("STSAFE: ECDH requires ephemeral slot - key must be generated in ephemeral slot"); + rc = WC_HW_E; +#endif } else { /* Key is already in ephemeral slot, use it */ slot = STSAFE_KEY_SLOT_EPHEMERAL; diff --git a/wolfssl/wolfcrypt/port/st/stsafe.h b/wolfssl/wolfcrypt/port/st/stsafe.h index 83b02c6053..49d61043c5 100644 --- a/wolfssl/wolfcrypt/port/st/stsafe.h +++ b/wolfssl/wolfcrypt/port/st/stsafe.h @@ -92,6 +92,10 @@ /* Return codes */ #define STSAFE_A_OK 0 /* STSE_OK */ + /* Key usage limits */ + #define STSAFE_PERSISTENT_KEY_USAGE_LIMIT 255 /* Usage limit for persistent keys in slot 1 */ + #define STSAFE_EPHEMERAL_KEY_USAGE_LIMIT 255 /* Usage limit for ephemeral keys in slot 0xFF */ + /* Hash types - must match stse_hash_algorithm_t values in STSELib */ #define STSAFE_HASH_SHA256 0 /* STSE_SHA_256 */ #define STSAFE_HASH_SHA384 1 /* STSE_SHA_384 */ From 384eaa48b393142c9cef4071656a17eb32e8f750 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Jan 2026 19:10:11 +0000 Subject: [PATCH 17/27] Peer review fixes (thank you copilot) --- wolfcrypt/src/port/st/stsafe.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index be8f41e9bd..7508efde25 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -283,6 +283,10 @@ static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, stse_ReturnCode_t ret; stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Use dedicated key slot for persistent keys */ + if (pPubKeyRaw == NULL) { + return BAD_FUNC_ARG; + } + /* Generate key pair - public key is X||Y concatenated * Note: stse_generate_ecc_key_pair expects stse_ecc_key_type_t, * but stsafe_curve_id_t values match stse_ecc_key_type_t enum values */ @@ -340,6 +344,10 @@ static int stsafe_sign(stsafe_slot_t slot, stsafe_curve_id_t curve_id, stse_ReturnCode_t ret; int key_sz = stsafe_get_key_size(curve_id); + if (pHash == NULL || pSigRS == NULL) { + return BAD_FUNC_ARG; + } + /* Sign hash - output is R || S concatenated */ ret = stse_ecc_generate_signature(&g_stse_handler, slot, curve_id, pHash, (uint16_t)key_sz, pSigRS); @@ -364,6 +372,11 @@ static int stsafe_verify(stsafe_curve_id_t curve_id, uint8_t* pHash, uint8_t pubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; uint8_t validity = 0; + if (pHash == NULL || pSigRS == NULL || pPubKeyX == NULL || + pPubKeyY == NULL || pResult == NULL) { + return BAD_FUNC_ARG; + } + /* Combine X and Y into single buffer (X||Y) */ XMEMCPY(pubKey, pPubKeyX, key_sz); XMEMCPY(pubKey + key_sz, pPubKeyY, key_sz); @@ -402,6 +415,11 @@ static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, int key_sz = stsafe_get_key_size(curve_id); uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; + if (pPubKeyX == NULL || pPubKeyY == NULL || pSharedSecret == NULL || + pSharedSecretLen == NULL) { + return BAD_FUNC_ARG; + } + /* Combine peer X and Y (X||Y format) */ XMEMCPY(peerPubKey, pPubKeyX, key_sz); XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); @@ -1558,22 +1576,19 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) pubKeyRaw); if (ret != STSE_OK) { STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (slot 1) error: %d\n", ret); - rc = (int)ret; + rc = WC_HW_E; } else { rc = STSAFE_A_OK; } - if (rc != STSAFE_A_OK) { - rc = WC_HW_E; - } #else /* Legacy A100/A110 uses slot-based key generation */ rc = stsafe_create_key(&slot, curve_id, pubKeyRaw); -#endif if (rc != STSAFE_A_OK) { STSAFE_INTERFACE_PRINTF("stsafe_create_key error: %d\n", rc); rc = WC_HW_E; } +#endif } if (rc == 0) { From 54f0ecb5363995decd1a9985a1525c88a80c0679 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Jan 2026 19:59:10 +0000 Subject: [PATCH 18/27] Fix for ephemeral key usage limit. --- wolfcrypt/src/port/st/stsafe.c | 2 +- wolfssl/wolfcrypt/port/st/stsafe.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 7508efde25..2e498228a8 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -1879,7 +1879,7 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, (stse_ecc_key_type_t)curve_id, - STSAFEA_EPHEMERAL_KEY_USAGE_LIMIT, + STSAFE_EPHEMERAL_KEY_USAGE_LIMIT, ephemeralPubKey); if (ret != STSE_OK) { STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret); diff --git a/wolfssl/wolfcrypt/port/st/stsafe.h b/wolfssl/wolfcrypt/port/st/stsafe.h index 49d61043c5..322ef729cf 100644 --- a/wolfssl/wolfcrypt/port/st/stsafe.h +++ b/wolfssl/wolfcrypt/port/st/stsafe.h @@ -94,7 +94,7 @@ /* Key usage limits */ #define STSAFE_PERSISTENT_KEY_USAGE_LIMIT 255 /* Usage limit for persistent keys in slot 1 */ - #define STSAFE_EPHEMERAL_KEY_USAGE_LIMIT 255 /* Usage limit for ephemeral keys in slot 0xFF */ + #define STSAFE_EPHEMERAL_KEY_USAGE_LIMIT 1 /* Usage limit for ephemeral keys in slot 0xFF */ /* Hash types - must match stse_hash_algorithm_t values in STSELib */ #define STSAFE_HASH_SHA256 0 /* STSE_SHA_256 */ From 16fb84d0d154ae01bf5ee0c36f5c8793c2e36803 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 19 Jan 2026 19:53:45 +0000 Subject: [PATCH 19/27] Peer review fixes. Tested with brainpool. --- wolfcrypt/src/port/st/stsafe.c | 114 +++++++++++++++++++++-------- wolfssl/wolfcrypt/port/st/stsafe.h | 10 ++- 2 files changed, 91 insertions(+), 33 deletions(-) diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 2e498228a8..36afc56c03 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -120,12 +120,12 @@ static int stsafe_get_key_size(stsafe_curve_id_t curve_id) { switch (curve_id) { case STSAFE_ECC_CURVE_P256: - #ifdef STSAFE_ECC_CURVE_BP256 + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256) case STSAFE_ECC_CURVE_BP256: #endif return 32; case STSAFE_ECC_CURVE_P384: - #ifdef STSAFE_ECC_CURVE_BP384 + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384) case STSAFE_ECC_CURVE_BP384: #endif return 48; @@ -145,11 +145,11 @@ static stsafe_curve_id_t stsafe_get_ecc_curve_id(int ecc_curve) return STSAFE_ECC_CURVE_P256; case ECC_SECP384R1: return STSAFE_ECC_CURVE_P384; - #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP256) + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256) case ECC_BRAINPOOLP256R1: return STSAFE_ECC_CURVE_BP256; #endif - #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP384) + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384) case ECC_BRAINPOOLP384R1: return STSAFE_ECC_CURVE_BP384; #endif @@ -170,11 +170,11 @@ static int stsafe_get_ecc_curve(stsafe_curve_id_t curve_id) return ECC_SECP256R1; case STSAFE_ECC_CURVE_P384: return ECC_SECP384R1; - #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP256) + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256) case STSAFE_ECC_CURVE_BP256: return ECC_BRAINPOOLP256R1; #endif - #if defined(HAVE_ECC_BRAINPOOL) && defined(STSAFE_ECC_CURVE_BP384) + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384) case STSAFE_ECC_CURVE_BP384: return ECC_BRAINPOOLP384R1; #endif @@ -413,13 +413,25 @@ static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, int rc = STSAFE_A_OK; stse_ReturnCode_t ret; int key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + uint8_t* peerPubKey = NULL; +#else uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; +#endif if (pPubKeyX == NULL || pPubKeyY == NULL || pSharedSecret == NULL || pSharedSecretLen == NULL) { return BAD_FUNC_ARG; } +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + peerPubKey = (uint8_t*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (peerPubKey == NULL) { + return MEMORY_E; + } +#endif + /* Combine peer X and Y (X||Y format) */ XMEMCPY(peerPubKey, pPubKeyX, key_sz); XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); @@ -441,6 +453,10 @@ static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, *pSharedSecretLen = (int32_t)key_sz; } +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(peerPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return rc; } @@ -458,13 +474,25 @@ static int stsafe_shared_secret_ecdhe(stsafe_curve_id_t curve_id, int rc = STSAFE_A_OK; stse_ReturnCode_t ret; int key_sz = stsafe_get_key_size(curve_id); +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + uint8_t* peerPubKey = NULL; +#else uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; +#endif if (pPubKeyX == NULL || pPubKeyY == NULL || pSharedSecret == NULL || pSharedSecretLen == NULL || key_sz == 0) { return BAD_FUNC_ARG; } +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + peerPubKey = (uint8_t*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (peerPubKey == NULL) { + return MEMORY_E; + } +#endif + /* Combine peer X and Y (X||Y format) */ XMEMCPY(peerPubKey, pPubKeyX, key_sz); XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); @@ -483,6 +511,10 @@ static int stsafe_shared_secret_ecdhe(stsafe_curve_id_t curve_id, *pSharedSecretLen = (int32_t)key_sz; } +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(peerPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return rc; } @@ -1820,7 +1852,14 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) curve_id = stsafe_get_ecc_curve_id(ecc_curve); /* Note: STSAFE_ECC_CURVE_P256 is 0, so we can't use STSAFE_DEFAULT_CURVE check. * Instead, verify the curve_id is valid by checking it's one of the supported curves */ - if (curve_id != STSAFE_ECC_CURVE_P256 && curve_id != STSAFE_ECC_CURVE_P384) { + if (curve_id != STSAFE_ECC_CURVE_P256 && curve_id != STSAFE_ECC_CURVE_P384 + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_256) + && curve_id != STSAFE_ECC_CURVE_BP256 + #endif + #if defined(HAVE_ECC_BRAINPOOL) && defined(STSE_CONF_ECC_BRAINPOOL_P_384) + && curve_id != STSAFE_ECC_CURVE_BP384 + #endif + ) { rc = BAD_FUNC_ARG; } } @@ -1873,35 +1912,52 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) * existing key in ephemeral slot, so for bidirectional ECDH, both keys * should be generated in ephemeral slot from the start. */ stse_ReturnCode_t ret; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* ephemeralPubKey = NULL; +#else byte ephemeralPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; +#endif int key_sz = stsafe_get_key_size(curve_id); slot = STSAFE_KEY_SLOT_EPHEMERAL; - ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, - (stse_ecc_key_type_t)curve_id, - STSAFE_EPHEMERAL_KEY_USAGE_LIMIT, - ephemeralPubKey); - if (ret != STSE_OK) { - STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret); - rc = (int)ret; - } else { - WOLFSSL_MSG("STSAFE: Generated ephemeral key for ECDH"); - /* Update devCtx to reflect ephemeral slot for this key */ - if (info->pk.ecdh.private_key != NULL) { - info->pk.ecdh.private_key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot); - } - /* Update the public key in the key structure to match the new ephemeral key */ - if (info->pk.ecdh.private_key != NULL && rc == 0) { - void* saved_devCtx = info->pk.ecdh.private_key->devCtx; - rc = wc_ecc_import_unsigned(info->pk.ecdh.private_key, - ephemeralPubKey, &ephemeralPubKey[key_sz], - NULL, ecc_curve); - /* Restore devCtx in case import cleared it */ - if (saved_devCtx != NULL && info->pk.ecdh.private_key->devCtx != saved_devCtx) { - info->pk.ecdh.private_key->devCtx = saved_devCtx; +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + ephemeralPubKey = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (ephemeralPubKey == NULL) { + rc = MEMORY_E; + } +#endif + + if (rc == 0) { + ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, + (stse_ecc_key_type_t)curve_id, + STSAFE_EPHEMERAL_KEY_USAGE_LIMIT, + ephemeralPubKey); + if (ret != STSE_OK) { + STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret); + rc = (int)ret; + } else { + WOLFSSL_MSG("STSAFE: Generated ephemeral key for ECDH"); + /* Update devCtx to reflect ephemeral slot for this key */ + if (info->pk.ecdh.private_key != NULL) { + info->pk.ecdh.private_key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot); + } + /* Update the public key in the key structure to match the new ephemeral key */ + if (info->pk.ecdh.private_key != NULL && rc == 0) { + void* saved_devCtx = info->pk.ecdh.private_key->devCtx; + rc = wc_ecc_import_unsigned(info->pk.ecdh.private_key, + ephemeralPubKey, &ephemeralPubKey[key_sz], + NULL, ecc_curve); + /* Restore devCtx in case import cleared it */ + if (saved_devCtx != NULL && info->pk.ecdh.private_key->devCtx != saved_devCtx) { + info->pk.ecdh.private_key->devCtx = saved_devCtx; + } } } } +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + XFREE(ephemeralPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif #else /* WOLFSSL_STSAFEA100 */ /* For A100/A110, ephemeral key generation in ECDH callback * is not supported. Keys must be generated in ephemeral slot diff --git a/wolfssl/wolfcrypt/port/st/stsafe.h b/wolfssl/wolfcrypt/port/st/stsafe.h index 322ef729cf..6e19233e12 100644 --- a/wolfssl/wolfcrypt/port/st/stsafe.h +++ b/wolfssl/wolfcrypt/port/st/stsafe.h @@ -77,12 +77,14 @@ /* Curve ID mappings - values depend on stse_conf.h settings! * With only NIST P-256 and P-384 enabled: * STSE_ECC_KT_NIST_P_256 = 0, STSE_ECC_KT_NIST_P_384 = 1 - * NOTE: If other curves are enabled, these values change! */ + * NOTE: If other curves are enabled, these values change! + * + * Compile-time static assertions and runtime checks in stsafe_interface_init() + * verify that these constants match the actual STSE_ECC_KT enum values. */ #define STSAFE_ECC_CURVE_P256 0 /* STSE_ECC_KT_NIST_P_256 */ #define STSAFE_ECC_CURVE_P384 1 /* STSE_ECC_KT_NIST_P_384 */ - /* Brainpool curves - only defined when enabled in stse_conf.h */ - /* #define STSAFE_ECC_CURVE_BP256 2 */ /* STSE_ECC_KT_BP_P_256 */ - /* #define STSAFE_ECC_CURVE_BP384 3 */ /* STSE_ECC_KT_BP_P_384 */ + #define STSAFE_ECC_CURVE_BP256 2 /* STSE_ECC_KT_BP_P_256 */ + #define STSAFE_ECC_CURVE_BP384 3 /* STSE_ECC_KT_BP_P_384 */ /* Slot mappings */ #define STSAFE_KEY_SLOT_0 0 From 38b0fe19a1ee34d2ea5679236776b1e63e28a79d Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 21 Jan 2026 00:02:52 +0000 Subject: [PATCH 20/27] Improvements to code for ECDHE and peer review fixes. --- .wolfssl_known_macro_extras | 2 + wolfcrypt/src/port/st/stsafe.c | 259 ++++++++------------------------- 2 files changed, 59 insertions(+), 202 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 01d989177a..3602cf6b56 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -548,6 +548,8 @@ STM32_NUTTX_RNG STSAFE_HOST_KEY_CIPHER STSAFE_HOST_KEY_MAC STSAFE_I2C_BUS +STSE_CONF_ECC_BRAINPOOL_P_256 +STSE_CONF_ECC_BRAINPOOL_P_384 TASK_EXTRA_STACK_SIZE TCP_NODELAY TFM_ALREADY_SET diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 36afc56c03..7f308d6f16 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -276,12 +276,11 @@ int stsafe_interface_init(void) * \details Uses dedicated key slot (slot 1) for persistent keys. * For ephemeral ECDHE keys, use stsafe_create_ecdhe_key() instead. */ -static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, +static int stsafe_create_key(stsafe_slot_t slot, stsafe_curve_id_t curve_id, uint8_t* pPubKeyRaw) { int rc = STSAFE_A_OK; stse_ReturnCode_t ret; - stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Use dedicated key slot for persistent keys */ if (pPubKeyRaw == NULL) { return BAD_FUNC_ARG; @@ -299,10 +298,6 @@ static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id, rc = (int)ret; } - if (rc == STSAFE_A_OK && pSlot != NULL) { - *pSlot = slot; - } - return rc; } @@ -460,64 +455,6 @@ static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id, return rc; } -/** - * \brief ECDHE shared secret using STSAFE-A120 - * \details Computes shared secret using the ephemeral ECDHE private key - * that was generated by stsafe_create_ecdhe_key(). The ephemeral - * private key is stored internally in the STSE device. - */ -static int stsafe_shared_secret_ecdhe(stsafe_curve_id_t curve_id, - uint8_t* pPubKeyX, uint8_t* pPubKeyY, - uint8_t* pSharedSecret, - int32_t* pSharedSecretLen) -{ - int rc = STSAFE_A_OK; - stse_ReturnCode_t ret; - int key_sz = stsafe_get_key_size(curve_id); -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - uint8_t* peerPubKey = NULL; -#else - uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; -#endif - - if (pPubKeyX == NULL || pPubKeyY == NULL || pSharedSecret == NULL || - pSharedSecretLen == NULL || key_sz == 0) { - return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - peerPubKey = (uint8_t*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (peerPubKey == NULL) { - return MEMORY_E; - } -#endif - - /* Combine peer X and Y (X||Y format) */ - XMEMCPY(peerPubKey, pPubKeyX, key_sz); - XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz); - - /* Compute shared secret using ephemeral slot (0xFF) - * The ephemeral private key was generated by stse_generate_ECDHE_key_pair() */ - ret = stse_ecc_establish_shared_secret(&g_stse_handler, - STSAFE_KEY_SLOT_EPHEMERAL, (stse_ecc_key_type_t)curve_id, peerPubKey, pSharedSecret); - if (ret != STSE_OK) { - STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret (ECDHE) error: %d\n", - ret); - rc = (int)ret; - } - - if (rc == STSAFE_A_OK) { - *pSharedSecretLen = (int32_t)key_sz; - } - -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - XFREE(peerPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return rc; -} - /** * \brief Read device certificate from STSAFE-A120 */ @@ -536,11 +473,16 @@ static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) /* First, get certificate size */ ret = stse_get_device_certificate_size(&g_stse_handler, certZone, &certLen); - if (ret != STSE_OK || certLen == 0) { + if (ret != STSE_OK) { STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size error: %d\n", ret); rc = (int)ret; } + else if (certLen == 0) { + /* Certificate size is 0 - invalid certificate data */ + STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size returned zero length\n"); + rc = ASN_PARSE_E; + } /* Allocate buffer */ if (rc == STSAFE_A_OK) { @@ -988,6 +930,14 @@ static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen) } break; } + /* Check if length parsing succeeded */ + if (*pCertLen == 0) { + rc = ASN_PARSE_E; + } + } + else { + /* Invalid ASN.1 header - expected SEQUENCE tag */ + rc = ASN_PARSE_E; } } else { @@ -1469,23 +1419,12 @@ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, } if (err == 0) { -#ifdef WOLFSSL_STSAFEA120 - /* Use ECDHE shared secret computation for A120 */ - err = stsafe_shared_secret_ecdhe(curve_id, otherKeyX, otherKeyY, - out, (int32_t*)outlen); - if (err != STSAFE_A_OK) { - STSAFE_INTERFACE_PRINTF("stsafe_shared_secret_ecdhe error: %d\n", err); - err = WC_HW_E; - } -#else - /* Legacy A100/A110 uses slot-based shared secret */ err = stsafe_shared_secret(slot, curve_id, otherKeyX, otherKeyY, out, (int32_t*)outlen); if (err != STSAFE_A_OK) { STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", err); err = WC_HW_E; } -#endif } if (tmpKeyInit) { @@ -1597,17 +1536,25 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) key_sz = stsafe_get_key_size(curve_id); /* For A120, generate keys in slot 1 (persistent slot) by default for ECDSA signing. - * For ECDH operations, ephemeral keys will be generated on-demand in the ECDH callback - * if needed (see WC_PK_TYPE_ECDH handling below). */ + * For ECDH operations, the key slot from devCtx will be used directly. + * If ECDH is required, keys should be generated in the ephemeral slot from the start. */ #ifdef WOLFSSL_STSAFEA120 - stse_ReturnCode_t ret; - slot = STSAFE_KEY_SLOT_1; /* Use persistent slot for ECDSA signing */ - ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, - (stse_ecc_key_type_t)curve_id, - STSAFE_PERSISTENT_KEY_USAGE_LIMIT, - pubKeyRaw); - if (ret != STSE_OK) { - STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (slot 1) error: %d\n", ret); + /* Retrieve slot from devCtx if available, otherwise use default */ + slot = STSAFE_KEY_SLOT_1; /* Default fallback */ + if (info->pk.eckg.key != NULL && info->pk.eckg.key->devCtx != NULL) { + slot = STSAFE_DEVCXT_TO_SLOT(info->pk.eckg.key->devCtx); + } + + STSAFE_INTERFACE_PRINTF("STSAFE: KeyGen slot %d, curve_id %d\n", + slot, curve_id); + + if (slot == STSAFE_KEY_SLOT_EPHEMERAL) { + rc = stsafe_create_ecdhe_key(curve_id, pubKeyRaw); + } else { + rc = stsafe_create_key(slot, curve_id, pubKeyRaw); + } + if (rc != STSE_OK) { + STSAFE_INTERFACE_PRINTF("STSAFE: KeyGen (slot %d) error: %d\n", slot, rc); rc = WC_HW_E; } else { rc = STSAFE_A_OK; @@ -1624,21 +1571,17 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } if (rc == 0) { - /* Store slot number directly in devCtx (no dynamic allocation) */ - info->pk.eckg.key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot); + /* Import public key */ + rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, + &pubKeyRaw[key_sz], NULL, ecc_curve); } if (rc == 0) { - /* Import public key - preserve devCtx */ - void* saved_devCtx = info->pk.eckg.key->devCtx; - rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw, - &pubKeyRaw[key_sz], NULL, ecc_curve); - /* Restore devCtx in case import cleared it */ - if (saved_devCtx != NULL && info->pk.eckg.key->devCtx != saved_devCtx) { - info->pk.eckg.key->devCtx = saved_devCtx; - } + /* Store slot number directly in devCtx */ + info->pk.eckg.key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot); } + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -1653,6 +1596,7 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) #endif byte* r; byte* s; + stsafe_slot_t slot; stsafe_curve_id_t curve_id; int ecc_curve; word32 inSz = info->pk.eccsign.inlen; @@ -1690,12 +1634,12 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN); /* Retrieve slot from devCtx if available, otherwise use default */ - stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Default fallback */ + slot = STSAFE_KEY_SLOT_1; /* Default fallback */ if (info->pk.eccsign.key != NULL && info->pk.eccsign.key->devCtx != NULL) { slot = STSAFE_DEVCXT_TO_SLOT(info->pk.eccsign.key->devCtx); - STSAFE_INTERFACE_PRINTF("STSAFE: Using slot %d from devCtx for signing\n", slot); + STSAFE_INTERFACE_PRINTF("STSAFE: Sign using slot %d\n", slot); } else { - WOLFSSL_MSG("STSAFE: Warning: devCtx not found, using default slot 1"); + WOLFSSL_MSG("STSAFE: Sign using default slot 1"); } rc = stsafe_sign(slot, curve_id, digest, sigRS); if (rc != STSAFE_A_OK) { @@ -1815,6 +1759,7 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) word32 otherKeyX_len = STSAFE_MAX_KEY_LEN; word32 otherKeyY_len = STSAFE_MAX_KEY_LEN; stsafe_curve_id_t curve_id; + stsafe_slot_t slot; int ecc_curve; WOLFSSL_MSG("STSAFE: ECDH"); @@ -1872,116 +1817,26 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) if (rc == 0) { *info->pk.ecdh.outlen = 0; - /* Check if private key is software but public key is hardware. - * In this case, we can't use hardware for computation since the - * private key is not in a slot. Return CRYPTOCB_UNAVAILABLE to - * let software handle it (but software path may also fail if - * public key export fails). */ - if (info->pk.ecdh.private_key == NULL || - info->pk.ecdh.private_key->devId == INVALID_DEVID) { - if (info->pk.ecdh.public_key != NULL && - info->pk.ecdh.public_key->devId != INVALID_DEVID) { - WOLFSSL_MSG("STSAFE: Private key is software, public key is hardware - cannot use hardware"); - rc = CRYPTOCB_UNAVAILABLE; - } - } - if (rc == 0) { - /* For ECDH operations, use ephemeral slot (0xFF). - * Keys are generated in slot 1 by default (for ECDSA signing). - * If the key is in slot 1, generate a new ephemeral key for ECDH. - * If the key is already in the ephemeral slot, use it directly. */ - stsafe_slot_t slot; - stsafe_slot_t original_slot = STSAFE_KEY_SLOT_1; - int need_ephemeral_key = 0; - + /* For ECDH operations, use the slot from devCtx. */ + slot = STSAFE_KEY_SLOT_EPHEMERAL; if (info->pk.ecdh.private_key != NULL && info->pk.ecdh.private_key->devCtx != NULL) { - original_slot = STSAFE_DEVCXT_TO_SLOT(info->pk.ecdh.private_key->devCtx); - - /* If key is in slot 1 (for ECDSA), we need to generate ephemeral key for ECDH */ - if (original_slot == STSAFE_KEY_SLOT_1) { - need_ephemeral_key = 1; - } + slot = STSAFE_DEVCXT_TO_SLOT(info->pk.ecdh.private_key->devCtx); } - if (need_ephemeral_key) { -#ifdef WOLFSSL_STSAFEA120 - /* Key is in slot 1 (for ECDSA), but ECDH requires ephemeral slot. - * Generate ephemeral key pair for ECDH. Note: This will overwrite any - * existing key in ephemeral slot, so for bidirectional ECDH, both keys - * should be generated in ephemeral slot from the start. */ - stse_ReturnCode_t ret; -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - byte* ephemeralPubKey = NULL; -#else - byte ephemeralPubKey[STSAFE_MAX_PUBKEY_RAW_LEN]; -#endif - int key_sz = stsafe_get_key_size(curve_id); - slot = STSAFE_KEY_SLOT_EPHEMERAL; + STSAFE_INTERFACE_PRINTF("STSAFE: ECDH with slot %d, curve_id %d\n", + slot, curve_id); -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - ephemeralPubKey = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (ephemeralPubKey == NULL) { - rc = MEMORY_E; - } -#endif - - if (rc == 0) { - ret = stse_generate_ecc_key_pair(&g_stse_handler, slot, - (stse_ecc_key_type_t)curve_id, - STSAFE_EPHEMERAL_KEY_USAGE_LIMIT, - ephemeralPubKey); - if (ret != STSE_OK) { - STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret); - rc = (int)ret; - } else { - WOLFSSL_MSG("STSAFE: Generated ephemeral key for ECDH"); - /* Update devCtx to reflect ephemeral slot for this key */ - if (info->pk.ecdh.private_key != NULL) { - info->pk.ecdh.private_key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot); - } - /* Update the public key in the key structure to match the new ephemeral key */ - if (info->pk.ecdh.private_key != NULL && rc == 0) { - void* saved_devCtx = info->pk.ecdh.private_key->devCtx; - rc = wc_ecc_import_unsigned(info->pk.ecdh.private_key, - ephemeralPubKey, &ephemeralPubKey[key_sz], - NULL, ecc_curve); - /* Restore devCtx in case import cleared it */ - if (saved_devCtx != NULL && info->pk.ecdh.private_key->devCtx != saved_devCtx) { - info->pk.ecdh.private_key->devCtx = saved_devCtx; - } - } - } - } -#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - XFREE(ephemeralPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif -#else /* WOLFSSL_STSAFEA100 */ - /* For A100/A110, ephemeral key generation in ECDH callback - * is not supported. Keys must be generated in ephemeral slot - * from the start for ECDH operations. */ - WOLFSSL_MSG("STSAFE: ECDH requires ephemeral slot - key must be generated in ephemeral slot"); + rc = stsafe_shared_secret(slot, curve_id, + otherKeyX, otherKeyY, + info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen); + if (rc != STSAFE_A_OK) { + WOLFSSL_MSG("STSAFE: stsafe_shared_secret failed"); + STSAFE_INTERFACE_PRINTF("stsafe_shared_secret " + "error: %d (slot: %d, curve_id: %d)\n", + rc, slot, curve_id); rc = WC_HW_E; -#endif - } else { - /* Key is already in ephemeral slot, use it */ - slot = STSAFE_KEY_SLOT_EPHEMERAL; - } - - if (rc == 0) { - STSAFE_INTERFACE_PRINTF("STSAFE: Computing shared secret with ephemeral slot %d, curve_id %d\n", - slot, curve_id); - rc = stsafe_shared_secret(slot, curve_id, - otherKeyX, otherKeyY, - info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen); - if (rc != STSAFE_A_OK) { - WOLFSSL_MSG("STSAFE: stsafe_shared_secret failed"); - STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d (slot: %d, curve_id: %d)\n", - rc, slot, curve_id); - rc = WC_HW_E; - } } } } From 88593f8dcd01deca53cf833b5816bae0e038c278 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 21 Jan 2026 12:04:28 +1000 Subject: [PATCH 21/27] ML-DSA: max values based on available parameters When building wolfSSL implementation, make maximum sizes based on available parameter sets. Add wc_MlDsaKey_SignCtx and wc_MlDsaKey_VerifyCtx macros. --- wolfssl/wolfcrypt/dilithium.h | 78 ++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/wolfssl/wolfcrypt/dilithium.h b/wolfssl/wolfcrypt/dilithium.h index 5659b56aef..9c4054be46 100644 --- a/wolfssl/wolfcrypt/dilithium.h +++ b/wolfssl/wolfcrypt/dilithium.h @@ -541,6 +541,50 @@ #endif /* LITTLE_ENDIAN_ORDER && WOLFSSL_DILITHIUM_ALIGNMENT == 0 */ #endif +#ifndef WOLFSSL_NO_ML_DSA_87 + +#define DILITHIUM_MAX_KEY_SIZE DILITHIUM_LEVEL5_KEY_SIZE +#define DILITHIUM_MAX_SIG_SIZE DILITHIUM_LEVEL5_SIG_SIZE +#define DILITHIUM_MAX_PUB_KEY_SIZE DILITHIUM_LEVEL5_PUB_KEY_SIZE +#define DILITHIUM_MAX_PRV_KEY_SIZE DILITHIUM_LEVEL5_PRV_KEY_SIZE +/* Buffer sizes large enough to store exported DER encoded keys */ +#define DILITHIUM_MAX_PUB_KEY_DER_SIZE DILITHIUM_LEVEL5_PUB_KEY_DER_SIZE +#define DILITHIUM_MAX_PRV_KEY_DER_SIZE DILITHIUM_LEVEL5_PRV_KEY_DER_SIZE +#define DILITHIUM_MAX_BOTH_KEY_DER_SIZE DILITHIUM_LEVEL5_BOTH_KEY_DER_SIZE +/* PEM size with the header "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----" and + * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ +#define DILITHIUM_MAX_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL5_BOTH_KEY_PEM_SIZE + +#elif !defined(WOLFSSL_NO_ML_DSA_65) + +#define DILITHIUM_MAX_KEY_SIZE DILITHIUM_LEVEL3_KEY_SIZE +#define DILITHIUM_MAX_SIG_SIZE DILITHIUM_LEVEL3_SIG_SIZE +#define DILITHIUM_MAX_PUB_KEY_SIZE DILITHIUM_LEVEL3_PUB_KEY_SIZE +#define DILITHIUM_MAX_PRV_KEY_SIZE DILITHIUM_LEVEL3_PRV_KEY_SIZE +/* Buffer sizes large enough to store exported DER encoded keys */ +#define DILITHIUM_MAX_PUB_KEY_DER_SIZE DILITHIUM_LEVEL3_PUB_KEY_DER_SIZE +#define DILITHIUM_MAX_PRV_KEY_DER_SIZE DILITHIUM_LEVEL3_PRV_KEY_DER_SIZE +#define DILITHIUM_MAX_BOTH_KEY_DER_SIZE DILITHIUM_LEVEL3_BOTH_KEY_DER_SIZE +/* PEM size with the header "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----" and + * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ +#define DILITHIUM_MAX_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL3_BOTH_KEY_PEM_SIZE + +#else + +#define DILITHIUM_MAX_KEY_SIZE DILITHIUM_LEVEL2_KEY_SIZE +#define DILITHIUM_MAX_SIG_SIZE DILITHIUM_LEVEL2_SIG_SIZE +#define DILITHIUM_MAX_PUB_KEY_SIZE DILITHIUM_LEVEL2_PUB_KEY_SIZE +#define DILITHIUM_MAX_PRV_KEY_SIZE DILITHIUM_LEVEL2_PRV_KEY_SIZE +/* Buffer sizes large enough to store exported DER encoded keys */ +#define DILITHIUM_MAX_PUB_KEY_DER_SIZE DILITHIUM_LEVEL2_PUB_KEY_DER_SIZE +#define DILITHIUM_MAX_PRV_KEY_DER_SIZE DILITHIUM_LEVEL2_PRV_KEY_DER_SIZE +#define DILITHIUM_MAX_BOTH_KEY_DER_SIZE DILITHIUM_LEVEL2_BOTH_KEY_DER_SIZE +/* PEM size with the header "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----" and + * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ +#define DILITHIUM_MAX_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL2_BOTH_KEY_PEM_SIZE + +#endif + #elif defined(HAVE_LIBOQS) #define DILITHIUM_LEVEL2_KEY_SIZE OQS_SIG_ml_dsa_44_ipd_length_secret_key @@ -621,8 +665,6 @@ * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ #define ML_DSA_LEVEL5_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL5_BOTH_KEY_PEM_SIZE -#endif - #define DILITHIUM_MAX_KEY_SIZE DILITHIUM_LEVEL5_KEY_SIZE #define DILITHIUM_MAX_SIG_SIZE DILITHIUM_LEVEL5_SIG_SIZE #define DILITHIUM_MAX_PUB_KEY_SIZE DILITHIUM_LEVEL5_PUB_KEY_SIZE @@ -634,6 +676,8 @@ /* PEM size with the header "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----" and * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ #define DILITHIUM_MAX_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL5_BOTH_KEY_PEM_SIZE +#endif + #ifdef WOLF_PRIVATE_KEY_ID @@ -1012,33 +1056,37 @@ WOLFSSL_LOCAL void wc_mldsa_poly_make_pos_avx2(sword32* a); #define MlDsaKey dilithium_key -#define wc_MlDsaKey_Init(key, heap, devId) \ +#define wc_MlDsaKey_Init(key, heap, devId) \ wc_dilithium_init_ex(key, heap, devId) -#define wc_MlDsaKey_SetParams(key, id) \ +#define wc_MlDsaKey_SetParams(key, id) \ wc_dilithium_set_level(key, id) -#define wc_MlDsaKey_GetParams(key, id) \ +#define wc_MlDsaKey_GetParams(key, id) \ wc_dilithium_get_level(key, id) -#define wc_MlDsaKey_MakeKey(key, rng) \ +#define wc_MlDsaKey_MakeKey(key, rng) \ wc_dilithium_make_key(key, rng) -#define wc_MlDsaKey_ExportPrivRaw(key, out, outLen) \ +#define wc_MlDsaKey_ExportPrivRaw(key, out, outLen) \ wc_dilithium_export_private_only(key, out, outLen) -#define wc_MlDsaKey_ImportPrivRaw(key, in, inLen) \ +#define wc_MlDsaKey_ImportPrivRaw(key, in, inLen) \ wc_dilithium_import_private_only(in, inLen, key) -#define wc_MlDsaKey_Sign(key, sig, sigSz, msg, msgSz, rng) \ +#define wc_MlDsaKey_Sign(key, sig, sigSz, msg, msgSz, rng) \ wc_dilithium_sign_msg(msg, msgSz, sig, sigSz, key, rng) -#define wc_MlDsaKey_Free(key) \ +#define wc_MlDsaKey_SignCtx(key, ctx, ctxSz, sig, sigSz, msg, msgSz, rng) \ + wc_dilithium_sign_ctx_msg(ctx, ctxSz, msg, msgSz, sig, sigSz, key, rng) +#define wc_MlDsaKey_Free(key) \ wc_dilithium_free(key) -#define wc_MlDsaKey_ExportPubRaw(key, out, outLen) \ +#define wc_MlDsaKey_ExportPubRaw(key, out, outLen) \ wc_dilithium_export_public(key, out, outLen) -#define wc_MlDsaKey_ImportPubRaw(key, in, inLen) \ +#define wc_MlDsaKey_ImportPubRaw(key, in, inLen) \ wc_dilithium_import_public(in, inLen, key) -#define wc_MlDsaKey_Verify(key, sig, sigSz, msg, msgSz, res) \ +#define wc_MlDsaKey_Verify(key, sig, sigSz, msg, msgSz, res) \ wc_dilithium_verify_msg(sig, sigSz, msg, msgSz, res, key) +#define wc_MlDsaKey_VerifyCtx(key, sig, sigSz, ctx, ctxSz, msg, msgSz, res) \ + wc_dilithium_verify_msg_ctx(sig, sigSz, ctx, ctxSz, msg, msgSz, res, key) -#define wc_MlDsaKey_PublicKeyToDer(key, output, len, withAlg) \ +#define wc_MlDsaKey_PublicKeyToDer(key, output, len, withAlg) \ wc_Dilithium_PublicKeyToDer(key, output, len, withAlg) -#define wc_MlDsaKey_PrivateKeyToDer(key, output, len) \ +#define wc_MlDsaKey_PrivateKeyToDer(key, output, len) \ wc_Dilithium_PrivateKeyToDer(key, output, len) From 69fd8dc01fbcdd180a6fbddbd4d9dad6a31c23cb Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 15 Jan 2026 14:28:35 -0500 Subject: [PATCH 22/27] Update from Ubuntu 22.04 to Ubuntu 24.04 for several github workflows --- .github/workflows/async.yml | 2 +- .github/workflows/bind.yml | 4 ++-- .github/workflows/codespell.yml | 2 +- .github/workflows/coverity-scan-fixes.yml | 2 +- .github/workflows/curl.yml | 4 ++-- .github/workflows/cyrus-sasl.yml | 4 ++-- .github/workflows/disable-pk-algs.yml | 2 +- .github/workflows/docker-Espressif.yml | 6 +++--- .github/workflows/docker-OpenWrt.yml | 4 ++-- .github/workflows/fil-c.yml | 2 +- .github/workflows/grpc.yml | 4 ++-- .github/workflows/haproxy.yml | 4 ++-- .github/workflows/intelasm-c-fallback.yml | 2 +- .github/workflows/ipmitool.yml | 6 +++--- .github/workflows/jwt-cpp.yml | 6 +++--- .github/workflows/libspdm.yml | 4 ++-- .github/workflows/libvncserver.yml | 4 ++-- .github/workflows/memcached.yml | 4 ++-- .github/workflows/mosquitto.yml | 4 ++-- .github/workflows/multi-compiler.yml | 12 +++--------- .github/workflows/net-snmp.yml | 4 ++-- .github/workflows/nginx.yml | 4 ++-- .github/workflows/no-malloc.yml | 2 +- .github/workflows/no-tls.yml | 2 +- .github/workflows/nss.yml | 4 ++-- .github/workflows/ntp.yml | 4 ++-- .github/workflows/ocsp.yml | 2 +- .github/workflows/openldap.yml | 4 ++-- .github/workflows/openssh.yml | 4 ++-- .github/workflows/opensslcoexist.yml | 2 +- .github/workflows/openvpn.yml | 4 ++-- .github/workflows/os-check.yml | 8 ++++---- .github/workflows/packaging.yml | 2 +- .github/workflows/pam-ipmi.yml | 4 ++-- .github/workflows/pq-all.yml | 2 +- .github/workflows/psk.yml | 2 +- .github/workflows/rng-tools.yml | 4 ++-- .github/workflows/smallStackSize.yml | 2 +- .github/workflows/socat.yml | 4 ++-- .github/workflows/softhsm.yml | 4 ++-- .github/workflows/sssd.yml | 4 ++-- .github/workflows/stunnel.yml | 4 ++-- .github/workflows/symbol-prefixes.yml | 2 +- .github/workflows/threadx.yml | 2 +- .github/workflows/wolfCrypt-Wconversion.yml | 2 +- .github/workflows/zephyr.yml | 2 +- 46 files changed, 80 insertions(+), 86 deletions(-) diff --git a/.github/workflows/async.yml b/.github/workflows/async.yml index 168450a95d..8a572c328f 100644 --- a/.github/workflows/async.yml +++ b/.github/workflows/async.yml @@ -24,7 +24,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/bind.yml b/.github/workflows/bind.yml index c26646feaa..a427ead431 100644 --- a/.github/workflows/bind.yml +++ b/.github/workflows/bind.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -47,7 +47,7 @@ jobs: ref: [ 9.18.0, 9.18.28, 9.18.33 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 10 needs: build_wolfssl diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index e188e2e70f..33688cc05c 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -14,7 +14,7 @@ concurrency: jobs: codespell: if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/coverity-scan-fixes.yml b/.github/workflows/coverity-scan-fixes.yml index 9a70e080b6..301df23749 100644 --- a/.github/workflows/coverity-scan-fixes.yml +++ b/.github/workflows/coverity-scan-fixes.yml @@ -10,7 +10,7 @@ on: jobs: coverity: if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/curl.yml b/.github/workflows/curl.yml index 90aaa7c2d6..26b7afa973 100644 --- a/.github/workflows/curl.yml +++ b/.github/workflows/curl.yml @@ -16,7 +16,7 @@ jobs: build_wolfssl: name: Build wolfSSL if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -40,7 +40,7 @@ jobs: test_curl: name: ${{ matrix.curl_ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 15 needs: build_wolfssl diff --git a/.github/workflows/cyrus-sasl.yml b/.github/workflows/cyrus-sasl.yml index 910c871224..2e5068d71c 100644 --- a/.github/workflows/cyrus-sasl.yml +++ b/.github/workflows/cyrus-sasl.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -48,7 +48,7 @@ jobs: ref: [ 2.1.28 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 needs: build_wolfssl diff --git a/.github/workflows/disable-pk-algs.yml b/.github/workflows/disable-pk-algs.yml index 123dfe2217..30573ee942 100644 --- a/.github/workflows/disable-pk-algs.yml +++ b/.github/workflows/disable-pk-algs.yml @@ -36,7 +36,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/docker-Espressif.yml b/.github/workflows/docker-Espressif.yml index 384509ecd9..4e79636f38 100644 --- a/.github/workflows/docker-Espressif.yml +++ b/.github/workflows/docker-Espressif.yml @@ -15,7 +15,7 @@ jobs: espressif_latest: name: latest Docker container if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 12 container: @@ -29,7 +29,7 @@ jobs: espressif_v4_4: name: v4.4 Docker container if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: espressif/idf:release-v4.4 steps: @@ -39,7 +39,7 @@ jobs: espressif_v5_0: name: v5.0 Docker container if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: espressif/idf:release-v5.0 steps: diff --git a/.github/workflows/docker-OpenWrt.yml b/.github/workflows/docker-OpenWrt.yml index 05890ffaed..1d8db9c2c9 100644 --- a/.github/workflows/docker-OpenWrt.yml +++ b/.github/workflows/docker-OpenWrt.yml @@ -18,7 +18,7 @@ jobs: build_library: name: Compile libwolfssl.so if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 container: @@ -42,7 +42,7 @@ jobs: compile_container: name: Compile container if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 2 needs: build_library diff --git a/.github/workflows/fil-c.yml b/.github/workflows/fil-c.yml index 3372969c37..410ba02727 100644 --- a/.github/workflows/fil-c.yml +++ b/.github/workflows/fil-c.yml @@ -28,7 +28,7 @@ jobs: # This should be a safe limit for the tests to run. timeout-minutes: 30 if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 name: ${{ matrix.config }} steps: - name: Download fil-c release diff --git a/.github/workflows/grpc.yml b/.github/workflows/grpc.yml index 4259b2a936..019c57632a 100644 --- a/.github/workflows/grpc.yml +++ b/.github/workflows/grpc.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 10 steps: @@ -52,7 +52,7 @@ jobs: h2_ssl_cert_test h2_ssl_session_reuse_test name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 30 needs: build_wolfssl diff --git a/.github/workflows/haproxy.yml b/.github/workflows/haproxy.yml index 99db830f9f..17f0f3f088 100644 --- a/.github/workflows/haproxy.yml +++ b/.github/workflows/haproxy.yml @@ -16,7 +16,7 @@ jobs: build_wolfssl: name: Build wolfSSL if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -40,7 +40,7 @@ jobs: test_haproxy: name: ${{ matrix.haproxy_ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 15 needs: build_wolfssl diff --git a/.github/workflows/intelasm-c-fallback.yml b/.github/workflows/intelasm-c-fallback.yml index 49d3639bce..adbe942189 100644 --- a/.github/workflows/intelasm-c-fallback.yml +++ b/.github/workflows/intelasm-c-fallback.yml @@ -22,7 +22,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/ipmitool.yml b/.github/workflows/ipmitool.yml index 9c38a66e87..bbcdd9028b 100644 --- a/.github/workflows/ipmitool.yml +++ b/.github/workflows/ipmitool.yml @@ -18,7 +18,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -48,11 +48,11 @@ jobs: git_ref: [ c3939dac2c060651361fc71516806f9ab8c38901 ] name: ${{ matrix.git_ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: build_wolfssl steps: - name: Install dependencies - run: export DEBIAN_FRONTEND=noninteractive && sudo apt-get update && sudo apt-get install -y libreadline8 + run: export DEBIAN_FRONTEND=noninteractive && sudo apt-get update && sudo apt-get install -y libreadline-dev - name: Download lib uses: actions/download-artifact@v4 with: diff --git a/.github/workflows/jwt-cpp.yml b/.github/workflows/jwt-cpp.yml index 2dcb209b5c..09d1151df1 100644 --- a/.github/workflows/jwt-cpp.yml +++ b/.github/workflows/jwt-cpp.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL # Just to keep it the same as the testing target if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -47,9 +47,9 @@ jobs: matrix: config: - ref: 0.7.0 - runner: ubuntu-22.04 + runner: ubuntu-24.04 - ref: 0.6.0 - runner: ubuntu-22.04 + runner: ubuntu-24.04 name: ${{ matrix.config.ref }} runs-on: ${{ matrix.config.runner }} needs: build_wolfssl diff --git a/.github/workflows/libspdm.yml b/.github/workflows/libspdm.yml index 855d3d825b..098881e97b 100644 --- a/.github/workflows/libspdm.yml +++ b/.github/workflows/libspdm.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -46,7 +46,7 @@ jobs: ref: [ 3.7.0 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 needs: build_wolfssl diff --git a/.github/workflows/libvncserver.yml b/.github/workflows/libvncserver.yml index 87a772bf95..8964a57b95 100644 --- a/.github/workflows/libvncserver.yml +++ b/.github/workflows/libvncserver.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL # Just to keep it the same as the testing target if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -47,7 +47,7 @@ jobs: ref: [ 0.9.13, 0.9.14 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: build_wolfssl steps: - name: Download lib diff --git a/.github/workflows/memcached.yml b/.github/workflows/memcached.yml index bdd0c0593e..128c03d470 100644 --- a/.github/workflows/memcached.yml +++ b/.github/workflows/memcached.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL # Just to keep it the same as the testing target if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Build wolfSSL uses: wolfSSL/actions-build-autotools-project@v1 @@ -48,7 +48,7 @@ jobs: - ref: 1.6.22 name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: build_wolfssl steps: - name: Download lib diff --git a/.github/workflows/mosquitto.yml b/.github/workflows/mosquitto.yml index 97afaf2826..3e14debc36 100644 --- a/.github/workflows/mosquitto.yml +++ b/.github/workflows/mosquitto.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL # Just to keep it the same as the testing target if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -45,7 +45,7 @@ jobs: ref: [ 2.0.18 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 needs: build_wolfssl diff --git a/.github/workflows/multi-compiler.yml b/.github/workflows/multi-compiler.yml index d2e0486969..349ec385dc 100644 --- a/.github/workflows/multi-compiler.yml +++ b/.github/workflows/multi-compiler.yml @@ -31,18 +31,12 @@ jobs: - CC: gcc-12 CXX: g++-12 OS: ubuntu-24.04 - - CC: clang-11 - CXX: clang++-11 - OS: ubuntu-22.04 - - CC: clang-12 - CXX: clang++-12 - OS: ubuntu-22.04 - - CC: clang-13 - CXX: clang++-13 - OS: ubuntu-22.04 - CC: clang-14 CXX: clang++-14 OS: ubuntu-24.04 + - CC: clang-19 + CXX: clang++-19 + OS: ubuntu-24.04 if: github.repository_owner == 'wolfssl' runs-on: ${{ matrix.OS }} # This should be a safe limit for the tests to run. diff --git a/.github/workflows/net-snmp.yml b/.github/workflows/net-snmp.yml index 7ce030b80c..3146e7369c 100644 --- a/.github/workflows/net-snmp.yml +++ b/.github/workflows/net-snmp.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -48,7 +48,7 @@ jobs: test_opts: -e 'agentxperl' name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 needs: build_wolfssl diff --git a/.github/workflows/nginx.yml b/.github/workflows/nginx.yml index c85161a0e2..cc67610f2b 100644 --- a/.github/workflows/nginx.yml +++ b/.github/workflows/nginx.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -107,7 +107,7 @@ jobs: stream_proxy_ssl_verify.t name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 needs: build_wolfssl diff --git a/.github/workflows/no-malloc.yml b/.github/workflows/no-malloc.yml index f2ec8eda93..1ed247122b 100644 --- a/.github/workflows/no-malloc.yml +++ b/.github/workflows/no-malloc.yml @@ -22,7 +22,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/no-tls.yml b/.github/workflows/no-tls.yml index 5fd4004b89..fb6ff9cadc 100644 --- a/.github/workflows/no-tls.yml +++ b/.github/workflows/no-tls.yml @@ -22,7 +22,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/nss.yml b/.github/workflows/nss.yml index 821bc2c916..f88f205929 100644 --- a/.github/workflows/nss.yml +++ b/.github/workflows/nss.yml @@ -21,7 +21,7 @@ jobs: build_nss: name: Build nss if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 30 steps: @@ -60,7 +60,7 @@ jobs: nss_test: name: Test interop with nss if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: build_nss timeout-minutes: 10 steps: diff --git a/.github/workflows/ntp.yml b/.github/workflows/ntp.yml index 2acd82b228..98beed6291 100644 --- a/.github/workflows/ntp.yml +++ b/.github/workflows/ntp.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -47,7 +47,7 @@ jobs: ref: [ 4.2.8p15, 4.2.8p17 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 10 needs: build_wolfssl diff --git a/.github/workflows/ocsp.yml b/.github/workflows/ocsp.yml index b7c8f8ef5f..3cd5636d9d 100644 --- a/.github/workflows/ocsp.yml +++ b/.github/workflows/ocsp.yml @@ -16,7 +16,7 @@ jobs: ocsp_stapling: name: ocsp stapling if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout wolfSSL diff --git a/.github/workflows/openldap.yml b/.github/workflows/openldap.yml index 2074b2df97..6d9c76867b 100644 --- a/.github/workflows/openldap.yml +++ b/.github/workflows/openldap.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -51,7 +51,7 @@ jobs: git_ref: OPENLDAP_REL_ENG_2_6_7 name: ${{ matrix.osp_ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 20 needs: build_wolfssl diff --git a/.github/workflows/openssh.yml b/.github/workflows/openssh.yml index adbf82081d..99e90b4d2e 100644 --- a/.github/workflows/openssh.yml +++ b/.github/workflows/openssh.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -71,7 +71,7 @@ jobs: connection-timeout name: ${{ matrix.osp_ver }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: build_wolfssl steps: - name: Download lib diff --git a/.github/workflows/opensslcoexist.yml b/.github/workflows/opensslcoexist.yml index e116a2107b..1b26ed947c 100644 --- a/.github/workflows/opensslcoexist.yml +++ b/.github/workflows/opensslcoexist.yml @@ -23,7 +23,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/openvpn.yml b/.github/workflows/openvpn.yml index 9746301451..34ea287518 100644 --- a/.github/workflows/openvpn.yml +++ b/.github/workflows/openvpn.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -46,7 +46,7 @@ jobs: ref: [ release/2.6, master ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 10 needs: build_wolfssl diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 3329cc39c0..02ff88e32b 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-22.04, macos-latest ] + os: [ ubuntu-24.04, macos-latest ] config: [ # Add new configs here '', @@ -87,7 +87,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-22.04, macos-latest ] + os: [ ubuntu-24.04, macos-latest ] user-settings: [ # Add new user_settings.h here 'examples/configs/user_settings_all.h', @@ -109,7 +109,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-22.04, macos-latest ] + os: [ ubuntu-24.04, macos-latest ] user-settings: [ # Add new user_settings.h here 'examples/configs/user_settings_eccnonblock.h', @@ -140,7 +140,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-22.04, macos-latest ] + os: [ ubuntu-24.04, macos-latest ] name: make user_setting.h (with sed) if: github.repository_owner == 'wolfssl' runs-on: ${{ matrix.os }} diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml index 2b78fc8f93..ec55f410f1 100644 --- a/.github/workflows/packaging.yml +++ b/.github/workflows/packaging.yml @@ -16,7 +16,7 @@ jobs: build_wolfssl: name: Package wolfSSL if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 10 steps: diff --git a/.github/workflows/pam-ipmi.yml b/.github/workflows/pam-ipmi.yml index 22da7d6b63..78b162a3ce 100644 --- a/.github/workflows/pam-ipmi.yml +++ b/.github/workflows/pam-ipmi.yml @@ -18,7 +18,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -48,7 +48,7 @@ jobs: git_ref: [ e4b13e6725abb178f62ee897fe1c0e81b06a9431 ] name: ${{ matrix.git_ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: build_wolfssl steps: - name: Install dependencies diff --git a/.github/workflows/pq-all.yml b/.github/workflows/pq-all.yml index fc32344f6c..4aeaa5eb07 100644 --- a/.github/workflows/pq-all.yml +++ b/.github/workflows/pq-all.yml @@ -25,7 +25,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/psk.yml b/.github/workflows/psk.yml index 54ad8737f4..5026c4bdfc 100644 --- a/.github/workflows/psk.yml +++ b/.github/workflows/psk.yml @@ -24,7 +24,7 @@ jobs: ] name: make check if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/rng-tools.yml b/.github/workflows/rng-tools.yml index ea4b628406..0f124e9f44 100644 --- a/.github/workflows/rng-tools.yml +++ b/.github/workflows/rng-tools.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -47,7 +47,7 @@ jobs: ref: [ 6.16 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 needs: build_wolfssl diff --git a/.github/workflows/smallStackSize.yml b/.github/workflows/smallStackSize.yml index a31105fd1f..bd832026b4 100644 --- a/.github/workflows/smallStackSize.yml +++ b/.github/workflows/smallStackSize.yml @@ -37,7 +37,7 @@ jobs: ] name: build library if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/socat.yml b/.github/workflows/socat.yml index 91417e7a71..1484027ece 100644 --- a/.github/workflows/socat.yml +++ b/.github/workflows/socat.yml @@ -16,7 +16,7 @@ jobs: build_wolfssl: name: Build wolfSSL if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 4 steps: - name: Build wolfSSL @@ -39,7 +39,7 @@ jobs: socat_check: if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 30 needs: build_wolfssl diff --git a/.github/workflows/softhsm.yml b/.github/workflows/softhsm.yml index bb3824d174..593cd69135 100644 --- a/.github/workflows/softhsm.yml +++ b/.github/workflows/softhsm.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 10 steps: @@ -47,7 +47,7 @@ jobs: ref: [ 2.6.1 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 20 needs: build_wolfssl diff --git a/.github/workflows/sssd.yml b/.github/workflows/sssd.yml index 82024508ea..b160bf29d7 100644 --- a/.github/workflows/sssd.yml +++ b/.github/workflows/sssd.yml @@ -17,7 +17,7 @@ jobs: if: github.repository_owner == 'wolfssl' name: Build wolfSSL # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -47,7 +47,7 @@ jobs: ref: [ 2.9.1 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: quay.io/sssd/ci-client-devel:ubuntu-latest env: diff --git a/.github/workflows/stunnel.yml b/.github/workflows/stunnel.yml index 701a4e51b0..977ac3ee59 100644 --- a/.github/workflows/stunnel.yml +++ b/.github/workflows/stunnel.yml @@ -17,7 +17,7 @@ jobs: name: Build wolfSSL if: github.repository_owner == 'wolfssl' # Just to keep it the same as the testing target - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 steps: @@ -46,7 +46,7 @@ jobs: ref: [ 5.67 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 4 needs: build_wolfssl diff --git a/.github/workflows/symbol-prefixes.yml b/.github/workflows/symbol-prefixes.yml index 84a0e75e94..5073f8e938 100644 --- a/.github/workflows/symbol-prefixes.yml +++ b/.github/workflows/symbol-prefixes.yml @@ -21,7 +21,7 @@ jobs: ] name: make and analyze if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/threadx.yml b/.github/workflows/threadx.yml index f93cea9c11..4cd1be57bd 100644 --- a/.github/workflows/threadx.yml +++ b/.github/workflows/threadx.yml @@ -9,7 +9,7 @@ on: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: diff --git a/.github/workflows/wolfCrypt-Wconversion.yml b/.github/workflows/wolfCrypt-Wconversion.yml index 258902a4a0..b1a7305e4e 100644 --- a/.github/workflows/wolfCrypt-Wconversion.yml +++ b/.github/workflows/wolfCrypt-Wconversion.yml @@ -27,7 +27,7 @@ jobs: ] name: build library if: github.repository_owner == 'wolfssl' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 6 steps: diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index fb7f0d2b3d..df1b2e1cdd 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -42,7 +42,7 @@ jobs: make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 \ autoconf automake bison build-essential ca-certificates cargo ccache chrpath cmake \ cpio device-tree-compiler dfu-util diffstat dos2unix doxygen file flex g++ gawk gcc \ - gcovr git git-core gnupg gperf gtk-sharp2 help2man iproute2 lcov libcairo2-dev \ + gcovr git git-core gnupg gperf gtk-sharp3 help2man iproute2 lcov libcairo2-dev \ libglib2.0-dev libgtk2.0-0 liblocale-gettext-perl libncurses5-dev libpcap-dev \ libpopt0 libsdl1.2-dev libsdl2-dev libssl-dev libtool libtool-bin locales make \ net-tools ninja-build openssh-client parallel pkg-config python3-dev python3-pip \ From f52930b844e4ab69c83dbb34806e1139ff6c0ee8 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 21 Jan 2026 09:52:48 -0800 Subject: [PATCH 23/27] More fixes for NO RNG and NO check key (broken in #9606 and #9576) --- src/internal.c | 2 +- wolfcrypt/src/rsa.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/internal.c b/src/internal.c index af622bb8ce..3eb6d7f8ee 100644 --- a/src/internal.c +++ b/src/internal.c @@ -29812,7 +29812,7 @@ static int DecodePrivateKey_ex(WOLFSSL *ssl, byte keyType, const DerBuffer* key, } } -#ifdef WOLF_PRIVATE_KEY_ID +#if defined(WOLF_PRIVATE_KEY_ID) && !defined(NO_CHECK_PRIVATE_KEY) if (keyDevId != INVALID_DEVID && (keyIdSet || keyLabelSet)) { /* Set hsType */ if (keyType == rsa_sa_algo) diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 0d2e25afea..6767231c1b 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -3792,7 +3792,7 @@ int wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key) { WC_RNG* rng; int ret; -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) if (key == NULL) { return BAD_FUNC_ARG; } @@ -3816,7 +3816,7 @@ int wc_RsaPrivateDecryptInline_ex(byte* in, word32 inLen, byte** out, { WC_RNG* rng; int ret; -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) if (key == NULL) { return BAD_FUNC_ARG; } @@ -3839,7 +3839,7 @@ int wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, { WC_RNG* rng; int ret; -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) if (key == NULL) { return BAD_FUNC_ARG; } @@ -3863,7 +3863,7 @@ int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen, byte* out, { WC_RNG* rng; int ret; -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) if (key == NULL) { return BAD_FUNC_ARG; } @@ -3931,7 +3931,7 @@ int wc_RsaSSL_Verify_ex2(const byte* in, word32 inLen, byte* out, word32 outLen return BAD_FUNC_ARG; } -#ifdef WC_RSA_BLINDING +#if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) rng = key->rng; #else rng = NULL; From d3d2105035646474e1d8b0da0f1ae7560c5faddc Mon Sep 17 00:00:00 2001 From: Tesfa Mael Date: Mon, 19 Jan 2026 11:52:03 -0800 Subject: [PATCH 24/27] Fix cert SW issues --- wolfcrypt/src/aes.c | 10 ++++++++-- wolfcrypt/src/random.c | 8 +++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 5893f1da53..a1d09be4c2 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -4101,10 +4101,16 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt( int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv, int dir) { + if (aes == NULL || userKey == NULL) { + return BAD_FUNC_ARG; + } + if (keylen > sizeof(aes->key)) { + return BAD_FUNC_ARG; + } + return wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir, 1); } - int wc_AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen, const byte* iv, int dir) { @@ -5282,7 +5288,7 @@ int wc_AesSetIV(Aes* aes, const byte* iv) { int ret; - if (aes == NULL) + if (aes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; VECTOR_REGISTERS_PUSH; ret = wc_AesEncrypt(aes, in, out); diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 5934c14df5..cee2c212ba 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -752,12 +752,18 @@ int wc_RNG_TestSeed(const byte* seed, word32 seedSz) /* Check the seed for duplicate words. */ word32 seedIdx = 0; - word32 scratchSz = min(SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ); + word32 scratchSz = 0; + + if (seed == NULL || seedSz < sizeof(word32)) + return BAD_FUNC_ARG; + + scratchSz = min(SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ); while (seedIdx < seedSz - SEED_BLOCK_SZ) { if (ConstantCompare(seed + seedIdx, seed + seedIdx + scratchSz, (int)scratchSz) == 0) { + ret = DRBG_CONT_FAILURE; } seedIdx += SEED_BLOCK_SZ; From 1c3816d7d852b6b524dfa95d33f6141d7541afb4 Mon Sep 17 00:00:00 2001 From: Tesfa Mael Date: Tue, 20 Jan 2026 10:50:37 -0800 Subject: [PATCH 25/27] Use seedSz < SEED_BLOCK_SZ --- wolfcrypt/src/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index cee2c212ba..71acbc4b4c 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -754,7 +754,7 @@ int wc_RNG_TestSeed(const byte* seed, word32 seedSz) word32 seedIdx = 0; word32 scratchSz = 0; - if (seed == NULL || seedSz < sizeof(word32)) + if (seed == NULL || seedSz < SEED_BLOCK_SZ) return BAD_FUNC_ARG; scratchSz = min(SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ); From 7d7299e25499c8d2de171123060f3bca5c03f192 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Wed, 21 Jan 2026 17:49:30 -0500 Subject: [PATCH 26/27] Do not allow NULL with non-zero length. --- wolfcrypt/src/chacha20_poly1305.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 75f522e877..cadf7ff5b4 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -313,7 +313,8 @@ int wc_XChaCha20Poly1305_Init( byte authKey[CHACHA20_POLY1305_AEAD_KEYSIZE]; int ret; - if ((aead == NULL) || (nonce == NULL) || (key == NULL)) + if ((aead == NULL) || (ad == NULL && ad_len > 0) || (nonce == NULL) || + (key == NULL)) return BAD_FUNC_ARG; if ((key_len != CHACHA20_POLY1305_AEAD_KEYSIZE) || From 142f493964803bbea73083e93ccfc3761535c55d Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 21 Jan 2026 18:20:29 -0600 Subject: [PATCH 27/27] configure.ac: if ENABLED_32BIT, add -DWC_32BIT_CPU to AM_CFLAGS, and don't add WOLFSSL_X86_64_BUILD to AM_CFLAGS; fix handling for --enable-bump; wolfssl/wolfcrypt/settings.h: classify OPENSSL_EXTRA as "desktop type system" in bump up of default FP_MAX_BITS and SP_INT_BITS; wolfssl/wolfcrypt/types.h: if WC_32BIT_CPU, don't define WC_64BIT_CPU. --- configure.ac | 37 +++++++++++++++++++----------------- wolfssl/wolfcrypt/settings.h | 3 ++- wolfssl/wolfcrypt/types.h | 8 ++++++-- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 788b29a811..975bb0418b 100644 --- a/configure.ac +++ b/configure.ac @@ -314,6 +314,11 @@ AC_ARG_ENABLE([32bit], [ ENABLED_32BIT=no ] ) +if test "$ENABLED_32BIT" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWC_32BIT_CPU" +fi + # 16-bit compiler support AC_ARG_ENABLE([16bit], [AS_HELP_STRING([--enable-16bit],[Enables 16-bit support (default: disabled)])], @@ -941,9 +946,21 @@ AC_ARG_ENABLE([fasthugemath], [ ENABLED_FASTHUGEMATH=no ] ) +# ssl bump build +AC_ARG_ENABLE([bump], + [AS_HELP_STRING([--enable-bump],[Enable SSL Bump build (default: disabled)])], + [ ENABLED_BUMP=$enableval ], + [ ENABLED_BUMP=no ] + ) + if test "$ENABLED_BUMP" = "yes" then - ENABLED_FASTHUGEMATH="yes" + AM_CFLAGS="$AM_CFLAGS -DLARGE_STATIC_BUFFERS -DWOLFSSL_CERT_GEN -DWOLFSSL_KEY_GEN -DHUGE_SESSION_CACHE -DWOLFSSL_DER_LOAD -DWOLFSSL_ALT_NAMES -DWOLFSSL_TEST_CERT" + DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=4096 + if test "$ENABLED_SP_MATH" = "no" && test "$ENABLED_SP_MATH_ALL" = "no" + then + ENABLED_FASTHUGEMATH="yes" + fi fi if test "$ENABLED_FASTHUGEMATH" = "yes" @@ -951,7 +968,8 @@ then ENABLED_FASTMATH="yes" fi -if test "$host_cpu" = "x86_64" || test "$host_cpu" = "amd64" +if (test "$host_cpu" = "x86_64" || test "$host_cpu" = "amd64") && + test "$ENABLED_32BIT" != "yes" then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_X86_64_BUILD" fi @@ -2488,13 +2506,6 @@ AC_ARG_ENABLE([qt], [ ENABLED_QT=no ] ) -# ssl bump build -AC_ARG_ENABLE([bump], - [AS_HELP_STRING([--enable-bump],[Enable SSL Bump build (default: disabled)])], - [ ENABLED_BUMP=$enableval ], - [ ENABLED_BUMP=no ] - ) - # SNIFFER AC_ARG_ENABLE([sniffer], [AS_HELP_STRING([--enable-sniffer],[Enable wolfSSL sniffer support (default: disabled)])], @@ -2798,14 +2809,6 @@ then AM_CFLAGS="$AM_CFLAGS -DFORTRESS -DWOLFSSL_ALWAYS_VERIFY_CB -DWOLFSSL_AES_COUNTER -DWOLFSSL_AES_DIRECT -DWOLFSSL_DER_LOAD -DWOLFSSL_KEY_GEN" fi - -if test "$ENABLED_BUMP" = "yes" -then - AM_CFLAGS="$AM_CFLAGS -DLARGE_STATIC_BUFFERS -DWOLFSSL_CERT_GEN -DWOLFSSL_KEY_GEN -DHUGE_SESSION_CACHE -DWOLFSSL_DER_LOAD -DWOLFSSL_ALT_NAMES -DWOLFSSL_TEST_CERT" - DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=4096 -fi - - # lean TLS build (TLS 1.2 client only (no client auth), ECC256, AES128 and SHA256 w/o Shamir) AC_ARG_ENABLE([leantls], [AS_HELP_STRING([--enable-leantls],[Enable Lean TLS build (default: disabled)])], diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index a101047b01..58ae0c41a0 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3349,7 +3349,8 @@ extern void uITRON4_free(void *p) ; #endif /* if desktop type system and fastmath increase default max bits */ -#if defined(WOLFSSL_X86_64_BUILD) || defined(WOLFSSL_AARCH64_BUILD) +#if defined(WOLFSSL_X86_64_BUILD) || defined(WOLFSSL_AARCH64_BUILD) || \ + defined(OPENSSL_EXTRA) #if defined(USE_FAST_MATH) && !defined(FP_MAX_BITS) #if MIN_FFDHE_FP_MAX_BITS <= 8192 #define FP_MAX_BITS 8192 diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 756b27db27..2c048d44b4 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -307,8 +307,11 @@ typedef const char wcchar[]; #endif #if defined(WORD64_AVAILABLE) && !defined(WC_16BIT_CPU) - /* These platforms have 64-bit CPU registers. */ - #if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \ + #if defined(WC_64BIT_CPU) + /* explicitly configured for 64 bit. */ + #elif defined(WC_32BIT_CPU) + /* explicitly configured for 32 bit. */ + #elif (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \ (defined(__mips64) && \ ((defined(_ABI64) && (_MIPS_SIM == _ABI64)) || \ (defined(_ABIO64) && (_MIPS_SIM == _ABIO64)))) || \ @@ -317,6 +320,7 @@ typedef const char wcchar[]; (defined(__riscv_xlen) && (__riscv_xlen == 64)) || defined(_M_ARM64) || \ defined(__aarch64__) || defined(__ppc64__) || \ (defined(__DCC__) && (defined(__LP64) || defined(__LP64__))) + /* The above platforms have 64-bit CPU registers. */ #define WC_64BIT_CPU #elif (defined(sun) || defined(__sun)) && \ (defined(LP64) || defined(_LP64))