Use sshutil and randutil from go.step.sm/crypto.

This commit is contained in:
Mariano Cano 2020-08-10 11:26:51 -07:00
parent ce1eb0a01b
commit e83e47a91e
28 changed files with 72 additions and 59 deletions

View file

@ -8,8 +8,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
)
// Provisioner is an interface that implements a subset of the provisioner.Interface --

View file

@ -31,7 +31,6 @@ import (
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/logging"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/certificates/templates"
"github.com/smallstep/cli/crypto/tlsutil"
"github.com/smallstep/cli/jose"
@ -564,7 +563,7 @@ type mockAuthority struct {
signSSHAddUser func(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error)
renewSSH func(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error)
rekeySSH func(ctx context.Context, cert *ssh.Certificate, key ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
getSSHHosts func(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error)
getSSHHosts func(ctx context.Context, cert *x509.Certificate) ([]authority.Host, error)
getSSHRoots func(ctx context.Context) (*authority.SSHKeys, error)
getSSHFederation func(ctx context.Context) (*authority.SSHKeys, error)
getSSHConfig func(ctx context.Context, typ string, data map[string]string) ([]templates.Output, error)
@ -697,11 +696,11 @@ func (m *mockAuthority) RekeySSH(ctx context.Context, cert *ssh.Certificate, key
return m.ret1.(*ssh.Certificate), m.err
}
func (m *mockAuthority) GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error) {
func (m *mockAuthority) GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]authority.Host, error) {
if m.getSSHHosts != nil {
return m.getSSHHosts(ctx, cert)
}
return m.ret1.([]sshutil.Host), m.err
return m.ret1.([]authority.Host), m.err
}
func (m *mockAuthority) GetSSHRoots(ctx context.Context) (*authority.SSHKeys, error) {

View file

@ -12,7 +12,6 @@ import (
"github.com/smallstep/certificates/authority"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/certificates/templates"
"golang.org/x/crypto/ssh"
)
@ -27,7 +26,7 @@ type SSHAuthority interface {
GetSSHFederation(ctx context.Context) (*authority.SSHKeys, error)
GetSSHConfig(ctx context.Context, typ string, data map[string]string) ([]templates.Output, error)
CheckSSHHost(ctx context.Context, principal string, token string) (bool, error)
GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error)
GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]authority.Host, error)
GetSSHBastion(ctx context.Context, user string, hostname string) (*authority.Bastion, error)
}
@ -87,7 +86,7 @@ type SSHCertificate struct {
// SSHGetHostsResponse is the response object that returns the list of valid
// hosts for SSH.
type SSHGetHostsResponse struct {
Hosts []sshutil.Host `json:"hosts"`
Hosts []authority.Host `json:"hosts"`
}
// MarshalJSON implements the json.Marshaler interface. Returns a quoted,

View file

@ -22,7 +22,6 @@ import (
"github.com/smallstep/certificates/authority"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/logging"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/certificates/templates"
"golang.org/x/crypto/ssh"
)
@ -569,29 +568,29 @@ func Test_caHandler_SSHCheckHost(t *testing.T) {
}
func Test_caHandler_SSHGetHosts(t *testing.T) {
hosts := []sshutil.Host{
{HostID: "1", HostTags: []sshutil.HostTag{{ID: "1", Name: "group", Value: "1"}}, Hostname: "host1"},
{HostID: "2", HostTags: []sshutil.HostTag{{ID: "1", Name: "group", Value: "1"}, {ID: "2", Name: "group", Value: "2"}}, Hostname: "host2"},
hosts := []authority.Host{
{HostID: "1", HostTags: []authority.HostTag{{ID: "1", Name: "group", Value: "1"}}, Hostname: "host1"},
{HostID: "2", HostTags: []authority.HostTag{{ID: "1", Name: "group", Value: "1"}, {ID: "2", Name: "group", Value: "2"}}, Hostname: "host2"},
}
hostsJSON, err := json.Marshal(hosts)
assert.FatalError(t, err)
tests := []struct {
name string
hosts []sshutil.Host
hosts []authority.Host
err error
body []byte
statusCode int
}{
{"ok", hosts, nil, []byte(fmt.Sprintf(`{"hosts":%s}`, hostsJSON)), http.StatusOK},
{"empty (array)", []sshutil.Host{}, nil, []byte(`{"hosts":[]}`), http.StatusOK},
{"empty (array)", []authority.Host{}, nil, []byte(`{"hosts":[]}`), http.StatusOK},
{"empty (nil)", nil, nil, []byte(`{"hosts":null}`), http.StatusOK},
{"error", nil, fmt.Errorf("an error"), nil, http.StatusInternalServerError},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := New(&mockAuthority{
getSSHHosts: func(context.Context, *x509.Certificate) ([]sshutil.Host, error) {
getSSHHosts: func(context.Context, *x509.Certificate) ([]authority.Host, error) {
return tt.hosts, tt.err
},
}).(*caHandler)

View file

@ -15,7 +15,6 @@ import (
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/kms"
kmsapi "github.com/smallstep/certificates/kms/apiv1"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/certificates/templates"
"github.com/smallstep/cli/crypto/pemutil"
"golang.org/x/crypto/ssh"
@ -55,7 +54,7 @@ type Authority struct {
// Custom functions
sshBastionFunc func(ctx context.Context, user, hostname string) (*Bastion, error)
sshCheckHostFunc func(ctx context.Context, principal string, tok string, roots []*x509.Certificate) (bool, error)
sshGetHostsFunc func(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error)
sshGetHostsFunc func(ctx context.Context, cert *x509.Certificate) ([]Host, error)
getIdentityFunc provisioner.GetIdentityFunc
}

View file

@ -18,8 +18,8 @@ import (
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
"golang.org/x/crypto/ssh"
"gopkg.in/square/go-jose.v2/jwt"
)

View file

@ -10,7 +10,6 @@ import (
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/kms"
"github.com/smallstep/certificates/sshutil"
"golang.org/x/crypto/ssh"
)
@ -64,7 +63,7 @@ func WithSSHBastionFunc(fn func(ctx context.Context, user, host string) (*Bastio
// WithSSHGetHosts sets a custom function to get the bastion for a
// given user-host pair.
func WithSSHGetHosts(fn func(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error)) Option {
func WithSSHGetHosts(fn func(ctx context.Context, cert *x509.Certificate) ([]Host, error)) Option {
return func(a *Authority) error {
a.sshGetHostsFunc = fn
return nil

View file

@ -17,8 +17,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
)
@ -497,7 +497,7 @@ func (p *AWS) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
data.SetToken(v)
}
templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.DefaultIIDCertificate)
templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.DefaultIIDTemplate)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "aws.AuthorizeSSHSign")
}

View file

@ -14,8 +14,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
)
@ -366,7 +366,7 @@ func (p *Azure) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
data.SetToken(v)
}
templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.DefaultIIDCertificate)
templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.DefaultIIDTemplate)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign")
}

