1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! Decoding functions for PEM-encoded data
//!
//! # Examples
//!
//! Parsing a certificate in PEM format:
//!
//! ```rust,no_run
//! # extern crate nom;
//! # #[macro_use] extern crate x509_parser;
//! use x509_parser::pem::pem_to_der;
//! use x509_parser::parse_x509_der;
//!
//! static IGCA_PEM: &'static [u8] = include_bytes!("../assets/IGC_A.pem");
//!
//! # fn main() {
//! let res = pem_to_der(IGCA_PEM);
//! match res {
//!     Ok((rem, pem)) => {
//!         assert!(rem.is_empty());
//!         //
//!         assert_eq!(pem.label, String::from("CERTIFICATE"));
//!         //
//!         let res_x509 = parse_x509_der(&pem.contents);
//!         assert!(res_x509.is_ok());
//!     },
//!     _ => panic!("PEM parsing failed: {:?}", res),
//! }
//! # }
//! ```

use std::str;
use base64;
use nom::IResult;

/// Representation of PEM data
#[derive(PartialEq,Debug)]
pub struct Pem {
    /// The PEM label
    pub label:    String,
    /// The PEM decoded data
    pub contents: Vec<u8>,
}

/// Read a PEM-encoded structure, and decode the base64 data
///
/// Allocates a new buffer for the decoded data.
pub fn pem_to_der<'a>(i:&'a[u8]) -> IResult<&'a[u8],Pem> {
    do_parse!(
        i,
           tag_s!("-----BEGIN ") >>
        l: map_res!(
                take_until!("-"),
                |x:&'a[u8]| str::from_utf8(x)
           ) >>
           tag_s!("-----") >>
        r: map_res!(
               take_until!("-----END"),
               |lines:&[u8]| {
                   let v = lines.split(|&x| x==0xa).fold(
                       Vec::new(),
                       |mut acc,line| {
                           if !line.is_empty() { acc.extend_from_slice(line); }
                           acc
                       }
                   );
                   base64::decode(&v)
               }
           ) >>
           tag_s!("-----END ") >>
           take_until!("-") >>
           tag_s!("-----") >>
           opt!(tag!(b"\n")) >>
        (
            Pem{
                label:    l.to_string(),
                contents: r
            }
        )
    )
}