forked from TrueCloudLab/certificates
Merge pull request #1096 from smallstep/attestation-info
Attestation data
This commit is contained in:
commit
a8f9b07aae
6 changed files with 139 additions and 49 deletions
|
@ -278,6 +278,7 @@ func (c *linkedCaClient) StoreCertificateChain(p provisioner.Interface, fullchai
|
|||
PemCertificate: serializeCertificateChain(fullchain[0]),
|
||||
PemCertificateChain: serializeCertificateChain(fullchain[1:]...),
|
||||
Provisioner: createProvisionerIdentity(p),
|
||||
AttestationData: createAttestationData(p),
|
||||
RaProvisioner: raProvisioner,
|
||||
EndpointId: endpointID,
|
||||
})
|
||||
|
@ -395,26 +396,34 @@ func createProvisionerIdentity(p provisioner.Interface) *linkedca.ProvisionerIde
|
|||
}
|
||||
}
|
||||
|
||||
type raProvisioner interface {
|
||||
RAInfo() *provisioner.RAInfo
|
||||
}
|
||||
|
||||
func createRegistrationAuthorityProvisioner(p provisioner.Interface) (*linkedca.RegistrationAuthorityProvisioner, string) {
|
||||
if rap, ok := p.(raProvisioner); ok {
|
||||
info := rap.RAInfo()
|
||||
typ := linkedca.Provisioner_Type_value[strings.ToUpper(info.ProvisionerType)]
|
||||
return &linkedca.RegistrationAuthorityProvisioner{
|
||||
AuthorityId: info.AuthorityID,
|
||||
Provisioner: &linkedca.ProvisionerIdentity{
|
||||
Id: info.ProvisionerID,
|
||||
Type: linkedca.Provisioner_Type(typ),
|
||||
Name: info.ProvisionerName,
|
||||
},
|
||||
}, info.EndpointID
|
||||
if info := rap.RAInfo(); info != nil {
|
||||
typ := linkedca.Provisioner_Type_value[strings.ToUpper(info.ProvisionerType)]
|
||||
return &linkedca.RegistrationAuthorityProvisioner{
|
||||
AuthorityId: info.AuthorityID,
|
||||
Provisioner: &linkedca.ProvisionerIdentity{
|
||||
Id: info.ProvisionerID,
|
||||
Type: linkedca.Provisioner_Type(typ),
|
||||
Name: info.ProvisionerName,
|
||||
},
|
||||
}, info.EndpointID
|
||||
}
|
||||
}
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func createAttestationData(p provisioner.Interface) *linkedca.AttestationData {
|
||||
if ap, ok := p.(attProvisioner); ok {
|
||||
if data := ap.AttestationData(); data != nil {
|
||||
return &linkedca.AttestationData{
|
||||
PermanentIdentifier: data.PermanentIdentifier,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func serializeCertificate(crt *x509.Certificate) string {
|
||||
if crt == nil {
|
||||
return ""
|
||||
|
|
|
@ -25,6 +25,44 @@ import (
|
|||
"github.com/smallstep/certificates/errs"
|
||||
)
|
||||
|
||||
type raProvisioner interface {
|
||||
RAInfo() *provisioner.RAInfo
|
||||
}
|
||||
|
||||
type attProvisioner interface {
|
||||
AttestationData() *provisioner.AttestationData
|
||||
}
|
||||
|
||||
// wrapProvisioner wraps the given provisioner with RA information and
|
||||
// attestation data.
|
||||
func wrapProvisioner(p provisioner.Interface, attData *provisioner.AttestationData) *wrappedProvisioner {
|
||||
var raInfo *provisioner.RAInfo
|
||||
if rap, ok := p.(raProvisioner); ok {
|
||||
raInfo = rap.RAInfo()
|
||||
}
|
||||
|
||||
return &wrappedProvisioner{
|
||||
Interface: p,
|
||||
attestationData: attData,
|
||||
raInfo: raInfo,
|
||||
}
|
||||
}
|
||||
|
||||
// wrappedProvisioner implements raProvisioner and attProvisioner.
|
||||
type wrappedProvisioner struct {
|
||||
provisioner.Interface
|
||||
attestationData *provisioner.AttestationData
|
||||
raInfo *provisioner.RAInfo
|
||||
}
|
||||
|
||||
func (p *wrappedProvisioner) AttestationData() *provisioner.AttestationData {
|
||||
return p.attestationData
|
||||
}
|
||||
|
||||
func (p *wrappedProvisioner) RAInfo() *provisioner.RAInfo {
|
||||
return p.raInfo
|
||||
}
|
||||
|
||||
// GetEncryptedKey returns the JWE key corresponding to the given kid argument.
|
||||
func (a *Authority) GetEncryptedKey(kid string) (string, error) {
|
||||
a.adminMutex.RLock()
|
||||
|
|
|
@ -258,6 +258,11 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Sign
|
|||
}
|
||||
|
||||
fullchain := append([]*x509.Certificate{resp.Certificate}, resp.CertificateChain...)
|
||||
|
||||
// Wrap provisioner with extra information.
|
||||
prov = wrapProvisioner(prov, attData)
|
||||
|
||||
// Store certificate in the db.
|
||||
if err = a.storeCertificate(prov, fullchain); err != nil {
|
||||
if !errors.Is(err, db.ErrNotImplemented) {
|
||||
return nil, errs.Wrap(http.StatusInternalServerError, err,
|
||||
|
|
|
@ -18,8 +18,6 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
|
||||
"go.step.sm/crypto/jose"
|
||||
"go.step.sm/crypto/keyutil"
|
||||
"go.step.sm/crypto/minica"
|
||||
|
@ -59,6 +57,15 @@ func (m *certificateDurationEnforcer) Enforce(cert *x509.Certificate) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type certificateChainDB struct {
|
||||
db.MockAuthDB
|
||||
MStoreCertificateChain func(provisioner.Interface, ...*x509.Certificate) error
|
||||
}
|
||||
|
||||
func (d *certificateChainDB) StoreCertificateChain(p provisioner.Interface, certs ...*x509.Certificate) error {
|
||||
return d.MStoreCertificateChain(p, certs...)
|
||||
}
|
||||
|
||||
func getDefaultIssuer(a *Authority) *x509.Certificate {
|
||||
return a.x509CAService.(*softcas.SoftCAS).CertificateChain[len(a.x509CAService.(*softcas.SoftCAS).CertificateChain)-1]
|
||||
}
|
||||
|
@ -767,7 +774,6 @@ ZYtQ9Ot36qc=
|
|||
aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
|
||||
aa.db = &db.MockAuthDB{
|
||||
MStoreCertificate: func(crt *x509.Certificate) error {
|
||||
fmt.Println(crt.Subject)
|
||||
assert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
||||
return nil
|
||||
},
|
||||
|
@ -793,6 +799,38 @@ ZYtQ9Ot36qc=
|
|||
extensionsCount: 6,
|
||||
}
|
||||
},
|
||||
"ok with attestation data": func(t *testing.T) *signTest {
|
||||
csr := getCSR(t, priv)
|
||||
aa := testAuthority(t)
|
||||
aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
|
||||
aa.db = &certificateChainDB{
|
||||
MStoreCertificateChain: func(prov provisioner.Interface, certs ...*x509.Certificate) error {
|
||||
p, ok := prov.(attProvisioner)
|
||||
if assert.True(t, ok) {
|
||||
assert.Equals(t, &provisioner.AttestationData{
|
||||
PermanentIdentifier: "1234567890",
|
||||
}, p.AttestationData())
|
||||
}
|
||||
if assert.Len(t, 2, certs) {
|
||||
assert.Equals(t, certs[0].Subject.CommonName, "smallstep test")
|
||||
assert.Equals(t, certs[1].Subject.CommonName, "smallstep Intermediate CA")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return &signTest{
|
||||
auth: aa,
|
||||
csr: csr,
|
||||
extraOpts: append(extraOpts, provisioner.AttestationData{
|
||||
PermanentIdentifier: "1234567890",
|
||||
}),
|
||||
signOpts: signOpts,
|
||||
notBefore: signOpts.NotBefore.Time().Truncate(time.Second),
|
||||
notAfter: signOpts.NotAfter.Time().Truncate(time.Second),
|
||||
extensionsCount: 6,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
for name, genTestCase := range tests {
|
||||
|
@ -1401,15 +1439,15 @@ func TestAuthority_Revoke(t *testing.T) {
|
|||
}
|
||||
},
|
||||
"fail/nil-db": func() test {
|
||||
cl := jwt.Claims{
|
||||
cl := jose.Claims{
|
||||
Subject: "sn",
|
||||
Issuer: validIssuer,
|
||||
NotBefore: jwt.NewNumericDate(now),
|
||||
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
|
||||
NotBefore: jose.NewNumericDate(now),
|
||||
Expiry: jose.NewNumericDate(now.Add(time.Minute)),
|
||||
Audience: validAudience,
|
||||
ID: "44",
|
||||
}
|
||||
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
|
||||
raw, err := jose.Signed(sig).Claims(cl).CompactSerialize()
|
||||
assert.FatalError(t, err)
|
||||
|
||||
return test{
|
||||
|
@ -1441,15 +1479,15 @@ func TestAuthority_Revoke(t *testing.T) {
|
|||
Err: errors.New("force"),
|
||||
}))
|
||||
|
||||
cl := jwt.Claims{
|
||||
cl := jose.Claims{
|
||||
Subject: "sn",
|
||||
Issuer: validIssuer,
|
||||
NotBefore: jwt.NewNumericDate(now),
|
||||
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
|
||||
NotBefore: jose.NewNumericDate(now),
|
||||
Expiry: jose.NewNumericDate(now.Add(time.Minute)),
|
||||
Audience: validAudience,
|
||||
ID: "44",
|
||||
}
|
||||
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
|
||||
raw, err := jose.Signed(sig).Claims(cl).CompactSerialize()
|
||||
assert.FatalError(t, err)
|
||||
|
||||
return test{
|
||||
|
@ -1481,15 +1519,15 @@ func TestAuthority_Revoke(t *testing.T) {
|
|||
Err: db.ErrAlreadyExists,
|
||||
}))
|
||||
|
||||
cl := jwt.Claims{
|
||||
cl := jose.Claims{
|
||||
Subject: "sn",
|
||||
Issuer: validIssuer,
|
||||
NotBefore: jwt.NewNumericDate(now),
|
||||
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
|
||||
NotBefore: jose.NewNumericDate(now),
|
||||
Expiry: jose.NewNumericDate(now.Add(time.Minute)),
|
||||
Audience: validAudience,
|
||||
ID: "44",
|
||||
}
|
||||
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
|
||||
raw, err := jose.Signed(sig).Claims(cl).CompactSerialize()
|
||||
assert.FatalError(t, err)
|
||||
|
||||
return test{
|
||||
|
@ -1520,15 +1558,15 @@ func TestAuthority_Revoke(t *testing.T) {
|
|||
},
|
||||
}))
|
||||
|
||||
cl := jwt.Claims{
|
||||
cl := jose.Claims{
|
||||
Subject: "sn",
|
||||
Issuer: validIssuer,
|
||||
NotBefore: jwt.NewNumericDate(now),
|
||||
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
|
||||
NotBefore: jose.NewNumericDate(now),
|
||||
Expiry: jose.NewNumericDate(now.Add(time.Minute)),
|
||||
Audience: validAudience,
|
||||
ID: "44",
|
||||
}
|
||||
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
|
||||
raw, err := jose.Signed(sig).Claims(cl).CompactSerialize()
|
||||
assert.FatalError(t, err)
|
||||
return test{
|
||||
auth: _a,
|
||||
|
@ -1612,15 +1650,15 @@ func TestAuthority_Revoke(t *testing.T) {
|
|||
},
|
||||
}))
|
||||
|
||||
cl := jwt.Claims{
|
||||
cl := jose.Claims{
|
||||
Subject: "sn",
|
||||
Issuer: validIssuer,
|
||||
NotBefore: jwt.NewNumericDate(now),
|
||||
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
|
||||
NotBefore: jose.NewNumericDate(now),
|
||||
Expiry: jose.NewNumericDate(now.Add(time.Minute)),
|
||||
Audience: validAudience,
|
||||
ID: "44",
|
||||
}
|
||||
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
|
||||
raw, err := jose.Signed(sig).Claims(cl).CompactSerialize()
|
||||
assert.FatalError(t, err)
|
||||
return test{
|
||||
auth: a,
|
||||
|
|
8
go.mod
8
go.mod
|
@ -11,7 +11,7 @@ require (
|
|||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.37 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.111 // indirect
|
||||
github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd // indirect
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0
|
||||
|
@ -42,8 +42,8 @@ require (
|
|||
github.com/urfave/cli v1.22.10
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
||||
go.step.sm/cli-utils v0.7.5
|
||||
go.step.sm/crypto v0.19.1-0.20220929182301-ae99d3fe3185
|
||||
go.step.sm/linkedca v0.19.0-rc.2
|
||||
go.step.sm/crypto v0.20.0
|
||||
go.step.sm/linkedca v0.19.0-rc.3
|
||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
|
@ -59,7 +59,7 @@ require (
|
|||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
cloud.google.com/go/iam v0.3.0 // indirect
|
||||
cloud.google.com/go/kms v1.4.0 // indirect
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
|
||||
filippo.io/edwards25519 v1.0.0 // indirect
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
|
|
16
go.sum
16
go.sum
|
@ -64,8 +64,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
|||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
|
||||
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw=
|
||||
|
@ -133,8 +133,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
|
|||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.44.37 h1:KvDxCX6dfJeEDC77U5GPGSP0ErecmNnhDHFxw+NIvlI=
|
||||
github.com/aws/aws-sdk-go v1.44.37/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.44.111 h1:AcWfOgeedSQ4gQVwcIe6aLxpQNJMloZQyqnr7Dzki+s=
|
||||
github.com/aws/aws-sdk-go v1.44.111/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
|
@ -788,10 +788,10 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
|
|||
go.step.sm/cli-utils v0.7.5 h1:jyp6X8k8mN1B0uWJydTid0C++8tQhm2kaaAdXKQQzdk=
|
||||
go.step.sm/cli-utils v0.7.5/go.mod h1:taSsY8haLmXoXM3ZkywIyRmVij/4Aj0fQbNTlJvv71I=
|
||||
go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
|
||||
go.step.sm/crypto v0.19.1-0.20220929182301-ae99d3fe3185 h1:W+UhojTrFZngWTudpP3n9vPs4UNLudVSkKrWZuZg/RU=
|
||||
go.step.sm/crypto v0.19.1-0.20220929182301-ae99d3fe3185/go.mod h1:972LarNeN9dgx4+zkF3fHCnTWLXzuQSIOdMaGeIslUY=
|
||||
go.step.sm/linkedca v0.19.0-rc.2 h1:IcPqZ5y7MZNq1+VbYQcKoQEvX80NKRncU1WFCDyY+So=
|
||||
go.step.sm/linkedca v0.19.0-rc.2/go.mod h1:MCZmPIdzElEofZbiw4eyUHayXgFTwa94cNAV34aJ5ew=
|
||||
go.step.sm/crypto v0.20.0 h1:IMZUjTdol70IxOLZYHt8AHJy9uIHz/PvDOi2S+urpOs=
|
||||
go.step.sm/crypto v0.20.0/go.mod h1:diT2XWIHQy0397UI3i78qCKeLLLp2wu0/DIJI66u/MU=
|
||||
go.step.sm/linkedca v0.19.0-rc.3 h1:3Uu8j187wm7mby+/pz/aQ0wHKRm7w/2AsVPpvcAn4v8=
|
||||
go.step.sm/linkedca v0.19.0-rc.3/go.mod h1:MCZmPIdzElEofZbiw4eyUHayXgFTwa94cNAV34aJ5ew=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
|
|
Loading…
Reference in a new issue