1use crate::oids;
2use oid::ObjectIdentifier;
3use picky_asn1::tag::{Tag, TagPeeker};
4use picky_asn1::wrapper::{IntegerAsn1, ObjectIdentifierAsn1, OctetStringAsn1};
5use serde::{de, ser, Deserialize, Serialize};
6use std::error::Error;
7use std::fmt;
8
9#[derive(Debug)]
11pub struct UnsupportedAlgorithmError {
12 pub algorithm: String,
13}
14
15impl fmt::Display for UnsupportedAlgorithmError {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 write!(f, "unsupported algorithm: {}", self.algorithm)
18 }
19}
20
21impl Error for UnsupportedAlgorithmError {}
22
23#[derive(Debug, PartialEq, Clone)]
24pub struct AlgorithmIdentifier {
25 algorithm: ObjectIdentifierAsn1,
26 parameters: AlgorithmIdentifierParameters,
27}
28
29impl AlgorithmIdentifier {
30 pub fn oid(&self) -> &ObjectIdentifier {
31 &self.algorithm.0
32 }
33
34 pub fn parameters(&self) -> &AlgorithmIdentifierParameters {
35 &self.parameters
36 }
37
38 pub fn is_a(&self, algorithm: ObjectIdentifier) -> bool {
39 algorithm.eq(&self.algorithm.0)
40 }
41
42 pub fn new_sha1_with_rsa_encryption() -> Self {
43 Self {
44 algorithm: oids::sha1_with_rsa_encryption().into(),
45 parameters: AlgorithmIdentifierParameters::Null,
46 }
47 }
48
49 pub fn new_sha224_with_rsa_encryption() -> Self {
50 Self {
51 algorithm: oids::sha224_with_rsa_encryption().into(),
52 parameters: AlgorithmIdentifierParameters::Null,
53 }
54 }
55
56 pub fn new_sha256_with_rsa_encryption() -> Self {
57 Self {
58 algorithm: oids::sha256_with_rsa_encryption().into(),
59 parameters: AlgorithmIdentifierParameters::Null,
60 }
61 }
62
63 pub fn new_sha384_with_rsa_encryption() -> Self {
64 Self {
65 algorithm: oids::sha384_with_rsa_encryption().into(),
66 parameters: AlgorithmIdentifierParameters::Null,
67 }
68 }
69
70 pub fn new_sha512_with_rsa_encryption() -> Self {
71 Self {
72 algorithm: oids::sha512_with_rsa_encryption().into(),
73 parameters: AlgorithmIdentifierParameters::Null,
74 }
75 }
76
77 pub fn new_sha3_384_with_rsa_encryption() -> Self {
78 Self {
79 algorithm: oids::id_rsassa_pkcs1_v1_5_with_sha3_384().into(),
80 parameters: AlgorithmIdentifierParameters::Null,
81 }
82 }
83
84 pub fn new_sha3_512_with_rsa_encryption() -> Self {
85 Self {
86 algorithm: oids::id_rsassa_pkcs1_v1_5_with_sha3_512().into(),
87 parameters: AlgorithmIdentifierParameters::Null,
88 }
89 }
90
91 pub fn new_rsa_encryption() -> Self {
92 Self {
93 algorithm: oids::rsa_encryption().into(),
94 parameters: AlgorithmIdentifierParameters::Null,
95 }
96 }
97
98 pub fn new_rsa_encryption_with_sha(variant: ShaVariant) -> Result<Self, UnsupportedAlgorithmError> {
99 let algorithm = match variant {
100 ShaVariant::SHA2_224 => oids::sha224_with_rsa_encryption(),
101 ShaVariant::SHA2_256 => oids::sha256_with_rsa_encryption(),
102 ShaVariant::SHA2_384 => oids::sha384_with_rsa_encryption(),
103 ShaVariant::SHA2_512 => oids::sha512_with_rsa_encryption(),
104 ShaVariant::SHA3_384 => oids::id_rsassa_pkcs1_v1_5_with_sha3_384(),
105 ShaVariant::SHA3_512 => oids::id_rsassa_pkcs1_v1_5_with_sha3_512(),
106 _ => {
107 return Err(UnsupportedAlgorithmError {
108 algorithm: format!("{:?}", variant),
109 })
110 }
111 };
112
113 Ok(Self {
114 algorithm: algorithm.into(),
115 parameters: AlgorithmIdentifierParameters::Null,
116 })
117 }
118
119 pub fn new_ecdsa_with_sha384() -> Self {
120 Self {
121 algorithm: oids::ecdsa_with_sha384().into(),
122 parameters: AlgorithmIdentifierParameters::None,
123 }
124 }
125
126 pub fn new_ecdsa_with_sha256() -> Self {
127 Self {
128 algorithm: oids::ecdsa_with_sha256().into(),
129 parameters: AlgorithmIdentifierParameters::None,
130 }
131 }
132
133 pub fn new_elliptic_curve<P: Into<EcParameters>>(ec_params: P) -> Self {
134 Self {
135 algorithm: oids::ec_public_key().into(),
136 parameters: AlgorithmIdentifierParameters::Ec(ec_params.into()),
137 }
138 }
139
140 pub fn new_ed25519() -> Self {
141 Self {
142 algorithm: oids::ed25519().into(),
143 parameters: AlgorithmIdentifierParameters::None,
144 }
145 }
146
147 pub fn new_aes128(mode: AesMode, params: AesParameters) -> Self {
148 Self {
149 algorithm: mode.to_128bit_oid(),
150 parameters: AlgorithmIdentifierParameters::Aes(params),
151 }
152 }
153
154 pub fn new_aes192(mode: AesMode, params: AesParameters) -> Self {
155 Self {
156 algorithm: mode.to_192bit_oid(),
157 parameters: AlgorithmIdentifierParameters::Aes(params),
158 }
159 }
160
161 pub fn new_aes256(mode: AesMode, params: AesParameters) -> Self {
162 Self {
163 algorithm: mode.to_256bit_oid(),
164 parameters: AlgorithmIdentifierParameters::Aes(params),
165 }
166 }
167
168 pub fn new_sha(variant: ShaVariant) -> Self {
169 Self {
170 algorithm: variant.into(),
171 parameters: AlgorithmIdentifierParameters::Null,
172 }
173 }
174}
175
176impl ser::Serialize for AlgorithmIdentifier {
177 fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
178 where
179 S: ser::Serializer,
180 {
181 use ser::SerializeSeq;
182 let mut seq = serializer.serialize_seq(Some(2))?;
183 seq.serialize_element(&self.algorithm)?;
184 match &self.parameters {
185 AlgorithmIdentifierParameters::None => {}
186 AlgorithmIdentifierParameters::Null => {
187 seq.serialize_element(&())?;
188 }
189 AlgorithmIdentifierParameters::Ec(ec_params) => {
190 seq.serialize_element(ec_params)?;
191 }
192 AlgorithmIdentifierParameters::Aes(aes_params) => {
193 seq.serialize_element(aes_params)?;
194 }
195 }
196 seq.end()
197 }
198}
199
200impl<'de> de::Deserialize<'de> for AlgorithmIdentifier {
201 fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
202 where
203 D: de::Deserializer<'de>,
204 {
205 struct Visitor;
206
207 impl<'de> de::Visitor<'de> for Visitor {
208 type Value = AlgorithmIdentifier;
209
210 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
211 formatter.write_str("a valid DER-encoded algorithm identifier")
212 }
213
214 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
215 where
216 A: de::SeqAccess<'de>,
217 {
218 let oid: ObjectIdentifierAsn1 = seq_next_element!(seq, AlgorithmIdentifier, "algorithm oid");
219
220 let args = match Into::<String>::into(&oid.0).as_str() {
221 oids::RSA_ENCRYPTION
222 | oids::SHA1_WITH_RSA_ENCRYPTION
223 | oids::SHA224_WITH_RSA_ENCRYPTION
224 | oids::SHA256_WITH_RSA_ENCRYPTION
225 | oids::SHA384_WITH_RSA_ENCRYPTION
226 | oids::SHA512_WITH_RSA_ENCRYPTION => {
227 let _ = seq.next_element::<()>();
232 AlgorithmIdentifierParameters::Null
233 }
234 oids::ECDSA_WITH_SHA384 | oids::ECDSA_WITH_SHA256 | oids::ED25519 => {
235 AlgorithmIdentifierParameters::None
236 }
237 oids::EC_PUBLIC_KEY => AlgorithmIdentifierParameters::Ec(seq_next_element!(
238 seq,
239 AlgorithmIdentifier,
240 "elliptic curves parameters"
241 )),
242 x if x.starts_with("2.16.840.1.101.3.4.1.") => AlgorithmIdentifierParameters::Aes(
244 seq_next_element!(seq, AlgorithmIdentifier, "aes algorithm identifier"),
245 ),
246 x if x.starts_with("2.16.840.1.101.3.4.2.") => {
248 type Unit = ();
249 seq_next_element!(seq, Unit, AlgorithmIdentifier, "sha algorithm identifier");
250 AlgorithmIdentifierParameters::Null
251 }
252 _ => {
253 return Err(serde_invalid_value!(
254 AlgorithmIdentifier,
255 "unsupported algorithm (unknown oid)",
256 "a supported algorithm"
257 ));
258 }
259 };
260
261 Ok(AlgorithmIdentifier {
262 algorithm: oid,
263 parameters: args,
264 })
265 }
266 }
267
268 deserializer.deserialize_seq(Visitor)
269 }
270}
271
272#[derive(Debug, PartialEq, Clone)]
273pub enum AlgorithmIdentifierParameters {
274 None,
275 Null,
276 Aes(AesParameters),
277 Ec(EcParameters),
278}
279
280#[derive(Debug, PartialEq, Clone)]
281pub enum EcParameters {
282 NamedCurve(ObjectIdentifierAsn1),
283 }
287
288impl From<ObjectIdentifierAsn1> for EcParameters {
289 fn from(oid: ObjectIdentifierAsn1) -> Self {
290 Self::NamedCurve(oid)
291 }
292}
293
294impl From<ObjectIdentifier> for EcParameters {
295 fn from(oid: ObjectIdentifier) -> Self {
296 Self::NamedCurve(oid.into())
297 }
298}
299
300impl ser::Serialize for EcParameters {
301 fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
302 where
303 S: ser::Serializer,
304 {
305 match &self {
306 EcParameters::NamedCurve(oid) => oid.serialize(serializer),
307 }
308 }
309}
310
311impl<'de> de::Deserialize<'de> for EcParameters {
312 fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
313 where
314 D: de::Deserializer<'de>,
315 {
316 struct Visitor;
317
318 impl<'de> de::Visitor<'de> for Visitor {
319 type Value = EcParameters;
320
321 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
322 formatter.write_str("a valid DER-encoded DirectoryString")
323 }
324
325 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
326 where
327 A: de::SeqAccess<'de>,
328 {
329 let tag_peeker: TagPeeker = seq_next_element!(seq, EcParameters, "choice tag");
330 match tag_peeker.next_tag {
331 Tag::OID => Ok(EcParameters::NamedCurve(seq_next_element!(
332 seq,
333 EcParameters,
334 "Object Identifier"
335 ))),
336 _ => Err(serde_invalid_value!(
337 EcParameters,
338 "unsupported or unknown elliptic curve parameter",
339 "a supported elliptic curve parameter"
340 )),
341 }
342 }
343 }
344
345 deserializer.deserialize_enum("DirectoryString", &["NamedCurve", "ImplicitCurve"], Visitor)
346 }
347}
348
349#[derive(Clone, Copy, PartialEq, Debug)]
350pub enum AesMode {
351 Ecb,
352 Cbc,
353 Ofb,
354 Cfb,
355 Wrap,
356 Gcm,
357 Ccm,
358 WrapPad,
359}
360
361#[derive(Debug, PartialEq, Clone)]
362pub enum AesParameters {
363 Null,
364 InitializationVector(OctetStringAsn1),
365 AuthenticatedEncryptionParameters(AesAuthEncParams),
366}
367
368#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
369pub struct AesAuthEncParams {
370 nonce: OctetStringAsn1,
371 icv_len: IntegerAsn1,
372}
373
374impl AesMode {
375 fn to_128bit_oid(self) -> ObjectIdentifierAsn1 {
376 match self {
377 AesMode::Ecb => oids::aes128_ecb().into(),
378 AesMode::Cbc => oids::aes128_cbc().into(),
379 AesMode::Ofb => oids::aes128_ofb().into(),
380 AesMode::Cfb => oids::aes128_cfb().into(),
381 AesMode::Wrap => oids::aes128_wrap().into(),
382 AesMode::Gcm => oids::aes128_gcm().into(),
383 AesMode::Ccm => oids::aes128_ccm().into(),
384 AesMode::WrapPad => oids::aes128_wrap_pad().into(),
385 }
386 }
387
388 fn to_192bit_oid(self) -> ObjectIdentifierAsn1 {
389 match self {
390 AesMode::Ecb => oids::aes192_ecb().into(),
391 AesMode::Cbc => oids::aes192_cbc().into(),
392 AesMode::Ofb => oids::aes192_ofb().into(),
393 AesMode::Cfb => oids::aes192_cfb().into(),
394 AesMode::Wrap => oids::aes192_wrap().into(),
395 AesMode::Gcm => oids::aes192_gcm().into(),
396 AesMode::Ccm => oids::aes192_ccm().into(),
397 AesMode::WrapPad => oids::aes192_wrap_pad().into(),
398 }
399 }
400
401 fn to_256bit_oid(self) -> ObjectIdentifierAsn1 {
402 match self {
403 AesMode::Ecb => oids::aes256_ecb().into(),
404 AesMode::Cbc => oids::aes256_cbc().into(),
405 AesMode::Ofb => oids::aes256_ofb().into(),
406 AesMode::Cfb => oids::aes256_cfb().into(),
407 AesMode::Wrap => oids::aes256_wrap().into(),
408 AesMode::Gcm => oids::aes256_gcm().into(),
409 AesMode::Ccm => oids::aes256_ccm().into(),
410 AesMode::WrapPad => oids::aes256_wrap_pad().into(),
411 }
412 }
413}
414
415impl ser::Serialize for AesParameters {
416 fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
417 where
418 S: ser::Serializer,
419 {
420 match self {
421 AesParameters::Null => ().serialize(serializer),
422 AesParameters::InitializationVector(iv) => iv.serialize(serializer),
423 AesParameters::AuthenticatedEncryptionParameters(params) => params.serialize(serializer),
424 }
425 }
426}
427
428impl<'de> de::Deserialize<'de> for AesParameters {
429 fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
430 where
431 D: de::Deserializer<'de>,
432 {
433 struct Visitor;
434
435 impl<'de> de::Visitor<'de> for Visitor {
436 type Value = AesParameters;
437
438 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
439 formatter.write_str("a valid DER-encoded DirectoryString")
440 }
441
442 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
443 where
444 A: de::SeqAccess<'de>,
445 {
446 let tag_peeker: TagPeeker = seq_next_element!(seq, AesParameters, "choice tag");
447 match tag_peeker.next_tag {
448 Tag::OCTET_STRING => Ok(AesParameters::InitializationVector(seq_next_element!(
449 seq,
450 AesParameters,
451 "Object Identifier"
452 ))),
453 Tag::NULL => {
454 seq.next_element::<()>()?.expect("should not panic");
455 Ok(AesParameters::Null)
456 }
457 Tag::SEQUENCE => Ok(AesParameters::AuthenticatedEncryptionParameters(seq_next_element!(
458 seq,
459 AesAuthEncParams,
460 "AES Authenticated Encryption parameters"
461 ))),
462 _ => Err(serde_invalid_value!(
463 AesParameters,
464 "unsupported or unknown AES parameter",
465 "a supported AES parameter"
466 )),
467 }
468 }
469 }
470
471 deserializer.deserialize_enum(
472 "DirectoryString",
473 &["Null", "InitializationVector", "AuthenticatedEncryptionParameters"],
474 Visitor,
475 )
476 }
477}
478
479#[derive(Clone, Copy, PartialEq, Debug)]
480#[allow(non_camel_case_types)] pub enum ShaVariant {
482 SHA2_224,
483 SHA2_256,
484 SHA2_384,
485 SHA2_512,
486 SHA2_512_224,
487 SHA2_512_256,
488 SHA3_224,
489 SHA3_256,
490 SHA3_384,
491 SHA3_512,
492 SHAKE128,
493 SHAKE256,
494}
495
496impl From<ShaVariant> for ObjectIdentifierAsn1 {
497 fn from(variant: ShaVariant) -> Self {
498 match variant {
499 ShaVariant::SHA2_224 => oids::sha224().into(),
500 ShaVariant::SHA2_256 => oids::sha256().into(),
501 ShaVariant::SHA2_384 => oids::sha384().into(),
502 ShaVariant::SHA2_512 => oids::sha512().into(),
503 ShaVariant::SHA2_512_224 => oids::sha512_224().into(),
504 ShaVariant::SHA2_512_256 => oids::sha512_256().into(),
505 ShaVariant::SHA3_224 => oids::sha3_224().into(),
506 ShaVariant::SHA3_256 => oids::sha3_256().into(),
507 ShaVariant::SHA3_384 => oids::sha3_384().into(),
508 ShaVariant::SHA3_512 => oids::sha3_512().into(),
509 ShaVariant::SHAKE128 => oids::shake128().into(),
510 ShaVariant::SHAKE256 => oids::shake256().into(),
511 }
512 }
513}
514
515#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
529pub struct DigestInfo {
530 pub oid: AlgorithmIdentifier,
531 pub digest: OctetStringAsn1,
532}
533
534#[cfg(test)]
535mod tests {
536 use super::*;
537
538 #[test]
539 fn aes_null_params() {
540 let expected = [48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 1, 1, 5, 0];
541 let aes_id = AlgorithmIdentifier::new_aes128(AesMode::Ecb, AesParameters::Null);
542 check_serde!(aes_id: AlgorithmIdentifier in expected);
543 }
544
545 #[test]
546 fn aes_iv_params() {
547 let expected = [
548 48, 25, 6, 9, 96, 134, 72, 1, 101, 3, 4, 1, 1, 4, 12, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
549 165, 165,
550 ];
551 let aes_id =
552 AlgorithmIdentifier::new_aes128(AesMode::Ecb, AesParameters::InitializationVector(vec![0xA5; 12].into()));
553 check_serde!(aes_id: AlgorithmIdentifier in expected);
554 }
555
556 #[test]
557 fn aes_ae_params() {
558 let expected = [
559 48, 30, 6, 9, 96, 134, 72, 1, 101, 3, 4, 1, 1, 48, 17, 4, 12, 255, 255, 255, 255, 255, 255, 255, 255, 255,
560 255, 255, 255, 2, 1, 12,
561 ];
562 let aes_id = AlgorithmIdentifier::new_aes128(
563 AesMode::Ecb,
564 AesParameters::AuthenticatedEncryptionParameters(AesAuthEncParams {
565 nonce: vec![0xff; 12].into(),
566 icv_len: vec![12].into(),
567 }),
568 );
569 check_serde!(aes_id: AlgorithmIdentifier in expected);
570 }
571
572 #[test]
573 fn sha256() {
574 let expected = [48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0];
575 let sha = AlgorithmIdentifier::new_sha(ShaVariant::SHA2_256);
576 check_serde!(sha: AlgorithmIdentifier in expected);
577 }
578
579 #[test]
580 fn ec_params() {
581 let expected = [
582 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2,
583 ];
584 let ec_params =
585 AlgorithmIdentifier::new_elliptic_curve(EcParameters::NamedCurve(oids::ecdsa_with_sha256().into()));
586 check_serde!(ec_params: AlgorithmIdentifier in expected);
587 }
588
589 #[test]
590 fn digest_info() {
591 let digest = picky_asn1_der::to_vec(&DigestInfo {
592 oid: AlgorithmIdentifier::new_sha(ShaVariant::SHA2_256),
593 digest: vec![
595 0xf4, 0x12, 0x6b, 0x55, 0xbf, 0xcf, 0x8c, 0xc4, 0xe9, 0xe0, 0xbe, 0x5a, 0x9c, 0x16, 0x88, 0x55, 0x0f,
596 0x26, 0x00, 0x8c, 0x2c, 0xa5, 0xf6, 0xaf, 0xbd, 0xe7, 0x9c, 0x42, 0x22, 0xe9, 0x25, 0xed,
597 ]
598 .into(),
599 })
600 .unwrap();
601
602 let expected = vec![
603 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
604 0x20, 0xf4, 0x12, 0x6b, 0x55, 0xbf, 0xcf, 0x8c, 0xc4, 0xe9, 0xe0, 0xbe, 0x5a, 0x9c, 0x16, 0x88, 0x55, 0x0f,
605 0x26, 0x00, 0x8c, 0x2c, 0xa5, 0xf6, 0xaf, 0xbd, 0xe7, 0x9c, 0x42, 0x22, 0xe9, 0x25, 0xed,
606 ];
607
608 assert_eq!(digest, expected);
609 }
610
611 #[test]
612 fn rsa_encryption() {
613 let expected = [
614 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00,
615 ];
616 let rsa_encryption = AlgorithmIdentifier::new_rsa_encryption();
617 check_serde!(rsa_encryption: AlgorithmIdentifier in expected);
618 }
619
620 #[test]
621 fn rsa_encryption_with_missing_params() {
622 let encoded = [
623 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
624 ];
625 let deserialized: AlgorithmIdentifier =
626 picky_asn1_der::from_bytes(&encoded).expect("failed AlgorithmIdentifier deserialization");
627 pretty_assertions::assert_eq!(
628 deserialized,
629 AlgorithmIdentifier::new_rsa_encryption(),
630 concat!("deserialized ", stringify!($item), " doesn't match")
631 );
632 }
633}