View file

@ -15,8 +15,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
)
@ -408,7 +408,7 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
data.SetToken(v)
}
templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.DefaultIIDCertificate)
templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.DefaultIIDTemplate)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSSHSign")
}

View file

@ -8,8 +8,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
)

View file

@ -11,9 +11,9 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
)

View file

@ -13,8 +13,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
)
@ -395,9 +395,9 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption
// Use the default template unless no-templates are configured and email is
// an admin, in that case we will use the parameters in the request.
isAdmin := o.IsAdmin(claims.Email)
defaultTemplate := sshutil.DefaultCertificate
defaultTemplate := sshutil.DefaultTemplate
if isAdmin && !o.Options.GetSSHOptions().HasTemplate() {
defaultTemplate = sshutil.DefaultAdminCertificate
defaultTemplate = sshutil.DefaultAdminTemplate
}
templateOptions, err := CustomSSHTemplateOptions(o.Options, data, defaultTemplate)

View file

@ -5,10 +5,10 @@ import (
"strings"
"github.com/pkg/errors"
"github.com/smallstep/certificates/sshutil"
"go.step.sm/crypto/sshutil"
)
// CertificateOptions is an interface that returns a list of options passed when
// SSHCertificateOptions is an interface that returns a list of options passed when
// creating a new certificate.
type SSHCertificateOptions interface {
Options(SignSSHOptions) []sshutil.Option
@ -45,7 +45,7 @@ func (o *SSHOptions) HasTemplate() bool {
// user data provided in the request. If no template has been provided,
// x509util.DefaultLeafTemplate will be used.
func TemplateSSHOptions(o *Options, data sshutil.TemplateData) (SSHCertificateOptions, error) {
return CustomSSHTemplateOptions(o, data, sshutil.DefaultCertificate)
return CustomSSHTemplateOptions(o, data, sshutil.DefaultTemplate)
}
// CustomTemplateOptions generates a CertificateOptions with the template, data

View file

@ -8,7 +8,7 @@ import (
"time"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"go.step.sm/crypto/sshutil"
"golang.org/x/crypto/ssh"
)

View file

@ -17,8 +17,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
"golang.org/x/crypto/ssh"
)

View file

@ -9,8 +9,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
)

