• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 //! PKCS#8 is specified in [RFC 5958].
16 //!
17 //! [RFC 5958]: https://tools.ietf.org/html/rfc5958.
18 
19 use crate::{ec, error, io::der};
20 
21 pub(crate) enum Version {
22     V1Only,
23     V1OrV2,
24     V2Only,
25 }
26 
27 /// A template for constructing PKCS#8 documents.
28 ///
29 /// Note that this only works for ECC.
30 pub(crate) struct Template {
31     pub bytes: &'static [u8],
32 
33     // The range within `bytes` that holds the value (not including the tag and
34     // length) for use in the PKCS#8 document's privateKeyAlgorithm field.
35     pub alg_id_range: core::ops::Range<usize>,
36 
37     // `bytes[alg_id_range][curve_id_index..]` contains the OID identifying the,
38     // curve, including the tag and length.
39     pub curve_id_index: usize,
40 
41     // `bytes` will be split into two parts at `private_key_index`, where the
42     // first part is written before the private key and the second part is
43     // written after the private key. The public key is written after the second
44     // part.
45     pub private_key_index: usize,
46 }
47 
48 impl Template {
49     #[inline]
alg_id_value(&self) -> untrusted::Input50     fn alg_id_value(&self) -> untrusted::Input {
51         untrusted::Input::from(self.alg_id_value_())
52     }
53 
alg_id_value_(&self) -> &[u8]54     fn alg_id_value_(&self) -> &[u8] {
55         &self.bytes[self.alg_id_range.start..self.alg_id_range.end]
56     }
57 
58     #[inline]
curve_oid(&self) -> untrusted::Input59     pub fn curve_oid(&self) -> untrusted::Input {
60         untrusted::Input::from(&self.alg_id_value_()[self.curve_id_index..])
61     }
62 }
63 
64 /// Parses an unencrypted PKCS#8 private key, verifies that it is the right type
65 /// of key, and returns the key value.
66 ///
67 /// PKCS#8 is specified in [RFC 5958].
68 ///
69 /// [RFC 5958]: https://tools.ietf.org/html/rfc5958.
unwrap_key<'a>( template: &Template, version: Version, input: untrusted::Input<'a>, ) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected>70 pub(crate) fn unwrap_key<'a>(
71     template: &Template,
72     version: Version,
73     input: untrusted::Input<'a>,
74 ) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected> {
75     unwrap_key_(template.alg_id_value(), version, input)
76 }
77 
78 /// Parses an unencrypted PKCS#8 private key, verifies that it is the right type
79 /// of key, and returns the key value.
80 ///
81 /// `alg_id` must be the encoded value (not including the outermost `SEQUENCE`
82 /// tag and length) of the `AlgorithmIdentifier` that identifies the key type.
83 /// The result will be an encoded `RSAPrivateKey` or `ECPrivateKey` or similar.
84 ///
85 /// PKCS#8 is specified in [RFC 5958].
86 ///
87 /// [RFC 5958]: https://tools.ietf.org/html/rfc5958.
unwrap_key_<'a>( alg_id: untrusted::Input, version: Version, input: untrusted::Input<'a>, ) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected>88 pub(crate) fn unwrap_key_<'a>(
89     alg_id: untrusted::Input,
90     version: Version,
91     input: untrusted::Input<'a>,
92 ) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected> {
93     input.read_all(error::KeyRejected::invalid_encoding(), |input| {
94         der::nested(
95             input,
96             der::Tag::Sequence,
97             error::KeyRejected::invalid_encoding(),
98             |input| unwrap_key__(alg_id, version, input),
99         )
100     })
101 }
102 
unwrap_key__<'a>( alg_id: untrusted::Input, version: Version, input: &mut untrusted::Reader<'a>, ) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected>103 fn unwrap_key__<'a>(
104     alg_id: untrusted::Input,
105     version: Version,
106     input: &mut untrusted::Reader<'a>,
107 ) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected> {
108     let actual_version = der::small_nonnegative_integer(input)
109         .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
110 
111     // Do things in a specific order to return more useful errors:
112     // 1. Check for completely unsupported version.
113     // 2. Check for algorithm mismatch.
114     // 3. Check for algorithm-specific version mismatch.
115 
116     if actual_version > 1 {
117         return Err(error::KeyRejected::version_not_supported());
118     };
119 
120     let actual_alg_id = der::expect_tag_and_get_value(input, der::Tag::Sequence)
121         .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
122     if actual_alg_id != alg_id {
123         return Err(error::KeyRejected::wrong_algorithm());
124     }
125 
126     let require_public_key = match (actual_version, version) {
127         (0, Version::V1Only) => false,
128         (0, Version::V1OrV2) => false,
129         (1, Version::V1OrV2) | (1, Version::V2Only) => true,
130         _ => {
131             return Err(error::KeyRejected::version_not_supported());
132         }
133     };
134 
135     let private_key = der::expect_tag_and_get_value(input, der::Tag::OctetString)
136         .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
137 
138     // Ignore any attributes that are present.
139     if input.peek(der::Tag::ContextSpecificConstructed0 as u8) {
140         let _ = der::expect_tag_and_get_value(input, der::Tag::ContextSpecificConstructed0)
141             .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
142     }
143 
144     let public_key = if require_public_key {
145         if input.at_end() {
146             return Err(error::KeyRejected::public_key_is_missing());
147         }
148         let public_key = der::nested(
149             input,
150             der::Tag::ContextSpecificConstructed1,
151             error::Unspecified,
152             der::bit_string_with_no_unused_bits,
153         )
154         .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
155         Some(public_key)
156     } else {
157         None
158     };
159 
160     Ok((private_key, public_key))
161 }
162 
163 /// A generated PKCS#8 document.
164 pub struct Document {
165     bytes: [u8; ec::PKCS8_DOCUMENT_MAX_LEN],
166     len: usize,
167 }
168 
169 impl AsRef<[u8]> for Document {
170     #[inline]
as_ref(&self) -> &[u8]171     fn as_ref(&self) -> &[u8] {
172         &self.bytes[..self.len]
173     }
174 }
175 
wrap_key(template: &Template, private_key: &[u8], public_key: &[u8]) -> Document176 pub(crate) fn wrap_key(template: &Template, private_key: &[u8], public_key: &[u8]) -> Document {
177     let mut result = Document {
178         bytes: [0; ec::PKCS8_DOCUMENT_MAX_LEN],
179         len: template.bytes.len() + private_key.len() + public_key.len(),
180     };
181     wrap_key_(
182         template,
183         private_key,
184         public_key,
185         &mut result.bytes[..result.len],
186     );
187     result
188 }
189 
190 /// Formats a private key "prefix||private_key||middle||public_key" where
191 /// `template` is "prefix||middle" split at position `private_key_index`.
wrap_key_(template: &Template, private_key: &[u8], public_key: &[u8], bytes: &mut [u8])192 fn wrap_key_(template: &Template, private_key: &[u8], public_key: &[u8], bytes: &mut [u8]) {
193     let (before_private_key, after_private_key) =
194         template.bytes.split_at(template.private_key_index);
195     let private_key_end_index = template.private_key_index + private_key.len();
196     bytes[..template.private_key_index].copy_from_slice(before_private_key);
197     bytes[template.private_key_index..private_key_end_index].copy_from_slice(&private_key);
198     bytes[private_key_end_index..(private_key_end_index + after_private_key.len())]
199         .copy_from_slice(after_private_key);
200     bytes[(private_key_end_index + after_private_key.len())..].copy_from_slice(public_key);
201 }
202