# Secure Archive Protocol (SAP) Implementation in IPATool: A Deep Dive into App Store Request Signing

> Discover Secure Archive Protocol SAP implementation in IPATool. Learn how it cryptographically signs App Store requests using a sandboxed runtime and plist HTTP handshake for session setup.

- Repository: [Majd/ipatool](https://github.com/majd/ipatool)
- Tags: deep-dive
- Published: 2026-09-06

---

**IPATool implements Apple's Secure Archive Protocol (SAP) in the `internal/sap` package to cryptographically sign App Store requests, using a sandboxed runtime process for the actual signing operations and a plist-based HTTP handshake for session establishment.**

The Secure Archive Protocol (SAP) is Apple's proprietary mechanism for authenticating requests to the App Store. In the `majd/ipatool` repository, the SAP implementation resides in `internal/sap` and provides a Go API that wraps Apple's binary runtime to generate valid cryptographic signatures required for purchasing and downloading apps.

## Architecture of the SAP Implementation

The implementation splits responsibilities between network handshake logic and cryptographic operations, isolating the sensitive SAP runtime in a separate process while exposing a simple `Sign` API to the rest of the application.

### The Setup Protocol Layer ([`internal/sap/protocol.go`](https://github.com/majd/ipatool/blob/main/internal/sap/protocol.go))

The `setupProtocol` struct manages the network handshake with Apple's SAP service. It retrieves certificates and exchanges encrypted setup payloads required to initialize a SAP session.

Key functions include:

- **`certificate(ctx, endpoint)`** – Performs a GET request to retrieve the plist-encoded SAP certificate from Apple's servers.
- **`exchange(ctx, endpoint, input)`** – POSTs a plist envelope containing the setup payload to the configured `SetupURL` and returns the response payload.
- **`send(request)`** – Handles low-level HTTP operations, enforcing a strict **1 MiB** size limit (`maxSetupBody`) on request and response bodies to prevent oversized data attacks.

All HTTP communication uses Apple's property list encoding via the `howett.net/plist` library.

### The Signer Abstraction ([`internal/sap/signer_local.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer_local.go))

The `Signer` struct wraps the Apple-provided SAP runtime (referred to as the "machine") and orchestrates the entire signing lifecycle.

Core methods include:

- **`NewSigner(ctx, config)`** – Loads bundled SAP binary assets from `internal/sap/assets`, initializes the sandboxed runtime via `machine.Open()`, performs the setup handshake, and returns an `ActionSigner` interface.
- **`Sign(input)`** – Accepts a byte slice payload and delegates to the machine's `Sign` method to produce the cryptographic signature that Apple expects in the `x-apple-sap-signature` header.
- **`Close()`** – Tears down the runtime process, zeroes out sensitive data including the hardware ID, and releases system resources.

## SAP Session Lifecycle and Workflow

Establishing a functional SAP session requires six distinct phases, from asset loading to cryptographic signing.

1. **Asset Loading** – The system calls `assets.Load(ctx)` to read the Apple-provided SAP binary bundle stored in `internal/sap/assets`. This binary contains the actual cryptographic implementation.

2. **Machine Initialization** – `machine.Open(ctx, bundle)` launches the SAP runtime in a sandboxed subprocess. This isolation prevents the proprietary Apple code from directly accessing the main application memory space.

3. **Session Context Creation** – `machine.Initialize(hardwareID)` creates a unique session context (returned as `uint64`) that binds the cryptographic operations to the specific device identifier.

4. **Setup Handshake** – The `setupProtocol` executes a two-step authentication dance:
   - Fetches the **SAP certificate** from the configured `CertificateURL`.
   - Creates a setup request using `machine.Exchange`, sends it via `exchange()` to the `SetupURL`, and feeds the response back to the machine to finalize the handshake.

5. **Request Signing** – Once initialized, `Signer.Sign(payload)` forwards data to the sandboxed machine, which returns a byte slice signature. IPATool attaches this to HTTP requests as the `x-apple-sap-signature` header.

6. **Resource Cleanup** – `Signer.Close()` terminates the runtime process, overwrites the hardware ID buffer with zeros, and closes all file descriptors.

## Security and Protocol Safeguards

The implementation includes specific safeguards to protect against misuse and data exfiltration.

- **Process Isolation**: The SAP binary runs in a separate sandboxed process created by `machine.Open()`, ensuring that Apple's proprietary code executes with restricted privileges.

- **Memory Sanitization**: The `Close()` method explicitly clears the `hardwareID` and other session secrets from memory before releasing resources.

- **Size Constraints**: The `send()` function enforces a `maxSetupBody` limit of **1 MiB** on all SAP setup communications, mitigating risks associated with unexpectedly large server responses.

- **Plist Encoding**: All setup protocol messages use Apple's property list format rather than JSON, maintaining compatibility with Apple's SAP endpoints.

## Integrating the SAP Signer in Your Code

Below is a complete example demonstrating how to initialize the SAP signer and use it to sign App Store requests. This pattern is used internally by IPATool when authenticating download or purchase operations.

```go
package main

import (
    "context"
    "encoding/hex"
    "log"
    
    "github.com/majd/ipatool/v2/internal/sap"
)

func main() {
    // 1️⃣ Configure SAP parameters (endpoint URLs from Apple's public documentation)
    cfg := sap.Config{
        HardwareID:     []byte{0x01, 0x02, 0x03, 0x04}, // Device-specific identifier
        CertificateURL: "https://developer.apple.com/certificates/sap",
        SetupURL:       "https://developer.apple.com/sap/setup",
        Version:        "5", // SAP protocol version
    }

    // 2️⃣ Initialize the signer (manages runtime lifecycle)
    ctx := context.Background()
    signer, err := sap.NewSigner(ctx, cfg)
    if err != nil {
        log.Fatalf("failed to initialise SAP signer: %v", err)
    }
    defer signer.Close()

    // 3️⃣ Sign a payload (e.g., App Store purchase request body)
    payload := []byte(`{"appId":"123456789","pricing":"STDQ"}`)
    signature, err := signer.Sign(payload)
    if err != nil {
        log.Fatalf("signing failed: %v", err)
    }
    
    log.Printf("SAP signature: %s", hex.EncodeToString(signature))
    
    // 4️⃣ Attach to HTTP request (as done internally in IPATool)
    // request.Header.Set("x-apple-sap-signature", hex.EncodeToString(signature))
}

```

## Summary

- **Location**: The SAP implementation lives in `internal/sap`, with protocol logic in [`protocol.go`](https://github.com/majd/ipatool/blob/main/protocol.go) and the signing API in [`signer_local.go`](https://github.com/majd/ipatool/blob/main/signer_local.go).
- **Architecture**: A two-layer design separates network handshake concerns (`setupProtocol`) from cryptographic operations (`Signer` wrapping the machine runtime).
- **Security**: The Apple SAP binary runs in a sandboxed subprocess with explicit memory sanitization and 1 MiB size limits on setup communications.
- **Workflow**: Asset loading → Machine start → Session initialization → Certificate fetch → Encrypted handshake → Signing.
- **Usage**: Call `sap.NewSigner()` with a valid `Config`, defer `Close()`, and invoke `Sign()` to generate `x-apple-sap-signature` headers for App Store requests.

## Frequently Asked Questions

### What is the Secure Archive Protocol (SAP) used for in IPATool?

The Secure Archive Protocol (SAP) is Apple's proprietary authentication mechanism that IPATool uses to cryptographically sign requests sent to the App Store. According to the `majd/ipatool` source code, SAP ensures that download and purchase requests originate from legitimate Apple devices by requiring a valid signature generated through a hardware-bound session.

### Where does IPATool store the Apple SAP binary assets?

The Apple-provided SAP binary assets are bundled in the `internal/sap/assets` directory and loaded at runtime via `assets.Load(ctx)`. These binaries contain the actual cryptographic implementation that runs inside the sandboxed process created by the machine layer in `internal/sap/machine`. The assets are not human-readable source code but compiled binaries required for the signing operation.

### How does IPATool protect against oversized SAP responses?

The `setupProtocol` implementation in [`internal/sap/protocol.go`](https://github.com/majd/ipatool/blob/main/internal/sap/protocol.go) enforces a strict **1 MiB** maximum body size through the `maxSetupBody` constant. The `send()` function checks response sizes before processing, preventing potential denial-of-service attacks or memory exhaustion from maliciously large plist payloads returned during the SAP certificate exchange or setup handshake.

### Can I reuse a SAP signer instance for multiple requests?

Yes, after initializing a signer via `sap.NewSigner()`, you can call the `Sign()` method multiple times to sign different payloads within the same session. However, you must call `Close()` when finished to terminate the sandboxed runtime process and zero out sensitive session data including the hardware ID. The example code demonstrates this pattern using `defer signer.Close()`.