apple_codesign/
code_requirement.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5/*! Code requirement language primitives.
6
7Code signatures contain a binary encoded expression tree denoting requirements.
8There is a human friendly DSL that can be turned into these binary expressions
9using the `csreq` Apple tool. This module reimplements that language.
10
11# Binary Encoding
12
13Requirement expressions consist of opcodes. An opcode is defined by a u32 where
14the high byte contains flags and the lower 3 bytes denote the opcode value.
15
16Some opcodes have payloads and the payload varies by opcode. A common pattern
17is to length encode arbitrary data via a u32 denoting the length and N bytes
18to follow.
19
20String data is not guaranteed to be terminated by a NULL. However, variable
21length data is padded will NULL bytes so the next opcode is always aligned
22on 4 byte boundaries.
23
24*/
25
26use {
27    crate::{
28        embedded_signature::{
29            read_and_validate_blob_header, CodeSigningMagic, RequirementBlob, RequirementSetBlob,
30        },
31        error::AppleCodesignError,
32    },
33    bcder::Oid,
34    chrono::TimeZone,
35    scroll::{IOwrite, Pread},
36    std::{
37        borrow::Cow,
38        cmp::Ordering,
39        fmt::{Debug, Display},
40        io::Write,
41        ops::{Deref, DerefMut},
42    },
43};
44
45const OPCODE_FLAG_MASK: u32 = 0xff000000;
46const OPCODE_VALUE_MASK: u32 = 0x00ffffff;
47
48/// Opcode flag meaning has size field, okay to default to false.
49#[allow(unused)]
50const OPCODE_FLAG_DEFAULT_FALSE: u32 = 0x80000000;
51
52/// Opcode flag meaning has size field, skip and continue.
53#[allow(unused)]
54const OPCODE_FLAG_SKIP: u32 = 0x40000000;
55
56/// Denotes type of code requirements.
57#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
58#[repr(u32)]
59pub enum RequirementType {
60    /// What hosts may run on us.
61    Host,
62    /// What guests we may run.
63    Guest,
64    /// Designated requirement.
65    Designated,
66    /// What libraries we may link against.
67    Library,
68    /// What plug-ins we may load.
69    Plugin,
70    /// Unknown requirement type.
71    Unknown(u32),
72}
73
74impl From<u32> for RequirementType {
75    fn from(v: u32) -> Self {
76        match v {
77            1 => Self::Host,
78            2 => Self::Guest,
79            3 => Self::Designated,
80            4 => Self::Library,
81            5 => Self::Plugin,
82            _ => Self::Unknown(v),
83        }
84    }
85}
86
87impl From<RequirementType> for u32 {
88    fn from(t: RequirementType) -> Self {
89        match t {
90            RequirementType::Host => 1,
91            RequirementType::Guest => 2,
92            RequirementType::Designated => 3,
93            RequirementType::Library => 4,
94            RequirementType::Plugin => 5,
95            RequirementType::Unknown(v) => v,
96        }
97    }
98}
99
100impl PartialOrd for RequirementType {
101    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
102        Some(self.cmp(other))
103    }
104}
105
106impl Ord for RequirementType {
107    fn cmp(&self, other: &Self) -> Ordering {
108        u32::from(*self).cmp(&u32::from(*other))
109    }
110}
111
112impl std::fmt::Display for RequirementType {
113    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114        match self {
115            Self::Host => f.write_str("host(1)"),
116            Self::Guest => f.write_str("guest(2)"),
117            Self::Designated => f.write_str("designated(3)"),
118            Self::Library => f.write_str("library(4)"),
119            Self::Plugin => f.write_str("plugin(5)"),
120            Self::Unknown(v) => f.write_fmt(format_args!("unknown({v})")),
121        }
122    }
123}
124
125fn read_data(data: &[u8]) -> Result<(&[u8], &[u8]), AppleCodesignError> {
126    let length = data.pread_with::<u32>(0, scroll::BE)?;
127    let value = &data[4..4 + length as usize];
128
129    // Next element is aligned on next 4 byte boundary.
130    let offset = 4 + length as usize;
131
132    let offset = match offset % 4 {
133        0 => offset,
134        extra => offset + 4 - extra,
135    };
136
137    let remaining = &data[offset..];
138
139    Ok((value, remaining))
140}
141
142fn write_data(dest: &mut impl Write, data: &[u8]) -> Result<(), AppleCodesignError> {
143    dest.iowrite_with(data.len() as u32, scroll::BE)?;
144    dest.write_all(data)?;
145
146    match data.len() % 4 {
147        0 => {}
148        pad => {
149            for _ in 0..4 - pad {
150                dest.iowrite(0u8)?;
151            }
152        }
153    }
154
155    Ok(())
156}
157
158/// Format a certificate slot's value to human form.
159fn format_certificate_slot(slot: i32) -> String {
160    match slot {
161        -1 => "root".to_string(),
162        0 => "leaf".to_string(),
163        _ => format!("{slot}"),
164    }
165}
166
167/// A value in a code requirement expression.
168///
169/// The value can be various primitive types. This type exists to make it
170/// easier to work with and format values in code requirement expressions.
171#[derive(Clone, Debug, Eq, PartialEq)]
172pub enum CodeRequirementValue<'a> {
173    String(Cow<'a, str>),
174    Bytes(Cow<'a, [u8]>),
175}
176
177impl<'a> From<&'a [u8]> for CodeRequirementValue<'a> {
178    fn from(value: &'a [u8]) -> Self {
179        let is_ascii_printable = |c: &u8| -> bool {
180            c.is_ascii_alphanumeric() || c.is_ascii_whitespace() || c.is_ascii_punctuation()
181        };
182
183        if value.iter().all(is_ascii_printable) {
184            Self::String(unsafe { std::str::from_utf8_unchecked(value) }.into())
185        } else {
186            Self::Bytes(value.into())
187        }
188    }
189}
190
191impl<'a> From<&'a str> for CodeRequirementValue<'a> {
192    fn from(s: &'a str) -> Self {
193        Self::String(s.into())
194    }
195}
196
197impl<'a> From<Cow<'a, str>> for CodeRequirementValue<'a> {
198    fn from(v: Cow<'a, str>) -> Self {
199        Self::String(v)
200    }
201}
202
203impl From<String> for CodeRequirementValue<'static> {
204    fn from(v: String) -> Self {
205        Self::String(Cow::Owned(v))
206    }
207}
208
209impl<'a> Display for CodeRequirementValue<'a> {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        match self {
212            Self::String(s) => f.write_str(s),
213            Self::Bytes(data) => f.write_fmt(format_args!("{}", hex::encode(data))),
214        }
215    }
216}
217
218impl<'a> CodeRequirementValue<'a> {
219    /// Write the encoded version of this value somewhere.
220    ///
221    /// Binary encoding is u32 of length, then raw bytes, then NULL padding to next u32.
222    fn write_encoded(&self, dest: &mut impl Write) -> Result<(), AppleCodesignError> {
223        match self {
224            Self::Bytes(data) => write_data(dest, data),
225            Self::String(s) => write_data(dest, s.as_bytes()),
226        }
227    }
228}
229
230/// An opcode representing a code requirement expression.
231#[derive(Clone, Copy, Debug, PartialEq)]
232#[repr(u32)]
233enum RequirementOpCode {
234    False = 0,
235    True = 1,
236    Identifier = 2,
237    AnchorApple = 3,
238    AnchorCertificateHash = 4,
239    InfoKeyValueLegacy = 5,
240    And = 6,
241    Or = 7,
242    CodeDirectoryHash = 8,
243    Not = 9,
244    InfoPlistExpression = 10,
245    CertificateField = 11,
246    CertificateTrusted = 12,
247    AnchorTrusted = 13,
248    CertificateGeneric = 14,
249    AnchorAppleGeneric = 15,
250    EntitlementsField = 16,
251    CertificatePolicy = 17,
252    NamedAnchor = 18,
253    NamedCode = 19,
254    Platform = 20,
255    Notarized = 21,
256    CertificateFieldDate = 22,
257    LegacyDeveloperId = 23,
258}
259
260impl TryFrom<u32> for RequirementOpCode {
261    type Error = AppleCodesignError;
262
263    fn try_from(v: u32) -> Result<Self, Self::Error> {
264        match v {
265            0 => Ok(Self::False),
266            1 => Ok(Self::True),
267            2 => Ok(Self::Identifier),
268            3 => Ok(Self::AnchorApple),
269            4 => Ok(Self::AnchorCertificateHash),
270            5 => Ok(Self::InfoKeyValueLegacy),
271            6 => Ok(Self::And),
272            7 => Ok(Self::Or),
273            8 => Ok(Self::CodeDirectoryHash),
274            9 => Ok(Self::Not),
275            10 => Ok(Self::InfoPlistExpression),
276            11 => Ok(Self::CertificateField),
277            12 => Ok(Self::CertificateTrusted),
278            13 => Ok(Self::AnchorTrusted),
279            14 => Ok(Self::CertificateGeneric),
280            15 => Ok(Self::AnchorAppleGeneric),
281            16 => Ok(Self::EntitlementsField),
282            17 => Ok(Self::CertificatePolicy),
283            18 => Ok(Self::NamedAnchor),
284            19 => Ok(Self::NamedCode),
285            20 => Ok(Self::Platform),
286            21 => Ok(Self::Notarized),
287            22 => Ok(Self::CertificateFieldDate),
288            23 => Ok(Self::LegacyDeveloperId),
289            _ => Err(AppleCodesignError::RequirementUnknownOpcode(v)),
290        }
291    }
292}
293
294impl RequirementOpCode {
295    /// Parse the payload of an opcode.
296    ///
297    /// On successful parse, returns an [CodeRequirementExpression] and remaining data in
298    /// the input slice.
299    pub fn parse_payload<'a>(
300        &self,
301        data: &'a [u8],
302    ) -> Result<(CodeRequirementExpression<'a>, &'a [u8]), AppleCodesignError> {
303        match self {
304            Self::False => Ok((CodeRequirementExpression::False, data)),
305            Self::True => Ok((CodeRequirementExpression::True, data)),
306            Self::Identifier => {
307                let (value, data) = read_data(data)?;
308                let s = std::str::from_utf8(value).map_err(|_| {
309                    AppleCodesignError::RequirementMalformed("identifier value not a UTF-8 string")
310                })?;
311
312                Ok((CodeRequirementExpression::Identifier(Cow::from(s)), data))
313            }
314            Self::AnchorApple => Ok((CodeRequirementExpression::AnchorApple, data)),
315            Self::AnchorCertificateHash => {
316                let slot = data.pread_with::<i32>(0, scroll::BE)?;
317                let digest_length = data.pread_with::<u32>(4, scroll::BE)?;
318                let digest = &data[8..8 + digest_length as usize];
319
320                Ok((
321                    CodeRequirementExpression::AnchorCertificateHash(slot, digest.into()),
322                    &data[8 + digest_length as usize..],
323                ))
324            }
325            Self::InfoKeyValueLegacy => {
326                let (key, data) = read_data(data)?;
327
328                let key = std::str::from_utf8(key).map_err(|_| {
329                    AppleCodesignError::RequirementMalformed("info key not a UTF-8 string")
330                })?;
331
332                let (value, data) = read_data(data)?;
333
334                let value = std::str::from_utf8(value).map_err(|_| {
335                    AppleCodesignError::RequirementMalformed("info value not a UTF-8 string")
336                })?;
337
338                Ok((
339                    CodeRequirementExpression::InfoKeyValueLegacy(key.into(), value.into()),
340                    data,
341                ))
342            }
343            Self::And => {
344                let (a, data) = CodeRequirementExpression::from_bytes(data)?;
345                let (b, data) = CodeRequirementExpression::from_bytes(data)?;
346
347                Ok((
348                    CodeRequirementExpression::And(Box::new(a), Box::new(b)),
349                    data,
350                ))
351            }
352            Self::Or => {
353                let (a, data) = CodeRequirementExpression::from_bytes(data)?;
354                let (b, data) = CodeRequirementExpression::from_bytes(data)?;
355
356                Ok((
357                    CodeRequirementExpression::Or(Box::new(a), Box::new(b)),
358                    data,
359                ))
360            }
361            Self::CodeDirectoryHash => {
362                let (value, data) = read_data(data)?;
363
364                Ok((
365                    CodeRequirementExpression::CodeDirectoryHash(value.into()),
366                    data,
367                ))
368            }
369            Self::Not => {
370                let (expr, data) = CodeRequirementExpression::from_bytes(data)?;
371
372                Ok((CodeRequirementExpression::Not(Box::new(expr)), data))
373            }
374            Self::InfoPlistExpression => {
375                let (key, data) = read_data(data)?;
376
377                let key = std::str::from_utf8(key).map_err(|_| {
378                    AppleCodesignError::RequirementMalformed("key is not valid UTF-8")
379                })?;
380
381                let (expr, data) = CodeRequirementMatchExpression::from_bytes(data)?;
382
383                Ok((
384                    CodeRequirementExpression::InfoPlistKeyField(key.into(), expr),
385                    data,
386                ))
387            }
388            Self::CertificateField => {
389                let slot = data.pread_with::<i32>(0, scroll::BE)?;
390
391                let (field, data) = read_data(&data[4..])?;
392
393                let field = std::str::from_utf8(field).map_err(|_| {
394                    AppleCodesignError::RequirementMalformed("certificate field is not valid UTF-8")
395                })?;
396
397                let (expr, data) = CodeRequirementMatchExpression::from_bytes(data)?;
398
399                Ok((
400                    CodeRequirementExpression::CertificateField(slot, field.into(), expr),
401                    data,
402                ))
403            }
404            Self::CertificateTrusted => {
405                let slot = data.pread_with::<i32>(0, scroll::BE)?;
406
407                Ok((
408                    CodeRequirementExpression::CertificateTrusted(slot),
409                    &data[4..],
410                ))
411            }
412            Self::AnchorTrusted => Ok((CodeRequirementExpression::AnchorTrusted, data)),
413            Self::CertificateGeneric => {
414                let slot = data.pread_with::<i32>(0, scroll::BE)?;
415
416                let (oid, data) = read_data(&data[4..])?;
417
418                let (expr, data) = CodeRequirementMatchExpression::from_bytes(data)?;
419
420                Ok((
421                    CodeRequirementExpression::CertificateGeneric(slot, Oid(oid), expr),
422                    data,
423                ))
424            }
425            Self::AnchorAppleGeneric => Ok((CodeRequirementExpression::AnchorAppleGeneric, data)),
426            Self::EntitlementsField => {
427                let (key, data) = read_data(data)?;
428
429                let key = std::str::from_utf8(key).map_err(|_| {
430                    AppleCodesignError::RequirementMalformed("entitlement key is not UTF-8")
431                })?;
432
433                let (expr, data) = CodeRequirementMatchExpression::from_bytes(data)?;
434
435                Ok((
436                    CodeRequirementExpression::EntitlementsKey(key.into(), expr),
437                    data,
438                ))
439            }
440            Self::CertificatePolicy => {
441                let slot = data.pread_with::<i32>(0, scroll::BE)?;
442
443                let (oid, data) = read_data(&data[4..])?;
444
445                let (expr, data) = CodeRequirementMatchExpression::from_bytes(data)?;
446
447                Ok((
448                    CodeRequirementExpression::CertificatePolicy(slot, Oid(oid), expr),
449                    data,
450                ))
451            }
452            Self::NamedAnchor => {
453                let (name, data) = read_data(data)?;
454
455                let name = std::str::from_utf8(name).map_err(|_| {
456                    AppleCodesignError::RequirementMalformed("named anchor isn't UTF-8")
457                })?;
458
459                Ok((CodeRequirementExpression::NamedAnchor(name.into()), data))
460            }
461            Self::NamedCode => {
462                let (name, data) = read_data(data)?;
463
464                let name = std::str::from_utf8(name).map_err(|_| {
465                    AppleCodesignError::RequirementMalformed("named code isn't UTF-8")
466                })?;
467
468                Ok((CodeRequirementExpression::NamedCode(name.into()), data))
469            }
470            Self::Platform => {
471                let value = data.pread_with::<u32>(0, scroll::BE)?;
472
473                Ok((CodeRequirementExpression::Platform(value), &data[4..]))
474            }
475            Self::Notarized => Ok((CodeRequirementExpression::Notarized, data)),
476            Self::CertificateFieldDate => {
477                let slot = data.pread_with::<i32>(0, scroll::BE)?;
478
479                let (oid, data) = read_data(&data[4..])?;
480
481                let (expr, data) = CodeRequirementMatchExpression::from_bytes(data)?;
482
483                Ok((
484                    CodeRequirementExpression::CertificateFieldDate(slot, Oid(oid), expr),
485                    data,
486                ))
487            }
488            Self::LegacyDeveloperId => Ok((CodeRequirementExpression::LegacyDeveloperId, data)),
489        }
490    }
491}
492
493/// Defines a code requirement expression.
494#[derive(Clone, Debug, PartialEq)]
495pub enum CodeRequirementExpression<'a> {
496    /// False
497    ///
498    /// `false`
499    ///
500    /// No payload.
501    False,
502
503    /// True
504    ///
505    /// `true`
506    ///
507    /// No payload.
508    True,
509
510    /// Signing identifier.
511    ///
512    /// `identifier <string>`
513    ///
514    /// 4 bytes length followed by C string.
515    Identifier(Cow<'a, str>),
516
517    /// The certificate chain must lead to an Apple root.
518    ///
519    /// `anchor apple`
520    ///
521    /// No payload.
522    AnchorApple,
523
524    /// The certificate chain must anchor to a certificate with specified SHA-1 hash.
525    ///
526    /// `certificate <slot> = H"<hash>"`
527    ///
528    /// 4 bytes slot number, 4 bytes hash length, hash value.
529    AnchorCertificateHash(i32, Cow<'a, [u8]>),
530
531    /// Info.plist key value (legacy).
532    ///
533    /// `info[<key>] = <value>`
534    ///
535    /// 2 pairs of (length + value).
536    InfoKeyValueLegacy(Cow<'a, str>, Cow<'a, str>),
537
538    /// Logical and.
539    ///
540    /// `expr0 and expr1`
541    ///
542    /// Payload consists of 2 sub-expressions with no additional encoding.
543    And(
544        Box<CodeRequirementExpression<'a>>,
545        Box<CodeRequirementExpression<'a>>,
546    ),
547
548    /// Logical or.
549    ///
550    /// `expr0 or expr1`
551    ///
552    /// Payload consists of 2 sub-expressions with no additional encoding.
553    Or(
554        Box<CodeRequirementExpression<'a>>,
555        Box<CodeRequirementExpression<'a>>,
556    ),
557
558    /// Code directory hash.
559    ///
560    /// `cdhash H"<hash>"
561    ///
562    /// 4 bytes length followed by raw digest value.
563    CodeDirectoryHash(Cow<'a, [u8]>),
564
565    /// Logical not.
566    ///
567    /// `!expr`
568    ///
569    /// Payload is 1 sub-expression.
570    Not(Box<CodeRequirementExpression<'a>>),
571
572    /// Info plist key field.
573    ///
574    /// `info [key] match expression`
575    ///
576    /// e.g. `info [CFBundleName] exists`
577    ///
578    /// 4 bytes key length, key string, then match expression.
579    InfoPlistKeyField(Cow<'a, str>, CodeRequirementMatchExpression<'a>),
580
581    /// Certificate field matches.
582    ///
583    /// `certificate <slot> [<field>] match expression`
584    ///
585    /// Slot i32, 4 bytes field length, field string, then match expression.
586    CertificateField(i32, Cow<'a, str>, CodeRequirementMatchExpression<'a>),
587
588    /// Certificate in position is trusted for code signing.
589    ///
590    /// `certificate <position> trusted`
591    ///
592    /// 4 bytes certificate position.
593    CertificateTrusted(i32),
594
595    /// The certificate chain must lead to a trusted root.
596    ///
597    /// `anchor trusted`
598    ///
599    /// No payload.
600    AnchorTrusted,
601
602    /// Certificate field matches by OID.
603    ///
604    /// `certificate <slot> [field.<oid>] match expression`
605    ///
606    /// Slot i32, 4 bytes OID length, OID raw bytes, match expression.
607    CertificateGeneric(i32, Oid<&'a [u8]>, CodeRequirementMatchExpression<'a>),
608
609    /// For code signed by Apple, including from code signing certificates issued by Apple.
610    ///
611    /// `anchor apple generic`
612    ///
613    /// No payload.
614    AnchorAppleGeneric,
615
616    /// Value associated with specified key in signature's embedded entitlements dictionary.
617    ///
618    /// `entitlement [<key>] match expression`
619    ///
620    /// 4 bytes key length, key bytes, match expression.
621    EntitlementsKey(Cow<'a, str>, CodeRequirementMatchExpression<'a>),
622
623    /// OID associated with certificate in a given slot.
624    ///
625    /// It is unknown what the OID means.
626    ///
627    /// `certificate <slot> [policy.<oid>] match expression`
628    CertificatePolicy(i32, Oid<&'a [u8]>, CodeRequirementMatchExpression<'a>),
629
630    /// A named Apple anchor.
631    ///
632    /// `anchor apple <name>`
633    ///
634    /// 4 bytes name length, name bytes.
635    NamedAnchor(Cow<'a, str>),
636
637    /// Named code.
638    ///
639    /// `(<name>)`
640    ///
641    /// 4 bytes name length, name bytes.
642    NamedCode(Cow<'a, str>),
643
644    /// Platform value.
645    ///
646    /// `platform = <value>`
647    ///
648    /// Payload is a u32.
649    Platform(u32),
650
651    /// Binary is notarized.
652    ///
653    /// `notarized`
654    ///
655    /// No Payload.
656    Notarized,
657
658    /// Certificate field date.
659    ///
660    /// Unknown what the OID corresponds to.
661    ///
662    /// `certificate <slot> [timestamp.<oid>] match expression`
663    CertificateFieldDate(i32, Oid<&'a [u8]>, CodeRequirementMatchExpression<'a>),
664
665    /// Legacy developer ID used.
666    LegacyDeveloperId,
667}
668
669impl<'a> Display for CodeRequirementExpression<'a> {
670    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
671        match self {
672            Self::False => f.write_str("never"),
673            Self::True => f.write_str("always"),
674            Self::Identifier(value) => f.write_fmt(format_args!("identifier \"{value}\"")),
675            Self::AnchorApple => f.write_str("anchor apple"),
676            Self::AnchorCertificateHash(slot, digest) => f.write_fmt(format_args!(
677                "certificate {} = H\"{}\"",
678                format_certificate_slot(*slot),
679                hex::encode(digest)
680            )),
681            Self::InfoKeyValueLegacy(key, value) => {
682                f.write_fmt(format_args!("info[{key}] = \"{value}\""))
683            }
684            Self::And(a, b) => f.write_fmt(format_args!("({a}) and ({b})")),
685            Self::Or(a, b) => f.write_fmt(format_args!("({a}) or ({b})")),
686            Self::CodeDirectoryHash(digest) => {
687                f.write_fmt(format_args!("cdhash H\"{}\"", hex::encode(digest)))
688            }
689            Self::Not(expr) => f.write_fmt(format_args!("!({expr})")),
690            Self::InfoPlistKeyField(key, expr) => f.write_fmt(format_args!("info [{key}] {expr}")),
691            Self::CertificateField(slot, field, expr) => f.write_fmt(format_args!(
692                "certificate {}[{}] {}",
693                format_certificate_slot(*slot),
694                field,
695                expr
696            )),
697            Self::CertificateTrusted(slot) => {
698                f.write_fmt(format_args!("certificate {slot} trusted"))
699            }
700            Self::AnchorTrusted => f.write_str("anchor trusted"),
701            Self::CertificateGeneric(slot, oid, expr) => f.write_fmt(format_args!(
702                "certificate {}[field.{}] {}",
703                format_certificate_slot(*slot),
704                oid,
705                expr
706            )),
707            Self::AnchorAppleGeneric => f.write_str("anchor apple generic"),
708            Self::EntitlementsKey(key, expr) => {
709                f.write_fmt(format_args!("entitlement [{key}] {expr}"))
710            }
711            Self::CertificatePolicy(slot, oid, expr) => f.write_fmt(format_args!(
712                "certificate {}[policy.{}] {}",
713                format_certificate_slot(*slot),
714                oid,
715                expr
716            )),
717            Self::NamedAnchor(name) => f.write_fmt(format_args!("anchor apple {name}")),
718            Self::NamedCode(name) => f.write_fmt(format_args!("({name})")),
719            Self::Platform(platform) => f.write_fmt(format_args!("platform = {platform}")),
720            Self::Notarized => f.write_str("notarized"),
721            Self::CertificateFieldDate(slot, oid, expr) => f.write_fmt(format_args!(
722                "certificate {}[timestamp.{}] {}",
723                format_certificate_slot(*slot),
724                oid,
725                expr
726            )),
727            Self::LegacyDeveloperId => f.write_str("legacy"),
728        }
729    }
730}
731
732impl<'a> From<&CodeRequirementExpression<'a>> for RequirementOpCode {
733    fn from(e: &CodeRequirementExpression) -> Self {
734        match e {
735            CodeRequirementExpression::False => RequirementOpCode::False,
736            CodeRequirementExpression::True => RequirementOpCode::True,
737            CodeRequirementExpression::Identifier(_) => RequirementOpCode::Identifier,
738            CodeRequirementExpression::AnchorApple => RequirementOpCode::AnchorApple,
739            CodeRequirementExpression::AnchorCertificateHash(_, _) => {
740                RequirementOpCode::AnchorCertificateHash
741            }
742            CodeRequirementExpression::InfoKeyValueLegacy(_, _) => {
743                RequirementOpCode::InfoKeyValueLegacy
744            }
745            CodeRequirementExpression::And(_, _) => RequirementOpCode::And,
746            CodeRequirementExpression::Or(_, _) => RequirementOpCode::Or,
747            CodeRequirementExpression::CodeDirectoryHash(_) => RequirementOpCode::CodeDirectoryHash,
748            CodeRequirementExpression::Not(_) => RequirementOpCode::Not,
749            CodeRequirementExpression::InfoPlistKeyField(_, _) => {
750                RequirementOpCode::InfoPlistExpression
751            }
752            CodeRequirementExpression::CertificateField(_, _, _) => {
753                RequirementOpCode::CertificateField
754            }
755            CodeRequirementExpression::CertificateTrusted(_) => {
756                RequirementOpCode::CertificateTrusted
757            }
758            CodeRequirementExpression::AnchorTrusted => RequirementOpCode::AnchorTrusted,
759            CodeRequirementExpression::CertificateGeneric(_, _, _) => {
760                RequirementOpCode::CertificateGeneric
761            }
762            CodeRequirementExpression::AnchorAppleGeneric => RequirementOpCode::AnchorAppleGeneric,
763            CodeRequirementExpression::EntitlementsKey(_, _) => {
764                RequirementOpCode::EntitlementsField
765            }
766            CodeRequirementExpression::CertificatePolicy(_, _, _) => {
767                RequirementOpCode::CertificatePolicy
768            }
769            CodeRequirementExpression::NamedAnchor(_) => RequirementOpCode::NamedAnchor,
770            CodeRequirementExpression::NamedCode(_) => RequirementOpCode::NamedCode,
771            CodeRequirementExpression::Platform(_) => RequirementOpCode::Platform,
772            CodeRequirementExpression::Notarized => RequirementOpCode::Notarized,
773            CodeRequirementExpression::CertificateFieldDate(_, _, _) => {
774                RequirementOpCode::CertificateFieldDate
775            }
776            CodeRequirementExpression::LegacyDeveloperId => RequirementOpCode::LegacyDeveloperId,
777        }
778    }
779}
780
781impl<'a> CodeRequirementExpression<'a> {
782    /// Construct an expression element by reading from a slice.
783    ///
784    /// Returns the newly constructed element and remaining data in the slice.
785    pub fn from_bytes(data: &'a [u8]) -> Result<(Self, &'a [u8]), AppleCodesignError> {
786        let opcode_raw = data.pread_with::<u32>(0, scroll::BE)?;
787
788        let _flags = opcode_raw & OPCODE_FLAG_MASK;
789        let opcode = opcode_raw & OPCODE_VALUE_MASK;
790
791        let data = &data[4..];
792
793        let opcode = RequirementOpCode::try_from(opcode)?;
794
795        opcode.parse_payload(data)
796    }
797
798    /// Write binary representation of this expression to a destination.
799    pub fn write_to(&self, dest: &mut impl Write) -> Result<(), AppleCodesignError> {
800        dest.iowrite_with(RequirementOpCode::from(self) as u32, scroll::BE)?;
801
802        match self {
803            Self::False => {}
804            Self::True => {}
805            Self::Identifier(s) => {
806                write_data(dest, s.as_bytes())?;
807            }
808            Self::AnchorApple => {}
809            Self::AnchorCertificateHash(slot, hash) => {
810                dest.iowrite_with(*slot, scroll::BE)?;
811                write_data(dest, hash)?;
812            }
813            Self::InfoKeyValueLegacy(key, value) => {
814                write_data(dest, key.as_bytes())?;
815                write_data(dest, value.as_bytes())?;
816            }
817            Self::And(a, b) => {
818                a.write_to(dest)?;
819                b.write_to(dest)?;
820            }
821            Self::Or(a, b) => {
822                a.write_to(dest)?;
823                b.write_to(dest)?;
824            }
825            Self::CodeDirectoryHash(hash) => {
826                write_data(dest, hash)?;
827            }
828            Self::Not(expr) => {
829                expr.write_to(dest)?;
830            }
831            Self::InfoPlistKeyField(key, m) => {
832                write_data(dest, key.as_bytes())?;
833                m.write_to(dest)?;
834            }
835            Self::CertificateField(slot, field, m) => {
836                dest.iowrite_with(*slot, scroll::BE)?;
837                write_data(dest, field.as_bytes())?;
838                m.write_to(dest)?;
839            }
840            Self::CertificateTrusted(slot) => {
841                dest.iowrite_with(*slot, scroll::BE)?;
842            }
843            Self::AnchorTrusted => {}
844            Self::CertificateGeneric(slot, oid, m) => {
845                dest.iowrite_with(*slot, scroll::BE)?;
846                write_data(dest, oid.as_ref())?;
847                m.write_to(dest)?;
848            }
849            Self::AnchorAppleGeneric => {}
850            Self::EntitlementsKey(key, m) => {
851                write_data(dest, key.as_bytes())?;
852                m.write_to(dest)?;
853            }
854            Self::CertificatePolicy(slot, oid, m) => {
855                dest.iowrite_with(*slot, scroll::BE)?;
856                write_data(dest, oid.as_ref())?;
857                m.write_to(dest)?;
858            }
859            Self::NamedAnchor(value) => {
860                write_data(dest, value.as_bytes())?;
861            }
862            Self::NamedCode(value) => {
863                write_data(dest, value.as_bytes())?;
864            }
865            Self::Platform(value) => {
866                dest.iowrite_with(*value, scroll::BE)?;
867            }
868            Self::Notarized => {}
869            Self::CertificateFieldDate(slot, oid, m) => {
870                dest.iowrite_with(*slot, scroll::BE)?;
871                write_data(dest, oid.as_ref())?;
872                m.write_to(dest)?;
873            }
874            Self::LegacyDeveloperId => {}
875        }
876
877        Ok(())
878    }
879
880    /// Produce the binary serialization of this expression.
881    ///
882    /// The blob header/magic is not included.
883    pub fn to_bytes(&self) -> Result<Vec<u8>, AppleCodesignError> {
884        let mut res = vec![];
885
886        self.write_to(&mut res)?;
887
888        Ok(res)
889    }
890}
891
892/// A code requirement match expression type.
893#[derive(Clone, Copy, Debug, PartialEq)]
894#[repr(u32)]
895enum MatchType {
896    Exists = 0,
897    Equal = 1,
898    Contains = 2,
899    BeginsWith = 3,
900    EndsWith = 4,
901    LessThan = 5,
902    GreaterThan = 6,
903    LessThanEqual = 7,
904    GreaterThanEqual = 8,
905    On = 9,
906    Before = 10,
907    After = 11,
908    OnOrBefore = 12,
909    OnOrAfter = 13,
910    Absent = 14,
911}
912
913impl TryFrom<u32> for MatchType {
914    type Error = AppleCodesignError;
915
916    fn try_from(v: u32) -> Result<Self, Self::Error> {
917        match v {
918            0 => Ok(Self::Exists),
919            1 => Ok(Self::Equal),
920            2 => Ok(Self::Contains),
921            3 => Ok(Self::BeginsWith),
922            4 => Ok(Self::EndsWith),
923            5 => Ok(Self::LessThan),
924            6 => Ok(Self::GreaterThan),
925            7 => Ok(Self::LessThanEqual),
926            8 => Ok(Self::GreaterThanEqual),
927            9 => Ok(Self::On),
928            10 => Ok(Self::Before),
929            11 => Ok(Self::After),
930            12 => Ok(Self::OnOrBefore),
931            13 => Ok(Self::OnOrAfter),
932            14 => Ok(Self::Absent),
933            _ => Err(AppleCodesignError::RequirementUnknownMatchExpression(v)),
934        }
935    }
936}
937
938impl MatchType {
939    /// Parse the payload of a match expression.
940    pub fn parse_payload<'a>(
941        &self,
942        data: &'a [u8],
943    ) -> Result<(CodeRequirementMatchExpression<'a>, &'a [u8]), AppleCodesignError> {
944        match self {
945            Self::Exists => Ok((CodeRequirementMatchExpression::Exists, data)),
946            Self::Equal => {
947                let (value, data) = read_data(data)?;
948
949                Ok((CodeRequirementMatchExpression::Equal(value.into()), data))
950            }
951            Self::Contains => {
952                let (value, data) = read_data(data)?;
953
954                Ok((CodeRequirementMatchExpression::Contains(value.into()), data))
955            }
956            Self::BeginsWith => {
957                let (value, data) = read_data(data)?;
958
959                Ok((
960                    CodeRequirementMatchExpression::BeginsWith(value.into()),
961                    data,
962                ))
963            }
964            Self::EndsWith => {
965                let (value, data) = read_data(data)?;
966
967                Ok((CodeRequirementMatchExpression::EndsWith(value.into()), data))
968            }
969            Self::LessThan => {
970                let (value, data) = read_data(data)?;
971
972                Ok((CodeRequirementMatchExpression::LessThan(value.into()), data))
973            }
974            Self::GreaterThan => {
975                let (value, data) = read_data(data)?;
976
977                Ok((
978                    CodeRequirementMatchExpression::GreaterThan(value.into()),
979                    data,
980                ))
981            }
982            Self::LessThanEqual => {
983                let (value, data) = read_data(data)?;
984
985                Ok((
986                    CodeRequirementMatchExpression::LessThanEqual(value.into()),
987                    data,
988                ))
989            }
990            Self::GreaterThanEqual => {
991                let (value, data) = read_data(data)?;
992
993                Ok((
994                    CodeRequirementMatchExpression::GreaterThanEqual(value.into()),
995                    data,
996                ))
997            }
998            Self::On => {
999                let value = data.pread_with::<i64>(0, scroll::BE)?;
1000
1001                Ok((
1002                    CodeRequirementMatchExpression::On(
1003                        chrono::Utc
1004                            .timestamp_opt(value, 0)
1005                            .single()
1006                            .ok_or(AppleCodesignError::BadTime)?,
1007                    ),
1008                    &data[8..],
1009                ))
1010            }
1011            Self::Before => {
1012                let value = data.pread_with::<i64>(0, scroll::BE)?;
1013
1014                Ok((
1015                    CodeRequirementMatchExpression::Before(
1016                        chrono::Utc
1017                            .timestamp_opt(value, 0)
1018                            .single()
1019                            .ok_or(AppleCodesignError::BadTime)?,
1020                    ),
1021                    &data[8..],
1022                ))
1023            }
1024            Self::After => {
1025                let value = data.pread_with::<i64>(0, scroll::BE)?;
1026
1027                Ok((
1028                    CodeRequirementMatchExpression::After(
1029                        chrono::Utc
1030                            .timestamp_opt(value, 0)
1031                            .single()
1032                            .ok_or(AppleCodesignError::BadTime)?,
1033                    ),
1034                    &data[8..],
1035                ))
1036            }
1037            Self::OnOrBefore => {
1038                let value = data.pread_with::<i64>(0, scroll::BE)?;
1039
1040                Ok((
1041                    CodeRequirementMatchExpression::OnOrBefore(
1042                        chrono::Utc
1043                            .timestamp_opt(value, 0)
1044                            .single()
1045                            .ok_or(AppleCodesignError::BadTime)?,
1046                    ),
1047                    &data[8..],
1048                ))
1049            }
1050            Self::OnOrAfter => {
1051                let value = data.pread_with::<i64>(0, scroll::BE)?;
1052
1053                Ok((
1054                    CodeRequirementMatchExpression::OnOrAfter(
1055                        chrono::Utc
1056                            .timestamp_opt(value, 0)
1057                            .single()
1058                            .ok_or(AppleCodesignError::BadTime)?,
1059                    ),
1060                    &data[8..],
1061                ))
1062            }
1063            Self::Absent => Ok((CodeRequirementMatchExpression::Absent, data)),
1064        }
1065    }
1066}
1067
1068/// An instance of a match expression in a [CodeRequirementExpression].
1069#[derive(Clone, Debug, Eq, PartialEq)]
1070pub enum CodeRequirementMatchExpression<'a> {
1071    /// Entity exists.
1072    ///
1073    /// `exists`
1074    ///
1075    /// No payload.
1076    Exists,
1077
1078    /// Equality.
1079    ///
1080    /// `= <value>`
1081    ///
1082    /// 4 bytes length, raw data.
1083    Equal(CodeRequirementValue<'a>),
1084
1085    /// Contains.
1086    ///
1087    /// `~ <value>`
1088    ///
1089    /// 4 bytes length, raw data.
1090    Contains(CodeRequirementValue<'a>),
1091
1092    /// Begins with.
1093    ///
1094    /// `= <value>*`
1095    ///
1096    /// 4 bytes length, raw data.
1097    BeginsWith(CodeRequirementValue<'a>),
1098
1099    /// Ends with.
1100    ///
1101    /// `= *<value>`
1102    ///
1103    /// 4 bytes length, raw data.
1104    EndsWith(CodeRequirementValue<'a>),
1105
1106    /// Less than.
1107    ///
1108    /// `< <value>`
1109    ///
1110    /// 4 bytes length, raw data.
1111    LessThan(CodeRequirementValue<'a>),
1112
1113    /// Greater than.
1114    ///
1115    /// `> <value>`
1116    GreaterThan(CodeRequirementValue<'a>),
1117
1118    /// Less than or equal to.
1119    ///
1120    /// `<= <value>`
1121    ///
1122    /// 4 bytes length, raw data.
1123    LessThanEqual(CodeRequirementValue<'a>),
1124
1125    /// Greater than or equal to.
1126    ///
1127    /// `>= <value>`
1128    ///
1129    /// 4 bytes length, raw data.
1130    GreaterThanEqual(CodeRequirementValue<'a>),
1131
1132    /// Timestamp value equivalent.
1133    ///
1134    /// `= timestamp "<timestamp>"`
1135    On(chrono::DateTime<chrono::Utc>),
1136
1137    /// Timestamp value before.
1138    ///
1139    /// `< timestamp "<timestamp>"`
1140    Before(chrono::DateTime<chrono::Utc>),
1141
1142    /// Timestamp value after.
1143    ///
1144    /// `> timestamp "<timestamp>"`
1145    After(chrono::DateTime<chrono::Utc>),
1146
1147    /// Timestamp value equivalent or before.
1148    ///
1149    /// `<= timestamp "<timestamp>"`
1150    OnOrBefore(chrono::DateTime<chrono::Utc>),
1151
1152    /// Timestamp value equivalent or after.
1153    ///
1154    /// `>= timestamp "<timestamp>"`
1155    OnOrAfter(chrono::DateTime<chrono::Utc>),
1156
1157    /// Value is absent.
1158    ///
1159    /// `<empty>`
1160    ///
1161    /// No payload.
1162    Absent,
1163}
1164
1165impl<'a> Display for CodeRequirementMatchExpression<'a> {
1166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1167        match self {
1168            Self::Exists => f.write_str("/* exists */"),
1169            Self::Equal(value) => f.write_fmt(format_args!("= \"{value}\"")),
1170            Self::Contains(value) => f.write_fmt(format_args!("~ \"{value}\"")),
1171            Self::BeginsWith(value) => f.write_fmt(format_args!("= \"{value}*\"")),
1172            Self::EndsWith(value) => f.write_fmt(format_args!("= \"*{value}\"")),
1173            Self::LessThan(value) => f.write_fmt(format_args!("< \"{value}\"")),
1174            Self::GreaterThan(value) => f.write_fmt(format_args!("> \"{value}\"")),
1175            Self::LessThanEqual(value) => f.write_fmt(format_args!("<= \"{value}\"")),
1176            Self::GreaterThanEqual(value) => f.write_fmt(format_args!(">= \"{value}\"")),
1177            Self::On(value) => f.write_fmt(format_args!("= \"{value}\"")),
1178            Self::Before(value) => f.write_fmt(format_args!("< \"{value}\"")),
1179            Self::After(value) => f.write_fmt(format_args!("> \"{value}\"")),
1180            Self::OnOrBefore(value) => f.write_fmt(format_args!("<= \"{value}\"")),
1181            Self::OnOrAfter(value) => f.write_fmt(format_args!(">= \"{value}\"")),
1182            Self::Absent => f.write_str("absent"),
1183        }
1184    }
1185}
1186
1187impl<'a> From<&CodeRequirementMatchExpression<'a>> for MatchType {
1188    fn from(m: &CodeRequirementMatchExpression<'a>) -> Self {
1189        match m {
1190            CodeRequirementMatchExpression::Exists => MatchType::Exists,
1191            CodeRequirementMatchExpression::Equal(_) => MatchType::Equal,
1192            CodeRequirementMatchExpression::Contains(_) => MatchType::Contains,
1193            CodeRequirementMatchExpression::BeginsWith(_) => MatchType::BeginsWith,
1194            CodeRequirementMatchExpression::EndsWith(_) => MatchType::EndsWith,
1195            CodeRequirementMatchExpression::LessThan(_) => MatchType::LessThan,
1196            CodeRequirementMatchExpression::GreaterThan(_) => MatchType::GreaterThan,
1197            CodeRequirementMatchExpression::LessThanEqual(_) => MatchType::LessThanEqual,
1198            CodeRequirementMatchExpression::GreaterThanEqual(_) => MatchType::GreaterThanEqual,
1199            CodeRequirementMatchExpression::On(_) => MatchType::On,
1200            CodeRequirementMatchExpression::Before(_) => MatchType::Before,
1201            CodeRequirementMatchExpression::After(_) => MatchType::After,
1202            CodeRequirementMatchExpression::OnOrBefore(_) => MatchType::OnOrBefore,
1203            CodeRequirementMatchExpression::OnOrAfter(_) => MatchType::OnOrAfter,
1204            CodeRequirementMatchExpression::Absent => MatchType::Absent,
1205        }
1206    }
1207}
1208
1209impl<'a> CodeRequirementMatchExpression<'a> {
1210    /// Parse a match expression from bytes.
1211    ///
1212    /// The slice should begin with the match type u32.
1213    pub fn from_bytes(data: &'a [u8]) -> Result<(Self, &'a [u8]), AppleCodesignError> {
1214        let typ = data.pread_with::<u32>(0, scroll::BE)?;
1215
1216        let typ = MatchType::try_from(typ)?;
1217
1218        typ.parse_payload(&data[4..])
1219    }
1220
1221    /// Write binary representation of this match expression to a destination.
1222    pub fn write_to(&self, dest: &mut impl Write) -> Result<(), AppleCodesignError> {
1223        dest.iowrite_with(MatchType::from(self) as u32, scroll::BE)?;
1224
1225        match self {
1226            Self::Exists => {}
1227            Self::Equal(value) => value.write_encoded(dest)?,
1228            Self::Contains(value) => value.write_encoded(dest)?,
1229            Self::BeginsWith(value) => value.write_encoded(dest)?,
1230            Self::EndsWith(value) => value.write_encoded(dest)?,
1231            Self::LessThan(value) => value.write_encoded(dest)?,
1232            Self::GreaterThan(value) => value.write_encoded(dest)?,
1233            Self::LessThanEqual(value) => value.write_encoded(dest)?,
1234            Self::GreaterThanEqual(value) => value.write_encoded(dest)?,
1235            Self::On(value) => dest.iowrite_with(value.timestamp(), scroll::BE)?,
1236            Self::Before(value) => dest.iowrite_with(value.timestamp(), scroll::BE)?,
1237            Self::After(value) => dest.iowrite_with(value.timestamp(), scroll::BE)?,
1238            Self::OnOrBefore(value) => dest.iowrite_with(value.timestamp(), scroll::BE)?,
1239            Self::OnOrAfter(value) => dest.iowrite_with(value.timestamp(), scroll::BE)?,
1240            Self::Absent => {}
1241        }
1242
1243        Ok(())
1244    }
1245}
1246
1247/// Represents a series of [CodeRequirementExpression].
1248#[derive(Clone, Debug, Default, PartialEq)]
1249pub struct CodeRequirements<'a>(Vec<CodeRequirementExpression<'a>>);
1250
1251impl<'a> Deref for CodeRequirements<'a> {
1252    type Target = Vec<CodeRequirementExpression<'a>>;
1253
1254    fn deref(&self) -> &Self::Target {
1255        &self.0
1256    }
1257}
1258
1259impl<'a> DerefMut for CodeRequirements<'a> {
1260    fn deref_mut(&mut self) -> &mut Self::Target {
1261        &mut self.0
1262    }
1263}
1264
1265impl<'a> Display for CodeRequirements<'a> {
1266    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1267        for (i, expr) in self.0.iter().enumerate() {
1268            f.write_fmt(format_args!("{i}: {expr};"))?;
1269        }
1270
1271        Ok(())
1272    }
1273}
1274
1275impl<'a> From<Vec<CodeRequirementExpression<'a>>> for CodeRequirements<'a> {
1276    fn from(v: Vec<CodeRequirementExpression<'a>>) -> Self {
1277        Self(v)
1278    }
1279}
1280
1281impl<'a> CodeRequirements<'a> {
1282    /// Parse the binary serialization of code requirements.
1283    ///
1284    /// This parses the data that follows the requirement blob header/magic that
1285    /// usually accompanies the binary representation of code requirements.
1286    pub fn parse_binary(data: &'a [u8]) -> Result<(Self, &'a [u8]), AppleCodesignError> {
1287        let count = data.pread_with::<u32>(0, scroll::BE)?;
1288        let mut data = &data[4..];
1289
1290        let mut elements = Vec::with_capacity(count as usize);
1291
1292        for _ in 0..count {
1293            let res = CodeRequirementExpression::from_bytes(data)?;
1294
1295            elements.push(res.0);
1296            data = res.1;
1297        }
1298
1299        Ok((Self(elements), data))
1300    }
1301
1302    /// Parse a code requirement blob, which begins with header magic.
1303    ///
1304    /// This can be used to parse the output generated by `csreq -b`.
1305    pub fn parse_blob(data: &'a [u8]) -> Result<(Self, &'a [u8]), AppleCodesignError> {
1306        let data = read_and_validate_blob_header(
1307            data,
1308            u32::from(CodeSigningMagic::Requirement),
1309            "code requirement blob",
1310        )
1311        .map_err(|_| AppleCodesignError::RequirementMalformed("blob header"))?;
1312
1313        Self::parse_binary(data)
1314    }
1315
1316    /// Write binary representation of these expressions to a destination.
1317    ///
1318    /// The blob header/magic is not written.
1319    pub fn write_to(&self, dest: &mut impl Write) -> Result<(), AppleCodesignError> {
1320        dest.iowrite_with(self.0.len() as u32, scroll::BE)?;
1321        for e in &self.0 {
1322            e.write_to(dest)?;
1323        }
1324
1325        Ok(())
1326    }
1327
1328    /// Obtain the blob representation of these expressions.
1329    ///
1330    /// This is like [CodeRequirements.write_to] except it will return an owned Vec
1331    /// and will prepend the blob header identifying the data as code requirements.
1332    ///
1333    /// The generated data should be equivalent to what `csreq -b` would produce.
1334    pub fn to_blob_data(&self) -> Result<Vec<u8>, AppleCodesignError> {
1335        let mut payload = vec![];
1336        self.write_to(&mut payload)?;
1337
1338        let mut dest = Vec::with_capacity(payload.len() + 8);
1339        dest.iowrite_with(u32::from(CodeSigningMagic::Requirement), scroll::BE)?;
1340        dest.iowrite_with(dest.capacity() as u32, scroll::BE)?;
1341        dest.write_all(&payload)?;
1342
1343        Ok(dest)
1344    }
1345
1346    /// Have this instance occupy a slot in a [RequirementSetBlob] instance.
1347    pub fn add_to_requirement_set(
1348        &self,
1349        requirements_set: &mut RequirementSetBlob,
1350        slot: RequirementType,
1351    ) -> Result<(), AppleCodesignError> {
1352        let blob = RequirementBlob::try_from(self)?;
1353
1354        requirements_set.set_requirements(slot, blob);
1355
1356        Ok(())
1357    }
1358}
1359
1360impl<'a> TryFrom<&CodeRequirements<'a>> for RequirementBlob<'static> {
1361    type Error = AppleCodesignError;
1362
1363    fn try_from(requirements: &CodeRequirements<'a>) -> Result<Self, Self::Error> {
1364        let mut data = Vec::<u8>::new();
1365        requirements.write_to(&mut data)?;
1366
1367        Ok(Self {
1368            data: Cow::Owned(data),
1369        })
1370    }
1371}
1372
1373#[cfg(test)]
1374mod test {
1375    use super::*;
1376
1377    fn verify_roundtrip(reqs: &CodeRequirements, source: &[u8]) {
1378        let mut dest = Vec::<u8>::new();
1379        reqs.write_to(&mut dest).unwrap();
1380        assert_eq!(dest.as_slice(), source);
1381    }
1382
1383    #[test]
1384    fn parse_false() {
1385        let source = hex::decode("0000000100000000").unwrap();
1386
1387        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1388
1389        assert_eq!(
1390            els,
1391            CodeRequirements(vec![CodeRequirementExpression::False])
1392        );
1393        assert!(data.is_empty());
1394        verify_roundtrip(&els, &source);
1395    }
1396
1397    #[test]
1398    fn parse_true() {
1399        let source = hex::decode("0000000100000001").unwrap();
1400
1401        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1402
1403        assert_eq!(els, CodeRequirements(vec![CodeRequirementExpression::True]));
1404        assert!(data.is_empty());
1405        verify_roundtrip(&els, &source);
1406    }
1407
1408    #[test]
1409    fn parse_identifier() {
1410        let source = hex::decode("000000010000000200000007666f6f2e62617200").unwrap();
1411
1412        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1413
1414        assert_eq!(
1415            els,
1416            CodeRequirements(vec![CodeRequirementExpression::Identifier(
1417                "foo.bar".into()
1418            )])
1419        );
1420        assert!(data.is_empty());
1421        verify_roundtrip(&els, &source);
1422    }
1423
1424    #[test]
1425    fn parse_anchor_apple() {
1426        let source = hex::decode("0000000100000003").unwrap();
1427
1428        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1429
1430        assert_eq!(
1431            els,
1432            CodeRequirements(vec![CodeRequirementExpression::AnchorApple])
1433        );
1434        assert!(data.is_empty());
1435        verify_roundtrip(&els, &source);
1436    }
1437
1438    #[test]
1439    fn parse_anchor_certificate_hash() {
1440        let source =
1441            hex::decode("0000000100000004ffffffff00000014deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
1442                .unwrap();
1443
1444        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1445
1446        assert_eq!(
1447            els,
1448            CodeRequirements(vec![CodeRequirementExpression::AnchorCertificateHash(
1449                -1,
1450                hex::decode("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
1451                    .unwrap()
1452                    .into()
1453            )])
1454        );
1455        assert!(data.is_empty());
1456        verify_roundtrip(&els, &source);
1457    }
1458
1459    #[test]
1460    fn parse_and() {
1461        let source = hex::decode("00000001000000060000000100000000").unwrap();
1462
1463        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1464
1465        assert_eq!(
1466            els,
1467            CodeRequirements(vec![CodeRequirementExpression::And(
1468                Box::new(CodeRequirementExpression::True),
1469                Box::new(CodeRequirementExpression::False)
1470            )])
1471        );
1472        assert!(data.is_empty());
1473        verify_roundtrip(&els, &source);
1474    }
1475
1476    #[test]
1477    fn parse_or() {
1478        let source = hex::decode("00000001000000070000000100000000").unwrap();
1479
1480        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1481
1482        assert_eq!(
1483            els,
1484            CodeRequirements(vec![CodeRequirementExpression::Or(
1485                Box::new(CodeRequirementExpression::True),
1486                Box::new(CodeRequirementExpression::False)
1487            )])
1488        );
1489        assert!(data.is_empty());
1490        verify_roundtrip(&els, &source);
1491    }
1492
1493    #[test]
1494    fn parse_code_directory_hash() {
1495        let source =
1496            hex::decode("000000010000000800000014deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
1497                .unwrap();
1498
1499        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1500
1501        assert_eq!(
1502            els,
1503            CodeRequirements(vec![CodeRequirementExpression::CodeDirectoryHash(
1504                hex::decode("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
1505                    .unwrap()
1506                    .into()
1507            )])
1508        );
1509        assert!(data.is_empty());
1510        verify_roundtrip(&els, &source);
1511    }
1512
1513    #[test]
1514    fn parse_not() {
1515        let source = hex::decode("000000010000000900000001").unwrap();
1516
1517        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1518
1519        assert_eq!(
1520            els,
1521            CodeRequirements(vec![CodeRequirementExpression::Not(Box::new(
1522                CodeRequirementExpression::True
1523            ))])
1524        );
1525        assert!(data.is_empty());
1526        verify_roundtrip(&els, &source);
1527    }
1528
1529    #[test]
1530    fn parse_info_plist_key_field() {
1531        let source = hex::decode("000000010000000a000000036b65790000000000").unwrap();
1532
1533        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1534
1535        assert_eq!(
1536            els,
1537            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1538                "key".into(),
1539                CodeRequirementMatchExpression::Exists
1540            )])
1541        );
1542        assert!(data.is_empty());
1543        verify_roundtrip(&els, &source);
1544    }
1545
1546    #[test]
1547    fn parse_certificate_field() {
1548        let source =
1549            hex::decode("000000010000000bffffffff0000000a7375626a6563742e434e000000000000")
1550                .unwrap();
1551
1552        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1553
1554        assert_eq!(
1555            els,
1556            CodeRequirements(vec![CodeRequirementExpression::CertificateField(
1557                -1,
1558                "subject.CN".into(),
1559                CodeRequirementMatchExpression::Exists
1560            )])
1561        );
1562        assert!(data.is_empty());
1563        verify_roundtrip(&els, &source);
1564    }
1565
1566    #[test]
1567    fn parse_certificate_trusted() {
1568        let source = hex::decode("000000010000000cffffffff").unwrap();
1569
1570        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1571
1572        assert_eq!(
1573            els,
1574            CodeRequirements(vec![CodeRequirementExpression::CertificateTrusted(-1)])
1575        );
1576        assert!(data.is_empty());
1577        verify_roundtrip(&els, &source);
1578    }
1579
1580    #[test]
1581    fn parse_anchor_trusted() {
1582        let source = hex::decode("000000010000000d").unwrap();
1583
1584        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1585
1586        assert_eq!(
1587            els,
1588            CodeRequirements(vec![CodeRequirementExpression::AnchorTrusted])
1589        );
1590        assert!(data.is_empty());
1591        verify_roundtrip(&els, &source);
1592    }
1593
1594    #[test]
1595    fn parse_certificate_generic() {
1596        let source = hex::decode("000000010000000effffffff000000035504030000000000").unwrap();
1597
1598        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1599
1600        assert_eq!(
1601            els,
1602            CodeRequirements(vec![CodeRequirementExpression::CertificateGeneric(
1603                -1,
1604                Oid(&[0x55, 4, 3]),
1605                CodeRequirementMatchExpression::Exists
1606            )])
1607        );
1608        assert!(data.is_empty());
1609        verify_roundtrip(&els, &source);
1610    }
1611
1612    #[test]
1613    fn parse_anchor_apple_generic() {
1614        let source = hex::decode("000000010000000f").unwrap();
1615
1616        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1617
1618        assert_eq!(
1619            els,
1620            CodeRequirements(vec![CodeRequirementExpression::AnchorAppleGeneric])
1621        );
1622        assert!(data.is_empty());
1623        verify_roundtrip(&els, &source);
1624    }
1625
1626    #[test]
1627    fn parse_entitlements_key() {
1628        let source = hex::decode("0000000100000010000000036b65790000000000").unwrap();
1629
1630        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1631
1632        assert_eq!(
1633            els,
1634            CodeRequirements(vec![CodeRequirementExpression::EntitlementsKey(
1635                "key".into(),
1636                CodeRequirementMatchExpression::Exists
1637            )])
1638        );
1639        assert!(data.is_empty());
1640        verify_roundtrip(&els, &source);
1641    }
1642
1643    #[test]
1644    fn parse_certificate_policy() {
1645        let source = hex::decode("0000000100000011ffffffff000000035504030000000000").unwrap();
1646
1647        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1648
1649        assert_eq!(
1650            els,
1651            CodeRequirements(vec![CodeRequirementExpression::CertificatePolicy(
1652                -1,
1653                Oid(&[0x55, 4, 3]),
1654                CodeRequirementMatchExpression::Exists
1655            )])
1656        );
1657        assert!(data.is_empty());
1658        verify_roundtrip(&els, &source);
1659    }
1660
1661    #[test]
1662    fn parse_named_anchor() {
1663        let source = hex::decode("000000010000001200000003666f6f00").unwrap();
1664
1665        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1666
1667        assert_eq!(
1668            els,
1669            CodeRequirements(vec![CodeRequirementExpression::NamedAnchor("foo".into())])
1670        );
1671        assert!(data.is_empty());
1672        verify_roundtrip(&els, &source);
1673    }
1674
1675    #[test]
1676    fn parse_named_code() {
1677        let source = hex::decode("000000010000001300000003666f6f00").unwrap();
1678
1679        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1680
1681        assert_eq!(
1682            els,
1683            CodeRequirements(vec![CodeRequirementExpression::NamedCode("foo".into())])
1684        );
1685        assert!(data.is_empty());
1686        verify_roundtrip(&els, &source);
1687    }
1688
1689    #[test]
1690    fn parse_platform() {
1691        let source = hex::decode("00000001000000140000000a").unwrap();
1692
1693        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1694
1695        assert_eq!(
1696            els,
1697            CodeRequirements(vec![CodeRequirementExpression::Platform(10)])
1698        );
1699        assert!(data.is_empty());
1700        verify_roundtrip(&els, &source);
1701    }
1702
1703    #[test]
1704    fn parse_notarized() {
1705        let source = hex::decode("0000000100000015").unwrap();
1706
1707        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1708
1709        assert_eq!(
1710            els,
1711            CodeRequirements(vec![CodeRequirementExpression::Notarized])
1712        );
1713        assert!(data.is_empty());
1714        verify_roundtrip(&els, &source);
1715    }
1716
1717    #[test]
1718    fn parse_certificate_field_date() {
1719        let source = hex::decode("0000000100000016ffffffff000000035504030000000000").unwrap();
1720
1721        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1722
1723        assert_eq!(
1724            els,
1725            CodeRequirements(vec![CodeRequirementExpression::CertificateFieldDate(
1726                -1,
1727                Oid(&[0x55, 4, 3]),
1728                CodeRequirementMatchExpression::Exists,
1729            )])
1730        );
1731        assert!(data.is_empty());
1732        verify_roundtrip(&els, &source);
1733    }
1734
1735    #[test]
1736    fn parse_legacy() {
1737        let source = hex::decode("0000000100000017").unwrap();
1738
1739        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1740
1741        assert_eq!(
1742            els,
1743            CodeRequirements(vec![CodeRequirementExpression::LegacyDeveloperId])
1744        );
1745        assert!(data.is_empty());
1746        verify_roundtrip(&els, &source);
1747    }
1748
1749    #[test]
1750    fn parse_blob() {
1751        let source = hex::decode("fade0c00000000100000000100000000").unwrap();
1752
1753        let (els, data) = CodeRequirements::parse_blob(&source).unwrap();
1754
1755        assert_eq!(
1756            els,
1757            CodeRequirements(vec![CodeRequirementExpression::False])
1758        );
1759        assert!(data.is_empty());
1760
1761        let dest = els.to_blob_data().unwrap();
1762        assert_eq!(source, dest);
1763    }
1764
1765    #[test]
1766    fn parse_match_exists() {
1767        let source = hex::decode("000000010000000a000000036b65790000000000").unwrap();
1768
1769        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1770
1771        assert_eq!(
1772            els,
1773            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1774                "key".into(),
1775                CodeRequirementMatchExpression::Exists
1776            )])
1777        );
1778        assert!(data.is_empty());
1779        verify_roundtrip(&els, &source);
1780    }
1781
1782    #[test]
1783    fn parse_match_absent() {
1784        let source = hex::decode("000000010000000a000000036b6579000000000e").unwrap();
1785
1786        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1787
1788        assert_eq!(
1789            els,
1790            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1791                "key".into(),
1792                CodeRequirementMatchExpression::Absent
1793            )])
1794        );
1795        assert!(data.is_empty());
1796        verify_roundtrip(&els, &source);
1797    }
1798
1799    #[test]
1800    fn parse_match_equal() {
1801        let source =
1802            hex::decode("000000010000000a000000036b657900000000010000000576616c7565000000")
1803                .unwrap();
1804
1805        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1806
1807        assert_eq!(
1808            els,
1809            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1810                "key".into(),
1811                CodeRequirementMatchExpression::Equal(b"value".as_ref().into())
1812            )])
1813        );
1814        assert!(data.is_empty());
1815        verify_roundtrip(&els, &source);
1816    }
1817
1818    #[test]
1819    fn parse_match_contains() {
1820        let source =
1821            hex::decode("000000010000000a000000036b657900000000020000000576616c7565000000")
1822                .unwrap();
1823
1824        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1825
1826        assert_eq!(
1827            els,
1828            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1829                "key".into(),
1830                CodeRequirementMatchExpression::Contains(b"value".as_ref().into())
1831            )])
1832        );
1833        assert!(data.is_empty());
1834        verify_roundtrip(&els, &source);
1835    }
1836
1837    #[test]
1838    fn parse_match_begins_with() {
1839        let source =
1840            hex::decode("000000010000000a000000036b657900000000030000000576616c7565000000")
1841                .unwrap();
1842
1843        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1844
1845        assert_eq!(
1846            els,
1847            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1848                "key".into(),
1849                CodeRequirementMatchExpression::BeginsWith(b"value".as_ref().into())
1850            )])
1851        );
1852        assert!(data.is_empty());
1853        verify_roundtrip(&els, &source);
1854    }
1855
1856    #[test]
1857    fn parse_match_ends_with() {
1858        let source =
1859            hex::decode("000000010000000a000000036b657900000000040000000576616c7565000000")
1860                .unwrap();
1861
1862        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1863
1864        assert_eq!(
1865            els,
1866            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1867                "key".into(),
1868                CodeRequirementMatchExpression::EndsWith(b"value".as_ref().into())
1869            )])
1870        );
1871        assert!(data.is_empty());
1872        verify_roundtrip(&els, &source);
1873    }
1874
1875    #[test]
1876    fn parse_match_less_than() {
1877        let source =
1878            hex::decode("000000010000000a000000036b657900000000050000000576616c7565000000")
1879                .unwrap();
1880
1881        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1882
1883        assert_eq!(
1884            els,
1885            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1886                "key".into(),
1887                CodeRequirementMatchExpression::LessThan(b"value".as_ref().into())
1888            )])
1889        );
1890        assert!(data.is_empty());
1891        verify_roundtrip(&els, &source);
1892    }
1893
1894    #[test]
1895    fn parse_match_greater_than() {
1896        let source =
1897            hex::decode("000000010000000a000000036b657900000000060000000576616c7565000000")
1898                .unwrap();
1899
1900        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1901
1902        assert_eq!(
1903            els,
1904            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1905                "key".into(),
1906                CodeRequirementMatchExpression::GreaterThan(b"value".as_ref().into())
1907            )])
1908        );
1909        assert!(data.is_empty());
1910        verify_roundtrip(&els, &source);
1911    }
1912
1913    #[test]
1914    fn parse_match_less_than_equal() {
1915        let source =
1916            hex::decode("000000010000000a000000036b657900000000070000000576616c7565000000")
1917                .unwrap();
1918
1919        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1920
1921        assert_eq!(
1922            els,
1923            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1924                "key".into(),
1925                CodeRequirementMatchExpression::LessThanEqual(b"value".as_ref().into())
1926            )])
1927        );
1928        assert!(data.is_empty());
1929        verify_roundtrip(&els, &source);
1930    }
1931
1932    #[test]
1933    fn parse_match_greater_than_equal() {
1934        let source =
1935            hex::decode("000000010000000a000000036b657900000000080000000576616c7565000000")
1936                .unwrap();
1937
1938        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1939
1940        assert_eq!(
1941            els,
1942            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1943                "key".into(),
1944                CodeRequirementMatchExpression::GreaterThanEqual(b"value".as_ref().into())
1945            )])
1946        );
1947        assert!(data.is_empty());
1948        verify_roundtrip(&els, &source);
1949    }
1950
1951    #[test]
1952    fn parse_match_on() {
1953        let source =
1954            hex::decode("000000010000000a000000036b6579000000000900000000605fca30").unwrap();
1955
1956        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1957
1958        assert_eq!(
1959            els,
1960            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1961                "key".into(),
1962                CodeRequirementMatchExpression::On(
1963                    chrono::Utc.timestamp_opt(1616890416, 0).unwrap()
1964                ),
1965            )])
1966        );
1967        assert!(data.is_empty());
1968        verify_roundtrip(&els, &source);
1969    }
1970
1971    #[test]
1972    fn parse_match_before() {
1973        let source =
1974            hex::decode("000000010000000a000000036b6579000000000a00000000605fca30").unwrap();
1975
1976        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1977
1978        assert_eq!(
1979            els,
1980            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
1981                "key".into(),
1982                CodeRequirementMatchExpression::Before(
1983                    chrono::Utc.timestamp_opt(1616890416, 0).unwrap()
1984                ),
1985            )])
1986        );
1987        assert!(data.is_empty());
1988        verify_roundtrip(&els, &source);
1989    }
1990
1991    #[test]
1992    fn parse_match_after() {
1993        let source =
1994            hex::decode("000000010000000a000000036b6579000000000b00000000605fca30").unwrap();
1995
1996        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
1997
1998        assert_eq!(
1999            els,
2000            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
2001                "key".into(),
2002                CodeRequirementMatchExpression::After(
2003                    chrono::Utc.timestamp_opt(1616890416, 0).unwrap()
2004                ),
2005            )])
2006        );
2007        assert!(data.is_empty());
2008        verify_roundtrip(&els, &source);
2009    }
2010
2011    #[test]
2012    fn parse_match_on_or_before() {
2013        let source =
2014            hex::decode("000000010000000a000000036b6579000000000c00000000605fca30").unwrap();
2015
2016        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
2017
2018        assert_eq!(
2019            els,
2020            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
2021                "key".into(),
2022                CodeRequirementMatchExpression::OnOrBefore(
2023                    chrono::Utc.timestamp_opt(1616890416, 0).unwrap()
2024                ),
2025            )])
2026        );
2027        assert!(data.is_empty());
2028        verify_roundtrip(&els, &source);
2029    }
2030
2031    #[test]
2032    fn parse_match_on_or_after() {
2033        let source =
2034            hex::decode("000000010000000a000000036b6579000000000d00000000605fca30").unwrap();
2035
2036        let (els, data) = CodeRequirements::parse_binary(&source).unwrap();
2037
2038        assert_eq!(
2039            els,
2040            CodeRequirements(vec![CodeRequirementExpression::InfoPlistKeyField(
2041                "key".into(),
2042                CodeRequirementMatchExpression::OnOrAfter(
2043                    chrono::Utc.timestamp_opt(1616890416, 0).unwrap()
2044                ),
2045            )])
2046        );
2047        assert!(data.is_empty());
2048        verify_roundtrip(&els, &source);
2049    }
2050}