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 }