diff --git a/Cargo.toml b/Cargo.toml index ac5a2345..8b14fa72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ test = true bindgen = "0.71" [dependencies] -asn1 = "0.21" +asn1 = "0.22" bimap = "0.6.3" bitflags = "2.4.1" constant_time_eq = "0.3.0" diff --git a/src/kasn1/mod.rs b/src/kasn1/mod.rs index 889f6045..baf85381 100644 --- a/src/kasn1/mod.rs +++ b/src/kasn1/mod.rs @@ -111,6 +111,9 @@ impl<'a> asn1::SimpleAsn1Writable for DerEncBigUint<'a> { fn write_data(&self, dest: &mut asn1::WriteBuf) -> asn1::WriteResult { dest.push_slice(self.as_bytes()) } + fn data_length(&self) -> Option { + Some(self.data.len()) + } } /// Represents a ASN.1 OctetString wrapper @@ -164,6 +167,9 @@ impl<'a> asn1::SimpleAsn1Writable for DerEncOctetString<'a> { fn write_data(&self, dest: &mut asn1::WriteBuf) -> asn1::WriteResult { dest.push_slice(self.as_bytes()) } + fn data_length(&self) -> Option { + Some(self.data.len()) + } } /// This type is used in PrivateKeyInfo diff --git a/src/kasn1/oid.rs b/src/kasn1/oid.rs index 08d0a5f8..cdaea5f4 100644 --- a/src/kasn1/oid.rs +++ b/src/kasn1/oid.rs @@ -23,14 +23,3 @@ pub const KKDF1_OID: asn1::ObjectIdentifier = /// Kryoptic Key Based Protection Scheme v1 pub const KKBPS1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 4, 1, 2312, 20, 2, 1); - -// The SHA3 OIDs are wrong in pyca -// https://github.com/pyca/cryptography/issues/13331 -pub const SHA3_224_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 7); -pub const SHA3_256_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 8); -pub const SHA3_384_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 9); -pub const SHA3_512_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 10); diff --git a/src/kasn1/pyca/oid.rs b/src/kasn1/pyca/oid.rs index 2ee0628a..573cab6c 100644 --- a/src/kasn1/pyca/oid.rs +++ b/src/kasn1/pyca/oid.rs @@ -182,16 +182,24 @@ pub const SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 2); pub const SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 3); -// The SHA3 OIDs are wrong in pyca -- redefined in ../oids.rs -// https://github.com/pyca/cryptography/issues/13331 -//pub const SHA3_224_OID: asn1::ObjectIdentifier = -// asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 224); -//pub const SHA3_256_OID: asn1::ObjectIdentifier = -// asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 256); -//pub const SHA3_384_OID: asn1::ObjectIdentifier = -// asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 384); -//pub const SHA3_512_OID: asn1::ObjectIdentifier = -// asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 512); +pub const SHA3_224_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 224); +pub const SHA3_256_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 256); +pub const SHA3_384_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 384); +pub const SHA3_512_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 512); + +// NIST SHA3 OIDs (standard values) +pub const SHA3_224_NIST_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 7); +pub const SHA3_256_NIST_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 8); +pub const SHA3_384_NIST_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 9); +pub const SHA3_512_NIST_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 10); pub const MGF1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 8); @@ -220,12 +228,16 @@ pub const PBES2_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 5, 13); pub const PBKDF2_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 5, 12); +pub const PBE_WITH_MD5_AND_DES_CBC: asn1::ObjectIdentifier = + asn1::oid!(1, 2, 840, 113549, 1, 5, 3); pub const SCRYPT_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 4, 1, 11591, 4, 11); -pub const PBES1_WITH_SHA_AND_3KEY_TRIPLEDES_CBC: asn1::ObjectIdentifier = +pub const PBE_WITH_SHA_AND_128_BIT_RC4: asn1::ObjectIdentifier = + asn1::oid!(1, 2, 840, 113549, 1, 12, 1, 1); +pub const PBE_WITH_SHA_AND_3KEY_TRIPLEDES_CBC: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 12, 1, 3); -pub const PBES1_WITH_SHA_AND_40_BIT_RC2_CBC: asn1::ObjectIdentifier = +pub const PBE_WITH_SHA_AND_40_BIT_RC2_CBC: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 12, 1, 6); pub const AES_128_CBC_OID: asn1::ObjectIdentifier = diff --git a/src/kasn1/pyca/pkcs.rs b/src/kasn1/pyca/pkcs.rs index cb40d641..7ddd76be 100644 --- a/src/kasn1/pyca/pkcs.rs +++ b/src/kasn1/pyca/pkcs.rs @@ -7,7 +7,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use asn1::Asn1DefinedByWritable; +use asn1::{Asn1DefinedByWritable, SimpleAsn1Writable}; //use crate::oid; @@ -54,6 +54,14 @@ pub enum AlgorithmParameters<'a> { Sha3_384(Option), #[defined_by(oid::SHA3_512_OID)] Sha3_512(Option), + #[defined_by(oid::SHA3_224_NIST_OID)] + Sha3_224Nist(Option), + #[defined_by(oid::SHA3_256_NIST_OID)] + Sha3_256Nist(Option), + #[defined_by(oid::SHA3_384_NIST_OID)] + Sha3_384Nist(Option), + #[defined_by(oid::SHA3_512_NIST_OID)] + Sha3_512Nist(Option), #[defined_by(oid::ED25519_OID)] Ed25519, @@ -180,10 +188,14 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::RC2_CBC)] Rc2Cbc(Rc2CbcParams), - #[defined_by(oid::PBES1_WITH_SHA_AND_3KEY_TRIPLEDES_CBC)] - Pbes1WithShaAnd3KeyTripleDesCbc(PBES1Params), - #[defined_by(oid::PBES1_WITH_SHA_AND_40_BIT_RC2_CBC)] - Pbe1WithShaAnd40BitRc2Cbc(PBES1Params), + #[defined_by(oid::PBE_WITH_MD5_AND_DES_CBC)] + PbeWithMd5AndDesCbc(PbeParams), + #[defined_by(oid::PBE_WITH_SHA_AND_128_BIT_RC4)] + PbeWithShaAnd128BitRc4(Pkcs12PbeParams<'a>), + #[defined_by(oid::PBE_WITH_SHA_AND_3KEY_TRIPLEDES_CBC)] + PbeWithShaAnd3KeyTripleDesCbc(Pkcs12PbeParams<'a>), + #[defined_by(oid::PBE_WITH_SHA_AND_40_BIT_RC2_CBC)] + PbeWithShaAnd40BitRc2Cbc(Pkcs12PbeParams<'a>), #[default] Other(asn1::ObjectIdentifier, Option>), @@ -198,7 +210,28 @@ pub struct SubjectPublicKeyInfo<'a> { #[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone)] pub struct AttributeTypeValue<'a> { pub type_id: asn1::ObjectIdentifier, - pub value: RawTlv<'a>, + pub value: AttributeValue<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone)] +pub enum AttributeValue<'a> { + UniversalString(asn1::UniversalString<'a>), + BmpString(asn1::BMPString<'a>), + PrintableString(asn1::PrintableString<'a>), + + // Must be last, because enums parse things in order. + AnyString(RawTlv<'a>), +} + +impl AttributeValue<'_> { + pub fn tag(&self) -> asn1::Tag { + match self { + AttributeValue::AnyString(tlv) => tlv.tag(), + AttributeValue::PrintableString(_) => asn1::PrintableString::TAG, + AttributeValue::UniversalString(_) => asn1::UniversalString::TAG, + AttributeValue::BmpString(_) => asn1::BMPString::TAG, + } + } } // Like `asn1::Tlv` but doesn't store `full_data` so it can be constructed from @@ -233,7 +266,14 @@ impl<'a> asn1::Asn1Readable<'a> for RawTlv<'a> { } impl asn1::Asn1Writable for RawTlv<'_> { fn write(&self, w: &mut asn1::Writer<'_>) -> asn1::WriteResult { - w.write_tlv(self.tag, move |dest| dest.push_slice(self.value)) + w.write_tlv(self.tag, Some(self.value.len()), move |dest| { + dest.push_slice(self.value) + }) + } + + fn encoded_length(&self) -> Option { + // TODO: we're missing an API to make this easy. + None } } @@ -296,6 +336,13 @@ impl Asn1ReadableOrWritable::Write(v) => U::write_data(v, w), } } + + fn data_length(&self) -> Option { + match self { + Asn1ReadableOrWritable::Read(v) => T::data_length(v), + Asn1ReadableOrWritable::Write(v) => U::data_length(v), + } + } } pub trait Asn1Operation { @@ -543,14 +590,24 @@ pub struct ScryptParams<'a> { pub key_length: Option, } +// RFC 8018 Appendix A.3 #[derive( asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug, )] -pub struct PBES1Params { +pub struct PbeParams { pub salt: [u8; 8], pub iterations: u64, } +// From RFC 7202 Appendix C +#[derive( + asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug, +)] +pub struct Pkcs12PbeParams<'a> { + pub salt: &'a [u8], + pub iterations: u64, +} + #[derive( asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug, )] @@ -571,7 +628,8 @@ impl<'a> UnvalidatedVisibleString<'a> { } impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedVisibleString<'a> { - const TAG: asn1::Tag = asn1::VisibleString::TAG; + const TAG: asn1::Tag = + as asn1::SimpleAsn1Readable>::TAG; fn parse_data(data: &'a [u8]) -> asn1::ParseResult { Ok(UnvalidatedVisibleString( std::str::from_utf8(data).map_err(|_| { @@ -586,6 +644,10 @@ impl asn1::SimpleAsn1Writable for UnvalidatedVisibleString<'_> { fn write_data(&self, _: &mut asn1::WriteBuf) -> asn1::WriteResult { unimplemented!(); } + + fn data_length(&self) -> Option { + None + } } /// A BMPString ASN.1 element, where it is stored as a UTF-8 string in memory. @@ -605,6 +667,10 @@ impl asn1::SimpleAsn1Writable for Utf8StoredBMPString<'_> { } Ok(()) } + + fn data_length(&self) -> Option { + Some(self.0.encode_utf16().count() * 2) + } } #[derive(Clone)] @@ -645,6 +711,10 @@ impl asn1::Asn1Writable for WithTlv<'_, T> { fn write(&self, w: &mut asn1::Writer<'_>) -> asn1::WriteResult<()> { self.value.write(w) } + + fn encoded_length(&self) -> Option { + self.value.encoded_length() + } } impl PartialEq for WithTlv<'_, T> { diff --git a/src/ossl/mldsa.rs b/src/ossl/mldsa.rs index 62e0688a..d1c9c2c9 100644 --- a/src/ossl/mldsa.rs +++ b/src/ossl/mldsa.rs @@ -446,10 +446,10 @@ impl MlDsaOperation { CKM_SHA256 => SHA256_OID, CKM_SHA384 => SHA384_OID, CKM_SHA512 => SHA512_OID, - CKM_SHA3_224 => SHA3_224_OID, - CKM_SHA3_256 => SHA3_256_OID, - CKM_SHA3_384 => SHA3_384_OID, - CKM_SHA3_512 => SHA3_512_OID, + CKM_SHA3_224 => SHA3_224_NIST_OID, + CKM_SHA3_256 => SHA3_256_NIST_OID, + CKM_SHA3_384 => SHA3_384_NIST_OID, + CKM_SHA3_512 => SHA3_512_NIST_OID, /* TODO SHAKE hashes? */ _ => return Err(CKR_MECHANISM_PARAM_INVALID)?, }; diff --git a/src/ossl/slhdsa.rs b/src/ossl/slhdsa.rs index 75ce327a..bb07595c 100644 --- a/src/ossl/slhdsa.rs +++ b/src/ossl/slhdsa.rs @@ -466,10 +466,10 @@ impl SlhDsaOperation { CKM_SHA256 => SHA256_OID, CKM_SHA384 => SHA384_OID, CKM_SHA512 => SHA512_OID, - CKM_SHA3_224 => SHA3_224_OID, - CKM_SHA3_256 => SHA3_256_OID, - CKM_SHA3_384 => SHA3_384_OID, - CKM_SHA3_512 => SHA3_512_OID, + CKM_SHA3_224 => SHA3_224_NIST_OID, + CKM_SHA3_256 => SHA3_256_NIST_OID, + CKM_SHA3_384 => SHA3_384_NIST_OID, + CKM_SHA3_512 => SHA3_512_NIST_OID, /* TODO SHAKE hashes? */ _ => return Err(CKR_MECHANISM_PARAM_INVALID)?, };