From 88cdd872abed7238239060cf687254a5446c7fb3 Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Tue, 10 Feb 2026 07:44:59 -0800 Subject: [PATCH 1/2] symm: Add regression test for cipher NIDs --- boring/src/symm.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/boring/src/symm.rs b/boring/src/symm.rs index 1604b70bd..1c6cdbb01 100644 --- a/boring/src/symm.rs +++ b/boring/src/symm.rs @@ -1061,7 +1061,8 @@ mod tests { Cipher::des_cbc(), Cipher::rc4(), ] { - assert_eq!(Cipher::from_nid(cipher.nid()), Some(cipher)); + let name = cipher.nid().short_name().unwrap_or("unknown"); + assert_eq!(Cipher::from_nid(cipher.nid()), Some(cipher), "{}", name); } for cipher in [ @@ -1070,7 +1071,103 @@ mod tests { Cipher::aes_256_gcm(), Cipher::des_ede3(), ] { - assert_eq!(Cipher::from_nid(cipher.nid()), None); + let name = cipher.nid().short_name().unwrap_or("unknown"); + assert_eq!(Cipher::from_nid(cipher.nid()), None, "{}", name); + } + } + + // Make sure the NIDs don't actually change upstream. + #[test] + fn test_nid_regression() { + struct TestCase { + cipher: Cipher, + nid: c_int, + } + + for t in [ + TestCase { + cipher: Cipher::aes_128_ecb(), + nid: 418, + }, + TestCase { + cipher: Cipher::aes_128_cbc(), + nid: 419, + }, + TestCase { + cipher: Cipher::aes_128_ctr(), + nid: 904, + }, + TestCase { + cipher: Cipher::aes_128_gcm(), + nid: 895, + }, + TestCase { + cipher: Cipher::aes_128_ofb(), + nid: 420, + }, + TestCase { + cipher: Cipher::aes_192_ecb(), + nid: 422, + }, + TestCase { + cipher: Cipher::aes_192_cbc(), + nid: 423, + }, + TestCase { + cipher: Cipher::aes_192_ctr(), + nid: 905, + }, + TestCase { + cipher: Cipher::aes_192_gcm(), + nid: 898, + }, + TestCase { + cipher: Cipher::aes_192_ofb(), + nid: 424, + }, + TestCase { + cipher: Cipher::aes_256_ecb(), + nid: 426, + }, + TestCase { + cipher: Cipher::aes_256_cbc(), + nid: 427, + }, + TestCase { + cipher: Cipher::aes_256_ctr(), + nid: 906, + }, + TestCase { + cipher: Cipher::aes_256_gcm(), + nid: 901, + }, + TestCase { + cipher: Cipher::aes_256_ofb(), + nid: 428, + }, + TestCase { + cipher: Cipher::des_ecb(), + nid: 29, + }, + TestCase { + cipher: Cipher::des_ede3_cbc(), + nid: 44, + }, + TestCase { + cipher: Cipher::des_cbc(), + nid: 31, + }, + TestCase { + cipher: Cipher::rc4(), + nid: 5, + }, + TestCase { + cipher: Cipher::des_ede3(), + nid: 33, + }, + ] { + let name = t.cipher.nid().short_name().unwrap_or("unknown"); + assert_eq!(t.cipher.nid().as_raw(), t.nid, "{}", name); } } } From 0847d31b9f818dd8818e58a6f014614253a85be0 Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Tue, 10 Feb 2026 07:47:22 -0800 Subject: [PATCH 2/2] symm: Ensure `Cipher::from_nid()` handles GCM NIDs This method returns `None` for the GCM NIDs. It appears to be implemented incorrectly: It first calls `OBJ_nid2sn(nid)` to get the NID's short name, then calls `EVP_get_cipherbyname(name)`. The documentation isn't clear as to whether `name` should be the short or long name, but it appears to expect the long name. At least, changing to `OBJ_nid2sn()` to `OBJ_nid2ln()` makes the method work properly, To fix this, this commit calls `EVP_get_cipherbynid()`, which is is more direct. Note that the method still returns `None` on the 3DES NID, but we're not likely to encounter this one in practice. --- boring/src/symm.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/boring/src/symm.rs b/boring/src/symm.rs index 1c6cdbb01..7067b86b5 100644 --- a/boring/src/symm.rs +++ b/boring/src/symm.rs @@ -145,7 +145,7 @@ impl Cipher { #[corresponds(EVP_get_cipherbynid)] #[must_use] pub fn from_nid(nid: Nid) -> Option { - let ptr = unsafe { ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())) }; + let ptr = unsafe { ffi::EVP_get_cipherbynid(nid.as_raw()) }; if ptr.is_null() { None } else { @@ -1044,6 +1044,9 @@ mod tests { #[test] fn test_nid_roundtrip() { for cipher in [ + Cipher::aes_128_gcm(), + Cipher::aes_192_gcm(), + Cipher::aes_256_gcm(), Cipher::aes_128_ecb(), Cipher::aes_128_cbc(), Cipher::aes_128_ctr(), @@ -1065,15 +1068,7 @@ mod tests { assert_eq!(Cipher::from_nid(cipher.nid()), Some(cipher), "{}", name); } - for cipher in [ - Cipher::aes_128_gcm(), - Cipher::aes_192_gcm(), - Cipher::aes_256_gcm(), - Cipher::des_ede3(), - ] { - let name = cipher.nid().short_name().unwrap_or("unknown"); - assert_eq!(Cipher::from_nid(cipher.nid()), None, "{}", name); - } + assert_eq!(Cipher::from_nid(Cipher::des_ede3().nid()), None); } // Make sure the NIDs don't actually change upstream.