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