1use crate::{ec, error, io::der};
20
21pub(crate) enum Version {
22 V1Only,
23 V1OrV2,
24 V2Only,
25}
26
27pub(crate) struct Template {
31 pub bytes: &'static [u8],
32
33 pub alg_id_range: core::ops::Range<usize>,
36
37 pub curve_id_index: usize,
40
41 pub private_key_index: usize,
46}
47
48impl Template {
49 #[inline]
50 fn alg_id_value(&self) -> untrusted::Input {
51 untrusted::Input::from(self.alg_id_value_())
52 }
53
54 fn alg_id_value_(&self) -> &[u8] {
55 &self.bytes[self.alg_id_range.start..self.alg_id_range.end]
56 }
57
58 #[inline]
59 pub fn curve_oid(&self) -> untrusted::Input {
60 untrusted::Input::from(&self.alg_id_value_()[self.curve_id_index..])
61 }
62}
63
64pub(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
78pub(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
103fn 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 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 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
163pub struct Document {
165 bytes: [u8; ec::PKCS8_DOCUMENT_MAX_LEN],
166 len: usize,
167}
168
169impl AsRef<[u8]> for Document {
170 #[inline]
171 fn as_ref(&self) -> &[u8] {
172 &self.bytes[..self.len]
173 }
174}
175
176pub(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
190fn 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}