Function apple_codesign::cryptography::parse_pfx_data
source · pub fn parse_pfx_data(
data: &[u8],
password: &str
) -> Result<(CapturedX509Certificate, InMemoryPrivateKey), AppleCodesignError>Expand description
Parse PFX data into a key pair.
PFX data is commonly encountered in .p12 files, such as those created
when exporting certificates from Apple’s Keychain Access application.
The contents of the PFX file require a password to decrypt. However, if no password was provided to create the PFX data, this password may be the empty string.
Examples found in repository?
src/cli.rs (line 590)
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
fn collect_certificates_from_args(
args: &ArgMatches,
scan_smartcard: bool,
) -> Result<(Vec<Box<dyn PrivateKey>>, Vec<CapturedX509Certificate>), AppleCodesignError> {
let mut keys: Vec<Box<dyn PrivateKey>> = vec![];
let mut certs = vec![];
if let Some(p12_path) = args.get_one::<String>("p12_path") {
let p12_data = std::fs::read(p12_path)?;
let p12_password = if let Some(password) = args.get_one::<String>("p12_password") {
password.to_string()
} else if let Some(path) = args.get_one::<String>("p12_password_file") {
std::fs::read_to_string(path)?
.lines()
.next()
.expect("should get a single line")
.to_string()
} else {
dialoguer::Password::new()
.with_prompt("Please enter password for p12 file")
.interact()?
};
let (cert, key) = parse_pfx_data(&p12_data, &p12_password)?;
keys.push(Box::new(key));
certs.push(cert);
}
if let Some(values) = args.get_many::<String>("pem_source") {
for pem_source in values {
warn!("reading PEM data from {}", pem_source);
let pem_data = std::fs::read(pem_source)?;
for pem in pem::parse_many(pem_data).map_err(AppleCodesignError::CertificatePem)? {
match pem.tag.as_str() {
"CERTIFICATE" => {
certs.push(CapturedX509Certificate::from_der(pem.contents)?);
}
"PRIVATE KEY" => {
keys.push(Box::new(InMemoryPrivateKey::from_pkcs8_der(&pem.contents)?));
}
"RSA PRIVATE KEY" => {
keys.push(Box::new(InMemoryPrivateKey::from_pkcs1_der(&pem.contents)?));
}
tag => warn!("(unhandled PEM tag {}; ignoring)", tag),
}
}
}
}
if let Some(values) = args.get_many::<String>("der_source") {
for der_source in values {
warn!("reading DER file {}", der_source);
let der_data = std::fs::read(der_source)?;
certs.push(CapturedX509Certificate::from_der(der_data)?);
}
}
find_certificates_in_keychain(args, &mut keys, &mut certs)?;
if scan_smartcard {
if let Some(slot) = args.get_one::<String>("smartcard_slot") {
let pin_env_var = args.get_one::<String>("smartcard_pin_env");
handle_smartcard_sign_slot(slot, pin_env_var.map(|x| &**x), &mut keys, &mut certs)?;
}
}
let remote_signing_url = if args.get_flag("remote_signer") {
args.get_one::<String>("remote_signing_url")
} else {
None
};
if let Some(remote_signing_url) = remote_signing_url {
let initiator = get_remote_signing_initiator(args)?;
let client = UnjoinedSigningClient::new_initiator(
remote_signing_url,
initiator,
Some(print_session_join),
)?;
// As part of the handshake we obtained the public certificates from the signer.
// So make them the canonical set.
if !certs.is_empty() {
warn!(
"ignoring {} local certificates and using remote signer's certificate(s)",
certs.len()
);
}
certs = vec![client.signing_certificate().clone()];
certs.extend(client.certificate_chain().iter().cloned());
// The client implements Sign, so we just use it as the private key.
keys = vec![Box::new(client)];
}
Ok((keys, certs))
}