View file

@ -10,8 +10,8 @@ import (
"github.com/smallstep/assert"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
)
func TestX5C_Getters(t *testing.T) {

View file

@ -13,10 +13,10 @@ import (
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/certificates/templates"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
"go.step.sm/crypto/sshutil"
"golang.org/x/crypto/ssh"
)
@ -51,6 +51,21 @@ type Bastion struct {
Flags string `json:"flags,omitempty"`
}
// HostTag are tagged with k,v pairs. These tags are how a user is ultimately
// associated with a host.
type HostTag struct {
ID string
Name string
Value string
}
// Host defines expected attributes for an ssh host.
type Host struct {
HostID string `json:"hid"`
HostTags []HostTag `json:"host_tags"`
Hostname string `json:"hostname"`
}
// Validate checks the fields in SSHConfig.
func (c *SSHConfig) Validate() error {
if c == nil {
@ -554,7 +569,7 @@ func (a *Authority) CheckSSHHost(ctx context.Context, principal string, token st
}
// GetSSHHosts returns a list of valid host principals.
func (a *Authority) GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error) {
func (a *Authority) GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]Host, error) {
if a.sshGetHostsFunc != nil {
hosts, err := a.sshGetHostsFunc(ctx, cert)
return hosts, errs.Wrap(http.StatusInternalServerError, err, "getSSHHosts")
@ -564,9 +579,9 @@ func (a *Authority) GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]
return nil, errs.Wrap(http.StatusInternalServerError, err, "getSSHHosts")
}
hosts := make([]sshutil.Host, len(hostnames))
hosts := make([]Host, len(hostnames))
for i, hn := range hostnames {
hosts[i] = sshutil.Host{Hostname: hn}
hosts[i] = Host{Hostname: hn}
}
return hosts, nil
}

View file

