forked from TrueCloudLab/certificates
iOS 16 beta 1 support
This commit is contained in:
parent
de5b0ef5c2
commit
5f5315260a
3 changed files with 80 additions and 39 deletions
|
@ -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{}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue