Documentation
¶
Overview ¶
Package pushcert parses APNs push certificates and derives their topic.
Why ¶
Apple puts the push topic in the certificate's subject UID attribute (OID 0.9.2342.19200300.100.1.1); it always starts with "com.apple.mgmt", and the Topic a device reports in Authenticate and TokenUpdate must match it. Phase 4 of the plan of record stores push certificates in the database (decision record 0015), so both the storage backends and the push package need to prove that a PEM pair is a valid certificate with its matching key and to learn its topic before accepting it.
This package imports only the standard library on purpose: storage backends import it to validate uploaded push certificates, and push imports storage, so any dependency on push would create an import cycle. Sending pushes is push and push/apns.
References ¶
- Decision record 0007: docs/research/decisions/0007-apns-push.md
- Decision record 0015: docs/research/decisions/0015-push-cert-store.md
- Plan of record: docs/research/implementation_plan.md (phase 4)
- Threat model: docs/security/threat-model.md (wrong or expired push certificate row)
- Apple: https://developer.apple.com/documentation/devicemanagement/setting-up-push-notifications-for-your-device-management-customers
- Apple: https://developer.apple.com/documentation/devicemanagement/managing-certificates-for-device-management-services-and-devices
- Schema: third_party/device-management/mdm/checkin/authenticate.yaml, tokenupdate.yaml (Topic)
Index ¶
Constants ¶
const TopicPrefix = "com.apple.mgmt"
TopicPrefix is the prefix every MDM push topic starts with.
Variables ¶
var ( ErrInvalid = errors.New("pushcert: invalid certificate or key") ErrNoTopic = errors.New("pushcert: no APNs topic in certificate subject") ErrKeyMismatch = errors.New("pushcert: private key does not match certificate") )
Errors returned by this package.
Functions ¶
func TopicFromCert ¶
func TopicFromCert(cert *x509.Certificate) (string, error)
TopicFromCert returns the topic in cert's subject UID. It returns ErrNoTopic when the attribute is absent or does not start with TopicPrefix.
Types ¶
type Parsed ¶
type Parsed struct {
// TLS is ready to use as a client certificate: Leaf is set and
// Certificate[0] is the leaf DER, followed by any chain certificates.
TLS tls.Certificate
// Leaf is the push certificate itself.
Leaf *x509.Certificate
// Topic is the APNs topic from the leaf's subject UID.
Topic string
// NotBefore and NotAfter are copied from the leaf.
NotBefore, NotAfter time.Time
}
Parsed is a validated certificate and key pair.
func Parse ¶
Parse decodes a PEM certificate and a PEM private key, checks that the key matches the leaf's public key, and derives the topic from the leaf's subject UID. The first CERTIFICATE block is the leaf; further CERTIFICATE blocks are kept as the chain. The key may be PKCS#1 RSA, PKCS#8, or SEC 1 EC; encrypted keys are rejected. Errors wrap ErrInvalid, ErrKeyMismatch, or ErrNoTopic.