Skip to main content
Impactor can generate and export P12 (PKCS#12) certificates that contain your Apple Developer signing identity. These certificates are used by apps like SideStore, AltStore, and LiveContainer for automatic app refresh and signing.

What is a P12 certificate?

A P12 file is a PKCS#12 archive containing:
  • Your Apple Developer certificate (X.509)
  • The corresponding private key (RSA 2048-bit)
  • Optional password protection
  • Certificate chain information
These certificates last 365 days and are generated when you first sign with your Apple ID.

Automatic P12 embedding

Impactor automatically embeds P12 certificates in supported apps during signing:

SideStore / AltStore

For direct installations:
// From plume_utils/src/signer.rs:118
bundle.set_info_plist_key("ALTCertificateID", &**serial_number)?;
fs::write(bundle.bundle_dir().join("ALTCertificate.p12"), p12_data).await?;
The P12 file is written to the app bundle root as ALTCertificate.p12 with the serial number stored in Info.plist.

LiveContainer with SideStore

For LiveContainer installations:
// From plume_utils/src/signer.rs:108
if let Some(embedded_bundle) = bundles
    .iter()
    .find(|b| b.bundle_dir().ends_with("SideStoreApp.framework"))
{
    embedded_bundle.set_info_plist_key("ALTCertificateID", &**serial_number)?;
    fs::write(
        embedded_bundle.bundle_dir().join("ALTCertificate.p12"),
        p12_data,
    ).await?;
}
The P12 is embedded in the SideStoreApp.framework bundle.

P12 generation process

1

Certificate retrieval

Impactor retrieves your signing certificate from Apple’s Developer API:
// From plume_core/src/utils/certificate.rs:79
let certs = session.qh_list_certs(&team_id).await?.certificates;
2

Key management

Your private key is stored locally in ~/.config/plume/keys/<team_id>/key.pem:
// From plume_core/src/utils/certificate.rs:65
let key_path = Self::key_dir(config_path, &team_id)?.join("key.pem");
If no key exists, a new 2048-bit RSA key is generated.
3

P12 creation

The certificate and key are packaged into PKCS#12 format:
// From plume_core/src/utils/certificate.rs:163
pub fn create_pkcs12(&self, data: &[Vec<u8>; 2], is_export: bool) -> Option<Vec<u8>> {
    let cert_der = pem::parse(&data[0]).ok()?.contents().to_vec();
    let key_der = pem::parse(&data[1]).ok()?.contents().to_vec();
    
    let cert = p12_keystore::Certificate::from_der(&cert_der).ok()?;
    let key_chain = p12_keystore::PrivateKeyChain::new(key_der, local_key_id, vec![cert]);
    
    let mut keystore = p12_keystore::KeyStore::new();
    keystore.add_entry("plume", p12_keystore::KeyStoreEntry::PrivateKeyChain(key_chain));
}
4

Password handling

Password is set based on the export type:
// From plume_core/src/utils/certificate.rs:188
let password = if is_export {
    "".to_string()  // Empty password for manual export
} else {
    self.machine_id.as_deref().unwrap_or("").to_string()  // Machine ID for SideStore
};

Export modes

For SideStore/AltStore (automatic)

Password: Machine ID from the certificate
  • Used for automatic refresh functionality
  • Embedded directly in the app during signing
  • SideStore locates the certificate by matching the machine ID

For manual export

Password: Empty string (no password)
  • Designed for manual installation
  • Compatible with LiveContainer’s import feature
  • Easy to install without password prompts
When exporting for LiveContainer, use the “Export P12” option in Impactor’s interface. This creates a password-free P12 file.

Using P12 with LiveContainer

1

Generate P12

In Impactor, navigate to Utilities → Export P12 Certificate.
2

Transfer to device

Transfer the exported P12 file to your device via:
  • AirDrop
  • iTunes File Sharing
  • Cloud storage (iCloud, Dropbox, etc.)
3

Import in LiveContainer

Open LiveContainer → Settings → Import Certificate → Select your P12 file.
4

Enable auto-refresh

LiveContainer can now sign and refresh apps automatically using your certificate.

Certificate matching

Impactor finds existing certificates by matching public keys:
// From plume_core/src/utils/certificate.rs:224
async fn find_certificate(
    &mut self,
    certs: Vec<Cert>,
    priv_key: &RsaPrivateKey,
    machine_name: &str,
) -> Result<Option<Cert>, Error> {
    let pub_key_der_obj = priv_key.to_public_key().to_pkcs1_der()?.as_bytes().to_vec();
    
    for cert in certs {
        if cert.machine_name.as_deref() == Some(machine_name) {
            let parsed_cert = X509Certificate::from_der(&cert.cert_content)?;
            if pub_key_der_obj == parsed_cert.public_key_data().as_ref() {
                return Ok(Some(cert));
            }
        }
    }
}
This ensures you reuse existing certificates across multiple machines.

Certificate lifecycle

Creation

New certificates are created via CSR (Certificate Signing Request):
// From plume_core/src/utils/certificate.rs:251
async fn request_new_certificate(
    &mut self,
    session: &DeveloperSession,
    team_id: &String,
    machine_name: &String,
    certs: Vec<Cert>,
) -> Result<(Cert, RsaPrivateKey), Error> {
    let priv_key = RsaPrivateKey::new(&mut OsRng, 2048)?;
    let cert_csr = rcgen::Certificate::from_params(params)?.serialize_request_pem()?;
    
    let cert_id = session
        .qh_submit_cert_csr(&team_id, cert_csr.clone(), machine_name)
        .await?;
}

Revocation

Free Apple Developer accounts are limited to 2 certificates. If the limit is reached, Impactor automatically revokes old certificates:
// From plume_core/src/utils/certificate.rs:286
loop {
    match session.qh_submit_cert_csr(&team_id, cert_csr.clone(), machine_name).await {
        Ok(id) => break id,
        Err(e) => {
            // Error code 7460 = too many certificates
            if matches!(&e, Error::DeveloperApi { result_code, .. } if *result_code == 7460) {
                for cid in &cert_serial_numbers {
                    if session.qh_revoke_cert(&team_id, cid).await.is_ok() {
                        break;
                    }
                }
            }
        }
    }
}

Expiration

Certificates last 365 days and must be renewed:
  • Impactor automatically creates new certificates when needed
  • Old keys are preserved for signature verification
  • Apps signed with expired certificates continue to work for their 7-day period

Technical details

Key storage

Private keys are stored in PEM format:
~/.config/plume/keys/<team_id>/key.pem
Keep your private keys secure. They grant full access to sign apps with your Apple ID.

Local key ID

The P12 local key ID is derived from the private key using SHA-1:
// From plume_core/src/utils/certificate.rs:169
let local_key_id = {
    use sha1::{Digest, Sha1};
    let mut hasher = Sha1::new();
    hasher.update(&key_der);
    let hash = hasher.finalize();
    hash[..8].to_vec()
};
This ensures consistent identification across imports and exports.

Modern encryption

Impactor uses modern PKCS#12 encryption via the p12-keystore crate:
// From plume_core/src/utils/certificate.rs:194
let writer = keystore.writer(&password);
writer.write().ok()
This provides better security than legacy PFX formats.

Exporting via CLI

For command-line usage:
plumesign account export-p12 \
  --email [email protected] \
  --output certificate.p12
The exported P12 will have no password and can be imported into any compatible app.

Troubleshooting

”Certificate not found” error

  • Ensure you’ve signed at least one app with your Apple ID
  • Check that your certificate hasn’t been revoked
  • Verify your internet connection for API access

SideStore can’t find certificate

  • Verify the ALTCertificateID matches the serial number
  • Ensure ALTCertificate.p12 exists in the app bundle
  • Check that the P12 password matches the machine ID

LiveContainer import fails

  • Ensure the P12 was exported with no password
  • Verify the certificate is still valid (not expired)
  • Check that the P12 file wasn’t corrupted during transfer

”Too many certificates” error

This occurs on free developer accounts with 2+ certificates:
  • Impactor automatically revokes old certificates
  • You can manually revoke certificates at developer.apple.com
  • Paid developer accounts support more certificates

Security best practices

  1. Never share your P12 files - They contain your signing identity
  2. Keep private keys secure - Store them in ~/.config/plume/keys/
  3. Use strong passwords - For exported P12 files intended for backup
  4. Revoke compromised certificates - If you suspect your keys were exposed
  5. Back up your keys - Before reformatting or switching machines

Next steps

Pairing Files

Generate pairing files for remote access

Entitlements

Understand entitlement handling

Build docs developers (and LLMs) love