forked from TrueCloudLab/certificates
Merge pull request #1265 from smallstep/check-csr-acme-da
Verify CSR key fingerprint with attestation certificate key
This commit is contained in:
commit
c2c246b062
10 changed files with 793 additions and 450 deletions
|
@ -8,15 +8,16 @@ import (
|
||||||
|
|
||||||
// Authorization representst an ACME Authorization.
|
// Authorization representst an ACME Authorization.
|
||||||
type Authorization struct {
|
type Authorization struct {
|
||||||
ID string `json:"-"`
|
ID string `json:"-"`
|
||||||
AccountID string `json:"-"`
|
AccountID string `json:"-"`
|
||||||
Token string `json:"-"`
|
Token string `json:"-"`
|
||||||
Identifier Identifier `json:"identifier"`
|
Fingerprint string `json:"-"`
|
||||||
Status Status `json:"status"`
|
Identifier Identifier `json:"identifier"`
|
||||||
Challenges []*Challenge `json:"challenges"`
|
Status Status `json:"status"`
|
||||||
Wildcard bool `json:"wildcard"`
|
Challenges []*Challenge `json:"challenges"`
|
||||||
ExpiresAt time.Time `json:"expires"`
|
Wildcard bool `json:"wildcard"`
|
||||||
Error *Error `json:"error,omitempty"`
|
ExpiresAt time.Time `json:"expires"`
|
||||||
|
Error *Error `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToLog enables response logging.
|
// ToLog enables response logging.
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/fxamacker/cbor/v2"
|
"github.com/fxamacker/cbor/v2"
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
|
"go.step.sm/crypto/keyutil"
|
||||||
"go.step.sm/crypto/pemutil"
|
"go.step.sm/crypto/pemutil"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
|
@ -347,6 +348,13 @@ type attestationObject struct {
|
||||||
|
|
||||||
// TODO(bweeks): move attestation verification to a shared package.
|
// TODO(bweeks): move attestation verification to a shared package.
|
||||||
func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, payload []byte) error {
|
func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, payload []byte) error {
|
||||||
|
// Load authorization to store the key fingerprint.
|
||||||
|
az, err := db.GetAuthorization(ctx, ch.AuthorizationID)
|
||||||
|
if err != nil {
|
||||||
|
return WrapErrorISE(err, "error loading authorization")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse payload.
|
||||||
var p payloadType
|
var p payloadType
|
||||||
if err := json.Unmarshal(payload, &p); err != nil {
|
if err := json.Unmarshal(payload, &p); err != nil {
|
||||||
return WrapErrorISE(err, "error unmarshalling JSON")
|
return WrapErrorISE(err, "error unmarshalling JSON")
|
||||||
|
@ -385,7 +393,6 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
}
|
}
|
||||||
return WrapErrorISE(err, "error validating attestation")
|
return WrapErrorISE(err, "error validating attestation")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate nonce with SHA-256 of the token.
|
// Validate nonce with SHA-256 of the token.
|
||||||
if len(data.Nonce) != 0 {
|
if len(data.Nonce) != 0 {
|
||||||
sum := sha256.Sum256([]byte(ch.Token))
|
sum := sha256.Sum256([]byte(ch.Token))
|
||||||
|
@ -401,6 +408,9 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
if data.UDID != ch.Value && data.SerialNumber != ch.Value {
|
if data.UDID != ch.Value && data.SerialNumber != ch.Value {
|
||||||
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"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update attestation key fingerprint to compare against the CSR
|
||||||
|
az.Fingerprint = data.Fingerprint
|
||||||
case "step":
|
case "step":
|
||||||
data, err := doStepAttestationFormat(ctx, prov, ch, jwk, &att)
|
data, err := doStepAttestationFormat(ctx, prov, ch, jwk, &att)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -426,6 +436,9 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
)
|
)
|
||||||
return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "permanent identifier does not match").AddSubproblems(subproblem))
|
return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "permanent identifier does not match").AddSubproblems(subproblem))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update attestation key fingerprint to compare against the CSR
|
||||||
|
az.Fingerprint = data.Fingerprint
|
||||||
default:
|
default:
|
||||||
return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "unexpected attestation object format"))
|
return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "unexpected attestation object format"))
|
||||||
}
|
}
|
||||||
|
@ -435,6 +448,15 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
ch.Error = nil
|
ch.Error = nil
|
||||||
ch.ValidatedAt = clock.Now().Format(time.RFC3339)
|
ch.ValidatedAt = clock.Now().Format(time.RFC3339)
|
||||||
|
|
||||||
|
// Store the fingerprint in the authorization.
|
||||||
|
//
|
||||||
|
// TODO: add method to update authorization and challenge atomically.
|
||||||
|
if az.Fingerprint != "" {
|
||||||
|
if err := db.UpdateAuthorization(ctx, az); err != nil {
|
||||||
|
return WrapErrorISE(err, "error updating authorization")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := db.UpdateChallenge(ctx, ch); err != nil {
|
if err := db.UpdateChallenge(ctx, ch); err != nil {
|
||||||
return WrapErrorISE(err, "error updating challenge")
|
return WrapErrorISE(err, "error updating challenge")
|
||||||
}
|
}
|
||||||
|
@ -471,6 +493,7 @@ type appleAttestationData struct {
|
||||||
UDID string
|
UDID string
|
||||||
SEPVersion string
|
SEPVersion string
|
||||||
Certificate *x509.Certificate
|
Certificate *x509.Certificate
|
||||||
|
Fingerprint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func doAppleAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, att *attestationObject) (*appleAttestationData, error) {
|
func doAppleAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, att *attestationObject) (*appleAttestationData, error) {
|
||||||
|
@ -527,6 +550,9 @@ func doAppleAttestationFormat(ctx context.Context, prov Provisioner, ch *Challen
|
||||||
data := &appleAttestationData{
|
data := &appleAttestationData{
|
||||||
Certificate: leaf,
|
Certificate: leaf,
|
||||||
}
|
}
|
||||||
|
if data.Fingerprint, err = keyutil.Fingerprint(leaf.PublicKey); err != nil {
|
||||||
|
return nil, WrapErrorISE(err, "error calculating key fingerprint")
|
||||||
|
}
|
||||||
for _, ext := range leaf.Extensions {
|
for _, ext := range leaf.Extensions {
|
||||||
switch {
|
switch {
|
||||||
case ext.Id.Equal(oidAppleSerialNumber):
|
case ext.Id.Equal(oidAppleSerialNumber):
|
||||||
|
@ -572,6 +598,7 @@ var oidYubicoSerialNumber = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 41482, 3, 7}
|
||||||
type stepAttestationData struct {
|
type stepAttestationData struct {
|
||||||
Certificate *x509.Certificate
|
Certificate *x509.Certificate
|
||||||
SerialNumber string
|
SerialNumber string
|
||||||
|
Fingerprint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func doStepAttestationFormat(ctx context.Context, prov Provisioner, 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) {
|
||||||
|
@ -667,6 +694,9 @@ func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challeng
|
||||||
data := &stepAttestationData{
|
data := &stepAttestationData{
|
||||||
Certificate: leaf,
|
Certificate: leaf,
|
||||||
}
|
}
|
||||||
|
if data.Fingerprint, err = keyutil.Fingerprint(leaf.PublicKey); err != nil {
|
||||||
|
return nil, WrapErrorISE(err, "error calculating key fingerprint")
|
||||||
|
}
|
||||||
for _, ext := range leaf.Extensions {
|
for _, ext := range leaf.Extensions {
|
||||||
if !ext.Id.Equal(oidYubicoSerialNumber) {
|
if !ext.Id.Equal(oidYubicoSerialNumber) {
|
||||||
continue
|
continue
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,7 @@ type dbAuthz struct {
|
||||||
Identifier acme.Identifier `json:"identifier"`
|
Identifier acme.Identifier `json:"identifier"`
|
||||||
Status acme.Status `json:"status"`
|
Status acme.Status `json:"status"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
Fingerprint string `json:"fingerprint,omitempty"`
|
||||||
ChallengeIDs []string `json:"challengeIDs"`
|
ChallengeIDs []string `json:"challengeIDs"`
|
||||||
Wildcard bool `json:"wildcard"`
|
Wildcard bool `json:"wildcard"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
@ -61,15 +62,16 @@ func (db *DB) GetAuthorization(ctx context.Context, id string) (*acme.Authorizat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &acme.Authorization{
|
return &acme.Authorization{
|
||||||
ID: dbaz.ID,
|
ID: dbaz.ID,
|
||||||
AccountID: dbaz.AccountID,
|
AccountID: dbaz.AccountID,
|
||||||
Identifier: dbaz.Identifier,
|
Identifier: dbaz.Identifier,
|
||||||
Status: dbaz.Status,
|
Status: dbaz.Status,
|
||||||
Challenges: chs,
|
Challenges: chs,
|
||||||
Wildcard: dbaz.Wildcard,
|
Wildcard: dbaz.Wildcard,
|
||||||
ExpiresAt: dbaz.ExpiresAt,
|
ExpiresAt: dbaz.ExpiresAt,
|
||||||
Token: dbaz.Token,
|
Token: dbaz.Token,
|
||||||
Error: dbaz.Error,
|
Fingerprint: dbaz.Fingerprint,
|
||||||
|
Error: dbaz.Error,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +99,7 @@ func (db *DB) CreateAuthorization(ctx context.Context, az *acme.Authorization) e
|
||||||
Identifier: az.Identifier,
|
Identifier: az.Identifier,
|
||||||
ChallengeIDs: chIDs,
|
ChallengeIDs: chIDs,
|
||||||
Token: az.Token,
|
Token: az.Token,
|
||||||
|
Fingerprint: az.Fingerprint,
|
||||||
Wildcard: az.Wildcard,
|
Wildcard: az.Wildcard,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,8 +114,8 @@ func (db *DB) UpdateAuthorization(ctx context.Context, az *acme.Authorization) e
|
||||||
}
|
}
|
||||||
|
|
||||||
nu := old.clone()
|
nu := old.clone()
|
||||||
|
|
||||||
nu.Status = az.Status
|
nu.Status = az.Status
|
||||||
|
nu.Fingerprint = az.Fingerprint
|
||||||
nu.Error = az.Error
|
nu.Error = az.Error
|
||||||
return db.save(ctx, old.ID, nu, old, "authz", authzTable)
|
return db.save(ctx, old.ID, nu, old, "authz", authzTable)
|
||||||
}
|
}
|
||||||
|
@ -136,15 +139,16 @@ func (db *DB) GetAuthorizationsByAccountID(ctx context.Context, accountID string
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
authzs = append(authzs, &acme.Authorization{
|
authzs = append(authzs, &acme.Authorization{
|
||||||
ID: dbaz.ID,
|
ID: dbaz.ID,
|
||||||
AccountID: dbaz.AccountID,
|
AccountID: dbaz.AccountID,
|
||||||
Identifier: dbaz.Identifier,
|
Identifier: dbaz.Identifier,
|
||||||
Status: dbaz.Status,
|
Status: dbaz.Status,
|
||||||
Challenges: nil, // challenges not required for current use case
|
Challenges: nil, // challenges not required for current use case
|
||||||
Wildcard: dbaz.Wildcard,
|
Wildcard: dbaz.Wildcard,
|
||||||
ExpiresAt: dbaz.ExpiresAt,
|
ExpiresAt: dbaz.ExpiresAt,
|
||||||
Token: dbaz.Token,
|
Token: dbaz.Token,
|
||||||
Error: dbaz.Error,
|
Fingerprint: dbaz.Fingerprint,
|
||||||
|
Error: dbaz.Error,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -473,6 +473,7 @@ func TestDB_UpdateAuthorization(t *testing.T) {
|
||||||
ExpiresAt: now.Add(5 * time.Minute),
|
ExpiresAt: now.Add(5 * time.Minute),
|
||||||
ChallengeIDs: []string{"foo", "bar"},
|
ChallengeIDs: []string{"foo", "bar"},
|
||||||
Wildcard: true,
|
Wildcard: true,
|
||||||
|
Fingerprint: "fingerprint",
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(dbaz)
|
b, err := json.Marshal(dbaz)
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
|
@ -549,10 +550,11 @@ func TestDB_UpdateAuthorization(t *testing.T) {
|
||||||
{ID: "foo"},
|
{ID: "foo"},
|
||||||
{ID: "bar"},
|
{ID: "bar"},
|
||||||
},
|
},
|
||||||
Token: dbaz.Token,
|
Token: dbaz.Token,
|
||||||
Wildcard: dbaz.Wildcard,
|
Wildcard: dbaz.Wildcard,
|
||||||
ExpiresAt: dbaz.ExpiresAt,
|
ExpiresAt: dbaz.ExpiresAt,
|
||||||
Error: acme.NewError(acme.ErrorMalformedType, "malformed"),
|
Fingerprint: "fingerprint",
|
||||||
|
Error: acme.NewError(acme.ErrorMalformedType, "malformed"),
|
||||||
}
|
}
|
||||||
return test{
|
return test{
|
||||||
az: updAz,
|
az: updAz,
|
||||||
|
@ -582,6 +584,7 @@ func TestDB_UpdateAuthorization(t *testing.T) {
|
||||||
assert.Equals(t, dbNew.Wildcard, dbaz.Wildcard)
|
assert.Equals(t, dbNew.Wildcard, dbaz.Wildcard)
|
||||||
assert.Equals(t, dbNew.CreatedAt, dbaz.CreatedAt)
|
assert.Equals(t, dbNew.CreatedAt, dbaz.CreatedAt)
|
||||||
assert.Equals(t, dbNew.ExpiresAt, dbaz.ExpiresAt)
|
assert.Equals(t, dbNew.ExpiresAt, dbaz.ExpiresAt)
|
||||||
|
assert.Equals(t, dbNew.Fingerprint, dbaz.Fingerprint)
|
||||||
assert.Equals(t, dbNew.Error.Error(), acme.NewError(acme.ErrorMalformedType, "The request message was malformed").Error())
|
assert.Equals(t, dbNew.Error.Error(), acme.NewError(acme.ErrorMalformedType, "The request message was malformed").Error())
|
||||||
return nu, true, nil
|
return nu, true, nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ package acme
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/subtle"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
|
@ -11,6 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
|
"go.step.sm/crypto/keyutil"
|
||||||
"go.step.sm/crypto/x509util"
|
"go.step.sm/crypto/x509util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -125,6 +127,27 @@ func (o *Order) UpdateStatus(ctx context.Context, db DB) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getKeyFingerprint returns a fingerprint from the list of authorizations. This
|
||||||
|
// fingerprint is used on the device-attest-01 flow to verify the attestation
|
||||||
|
// certificate public key with the CSR public key.
|
||||||
|
//
|
||||||
|
// There's no point on reading all the authorizations as there will be only one
|
||||||
|
// for a permanent identifier.
|
||||||
|
func (o *Order) getAuthorizationFingerprint(ctx context.Context, db DB) (string, error) {
|
||||||
|
for _, azID := range o.AuthorizationIDs {
|
||||||
|
az, err := db.GetAuthorization(ctx, azID)
|
||||||
|
if err != nil {
|
||||||
|
return "", WrapErrorISE(err, "error getting authorization %q", azID)
|
||||||
|
}
|
||||||
|
// There's no point on reading all the authorizations as there will
|
||||||
|
// be only one for a permanent identifier.
|
||||||
|
if az.Fingerprint != "" {
|
||||||
|
return az.Fingerprint, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// Finalize signs a certificate if the necessary conditions for Order completion
|
// Finalize signs a certificate if the necessary conditions for Order completion
|
||||||
// have been met.
|
// have been met.
|
||||||
//
|
//
|
||||||
|
@ -150,6 +173,24 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques
|
||||||
return NewErrorISE("unexpected status %s for order %s", o.Status, o.ID)
|
return NewErrorISE("unexpected status %s for order %s", o.Status, o.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get key fingerprint if any. And then compare it with the CSR fingerprint.
|
||||||
|
//
|
||||||
|
// In device-attest-01 challenges we should check that the keys in the CSR
|
||||||
|
// and the attestation certificate are the same.
|
||||||
|
fingerprint, err := o.getAuthorizationFingerprint(ctx, db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if fingerprint != "" {
|
||||||
|
fp, err := keyutil.Fingerprint(csr.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return WrapErrorISE(err, "error calculating key fingerprint")
|
||||||
|
}
|
||||||
|
if subtle.ConstantTimeCompare([]byte(fingerprint), []byte(fp)) == 0 {
|
||||||
|
return NewError(ErrorUnauthorizedType, "order %s csr does not match the attested key", o.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// canonicalize the CSR to allow for comparison
|
// canonicalize the CSR to allow for comparison
|
||||||
csr = canonicalize(csr)
|
csr = canonicalize(csr)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
"github.com/smallstep/assert"
|
"github.com/smallstep/assert"
|
||||||
"github.com/smallstep/certificates/authority"
|
"github.com/smallstep/certificates/authority"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
|
"go.step.sm/crypto/keyutil"
|
||||||
"go.step.sm/crypto/x509util"
|
"go.step.sm/crypto/x509util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -308,6 +310,14 @@ func (m *mockSignAuth) Revoke(context.Context, *authority.RevokeOptions) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOrder_Finalize(t *testing.T) {
|
func TestOrder_Finalize(t *testing.T) {
|
||||||
|
mustSigner := func(kty, crv string, size int) crypto.Signer {
|
||||||
|
s, err := keyutil.GenerateSigner(kty, crv, size)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
o *Order
|
o *Order
|
||||||
err *Error
|
err *Error
|
||||||
|
@ -400,10 +410,18 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
{Type: "permanent-identifier", Value: "a-permanent-identifier"},
|
{Type: "permanent-identifier", Value: "a-permanent-identifier"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signer := mustSigner("EC", "P-256", 0)
|
||||||
|
fingerprint, err := keyutil.Fingerprint(signer.Public())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
csr := &x509.CertificateRequest{
|
csr := &x509.CertificateRequest{
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
CommonName: "a-different-identifier",
|
CommonName: "a-different-identifier",
|
||||||
},
|
},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
ExtraExtensions: []pkix.Extension{
|
ExtraExtensions: []pkix.Extension{
|
||||||
{
|
{
|
||||||
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
||||||
|
@ -414,6 +432,29 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
return test{
|
return test{
|
||||||
o: o,
|
o: o,
|
||||||
csr: csr,
|
csr: csr,
|
||||||
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
switch id {
|
||||||
|
case "a":
|
||||||
|
return &Authorization{
|
||||||
|
ID: id,
|
||||||
|
Status: StatusValid,
|
||||||
|
}, nil
|
||||||
|
case "b":
|
||||||
|
return &Authorization{
|
||||||
|
ID: id,
|
||||||
|
Fingerprint: fingerprint,
|
||||||
|
Status: StatusValid,
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
assert.FatalError(t, errors.Errorf("unexpected authorization %s", id))
|
||||||
|
return nil, errors.New("force")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MockUpdateOrder: func(ctx context.Context, o *Order) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
err: &Error{
|
err: &Error{
|
||||||
Type: "urn:ietf:params:acme:error:badCSR",
|
Type: "urn:ietf:params:acme:error:badCSR",
|
||||||
Detail: "The CSR is unacceptable",
|
Detail: "The CSR is unacceptable",
|
||||||
|
@ -452,6 +493,11 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
err: NewErrorISE("error retrieving authorization options from ACME provisioner: force"),
|
err: NewErrorISE("error retrieving authorization options from ACME provisioner: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -491,6 +537,11 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
err: NewErrorISE("error creating template options from ACME provisioner: error unmarshaling template data: invalid character 'o' in literal false (expecting 'a')"),
|
err: NewErrorISE("error creating template options from ACME provisioner: error unmarshaling template data: invalid character 'o' in literal false (expecting 'a')"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -532,6 +583,11 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
return nil, errors.New("force")
|
return nil, errors.New("force")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
err: NewErrorISE("error signing certificate for order oID: force"),
|
err: NewErrorISE("error signing certificate for order oID: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -578,6 +634,9 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db: &MockDB{
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
assert.Equals(t, cert.AccountID, o.AccountID)
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
assert.Equals(t, cert.OrderID, o.ID)
|
assert.Equals(t, cert.OrderID, o.ID)
|
||||||
|
@ -632,6 +691,9 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db: &MockDB{
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
cert.ID = "certID"
|
cert.ID = "certID"
|
||||||
assert.Equals(t, cert.AccountID, o.AccountID)
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
|
@ -654,7 +716,7 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
err: NewErrorISE("error updating order oID: force"),
|
err: NewErrorISE("error updating order oID: force"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ok/permanent-identifier": func(t *testing.T) test {
|
"fail/csr-fingerprint": func(t *testing.T) test {
|
||||||
now := clock.Now()
|
now := clock.Now()
|
||||||
o := &Order{
|
o := &Order{
|
||||||
ID: "oID",
|
ID: "oID",
|
||||||
|
@ -666,10 +728,14 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
{Type: "permanent-identifier", Value: "a-permanent-identifier"},
|
{Type: "permanent-identifier", Value: "a-permanent-identifier"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signer := mustSigner("EC", "P-256", 0)
|
||||||
|
|
||||||
csr := &x509.CertificateRequest{
|
csr := &x509.CertificateRequest{
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
CommonName: "a-permanent-identifier",
|
CommonName: "a-permanent-identifier",
|
||||||
},
|
},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
ExtraExtensions: []pkix.Extension{
|
ExtraExtensions: []pkix.Extension{
|
||||||
{
|
{
|
||||||
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
||||||
|
@ -679,7 +745,8 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf := &x509.Certificate{
|
leaf := &x509.Certificate{
|
||||||
Subject: pkix.Name{CommonName: "a-permanent-identifier"},
|
Subject: pkix.Name{CommonName: "a-permanent-identifier"},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
ExtraExtensions: []pkix.Extension{
|
ExtraExtensions: []pkix.Extension{
|
||||||
{
|
{
|
||||||
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
||||||
|
@ -709,6 +776,117 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db: &MockDB{
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{
|
||||||
|
ID: id,
|
||||||
|
Fingerprint: "other-fingerprint",
|
||||||
|
Status: StatusValid,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
|
cert.ID = "certID"
|
||||||
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
|
assert.Equals(t, cert.OrderID, o.ID)
|
||||||
|
assert.Equals(t, cert.Leaf, leaf)
|
||||||
|
assert.Equals(t, cert.Intermediates, []*x509.Certificate{inter, root})
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
MockUpdateOrder: func(ctx context.Context, updo *Order) error {
|
||||||
|
assert.Equals(t, updo.CertificateID, "certID")
|
||||||
|
assert.Equals(t, updo.Status, StatusValid)
|
||||||
|
assert.Equals(t, updo.ID, o.ID)
|
||||||
|
assert.Equals(t, updo.AccountID, o.AccountID)
|
||||||
|
assert.Equals(t, updo.ExpiresAt, o.ExpiresAt)
|
||||||
|
assert.Equals(t, updo.AuthorizationIDs, o.AuthorizationIDs)
|
||||||
|
assert.Equals(t, updo.Identifiers, o.Identifiers)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: NewError(ErrorUnauthorizedType, "order oID csr does not match the attested key"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ok/permanent-identifier": func(t *testing.T) test {
|
||||||
|
now := clock.Now()
|
||||||
|
o := &Order{
|
||||||
|
ID: "oID",
|
||||||
|
AccountID: "accID",
|
||||||
|
Status: StatusReady,
|
||||||
|
ExpiresAt: now.Add(5 * time.Minute),
|
||||||
|
AuthorizationIDs: []string{"a", "b"},
|
||||||
|
Identifiers: []Identifier{
|
||||||
|
{Type: "permanent-identifier", Value: "a-permanent-identifier"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
signer := mustSigner("EC", "P-256", 0)
|
||||||
|
fingerprint, err := keyutil.Fingerprint(signer.Public())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
csr := &x509.CertificateRequest{
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: "a-permanent-identifier",
|
||||||
|
},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
|
ExtraExtensions: []pkix.Extension{
|
||||||
|
{
|
||||||
|
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
||||||
|
Value: []byte("a-permanent-identifier"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf := &x509.Certificate{
|
||||||
|
Subject: pkix.Name{CommonName: "a-permanent-identifier"},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
|
ExtraExtensions: []pkix.Extension{
|
||||||
|
{
|
||||||
|
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
||||||
|
Value: []byte("a-permanent-identifier"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
inter := &x509.Certificate{Subject: pkix.Name{CommonName: "inter"}}
|
||||||
|
root := &x509.Certificate{Subject: pkix.Name{CommonName: "root"}}
|
||||||
|
|
||||||
|
return test{
|
||||||
|
o: o,
|
||||||
|
csr: csr,
|
||||||
|
prov: &MockProvisioner{
|
||||||
|
MauthorizeSign: func(ctx context.Context, token string) ([]provisioner.SignOption, error) {
|
||||||
|
assert.Equals(t, token, "")
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
MgetOptions: func() *provisioner.Options {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ca: &mockSignAuth{
|
||||||
|
sign: func(_csr *x509.CertificateRequest, signOpts provisioner.SignOptions, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) {
|
||||||
|
assert.Equals(t, _csr, csr)
|
||||||
|
return []*x509.Certificate{leaf, inter, root}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
switch id {
|
||||||
|
case "a":
|
||||||
|
return &Authorization{
|
||||||
|
ID: id,
|
||||||
|
Status: StatusValid,
|
||||||
|
}, nil
|
||||||
|
case "b":
|
||||||
|
return &Authorization{
|
||||||
|
ID: id,
|
||||||
|
Fingerprint: fingerprint,
|
||||||
|
Status: StatusValid,
|
||||||
|
}, nil
|
||||||
|
default:
|
||||||
|
assert.FatalError(t, errors.Errorf("unexpected authorization %s", id))
|
||||||
|
return nil, errors.New("force")
|
||||||
|
}
|
||||||
|
},
|
||||||
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
cert.ID = "certID"
|
cert.ID = "certID"
|
||||||
assert.Equals(t, cert.AccountID, o.AccountID)
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
|
@ -743,11 +921,19 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
{Type: "permanent-identifier", Value: "a-permanent-identifier"},
|
{Type: "permanent-identifier", Value: "a-permanent-identifier"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signer := mustSigner("EC", "P-256", 0)
|
||||||
|
fingerprint, err := keyutil.Fingerprint(signer.Public())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
csr := &x509.CertificateRequest{
|
csr := &x509.CertificateRequest{
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
CommonName: "a-permanent-identifier",
|
CommonName: "a-permanent-identifier",
|
||||||
},
|
},
|
||||||
DNSNames: []string{"foo.internal"},
|
DNSNames: []string{"foo.internal"},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
ExtraExtensions: []pkix.Extension{
|
ExtraExtensions: []pkix.Extension{
|
||||||
{
|
{
|
||||||
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
||||||
|
@ -757,7 +943,8 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf := &x509.Certificate{
|
leaf := &x509.Certificate{
|
||||||
Subject: pkix.Name{CommonName: "a-permanent-identifier"},
|
Subject: pkix.Name{CommonName: "a-permanent-identifier"},
|
||||||
|
PublicKey: signer.Public(),
|
||||||
ExtraExtensions: []pkix.Extension{
|
ExtraExtensions: []pkix.Extension{
|
||||||
{
|
{
|
||||||
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 8, 3},
|
||||||
|
@ -792,6 +979,13 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db: &MockDB{
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{
|
||||||
|
ID: id,
|
||||||
|
Fingerprint: fingerprint,
|
||||||
|
Status: StatusValid,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
cert.ID = "certID"
|
cert.ID = "certID"
|
||||||
assert.Equals(t, cert.AccountID, o.AccountID)
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
|
@ -856,6 +1050,9 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db: &MockDB{
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
cert.ID = "certID"
|
cert.ID = "certID"
|
||||||
assert.Equals(t, cert.AccountID, o.AccountID)
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
|
@ -917,6 +1114,9 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db: &MockDB{
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
cert.ID = "certID"
|
cert.ID = "certID"
|
||||||
assert.Equals(t, cert.AccountID, o.AccountID)
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
|
@ -981,6 +1181,9 @@ func TestOrder_Finalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db: &MockDB{
|
db: &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
MockCreateCertificate: func(ctx context.Context, cert *Certificate) error {
|
||||||
cert.ID = "certID"
|
cert.ID = "certID"
|
||||||
assert.Equals(t, cert.AccountID, o.AccountID)
|
assert.Equals(t, cert.AccountID, o.AccountID)
|
||||||
|
@ -1688,3 +1891,55 @@ func TestOrder_sans(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOrder_getAuthorizationFingerprint(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
type fields struct {
|
||||||
|
AuthorizationIDs []string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
db DB
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"ok", fields{[]string{"az1", "az2"}}, args{ctx, &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
},
|
||||||
|
}}, "", false},
|
||||||
|
{"ok fingerprint", fields{[]string{"az1", "az2"}}, args{ctx, &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
if id == "az1" {
|
||||||
|
return &Authorization{ID: id, Status: StatusValid}, nil
|
||||||
|
}
|
||||||
|
return &Authorization{ID: id, Fingerprint: "fingerprint", Status: StatusValid}, nil
|
||||||
|
},
|
||||||
|
}}, "fingerprint", false},
|
||||||
|
{"fail", fields{[]string{"az1", "az2"}}, args{ctx, &MockDB{
|
||||||
|
MockGetAuthorization: func(ctx context.Context, id string) (*Authorization, error) {
|
||||||
|
return nil, errors.New("force")
|
||||||
|
},
|
||||||
|
}}, "", true},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
o := &Order{
|
||||||
|
AuthorizationIDs: tt.fields.AuthorizationIDs,
|
||||||
|
}
|
||||||
|
got, err := o.getAuthorizationFingerprint(tt.args.ctx, tt.args.db)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Order.getAuthorizationFingerprint() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("Order.getAuthorizationFingerprint() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
step.Set("Smallstep CA", Version, BuildTime)
|
step.Set("Smallstep CA", Version, BuildTime)
|
||||||
authority.GlobalVersion.Version = Version
|
authority.GlobalVersion.Version = Version
|
||||||
|
//nolint:staticcheck // deprecated in Go 1.20
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
// Add support for asking passwords
|
// Add support for asking passwords
|
||||||
pemutil.PromptPassword = func(msg string) ([]byte, error) {
|
pemutil.PromptPassword = func(msg string) ([]byte, error) {
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -12,7 +12,7 @@ require (
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3
|
github.com/Masterminds/sprig/v3 v3.2.3
|
||||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.44.185 // indirect
|
github.com/aws/aws-sdk-go v1.44.195 // indirect
|
||||||
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
||||||
github.com/fatih/color v1.9.0 // indirect
|
github.com/fatih/color v1.9.0 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.4.0
|
github.com/fxamacker/cbor/v2 v2.4.0
|
||||||
|
@ -43,7 +43,7 @@ require (
|
||||||
github.com/urfave/cli v1.22.12
|
github.com/urfave/cli v1.22.12
|
||||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
||||||
go.step.sm/cli-utils v0.7.5
|
go.step.sm/cli-utils v0.7.5
|
||||||
go.step.sm/crypto v0.23.2
|
go.step.sm/crypto v0.25.0
|
||||||
go.step.sm/linkedca v0.19.0
|
go.step.sm/linkedca v0.19.0
|
||||||
golang.org/x/crypto v0.5.0
|
golang.org/x/crypto v0.5.0
|
||||||
golang.org/x/net v0.5.0
|
golang.org/x/net v0.5.0
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -84,8 +84,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/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-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.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.44.185 h1:stasiou+Ucx2A0RyXRyPph4sLCBxVQK7DPPK8tNcl5g=
|
github.com/aws/aws-sdk-go v1.44.195 h1:d5xFL0N83Fpsq2LFiHgtBUHknCRUPGHdOlCWt/jtOJs=
|
||||||
github.com/aws/aws-sdk-go v1.44.185/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
github.com/aws/aws-sdk-go v1.44.195/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
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 v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
@ -690,8 +690,8 @@ 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 h1:jyp6X8k8mN1B0uWJydTid0C++8tQhm2kaaAdXKQQzdk=
|
||||||
go.step.sm/cli-utils v0.7.5/go.mod h1:taSsY8haLmXoXM3ZkywIyRmVij/4Aj0fQbNTlJvv71I=
|
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.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
|
||||||
go.step.sm/crypto v0.23.2 h1:XGmQH9Pkpxop47cjYlUhF10L5roPCbu1BCZXopbeW8I=
|
go.step.sm/crypto v0.25.0 h1:a+7sKyozZH9B30s0dHluygxreUxI1NtCBEmuNXx7a4k=
|
||||||
go.step.sm/crypto v0.23.2/go.mod h1:/IXGz8al8k7u7OV0RTWIi8TRVqO2FMyZVpedV+6Da6U=
|
go.step.sm/crypto v0.25.0/go.mod h1:kr1rzO6SzeQnLm6Zu6lNtksHZLiFe9k8LolSJNhoc94=
|
||||||
go.step.sm/linkedca v0.19.0 h1:xuagkR35wrJI2gnu6FAM+q3VmjwsHScvGcJsfZ0GdsI=
|
go.step.sm/linkedca v0.19.0 h1:xuagkR35wrJI2gnu6FAM+q3VmjwsHScvGcJsfZ0GdsI=
|
||||||
go.step.sm/linkedca v0.19.0/go.mod h1:b7vWPrHfYLEOTSUZitFEcztVCpTc+ileIN85CwEAluM=
|
go.step.sm/linkedca v0.19.0/go.mod h1:b7vWPrHfYLEOTSUZitFEcztVCpTc+ileIN85CwEAluM=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
|
Loading…
Reference in a new issue