1use crate::error::{X509Error, X509Result};
7use crate::objects::*;
8use crate::public_key::*;
9
10use asn1_rs::{
11 Any, BitString, BmpString, DerSequence, FromBer, FromDer, OptTaggedParser, ParseResult,
12};
13use core::convert::TryFrom;
14use data_encoding::HEXUPPER;
15use der_parser::ber::MAX_OBJECT_SIZE;
16use der_parser::der::*;
17use der_parser::error::*;
18use der_parser::num_bigint::BigUint;
19use der_parser::*;
20use nom::branch::alt;
21use nom::bytes::complete::take;
22use nom::combinator::{complete, map};
23use nom::multi::{many0, many1};
24use nom::{Err, Offset};
25use oid_registry::*;
26use rusticata_macros::newtype_enum;
27use std::fmt;
28use std::iter::FromIterator;
29
30#[derive(Debug, PartialEq, Eq, Clone, Copy)]
39pub struct X509Version(pub u32);
40
41impl X509Version {
42 pub(crate) fn from_der_tagged_0(i: &[u8]) -> X509Result<X509Version> {
44 let (rem, opt_version) = OptTaggedParser::from(0)
45 .parse_der(i, |_, data| Self::from_der(data))
46 .map_err(Err::convert)?;
47 let version = opt_version.unwrap_or(X509Version::V1);
48 Ok((rem, version))
49 }
50}
51
52impl<'a> FromDer<'a, X509Error> for X509Version {
54 fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
55 map(<u32>::from_der, X509Version)(i).map_err(|_| Err::Error(X509Error::InvalidVersion))
56 }
57}
58
59newtype_enum! {
60 impl display X509Version {
61 V1 = 0,
62 V2 = 1,
63 V3 = 2,
64 }
65}
66
67#[derive(Clone, Debug, PartialEq)]
71pub struct AttributeTypeAndValue<'a> {
72 attr_type: Oid<'a>,
73 attr_value: Any<'a>, }
75
76impl<'a> AttributeTypeAndValue<'a> {
77 #[inline]
79 pub const fn new(attr_type: Oid<'a>, attr_value: Any<'a>) -> Self {
80 AttributeTypeAndValue {
81 attr_type,
82 attr_value,
83 }
84 }
85
86 #[inline]
88 pub const fn attr_type(&self) -> &Oid<'a> {
89 &self.attr_type
90 }
91
92 #[inline]
94 pub const fn attr_value(&self) -> &Any<'a> {
95 &self.attr_value
96 }
97
98 #[inline]
107 pub fn as_str(&self) -> Result<&'a str, X509Error> {
108 match self.attr_value.tag() {
110 Tag::NumericString | Tag::PrintableString | Tag::Utf8String | Tag::Ia5String => {
111 let s = core::str::from_utf8(self.attr_value.data)
112 .map_err(|_| X509Error::InvalidAttributes)?;
113 Ok(s)
114 }
115 t => Err(X509Error::Der(Error::unexpected_tag(None, t))),
116 }
117 }
118
119 #[inline]
121 pub fn as_slice(&self) -> &[u8] {
122 self.attr_value.as_bytes()
123 }
124}
125
126impl<'a, 'b> TryFrom<&'a AttributeTypeAndValue<'b>> for &'a str {
127 type Error = X509Error;
128
129 fn try_from(value: &'a AttributeTypeAndValue<'b>) -> Result<Self, Self::Error> {
130 value.attr_value.as_str().map_err(|e| e.into())
131 }
132}
133
134impl<'a, 'b> From<&'a AttributeTypeAndValue<'b>> for &'a [u8] {
135 fn from(value: &'a AttributeTypeAndValue<'b>) -> Self {
136 value.as_slice()
137 }
138}
139
140impl<'a> FromDer<'a, X509Error> for AttributeTypeAndValue<'a> {
144 fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
145 parse_der_sequence_defined_g(|i, _| {
146 let (i, attr_type) = Oid::from_der(i).or(Err(X509Error::InvalidX509Name))?;
147 let (i, attr_value) = parse_attribute_value(i).or(Err(X509Error::InvalidX509Name))?;
148 let attr = AttributeTypeAndValue::new(attr_type, attr_value);
149 Ok((i, attr))
150 })(i)
151 }
152}
153
154#[inline]
156fn parse_attribute_value(i: &[u8]) -> ParseResult<Any, Error> {
157 alt((Any::from_der, parse_malformed_string))(i)
158}
159
160fn parse_malformed_string(i: &[u8]) -> ParseResult<Any, Error> {
161 let (rem, hdr) = Header::from_der(i)?;
162 let len = hdr.length().definite()?;
163 if len > MAX_OBJECT_SIZE {
164 return Err(Err::Error(Error::InvalidLength));
165 }
166 match hdr.tag() {
167 Tag::PrintableString => {
168 let (rem, data) = take(len)(rem)?;
172 let _ = std::str::from_utf8(data).map_err(|_| Error::BerValueError)?;
174 let obj = Any::new(hdr, data);
175 Ok((rem, obj))
176 }
177 t => Err(Err::Error(Error::unexpected_tag(
178 Some(Tag::PrintableString),
179 t,
180 ))),
181 }
182}
183
184#[derive(Clone, Debug, PartialEq)]
188pub struct RelativeDistinguishedName<'a> {
189 set: Vec<AttributeTypeAndValue<'a>>,
190}
191
192impl<'a> RelativeDistinguishedName<'a> {
193 #[inline]
195 pub const fn new(set: Vec<AttributeTypeAndValue<'a>>) -> Self {
196 RelativeDistinguishedName { set }
197 }
198
199 pub fn iter(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
201 self.set.iter()
202 }
203}
204
205impl<'a> FromIterator<AttributeTypeAndValue<'a>> for RelativeDistinguishedName<'a> {
206 fn from_iter<T: IntoIterator<Item = AttributeTypeAndValue<'a>>>(iter: T) -> Self {
207 let set = iter.into_iter().collect();
208 RelativeDistinguishedName { set }
209 }
210}
211
212impl<'a> FromDer<'a, X509Error> for RelativeDistinguishedName<'a> {
213 fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
214 parse_der_set_defined_g(|i, _| {
215 let (i, set) = many1(complete(AttributeTypeAndValue::from_der))(i)?;
216 let rdn = RelativeDistinguishedName { set };
217 Ok((i, rdn))
218 })(i)
219 }
220}
221
222#[derive(Clone, Debug, PartialEq)]
223pub struct SubjectPublicKeyInfo<'a> {
224 pub algorithm: AlgorithmIdentifier<'a>,
225 pub subject_public_key: BitString<'a>,
226 pub raw: &'a [u8],
230}
231
232impl SubjectPublicKeyInfo<'_> {
233 pub fn parsed(&self) -> Result<PublicKey, X509Error> {
235 let b = &self.subject_public_key.data;
236 if self.algorithm.algorithm == OID_PKCS1_RSAENCRYPTION {
237 let (_, key) = RSAPublicKey::from_der(b).map_err(|_| X509Error::InvalidSPKI)?;
238 Ok(PublicKey::RSA(key))
239 } else if self.algorithm.algorithm == OID_KEY_TYPE_EC_PUBLIC_KEY {
240 let key = ECPoint::from(b.as_ref());
241 Ok(PublicKey::EC(key))
242 } else if self.algorithm.algorithm == OID_KEY_TYPE_DSA {
243 let s = parse_der_integer(b)
244 .and_then(|(_, obj)| obj.as_slice().map_err(Err::Error))
245 .or(Err(X509Error::InvalidSPKI))?;
246 Ok(PublicKey::DSA(s))
247 } else if self.algorithm.algorithm == OID_GOST_R3410_2001 {
248 let (_, s) = <&[u8]>::from_der(b).or(Err(X509Error::InvalidSPKI))?;
249 Ok(PublicKey::GostR3410(s))
250 } else if self.algorithm.algorithm == OID_KEY_TYPE_GOST_R3410_2012_256
251 || self.algorithm.algorithm == OID_KEY_TYPE_GOST_R3410_2012_512
252 {
253 let (_, s) = <&[u8]>::from_der(b).or(Err(X509Error::InvalidSPKI))?;
254 Ok(PublicKey::GostR3410_2012(s))
255 } else {
256 Ok(PublicKey::Unknown(b))
257 }
258 }
259}
260
261impl<'a> FromDer<'a, X509Error> for SubjectPublicKeyInfo<'a> {
262 fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
264 let start_i = i;
265 parse_der_sequence_defined_g(move |i, _| {
266 let (i, algorithm) = AlgorithmIdentifier::from_der(i)?;
267 let (i, subject_public_key) = BitString::from_der(i).or(Err(X509Error::InvalidSPKI))?;
268 let len = start_i.offset(i);
269 let raw = &start_i[..len];
270 let spki = SubjectPublicKeyInfo {
271 algorithm,
272 subject_public_key,
273 raw,
274 };
275 Ok((i, spki))
276 })(i)
277 }
278}
279
280#[derive(Clone, Debug, PartialEq, DerSequence)]
295#[error(X509Error)]
296pub struct AlgorithmIdentifier<'a> {
297 #[map_err(|_| X509Error::InvalidAlgorithmIdentifier)]
298 pub algorithm: Oid<'a>,
299 #[optional]
300 pub parameters: Option<Any<'a>>,
301}
302
303impl<'a> AlgorithmIdentifier<'a> {
304 pub const fn new(algorithm: Oid<'a>, parameters: Option<Any<'a>>) -> Self {
306 Self {
307 algorithm,
308 parameters,
309 }
310 }
311
312 pub const fn oid(&'a self) -> &'a Oid<'a> {
314 &self.algorithm
315 }
316
317 pub const fn parameters(&'a self) -> Option<&'a Any<'a>> {
319 self.parameters.as_ref()
320 }
321}
322
323#[derive(Clone, Debug, PartialEq)]
330pub struct X509Name<'a> {
331 pub(crate) rdn_seq: Vec<RelativeDistinguishedName<'a>>,
332 pub(crate) raw: &'a [u8],
333}
334
335impl fmt::Display for X509Name<'_> {
336 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
337 match x509name_to_string(&self.rdn_seq, oid_registry()) {
338 Ok(o) => write!(f, "{}", o),
339 Err(_) => write!(f, "<X509Error: Invalid X.509 name>"),
340 }
341 }
342}
343
344impl<'a> X509Name<'a> {
345 #[inline]
347 pub const fn new(rdn_seq: Vec<RelativeDistinguishedName<'a>>, raw: &'a [u8]) -> Self {
348 X509Name { rdn_seq, raw }
349 }
350
351 pub fn to_string_with_registry(&self, oid_registry: &OidRegistry) -> Result<String, X509Error> {
356 x509name_to_string(&self.rdn_seq, oid_registry)
357 }
358
359 pub fn as_raw(&self) -> &'a [u8] {
361 self.raw
362 }
363
364 pub fn iter(&self) -> impl Iterator<Item = &RelativeDistinguishedName<'a>> {
366 self.rdn_seq.iter()
367 }
368
369 pub fn iter_rdn(&self) -> impl Iterator<Item = &RelativeDistinguishedName<'a>> {
371 self.rdn_seq.iter()
372 }
373
374 pub fn iter_attributes(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
376 self.rdn_seq.iter().flat_map(|rdn| rdn.set.iter())
377 }
378
379 pub fn iter_by_oid(&self, oid: &Oid<'a>) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
391 let oid = oid.clone();
396 self.iter_attributes()
397 .filter(move |obj| obj.attr_type == oid)
398 }
399
400 pub fn iter_common_name(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
422 self.iter_by_oid(&OID_X509_COMMON_NAME)
423 }
424
425 pub fn iter_country(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
427 self.iter_by_oid(&OID_X509_COUNTRY_NAME)
428 }
429
430 pub fn iter_organization(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
432 self.iter_by_oid(&OID_X509_ORGANIZATION_NAME)
433 }
434
435 pub fn iter_organizational_unit(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
437 self.iter_by_oid(&OID_X509_ORGANIZATIONAL_UNIT)
438 }
439
440 pub fn iter_state_or_province(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
442 self.iter_by_oid(&OID_X509_STATE_OR_PROVINCE_NAME)
443 }
444
445 pub fn iter_locality(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
447 self.iter_by_oid(&OID_X509_LOCALITY_NAME)
448 }
449
450 pub fn iter_email(&self) -> impl Iterator<Item = &AttributeTypeAndValue<'a>> {
452 self.iter_by_oid(&OID_PKCS9_EMAIL_ADDRESS)
453 }
454}
455
456impl<'a> FromIterator<RelativeDistinguishedName<'a>> for X509Name<'a> {
457 fn from_iter<T: IntoIterator<Item = RelativeDistinguishedName<'a>>>(iter: T) -> Self {
458 let rdn_seq = iter.into_iter().collect();
459 X509Name { rdn_seq, raw: &[] }
460 }
461}
462
463impl<'a> From<X509Name<'a>> for Vec<RelativeDistinguishedName<'a>> {
464 fn from(name: X509Name<'a>) -> Self {
465 name.rdn_seq
466 }
467}
468
469impl<'a> FromDer<'a, X509Error> for X509Name<'a> {
470 fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
472 let start_i = i;
473 parse_der_sequence_defined_g(move |i, _| {
474 let (i, rdn_seq) = many0(complete(RelativeDistinguishedName::from_der))(i)?;
475 let len = start_i.offset(i);
476 let name = X509Name {
477 rdn_seq,
478 raw: &start_i[..len],
479 };
480 Ok((i, name))
481 })(i)
482 }
483}
484
485#[derive(Debug, PartialEq, Eq, Clone, Copy)]
486pub struct ReasonCode(pub u8);
487
488newtype_enum! {
489impl display ReasonCode {
490 Unspecified = 0,
491 KeyCompromise = 1,
492 CACompromise = 2,
493 AffiliationChanged = 3,
494 Superseded = 4,
495 CessationOfOperation = 5,
496 CertificateHold = 6,
497 RemoveFromCRL = 8,
499 PrivilegeWithdrawn = 9,
500 AACompromise = 10,
501}
502}
503
504impl Default for ReasonCode {
505 fn default() -> Self {
506 ReasonCode::Unspecified
507 }
508}
509
510fn attribute_value_to_string(attr: &Any, _attr_type: &Oid) -> Result<String, X509Error> {
513 match attr.tag() {
515 Tag::NumericString
516 | Tag::VisibleString
517 | Tag::PrintableString
518 | Tag::GeneralString
519 | Tag::ObjectDescriptor
520 | Tag::GraphicString
521 | Tag::T61String
522 | Tag::VideotexString
523 | Tag::Utf8String
524 | Tag::Ia5String => {
525 let s = core::str::from_utf8(attr.data).map_err(|_| X509Error::InvalidAttributes)?;
526 Ok(s.to_owned())
527 }
528 Tag::BmpString => {
529 let any = attr.clone();
531 let s = BmpString::try_from(any).map_err(|_| X509Error::InvalidAttributes)?;
532 Ok(s.string())
533 }
534 _ => {
535 Ok(HEXUPPER.encode(attr.as_bytes()))
537 }
538 }
539}
540
541fn x509name_to_string(
548 rdn_seq: &[RelativeDistinguishedName],
549 oid_registry: &OidRegistry,
550) -> Result<String, X509Error> {
551 rdn_seq.iter().try_fold(String::new(), |acc, rdn| {
552 rdn.set
553 .iter()
554 .try_fold(String::new(), |acc2, attr| {
555 let val_str = attribute_value_to_string(&attr.attr_value, &attr.attr_type)?;
556 let abbrev = match oid2abbrev(&attr.attr_type, oid_registry) {
558 Ok(s) => String::from(s),
559 _ => format!("{:?}", attr.attr_type),
560 };
561 let rdn = format!("{}={}", abbrev, val_str);
562 match acc2.len() {
563 0 => Ok(rdn),
564 _ => Ok(acc2 + " + " + &rdn),
565 }
566 })
567 .map(|v| match acc.len() {
568 0 => v,
569 _ => acc + ", " + &v,
570 })
571 })
572}
573
574pub(crate) fn parse_signature_value(i: &[u8]) -> X509Result<BitString> {
575 BitString::from_der(i).or(Err(Err::Error(X509Error::InvalidSignatureValue)))
576}
577
578pub(crate) fn parse_serial(i: &[u8]) -> X509Result<(&[u8], BigUint)> {
579 let (rem, any) = Any::from_ber(i).map_err(|_| X509Error::InvalidSerial)?;
580 any.tag()
584 .assert_eq(Tag::Integer)
585 .map_err(|_| X509Error::InvalidSerial)?;
586 let slice = any.data;
587 let big = BigUint::from_bytes_be(slice);
588 Ok((rem, (slice, big)))
589}
590
591#[cfg(test)]
592mod tests {
593 use super::*;
594
595 #[test]
596 fn test_x509_version() {
597 let data: &[u8] = &[0xa0, 0x03, 0x02, 0x01, 0x00];
599 let r = X509Version::from_der_tagged_0(data);
600 assert!(r.is_ok());
601
602 let data: &[u8] = &[0xa1, 0x03, 0x02, 0x01, 0x00];
604 let r = X509Version::from_der_tagged_0(data);
605 assert!(r.is_ok());
606
607 let data: &[u8] = &[0xa0, 0x01];
609 let r = X509Version::from_der_tagged_0(data);
610 assert!(r.is_err());
611
612 let data: &[u8] = &[0xa1, 0x01];
614 let r = X509Version::from_der_tagged_0(data);
615 assert!(r.is_err());
616 }
617
618 #[test]
619 fn test_x509_name() {
620 let name = X509Name {
621 rdn_seq: vec![
622 RelativeDistinguishedName {
623 set: vec![AttributeTypeAndValue {
624 attr_type: oid! {2.5.4.6}, attr_value: Any::from_tag_and_data(Tag::PrintableString, b"FR"),
626 }],
627 },
628 RelativeDistinguishedName {
629 set: vec![AttributeTypeAndValue {
630 attr_type: oid! {2.5.4.8}, attr_value: Any::from_tag_and_data(Tag::PrintableString, b"Some-State"),
632 }],
633 },
634 RelativeDistinguishedName {
635 set: vec![AttributeTypeAndValue {
636 attr_type: oid! {2.5.4.10}, attr_value: Any::from_tag_and_data(
638 Tag::PrintableString,
639 b"Internet Widgits Pty Ltd",
640 ),
641 }],
642 },
643 RelativeDistinguishedName {
644 set: vec![
645 AttributeTypeAndValue {
646 attr_type: oid! {2.5.4.3}, attr_value: Any::from_tag_and_data(Tag::PrintableString, b"Test1"),
648 },
649 AttributeTypeAndValue {
650 attr_type: oid! {2.5.4.3}, attr_value: Any::from_tag_and_data(Tag::PrintableString, b"Test2"),
652 },
653 ],
654 },
655 ],
656 raw: &[], };
658 assert_eq!(
659 name.to_string(),
660 "C=FR, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Test1 + CN=Test2"
661 );
662 }
663}