c2pa-rs

A fork of https://github.com/contentauth/c2pa-rs/
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/c2pa-rs.git
Log | Files | Refs | README

rfc3161.rs (16202B)


      1 // This Source Code Form is subject to the terms of the Mozilla Public
      2 // License, v. 2.0. If a copy of the MPL was not distributed with this
      3 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
      4 
      5 //! ASN.1 types defined by RFC 3161.
      6 
      7 use bcder::{
      8     decode::{Constructed, DecodeError, Primitive, Source},
      9     encode::{self, PrimitiveContent, Values},
     10     ConstOid, Integer, OctetString, Oid, Tag,
     11 };
     12 use x509_certificate::{
     13     asn1time::GeneralizedTime,
     14     rfc3280::GeneralName,
     15     rfc5280::{AlgorithmIdentifier, Extensions},
     16 };
     17 
     18 use crate::asn1::{rfc4210::PkiFreeText, rfc5652::ContentInfo};
     19 
     20 /// Content-Type for Time-Stamp Token Info.
     21 ///
     22 /// 1.2.840.113549.1.9.16.1.4
     23 pub const OID_CONTENT_TYPE_TST_INFO: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 16, 1, 4]);
     24 
     25 /// id-aa-timeStampToken
     26 ///
     27 /// 1.2.840.113549.1.9.16.2.14
     28 pub const OID_TIME_STAMP_TOKEN: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 16, 2, 14]);
     29 
     30 /// A time-stamp request.
     31 ///
     32 /// ```ASN.1
     33 /// TimeStampReq ::= SEQUENCE  {
     34 ///    version                  INTEGER  { v1(1) },
     35 ///    messageImprint           MessageImprint,
     36 ///      --a hash algorithm OID and the hash value of the data to be
     37 ///      --time-stamped
     38 ///    reqPolicy                TSAPolicyId                OPTIONAL,
     39 ///    nonce                    INTEGER                    OPTIONAL,
     40 ///    certReq                  BOOLEAN                    DEFAULT FALSE,
     41 ///    extensions               [0] IMPLICIT Extensions    OPTIONAL  }
     42 /// ```
     43 #[derive(Clone, Debug, Eq, PartialEq)]
     44 pub struct TimeStampReq {
     45     pub version: Integer,
     46     pub message_imprint: MessageImprint,
     47     pub req_policy: Option<TsaPolicyId>,
     48     pub nonce: Option<Integer>,
     49     pub cert_req: Option<bool>,
     50     pub extensions: Option<Extensions>,
     51 }
     52 
     53 impl TimeStampReq {
     54     pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
     55         cons.take_sequence(|cons| {
     56             let version = Integer::take_from(cons)?;
     57             let message_imprint = MessageImprint::take_from(cons)?;
     58             let req_policy = TsaPolicyId::take_opt_from(cons)?;
     59             let nonce =
     60                 cons.take_opt_primitive_if(Tag::INTEGER, |prim| Integer::from_primitive(prim))?;
     61             let cert_req = cons.take_opt_bool()?;
     62             let extensions =
     63                 cons.take_opt_constructed_if(Tag::CTX_0, |cons| Extensions::take_from(cons))?;
     64 
     65             Ok(Self {
     66                 version,
     67                 message_imprint,
     68                 req_policy,
     69                 nonce,
     70                 cert_req,
     71                 extensions,
     72             })
     73         })
     74     }
     75 
     76     pub fn encode_ref(&self) -> impl Values + '_ {
     77         encode::sequence((
     78             (&self.version).encode(),
     79             self.message_imprint.encode_ref(),
     80             self.req_policy
     81                 .as_ref()
     82                 .map(|req_policy| req_policy.encode_ref()),
     83             self.nonce.as_ref().map(|nonce| nonce.encode()),
     84             self.cert_req.as_ref().map(|cert_req| cert_req.encode_ref()),
     85             self.extensions
     86                 .as_ref()
     87                 .map(|extensions| extensions.encode_ref_as(Tag::CTX_0)),
     88         ))
     89     }
     90 }
     91 
     92 /// Message imprint.
     93 ///
     94 /// ```ASN.1
     95 /// MessageImprint ::= SEQUENCE  {
     96 ///      hashAlgorithm                AlgorithmIdentifier,
     97 ///      hashedMessage                OCTET STRING  }
     98 /// ```
     99 #[derive(Clone, Debug, Eq, PartialEq)]
    100 pub struct MessageImprint {
    101     pub hash_algorithm: AlgorithmIdentifier,
    102     pub hashed_message: OctetString,
    103 }
    104 
    105 impl MessageImprint {
    106     pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
    107         cons.take_sequence(|cons| {
    108             let hash_algorithm = AlgorithmIdentifier::take_from(cons)?;
    109             let hashed_message = OctetString::take_from(cons)?;
    110 
    111             Ok(Self {
    112                 hash_algorithm,
    113                 hashed_message,
    114             })
    115         })
    116     }
    117 
    118     pub fn encode_ref(&self) -> impl Values + '_ {
    119         encode::sequence((&self.hash_algorithm, self.hashed_message.encode_ref()))
    120     }
    121 }
    122 
    123 pub type TsaPolicyId = Oid;
    124 
    125 /// Time stamp response.
    126 ///
    127 /// ```ASN.1
    128 /// TimeStampResp ::= SEQUENCE  {
    129 ///      status                  PKIStatusInfo,
    130 ///      timeStampToken          TimeStampToken     OPTIONAL  }
    131 /// ```
    132 #[derive(Clone, Debug, Eq, PartialEq)]
    133 pub struct TimeStampResp {
    134     pub status: PkiStatusInfo,
    135     pub time_stamp_token: Option<TimeStampToken>,
    136 }
    137 
    138 impl TimeStampResp {
    139     pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
    140         cons.take_sequence(|cons| {
    141             let status = PkiStatusInfo::take_from(cons)?;
    142             let time_stamp_token = TimeStampToken::take_opt_from(cons)?;
    143 
    144             Ok(Self {
    145                 status,
    146                 time_stamp_token,
    147             })
    148         })
    149     }
    150 
    151     pub fn encode_ref(&self) -> impl Values + '_ {
    152         encode::sequence((
    153             self.status.encode_ref(),
    154             if let Some(time_stamp_token) = &self.time_stamp_token {
    155                 Some(time_stamp_token)
    156             } else {
    157                 None
    158             },
    159         ))
    160     }
    161 }
    162 
    163 /// PKI status info
    164 ///
    165 /// ```ASN.1
    166 /// PKIStatusInfo ::= SEQUENCE {
    167 ///     status        PKIStatus,
    168 ///     statusString  PKIFreeText     OPTIONAL,
    169 ///     failInfo      PKIFailureInfo  OPTIONAL  }
    170 /// ```
    171 #[derive(Clone, Debug, Eq, PartialEq)]
    172 pub struct PkiStatusInfo {
    173     pub status: PkiStatus,
    174     pub status_string: Option<PkiFreeText>,
    175     pub fail_info: Option<PkiFailureInfo>,
    176 }
    177 
    178 impl PkiStatusInfo {
    179     pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
    180         cons.take_sequence(|cons| {
    181             let status = PkiStatus::take_from(cons)?;
    182             let status_string = PkiFreeText::take_opt_from(cons)?;
    183             let fail_info = PkiFailureInfo::take_opt_from(cons)?;
    184 
    185             Ok(Self {
    186                 status,
    187                 status_string,
    188                 fail_info,
    189             })
    190         })
    191     }
    192 
    193     pub fn encode_ref(&self) -> impl Values + '_ {
    194         encode::sequence((
    195             self.status.encode(),
    196             self.status_string
    197                 .as_ref()
    198                 .map(|status_string| status_string.encode_ref()),
    199             self.fail_info.as_ref().map(|fail_info| fail_info.encode()),
    200         ))
    201     }
    202 }
    203 
    204 /// PKI status.
    205 ///
    206 /// ```ASN.1
    207 /// PKIStatus ::= INTEGER {
    208 ///     granted                (0),
    209 ///     -- when the PKIStatus contains the value zero a TimeStampToken, as
    210 ///        requested, is present.
    211 ///     grantedWithMods        (1),
    212 ///      -- when the PKIStatus contains the value one a TimeStampToken,
    213 ///        with modifications, is present.
    214 ///     rejection              (2),
    215 ///     waiting                (3),
    216 ///     revocationWarning      (4),
    217 ///      -- this message contains a warning that a revocation is
    218 ///      -- imminent
    219 ///     revocationNotification (5)
    220 ///      -- notification that a revocation has occurred   }
    221 ///
    222 ///     -- When the TimeStampToken is not present
    223 ///     -- failInfo indicates the reason why the
    224 ///     -- time-stamp request was rejected and
    225 ///     -- may be one of the following values.
    226 /// ```
    227 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    228 pub enum PkiStatus {
    229     Granted = 0,
    230     GrantedWithMods = 1,
    231     Rejection = 2,
    232     Waiting = 3,
    233     RevocationWarning = 4,
    234     RevocationNotification = 5,
    235 }
    236 
    237 impl PkiStatus {
    238     pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
    239         match cons.take_primitive_if(Tag::INTEGER, Integer::i8_from_primitive)? {
    240             0 => Ok(Self::Granted),
    241             1 => Ok(Self::GrantedWithMods),
    242             2 => Ok(Self::Rejection),
    243             3 => Ok(Self::Waiting),
    244             4 => Ok(Self::RevocationWarning),
    245             5 => Ok(Self::RevocationNotification),
    246             _ => Err(cons.content_err("unknown PKIStatus value")),
    247         }
    248     }
    249 
    250     pub fn encode(self) -> impl Values {
    251         u8::from(self).encode()
    252     }
    253 }
    254 
    255 impl From<PkiStatus> for u8 {
    256     fn from(v: PkiStatus) -> u8 {
    257         match v {
    258             PkiStatus::Granted => 0,
    259             PkiStatus::GrantedWithMods => 1,
    260             PkiStatus::Rejection => 2,
    261             PkiStatus::Waiting => 3,
    262             PkiStatus::RevocationWarning => 4,
    263             PkiStatus::RevocationNotification => 5,
    264         }
    265     }
    266 }
    267 
    268 /// PKI failure info.
    269 ///
    270 /// ```ASN.1
    271 /// PKIFailureInfo ::= BIT STRING {
    272 ///     badAlg               (0),
    273 ///       -- unrecognized or unsupported Algorithm Identifier
    274 ///     badRequest           (2),
    275 ///       -- transaction not permitted or supported
    276 ///     badDataFormat        (5),
    277 ///       -- the data submitted has the wrong format
    278 ///     timeNotAvailable    (14),
    279 ///       -- the TSA's time source is not available
    280 ///     unacceptedPolicy    (15),
    281 ///       -- the requested TSA policy is not supported by the TSA.
    282 ///     unacceptedExtension (16),
    283 ///       -- the requested extension is not supported by the TSA.
    284 ///     addInfoNotAvailable (17)
    285 ///       -- the additional information requested could not be understood
    286 ///       -- or is not available
    287 ///     systemFailure       (25)
    288 ///       -- the request cannot be handled due to system failure  }
    289 /// ```
    290 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    291 pub enum PkiFailureInfo {
    292     BadAlg = 0,
    293     BadRequest = 1,
    294     BadDataFormat = 5,
    295     TimeNotAvailable = 14,
    296     UnacceptedPolicy = 15,
    297     UnacceptedExtension = 16,
    298     AddInfoNotAvailable = 17,
    299     SystemFailure = 25,
    300 }
    301 
    302 impl PkiFailureInfo {
    303     pub fn take_opt_from<S: Source>(
    304         cons: &mut Constructed<S>,
    305     ) -> Result<Option<Self>, DecodeError<S::Error>> {
    306         cons.take_opt_primitive_if(Tag::INTEGER, Self::from_primitive)
    307     }
    308 
    309     pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
    310         cons.take_primitive_if(Tag::INTEGER, Self::from_primitive)
    311     }
    312 
    313     pub fn from_primitive<S: Source>(
    314         prim: &mut Primitive<S>,
    315     ) -> Result<Self, DecodeError<S::Error>> {
    316         match Integer::i8_from_primitive(prim)? {
    317             0 => Ok(Self::BadAlg),
    318             1 => Ok(Self::BadRequest),
    319             5 => Ok(Self::BadDataFormat),
    320             14 => Ok(Self::TimeNotAvailable),
    321             15 => Ok(Self::UnacceptedPolicy),
    322             16 => Ok(Self::UnacceptedExtension),
    323             17 => Ok(Self::AddInfoNotAvailable),
    324             25 => Ok(Self::SystemFailure),
    325             _ => Err(prim.content_err("Unknown PKIFailureInfo value")),
    326         }
    327     }
    328 
    329     pub fn encode(self) -> impl Values {
    330         u8::from(self).encode()
    331     }
    332 }
    333 
    334 impl From<PkiFailureInfo> for u8 {
    335     fn from(v: PkiFailureInfo) -> u8 {
    336         match v {
    337             PkiFailureInfo::BadAlg => 0,
    338             PkiFailureInfo::BadRequest => 1,
    339             PkiFailureInfo::BadDataFormat => 5,
    340             PkiFailureInfo::TimeNotAvailable => 14,
    341             PkiFailureInfo::UnacceptedPolicy => 15,
    342             PkiFailureInfo::UnacceptedExtension => 16,
    343             PkiFailureInfo::AddInfoNotAvailable => 17,
    344             PkiFailureInfo::SystemFailure => 25,
    345         }
    346     }
    347 }
    348 
    349 /// Time stamp token.
    350 ///
    351 /// ```ASN.1
    352 /// TimeStampToken ::= ContentInfo
    353 /// ```
    354 pub type TimeStampToken = ContentInfo;
    355 
    356 /// Time stamp token info.
    357 ///
    358 /// ```ASN.1
    359 /// TSTInfo ::= SEQUENCE  {
    360 ///     version                      INTEGER  { v1(1) },
    361 ///     policy                       TSAPolicyId,
    362 ///     messageImprint               MessageImprint,
    363 ///       -- MUST have the same value as the similar field in
    364 ///       -- TimeStampReq
    365 ///     serialNumber                 INTEGER,
    366 ///      -- Time-Stamping users MUST be ready to accommodate integers
    367 ///      -- up to 160 bits.
    368 ///     genTime                      GeneralizedTime,
    369 ///     accuracy                     Accuracy                 OPTIONAL,
    370 ///     ordering                     BOOLEAN             DEFAULT FALSE,
    371 ///     nonce                        INTEGER                  OPTIONAL,
    372 ///       -- MUST be present if the similar field was present
    373 ///       -- in TimeStampReq.  In that case it MUST have the same value.
    374 ///     tsa                          [0] GeneralName          OPTIONAL,
    375 ///     extensions                   [1] IMPLICIT Extensions  OPTIONAL   }
    376 /// ```
    377 #[derive(Clone, Debug, Eq, PartialEq)]
    378 pub struct TstInfo {
    379     pub version: Integer,
    380     pub policy: TsaPolicyId,
    381     pub message_imprint: MessageImprint,
    382     pub serial_number: Integer,
    383     pub gen_time: GeneralizedTime,
    384     pub accuracy: Option<Accuracy>,
    385     pub ordering: Option<bool>,
    386     pub nonce: Option<Integer>,
    387     pub tsa: Option<GeneralName>,
    388     pub extensions: Option<Extensions>,
    389 }
    390 
    391 impl TstInfo {
    392     pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
    393         cons.take_sequence(|cons| {
    394             let version = Integer::take_from(cons)?;
    395             let policy = TsaPolicyId::take_from(cons)?;
    396             let message_imprint = MessageImprint::take_from(cons)?;
    397             let serial_number = Integer::take_from(cons)?;
    398             let gen_time = GeneralizedTime::take_from_allow_fractional_z(cons)?;
    399             let accuracy = Accuracy::take_opt_from(cons)?;
    400             let ordering = cons.take_opt_bool()?;
    401             let nonce =
    402                 cons.take_opt_primitive_if(Tag::INTEGER, |prim| Integer::from_primitive(prim))?;
    403             let tsa =
    404                 cons.take_opt_constructed_if(Tag::CTX_0, |cons| GeneralName::take_from(cons))?;
    405             let extensions =
    406                 cons.take_opt_constructed_if(Tag::CTX_1, |cons| Extensions::take_from(cons))?;
    407 
    408             Ok(Self {
    409                 version,
    410                 policy,
    411                 message_imprint,
    412                 serial_number,
    413                 gen_time,
    414                 accuracy,
    415                 ordering,
    416                 nonce,
    417                 tsa,
    418                 extensions,
    419             })
    420         })
    421     }
    422 
    423     pub fn encode_ref(&self) -> impl Values + '_ {
    424         encode::sequence((
    425             (&self.version).encode(),
    426             self.policy.encode_ref(),
    427             self.message_imprint.encode_ref(),
    428             (&self.serial_number).encode(),
    429             self.gen_time.encode_ref(),
    430             self.accuracy.as_ref().map(|accuracy| accuracy.encode_ref()),
    431             self.ordering.as_ref().map(|ordering| ordering.encode_ref()),
    432             self.nonce.as_ref().map(|nonce| nonce.encode()),
    433             self.tsa
    434                 .as_ref()
    435                 .map(|tsa| tsa.encode_ref().explicit(Tag::CTX_0)),
    436             self.extensions
    437                 .as_ref()
    438                 .map(|extensions| extensions.encode_ref_as(Tag::CTX_1)),
    439         ))
    440     }
    441 }
    442 
    443 /// Accuracy
    444 ///
    445 /// ```ASN.1
    446 /// Accuracy ::= SEQUENCE {
    447 ///                 seconds        INTEGER           OPTIONAL,
    448 ///                 millis     [0] INTEGER  (1..999) OPTIONAL,
    449 ///                 micros     [1] INTEGER  (1..999) OPTIONAL  }
    450 /// ```
    451 #[derive(Clone, Debug, Eq, PartialEq)]
    452 pub struct Accuracy {
    453     pub seconds: Option<Integer>,
    454     pub millis: Option<Integer>,
    455     pub micros: Option<Integer>,
    456 }
    457 
    458 impl Accuracy {
    459     pub fn take_opt_from<S: Source>(
    460         cons: &mut Constructed<S>,
    461     ) -> Result<Option<Self>, DecodeError<S::Error>> {
    462         cons.take_opt_sequence(|cons| Self::from_sequence(cons))
    463     }
    464 
    465     pub fn from_sequence<S: Source>(
    466         cons: &mut Constructed<S>,
    467     ) -> Result<Self, DecodeError<S::Error>> {
    468         let seconds =
    469             cons.take_opt_primitive_if(Tag::INTEGER, |prim| Integer::from_primitive(prim))?;
    470 
    471         let millis =
    472             cons.take_opt_primitive_if(Tag::CTX_0, |prim| Integer::from_primitive(prim))?;
    473 
    474         let micros =
    475             cons.take_opt_primitive_if(Tag::CTX_1, |prim| Integer::from_primitive(prim))?;
    476 
    477         Ok(Self {
    478             seconds,
    479             millis,
    480             micros,
    481         })
    482     }
    483 
    484     pub fn encode_ref(&self) -> impl Values + '_ {
    485         encode::sequence((
    486             self.seconds.as_ref().map(|seconds| seconds.encode()),
    487             self.millis.as_ref().map(|millis| millis.encode()),
    488             self.micros.as_ref().map(|micros| micros.encode()),
    489         ))
    490     }
    491 }