@ -18,9 +18,9 @@ import (
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/certificates/templates"
"github.com/smallstep/cli/jose"
"go.step.sm/crypto/sshutil"
"golang.org/x/crypto/ssh"
)
@ -706,17 +706,17 @@ func TestAuthority_GetSSHHosts(t *testing.T) {
a := testAuthority(t)
type test struct {
getHostsFunc func(context.Context, *x509.Certificate) ([]sshutil.Host, error)
getHostsFunc func(context.Context, *x509.Certificate) ([]Host, error)
auth *Authority
cert *x509.Certificate
cmp func(got []sshutil.Host)
cmp func(got []Host)
err error
code int
}
tests := map[string]func(t *testing.T) *test{
"fail/getHostsFunc-fail": func(t *testing.T) *test {
return &test{
getHostsFunc: func(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error) {
getHostsFunc: func(ctx context.Context, cert *x509.Certificate) ([]Host, error) {
return nil, errors.New("force")
},
cert: &x509.Certificate{},
@ -725,17 +725,17 @@ func TestAuthority_GetSSHHosts(t *testing.T) {
}
},
"ok/getHostsFunc-defined": func(t *testing.T) *test {
hosts := []sshutil.Host{
hosts := []Host{
{HostID: "1", Hostname: "foo"},
{HostID: "2", Hostname: "bar"},
}
return &test{
getHostsFunc: func(ctx context.Context, cert *x509.Certificate) ([]sshutil.Host, error) {
getHostsFunc: func(ctx context.Context, cert *x509.Certificate) ([]Host, error) {
return hosts, nil
},
cert: &x509.Certificate{},
cmp: func(got []sshutil.Host) {
cmp: func(got []Host) {
assert.Equals(t, got, hosts)
},
}
@ -760,8 +760,8 @@ func TestAuthority_GetSSHHosts(t *testing.T) {
},
})),
cert: &x509.Certificate{},
cmp: func(got []sshutil.Host) {
assert.Equals(t, got, []sshutil.Host{
cmp: func(got []Host) {
assert.Equals(t, got, []Host{
{Hostname: "foo"},
{Hostname: "bar"},
})

View file

@ -15,8 +15,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/api"
"github.com/smallstep/certificates/authority"
"github.com/smallstep/cli/crypto/randutil"
stepJOSE "github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)

View file

@ -27,9 +27,9 @@ import (
"github.com/smallstep/certificates/errs"
"github.com/smallstep/cli/crypto/keys"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/crypto/x509util"
stepJOSE "github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)

View file

@ -7,10 +7,10 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/jose"
"github.com/smallstep/cli/token"
"github.com/smallstep/cli/token/provision"
"go.step.sm/crypto/randutil"
)
const tokenLifetime = 5 * time.Minute

View file

@ -18,8 +18,8 @@ import (
"github.com/smallstep/certificates/api"
"github.com/smallstep/certificates/authority"
"github.com/smallstep/cli/crypto/randutil"
stepJOSE "github.com/smallstep/cli/jose"
"go.step.sm/crypto/randutil"
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)

View file

@ -13,11 +13,11 @@ import (
"github.com/smallstep/certificates/ca"
"github.com/smallstep/certificates/pki"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/ui"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
"go.step.sm/crypto/randutil"
)
// defaultOnboardingURL is the production onboarding url, to use a development

2
go.mod
View file

@ -17,7 +17,7 @@ require (
github.com/smallstep/cli v0.14.7-rc.1.0.20200721180458-731b7c4c8c95
github.com/smallstep/nosql v0.3.0
github.com/urfave/cli v1.22.2
go.step.sm/crypto v0.0.0-20200805202904-ec18b6df3cf0
go.step.sm/crypto v0.1.0
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
google.golang.org/api v0.15.0

3
go.sum
View file

@ -479,6 +479,7 @@ github.com/smallstep/assert v0.0.0-20200103212524-b99dc1097b15/go.mod h1:MyOHs9P
github.com/smallstep/certificates v0.14.5/go.mod h1:zzpB8wMz967gL8FmK6zvCNB4pDVwFDKjPg1diTVc1h8=
github.com/smallstep/certinfo v1.3.0/go.mod h1:1gQJekdPwPvUwFWGTi7bZELmQT09cxC9wJ0VBkBNiwU=
github.com/smallstep/cli v0.14.5/go.mod h1:mRFuqC3cGwQESBGJvog4o76jZZZ7bMjkE+hAnq2QyR8=
github.com/smallstep/cli v0.14.6 h1:xc9rawDKB70Vgvg10gfQAh9EpDWS3k1O002J5bApqUk=
github.com/smallstep/cli v0.14.7-rc.1.0.20200721180458-731b7c4c8c95 h1:TcCYqEqh6EIEiFabRdtG0IGyFK01kRLTjx6TIKqjxX8=
github.com/smallstep/cli v0.14.7-rc.1.0.20200721180458-731b7c4c8c95/go.mod h1:7aWHk7WwJMpEP4PYyav86FMpaI9vuA0uJRliUAqCwxg=
github.com/smallstep/nosql v0.3.0 h1:V1X5vfDsDt89499h3jZFUlR4VnnsYYs5tXaQZ0w8z5U=
@ -579,6 +580,8 @@ go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.step.sm/crypto v0.0.0-20200805202904-ec18b6df3cf0 h1:FymMl8TrXGxFf80BWpO0CnkSfLnw0BkDdRrhbMGf5zE=
go.step.sm/crypto v0.0.0-20200805202904-ec18b6df3cf0/go.mod h1:8VYxmvSKt5yOTBx3MGsD2Gk4F1Es/3FIxrjnfeYWE8U=
go.step.sm/crypto v0.1.0 h1:SLo25kNU3C6u8Ne5BnavI9bhtA+PBrMnnNZKYIWhKFU=
go.step.sm/crypto v0.1.0/go.mod h1:cIoSWTfTQ5xqvwTeZH9ZXZzi6jdMepjK4A/TDWMUvw8=
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=
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=

View file

@ -6,7 +6,7 @@ import (
"encoding/json"
"github.com/pkg/errors"
"github.com/smallstep/cli/crypto/randutil"
"go.step.sm/crypto/randutil"
"golang.org/x/crypto/ssh"
)