Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions support/crypto/src/hashes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub enum HashAlgorithm {
Sha256,
/// SHA-384
Sha384,
/// SHA-512
Sha512,
}

impl HashAlgorithm {
Expand All @@ -29,6 +31,7 @@ impl HashAlgorithm {
HashAlgorithm::Sha1 => symcrypt::hash::sha1(data).to_vec(),
HashAlgorithm::Sha256 => symcrypt::hash::sha256(data).to_vec(),
HashAlgorithm::Sha384 => symcrypt::hash::sha384(data).to_vec(),
HashAlgorithm::Sha512 => symcrypt::hash::sha512(data).to_vec(),
}
}

Expand All @@ -39,6 +42,7 @@ impl HashAlgorithm {
HashAlgorithm::Sha1 => sha1::Sha1::digest(data).to_vec(),
HashAlgorithm::Sha256 => sha2::Sha256::digest(data).to_vec(),
HashAlgorithm::Sha384 => sha2::Sha384::digest(data).to_vec(),
HashAlgorithm::Sha512 => sha2::Sha512::digest(data).to_vec(),
}
}

Expand Down Expand Up @@ -68,6 +72,7 @@ impl HashAlgorithm {
HashAlgorithm::Sha1 => BCRYPT_SHA1_ALG_HANDLE,
HashAlgorithm::Sha256 => BCRYPT_SHA256_ALG_HANDLE,
HashAlgorithm::Sha384 => BCRYPT_SHA384_ALG_HANDLE,
HashAlgorithm::Sha512 => BCRYPT_SHA512_ALG_HANDLE,
}
}

Expand All @@ -78,6 +83,7 @@ impl HashAlgorithm {
HashAlgorithm::Sha1 => BCRYPT_SHA1_ALGORITHM,
HashAlgorithm::Sha256 => BCRYPT_SHA256_ALGORITHM,
HashAlgorithm::Sha384 => BCRYPT_SHA384_ALGORITHM,
HashAlgorithm::Sha512 => BCRYPT_SHA512_ALGORITHM,
}
}

Expand All @@ -87,6 +93,38 @@ impl HashAlgorithm {
HashAlgorithm::Sha1 => 20,
HashAlgorithm::Sha256 => 32,
HashAlgorithm::Sha384 => 48,
HashAlgorithm::Sha512 => 64,
}
}

/// Returns the hash algorithm named by a CryptoAPI RSA signature
/// algorithm OID string (`szOID_RSA_*RSA`), or `None` if `oid` is null or
/// names an unsupported algorithm.
#[cfg(all(native, windows))]
pub(crate) fn from_rsa_signature_oid(oid: windows::core::PSTR) -> Option<Self> {
use windows::Win32::Security::Cryptography::szOID_RSA_SHA1RSA;
use windows::Win32::Security::Cryptography::szOID_RSA_SHA256RSA;
use windows::Win32::Security::Cryptography::szOID_RSA_SHA384RSA;
use windows::Win32::Security::Cryptography::szOID_RSA_SHA512RSA;

if oid.is_null() {
return None;
}
// SAFETY: ASN.1-decoded OID strings from crypt32 are null-terminated,
// as are the szOID_* constants.
unsafe {
let oid = oid.as_bytes();
if oid == szOID_RSA_SHA256RSA.as_bytes() {
Some(HashAlgorithm::Sha256)
} else if oid == szOID_RSA_SHA384RSA.as_bytes() {
Some(HashAlgorithm::Sha384)
} else if oid == szOID_RSA_SHA512RSA.as_bytes() {
Some(HashAlgorithm::Sha512)
} else if oid == szOID_RSA_SHA1RSA.as_bytes() {
Some(HashAlgorithm::Sha1)
} else {
None
}
}
}

