Skip to main content
Apple Developer certificates are cryptographic credentials that prove your identity when signing iOS applications. They’re essential for sideloading apps to your device.

What is a certificate?

A certificate is a digital document that contains:
  • Your public key
  • Your Apple Developer identity information
  • Apple’s signature verifying the certificate is legitimate
  • An expiration date
  • A unique serial number
When combined with your private key, a certificate allows you to sign iOS applications that your device will trust.

Certificate types

Impactor uses iOS Development Certificates for sideloading:

Development Certificate

  • Used for testing apps on your devices
  • Lasts 365 days
  • Can sign apps for registered devices only
  • Created automatically by Impactor

Distribution Certificate

  • Used for App Store submissions
  • Not used by Impactor
  • Requires paid developer account
  • Can sign apps for public release

Certificate lifecycle

1

Key generation

Impactor generates a 2048-bit RSA private key on your machine:
let priv_key = RsaPrivateKey::new(&mut OsRng, 2048)?;
This key never leaves your computer and is stored securely.
2

CSR creation

A Certificate Signing Request (CSR) is created containing:
  • Your public key (derived from the private key)
  • Distinguished Name information (Country, State, Organization)
  • A unique machine ID
let mut params = rcgen::CertificateParams::new(vec![]);
params.alg = &PKCS_RSA_SHA256;
let cert_csr = rcgen::Certificate::from_params(params)?.serialize_request_pem()?;
3

Apple signature

The CSR is submitted to Apple’s servers:
pub async fn qh_submit_cert_csr(
    &self,
    team_id: &String,
    csr_data: String,
    machine_name: &String,
) -> Result<CsrResponse, Error>
Apple signs your public key with their private key, creating a trusted certificate.
4

Certificate retrieval

The signed certificate is downloaded and matched with your stored private key.Impactor verifies the certificate matches by comparing public keys:
let pub_key_der_obj = priv_key.to_public_key().to_pkcs1_der()?.as_bytes().to_vec();
let parsed_cert = X509Certificate::from_der(&cert.cert_content)?;
if pub_key_der_obj == parsed_cert.public_key_data().as_ref() {
    // Certificate matches!
}

Certificate storage

Certificates and keys are stored in your Impactor configuration directory:
~/.config/plume_impactor/keys/<team_id>/
  └── key.pem          # Your private key (NEVER share this)
Never share your private key (key.pem). Anyone with access to this file can sign apps as you and access your Apple Developer account credentials.
The certificate itself is fetched from Apple’s servers when needed, so only the private key needs to be stored locally.

Certificate limits

Free Apple Developer accounts have strict certificate limits:
  • Maximum of 2-3 active certificates at once
  • Each certificate lasts 365 days
  • When limit is reached, an old certificate must be revoked
Impactor automatically handles certificate limits by revoking old certificates when creating new ones:
if matches!(&e, Error::DeveloperApi { result_code, .. } if *result_code == 7460) {
    // Error 7460 = too many certificates
    for cid in &cert_serial_numbers {
        if session.qh_revoke_cert(&team_id, cid).await.is_ok() {
            log::warn!("Revoked certificate with serial number {}", cid);
            revoked_any = true;
            break;
        }
    }
}

Certificate identification

Each certificate has several identifying properties:
pub struct Cert {
    pub name: String,                    // Human-readable name
    pub certificate_id: String,          // Apple's internal ID
    pub serial_number: String,           // Unique serial number
    pub status: String,                  // "Issued" or "Revoked"
    pub expiration_date: Date,           // When it expires
    pub machine_id: Option<String>,      // Machine that created it
    pub machine_name: Option<String>,    // "AltStore" or custom name
}
The machine name defaults to “AltStore” for compatibility with other sideloading tools:
pub(crate) const MACHINE_NAME: &str = "AltStore";

P12 export format

Impactor can export your certificate and private key as a P12 file for use with other tools:
P12 (PKCS#12) is a binary format that bundles:
  • Your certificate
  • Your private key
  • Optional password protection
This format is used by:
  • SideStore / AltStore for wireless signing
  • LiveContainer for app management
  • Other iOS sideloading tools
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 password = if is_export {
        "".to_string()  // Empty password for exports
    } else {
        self.machine_id.as_deref().unwrap_or("").to_string()  // Machine ID for SideStore
    };
    
    keystore.writer(&password).write().ok()
}
When exporting for manual use, no password is set. When generating for SideStore, the machine ID is used as the password.

Multi-machine usage

If you use Impactor on multiple computers:
1

Copy your private key

Transfer ~/.config/plume_impactor/keys/<team_id>/key.pem from your primary machine to the same location on other machines.
2

Impactor detects the key

Impactor will automatically use the existing key and find the matching certificate from Apple’s servers.
3

Same certificate everywhere

All your machines will use the same certificate, avoiding certificate limit issues.
Without copying the key, each machine will create its own certificate, counting against your certificate limit and potentially causing issues if you exceed the maximum.

Build docs developers (and LLMs) love