# How the SAP Signer Validates Configurations and Endpoints in ipatool

> Learn how the SAP signer in ipatool validates configurations and endpoints. It enforces SAP version 200, hardware ID limits, and absolute HTTPS URLs for secure runtime initialization.

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

---

**The SAP signer in ipatool validates configurations by enforcing a strict SAP version of 200, restricting hardware identifiers to 1-20 bytes, and requiring absolute HTTPS URLs for both setup and certificate endpoints before initializing the secure runtime.**

The `internal/sap` package in the [majd/ipatool](https://github.com/majdiyatool) repository implements the Secure Acquisition Protocol (SAP) used to authenticate requests with Apple’s services. Before performing any cryptographic operations or network calls, the signer performs rigorous validation to prevent malformed configurations from reaching the underlying SAP runtime.

## Configuration Validation in internal/sap/signer.go

All validation logic resides in [`internal/sap/signer.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer.go), where the `validateConfig` function acts as the gatekeeper for signer construction. This function validates two critical aspects of the provided `Config` struct: protocol version compatibility and hardware identifier constraints.

### SAP Version and Hardware ID Constraints

The signer requires a specific SAP protocol version defined by the constant `supportedVersion = uint32(200)`. The `validateConfig` function rejects any configuration where `config.Version` does not exactly match this constant. Additionally, the hardware identifier must be a non-empty byte slice containing between 1 and 20 bytes.

```go
const supportedVersion = uint32(200)

func validateConfig(config Config) error {
    if config.Version != supportedVersion {
        return fmt.Errorf("unsupported SAP version %d", config.Version)
    }
    if len(config.HardwareID) == 0 || len(config.HardwareID) > 20 {
        return errors.New("SAP hardware ID must contain between 1 and 20 bytes")
    }
    // ... endpoint validation
}

```

These checks ensure compatibility with the specific Apple SAP runtime bundled in `internal/sap/assets`, preventing version mismatches that could cause cryptographic failures or undefined behavior in the underlying native code.

### Endpoint URL Security Checks

The `validateEndpoint` helper function parses each URL using `net/url.Parse` and enforces strict security policies. Both `SetupURL` and `CertificateURL` must satisfy four conditions: they must parse successfully, use the **HTTPS** scheme, contain a non-empty host, and include no user authentication information (username/password).

```go
func validateEndpoint(label, value string) error {
    endpoint, err := url.Parse(value)
    if err != nil || endpoint.Scheme != "https" || endpoint.Host == "" || endpoint.User != nil {
        return fmt.Errorf("SAP %s URL must be an absolute HTTPS URL", label)
    }
    return nil
}

```

The `validateConfig` function invokes this helper for both endpoints, aborting immediately if either check fails:

```go
if err := validateEndpoint("setup", config.SetupURL); err != nil {
    return err
}
if err := validateEndpoint("certificate", config.CertificateURL); err != nil {
    return err
}

```

## Validation Execution During Signer Initialization

Validation occurs inside the `NewSigner` constructor found in [`internal/sap/signer_local.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer_local.go). This constructor executes `validateConfig` before loading SAP assets, opening the secure machine context, or performing the setup exchange with Apple’s servers.

```go
func NewSigner(ctx context.Context, config Config) (Signer, error) {
    if err := validateConfig(config); err != nil {
        return nil, err
    }
    // ... proceed with asset loading and machine initialization
}

```

By validating early in the constructor, the signer guarantees that only well-formed configurations reach the low-level `internal/sap/machine` wrappers, eliminating the risk of sending malformed hardware identifiers or insecure HTTP URLs to the Apple SAP runtime.

## Practical Implementation Example

The following example demonstrates proper configuration of the SAP signer with valid parameters that pass all validation checks:

```go
package main

import (
    "context"
    "log"
    "time"

    "github.com/majdiyatool/v2/internal/sap"
)

func main() {
    cfg := sap.Config{
        SetupURL:       "https://setup.apple.com/sap",
        CertificateURL: "https://cert.apple.com/sap",
        Version:        200, // Must match supportedVersion constant
        HardwareID:     []byte{0x01, 0x02, 0x03}, // 3 bytes, valid range
    }

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    // Validation occurs here; returns error if checks fail
    signer, err := sap.NewSigner(ctx, cfg)
    if err != nil {
        log.Fatalf("SAP signer validation failed: %v", err)
    }
    defer signer.Close()

    // Signer ready for cryptographic operations
    payload := []byte("authentication request")
    signature, err := signer.Sign(payload)
    if err != nil {
        log.Fatalf("Signing failed: %v", err)
    }
    
    log.Printf("Generated SAP signature: %x", signature)
}

```

This implementation pattern ensures that invalid URLs, incorrect protocol versions, or malformed hardware identifiers trigger immediate, descriptive errors during initialization rather than during network communication.

## Summary

- **Version Lock**: The SAP signer strictly requires `config.Version` to equal `200` as defined in [`internal/sap/signer.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer.go).
- **Hardware Constraints**: Hardware identifiers must contain 1-20 bytes; empty or oversized identifiers are rejected.
- **HTTPS Enforcement**: Both `SetupURL` and `CertificateURL` must be absolute HTTPS URLs with valid hosts and no embedded credentials.
- **Early Validation**: All checks execute in `NewSigner` (from [`internal/sap/signer_local.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer_local.go)) before any asset loading or network operations occur.
- **Security First**: The validation layer prevents malformed configurations from reaching the native SAP runtime in `internal/sap/machine`.

## Frequently Asked Questions

### What SAP version does ipatool support?

According to the source code in [`internal/sap/signer.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer.go), ipatool supports only SAP version `200`. The `validateConfig` function compares `config.Version` against the `supportedVersion` constant (declared as `uint32(200)`) and returns an error if they do not match, ensuring compatibility with the bundled SAP runtime assets.

### Why does the SAP signer require absolute HTTPS URLs?

The `validateEndpoint` function in [`internal/sap/signer.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer.go) explicitly checks that `endpoint.Scheme` equals `"https"` and that `endpoint.Host` is non-empty. This prevents man-in-the-middle attacks and credential leakage by blocking HTTP endpoints, relative paths, and URLs containing user authentication information (`endpoint.User != nil`).

### What happens if the hardware ID is empty or too long?

The signer returns an immediate error with the message `"SAP hardware ID must contain between 1 and 20 bytes"` if `len(config.HardwareID)` is zero or exceeds 20 bytes. This validation occurs in `validateConfig` before the `NewSigner` constructor proceeds, ensuring the hardware identifier conforms to Apple SAP protocol specifications.

### Where does validation occur in the signer lifecycle?

Validation occurs during signer construction in `NewSigner` within [`internal/sap/signer_local.go`](https://github.com/majd/ipatool/blob/main/internal/sap/signer_local.go). The constructor calls `validateConfig` immediately after receiving the configuration struct, aborting initialization if any checks fail. This ensures that no network calls, asset loading, or machine context creation occurs with invalid parameters.