1 //! Tests for custom derive support. 2 //! 3 //! # Debugging with `cargo expand` 4 //! 5 //! To expand the Rust code generated by the proc macro when debugging 6 //! issues related to these tests, run: 7 //! 8 //! $ cargo expand --test derive --all-features 9 10 #![cfg(all(feature = "derive", feature = "alloc"))] 11 12 /// Custom derive test cases for the `Choice` macro. 13 mod choice { 14 /// `Choice` with `EXPLICIT` tagging. 15 mod explicit { 16 use der::{ 17 asn1::{GeneralizedTime, UtcTime}, 18 Choice, Decode, Encode, SliceWriter, 19 }; 20 use hex_literal::hex; 21 use std::time::Duration; 22 23 /// Custom derive test case for the `Choice` macro. 24 /// 25 /// Based on `Time` as defined in RFC 5280: 26 /// <https://tools.ietf.org/html/rfc5280#page-117> 27 /// 28 /// ```text 29 /// Time ::= CHOICE { 30 /// utcTime UTCTime, 31 /// generalTime GeneralizedTime } 32 /// ``` 33 #[derive(Choice)] 34 pub enum Time { 35 #[asn1(type = "UTCTime")] 36 UtcTime(UtcTime), 37 38 #[asn1(type = "GeneralizedTime")] 39 GeneralTime(GeneralizedTime), 40 } 41 42 impl Time { to_unix_duration(self) -> Duration43 fn to_unix_duration(self) -> Duration { 44 match self { 45 Time::UtcTime(t) => t.to_unix_duration(), 46 Time::GeneralTime(t) => t.to_unix_duration(), 47 } 48 } 49 } 50 51 const UTC_TIMESTAMP_DER: &'static [u8] = 52 &hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a"); 53 const GENERAL_TIMESTAMP_DER: &'static [u8] = 54 &hex!("18 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); 55 56 #[test] decode()57 fn decode() { 58 let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); 59 assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); 60 61 let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); 62 assert_eq!(general_time.to_unix_duration().as_secs(), 673573540); 63 } 64 65 #[test] encode()66 fn encode() { 67 let mut buf = [0u8; 128]; 68 69 let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); 70 let mut encoder = SliceWriter::new(&mut buf); 71 utc_time.encode(&mut encoder).unwrap(); 72 assert_eq!(UTC_TIMESTAMP_DER, encoder.finish().unwrap()); 73 74 let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); 75 let mut encoder = SliceWriter::new(&mut buf); 76 general_time.encode(&mut encoder).unwrap(); 77 assert_eq!(GENERAL_TIMESTAMP_DER, encoder.finish().unwrap()); 78 } 79 } 80 81 /// `Choice` with `IMPLICIT` tagging. 82 mod implicit { 83 use der::{ 84 asn1::{BitStringRef, GeneralizedTime}, 85 Choice, Decode, Encode, SliceWriter, 86 }; 87 use hex_literal::hex; 88 89 /// `Choice` macro test case for `IMPLICIT` tagging. 90 #[derive(Choice, Debug, Eq, PartialEq)] 91 #[asn1(tag_mode = "IMPLICIT")] 92 pub enum ImplicitChoice<'a> { 93 #[asn1(context_specific = "0", type = "BIT STRING")] 94 BitString(BitStringRef<'a>), 95 96 #[asn1(context_specific = "1", type = "GeneralizedTime")] 97 Time(GeneralizedTime), 98 99 #[asn1(context_specific = "2", type = "UTF8String")] 100 Utf8String(String), 101 } 102 103 impl<'a> ImplicitChoice<'a> { bit_string(&self) -> Option<BitStringRef<'a>>104 pub fn bit_string(&self) -> Option<BitStringRef<'a>> { 105 match self { 106 Self::BitString(bs) => Some(*bs), 107 _ => None, 108 } 109 } 110 time(&self) -> Option<GeneralizedTime>111 pub fn time(&self) -> Option<GeneralizedTime> { 112 match self { 113 Self::Time(time) => Some(*time), 114 _ => None, 115 } 116 } 117 } 118 119 const BITSTRING_DER: &'static [u8] = &hex!("80 04 00 01 02 03"); 120 const TIME_DER: &'static [u8] = &hex!("81 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); 121 122 #[test] decode()123 fn decode() { 124 let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); 125 assert_eq!( 126 cs_bit_string.bit_string().unwrap().as_bytes().unwrap(), 127 &[1, 2, 3] 128 ); 129 130 let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); 131 assert_eq!( 132 cs_time.time().unwrap().to_unix_duration().as_secs(), 133 673573540 134 ); 135 } 136 137 #[test] encode()138 fn encode() { 139 let mut buf = [0u8; 128]; 140 141 let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); 142 let mut encoder = SliceWriter::new(&mut buf); 143 cs_bit_string.encode(&mut encoder).unwrap(); 144 assert_eq!(BITSTRING_DER, encoder.finish().unwrap()); 145 146 let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); 147 let mut encoder = SliceWriter::new(&mut buf); 148 cs_time.encode(&mut encoder).unwrap(); 149 assert_eq!(TIME_DER, encoder.finish().unwrap()); 150 } 151 } 152 } 153 154 /// Custom derive test cases for the `Enumerated` macro. 155 mod enumerated { 156 use der::{Decode, Encode, Enumerated, SliceWriter}; 157 use hex_literal::hex; 158 159 /// X.509 `CRLReason`. 160 #[derive(Enumerated, Copy, Clone, Debug, Eq, PartialEq)] 161 #[repr(u32)] 162 pub enum CrlReason { 163 Unspecified = 0, 164 KeyCompromise = 1, 165 CaCompromise = 2, 166 AffiliationChanged = 3, 167 Superseded = 4, 168 CessationOfOperation = 5, 169 CertificateHold = 6, 170 RemoveFromCrl = 8, 171 PrivilegeWithdrawn = 9, 172 AaCompromised = 10, 173 } 174 175 const UNSPECIFIED_DER: &[u8] = &hex!("0a 01 00"); 176 const KEY_COMPROMISE_DER: &[u8] = &hex!("0a 01 01"); 177 178 #[test] decode()179 fn decode() { 180 let unspecified = CrlReason::from_der(UNSPECIFIED_DER).unwrap(); 181 assert_eq!(CrlReason::Unspecified, unspecified); 182 183 let key_compromise = CrlReason::from_der(KEY_COMPROMISE_DER).unwrap(); 184 assert_eq!(CrlReason::KeyCompromise, key_compromise); 185 } 186 187 #[test] encode()188 fn encode() { 189 let mut buf = [0u8; 128]; 190 191 let mut encoder = SliceWriter::new(&mut buf); 192 CrlReason::Unspecified.encode(&mut encoder).unwrap(); 193 assert_eq!(UNSPECIFIED_DER, encoder.finish().unwrap()); 194 195 let mut encoder = SliceWriter::new(&mut buf); 196 CrlReason::KeyCompromise.encode(&mut encoder).unwrap(); 197 assert_eq!(KEY_COMPROMISE_DER, encoder.finish().unwrap()); 198 } 199 } 200 201 /// Custom derive test cases for the `Sequence` macro. 202 #[cfg(feature = "oid")] 203 mod sequence { 204 use der::{ 205 asn1::{AnyRef, ObjectIdentifier, SetOf}, 206 Decode, Encode, Sequence, ValueOrd, 207 }; 208 use hex_literal::hex; 209 default_false_example() -> bool210 pub fn default_false_example() -> bool { 211 false 212 } 213 214 // Issuing distribution point extension as defined in [RFC 5280 Section 5.2.5] and as identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. 215 // 216 // ```text 217 // IssuingDistributionPoint ::= SEQUENCE { 218 // distributionPoint [0] DistributionPointName OPTIONAL, 219 // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, 220 // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, 221 // onlySomeReasons [3] ReasonFlags OPTIONAL, 222 // indirectCRL [4] BOOLEAN DEFAULT FALSE, 223 // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } 224 // -- at most one of onlyContainsUserCerts, onlyContainsCACerts, 225 // -- and onlyContainsAttributeCerts may be set to TRUE. 226 // ``` 227 // 228 // [RFC 5280 Section 5.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5 229 #[derive(Sequence)] 230 pub struct IssuingDistributionPointExample { 231 // Omit distributionPoint and only_some_reasons because corresponding structs are not 232 // available here and are not germane to the example 233 // distributionPoint [0] DistributionPointName OPTIONAL, 234 //#[asn1(context_specific="0", optional="true", tag_mode="IMPLICIT")] 235 //pub distribution_point: Option<DistributionPointName<'a>>, 236 /// onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, 237 #[asn1( 238 context_specific = "1", 239 default = "default_false_example", 240 tag_mode = "IMPLICIT" 241 )] 242 pub only_contains_user_certs: bool, 243 244 /// onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, 245 #[asn1( 246 context_specific = "2", 247 default = "default_false_example", 248 tag_mode = "IMPLICIT" 249 )] 250 pub only_contains_cacerts: bool, 251 252 // onlySomeReasons [3] ReasonFlags OPTIONAL, 253 //#[asn1(context_specific="3", optional="true", tag_mode="IMPLICIT")] 254 //pub only_some_reasons: Option<ReasonFlags<'a>>, 255 /// indirectCRL [4] BOOLEAN DEFAULT FALSE, 256 #[asn1( 257 context_specific = "4", 258 default = "default_false_example", 259 tag_mode = "IMPLICIT" 260 )] 261 pub indirect_crl: bool, 262 263 /// onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE 264 #[asn1( 265 context_specific = "5", 266 default = "default_false_example", 267 tag_mode = "IMPLICIT" 268 )] 269 pub only_contains_attribute_certs: bool, 270 } 271 272 // Extension as defined in [RFC 5280 Section 4.1.2.9]. 273 // 274 // The ASN.1 definition for Extension objects is below. The extnValue type may be further parsed using a decoder corresponding to the extnID value. 275 // 276 // ```text 277 // Extension ::= SEQUENCE { 278 // extnID OBJECT IDENTIFIER, 279 // critical BOOLEAN DEFAULT FALSE, 280 // extnValue OCTET STRING 281 // -- contains the DER encoding of an ASN.1 value 282 // -- corresponding to the extension type identified 283 // -- by extnID 284 // } 285 // ``` 286 // 287 // [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 288 #[derive(Clone, Debug, Eq, PartialEq, Sequence)] 289 pub struct ExtensionExample<'a> { 290 /// extnID OBJECT IDENTIFIER, 291 pub extn_id: ObjectIdentifier, 292 293 /// critical BOOLEAN DEFAULT FALSE, 294 #[asn1(default = "default_false_example")] 295 pub critical: bool, 296 297 /// extnValue OCTET STRING 298 #[asn1(type = "OCTET STRING")] 299 pub extn_value: &'a [u8], 300 } 301 302 /// X.509 `AlgorithmIdentifier` 303 #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] 304 pub struct AlgorithmIdentifier<'a> { 305 pub algorithm: ObjectIdentifier, 306 pub parameters: Option<AnyRef<'a>>, 307 } 308 309 /// X.509 `SubjectPublicKeyInfo` (SPKI) 310 #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] 311 pub struct SubjectPublicKeyInfo<'a> { 312 pub algorithm: AlgorithmIdentifier<'a>, 313 #[asn1(type = "BIT STRING")] 314 pub subject_public_key: &'a [u8], 315 } 316 317 /// PKCS#8v2 `OneAsymmetricKey` 318 #[derive(Sequence)] 319 pub struct OneAsymmetricKey<'a> { 320 pub version: u8, 321 pub private_key_algorithm: AlgorithmIdentifier<'a>, 322 #[asn1(type = "OCTET STRING")] 323 pub private_key: &'a [u8], 324 #[asn1(context_specific = "0", extensible = "true", optional = "true")] 325 pub attributes: Option<SetOf<AnyRef<'a>, 1>>, 326 #[asn1( 327 context_specific = "1", 328 extensible = "true", 329 optional = "true", 330 type = "BIT STRING" 331 )] 332 pub public_key: Option<&'a [u8]>, 333 } 334 335 /// X.509 extension 336 // TODO(tarcieri): tests for code derived with the `default` attribute 337 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] 338 pub struct Extension<'a> { 339 extn_id: ObjectIdentifier, 340 #[asn1(default = "critical_default")] 341 critical: bool, 342 #[asn1(type = "OCTET STRING")] 343 extn_value: &'a [u8], 344 } 345 346 /// Default value of the `critical` bit critical_default() -> bool347 fn critical_default() -> bool { 348 false 349 } 350 351 const ID_EC_PUBLIC_KEY_OID: ObjectIdentifier = 352 ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); 353 354 const PRIME256V1_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); 355 356 const ALGORITHM_IDENTIFIER_DER: &[u8] = 357 &hex!("30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03 01 07"); 358 359 #[derive(Sequence)] 360 #[asn1(tag_mode = "IMPLICIT")] 361 pub struct TypeCheckExpandedSequenceFieldAttributeCombinations<'a> { 362 pub simple: bool, 363 #[asn1(type = "BIT STRING")] 364 pub typed: &'a [u8], 365 #[asn1(context_specific = "0")] 366 pub context_specific: bool, 367 #[asn1(optional = "true")] 368 pub optional: Option<bool>, 369 #[asn1(default = "default_false_example")] 370 pub default: bool, 371 #[asn1(type = "BIT STRING", context_specific = "1")] 372 pub typed_context_specific: &'a [u8], 373 #[asn1(context_specific = "2", optional = "true")] 374 pub context_specific_optional: Option<bool>, 375 #[asn1(context_specific = "3", default = "default_false_example")] 376 pub context_specific_default: bool, 377 #[asn1(type = "BIT STRING", context_specific = "4", optional = "true")] 378 pub typed_context_specific_optional: Option<&'a [u8]>, 379 } 380 381 #[test] idp_test()382 fn idp_test() { 383 let idp = IssuingDistributionPointExample::from_der(&hex!("30038101FF")).unwrap(); 384 assert_eq!(idp.only_contains_user_certs, true); 385 assert_eq!(idp.only_contains_cacerts, false); 386 assert_eq!(idp.indirect_crl, false); 387 assert_eq!(idp.only_contains_attribute_certs, false); 388 389 let idp = IssuingDistributionPointExample::from_der(&hex!("30038201FF")).unwrap(); 390 assert_eq!(idp.only_contains_user_certs, false); 391 assert_eq!(idp.only_contains_cacerts, true); 392 assert_eq!(idp.indirect_crl, false); 393 assert_eq!(idp.only_contains_attribute_certs, false); 394 395 let idp = IssuingDistributionPointExample::from_der(&hex!("30038401FF")).unwrap(); 396 assert_eq!(idp.only_contains_user_certs, false); 397 assert_eq!(idp.only_contains_cacerts, false); 398 assert_eq!(idp.indirect_crl, true); 399 assert_eq!(idp.only_contains_attribute_certs, false); 400 401 let idp = IssuingDistributionPointExample::from_der(&hex!("30038501FF")).unwrap(); 402 assert_eq!(idp.only_contains_user_certs, false); 403 assert_eq!(idp.only_contains_cacerts, false); 404 assert_eq!(idp.indirect_crl, false); 405 assert_eq!(idp.only_contains_attribute_certs, true); 406 } 407 408 // demonstrates default field that is not context specific 409 #[test] extension_test()410 fn extension_test() { 411 let ext1 = ExtensionExample::from_der(&hex!( 412 "300F" // 0 15: SEQUENCE { 413 "0603551D13" // 2 3: OBJECT IDENTIFIER basicConstraints (2 5 29 19) 414 "0101FF" // 7 1: BOOLEAN TRUE 415 "0405" // 10 5: OCTET STRING, encapsulates { 416 "3003" // 12 3: SEQUENCE { 417 "0101FF" // 14 1: BOOLEAN TRUE 418 )) 419 .unwrap(); 420 assert_eq!(ext1.critical, true); 421 422 let ext2 = ExtensionExample::from_der(&hex!( 423 "301F" // 0 31: SEQUENCE { 424 "0603551D23" // 2 3: OBJECT IDENTIFIER authorityKeyIdentifier (2 5 29 35) 425 "0418" // 7 24: OCTET STRING, encapsulates { 426 "3016" // 9 22: SEQUENCE { 427 "8014E47D5FD15C9586082C05AEBE75B665A7D95DA866" // 11 20: [0] E4 7D 5F D1 5C 95 86 08 2C 05 AE BE 75 B6 65 A7 D9 5D A8 66 428 )) 429 .unwrap(); 430 assert_eq!(ext2.critical, false); 431 } 432 433 #[test] decode()434 fn decode() { 435 let algorithm_identifier = 436 AlgorithmIdentifier::from_der(&ALGORITHM_IDENTIFIER_DER).unwrap(); 437 438 assert_eq!(ID_EC_PUBLIC_KEY_OID, algorithm_identifier.algorithm); 439 assert_eq!( 440 PRIME256V1_OID, 441 ObjectIdentifier::try_from(algorithm_identifier.parameters.unwrap()).unwrap() 442 ); 443 } 444 445 #[test] encode()446 fn encode() { 447 let parameters_oid = PRIME256V1_OID; 448 449 let algorithm_identifier = AlgorithmIdentifier { 450 algorithm: ID_EC_PUBLIC_KEY_OID, 451 parameters: Some(AnyRef::from(¶meters_oid)), 452 }; 453 454 assert_eq!( 455 ALGORITHM_IDENTIFIER_DER, 456 algorithm_identifier.to_vec().unwrap() 457 ); 458 } 459 } 460