picky_asn1_x509/
attribute.rs1#[cfg(feature = "pkcs7")]
2use crate::pkcs7::content_info::SpcSpOpusInfo;
3use crate::{oids, Extension, Extensions};
4use picky_asn1::date::UTCTime;
5use picky_asn1::wrapper::{Asn1SequenceOf, Asn1SetOf, ObjectIdentifierAsn1, OctetStringAsn1, UtcTimeAsn1};
6use serde::{de, ser};
7
8pub type Attributes = Asn1SequenceOf<Attribute>;
9
10#[derive(Clone, Debug, PartialEq)]
19pub enum AttributeValues {
20 Extensions(Asn1SetOf<Extensions>), ContentType(Asn1SetOf<ObjectIdentifierAsn1>),
25 SpcStatementType(Asn1SetOf<Asn1SequenceOf<ObjectIdentifierAsn1>>),
26 MessageDigest(Asn1SetOf<OctetStringAsn1>),
27 SigningTime(Asn1SetOf<UtcTimeAsn1>),
28 #[cfg(feature = "pkcs7")]
29 SpcSpOpusInfo(Asn1SetOf<SpcSpOpusInfo>),
30 Custom(picky_asn1_der::Asn1RawDer), }
32
33#[derive(Clone, Debug, PartialEq)]
34pub struct Attribute {
35 pub ty: ObjectIdentifierAsn1,
36 pub value: AttributeValues,
37}
38
39impl Attribute {
40 pub fn new_extension_request(extensions: Vec<Extension>) -> Self {
41 Self {
42 ty: oids::extension_request().into(),
43 value: AttributeValues::Extensions(Asn1SetOf(vec![Extensions(extensions)])),
44 }
45 }
46
47 pub fn new_content_type_pkcs7() -> Self {
48 Self {
49 ty: oids::content_type().into(),
50 value: AttributeValues::ContentType(vec![oids::content_info_type_data().into()].into()),
51 }
52 }
53
54 pub fn new_signing_time(signing_time: UTCTime) -> Self {
55 Self {
56 ty: oids::signing_time().into(),
57 value: AttributeValues::SigningTime(vec![signing_time.into()].into()),
58 }
59 }
60
61 pub fn new_message_digest(digest: Vec<u8>) -> Self {
62 Self {
63 ty: oids::message_digest().into(),
64 value: AttributeValues::MessageDigest(vec![digest.into()].into()),
65 }
66 }
67}
68
69impl ser::Serialize for Attribute {
70 fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
71 where
72 S: ser::Serializer,
73 {
74 use ser::SerializeSeq;
75 let mut seq = serializer.serialize_seq(Some(2))?;
76 seq.serialize_element(&self.ty)?;
77 match &self.value {
78 AttributeValues::Extensions(extensions) => seq.serialize_element(extensions)?,
79 AttributeValues::Custom(der) => seq.serialize_element(der)?,
80 AttributeValues::ContentType(oid) => seq.serialize_element(oid)?,
81 AttributeValues::MessageDigest(octet_string) => seq.serialize_element(octet_string)?,
82 AttributeValues::SigningTime(signing_time) => seq.serialize_element(signing_time)?,
83 #[cfg(feature = "pkcs7")]
84 AttributeValues::SpcSpOpusInfo(spc_sp_opus_info) => seq.serialize_element(spc_sp_opus_info)?,
85 AttributeValues::SpcStatementType(spc_statement_type) => seq.serialize_element(spc_statement_type)?,
86 }
87 seq.end()
88 }
89}
90
91impl<'de> de::Deserialize<'de> for Attribute {
92 fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
93 where
94 D: de::Deserializer<'de>,
95 {
96 use std::fmt;
97
98 struct Visitor;
99
100 impl<'de> de::Visitor<'de> for Visitor {
101 type Value = Attribute;
102
103 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
104 formatter.write_str("a valid DER-encoded attribute")
105 }
106
107 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
108 where
109 A: de::SeqAccess<'de>,
110 {
111 let ty: ObjectIdentifierAsn1 = seq_next_element!(seq, Attribute, "type oid");
112
113 let value = match Into::<String>::into(&ty.0).as_str() {
114 oids::EXTENSION_REQ => {
115 AttributeValues::Extensions(seq_next_element!(seq, Attribute, "at extension request"))
116 }
117 oids::CONTENT_TYPE => {
118 AttributeValues::ContentType(seq_next_element!(seq, Attribute, "message digest oid"))
119 }
120 oids::MESSAGE_DIGEST => {
121 AttributeValues::MessageDigest(seq_next_element!(seq, Attribute, "an octet string"))
122 }
123 oids::SIGNING_TIME => AttributeValues::SigningTime(seq_next_element!(seq, Attribute, "UTCTime")),
124 #[cfg(feature = "pkcs7")]
125 oids::SPC_SP_OPUS_INFO_OBJID => {
126 AttributeValues::SpcSpOpusInfo(seq_next_element!(seq, Attribute, "an SpcSpOpusInfo object"))
127 }
128 oids::SPC_STATEMENT_TYPE => {
129 AttributeValues::SpcStatementType(seq_next_element!(seq, Attribute, "an SpcStatementType"))
130 }
131 _ => AttributeValues::Custom(seq_next_element!(seq, Attribute, "at custom value")),
132 };
133
134 Ok(Attribute { ty, value })
135 }
136 }
137
138 deserializer.deserialize_seq(Visitor)
139 }
140}