From 5f5315260a470e25f907922fc3c5286c364ecdd5 Mon Sep 17 00:00:00 2001 From: Brandon Weeks Date: Mon, 6 Jun 2022 21:09:31 -0700 Subject: [PATCH] iOS 16 beta 1 support --- acme/api/order.go | 2 + acme/challenge.go | 107 +++++++++++++++++++++++++++++----------------- acme/order.go | 10 +++++ 3 files changed, 80 insertions(+), 39 deletions(-) diff --git a/acme/api/order.go b/acme/api/order.go index 0c81df76..2f6cd776 100644 --- a/acme/api/order.go +++ b/acme/api/order.go @@ -399,6 +399,8 @@ func challengeTypes(az *acme.Authorization) []acme.ChallengeType { } case acme.PermanentIdentifier: chTypes = []acme.ChallengeType{acme.DEVICEATTEST01} + case acme.CA: + chTypes = []acme.ChallengeType{acme.APPLEATTEST01} default: chTypes = []acme.ChallengeType{} } diff --git a/acme/challenge.go b/acme/challenge.go index 585050fa..8a369342 100644 --- a/acme/challenge.go +++ b/acme/challenge.go @@ -16,11 +16,13 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" + "encoding/pem" "errors" "fmt" "io" "net" "net/url" + "os" "reflect" "strconv" "strings" @@ -43,6 +45,7 @@ const ( TLSALPN01 ChallengeType = "tls-alpn-01" // DEVICEATTEST01 is the device-attest-01 ACME challenge type DEVICEATTEST01 ChallengeType = "device-attest-01" + APPLEATTEST01 ChallengeType = "client-01" ) // Challenge represents an ACME response Challenge type. @@ -86,6 +89,8 @@ func (ch *Challenge) Validate(ctx context.Context, db DB, jwk *jose.JSONWebKey, return tlsalpn01Validate(ctx, ch, db, jwk) case DEVICEATTEST01: return deviceAttest01Validate(ctx, ch, db, jwk, payload) + case APPLEATTEST01: + return appleAttest01Validate(ctx, ch, db, jwk, payload) default: return NewErrorISE("unexpected challenge type '%s'", ch.Type) } @@ -349,7 +354,6 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose NewError(ErrorBadAttestationStatementType, "attestation format %q is not enabled", att.Format)) } -<<<<<<< HEAD switch att.Format { case "apple": data, err := doAppleAttestationFormat(ctx, prov, ch, &att) @@ -362,44 +366,6 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose return storeError(ctx, db, ch, true, acmeError) } return WrapErrorISE(err, "error validating attestation") -======= - akCertBytes, valid := x5c[0].([]byte) - if !valid { - return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType, - "error getting certificate from x5c cert chain")) - } - - akCert, err := x509.ParseCertificate(akCertBytes) - if err != nil { - return WrapErrorISE(err, "error parsing AK certificate") - } - - if err := params.Verify(attest.VerifyOpts{Public: akCert.PublicKey, Hash: crypto.SHA256}); err != nil { - return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType, - "params.Verify failed: %v", err)) - } - - attData, err := tpm2.DecodeAttestationData(params.CreateAttestation) - if err != nil { - return WrapErrorISE(err, "error decoding attestation data") - } - - keyAuth, err := KeyAuthorization(ch.Token, jwk) - if err != nil { - return err - } - hashedKeyAuth := sha256.Sum256([]byte(keyAuth)) - - if !bytes.Equal(attData.ExtraData, hashedKeyAuth[:]) { - return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType, - "key authorization mismatch")) - } - - var sanExt pkix.Extension - for _, ext := range akCert.Extensions { - if ext.Id.Equal(oid.SubjectAltName) { - sanExt = ext ->>>>>>> b02694a3 (Verify key authorization is contained within the TPM quote extraData field) } // Validate nonce with SHA-256 of the token. @@ -452,6 +418,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose return nil } +<<<<<<< HEAD // Apple Enterprise Attestation Root CA from // https://www.apple.com/certificateauthority/private/ const appleEnterpriseAttestationRootCA = `-----BEGIN CERTIFICATE----- @@ -692,6 +659,68 @@ func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challeng } return data, nil +======= +type ApplePayload struct { + AttObj string `json:"attObj"` + Error string `json:"error"` +} + +func appleAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, payload []byte) error { + var p ApplePayload + if err := json.Unmarshal(payload, &p); err != nil { + return WrapErrorISE(err, "error unmarshalling JSON") + } + + fmt.Fprintf(os.Stderr, "p.AttObj: %v\n", p.AttObj) + + attObj, err := base64.RawURLEncoding.DecodeString(p.AttObj) + if err != nil { + return WrapErrorISE(err, "error base64 decoding attObj") + } + + att := AttestationObject{} + if err := cbor.Unmarshal(attObj, &att); err != nil { + return WrapErrorISE(err, "error unmarshalling CBOR") + } + + if att.Format != "apple" { + return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatement, + "unexpected attestation object format")) + } + + x5c, x509present := att.AttStatement["x5c"].([]interface{}) + if !x509present { + return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatement, + "x5c not present")) + } + + attCertBytes, valid := x5c[0].([]byte) + if !valid { + return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType, + "error getting certificate from x5c cert chain")) + } + + attCert, err := x509.ParseCertificate(attCertBytes) + if err != nil { + return WrapErrorISE(err, "error parsing AK certificate") + } + + b := &pem.Block{ + Type: "CERTIFICATE", + Bytes: attCert.Raw, + } + pem.Encode(os.Stderr, b) + + // Update and store the challenge. + ch.Status = StatusValid + ch.Error = nil + ch.ValidatedAt = clock.Now().Format(time.RFC3339) + + if err := db.UpdateChallenge(ctx, ch); err != nil { + return WrapErrorISE(err, "error updating challenge") + } + return nil +>>>>>>> 26e1b4ba (iOS 16 beta 1 support) } // serverName determines the SNI HostName to set based on an acme.Challenge diff --git a/acme/order.go b/acme/order.go index 8f74695d..127edb74 100644 --- a/acme/order.go +++ b/acme/order.go @@ -5,7 +5,9 @@ import ( "context" "crypto/x509" "encoding/json" + "encoding/pem" "net" + "os" "sort" "strings" "time" @@ -26,6 +28,7 @@ const ( // PermanentIdentifier is the ACME permanent-identifier identifier type // defined in https://datatracker.ietf.org/doc/html/draft-bweeks-acme-device-attest-00 PermanentIdentifier IdentifierType = "permanent-identifier" + CA IdentifierType = "ca" ) // Identifier encodes the type that an order pertains to. @@ -152,6 +155,12 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques return NewErrorISE("unexpected status %s for order %s", o.Status, o.ID) } + b := &pem.Block{ + Type: "CERTIFICATE REQUEST", + Bytes: csr.Raw, + } + pem.Encode(os.Stderr, b) + // canonicalize the CSR to allow for comparison csr = canonicalize(csr) @@ -260,6 +269,7 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ case PermanentIdentifier: orderPIDs[indexPID] = n.Value indexPID++ + case CA: default: return sans, NewErrorISE("unsupported identifier type in order: %s", n.Type) }