sec1_decode/
decoder.rs

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use crate::error::Sec1PemError;
use der::asn1::{ContextSpecific, ObjectIdentifier, OctetString};
pub use der::{Decodable, Message};
use std::option::Option::Some;

#[derive(Clone, Debug, Eq, PartialEq, Message)]
/// Direct intermediate representation of the der sequence. This is just a view over that sequence,
/// so it cannot be simply returned from a function, even when cloned.
struct EcPrivateKey_<'a> {
    version: u8,
    key: OctetString<'a>,
    curve: Option<ContextSpecific<'a>>,
    public_key: Option<ContextSpecific<'a>>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
/// The SEC1 EcPrivateKey structure decoded from the input.
pub struct EcPrivateKey {
    /// The version of the curve.
    pub version: u8,
    /// The private key bytes.
    pub key: Vec<u8>,
    /// The curve OID.
    pub curve: Option<ObjectIdentifier>,
    /// The public key bytes, if included.
    pub public_key: Option<Vec<u8>>,
}

impl From<EcPrivateKey_<'_>> for EcPrivateKey {
    fn from(other: EcPrivateKey_<'_>) -> Self {
        let version = other.version;
        let key = other.key.as_bytes().to_vec();
        let curve = other.curve.map(|curve| curve.value.oid().unwrap());
        let public_key = other
            .public_key
            .map(|pub_k| pub_k.value.as_bytes().to_vec());

        EcPrivateKey {
            version,
            key,
            curve,
            public_key,
        }
    }
}

const PEM_EC_HEADER: &str = "EC PRIVATE KEY";

/// Attempts to parse an EcPrivateKey sequence from the passed PEM bytes.
/// ```
/// # use sec1_decode::parse_pem;
/// const PEM:&str = "-----BEGIN EC PRIVATE KEY-----
/// MHcCAQEEIASgox4rXoGc6ajVAjBCsjVIjbfHd8OK3m5v34ZWVBmmoAoGCCqGSM49
/// AwEHoUQDQgAEUfXAsSR5LH4rVdHbcK1vnYcN9I/6T7u1bl1RprSZFf89aZXL+CeG
/// G21XVW8IDhjU7HAXgrO1Sqj00zQtluVBTg==
/// -----END EC PRIVATE KEY-----";
///
/// let parsed = parse_pem(PEM.as_bytes()).unwrap();
/// ```
pub fn parse_pem(bytes: &[u8]) -> Result<EcPrivateKey, Sec1PemError> {
    //Parse many to account for curve params pem
    let parsed = pem::parse_many(bytes);

    let pk_pem = parsed.into_iter().find(|pem| pem.tag == PEM_EC_HEADER);

    if let Some(pk_pem) = pk_pem {
        //Parse der sequence into struct
        let key =
            EcPrivateKey_::from_der(&pk_pem.contents).map_err(|_| Sec1PemError::ParseError)?;
        Ok(key.into())
    } else {
        Err(Sec1PemError::NoECPrivateKey)
    }
}

/// Attempts to parse an EcPrivateKey sequence from the passed DER bytes.
pub fn parse_der(bytes: &[u8]) -> Result<EcPrivateKey, Sec1PemError> {
    Ok(EcPrivateKey_::from_der(bytes)
        .map_err(|_| Sec1PemError::ParseError)?
        .into())
}

#[cfg(test)]
mod test {
    use std::path;
    use std::path::PathBuf;

    fn get_path() -> PathBuf {
        let mut path = path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        path.push("resources/");
        path
    }

    #[test]
    /// Tests that more than one PEM will parse. Does not verify the keys are correct.
    fn test_pems() {
        let path = get_path();

        //Test each pem
        for file in path.read_dir().unwrap() {
            let path = file.unwrap().path();

            //Skip the bad key
            if path.ends_with("pkcs8eckey.pem") || path.ends_with("private_key.der") {
                continue;
            }

            let pem = std::fs::read_to_string(path).unwrap();

            let parse = crate::parse_pem(pem.as_bytes()).unwrap();

            println!("Parsed: {:?}", parse);

            assert_eq!(parse.version, 1);
            assert!(!parse.key.is_empty());
            assert_eq!(parse.key.len(), 32); //32 * 8 bytes = 256 byte key (we're using P256)
            assert!(parse.public_key.is_some());
            assert!(parse.curve.is_some());
        }
    }

    #[test]
    /// Tests that a known key parses.
    fn test_key_parses_pem() {
        let mut path = get_path();
        path.push("private_key2.pem"); //This is the key without a curve header.
        let pem = std::fs::read_to_string(path).unwrap();
        let expected =
            hex::decode("04A0A31E2B5E819CE9A8D5023042B235488DB7C777C38ADE6E6FDF86565419A6") //The key in hex form, dumped from openssl
                .unwrap();

        let parsed = crate::parse_pem(pem.as_bytes()).unwrap();

        assert_eq!(expected, parsed.key)
    }

    #[test]
    fn test_key_parses_der() {
        let mut path = get_path();
        path.push("private_key.der");
        let pem = std::fs::read(path).unwrap();

        let parsed = crate::parse_der(&pem).unwrap();

        println!("{:?}", parsed.key);
    }

    #[test]
    /// Tests that non ECPrivateKeys are not accepted.
    fn test_pkcs8_fails() {
        let mut path = get_path();
        path.push("pkcs8eckey.pem"); //pkcs8 encrypted key.
        let pem = std::fs::read_to_string(path).unwrap();

        let fails = crate::parse_pem(pem.as_bytes());

        assert_eq!(
            fails.unwrap_err(),
            crate::error::Sec1PemError::NoECPrivateKey
        )
    }
}