1use crate::{ec, error, io::der};
20
21pub(crate) struct PublicKeyOptions {
22 pub accept_legacy_ed25519_public_key_tag: bool,
25}
26
27pub(crate) enum Version {
28 V1Only,
29 V1OrV2(PublicKeyOptions),
30 V2Only(PublicKeyOptions),
31}
32
33pub(crate) struct Template {
37 pub bytes: &'static [u8],
38
39 pub alg_id_range: core::ops::Range<usize>,
42
43 pub curve_id_index: usize,
46
47 pub private_key_index: usize,
52}
53
54impl Template {
55 #[inline]
56 fn alg_id_value(&self) -> untrusted::Input {
57 untrusted::Input::from(self.alg_id_value_())
58 }
59
60 fn alg_id_value_(&self) -> &[u8] {
61 &self.bytes[self.alg_id_range.start..self.alg_id_range.end]
62 }
63
64 #[inline]
65 pub fn curve_oid(&self) -> untrusted::Input {
66 untrusted::Input::from(&self.alg_id_value_()[self.curve_id_index..])
67 }
68}
69
70pub(crate) fn unwrap_key<'a>(
77 template: &Template,
78 version: Version,
79 input: untrusted::Input<'a>,
80) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected> {
81 unwrap_key_(template.alg_id_value(), version, input)
82}
83
84pub(crate) fn unwrap_key_<'a>(
95 alg_id: untrusted::Input,
96 version: Version,
97 input: untrusted::Input<'a>,
98) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected> {
99 input.read_all(error::KeyRejected::invalid_encoding(), |input| {
100 der::nested(
101 input,
102 der::Tag::Sequence,
103 error::KeyRejected::invalid_encoding(),
104 |input| unwrap_key__(alg_id, version, input),
105 )
106 })
107}
108
109fn unwrap_key__<'a>(
110 alg_id: untrusted::Input,
111 version: Version,
112 input: &mut untrusted::Reader<'a>,
113) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected> {
114 let actual_version = der::small_nonnegative_integer(input)
115 .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
116
117 if actual_version > 1 {
123 return Err(error::KeyRejected::version_not_supported());
124 };
125
126 let actual_alg_id = der::expect_tag_and_get_value(input, der::Tag::Sequence)
127 .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
128 if actual_alg_id.as_slice_less_safe() != alg_id.as_slice_less_safe() {
129 return Err(error::KeyRejected::wrong_algorithm());
130 }
131
132 let public_key_options = match (actual_version, version) {
133 (0, Version::V1Only) => None,
134 (0, Version::V1OrV2(_)) => None,
135 (1, Version::V1OrV2(options)) | (1, Version::V2Only(options)) => Some(options),
136 _ => {
137 return Err(error::KeyRejected::version_not_supported());
138 }
139 };
140
141 let private_key = der::expect_tag_and_get_value(input, der::Tag::OctetString)
142 .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
143
144 if input.peek(der::Tag::ContextSpecificConstructed0 as u8) {
146 let _ = der::expect_tag_and_get_value(input, der::Tag::ContextSpecificConstructed0)
147 .map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
148 }
149
150 let public_key = if let Some(options) = public_key_options {
151 if input.at_end() {
152 return Err(error::KeyRejected::public_key_is_missing());
153 }
154
155 const INCORRECT_LEGACY: der::Tag = der::Tag::ContextSpecificConstructed1;
156 let result =
157 if options.accept_legacy_ed25519_public_key_tag && input.peek(INCORRECT_LEGACY as u8) {
158 der::nested(
159 input,
160 INCORRECT_LEGACY,
161 error::Unspecified,
162 der::bit_string_with_no_unused_bits,
163 )
164 } else {
165 der::bit_string_tagged_with_no_unused_bits(der::Tag::ContextSpecific1, input)
166 };
167 let public_key =
168 result.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
169 Some(public_key)
170 } else {
171 None
172 };
173
174 Ok((private_key, public_key))
175}
176
177pub struct Document {
179 bytes: [u8; ec::PKCS8_DOCUMENT_MAX_LEN],
180 len: usize,
181}
182
183impl AsRef<[u8]> for Document {
184 #[inline]
185 fn as_ref(&self) -> &[u8] {
186 &self.bytes[..self.len]
187 }
188}
189
190pub(crate) fn wrap_key(template: &Template, private_key: &[u8], public_key: &[u8]) -> Document {
191 let mut result = Document {
192 bytes: [0; ec::PKCS8_DOCUMENT_MAX_LEN],
193 len: template.bytes.len() + private_key.len() + public_key.len(),
194 };
195 wrap_key_(
196 template,
197 private_key,
198 public_key,
199 &mut result.bytes[..result.len],
200 );
201 result
202}
203
204fn wrap_key_(template: &Template, private_key: &[u8], public_key: &[u8], bytes: &mut [u8]) {
207 let (before_private_key, after_private_key) =
208 template.bytes.split_at(template.private_key_index);
209 let private_key_end_index = template.private_key_index + private_key.len();
210 bytes[..template.private_key_index].copy_from_slice(before_private_key);
211 bytes[template.private_key_index..private_key_end_index].copy_from_slice(private_key);
212 bytes[private_key_end_index..(private_key_end_index + after_private_key.len())]
213 .copy_from_slice(after_private_key);
214 bytes[(private_key_end_index + after_private_key.len())..].copy_from_slice(public_key);
215}