Documentation
¶
Overview ¶
Package cms signs and verifies attached and detached CMS signatures used by Apple device management.
Design ¶
Detached signatures authenticate Mdm-Signature request bodies; attached signatures carry configuration-profile content. Verification requires one signer and supports explicit trust roots, an injected clock and configured signing-time tolerance. The tolerant path still validates digest, attributes, signature and chain.
A valid signature proves key possession, not authorization for an enrollment. HTTP certificate extraction and service pinning apply that separate policy. Callers select trust roots and whether profile parsing requires a signature.
References ¶
- Decision record 0006: https://github.com/deploymenttheory/go-apple-dm/blob/main/docs/research/decisions/0006-mdm-signature-verification.md
- Decision record 0009: https://github.com/deploymenttheory/go-apple-dm/blob/main/docs/research/decisions/0009-enrollment-profiles.md
- Threat model: https://github.com/deploymenttheory/go-apple-dm/blob/main/docs/security/threat-model.md (/checkin and /connect rows)
- Apple: https://developer.apple.com/documentation/devicemanagement/check-in
- Apple: https://developer.apple.com/documentation/devicemanagement/managing-certificates-for-device-management-services-and-devices
- Schema: third_party/device-management/mdm/profiles/com.apple.mdm.yaml (SignMessage)
- RFC 5652 (Cryptographic Message Syntax): https://www.rfc-editor.org/rfc/rfc5652
Index ¶
- Constants
- Variables
- func DecodeHeader(header string) ([]byte, error)
- func EncodeHeader(der []byte) string
- func Fingerprint(cert *x509.Certificate) string
- func IsSigned(data []byte) bool
- func Sign(content []byte, cert *x509.Certificate, key crypto.Signer) ([]byte, error)
- func SignAttached(content []byte, cert *x509.Certificate, key crypto.Signer) ([]byte, error)
- func Verify(der, content []byte, o VerifyOptions) (*x509.Certificate, error)
- func VerifyAttached(der []byte, o VerifyOptions) ([]byte, *x509.Certificate, error)
- func VerifyAttachedWith(der []byte, o VerifyAttachedOptions) ([]byte, *x509.Certificate, error)
- func VerifyHeader(header string, body []byte, o VerifyOptions) (*x509.Certificate, error)
- type VerifyAttachedOptions
- type VerifyOptions
Constants ¶
const HeaderName = "Mdm-Signature"
HeaderName is the HTTP header Apple devices use.
Variables ¶
var ( ErrHeader = errors.New("cms: malformed Mdm-Signature header") ErrParse = errors.New("cms: malformed CMS structure") ErrNoSigner = errors.New("cms: no signer") ErrMultipleSigners = errors.New("cms: more than one signer") ErrSignature = errors.New("cms: signature verification failed") ErrSigningTime = errors.New("cms: signing time outside certificate validity") ErrChain = errors.New("cms: certificate chain verification failed") ErrAlgorithm = errors.New("cms: unsupported algorithm") ErrSign = errors.New("cms: signing failed") )
Errors returned by this package.
Functions ¶
func DecodeHeader ¶
DecodeHeader parses an Mdm-Signature header value.
func EncodeHeader ¶
EncodeHeader renders a DER signature as the Mdm-Signature header value.
func Fingerprint ¶
func Fingerprint(cert *x509.Certificate) string
Fingerprint is the lower-case hex SHA-256 of the certificate's DER, the value stored for identity pinning.
func IsSigned ¶
IsSigned reports whether data looks like a DER CMS structure rather than a plain plist, so callers can accept both signed and unsigned profiles.
func Sign ¶
Sign produces a detached, DER-encoded CMS SignedData over content with SHA-256, signed by key and carrying cert.
func SignAttached ¶
SignAttached produces a CMS SignedData with the content embedded, which is what signed configuration profiles are (a .mobileconfig whose bytes are the DER structure).
func Verify ¶
func Verify(der, content []byte, o VerifyOptions) (*x509.Certificate, error)
Verify checks a detached signature over content and returns the signer certificate.
func VerifyAttached ¶
func VerifyAttached(der []byte, o VerifyOptions) ([]byte, *x509.Certificate, error)
VerifyAttached checks an attached signature and returns the embedded content and the signer certificate. The same trust and skew options as Verify apply.
func VerifyAttachedWith ¶
func VerifyAttachedWith(der []byte, o VerifyAttachedOptions) ([]byte, *x509.Certificate, error)
VerifyAttachedWith verifies an attached SignedData the way Apple device identities sign MachineInfo: exactly one signer whose certificate is in the bundle; when authenticated attributes are present the signature covers their DER SET and the messageDigest attribute must equal the digest of the content while contentType must be id-data, otherwise the signature covers the content; digest and signature algorithms are taken from the SignerInfo. It returns the embedded content and the signer.
func VerifyHeader ¶
func VerifyHeader(header string, body []byte, o VerifyOptions) (*x509.Certificate, error)
VerifyHeader verifies an Mdm-Signature header against the request body.
Types ¶
type VerifyAttachedOptions ¶
type VerifyAttachedOptions struct {
VerifyOptions
// IgnoreValidity builds the certificate path by name and signature
// alone, without applying validity windows. Apple device identities
// chain through the Apple iPhone Device CA, which expired in 2014 and
// still issues current leaves, so stock chain verification cannot
// accept them. SHA-1 signatures are tolerated on this path because the
// chain uses them.
IgnoreValidity bool
// Anchors are trust anchors matched by identity: the path is accepted
// when it reaches a certificate issued (by name and signature) by one
// of them, or one of them itself. They are the trust store for
// IgnoreValidity, since a CertPool cannot be walked; when
// IgnoreValidity is false they are added to Roots. Nil Anchors and nil
// Roots skip chain verification, as in Verify.
Anchors []*x509.Certificate
}
VerifyAttachedOptions control VerifyAttachedWith.
type VerifyOptions ¶
type VerifyOptions struct {
// Roots, when set, requires the signer certificate to chain to one of
// them (intermediates from the CMS structure are used). Nil skips chain
// verification and only checks the signature itself.
Roots *x509.CertPool
// Now supplies the verification time; defaults to time.Now.
Now func() time.Time
// ClockSkew tolerates a signing time this far outside the signer
// certificate's validity. Zero means no tolerance.
ClockSkew time.Duration
}
VerifyOptions control Verify.