522 lines
20 KiB
Diff
522 lines
20 KiB
Diff
--- a/apple-codesign/src/cli/certificate_source.rs
|
|
+++ b/apple-codesign/src/cli/certificate_source.rs
|
|
@@ -16,0 +17 @@
|
|
+ bytes::Bytes,
|
|
@@ -19,0 +21 @@
|
|
+ signature::Signer,
|
|
@@ -21,2 +23,10 @@
|
|
- std::path::PathBuf,
|
|
- x509_certificate::CapturedX509Certificate,
|
|
+ std::{
|
|
+ path::PathBuf,
|
|
+ process::Command,
|
|
+ sync::atomic::{AtomicU64, Ordering},
|
|
+ },
|
|
+ x509_certificate::{
|
|
+ CapturedX509Certificate, KeyAlgorithm, Sign, Signature, SignatureAlgorithm,
|
|
+ X509CertificateError,
|
|
+ },
|
|
+ zeroize::Zeroizing,
|
|
@@ -36,0 +47,2 @@
|
|
+static PKCS11_SIGN_COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
+
|
|
@@ -204,0 +214,262 @@
|
|
+#[derive(Clone, Debug)]
|
|
+struct Pkcs11PrivateKey {
|
|
+ tool: String,
|
|
+ module: PathBuf,
|
|
+ slot_id: Option<String>,
|
|
+ token_label: Option<String>,
|
|
+ key_id: Option<String>,
|
|
+ key_label: Option<String>,
|
|
+ pin: String,
|
|
+ cert: CapturedX509Certificate,
|
|
+}
|
|
+
|
|
+impl signature::Signer<Signature> for Pkcs11PrivateKey {
|
|
+ fn try_sign(&self, message: &[u8]) -> Result<Signature, signature::Error> {
|
|
+ match self.cert.key_algorithm() {
|
|
+ Some(KeyAlgorithm::Rsa) => {}
|
|
+ Some(algorithm) => {
|
|
+ return Err(signature::Error::from_source(format!(
|
|
+ "PKCS#11 signing currently supports RSA certificates, not {algorithm:?}"
|
|
+ )));
|
|
+ }
|
|
+ None => {
|
|
+ return Err(signature::Error::from_source(
|
|
+ "failed to resolve PKCS#11 certificate key algorithm",
|
|
+ ));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ let sequence = PKCS11_SIGN_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
+ let base = std::env::temp_dir().join(format!(
|
|
+ "rcodesign-pkcs11-{}-{sequence}",
|
|
+ std::process::id()
|
|
+ ));
|
|
+ let input_path = base.with_extension("in");
|
|
+ let output_path = base.with_extension("sig");
|
|
+ let openssl_config_path = base.with_extension("openssl.cnf");
|
|
+ let provider_debug_path = base.with_extension("pkcs11-provider.log");
|
|
+
|
|
+ std::fs::write(&input_path, message).map_err(signature::Error::from_source)?;
|
|
+
|
|
+ let provider_override =
|
|
+ std::env::var("BURROW_APPLE_PKCS11_SIGN_WITH_OPENSSL_PROVIDER")
|
|
+ .or_else(|_| std::env::var("BURROW_PKCS11_SIGN_WITH_OPENSSL_PROVIDER"))
|
|
+ .ok()
|
|
+ .and_then(|value| {
|
|
+ if value.trim().is_empty() {
|
|
+ None
|
|
+ } else {
|
|
+ Some(matches!(value.as_str(), "1" | "true" | "TRUE" | "yes" | "YES" | "on" | "ON"))
|
|
+ }
|
|
+ });
|
|
+ let use_openssl_provider = provider_override.unwrap_or_else(|| {
|
|
+ std::env::var("BURROW_APPLE_PKCS11_BACKEND")
|
|
+ .or_else(|_| std::env::var("BURROW_PKCS11_BACKEND"))
|
|
+ .map(|value| value == "gcp-kms")
|
|
+ .unwrap_or(false)
|
|
+ || self.module.to_string_lossy().contains("kmsp11")
|
|
+ || std::env::var("BURROW_GCP_KMS_PKCS11_CONFIG").is_ok()
|
|
+ || std::env::var("KMS_PKCS11_CONFIG").is_ok()
|
|
+ });
|
|
+
|
|
+ if use_openssl_provider {
|
|
+ let token_label = self.token_label.as_ref().ok_or_else(|| {
|
|
+ signature::Error::from_source(
|
|
+ "OpenSSL PKCS#11 provider signing requires --pkcs11-token-label",
|
|
+ )
|
|
+ })?;
|
|
+ let mut key_uri = format!("pkcs11:token={token_label}");
|
|
+ if let Some(label) = &self.key_label {
|
|
+ key_uri.push_str(";object=");
|
|
+ key_uri.push_str(label);
|
|
+ } else if let Some(id) = &self.key_id {
|
|
+ key_uri.push_str(";id=");
|
|
+ key_uri.push_str(id);
|
|
+ } else {
|
|
+ return Err(signature::Error::from_source(
|
|
+ "OpenSSL PKCS#11 provider signing requires --pkcs11-key-label or --pkcs11-key-id",
|
|
+ ));
|
|
+ }
|
|
+ key_uri.push_str(";type=private");
|
|
+
|
|
+ let pin_path = base.with_extension("pin");
|
|
+ std::fs::write(&pin_path, &self.pin).map_err(signature::Error::from_source)?;
|
|
+
|
|
+ let module_path = self.module.to_string_lossy();
|
|
+ let kms_config = std::env::var("KMS_PKCS11_CONFIG")
|
|
+ .or_else(|_| std::env::var("BURROW_GCP_KMS_PKCS11_CONFIG"))
|
|
+ .ok();
|
|
+ let needs_kms_config = module_path.contains("kmsp11") || kms_config.is_some();
|
|
+ if needs_kms_config {
|
|
+ let config_path = kms_config.as_ref().ok_or_else(|| {
|
|
+ signature::Error::from_source(
|
|
+ "OpenSSL PKCS#11 provider signing with Google KMS requires KMS_PKCS11_CONFIG",
|
|
+ )
|
|
+ })?;
|
|
+ let metadata = std::fs::metadata(config_path).map_err(|err| {
|
|
+ signature::Error::from_source(format!(
|
|
+ "OpenSSL PKCS#11 provider signing could not read KMS_PKCS11_CONFIG at {config_path}: {err}"
|
|
+ ))
|
|
+ })?;
|
|
+ if !metadata.is_file() || metadata.len() == 0 {
|
|
+ return Err(signature::Error::from_source(format!(
|
|
+ "OpenSSL PKCS#11 provider signing requires a non-empty KMS_PKCS11_CONFIG file at {config_path}"
|
|
+ )));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ let openssl_modules = std::env::var("BURROW_OPENSSL_MODULES")
|
|
+ .or_else(|_| std::env::var("OPENSSL_MODULES"))
|
|
+ .ok()
|
|
+ .filter(|value| !value.trim().is_empty());
|
|
+ if let Some(modules) = &openssl_modules {
|
|
+ let provider_extension = if cfg!(target_os = "macos") {
|
|
+ "dylib"
|
|
+ } else {
|
|
+ "so"
|
|
+ };
|
|
+ let provider_module = PathBuf::from(modules)
|
|
+ .join(format!("pkcs11.{provider_extension}"));
|
|
+ if provider_module.is_file() {
|
|
+ let config = format!(
|
|
+ "HOME = .\nopenssl_conf = openssl_init\n\n[openssl_init]\nproviders = provider_sect\n\n[provider_sect]\ndefault = default_sect\npkcs11 = pkcs11_sect\n\n[default_sect]\nactivate = 1\n\n[pkcs11_sect]\nmodule = {}\npkcs11-module-path = {}\npkcs11-module-token-pin = file:{}\npkcs11-module-cache-pins = cache\npkcs11-module-quirks = no-operation-state no-allowed-mechanisms\nactivate = 1\n",
|
|
+ provider_module.display(),
|
|
+ self.module.display(),
|
|
+ pin_path.display(),
|
|
+ );
|
|
+ std::fs::write(&openssl_config_path, config)
|
|
+ .map_err(signature::Error::from_source)?;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ let openssl = std::env::var("BURROW_OPENSSL").unwrap_or_else(|_| "openssl".into());
|
|
+ let mut command = Command::new(openssl);
|
|
+ command
|
|
+ .env("PKCS11_PROVIDER_MODULE", &self.module)
|
|
+ .arg("dgst")
|
|
+ .arg("-provider")
|
|
+ .arg("pkcs11")
|
|
+ .arg("-provider")
|
|
+ .arg("default")
|
|
+ .arg("-sha256")
|
|
+ .arg("-sign")
|
|
+ .arg(&key_uri)
|
|
+ .arg("-passin")
|
|
+ .arg(format!("file:{}", pin_path.display()))
|
|
+ .arg("-out")
|
|
+ .arg(&output_path)
|
|
+ .arg(&input_path);
|
|
+ if let Some(config_path) = kms_config {
|
|
+ command
|
|
+ .env("KMS_PKCS11_CONFIG", &config_path)
|
|
+ .env("BURROW_GCP_KMS_PKCS11_CONFIG", &config_path);
|
|
+ }
|
|
+ if let Ok(credentials_path) = std::env::var("GOOGLE_APPLICATION_CREDENTIALS") {
|
|
+ command.env("GOOGLE_APPLICATION_CREDENTIALS", credentials_path);
|
|
+ }
|
|
+ if let Some(modules) = openssl_modules {
|
|
+ command.env("OPENSSL_MODULES", modules);
|
|
+ }
|
|
+ if openssl_config_path.is_file() {
|
|
+ command.env("OPENSSL_CONF", &openssl_config_path);
|
|
+ }
|
|
+ if let Ok(debug) = std::env::var("BURROW_PKCS11_PROVIDER_DEBUG")
|
|
+ .or_else(|_| std::env::var("PKCS11_PROVIDER_DEBUG"))
|
|
+ {
|
|
+ command.env("PKCS11_PROVIDER_DEBUG", debug);
|
|
+ } else {
|
|
+ command.env(
|
|
+ "PKCS11_PROVIDER_DEBUG",
|
|
+ format!("file:{},level:1", provider_debug_path.display()),
|
|
+ );
|
|
+ }
|
|
+
|
|
+ let output = command.output().map_err(signature::Error::from_source)?;
|
|
+ let _ = std::fs::remove_file(&input_path);
|
|
+ let _ = std::fs::remove_file(&pin_path);
|
|
+ let _ = std::fs::remove_file(&openssl_config_path);
|
|
+
|
|
+ if !output.status.success() {
|
|
+ let _ = std::fs::remove_file(&output_path);
|
|
+ let provider_debug = std::fs::read_to_string(&provider_debug_path)
|
|
+ .ok()
|
|
+ .filter(|value| !value.trim().is_empty())
|
|
+ .map(|value| {
|
|
+ let tail = value
|
|
+ .lines()
|
|
+ .rev()
|
|
+ .take(80)
|
|
+ .collect::<Vec<_>>()
|
|
+ .into_iter()
|
|
+ .rev()
|
|
+ .collect::<Vec<_>>()
|
|
+ .join("\n");
|
|
+ format!("\nPKCS#11 provider debug tail:\n{tail}\n")
|
|
+ })
|
|
+ .unwrap_or_default();
|
|
+ let _ = std::fs::remove_file(&provider_debug_path);
|
|
+ return Err(signature::Error::from_source(format!(
|
|
+ "OpenSSL PKCS#11 provider signing failed with status {}: {}{}{}",
|
|
+ output.status,
|
|
+ String::from_utf8_lossy(&output.stdout),
|
|
+ String::from_utf8_lossy(&output.stderr),
|
|
+ provider_debug
|
|
+ )));
|
|
+ }
|
|
+ let _ = std::fs::remove_file(&provider_debug_path);
|
|
+ } else {
|
|
+ let mut command = Command::new(&self.tool);
|
|
+ command
|
|
+ .arg("--module")
|
|
+ .arg(&self.module)
|
|
+ .arg("--login")
|
|
+ .arg("--pin")
|
|
+ .arg(&self.pin)
|
|
+ .arg("--sign")
|
|
+ .arg("--mechanism")
|
|
+ .arg("SHA256-RSA-PKCS")
|
|
+ .arg("--input-file")
|
|
+ .arg(&input_path)
|
|
+ .arg("--output-file")
|
|
+ .arg(&output_path);
|
|
+
|
|
+ if let Some(slot_id) = &self.slot_id {
|
|
+ command.arg("--slot").arg(slot_id);
|
|
+ }
|
|
+ if let Some(token_label) = &self.token_label {
|
|
+ command.arg("--token-label").arg(token_label);
|
|
+ }
|
|
+ if let Some(id) = &self.key_id {
|
|
+ command.arg("--id").arg(id);
|
|
+ }
|
|
+ if let Some(label) = &self.key_label {
|
|
+ command.arg("--label").arg(label);
|
|
+ }
|
|
+
|
|
+ let output = command.output().map_err(signature::Error::from_source)?;
|
|
+
|
|
+ let _ = std::fs::remove_file(&input_path);
|
|
+
|
|
+ if !output.status.success() {
|
|
+ let _ = std::fs::remove_file(&output_path);
|
|
+ return Err(signature::Error::from_source(format!(
|
|
+ "pkcs11-tool signing failed with status {}: {}{}",
|
|
+ output.status,
|
|
+ String::from_utf8_lossy(&output.stdout),
|
|
+ String::from_utf8_lossy(&output.stderr)
|
|
+ )));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ let signature = std::fs::read(&output_path).map_err(signature::Error::from_source)?;
|
|
+ let _ = std::fs::remove_file(&output_path);
|
|
+
|
|
+ if signature.is_empty() {
|
|
+ return Err(signature::Error::from_source(
|
|
+ "pkcs11-tool produced an empty signature",
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ Ok(signature.into())
|
|
+ }
|
|
+}
|
|
@@ -204,0 +384,214 @@
|
|
+impl Sign for Pkcs11PrivateKey {
|
|
+ fn sign(&self, message: &[u8]) -> Result<(Vec<u8>, SignatureAlgorithm), X509CertificateError> {
|
|
+ let algorithm = self.signature_algorithm()?;
|
|
+
|
|
+ Ok((self.try_sign(message)?.into(), algorithm))
|
|
+ }
|
|
+
|
|
+ fn key_algorithm(&self) -> Option<KeyAlgorithm> {
|
|
+ self.cert.key_algorithm()
|
|
+ }
|
|
+
|
|
+ fn public_key_data(&self) -> Bytes {
|
|
+ self.cert.public_key_data()
|
|
+ }
|
|
+
|
|
+ fn signature_algorithm(&self) -> Result<SignatureAlgorithm, X509CertificateError> {
|
|
+ match self.cert.key_algorithm() {
|
|
+ Some(KeyAlgorithm::Rsa) => Ok(SignatureAlgorithm::RsaSha256),
|
|
+ Some(algorithm) => Err(X509CertificateError::UnknownSignatureAlgorithm(format!(
|
|
+ "PKCS#11 signing currently supports RSA certificates, not {algorithm:?}"
|
|
+ ))),
|
|
+ None => Err(X509CertificateError::UnknownSignatureAlgorithm(
|
|
+ "failed to resolve PKCS#11 certificate key algorithm".into(),
|
|
+ )),
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fn private_key_data(&self) -> Option<Zeroizing<Vec<u8>>> {
|
|
+ None
|
|
+ }
|
|
+
|
|
+ fn rsa_primes(
|
|
+ &self,
|
|
+ ) -> Result<Option<(Zeroizing<Vec<u8>>, Zeroizing<Vec<u8>>)>, X509CertificateError> {
|
|
+ Ok(None)
|
|
+ }
|
|
+}
|
|
+
|
|
+impl x509_certificate::KeyInfoSigner for Pkcs11PrivateKey {}
|
|
+
|
|
+impl PrivateKey for Pkcs11PrivateKey {
|
|
+ fn as_key_info_signer(&self) -> &dyn x509_certificate::KeyInfoSigner {
|
|
+ self
|
|
+ }
|
|
+
|
|
+ fn to_public_key_peer_decrypt(
|
|
+ &self,
|
|
+ ) -> Result<
|
|
+ Box<dyn crate::remote_signing::session_negotiation::PublicKeyPeerDecrypt>,
|
|
+ AppleCodesignError,
|
|
+ > {
|
|
+ Err(AppleCodesignError::CliGeneralError(
|
|
+ "PKCS#11 keys cannot decrypt remote-signing peer setup data".into(),
|
|
+ ))
|
|
+ }
|
|
+
|
|
+ fn finish(&self) -> Result<(), AppleCodesignError> {
|
|
+ Ok(())
|
|
+ }
|
|
+}
|
|
+
|
|
+#[derive(Args, Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
|
+#[serde(deny_unknown_fields)]
|
|
+pub struct Pkcs11SigningKey {
|
|
+ /// Path to pkcs11-tool
|
|
+ #[arg(id = "pkcs11_tool", long = "pkcs11-tool", default_value = "pkcs11-tool", value_name = "PATH")]
|
|
+ pub tool: String,
|
|
+
|
|
+ /// Path to the PKCS#11 module to use for signing
|
|
+ #[arg(
|
|
+ long = "pkcs11-library",
|
|
+ alias = "pkcs11-module",
|
|
+ id = "pkcs11_library",
|
|
+ value_name = "PATH"
|
|
+ )]
|
|
+ pub module: Option<PathBuf>,
|
|
+
|
|
+ /// PKCS#11 slot id containing the signing key
|
|
+ #[arg(id = "pkcs11_slot_id", long = "pkcs11-slot-id", value_name = "SLOT")]
|
|
+ pub slot_id: Option<String>,
|
|
+
|
|
+ /// PKCS#11 token label containing the signing key
|
|
+ #[arg(id = "pkcs11_token_label", long = "pkcs11-token-label", value_name = "LABEL")]
|
|
+ pub token_label: Option<String>,
|
|
+
|
|
+ /// PKCS#11 private-key object id, usually hex
|
|
+ #[arg(id = "pkcs11_key_id", long = "pkcs11-key-id", value_name = "ID")]
|
|
+ pub key_id: Option<String>,
|
|
+
|
|
+ /// PKCS#11 private-key object label
|
|
+ #[arg(id = "pkcs11_key_label", long = "pkcs11-key-label", value_name = "LABEL")]
|
|
+ pub key_label: Option<String>,
|
|
+
|
|
+ /// PIN used to unlock the PKCS#11 token
|
|
+ #[arg(id = "pkcs11_pin", long = "pkcs11-pin", group = "pkcs11-pin-source", value_name = "PIN")]
|
|
+ pub pin: Option<String>,
|
|
+
|
|
+ /// File containing the PIN used to unlock the PKCS#11 token
|
|
+ #[arg(id = "pkcs11_pin_file", long = "pkcs11-pin-file", group = "pkcs11-pin-source", value_name = "PATH")]
|
|
+ pub pin_path: Option<PathBuf>,
|
|
+
|
|
+ /// Environment variable holding the PIN used to unlock the PKCS#11 token
|
|
+ #[arg(id = "pkcs11_pin_env", long = "pkcs11-pin-env", group = "pkcs11-pin-source", value_name = "ENV")]
|
|
+ #[serde(skip)]
|
|
+ pub pin_env: Option<String>,
|
|
+
|
|
+ /// DER certificate file corresponding to the PKCS#11 private key
|
|
+ #[arg(
|
|
+ long = "pkcs11-certificate-file",
|
|
+ alias = "pkcs11-certificate-der-file",
|
|
+ id = "pkcs11_certificate_file",
|
|
+ value_name = "PATH"
|
|
+ )]
|
|
+ pub certificate_path: Option<PathBuf>,
|
|
+}
|
|
+
|
|
+impl Pkcs11SigningKey {
|
|
+ pub(crate) fn configured(&self) -> bool {
|
|
+ self.module.is_some()
|
|
+ || self.slot_id.is_some()
|
|
+ || self.token_label.is_some()
|
|
+ || self.key_id.is_some()
|
|
+ || self.key_label.is_some()
|
|
+ || self.pin.is_some()
|
|
+ || self.pin_path.is_some()
|
|
+ || self.pin_env.is_some()
|
|
+ || self.certificate_path.is_some()
|
|
+ }
|
|
+
|
|
+ fn not_configured(&self) -> bool {
|
|
+ !self.configured()
|
|
+ }
|
|
+
|
|
+ fn resolve_pin(&self) -> Result<String, AppleCodesignError> {
|
|
+ if let Some(pin) = &self.pin {
|
|
+ Ok(pin.clone())
|
|
+ } else if let Some(path) = &self.pin_path {
|
|
+ Ok(std::fs::read_to_string(path)?.trim().to_string())
|
|
+ } else if let Some(env) = &self.pin_env {
|
|
+ std::env::var(env).map_err(|_| {
|
|
+ AppleCodesignError::CliGeneralError(format!(
|
|
+ "failed reading PKCS#11 PIN from {env} environment variable"
|
|
+ ))
|
|
+ })
|
|
+ } else {
|
|
+ Err(AppleCodesignError::CliGeneralError(
|
|
+ "--pkcs11-pin, --pkcs11-pin-file, or --pkcs11-pin-env is required".into(),
|
|
+ ))
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+impl KeySource for Pkcs11SigningKey {
|
|
+ fn resolve_certificates(&self) -> Result<SigningCertificates, AppleCodesignError> {
|
|
+ if !self.configured() {
|
|
+ return Ok(Default::default());
|
|
+ }
|
|
+
|
|
+ let module = self.module.clone().ok_or_else(|| {
|
|
+ AppleCodesignError::CliGeneralError("--pkcs11-library is required".into())
|
|
+ })?;
|
|
+ if self.slot_id.is_none() && self.token_label.is_none() {
|
|
+ return Err(AppleCodesignError::CliGeneralError(
|
|
+ "--pkcs11-slot-id or --pkcs11-token-label is required".into(),
|
|
+ ));
|
|
+ }
|
|
+ if self.key_id.is_none() && self.key_label.is_none() {
|
|
+ return Err(AppleCodesignError::CliGeneralError(
|
|
+ "--pkcs11-key-id or --pkcs11-key-label is required".into(),
|
|
+ ));
|
|
+ }
|
|
+ let certificate_path = self.certificate_path.clone().ok_or_else(|| {
|
|
+ AppleCodesignError::CliGeneralError("--pkcs11-certificate-file is required".into())
|
|
+ })?;
|
|
+ let pin = self.resolve_pin()?;
|
|
+
|
|
+ warn!(
|
|
+ "reading PKCS#11 certificate data from {}",
|
|
+ certificate_path.display()
|
|
+ );
|
|
+ let cert = CapturedX509Certificate::from_der(std::fs::read(certificate_path)?)?;
|
|
+
|
|
+ match cert.key_algorithm() {
|
|
+ Some(KeyAlgorithm::Rsa) => {}
|
|
+ Some(algorithm) => {
|
|
+ return Err(AppleCodesignError::CliGeneralError(format!(
|
|
+ "PKCS#11 signing currently supports RSA certificates, not {algorithm:?}"
|
|
+ )));
|
|
+ }
|
|
+ None => {
|
|
+ return Err(AppleCodesignError::CliGeneralError(
|
|
+ "failed to resolve PKCS#11 certificate key algorithm".into(),
|
|
+ ));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ let signer = Pkcs11PrivateKey {
|
|
+ tool: self.tool.clone(),
|
|
+ module,
|
|
+ slot_id: self.slot_id.clone(),
|
|
+ token_label: self.token_label.clone(),
|
|
+ key_id: self.key_id.clone(),
|
|
+ key_label: self.key_label.clone(),
|
|
+ pin,
|
|
+ cert: cert.clone(),
|
|
+ };
|
|
+
|
|
+ Ok(SigningCertificates {
|
|
+ keys: vec![Box::new(signer)],
|
|
+ certs: vec![cert],
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
@@ -643,0 +1037,8 @@
|
|
+ rename = "pkcs11",
|
|
+ skip_serializing_if = "Pkcs11SigningKey::not_configured"
|
|
+ )]
|
|
+ pub pkcs11_key: Pkcs11SigningKey,
|
|
+
|
|
+ #[command(flatten)]
|
|
+ #[serde(
|
|
+ default,
|
|
@@ -680,0 +1082,2 @@
|
|
+ res.push(&self.pkcs11_key as &dyn KeySource);
|
|
+
|
|
--- a/apple-codesign/src/cli/mod.rs
|
|
+++ b/apple-codesign/src/cli/mod.rs
|
|
@@ -1529 +1532,6 @@
|
|
- let certs = c.signer.resolve_certificates(true)?;
|
|
+ let signer = if self.certificate.pkcs11_key.configured() {
|
|
+ &self.certificate
|
|
+ } else {
|
|
+ &c.signer
|
|
+ };
|
|
+ let certs = signer.resolve_certificates(true)?;
|