1use {
8 crate::{apple_certificates::KnownCertificate, error::AppleCodesignError},
9 bcder::{
10 encode::{PrimitiveContent, Values},
11 ConstOid, Oid,
12 },
13 bytes::Bytes,
14 pkcs8::EncodePrivateKey,
15 std::{
16 fmt::{Display, Formatter},
17 str::FromStr,
18 },
19 x509_certificate::{
20 certificate::KeyUsage, rfc4519::OID_COUNTRY_NAME, CapturedX509Certificate,
21 InMemorySigningKeyPair, KeyAlgorithm, X509CertificateBuilder,
22 },
23};
24
25const OID_EXTENDED_KEY_USAGE: ConstOid = Oid(&[85, 29, 37]);
29
30const OID_EKU_PURPOSE_CODE_SIGNING: ConstOid = Oid(&[43, 6, 1, 5, 5, 7, 3, 3]);
34
35const OID_EKU_PURPOSE_SAFARI_DEVELOPER: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 4, 8]);
39
40const OID_EKU_PURPOSE_3RD_PARTY_MAC_DEVELOPER_INSTALLER: ConstOid =
44 Oid(&[42, 134, 72, 134, 247, 99, 100, 4, 9]);
45
46const OID_EKU_PURPOSE_DEVELOPER_ID_INSTALLER: ConstOid =
50 Oid(&[42, 134, 72, 134, 247, 99, 100, 4, 13]);
51
52const ALL_OID_EKUS: &[&ConstOid; 4] = &[
54 &OID_EKU_PURPOSE_CODE_SIGNING,
55 &OID_EKU_PURPOSE_SAFARI_DEVELOPER,
56 &OID_EKU_PURPOSE_3RD_PARTY_MAC_DEVELOPER_INSTALLER,
57 &OID_EKU_PURPOSE_DEVELOPER_ID_INSTALLER,
58];
59
60const OID_EXTENSION_APPLE_SIGNING: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 1]);
64
65const OID_EXTENSION_IPHONE_DEVELOPER: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 2]);
69
70const OID_EXTENSION_IPHONE_OS_APPLICATION_SIGNING: ConstOid =
74 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 3]);
75
76const OID_EXTENSION_APPLE_DEVELOPER_CERTIFICATE_SUBMISSION: ConstOid =
82 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 4]);
83
84const OID_EXTENSION_SAFARI_DEVELOPER: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 5]);
88
89const OID_EXTENSION_IPHONE_OS_VPN_SIGNING: ConstOid =
93 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 6]);
94
95const OID_EXTENSION_APPLE_MAC_APP_SIGNING_DEVELOPMENT: ConstOid =
101 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 7]);
102
103const OID_EXTENSION_APPLE_MAC_APP_SIGNING_SUBMISSION: ConstOid =
107 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 8]);
108
109const OID_EXTENSION_APPLE_MAC_APP_STORE_CODE_SIGNING: ConstOid =
113 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 9]);
114
115const OID_EXTENSION_APPLE_MAC_APP_STORE_INSTALLER_SIGNING: ConstOid =
119 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 10]);
120
121const OID_EXTENSION_MAC_DEVELOPER: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 12]);
127
128const OID_EXTENSION_DEVELOPER_ID_APPLICATION: ConstOid =
132 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 13]);
133
134const OID_EXTENSION_DEVELOPER_ID_INSTALLER: ConstOid =
138 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 14]);
139
140const OID_EXTENSION_PASSBOOK_SIGNING: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 16]);
147
148const OID_EXTENSION_WEBSITE_PUSH_NOTIFICATION_SIGNING: ConstOid =
152 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 17]);
153
154const OID_EXTENSION_DEVELOPER_ID_KERNEL: ConstOid =
158 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 18]);
159
160const OID_EXTENSION_DEVELOPER_ID_DATE: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 33]);
169
170const OID_EXTENSION_TEST_FLIGHT: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 1, 25, 1]);
174
175const ALL_OID_NON_CA_EXTENSIONS: &[&ConstOid; 18] = &[
177 &OID_EXTENSION_APPLE_SIGNING,
178 &OID_EXTENSION_IPHONE_DEVELOPER,
179 &OID_EXTENSION_IPHONE_OS_APPLICATION_SIGNING,
180 &OID_EXTENSION_APPLE_DEVELOPER_CERTIFICATE_SUBMISSION,
181 &OID_EXTENSION_SAFARI_DEVELOPER,
182 &OID_EXTENSION_IPHONE_OS_VPN_SIGNING,
183 &OID_EXTENSION_APPLE_MAC_APP_SIGNING_DEVELOPMENT,
184 &OID_EXTENSION_APPLE_MAC_APP_SIGNING_SUBMISSION,
185 &OID_EXTENSION_APPLE_MAC_APP_STORE_CODE_SIGNING,
186 &OID_EXTENSION_APPLE_MAC_APP_STORE_INSTALLER_SIGNING,
187 &OID_EXTENSION_MAC_DEVELOPER,
188 &OID_EXTENSION_DEVELOPER_ID_APPLICATION,
189 &OID_EXTENSION_DEVELOPER_ID_INSTALLER,
190 &OID_EXTENSION_PASSBOOK_SIGNING,
191 &OID_EXTENSION_WEBSITE_PUSH_NOTIFICATION_SIGNING,
192 &OID_EXTENSION_DEVELOPER_ID_KERNEL,
193 &OID_EXTENSION_DEVELOPER_ID_DATE,
194 &OID_EXTENSION_TEST_FLIGHT,
195];
196
197pub const OID_USER_ID: ConstOid = Oid(&[9, 146, 38, 137, 147, 242, 44, 100, 1, 1]);
201
202const OID_EMAIL_ADDRESS: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 1]);
204
205const OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS: ConstOid =
209 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 1]);
210
211const OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION: ConstOid =
215 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 3]);
216
217const OID_CA_EXTENSION_DEVELOPER_ID: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 6]);
221
222const OID_CA_EXTENSION_APPLE_TIMESTAMP: ConstOid = Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 9]);
226
227const OID_CA_EXTENSION_DEVELOPER_AUTHENTICATION: ConstOid =
231 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 11]);
232
233const OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G3: ConstOid =
237 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 14]);
238
239const OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS_G2: ConstOid =
243 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 15]);
244
245const OID_CA_EXTENSION_APPLE_SOFTWARE_UPDATE_CERTIFICATION: ConstOid =
249 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 19]);
250
251const OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G1: ConstOid =
259 Oid(&[42, 134, 72, 134, 247, 99, 100, 6, 2, 31]);
260
261const ALL_OID_CA_EXTENSIONS: &[&ConstOid; 9] = &[
262 &OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS,
263 &OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION,
264 &OID_CA_EXTENSION_DEVELOPER_ID,
265 &OID_CA_EXTENSION_APPLE_TIMESTAMP,
266 &OID_CA_EXTENSION_DEVELOPER_AUTHENTICATION,
267 &OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G3,
268 &OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS_G2,
269 &OID_CA_EXTENSION_APPLE_SOFTWARE_UPDATE_CERTIFICATION,
270 &OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G1,
271];
272
273#[derive(Clone, Copy, Debug, Eq, PartialEq)]
282pub enum ExtendedKeyUsagePurpose {
283 CodeSigning,
285
286 SafariDeveloper,
288
289 ThirdPartyMacDeveloperInstaller,
293
294 DeveloperIdInstaller,
296}
297
298impl ExtendedKeyUsagePurpose {
299 pub fn all() -> Vec<Self> {
301 vec![
302 Self::CodeSigning,
303 Self::SafariDeveloper,
304 Self::ThirdPartyMacDeveloperInstaller,
305 Self::DeveloperIdInstaller,
306 ]
307 }
308
309 pub fn all_oids() -> &'static [&'static ConstOid] {
310 ALL_OID_EKUS
311 }
312
313 pub fn as_oid(&self) -> ConstOid {
314 match self {
315 Self::CodeSigning => OID_EKU_PURPOSE_CODE_SIGNING,
316 Self::SafariDeveloper => OID_EKU_PURPOSE_SAFARI_DEVELOPER,
317 Self::ThirdPartyMacDeveloperInstaller => {
318 OID_EKU_PURPOSE_3RD_PARTY_MAC_DEVELOPER_INSTALLER
319 }
320 Self::DeveloperIdInstaller => OID_EKU_PURPOSE_DEVELOPER_ID_INSTALLER,
321 }
322 }
323}
324
325impl Display for ExtendedKeyUsagePurpose {
326 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
327 match self {
328 ExtendedKeyUsagePurpose::CodeSigning => f.write_str("Code Signing"),
329 ExtendedKeyUsagePurpose::SafariDeveloper => f.write_str("Safari Developer"),
330 ExtendedKeyUsagePurpose::ThirdPartyMacDeveloperInstaller => {
331 f.write_str("3rd Party Mac Developer Installer Packaging Signing")
332 }
333 ExtendedKeyUsagePurpose::DeveloperIdInstaller => f.write_str("Developer ID Installer"),
334 }
335 }
336}
337
338impl TryFrom<&Oid> for ExtendedKeyUsagePurpose {
339 type Error = AppleCodesignError;
340
341 fn try_from(oid: &Oid) -> Result<Self, Self::Error> {
342 if oid.as_ref() == OID_EKU_PURPOSE_CODE_SIGNING.as_ref() {
344 Ok(Self::CodeSigning)
345 } else if oid.as_ref() == OID_EKU_PURPOSE_SAFARI_DEVELOPER.as_ref() {
346 Ok(Self::SafariDeveloper)
347 } else if oid.as_ref() == OID_EKU_PURPOSE_3RD_PARTY_MAC_DEVELOPER_INSTALLER.as_ref() {
348 Ok(Self::ThirdPartyMacDeveloperInstaller)
349 } else if oid.as_ref() == OID_EKU_PURPOSE_DEVELOPER_ID_INSTALLER.as_ref() {
350 Ok(Self::DeveloperIdInstaller)
351 } else {
352 Err(AppleCodesignError::OidIsntCertificateAuthority)
353 }
354 }
355}
356
357#[derive(Clone, Copy, Debug, Eq, PartialEq)]
359pub enum CodeSigningCertificateExtension {
360 AppleSigning,
364
365 IPhoneDeveloper,
367
368 IPhoneOsApplicationSigning,
370
371 AppleDeveloperCertificateSubmission,
375
376 SafariDeveloper,
378
379 IPhoneOsVpnSigning,
381
382 AppleMacAppSigningDevelopment,
386
387 AppleMacAppSigningSubmission,
389
390 AppleMacAppStoreCodeSigning,
392
393 AppleMacAppStoreInstallerSigning,
395
396 MacDeveloper,
398
399 DeveloperIdApplication,
401
402 DeveloperIdDate,
404
405 DeveloperIdInstaller,
407
408 ApplePayPassbookSigning,
410
411 WebsitePushNotificationSigning,
413
414 DeveloperIdKernel,
416
417 TestFlight,
419}
420
421impl CodeSigningCertificateExtension {
422 pub fn all() -> Vec<Self> {
424 vec![
425 Self::AppleSigning,
426 Self::IPhoneDeveloper,
427 Self::IPhoneOsApplicationSigning,
428 Self::AppleDeveloperCertificateSubmission,
429 Self::SafariDeveloper,
430 Self::IPhoneOsVpnSigning,
431 Self::AppleMacAppSigningDevelopment,
432 Self::AppleMacAppSigningSubmission,
433 Self::AppleMacAppStoreCodeSigning,
434 Self::AppleMacAppStoreInstallerSigning,
435 Self::MacDeveloper,
436 Self::DeveloperIdApplication,
437 Self::DeveloperIdDate,
438 Self::DeveloperIdInstaller,
439 Self::ApplePayPassbookSigning,
440 Self::WebsitePushNotificationSigning,
441 Self::DeveloperIdKernel,
442 Self::TestFlight,
443 ]
444 }
445
446 pub fn all_oids() -> &'static [&'static ConstOid] {
448 ALL_OID_NON_CA_EXTENSIONS
449 }
450
451 pub fn as_oid(&self) -> ConstOid {
452 match self {
453 Self::AppleSigning => OID_EXTENSION_APPLE_SIGNING,
454 Self::IPhoneDeveloper => OID_EXTENSION_IPHONE_DEVELOPER,
455 Self::IPhoneOsApplicationSigning => OID_EXTENSION_IPHONE_OS_APPLICATION_SIGNING,
456 Self::AppleDeveloperCertificateSubmission => {
457 OID_EXTENSION_APPLE_DEVELOPER_CERTIFICATE_SUBMISSION
458 }
459 Self::SafariDeveloper => OID_EXTENSION_SAFARI_DEVELOPER,
460 Self::IPhoneOsVpnSigning => OID_EXTENSION_IPHONE_OS_VPN_SIGNING,
461 Self::AppleMacAppSigningDevelopment => OID_EXTENSION_APPLE_MAC_APP_SIGNING_DEVELOPMENT,
462 Self::AppleMacAppSigningSubmission => OID_EXTENSION_APPLE_MAC_APP_SIGNING_SUBMISSION,
463 Self::AppleMacAppStoreCodeSigning => OID_EXTENSION_APPLE_MAC_APP_STORE_CODE_SIGNING,
464 Self::AppleMacAppStoreInstallerSigning => {
465 OID_EXTENSION_APPLE_MAC_APP_STORE_INSTALLER_SIGNING
466 }
467 Self::MacDeveloper => OID_EXTENSION_MAC_DEVELOPER,
468 Self::DeveloperIdApplication => OID_EXTENSION_DEVELOPER_ID_APPLICATION,
469 Self::DeveloperIdDate => OID_EXTENSION_DEVELOPER_ID_DATE,
470 Self::DeveloperIdInstaller => OID_EXTENSION_DEVELOPER_ID_INSTALLER,
471 Self::ApplePayPassbookSigning => OID_EXTENSION_PASSBOOK_SIGNING,
472 Self::WebsitePushNotificationSigning => OID_EXTENSION_WEBSITE_PUSH_NOTIFICATION_SIGNING,
473 Self::DeveloperIdKernel => OID_EXTENSION_DEVELOPER_ID_KERNEL,
474 Self::TestFlight => OID_EXTENSION_TEST_FLIGHT,
475 }
476 }
477}
478
479impl Display for CodeSigningCertificateExtension {
480 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
481 match self {
482 CodeSigningCertificateExtension::AppleSigning => f.write_str("Apple Signing"),
483 CodeSigningCertificateExtension::IPhoneDeveloper => f.write_str("iPhone Developer"),
484 CodeSigningCertificateExtension::IPhoneOsApplicationSigning => {
485 f.write_str("Apple iPhone OS Application Signing")
486 }
487 CodeSigningCertificateExtension::AppleDeveloperCertificateSubmission => {
488 f.write_str("Apple Developer Certificate (Submission)")
489 }
490 CodeSigningCertificateExtension::SafariDeveloper => f.write_str("Safari Developer"),
491 CodeSigningCertificateExtension::IPhoneOsVpnSigning => {
492 f.write_str("Apple iPhone OS VPN Signing")
493 }
494 CodeSigningCertificateExtension::AppleMacAppSigningDevelopment => {
495 f.write_str("Apple Mac App Signing (Development)")
496 }
497 CodeSigningCertificateExtension::AppleMacAppSigningSubmission => {
498 f.write_str("Apple Mac App Signing Submission")
499 }
500 CodeSigningCertificateExtension::AppleMacAppStoreCodeSigning => {
501 f.write_str("Mac App Store Code Signing")
502 }
503 CodeSigningCertificateExtension::AppleMacAppStoreInstallerSigning => {
504 f.write_str("Mac App Store Installer Signing")
505 }
506 CodeSigningCertificateExtension::MacDeveloper => f.write_str("Mac Developer"),
507 CodeSigningCertificateExtension::DeveloperIdApplication => {
508 f.write_str("Developer ID Application")
509 }
510 CodeSigningCertificateExtension::DeveloperIdDate => f.write_str("Developer ID Date"),
511 CodeSigningCertificateExtension::DeveloperIdInstaller => {
512 f.write_str("Developer ID Installer")
513 }
514 CodeSigningCertificateExtension::ApplePayPassbookSigning => {
515 f.write_str("Apple Pay Passbook Signing")
516 }
517 CodeSigningCertificateExtension::WebsitePushNotificationSigning => {
518 f.write_str("Web Site Push Notifications Signing")
519 }
520 CodeSigningCertificateExtension::DeveloperIdKernel => {
521 f.write_str("Developer ID Kernel")
522 }
523 CodeSigningCertificateExtension::TestFlight => f.write_str("TestFlight"),
524 }
525 }
526}
527
528impl TryFrom<&Oid> for CodeSigningCertificateExtension {
529 type Error = AppleCodesignError;
530
531 fn try_from(oid: &Oid) -> Result<Self, Self::Error> {
532 let o = oid.as_ref();
534
535 if o == OID_EXTENSION_APPLE_SIGNING.as_ref() {
536 Ok(Self::AppleSigning)
537 } else if o == OID_EXTENSION_IPHONE_DEVELOPER.as_ref() {
538 Ok(Self::IPhoneDeveloper)
539 } else if o == OID_EXTENSION_IPHONE_OS_APPLICATION_SIGNING.as_ref() {
540 Ok(Self::IPhoneOsApplicationSigning)
541 } else if o == OID_EXTENSION_APPLE_DEVELOPER_CERTIFICATE_SUBMISSION.as_ref() {
542 Ok(Self::AppleDeveloperCertificateSubmission)
543 } else if o == OID_EXTENSION_SAFARI_DEVELOPER.as_ref() {
544 Ok(Self::SafariDeveloper)
545 } else if o == OID_EXTENSION_IPHONE_OS_VPN_SIGNING.as_ref() {
546 Ok(Self::IPhoneOsVpnSigning)
547 } else if o == OID_EXTENSION_APPLE_MAC_APP_SIGNING_DEVELOPMENT.as_ref() {
548 Ok(Self::AppleMacAppSigningDevelopment)
549 } else if o == OID_EXTENSION_APPLE_MAC_APP_SIGNING_SUBMISSION.as_ref() {
550 Ok(Self::AppleMacAppSigningSubmission)
551 } else if o == OID_EXTENSION_APPLE_MAC_APP_STORE_CODE_SIGNING.as_ref() {
552 Ok(Self::AppleMacAppStoreCodeSigning)
553 } else if o == OID_EXTENSION_APPLE_MAC_APP_STORE_INSTALLER_SIGNING.as_ref() {
554 Ok(Self::AppleMacAppStoreInstallerSigning)
555 } else if o == OID_EXTENSION_MAC_DEVELOPER.as_ref() {
556 Ok(Self::MacDeveloper)
557 } else if o == OID_EXTENSION_DEVELOPER_ID_APPLICATION.as_ref() {
558 Ok(Self::DeveloperIdApplication)
559 } else if o == OID_EXTENSION_DEVELOPER_ID_INSTALLER.as_ref() {
560 Ok(Self::DeveloperIdInstaller)
561 } else if o == OID_EXTENSION_PASSBOOK_SIGNING.as_ref() {
562 Ok(Self::ApplePayPassbookSigning)
563 } else if o == OID_EXTENSION_WEBSITE_PUSH_NOTIFICATION_SIGNING.as_ref() {
564 Ok(Self::WebsitePushNotificationSigning)
565 } else if o == OID_EXTENSION_DEVELOPER_ID_KERNEL.as_ref() {
566 Ok(Self::DeveloperIdKernel)
567 } else if o == OID_EXTENSION_DEVELOPER_ID_DATE.as_ref() {
568 Ok(Self::DeveloperIdDate)
569 } else if o == OID_EXTENSION_TEST_FLIGHT.as_ref() {
570 Ok(Self::TestFlight)
571 } else {
572 Err(AppleCodesignError::OidIsntCodeSigningExtension)
573 }
574 }
575}
576
577#[derive(Clone, Copy, Debug, Eq, PartialEq)]
582pub enum CertificateAuthorityExtension {
583 AppleWorldwideDeveloperRelations,
587
588 AppleApplicationIntegration,
590
591 DeveloperId,
593
594 AppleTimestamp,
596
597 DeveloperAuthentication,
599
600 AppleApplicationIntegrationG3,
602
603 AppleWorldwideDeveloperRelationsG2,
605
606 AppleSoftwareUpdateCertification,
608
609 AppleApplicationIntegrationG1,
611}
612
613impl CertificateAuthorityExtension {
614 pub fn all() -> Vec<Self> {
616 vec![
617 Self::AppleWorldwideDeveloperRelations,
618 Self::AppleApplicationIntegration,
619 Self::DeveloperId,
620 Self::AppleTimestamp,
621 Self::DeveloperAuthentication,
622 Self::AppleApplicationIntegrationG3,
623 Self::AppleWorldwideDeveloperRelationsG2,
624 Self::AppleSoftwareUpdateCertification,
625 Self::AppleApplicationIntegrationG1,
626 ]
627 }
628
629 pub fn all_oids() -> &'static [&'static ConstOid] {
631 ALL_OID_CA_EXTENSIONS
632 }
633
634 pub fn as_oid(&self) -> ConstOid {
635 match self {
636 Self::AppleWorldwideDeveloperRelations => {
637 OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS
638 }
639 Self::AppleApplicationIntegration => OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION,
640 Self::DeveloperId => OID_CA_EXTENSION_DEVELOPER_ID,
641 Self::AppleTimestamp => OID_CA_EXTENSION_APPLE_TIMESTAMP,
642 Self::DeveloperAuthentication => OID_CA_EXTENSION_DEVELOPER_AUTHENTICATION,
643 Self::AppleApplicationIntegrationG3 => {
644 OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G3
645 }
646 Self::AppleWorldwideDeveloperRelationsG2 => {
647 OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS_G2
648 }
649 Self::AppleSoftwareUpdateCertification => {
650 OID_CA_EXTENSION_APPLE_SOFTWARE_UPDATE_CERTIFICATION
651 }
652 Self::AppleApplicationIntegrationG1 => {
653 OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G1
654 }
655 }
656 }
657}
658
659impl Display for CertificateAuthorityExtension {
660 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
661 match self {
662 CertificateAuthorityExtension::AppleWorldwideDeveloperRelations => {
663 f.write_str("Apple Worldwide Developer Relations")
664 }
665 CertificateAuthorityExtension::AppleApplicationIntegration => {
666 f.write_str("Apple Application Integration")
667 }
668 CertificateAuthorityExtension::DeveloperId => {
669 f.write_str("Developer ID Certification Authority")
670 }
671 CertificateAuthorityExtension::AppleTimestamp => f.write_str("Apple Timestamp"),
672 CertificateAuthorityExtension::DeveloperAuthentication => {
673 f.write_str("Developer Authentication Certification Authority")
674 }
675 CertificateAuthorityExtension::AppleApplicationIntegrationG3 => {
676 f.write_str("Apple Application Integration CA - G3")
677 }
678 CertificateAuthorityExtension::AppleWorldwideDeveloperRelationsG2 => {
679 f.write_str("Apple Worldwide Developer Relations CA - G2")
680 }
681 CertificateAuthorityExtension::AppleSoftwareUpdateCertification => {
682 f.write_str("Apple Software Update Certification")
683 }
684 CertificateAuthorityExtension::AppleApplicationIntegrationG1 => {
685 f.write_str("Apple Application Integration CA - G1")
686 }
687 }
688 }
689}
690
691impl TryFrom<&Oid> for CertificateAuthorityExtension {
692 type Error = AppleCodesignError;
693
694 fn try_from(oid: &Oid) -> Result<Self, Self::Error> {
695 if oid.as_ref() == OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS.as_ref() {
697 Ok(Self::AppleWorldwideDeveloperRelations)
698 } else if oid.as_ref() == OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION.as_ref() {
699 Ok(Self::AppleApplicationIntegration)
700 } else if oid.as_ref() == OID_CA_EXTENSION_DEVELOPER_ID.as_ref() {
701 Ok(Self::DeveloperId)
702 } else if oid.as_ref() == OID_CA_EXTENSION_APPLE_TIMESTAMP.as_ref() {
703 Ok(Self::AppleTimestamp)
704 } else if oid.as_ref() == OID_CA_EXTENSION_DEVELOPER_AUTHENTICATION.as_ref() {
705 Ok(Self::DeveloperAuthentication)
706 } else if oid.as_ref() == OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G3.as_ref() {
707 Ok(Self::AppleApplicationIntegrationG3)
708 } else if oid.as_ref() == OID_CA_EXTENSION_APPLE_WORLDWIDE_DEVELOPER_RELATIONS_G2.as_ref() {
709 Ok(Self::AppleWorldwideDeveloperRelationsG2)
710 } else if oid.as_ref() == OID_CA_EXTENSION_APPLE_SOFTWARE_UPDATE_CERTIFICATION.as_ref() {
711 Ok(Self::AppleSoftwareUpdateCertification)
712 } else if oid.as_ref() == OID_CA_EXTENSION_APPLE_APPLICATION_INTEGRATION_G1.as_ref() {
713 Ok(Self::AppleApplicationIntegrationG1)
714 } else {
715 Err(AppleCodesignError::OidIsntCertificateAuthority)
716 }
717 }
718}
719
720#[derive(Clone, Copy, Debug, Eq, PartialEq)]
734pub enum CertificateProfile {
735 MacInstallerDistribution,
747
748 AppleDistribution,
756
757 AppleDevelopment,
766
767 DeveloperIdApplication,
772
773 DeveloperIdInstaller,
778}
779
780impl CertificateProfile {
781 pub fn all() -> &'static [Self] {
782 &[
783 Self::MacInstallerDistribution,
784 Self::AppleDistribution,
785 Self::AppleDevelopment,
786 Self::DeveloperIdApplication,
787 Self::DeveloperIdInstaller,
788 ]
789 }
790
791 pub fn str_names() -> [&'static str; 5] {
793 [
794 "mac-installer-distribution",
795 "apple-distribution",
796 "apple-development",
797 "developer-id-application",
798 "developer-id-installer",
799 ]
800 }
801}
802
803impl Display for CertificateProfile {
804 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
805 match self {
806 CertificateProfile::MacInstallerDistribution => {
807 f.write_str("mac-installer-distribution")
808 }
809 CertificateProfile::AppleDistribution => f.write_str("apple-distribution"),
810 CertificateProfile::AppleDevelopment => f.write_str("apple-development"),
811 CertificateProfile::DeveloperIdApplication => f.write_str("developer-id-application"),
812 CertificateProfile::DeveloperIdInstaller => f.write_str("developer-id-installer"),
813 }
814 }
815}
816
817impl FromStr for CertificateProfile {
818 type Err = AppleCodesignError;
819
820 fn from_str(s: &str) -> Result<Self, Self::Err> {
821 match s {
822 "apple-distribution" => Ok(Self::AppleDistribution),
823 "apple-development" => Ok(Self::AppleDevelopment),
824 "developer-id-application" => Ok(Self::DeveloperIdApplication),
825 "developer-id-installer" => Ok(Self::DeveloperIdInstaller),
826 "mac-installer-distribution" => Ok(Self::MacInstallerDistribution),
827 _ => Err(AppleCodesignError::UnknownCertificateProfile(s.to_string())),
828 }
829 }
830}
831
832pub trait AppleCertificate: Sized {
834 fn is_apple_root_ca(&self) -> bool;
839
840 fn is_apple_intermediate_ca(&self) -> bool;
845
846 fn apple_ca_extensions(&self) -> Vec<CertificateAuthorityExtension>;
855
856 fn apple_extended_key_usage_purposes(&self) -> Vec<ExtendedKeyUsagePurpose>;
858
859 fn apple_code_signing_extensions(&self) -> Vec<CodeSigningCertificateExtension>;
861
862 fn apple_guess_profile(&self) -> Option<CertificateProfile>;
871
872 fn apple_issuing_chain(&self) -> Vec<KnownCertificate>;
881
882 fn chains_to_apple_root_ca(&self) -> bool;
888
889 fn apple_root_certificate_chain(&self) -> Option<Vec<CapturedX509Certificate>>;
895
896 fn apple_team_id(&self) -> Option<String>;
903
904 fn is_test_apple_signed_certificate(&self) -> bool;
906}
907
908impl AppleCertificate for CapturedX509Certificate {
909 fn is_apple_root_ca(&self) -> bool {
910 KnownCertificate::all_roots().contains(&self)
911 }
912
913 fn is_apple_intermediate_ca(&self) -> bool {
914 KnownCertificate::all().contains(&self) && !KnownCertificate::all_roots().contains(&self)
915 }
916
917 fn apple_ca_extensions(&self) -> Vec<CertificateAuthorityExtension> {
918 let cert: &x509_certificate::rfc5280::Certificate = self.as_ref();
919
920 cert.iter_extensions()
921 .filter_map(|extension| CertificateAuthorityExtension::try_from(&extension.id).ok())
922 .collect::<Vec<_>>()
923 }
924
925 fn apple_extended_key_usage_purposes(&self) -> Vec<ExtendedKeyUsagePurpose> {
926 let cert: &x509_certificate::rfc5280::Certificate = self.as_ref();
927
928 cert.iter_extensions()
929 .filter_map(|extension| {
930 if extension.id.as_ref() == OID_EXTENDED_KEY_USAGE.as_ref() {
931 if let Some(oid) = extension.try_decode_sequence_single_oid() {
932 ExtendedKeyUsagePurpose::try_from(&oid).ok()
933 } else {
934 None
935 }
936 } else {
937 None
938 }
939 })
940 .collect::<Vec<_>>()
941 }
942
943 fn apple_code_signing_extensions(&self) -> Vec<CodeSigningCertificateExtension> {
944 let cert: &x509_certificate::rfc5280::Certificate = self.as_ref();
945
946 cert.iter_extensions()
947 .filter_map(|extension| {
948 CodeSigningCertificateExtension::try_from(&extension.id).ok()
949 })
950 .collect::<Vec<_>>()
951 }
952
953 fn apple_guess_profile(&self) -> Option<CertificateProfile> {
954 let ekus = self.apple_extended_key_usage_purposes();
955 let signing = self.apple_code_signing_extensions();
956
957 if ekus.contains(&ExtendedKeyUsagePurpose::DeveloperIdInstaller) {
962 Some(CertificateProfile::DeveloperIdInstaller)
963 } else if ekus.contains(&ExtendedKeyUsagePurpose::ThirdPartyMacDeveloperInstaller) {
964 Some(CertificateProfile::MacInstallerDistribution)
965 } else if signing.contains(&CodeSigningCertificateExtension::DeveloperIdApplication) {
968 Some(CertificateProfile::DeveloperIdApplication)
969 } else if signing.contains(&CodeSigningCertificateExtension::IPhoneDeveloper)
970 && signing.contains(&CodeSigningCertificateExtension::MacDeveloper)
971 {
972 Some(CertificateProfile::AppleDevelopment)
973 } else if signing.contains(&CodeSigningCertificateExtension::AppleMacAppSigningDevelopment)
974 && signing
975 .contains(&CodeSigningCertificateExtension::AppleDeveloperCertificateSubmission)
976 {
977 Some(CertificateProfile::AppleDistribution)
978 } else {
979 None
980 }
981 }
982
983 fn apple_issuing_chain(&self) -> Vec<KnownCertificate> {
984 self.resolve_signing_chain(KnownCertificate::all().iter().copied())
985 .into_iter()
986 .filter_map(|cert| KnownCertificate::try_from(cert).ok())
987 .collect::<Vec<_>>()
988 }
989
990 fn chains_to_apple_root_ca(&self) -> bool {
991 if self.is_apple_root_ca() {
992 true
993 } else {
994 self.resolve_signing_chain(KnownCertificate::all().iter().copied())
995 .into_iter()
996 .any(|cert| cert.is_apple_root_ca())
997 }
998 }
999
1000 fn apple_root_certificate_chain(&self) -> Option<Vec<CapturedX509Certificate>> {
1001 let mut chain = vec![self.clone()];
1002
1003 for cert in self.resolve_signing_chain(KnownCertificate::all().iter().copied()) {
1004 chain.push(cert.clone());
1005
1006 if cert.is_apple_root_ca() {
1007 break;
1008 }
1009 }
1010
1011 if chain.last().unwrap().is_apple_root_ca() {
1012 Some(chain)
1013 } else {
1014 None
1015 }
1016 }
1017
1018 fn apple_team_id(&self) -> Option<String> {
1019 self.subject_name()
1020 .find_first_attribute_string(Oid(
1021 x509_certificate::rfc4519::OID_ORGANIZATIONAL_UNIT_NAME
1022 .as_ref()
1023 .into(),
1024 ))
1025 .unwrap_or(None)
1026 }
1027
1028 fn is_test_apple_signed_certificate(&self) -> bool {
1029 if let Ok(digest) = self.sha256_fingerprint() {
1030 hex::encode(digest)
1031 == "5939ad5770d8b977b38d07533754371314744e87a8d606433f689e9bc6b980a0"
1032 } else {
1033 false
1034 }
1035 }
1036}
1037
1038pub trait AppleCertificateBuilder: Sized {
1046 fn apple_subject(
1051 &mut self,
1052 team_id: &str,
1053 person_name: &str,
1054 country: &str,
1055 ) -> Result<(), AppleCodesignError>;
1056
1057 fn apple_email_address(&mut self, address: &str) -> Result<(), AppleCodesignError>;
1059
1060 fn apple_extended_key_usage(
1062 &mut self,
1063 usage: ExtendedKeyUsagePurpose,
1064 ) -> Result<(), AppleCodesignError>;
1065
1066 fn apple_code_signing_certificate_extension(
1068 &mut self,
1069 extension: CodeSigningCertificateExtension,
1070 ) -> Result<(), AppleCodesignError>;
1071
1072 fn apple_certificate_profile(
1079 &mut self,
1080 profile: CertificateProfile,
1081 ) -> Result<(), AppleCodesignError>;
1082
1083 fn apple_code_signing_extensions(&self) -> Vec<CodeSigningCertificateExtension>;
1085}
1086
1087impl AppleCertificateBuilder for X509CertificateBuilder {
1088 fn apple_subject(
1089 &mut self,
1090 team_id: &str,
1091 person_name: &str,
1092 country: &str,
1093 ) -> Result<(), AppleCodesignError> {
1094 self.subject()
1099 .append_utf8_string(Oid(OID_USER_ID.as_ref().into()), team_id)
1100 .map_err(|e| AppleCodesignError::CertificateBuildError(format!("{e:?}")))?;
1101
1102 let extensions = self.apple_code_signing_extensions();
1105
1106 let common_name =
1107 if extensions.contains(&CodeSigningCertificateExtension::DeveloperIdApplication) {
1108 format!("Developer ID Application: {person_name} ({team_id})")
1109 } else if extensions.contains(&CodeSigningCertificateExtension::DeveloperIdInstaller) {
1110 format!("Developer ID Installer: {person_name} ({team_id})")
1111 } else if extensions
1112 .contains(&CodeSigningCertificateExtension::AppleDeveloperCertificateSubmission)
1113 {
1114 format!("Apple Distribution: {person_name} ({team_id})")
1115 } else if extensions
1116 .contains(&CodeSigningCertificateExtension::AppleMacAppSigningSubmission)
1117 {
1118 format!("3rd Party Mac Developer Installer: {person_name} ({team_id})")
1119 } else if extensions.contains(&CodeSigningCertificateExtension::MacDeveloper) {
1120 format!("Apple Development: {person_name} ({team_id})")
1121 } else {
1122 format!("{person_name} ({team_id})")
1123 };
1124
1125 self.subject()
1126 .append_common_name_utf8_string(&common_name)
1127 .map_err(|e| AppleCodesignError::CertificateBuildError(format!("{e:?}")))?;
1128
1129 self.subject()
1130 .append_organizational_unit_utf8_string(team_id)
1131 .map_err(|e| AppleCodesignError::CertificateBuildError(format!("{e:?}")))?;
1132
1133 self.subject()
1134 .append_organization_utf8_string(person_name)
1135 .map_err(|e| AppleCodesignError::CertificateBuildError(format!("{e:?}")))?;
1136
1137 self.subject()
1138 .append_printable_string(Oid(OID_COUNTRY_NAME.as_ref().into()), country)
1139 .map_err(|e| AppleCodesignError::CertificateBuildError(format!("{e:?}")))?;
1140
1141 Ok(())
1142 }
1143
1144 fn apple_email_address(&mut self, address: &str) -> Result<(), AppleCodesignError> {
1145 self.subject()
1146 .append_utf8_string(Oid(OID_EMAIL_ADDRESS.as_ref().into()), address)
1147 .map_err(|e| AppleCodesignError::CertificateBuildError(format!("{e:?}")))?;
1148
1149 Ok(())
1150 }
1151
1152 fn apple_extended_key_usage(
1153 &mut self,
1154 usage: ExtendedKeyUsagePurpose,
1155 ) -> Result<(), AppleCodesignError> {
1156 let payload =
1157 bcder::encode::sequence(Oid(Bytes::copy_from_slice(usage.as_oid().as_ref())).encode())
1158 .to_captured(bcder::Mode::Der);
1159
1160 self.add_extension_der_data(
1161 Oid(OID_EXTENDED_KEY_USAGE.as_ref().into()),
1162 true,
1163 payload.as_slice(),
1164 );
1165
1166 Ok(())
1167 }
1168
1169 fn apple_code_signing_certificate_extension(
1170 &mut self,
1171 extension: CodeSigningCertificateExtension,
1172 ) -> Result<(), AppleCodesignError> {
1173 let (critical, payload) = match extension {
1174 CodeSigningCertificateExtension::IPhoneDeveloper => {
1175 (true, Bytes::copy_from_slice(&[0x05, 0x00]))
1181 }
1182 CodeSigningCertificateExtension::AppleDeveloperCertificateSubmission => {
1183 (true, Bytes::copy_from_slice(&[0x05, 0x00]))
1189 }
1190 CodeSigningCertificateExtension::AppleMacAppSigningDevelopment => {
1191 (true, Bytes::copy_from_slice(&[0x05, 0x00]))
1197 }
1198 CodeSigningCertificateExtension::AppleMacAppSigningSubmission => {
1199 (true, Bytes::copy_from_slice(&[0x05, 0x00]))
1205 }
1206 CodeSigningCertificateExtension::MacDeveloper => {
1207 (true, Bytes::copy_from_slice(&[0x05, 0x00]))
1213 }
1214 CodeSigningCertificateExtension::DeveloperIdApplication => {
1215 (true, Bytes::copy_from_slice(&[0x05, 0x00]))
1221 }
1222 CodeSigningCertificateExtension::DeveloperIdInstaller => {
1223 (true, Bytes::copy_from_slice(&[0x05, 0x00]))
1229 }
1230
1231 _ => {
1234 return Err(AppleCodesignError::CertificateBuildError(format!(
1235 "don't know how to handle code signing extension {extension:?}"
1236 )));
1237 }
1238 };
1239
1240 self.add_extension_der_data(
1241 Oid(Bytes::copy_from_slice(extension.as_oid().as_ref())),
1242 critical,
1243 payload,
1244 );
1245
1246 Ok(())
1247 }
1248
1249 fn apple_certificate_profile(
1250 &mut self,
1251 profile: CertificateProfile,
1252 ) -> Result<(), AppleCodesignError> {
1253 match profile {
1255 CertificateProfile::DeveloperIdApplication => {
1256 self.constraint_not_ca();
1257 self.apple_extended_key_usage(ExtendedKeyUsagePurpose::CodeSigning)?;
1258 self.key_usage(KeyUsage::DigitalSignature);
1259
1260 self.apple_code_signing_certificate_extension(
1265 CodeSigningCertificateExtension::DeveloperIdApplication,
1266 )?;
1267 }
1268 CertificateProfile::DeveloperIdInstaller => {
1269 self.constraint_not_ca();
1270 self.apple_extended_key_usage(ExtendedKeyUsagePurpose::DeveloperIdInstaller)?;
1271 self.key_usage(KeyUsage::DigitalSignature);
1272
1273 self.apple_code_signing_certificate_extension(
1276 CodeSigningCertificateExtension::DeveloperIdInstaller,
1277 )?;
1278 }
1279 CertificateProfile::AppleDevelopment => {
1280 self.constraint_not_ca();
1281 self.apple_extended_key_usage(ExtendedKeyUsagePurpose::CodeSigning)?;
1282 self.key_usage(KeyUsage::DigitalSignature);
1283 self.apple_code_signing_certificate_extension(
1284 CodeSigningCertificateExtension::IPhoneDeveloper,
1285 )?;
1286 self.apple_code_signing_certificate_extension(
1287 CodeSigningCertificateExtension::MacDeveloper,
1288 )?;
1289 }
1290 CertificateProfile::AppleDistribution => {
1291 self.constraint_not_ca();
1292 self.apple_extended_key_usage(ExtendedKeyUsagePurpose::CodeSigning)?;
1293 self.key_usage(KeyUsage::DigitalSignature);
1294
1295 self.apple_code_signing_certificate_extension(
1298 CodeSigningCertificateExtension::AppleMacAppSigningDevelopment,
1299 )?;
1300 self.apple_code_signing_certificate_extension(
1301 CodeSigningCertificateExtension::AppleDeveloperCertificateSubmission,
1302 )?;
1303 }
1304 CertificateProfile::MacInstallerDistribution => {
1305 self.constraint_not_ca();
1306 self.apple_extended_key_usage(
1307 ExtendedKeyUsagePurpose::ThirdPartyMacDeveloperInstaller,
1308 )?;
1309 self.key_usage(KeyUsage::DigitalSignature);
1310
1311 self.apple_code_signing_certificate_extension(
1312 CodeSigningCertificateExtension::AppleMacAppSigningSubmission,
1313 )?;
1314 }
1315 }
1316
1317 Ok(())
1318 }
1319
1320 fn apple_code_signing_extensions(&self) -> Vec<CodeSigningCertificateExtension> {
1321 self.extensions()
1322 .iter()
1323 .filter_map(|ext| {
1324 CodeSigningCertificateExtension::try_from(&ext.id).ok()
1325 })
1326 .collect::<Vec<_>>()
1327 }
1328}
1329
1330pub fn create_self_signed_code_signing_certificate(
1341 algorithm: KeyAlgorithm,
1342 profile: CertificateProfile,
1343 team_id: &str,
1344 person_name: &str,
1345 country: &str,
1346 validity_duration: chrono::Duration,
1347) -> Result<(CapturedX509Certificate, InMemorySigningKeyPair), AppleCodesignError> {
1348 let mut builder = X509CertificateBuilder::default();
1349
1350 builder.apple_certificate_profile(profile)?;
1351 builder.apple_subject(team_id, person_name, country)?;
1352 builder.validity_duration(validity_duration);
1353
1354 if matches!(algorithm, KeyAlgorithm::Rsa) {
1357 let private_key = rsa::RsaPrivateKey::new(&mut rand::thread_rng(), 2048).map_err(|e| {
1358 AppleCodesignError::CertificateBuildError(format!("error generating RSA key: {}", e))
1359 })?;
1360 let key_pair = InMemorySigningKeyPair::from_pkcs8_der(
1361 private_key
1362 .to_pkcs8_der()
1363 .map_err(|e| {
1364 AppleCodesignError::CertificateGeneric(format!(
1365 "error converting RSA key to DER: {}",
1366 e
1367 ))
1368 })?
1369 .as_bytes(),
1370 )?;
1371
1372 let cert = builder.create_with_key_pair(&key_pair)?;
1373
1374 Ok((cert, key_pair))
1375 } else {
1376 Ok(builder.create_with_random_keypair(algorithm)?)
1377 }
1378}
1379
1380#[cfg(test)]
1381mod tests {
1382 use {
1383 super::*,
1384 cryptographic_message_syntax::{SignedData, SignedDataBuilder, SignerBuilder},
1385 x509_certificate::EcdsaCurve,
1386 };
1387
1388 #[test]
1389 fn generate_self_signed_certificate_ecdsa() {
1390 for curve in EcdsaCurve::all() {
1391 create_self_signed_code_signing_certificate(
1392 KeyAlgorithm::Ecdsa(*curve),
1393 CertificateProfile::DeveloperIdInstaller,
1394 "team1",
1395 "Joe Developer",
1396 "US",
1397 chrono::Duration::hours(1),
1398 )
1399 .unwrap();
1400 }
1401 }
1402
1403 #[test]
1404 fn generate_self_signed_certificate_ed25519() {
1405 create_self_signed_code_signing_certificate(
1406 KeyAlgorithm::Ed25519,
1407 CertificateProfile::DeveloperIdInstaller,
1408 "team2",
1409 "Joe Developer",
1410 "US",
1411 chrono::Duration::hours(1),
1412 )
1413 .unwrap();
1414 }
1415
1416 #[test]
1417 fn generate_all_profiles() {
1418 for profile in CertificateProfile::all() {
1419 create_self_signed_code_signing_certificate(
1420 KeyAlgorithm::Ed25519,
1421 *profile,
1422 "team",
1423 "Joe Developer",
1424 "Wakanda",
1425 chrono::Duration::hours(1),
1426 )
1427 .unwrap();
1428 }
1429 }
1430
1431 #[test]
1432 fn cms_self_signed_certificate_signing_ecdsa() {
1433 for curve in EcdsaCurve::all() {
1434 let (cert, signing_key) = create_self_signed_code_signing_certificate(
1435 KeyAlgorithm::Ecdsa(*curve),
1436 CertificateProfile::DeveloperIdInstaller,
1437 "team",
1438 "Joe Developer",
1439 "US",
1440 chrono::Duration::hours(1),
1441 )
1442 .unwrap();
1443
1444 let plaintext = "hello, world";
1445
1446 let cms = SignedDataBuilder::default()
1447 .certificate(cert.clone())
1448 .content_inline(plaintext.as_bytes().to_vec())
1449 .signer(SignerBuilder::new(&signing_key, cert.clone()))
1450 .build_der()
1451 .unwrap();
1452
1453 let signed_data = SignedData::parse_ber(&cms).unwrap();
1454
1455 for signer in signed_data.signers() {
1456 signer
1457 .verify_signature_with_signed_data(&signed_data)
1458 .unwrap();
1459 }
1460 }
1461 }
1462
1463 #[test]
1464 fn cms_self_signed_certificate_signing_ed25519() {
1465 let (cert, signing_key) = create_self_signed_code_signing_certificate(
1466 KeyAlgorithm::Ed25519,
1467 CertificateProfile::DeveloperIdInstaller,
1468 "team",
1469 "Joe Developer",
1470 "US",
1471 chrono::Duration::hours(1),
1472 )
1473 .unwrap();
1474
1475 let plaintext = "hello, world";
1476
1477 let cms = SignedDataBuilder::default()
1478 .certificate(cert.clone())
1479 .content_inline(plaintext.as_bytes().to_vec())
1480 .signer(SignerBuilder::new(&signing_key, cert))
1481 .build_der()
1482 .unwrap();
1483
1484 let signed_data = SignedData::parse_ber(&cms).unwrap();
1485
1486 for signer in signed_data.signers() {
1487 signer
1488 .verify_signature_with_signed_data(&signed_data)
1489 .unwrap();
1490 }
1491 }
1492
1493 #[test]
1494 fn third_mac_mac() {
1495 let der = include_bytes!("testdata/apple-signed-3rd-party-mac.cer");
1496 let cert = CapturedX509Certificate::from_der(der.to_vec()).unwrap();
1497
1498 assert_eq!(
1499 cert.apple_extended_key_usage_purposes(),
1500 vec![ExtendedKeyUsagePurpose::ThirdPartyMacDeveloperInstaller]
1501 );
1502 assert_eq!(
1503 cert.apple_code_signing_extensions(),
1504 vec![CodeSigningCertificateExtension::AppleMacAppSigningSubmission]
1505 );
1506 assert_eq!(
1507 cert.apple_guess_profile(),
1508 Some(CertificateProfile::MacInstallerDistribution)
1509 );
1510 assert_eq!(
1511 cert.apple_issuing_chain(),
1512 vec![
1513 KnownCertificate::WwdrG3,
1514 KnownCertificate::AppleRootCa,
1515 KnownCertificate::AppleComputerIncRoot
1516 ]
1517 );
1518 assert!(cert.chains_to_apple_root_ca());
1519 assert_eq!(
1520 cert.apple_root_certificate_chain(),
1521 Some(vec![
1522 cert.clone(),
1523 (*KnownCertificate::WwdrG3).clone(),
1524 (*KnownCertificate::AppleRootCa).clone()
1525 ])
1526 );
1527 assert_eq!(cert.apple_team_id(), Some("MK22MZP987".into()));
1528
1529 let mut builder = X509CertificateBuilder::default();
1530 builder
1531 .apple_certificate_profile(CertificateProfile::MacInstallerDistribution)
1532 .unwrap();
1533
1534 let built = builder
1535 .create_with_random_keypair(KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1))
1536 .unwrap()
1537 .0;
1538
1539 assert_eq!(
1540 built.apple_extended_key_usage_purposes(),
1541 cert.apple_extended_key_usage_purposes()
1542 );
1543 assert_eq!(
1544 built.apple_code_signing_extensions(),
1545 cert.apple_code_signing_extensions()
1546 );
1547 assert_eq!(built.apple_guess_profile(), cert.apple_guess_profile());
1548 assert_eq!(built.apple_issuing_chain(), vec![]);
1549 assert!(!built.chains_to_apple_root_ca());
1550 assert!(built.apple_root_certificate_chain().is_none());
1551 }
1552
1553 #[test]
1554 fn apple_development() {
1555 let der = include_bytes!("testdata/apple-signed-apple-development.cer");
1556 let cert = CapturedX509Certificate::from_der(der.to_vec()).unwrap();
1557
1558 assert_eq!(
1559 cert.apple_extended_key_usage_purposes(),
1560 vec![ExtendedKeyUsagePurpose::CodeSigning]
1561 );
1562 assert_eq!(
1563 cert.apple_code_signing_extensions(),
1564 vec![
1565 CodeSigningCertificateExtension::IPhoneDeveloper,
1566 CodeSigningCertificateExtension::MacDeveloper
1567 ]
1568 );
1569 assert_eq!(
1570 cert.apple_guess_profile(),
1571 Some(CertificateProfile::AppleDevelopment)
1572 );
1573 assert_eq!(
1574 cert.apple_issuing_chain(),
1575 vec![
1576 KnownCertificate::WwdrG3,
1577 KnownCertificate::AppleRootCa,
1578 KnownCertificate::AppleComputerIncRoot
1579 ],
1580 );
1581 assert!(cert.chains_to_apple_root_ca());
1582 assert_eq!(
1583 cert.apple_root_certificate_chain(),
1584 Some(vec![
1585 cert.clone(),
1586 (*KnownCertificate::WwdrG3).clone(),
1587 (*KnownCertificate::AppleRootCa).clone()
1588 ])
1589 );
1590 assert_eq!(cert.apple_team_id(), Some("MK22MZP987".into()));
1591
1592 let mut builder = X509CertificateBuilder::default();
1593 builder
1594 .apple_certificate_profile(CertificateProfile::AppleDevelopment)
1595 .unwrap();
1596
1597 let built = builder
1598 .create_with_random_keypair(KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1))
1599 .unwrap()
1600 .0;
1601
1602 assert_eq!(
1603 built.apple_extended_key_usage_purposes(),
1604 cert.apple_extended_key_usage_purposes()
1605 );
1606 assert_eq!(
1607 built.apple_code_signing_extensions(),
1608 cert.apple_code_signing_extensions()
1609 );
1610 assert_eq!(built.apple_guess_profile(), cert.apple_guess_profile());
1611 assert_eq!(built.apple_issuing_chain(), vec![]);
1612 assert!(!built.chains_to_apple_root_ca());
1613 assert!(built.apple_root_certificate_chain().is_none());
1614 }
1615
1616 #[test]
1617 fn apple_distribution() {
1618 let der = include_bytes!("testdata/apple-signed-apple-distribution.cer");
1619 let cert = CapturedX509Certificate::from_der(der.to_vec()).unwrap();
1620
1621 assert_eq!(
1622 cert.apple_extended_key_usage_purposes(),
1623 vec![ExtendedKeyUsagePurpose::CodeSigning]
1624 );
1625 assert_eq!(
1626 cert.apple_code_signing_extensions(),
1627 vec![
1628 CodeSigningCertificateExtension::AppleMacAppSigningDevelopment,
1629 CodeSigningCertificateExtension::AppleDeveloperCertificateSubmission
1630 ]
1631 );
1632 assert_eq!(
1633 cert.apple_guess_profile(),
1634 Some(CertificateProfile::AppleDistribution)
1635 );
1636 assert_eq!(
1637 cert.apple_issuing_chain(),
1638 vec![
1639 KnownCertificate::WwdrG3,
1640 KnownCertificate::AppleRootCa,
1641 KnownCertificate::AppleComputerIncRoot
1642 ],
1643 );
1644 assert!(cert.chains_to_apple_root_ca());
1645 assert_eq!(
1646 cert.apple_root_certificate_chain(),
1647 Some(vec![
1648 cert.clone(),
1649 (*KnownCertificate::WwdrG3).clone(),
1650 (*KnownCertificate::AppleRootCa).clone()
1651 ])
1652 );
1653 assert_eq!(cert.apple_team_id(), Some("MK22MZP987".into()));
1654
1655 let mut builder = X509CertificateBuilder::default();
1656 builder
1657 .apple_certificate_profile(CertificateProfile::AppleDistribution)
1658 .unwrap();
1659
1660 let built = builder
1661 .create_with_random_keypair(KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1))
1662 .unwrap()
1663 .0;
1664
1665 assert_eq!(
1666 built.apple_extended_key_usage_purposes(),
1667 cert.apple_extended_key_usage_purposes()
1668 );
1669 assert_eq!(
1670 built.apple_code_signing_extensions(),
1671 cert.apple_code_signing_extensions()
1672 );
1673 assert_eq!(built.apple_guess_profile(), cert.apple_guess_profile());
1674 assert_eq!(built.apple_issuing_chain(), vec![]);
1675 assert!(!built.chains_to_apple_root_ca());
1676 assert!(built.apple_root_certificate_chain().is_none());
1677 }
1678
1679 #[test]
1680 fn apple_developer_id_application() {
1681 let der = include_bytes!("testdata/apple-signed-developer-id-application.cer");
1682 let cert = CapturedX509Certificate::from_der(der.to_vec()).unwrap();
1683
1684 assert_eq!(
1685 cert.apple_extended_key_usage_purposes(),
1686 vec![ExtendedKeyUsagePurpose::CodeSigning]
1687 );
1688 assert_eq!(
1689 cert.apple_code_signing_extensions(),
1690 vec![
1691 CodeSigningCertificateExtension::DeveloperIdDate,
1692 CodeSigningCertificateExtension::DeveloperIdApplication
1693 ]
1694 );
1695 assert_eq!(
1696 cert.apple_guess_profile(),
1697 Some(CertificateProfile::DeveloperIdApplication)
1698 );
1699 assert_eq!(
1700 cert.apple_issuing_chain(),
1701 vec![
1702 KnownCertificate::DeveloperIdG1,
1703 KnownCertificate::AppleRootCa,
1704 KnownCertificate::AppleComputerIncRoot
1705 ]
1706 );
1707 assert!(cert.chains_to_apple_root_ca());
1708 assert_eq!(
1709 cert.apple_root_certificate_chain(),
1710 Some(vec![
1711 cert.clone(),
1712 (*KnownCertificate::DeveloperIdG1).clone(),
1713 (*KnownCertificate::AppleRootCa).clone()
1714 ])
1715 );
1716 assert_eq!(cert.apple_team_id(), Some("MK22MZP987".into()));
1717
1718 let mut builder = X509CertificateBuilder::default();
1719 builder
1720 .apple_certificate_profile(CertificateProfile::DeveloperIdApplication)
1721 .unwrap();
1722
1723 let built = builder
1724 .create_with_random_keypair(KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1))
1725 .unwrap()
1726 .0;
1727
1728 assert_eq!(
1729 built.apple_extended_key_usage_purposes(),
1730 cert.apple_extended_key_usage_purposes()
1731 );
1732 assert_eq!(
1733 built.apple_code_signing_extensions(),
1734 cert.apple_code_signing_extensions()
1736 .into_iter()
1737 .filter(|e| !matches!(e, CodeSigningCertificateExtension::DeveloperIdDate))
1738 .collect::<Vec<_>>()
1739 );
1740 assert_eq!(built.apple_guess_profile(), cert.apple_guess_profile());
1741 assert_eq!(built.apple_issuing_chain(), vec![]);
1742 assert!(!built.chains_to_apple_root_ca());
1743 assert!(built.apple_root_certificate_chain().is_none());
1744 }
1745
1746 #[test]
1747 fn apple_developer_id_installer() {
1748 let der = include_bytes!("testdata/apple-signed-developer-id-installer.cer");
1749 let cert = CapturedX509Certificate::from_der(der.to_vec()).unwrap();
1750
1751 assert_eq!(
1752 cert.apple_extended_key_usage_purposes(),
1753 vec![ExtendedKeyUsagePurpose::DeveloperIdInstaller]
1754 );
1755 assert_eq!(
1756 cert.apple_code_signing_extensions(),
1757 vec![
1758 CodeSigningCertificateExtension::DeveloperIdDate,
1759 CodeSigningCertificateExtension::DeveloperIdInstaller
1760 ]
1761 );
1762 assert_eq!(
1763 cert.apple_guess_profile(),
1764 Some(CertificateProfile::DeveloperIdInstaller)
1765 );
1766 assert_eq!(
1767 cert.apple_issuing_chain(),
1768 vec![
1769 KnownCertificate::DeveloperIdG1,
1770 KnownCertificate::AppleRootCa,
1771 KnownCertificate::AppleComputerIncRoot
1772 ]
1773 );
1774 assert!(cert.chains_to_apple_root_ca());
1775 assert_eq!(
1776 cert.apple_root_certificate_chain(),
1777 Some(vec![
1778 cert.clone(),
1779 (*KnownCertificate::DeveloperIdG1).clone(),
1780 (*KnownCertificate::AppleRootCa).clone()
1781 ])
1782 );
1783 assert_eq!(cert.apple_team_id(), Some("MK22MZP987".into()));
1784
1785 let mut builder = X509CertificateBuilder::default();
1786 builder
1787 .apple_certificate_profile(CertificateProfile::DeveloperIdInstaller)
1788 .unwrap();
1789
1790 let built = builder
1791 .create_with_random_keypair(KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1))
1792 .unwrap()
1793 .0;
1794
1795 assert_eq!(
1796 built.apple_extended_key_usage_purposes(),
1797 cert.apple_extended_key_usage_purposes()
1798 );
1799 assert_eq!(
1800 built.apple_code_signing_extensions(),
1801 cert.apple_code_signing_extensions()
1803 .into_iter()
1804 .filter(|e| !matches!(e, CodeSigningCertificateExtension::DeveloperIdDate))
1805 .collect::<Vec<_>>()
1806 );
1807 assert_eq!(built.apple_guess_profile(), cert.apple_guess_profile());
1808 assert_eq!(built.apple_issuing_chain(), vec![]);
1809 assert!(!built.chains_to_apple_root_ca());
1810 assert!(built.apple_root_certificate_chain().is_none());
1811 }
1812}