forked from TrueCloudLab/certificates
Add unit tests for apple and step attestations
This commit is contained in:
parent
42102d88d5
commit
6b73a020e3
3 changed files with 419 additions and 16 deletions
|
@ -350,7 +350,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
|
|
||||||
switch att.Format {
|
switch att.Format {
|
||||||
case "apple":
|
case "apple":
|
||||||
data, err := doAppleAttestationFormat(ctx, ch, db, &att)
|
data, err := doAppleAttestationFormat(ctx, prov, ch, &att)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var acmeError *Error
|
var acmeError *Error
|
||||||
if errors.As(err, &acmeError) {
|
if errors.As(err, &acmeError) {
|
||||||
|
@ -378,7 +378,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "permanent identifier does not match"))
|
return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "permanent identifier does not match"))
|
||||||
}
|
}
|
||||||
case "step":
|
case "step":
|
||||||
data, err := doStepAttestationFormat(ctx, ch, jwk, &att)
|
data, err := doStepAttestationFormat(ctx, prov, ch, jwk, &att)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var acmeError *Error
|
var acmeError *Error
|
||||||
if errors.As(err, &acmeError) {
|
if errors.As(err, &acmeError) {
|
||||||
|
@ -444,13 +444,17 @@ type appleAttestationData struct {
|
||||||
Certificate *x509.Certificate
|
Certificate *x509.Certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
func doAppleAttestationFormat(ctx context.Context, ch *Challenge, db DB, att *AttestationObject) (*appleAttestationData, error) {
|
func doAppleAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, att *AttestationObject) (*appleAttestationData, error) {
|
||||||
root, err := pemutil.ParseCertificate([]byte(appleEnterpriseAttestationRootCA))
|
// Use configured or default attestation roots if none is configured.
|
||||||
if err != nil {
|
roots, ok := prov.GetAttestationRoots()
|
||||||
return nil, WrapErrorISE(err, "error parsing apple enterprise ca")
|
if !ok {
|
||||||
|
root, err := pemutil.ParseCertificate([]byte(appleEnterpriseAttestationRootCA))
|
||||||
|
if err != nil {
|
||||||
|
return nil, WrapErrorISE(err, "error parsing apple enterprise ca")
|
||||||
|
}
|
||||||
|
roots = x509.NewCertPool()
|
||||||
|
roots.AddCert(root)
|
||||||
}
|
}
|
||||||
roots := x509.NewCertPool()
|
|
||||||
roots.AddCert(root)
|
|
||||||
|
|
||||||
x5c, ok := att.AttStatement["x5c"].([]interface{})
|
x5c, ok := att.AttStatement["x5c"].([]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -541,13 +545,17 @@ type stepAttestationData struct {
|
||||||
SerialNumber string
|
SerialNumber string
|
||||||
}
|
}
|
||||||
|
|
||||||
func doStepAttestationFormat(ctx context.Context, ch *Challenge, jwk *jose.JSONWebKey, att *AttestationObject) (*stepAttestationData, error) {
|
func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, jwk *jose.JSONWebKey, att *AttestationObject) (*stepAttestationData, error) {
|
||||||
root, err := pemutil.ParseCertificate([]byte(yubicoPIVRootCA))
|
// Use configured or default attestation roots if none is configured.
|
||||||
if err != nil {
|
roots, ok := prov.GetAttestationRoots()
|
||||||
return nil, WrapErrorISE(err, "error parsing root ca")
|
if !ok {
|
||||||
|
root, err := pemutil.ParseCertificate([]byte(yubicoPIVRootCA))
|
||||||
|
if err != nil {
|
||||||
|
return nil, WrapErrorISE(err, "error parsing root ca")
|
||||||
|
}
|
||||||
|
roots = x509.NewCertPool()
|
||||||
|
roots.AddCert(root)
|
||||||
}
|
}
|
||||||
roots := x509.NewCertPool()
|
|
||||||
roots.AddCert(root)
|
|
||||||
|
|
||||||
// Extract x5c and verify certificate
|
// Extract x5c and verify certificate
|
||||||
x5c, ok := att.AttStatement["x5c"].([]interface{})
|
x5c, ok := att.AttStatement["x5c"].([]interface{})
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
@ -13,6 +15,7 @@ import (
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -20,13 +23,18 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.step.sm/crypto/jose"
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
|
||||||
"github.com/smallstep/assert"
|
"github.com/smallstep/assert"
|
||||||
|
"github.com/smallstep/certificates/authority/config"
|
||||||
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
|
"go.step.sm/crypto/jose"
|
||||||
|
"go.step.sm/crypto/keyutil"
|
||||||
|
"go.step.sm/crypto/minica"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockClient struct {
|
type mockClient struct {
|
||||||
|
@ -2400,3 +2408,381 @@ func Test_http01ChallengeHost(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_doAppleAttestationFormat(t *testing.T) {
|
||||||
|
makeProvisioner := func(roots []byte) Provisioner {
|
||||||
|
prov := &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
Challenges: []provisioner.ACMEChallenge{provisioner.DEVICE_ATTEST_01},
|
||||||
|
AttestationRoots: roots,
|
||||||
|
}
|
||||||
|
if err := prov.Init(provisioner.Config{
|
||||||
|
Claims: config.GlobalProvisionerClaims,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return prov
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ca, err := minica.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
caRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ca.Root.Raw})
|
||||||
|
signer, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
leaf, err := ca.Sign(&x509.Certificate{
|
||||||
|
Subject: pkix.Name{CommonName: "attestation cert"},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
|
ExtraExtensions: []pkix.Extension{
|
||||||
|
{Id: oidAppleSerialNumber, Value: []byte("serial-number")},
|
||||||
|
{Id: oidAppleUniqueDeviceIdentifier, Value: []byte("udid")},
|
||||||
|
{Id: oidAppleSecureEnclaveProcessorOSVersion, Value: []byte("16.0")},
|
||||||
|
{Id: oidAppleNonce, Value: []byte("nonce")},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
prov Provisioner
|
||||||
|
ch *Challenge
|
||||||
|
att *AttestationObject
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *appleAttestationData
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"ok", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
},
|
||||||
|
}}, &appleAttestationData{
|
||||||
|
Nonce: []byte("nonce"),
|
||||||
|
SerialNumber: "serial-number",
|
||||||
|
UDID: "udid",
|
||||||
|
SEPVersion: "16.0",
|
||||||
|
Certificate: leaf,
|
||||||
|
}, false},
|
||||||
|
{"fail apple issuer", args{ctx, makeProvisioner(nil), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail missing x5c", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail empty issuer", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{},
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail leaf type", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{"leaf", ca.Intermediate.Raw},
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail leaf parse", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw[:100], ca.Intermediate.Raw},
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail intermediate type", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, "intermediate"},
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail intermediate parse", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw[:100]},
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail verify", args{ctx, makeProvisioner(caRoot), &Challenge{}, &AttestationObject{
|
||||||
|
Format: "apple",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw},
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := doAppleAttestationFormat(tt.args.ctx, tt.args.prov, tt.args.ch, tt.args.att)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("doAppleAttestationFormat() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("doAppleAttestationFormat() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_doStepAttestationFormat(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
ca, err := minica.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
caRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ca.Root.Raw})
|
||||||
|
|
||||||
|
makeProvisioner := func(roots []byte) Provisioner {
|
||||||
|
prov := &provisioner.ACME{
|
||||||
|
Type: "ACME",
|
||||||
|
Name: "acme",
|
||||||
|
Challenges: []provisioner.ACMEChallenge{provisioner.DEVICE_ATTEST_01},
|
||||||
|
AttestationRoots: roots,
|
||||||
|
}
|
||||||
|
if err := prov.Init(provisioner.Config{
|
||||||
|
Claims: config.GlobalProvisionerClaims,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return prov
|
||||||
|
}
|
||||||
|
makeLeaf := func(signer crypto.Signer, serialNumber []byte) *x509.Certificate {
|
||||||
|
leaf, err := ca.Sign(&x509.Certificate{
|
||||||
|
Subject: pkix.Name{CommonName: "attestation cert"},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
|
ExtraExtensions: []pkix.Extension{
|
||||||
|
{Id: oidYubicoSerialNumber, Value: serialNumber},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return leaf
|
||||||
|
}
|
||||||
|
mustSigner := func(kty, crv string, size int) crypto.Signer {
|
||||||
|
s, err := keyutil.GenerateSigner(kty, crv, size)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
signer, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
serialNumber, err := asn1.Marshal(1234)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
leaf := makeLeaf(signer, serialNumber)
|
||||||
|
|
||||||
|
jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
keyAuth, err := KeyAuthorization("token", jwk)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
keyAuthSum := sha256.Sum256([]byte(keyAuth))
|
||||||
|
sig, err := signer.Sign(rand.Reader, keyAuthSum[:], crypto.SHA256)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cborSig, err := cbor.Marshal(sig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
otherSigner, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
otherSig, err := otherSigner.Sign(rand.Reader, keyAuthSum[:], crypto.SHA256)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
otherCBORSig, err := cbor.Marshal(otherSig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
prov Provisioner
|
||||||
|
ch *Challenge
|
||||||
|
jwk *jose.JSONWebKey
|
||||||
|
att *AttestationObject
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *stepAttestationData
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"ok", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, &stepAttestationData{
|
||||||
|
SerialNumber: "1234",
|
||||||
|
Certificate: leaf,
|
||||||
|
}, false},
|
||||||
|
{"fail yubico issuer", args{ctx, makeProvisioner(nil), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail x5c type", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": [][]byte{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail x5c empty", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail leaf type", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{"leaf", ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail leaf parse", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw[:100], ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail intermediate type", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, "intermediate"},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail intermediate parse", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw[:100]},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail verify", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail sig type", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": string(cborSig),
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail sig unmarshal", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": []byte("bad-sig"),
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail keyAuthorization", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, &jose.JSONWebKey{Key: []byte("not an asymmetric key")}, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail sig verify P-256", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": otherCBORSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail sig verify P-384", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{makeLeaf(mustSigner("EC", "P-384", 0), serialNumber).Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail sig verify RSA", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{makeLeaf(mustSigner("RSA", "", 2048), serialNumber).Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail sig verify Ed25519", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{makeLeaf(mustSigner("OKP", "Ed25519", 0), serialNumber).Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail unmarshal serial number", args{ctx, makeProvisioner(caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{makeLeaf(signer, []byte("bad-serial")).Raw, ca.Intermediate.Raw},
|
||||||
|
"alg": -7,
|
||||||
|
"sig": cborSig,
|
||||||
|
},
|
||||||
|
}}, nil, true},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := doStepAttestationFormat(tt.args.ctx, tt.args.prov, tt.args.ch, tt.args.jwk, tt.args.att)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("doStepAttestationFormat() error = %#v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("doStepAttestationFormat() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ type Provisioner interface {
|
||||||
AuthorizeRevoke(ctx context.Context, token string) error
|
AuthorizeRevoke(ctx context.Context, token string) error
|
||||||
IsChallengeEnabled(ctx context.Context, challenge provisioner.ACMEChallenge) bool
|
IsChallengeEnabled(ctx context.Context, challenge provisioner.ACMEChallenge) bool
|
||||||
IsAttestationFormatEnabled(ctx context.Context, format provisioner.ACMEAttestationFormat) bool
|
IsAttestationFormatEnabled(ctx context.Context, format provisioner.ACMEAttestationFormat) bool
|
||||||
|
GetAttestationRoots() (*x509.CertPool, bool)
|
||||||
GetID() string
|
GetID() string
|
||||||
GetName() string
|
GetName() string
|
||||||
DefaultTLSCertDuration() time.Duration
|
DefaultTLSCertDuration() time.Duration
|
||||||
|
@ -113,6 +114,7 @@ type MockProvisioner struct {
|
||||||
MauthorizeRevoke func(ctx context.Context, token string) error
|
MauthorizeRevoke func(ctx context.Context, token string) error
|
||||||
MisChallengeEnabled func(ctx context.Context, challenge provisioner.ACMEChallenge) bool
|
MisChallengeEnabled func(ctx context.Context, challenge provisioner.ACMEChallenge) bool
|
||||||
MisAttFormatEnabled func(ctx context.Context, format provisioner.ACMEAttestationFormat) bool
|
MisAttFormatEnabled func(ctx context.Context, format provisioner.ACMEAttestationFormat) bool
|
||||||
|
MgetAttestationRoots func() (*x509.CertPool, bool)
|
||||||
MdefaultTLSCertDuration func() time.Duration
|
MdefaultTLSCertDuration func() time.Duration
|
||||||
MgetOptions func() *provisioner.Options
|
MgetOptions func() *provisioner.Options
|
||||||
}
|
}
|
||||||
|
@ -165,6 +167,13 @@ func (m *MockProvisioner) IsAttestationFormatEnabled(ctx context.Context, format
|
||||||
return m.Merr == nil
|
return m.Merr == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockProvisioner) GetAttestationRoots() (*x509.CertPool, bool) {
|
||||||
|
if m.MgetAttestationRoots != nil {
|
||||||
|
return m.MgetAttestationRoots()
|
||||||
|
}
|
||||||
|
return m.Mret1.(*x509.CertPool), m.Mret1 != nil
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultTLSCertDuration mock
|
// DefaultTLSCertDuration mock
|
||||||
func (m *MockProvisioner) DefaultTLSCertDuration() time.Duration {
|
func (m *MockProvisioner) DefaultTLSCertDuration() time.Duration {
|
||||||
if m.MdefaultTLSCertDuration != nil {
|
if m.MdefaultTLSCertDuration != nil {
|
||||||
|
|
Loading…
Reference in a new issue