Expand All @@ -102,13 +140,16 @@ impl HashAlgorithm {
static SHA256: crate::mac::CFStringRef;
#[link_name = "kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384"]
static SHA384: crate::mac::CFStringRef;
#[link_name = "kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512"]
static SHA512: crate::mac::CFStringRef;
}
// SAFETY: extern statics are always valid.
unsafe {
match self {
HashAlgorithm::Sha1 => SHA1,
HashAlgorithm::Sha256 => SHA256,
HashAlgorithm::Sha384 => SHA384,
HashAlgorithm::Sha512 => SHA512,
}
}
}
Expand All @@ -125,13 +166,16 @@ impl HashAlgorithm {
static SHA256: crate::mac::CFStringRef;
#[link_name = "kSecKeyAlgorithmRSASignatureMessagePSSSHA384"]
static SHA384: crate::mac::CFStringRef;
#[link_name = "kSecKeyAlgorithmRSASignatureMessagePSSSHA512"]
static SHA512: crate::mac::CFStringRef;
}
// SAFETY: extern statics are always valid.
unsafe {
match self {
HashAlgorithm::Sha1 => SHA1,
HashAlgorithm::Sha256 => SHA256,
HashAlgorithm::Sha384 => SHA384,
HashAlgorithm::Sha512 => SHA512,
}
}
}
Expand All @@ -148,13 +192,16 @@ impl HashAlgorithm {
static SHA256: crate::mac::CFStringRef;
#[link_name = "kSecKeyAlgorithmRSAEncryptionOAEPSHA384"]
static SHA384: crate::mac::CFStringRef;
#[link_name = "kSecKeyAlgorithmRSAEncryptionOAEPSHA512"]
static SHA512: crate::mac::CFStringRef;
}
// SAFETY: extern statics are always valid.
unsafe {
match self {
HashAlgorithm::Sha1 => SHA1,
HashAlgorithm::Sha256 => SHA256,
HashAlgorithm::Sha384 => SHA384,
HashAlgorithm::Sha512 => SHA512,
}
Comment thread
smalis-msft marked this conversation as resolved.
}
}
Expand All @@ -168,6 +215,7 @@ impl TryFrom<der::asn1::ObjectIdentifier> for HashAlgorithm {
match oid {
der::oid::db::rfc5912::SHA_256_WITH_RSA_ENCRYPTION => Ok(Self::Sha256),
der::oid::db::rfc5912::SHA_384_WITH_RSA_ENCRYPTION => Ok(Self::Sha384),
der::oid::db::rfc5912::SHA_512_WITH_RSA_ENCRYPTION => Ok(Self::Sha512),
der::oid::db::rfc5912::SHA_1_WITH_RSA_ENCRYPTION => Ok(Self::Sha1),
_ => Err(der::ErrorKind::OidUnknown { oid }.to_error()),
}
Expand All @@ -181,6 +229,7 @@ impl From<HashAlgorithm> for openssl::hash::MessageDigest {
HashAlgorithm::Sha1 => openssl::hash::MessageDigest::sha1(),
HashAlgorithm::Sha256 => openssl::hash::MessageDigest::sha256(),
HashAlgorithm::Sha384 => openssl::hash::MessageDigest::sha384(),
HashAlgorithm::Sha512 => openssl::hash::MessageDigest::sha512(),
}
}
}
Expand All @@ -192,6 +241,7 @@ impl From<HashAlgorithm> for &'static openssl::md::MdRef {
HashAlgorithm::Sha1 => openssl::md::Md::sha1(),
HashAlgorithm::Sha256 => openssl::md::Md::sha256(),
HashAlgorithm::Sha384 => openssl::md::Md::sha384(),
HashAlgorithm::Sha512 => openssl::md::Md::sha512(),
}
}
}
Expand All @@ -203,6 +253,7 @@ impl From<HashAlgorithm> for symcrypt::hash::HashAlgorithm {
HashAlgorithm::Sha1 => symcrypt::hash::HashAlgorithm::Sha1,
HashAlgorithm::Sha256 => symcrypt::hash::HashAlgorithm::Sha256,
HashAlgorithm::Sha384 => symcrypt::hash::HashAlgorithm::Sha384,
HashAlgorithm::Sha512 => symcrypt::hash::HashAlgorithm::Sha512,
}
}
}
9 changes: 7 additions & 2 deletions support/crypto/src/rsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,18 @@ mod tests {
assert!(valid);
}

/// OAEP encrypt/decrypt round-trip with both supported hash algorithms.
/// OAEP encrypt/decrypt round-trip with every supported hash algorithm.
#[test]
#[expect(deprecated)]
fn oaep_roundtrip() {
let key = RsaKeyPair::generate(2048).unwrap();
Comment thread
smalis-msft marked this conversation as resolved.
let payload = b"a secret message";
for alg in [HashAlgorithm::Sha1, HashAlgorithm::Sha256] {
for alg in [
HashAlgorithm::Sha1,
HashAlgorithm::Sha256,
HashAlgorithm::Sha384,
HashAlgorithm::Sha512,
] {
let ct = key.oaep_encrypt(payload, alg).unwrap();
let pt = key.oaep_decrypt(&ct, alg).unwrap();
assert_eq!(pt, payload);
Expand Down
20 changes: 20 additions & 0 deletions support/crypto/src/rsa/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ impl RsaKeyPairInner {
self.0
.decrypt_blinded(&mut rng(), Oaep::<sha2::Sha384>::new(), input)
}
HashAlgorithm::Sha512 => {
self.0
.decrypt_blinded(&mut rng(), Oaep::<sha2::Sha512>::new(), input)
}
}
.map_err(|e| RsaError(e, "OAEP decryption"))
}
Expand All @@ -94,6 +98,10 @@ impl RsaKeyPairInner {
self.0
.sign_with_rng(&mut rng(), Pkcs1v15Sign::new::<sha2::Sha384>(), &data)
}
HashAlgorithm::Sha512 => {
self.0
.sign_with_rng(&mut rng(), Pkcs1v15Sign::new::<sha2::Sha512>(), &data)
}
}
.map_err(|e| RsaError(e, "PKCS#1 signing"))
}
Expand Down Expand Up @@ -121,6 +129,10 @@ impl RsaKeyPairInner {
self.0
.sign_with_rng(&mut rng(), Pss::<sha2::Sha384>::new(), &data)
}
HashAlgorithm::Sha512 => {
self.0
.sign_with_rng(&mut rng(), Pss::<sha2::Sha512>::new(), &data)
}
}
.map_err(|e| RsaError(e, "PSS signing"))
}
Expand Down Expand Up @@ -157,6 +169,9 @@ impl RsaPublicKeyInner {
HashAlgorithm::Sha384 => self
.0
.encrypt(&mut rng(), Oaep::<sha2::Sha384>::new(), input),
HashAlgorithm::Sha512 => self
.0
.encrypt(&mut rng(), Oaep::<sha2::Sha512>::new(), input),
}
.map_err(|e| RsaError(e, "OAEP encryption"))
}
Expand Down Expand Up @@ -184,6 +199,10 @@ impl RsaPublicKeyInner {
self.0
.verify(Pkcs1v15Sign::new::<sha2::Sha384>(), &data, signature)
}
HashAlgorithm::Sha512 => {
self.0
.verify(Pkcs1v15Sign::new::<sha2::Sha512>(), &data, signature)
}
};
match result {
Ok(()) => Ok(true),
Expand All @@ -207,6 +226,7 @@ impl RsaPublicKeyInner {
HashAlgorithm::Sha1 => self.0.verify(Pss::<sha1::Sha1>::new(), &data, signature),
HashAlgorithm::Sha256 => self.0.verify(Pss::<sha2::Sha256>::new(), &data, signature),
HashAlgorithm::Sha384 => self.0.verify(Pss::<sha2::Sha384>::new(), &data, signature),
HashAlgorithm::Sha512 => self.0.verify(Pss::<sha2::Sha512>::new(), &data, signature),
};
match result {
Ok(()) => Ok(true),
Expand Down
46 changes: 11 additions & 35 deletions support/crypto/src/x509/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use windows::Win32::Security::Cryptography::szOID_COMMON_NAME;
use windows::Win32::Security::Cryptography::szOID_ECC_PUBLIC_KEY;
use windows::Win32::Security::Cryptography::szOID_KEY_USAGE;
use windows::Win32::Security::Cryptography::szOID_RSA_RSA;
#[cfg(any(test, feature = "test_helpers"))]
use windows::Win32::Security::Cryptography::szOID_RSA_SHA256RSA;
use windows::Win32::Security::Cryptography::szOID_SUBJECT_KEY_IDENTIFIER;
use windows::core::PCSTR;
Expand Down Expand Up @@ -179,41 +180,16 @@ impl X509CertificateInner {
.map_err(|e| crate::rsa::RsaError(backend_err(e)))?;

// Hash algorithm from the signature algorithm OID.
let oid = signed.value.SignatureAlgorithm.pszObjId;
if oid.is_null() {
return Err(rsa_err(
windows_result::Error::from_hresult(windows::core::HRESULT(
windows::Win32::Foundation::E_NOTIMPL.0,
)),
"missing signature algorithm OID",
));
}
// SAFETY: ASN.1-decoded OID strings from crypt32 are null-terminated,
// as are the szOID_* constants.
let hash = unsafe {
let oid_bytes = oid.as_bytes();
if oid_bytes == szOID_RSA_SHA256RSA.as_bytes() {
crate::HashAlgorithm::Sha256
} else if oid_bytes
== windows::Win32::Security::Cryptography::szOID_RSA_SHA384RSA.as_bytes()
{
crate::HashAlgorithm::Sha384
} else if oid_bytes
== windows::Win32::Security::Cryptography::szOID_RSA_SHA1RSA.as_bytes()
{
#[expect(deprecated)]
{
crate::HashAlgorithm::Sha1
}
} else {
return Err(rsa_err(
windows_result::Error::from_hresult(windows::core::HRESULT(
windows::Win32::Foundation::E_NOTIMPL.0,
)),
"unsupported signature algorithm OID",
));
}
};
let hash =
crate::HashAlgorithm::from_rsa_signature_oid(signed.value.SignatureAlgorithm.pszObjId)
.ok_or_else(|| {
rsa_err(
windows_result::Error::from_hresult(windows::core::HRESULT(
windows::Win32::Foundation::E_NOTIMPL.0,
)),
"missing or unsupported signature algorithm OID",
)
})?;

let tbs = blob_as_slice(&signed.value.ToBeSigned).ok_or_else(|| {
rsa_err(
Expand Down
Loading