1use crate::{ContentInfo, Error, ErrorCode, Octets, Result, SignedData};
10use crate::{attribute::Attribute, enveloped::EncodedValue, signer::required};
11use structured_asn1::memory::{OwnedVec, Work};
12use structured_asn1::{Element, Integer, Oid, Reader, Tag, universal};
13use structured_pkix::AlgorithmIdentifier;
14
15mod process;
16pub mod protection;
17pub use process::{
18 Backend, Cause, Decision, Failure, Fragments, Origin, Plaintext, Source, legacy_password,
19 process,
20};
21
22const FIELD: &str = "personal";
23const DATA: Oid<'static> = Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 7, 1]);
24const SIGNED: Oid<'static> = Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 7, 2]);
25const ENCRYPTED: Oid<'static> = Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 7, 6]);
26
27pub enum Integrity<'a> {
29 Password {
31 safe: Octets<'a>,
33 mac: Option<MacData<'a>>,
35 },
36 Signed(SignedData<'a>),
38}
39
40pub struct Pfx<'a> {
42 integrity: Integrity<'a>,
43 original: EncodedValue<'a>,
44}
45impl<'a> Pfx<'a> {
46 pub fn read(parent: &mut Reader<'a>) -> Result<Self> {
48 let element = required(parent, FIELD)?;
49 let value = Self::read_element(parent, &element)?;
50 end(parent)?;
51 Ok(value)
52 }
53 pub fn read_element(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
55 let mut inside = sequence(parent, element)?;
56 let version = number(&mut inside)?;
57 if version.as_u64() != Some(3) {
58 return Err(invalid(ErrorCode::UnsupportedVersion, element));
59 }
60 let envelope = required(&mut inside, FIELD)?;
61 let (info, reader) = ContentInfo::read_element(&inside, &envelope)?;
62 let mac = inside
63 .next_element()
64 .map_err(encoding)?
65 .map(|value| MacData::read(&inside, &value))
66 .transpose()?;
67 end(&inside)?;
68 let integrity = if equal_oid(&inside, info.kind(), DATA)? {
69 Integrity::Password {
70 safe: Octets::read(&reader, info.content(), FIELD)?,
71 mac,
72 }
73 } else if equal_oid(&inside, info.kind(), SIGNED)? {
74 if mac.is_some() {
77 return Err(invalid(ErrorCode::FieldOrder, element));
78 }
79 let signed = SignedData::read_element(&reader, info.content())?;
80 if !equal_oid(&reader, signed.content().kind(), DATA)? {
81 return Err(invalid(ErrorCode::UnexpectedContentType, info.content()));
82 }
83 if signed.content().content().is_none() {
84 return Err(invalid(ErrorCode::DetachedContent, info.content()));
85 }
86 Integrity::Signed(signed)
87 } else {
88 return Err(invalid(ErrorCode::UnexpectedContentType, &envelope));
89 };
90 Ok(Self {
91 integrity,
92 original: EncodedValue::new(parent, *element),
93 })
94 }
95 #[must_use]
97 pub fn original(&self) -> &EncodedValue<'a> {
98 &self.original
99 }
100 #[must_use]
102 pub fn integrity(&self) -> &Integrity<'a> {
103 &self.integrity
104 }
105 pub(crate) fn safe(&self) -> &Octets<'a> {
106 match &self.integrity {
107 Integrity::Password { safe, .. } => safe,
108 Integrity::Signed(signed) => signed.content().content().expect("checked attached PFX"),
109 }
110 }
111}
112
113pub struct MacData<'a> {
115 pub algorithm: AlgorithmIdentifier<'a>,
117 pub digest: Octets<'a>,
119 pub salt: Octets<'a>,
121 pub iterations: Option<Integer<'a>>,
124 pub pbmac1: Option<protection::Pair<'a>>,
126}
127impl<'a> MacData<'a> {
128 pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
130 let mut inside = sequence(parent, element)?;
131 let digest_info = required(&mut inside, FIELD)?;
132 let mut digest_info = sequence(&inside, &digest_info)?;
133 let algorithm = algorithm(&mut digest_info)?;
134 let value = required(&mut digest_info, FIELD)?;
135 let digest = Octets::read(&digest_info, &value, FIELD)?;
136 end(&digest_info)?;
137 let value = required(&mut inside, FIELD)?;
138 let salt = Octets::read(&inside, &value, FIELD)?;
139 let iterations = if inside.is_empty() {
140 None
141 } else {
142 Some(number(&mut inside)?)
143 };
144 end(&inside)?;
145 if let Some(rounds) = iterations {
148 default_one(parent, rounds, element)?;
149 }
150 let pbmac1 = if equal_oid(parent, algorithm.algorithm(), protection::PBMAC1)? {
151 let pair = protection::Pair::read(algorithm, parent)?;
152 if let Some(width) = protection::hmac_width(pair.scheme, parent)?
153 && digest.len() != width
154 {
155 return Err(invalid(ErrorCode::DigestWidth, element));
156 }
157 if let Some(kdf) = pair.pbkdf2.as_ref()
158 && kdf.key_length.is_none()
159 {
160 return Err(invalid(ErrorCode::MissingField, element));
161 }
162 Some(pair)
163 } else {
164 match structured_pkix::algorithm::digest::algorithm(&algorithm, &parent.execution())
165 .map_err(Error::pkix)?
166 {
167 structured_asn1::digest::Resolution::Supported(hash)
168 if digest.len() != hash.width() =>
169 {
170 return Err(invalid(ErrorCode::DigestWidth, element));
171 }
172 structured_asn1::digest::Resolution::Malformed => {
173 return Err(invalid(ErrorCode::AlgorithmSyntax, element));
174 }
175 _ => {}
176 }
177 if let Some(rounds) = iterations {
178 positive(rounds, element)?;
179 }
180 None
181 };
182 Ok(Self {
183 algorithm,
184 digest,
185 salt,
186 iterations,
187 pbmac1,
188 })
189 }
190}
191
192pub enum Safe<'a> {
194 Data(Octets<'a>),
196 Encrypted(EncryptedData<'a>),
198 Enveloped(crate::enveloped::EnvelopedData<'a>),
200 Other {
202 kind: Oid<'a>,
204 value: EncodedValue<'a>,
206 },
207}
208impl<'a> Safe<'a> {
209 pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
211 let (info, reader) = ContentInfo::read_element(parent, element)?;
212 if equal_oid(parent, info.kind(), DATA)? {
213 Ok(Self::Data(Octets::read(&reader, info.content(), FIELD)?))
214 } else if equal_oid(parent, info.kind(), ENCRYPTED)? {
215 Ok(Self::Encrypted(EncryptedData::read(
216 &reader,
217 info.content(),
218 )?))
219 } else if equal_oid(parent, info.kind(), crate::enveloped::IDENTIFIER)? {
220 Ok(Self::Enveloped(
221 crate::enveloped::EnvelopedData::read_element(&reader, info.content())?,
222 ))
223 } else {
224 Ok(Self::Other {
225 kind: info.kind(),
226 value: EncodedValue::new(&reader, *info.content()),
227 })
228 }
229 }
230}
231
232pub struct EncryptedData<'a> {
234 pub content: crate::enveloped::EncryptedContent<'a>,
236 pub attributes: Option<OwnedVec<Attribute<'a>>>,
238 pub protection: protection::Protection<'a>,
240}
241impl<'a> EncryptedData<'a> {
242 pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
244 let mut inside = sequence(parent, element)?;
245 let version = number(&mut inside)?;
246 let info = required(&mut inside, FIELD)?;
247 let content = crate::enveloped::encrypted_content(&inside, &info)?;
248 let attributes = inside
249 .next_element()
250 .map_err(encoding)?
251 .map(|set| attributes(&inside, &set, Tag::context(true, 1)))
252 .transpose()?;
253 end(&inside)?;
254 if version.as_u64() != Some(if attributes.is_some() { 2 } else { 0 }) {
255 return Err(invalid(ErrorCode::VersionMismatch, element));
256 }
257 if attributes.as_ref().is_some_and(|a| a.is_empty()) {
258 return Err(invalid(ErrorCode::EmptyAttributes, element));
259 }
260 let protection = protection::Protection::read(content.algorithm, parent)?;
261 Ok(Self {
262 content,
263 attributes,
264 protection,
265 })
266 }
267}
268
269pub struct PrivateKey<'a> {
271 pub version: u64,
273 pub algorithm: AlgorithmIdentifier<'a>,
275 pub secret: Octets<'a>,
277 pub attributes: Option<OwnedVec<Attribute<'a>>>,
279 pub public_key: Option<EncodedValue<'a>>,
281}
282impl<'a> PrivateKey<'a> {
283 pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
285 let mut inside = sequence(parent, element)?;
286 let version = number(&mut inside)?
287 .as_u64()
288 .ok_or_else(|| invalid(ErrorCode::ValueTooLarge, element))?;
289 let algorithm = algorithm(&mut inside)?;
290 let value = required(&mut inside, FIELD)?;
291 let secret = Octets::read(&inside, &value, FIELD)?;
292 let mut next = inside.next_element().map_err(encoding)?;
293 let attributes = if let Some(set) = next.filter(|v| v.tag() == Tag::context(true, 0)) {
294 let attributes = attributes(&inside, &set, Tag::context(true, 0))?;
295 next = inside.next_element().map_err(encoding)?;
296 Some(attributes)
297 } else {
298 None
299 };
300 let public_key = if let Some(bits) = next {
301 if bits.tag() != Tag::context(false, 1) && bits.tag() != Tag::context(true, 1) {
302 return Err(invalid(ErrorCode::UnexpectedTag, &bits));
303 }
304 structured_pkix::der::implicit_bit_string(&inside, &bits, FIELD)
305 .map_err(Error::pkix)?;
306 Some(EncodedValue::new(&inside, bits))
307 } else {
308 None
309 };
310 end(&inside)?;
311 if version != u64::from(public_key.is_some()) {
312 return Err(invalid(ErrorCode::VersionMismatch, element));
313 }
314 Ok(Self {
315 version,
316 algorithm,
317 secret,
318 attributes,
319 public_key,
320 })
321 }
322}
323
324pub struct ShroudedKey<'a> {
326 pub algorithm: AlgorithmIdentifier<'a>,
328 pub encrypted: Octets<'a>,
330 pub protection: protection::Protection<'a>,
332}
333impl<'a> ShroudedKey<'a> {
334 pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
336 let mut inside = sequence(parent, element)?;
337 let algorithm = algorithm(&mut inside)?;
338 let value = required(&mut inside, FIELD)?;
339 let encrypted = Octets::read(&inside, &value, FIELD)?;
340 end(&inside)?;
341 let protection = protection::Protection::read(algorithm, parent)?;
342 Ok(Self {
343 algorithm,
344 encrypted,
345 protection,
346 })
347 }
348}
349
350#[expect(
352 clippy::large_enum_variant,
353 reason = "one bag is decoded/visited at a time; inline protection facts avoid an extra heap owner per shrouded key"
354)]
355pub enum BagValue<'a> {
356 Key(PrivateKey<'a>),
358 Shrouded(ShroudedKey<'a>),
360 Certificate(Octets<'a>),
362 Sdsi(Octets<'a>),
364 Crl(Octets<'a>),
366 Secret {
368 kind: Oid<'a>,
370 value: EncodedValue<'a>,
372 },
373 Other {
375 kind: Oid<'a>,
377 value: EncodedValue<'a>,
379 },
380 Contents(EncodedValue<'a>),
382}
383pub struct Bag<'a> {
385 pub kind: Oid<'a>,
387 pub original: EncodedValue<'a>,
389 pub value: BagValue<'a>,
391 pub attributes: Option<OwnedVec<Attribute<'a>>>,
393}
394impl<'a> Bag<'a> {
395 pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
398 let mut inside = sequence(parent, element)?;
399 let kind = inside.read_oid().map_err(encoding)?;
400 let wrapper = inside.expect(Tag::context(true, 0)).map_err(encoding)?;
401 let mut explicit = inside.enter(&wrapper).map_err(encoding)?;
402 let value = required(&mut explicit, FIELD)?;
403 end(&explicit)?;
404 let attributes = inside
405 .next_element()
406 .map_err(encoding)?
407 .map(|set| attributes(&inside, &set, Tag::constructed(universal::SET)))
408 .transpose()?;
409 end(&inside)?;
410 let value = if bag_id(parent, kind, 1)? {
412 BagValue::Key(PrivateKey::read(&explicit, &value)?)
413 } else if bag_id(parent, kind, 2)? {
414 BagValue::Shrouded(ShroudedKey::read(&explicit, &value)?)
415 } else if bag_id(parent, kind, 6)? {
416 tag(&value, Tag::constructed(universal::SEQUENCE))?;
417 BagValue::Contents(EncodedValue::new(&explicit, value))
418 } else if bag_id(parent, kind, 3)? || bag_id(parent, kind, 4)? || bag_id(parent, kind, 5)? {
419 let mut typed = sequence(&explicit, &value)?;
420 let inner_kind = typed.read_oid().map_err(encoding)?;
421 let wrapper = typed.expect(Tag::context(true, 0)).map_err(encoding)?;
422 let mut inner = typed.enter(&wrapper).map_err(encoding)?;
423 let content = required(&mut inner, FIELD)?;
424 end(&inner)?;
425 end(&typed)?;
426 let certificate = Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 9, 22, 1]);
427 let sdsi = Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 9, 22, 2]);
428 let crl = Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 9, 23, 1]);
429 if bag_id(parent, kind, 5)? {
430 structured_pkix::der::conforms(&inner, &content, FIELD).map_err(Error::pkix)?;
431 BagValue::Secret {
432 kind: inner_kind,
433 value: EncodedValue::new(&inner, content),
434 }
435 } else if bag_id(parent, kind, 3)? && equal_oid(parent, inner_kind, certificate)? {
436 BagValue::Certificate(Octets::read(&inner, &content, FIELD)?)
437 } else if bag_id(parent, kind, 3)? && equal_oid(parent, inner_kind, sdsi)? {
438 BagValue::Sdsi(Octets::read_ia5(&inner, &content, FIELD)?)
439 } else if bag_id(parent, kind, 4)? && equal_oid(parent, inner_kind, crl)? {
440 BagValue::Crl(Octets::read(&inner, &content, FIELD)?)
441 } else {
442 structured_pkix::der::conforms(&inner, &content, FIELD).map_err(Error::pkix)?;
443 BagValue::Other {
444 kind: inner_kind,
445 value: EncodedValue::new(&inner, content),
446 }
447 }
448 } else {
449 structured_pkix::der::conforms(&explicit, &value, FIELD).map_err(Error::pkix)?;
450 BagValue::Other {
451 kind,
452 value: EncodedValue::new(&explicit, value),
453 }
454 };
455 Ok(Self {
456 kind,
457 original: EncodedValue::new(parent, *element),
458 value,
459 attributes,
460 })
461 }
462}
463
464fn bag_id(parent: &Reader<'_>, oid: Oid<'_>, last: u8) -> Result<bool> {
465 equal_oid(
466 parent,
467 oid,
468 Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 12, 10, 1, last]),
469 )
470}
471pub(super) fn equal_oid(parent: &Reader<'_>, left: Oid<'_>, right: Oid<'_>) -> Result<bool> {
472 parent.charge(1).map_err(encoding)?;
473 if left.as_bytes().len() != right.as_bytes().len() {
474 return Ok(false);
475 }
476 parent
477 .charge(left.as_bytes().len() as u64)
478 .map_err(encoding)?;
479 Ok(left == right)
480}
481fn attributes<'a>(
482 parent: &Reader<'a>,
483 set: &Element<'a>,
484 expected: Tag,
485) -> Result<OwnedVec<Attribute<'a>>> {
486 tag(set, expected)?;
487 let mut inside = parent.enter(set).map_err(encoding)?;
488 let execution = parent.execution();
489 let mut out = execution.vector();
490 let mut previous = None;
491 while let Some(value) = inside.next_element().map_err(encoding)? {
492 if inside.encoding().is_der() {
493 if let Some(bytes) = previous
494 && !structured_pkix::der::set_ordered(&inside, bytes, &value, FIELD)
495 .map_err(Error::pkix)?
496 {
497 return Err(invalid(ErrorCode::SetOrder, &value));
498 }
499 previous = Some(value.as_bytes());
500 }
501 let attribute = Attribute::read(&inside, &value, FIELD)?;
502 if !inside.encoding().is_der() {
506 for (ordinal, item) in attribute.values().iter().enumerate() {
507 let reader = attribute
508 .value_reader_in(ordinal, &inside, FIELD)?
509 .expect("ordinal comes from this attribute's original values");
510 structured_pkix::der::conforms(&reader, item, FIELD).map_err(Error::pkix)?;
511 }
512 }
513 out.try_push(attribute)
514 .map_err(|e| Error::resource(e, FIELD, value.span().start))?;
515 }
516 Ok(out.into_owned())
517}
518pub(super) fn sequence<'a>(parent: &Reader<'a>, element: &Element<'a>) -> Result<Reader<'a>> {
519 tag(element, Tag::constructed(universal::SEQUENCE))?;
520 parent.enter(element).map_err(encoding)
521}
522pub(super) fn tag(element: &Element<'_>, expected: Tag) -> Result<()> {
523 if element.tag() != expected {
524 return Err(invalid(ErrorCode::UnexpectedTag, element));
525 }
526 Ok(())
527}
528pub(super) fn end(parent: &Reader<'_>) -> Result<()> {
529 if !parent.is_empty() {
530 return Err(Error::schema(
531 ErrorCode::TrailingData,
532 FIELD,
533 parent.offset(),
534 ));
535 }
536 Ok(())
537}
538pub(super) fn number<'a>(parent: &mut Reader<'a>) -> Result<Integer<'a>> {
539 parent.read_integer().map_err(encoding)
540}
541pub(super) fn positive(value: Integer<'_>, element: &Element<'_>) -> Result<()> {
542 if value.is_negative() || value.as_u64() == Some(0) {
543 return Err(invalid(ErrorCode::MalformedValue, element));
544 }
545 Ok(())
546}
547fn default_one(parent: &Reader<'_>, value: Integer<'_>, element: &Element<'_>) -> Result<()> {
548 if parent.encoding().is_der() && value.as_u64() == Some(1) {
549 return Err(invalid(ErrorCode::DefaultWritten, element));
550 }
551 Ok(())
552}
553pub(super) fn algorithm<'a>(parent: &mut Reader<'a>) -> Result<AlgorithmIdentifier<'a>> {
554 let element = required(parent, FIELD)?;
555 structured_pkix::algorithm::read(parent, &element, FIELD).map_err(Error::pkix)
556}
557pub(super) fn invalid(code: ErrorCode, element: &Element<'_>) -> Error {
558 Error::schema(code, FIELD, element.span().start)
559}
560pub(super) fn encoding(error: structured_asn1::Error) -> Error {
561 Error::encoding(error, FIELD)
562}