forked from TrueCloudLab/certificates
Use sshutil for SSH certificate signing.
This commit is contained in:
parent
570ede45e7
commit
b66d123572
1 changed files with 30 additions and 26 deletions
|
@ -205,56 +205,66 @@ func (a *Authority) GetSSHBastion(ctx context.Context, user string, hostname str
|
||||||
|
|
||||||
// SignSSH creates a signed SSH certificate with the given public key and options.
|
// SignSSH creates a signed SSH certificate with the given public key and options.
|
||||||
func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) {
|
func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) {
|
||||||
var mods []provisioner.SSHCertModifier
|
var (
|
||||||
var validators []provisioner.SSHCertValidator
|
certOptions []sshutil.Option
|
||||||
|
mods []provisioner.SSHCertModifier
|
||||||
|
validators []provisioner.SSHCertValidator
|
||||||
|
)
|
||||||
|
|
||||||
// Set backdate with the configured value
|
// Set backdate with the configured value
|
||||||
opts.Backdate = a.config.AuthorityConfig.Backdate.Duration
|
opts.Backdate = a.config.AuthorityConfig.Backdate.Duration
|
||||||
|
|
||||||
for _, op := range signOpts {
|
for _, op := range signOpts {
|
||||||
switch o := op.(type) {
|
switch o := op.(type) {
|
||||||
|
// add options to NewCertificate
|
||||||
|
case provisioner.SSHCertificateOptions:
|
||||||
|
certOptions = append(certOptions, o.Options(opts)...)
|
||||||
|
|
||||||
// modify the ssh.Certificate
|
// modify the ssh.Certificate
|
||||||
case provisioner.SSHCertModifier:
|
case provisioner.SSHCertModifier:
|
||||||
mods = append(mods, o)
|
mods = append(mods, o)
|
||||||
|
|
||||||
// modify the ssh.Certificate given the SSHOptions
|
// modify the ssh.Certificate given the SSHOptions
|
||||||
case provisioner.SSHCertOptionModifier:
|
case provisioner.SSHCertOptionModifier:
|
||||||
mods = append(mods, o.Option(opts))
|
mods = append(mods, o.Option(opts))
|
||||||
|
|
||||||
// validate the ssh.Certificate
|
// validate the ssh.Certificate
|
||||||
case provisioner.SSHCertValidator:
|
case provisioner.SSHCertValidator:
|
||||||
validators = append(validators, o)
|
validators = append(validators, o)
|
||||||
|
|
||||||
// validate the given SSHOptions
|
// validate the given SSHOptions
|
||||||
case provisioner.SSHCertOptionsValidator:
|
case provisioner.SSHCertOptionsValidator:
|
||||||
if err := o.Valid(opts); err != nil {
|
if err := o.Valid(opts); err != nil {
|
||||||
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, errs.InternalServer("signSSH: invalid extra option type %T", o)
|
return nil, errs.InternalServer("signSSH: invalid extra option type %T", o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, err := randutil.ASCII(32)
|
// Create certificate from template.
|
||||||
|
certificate, err := sshutil.NewCertificate(key, certOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH")
|
if _, ok := err.(*sshutil.TemplateError); ok {
|
||||||
|
return nil, errs.NewErr(http.StatusBadRequest, err,
|
||||||
|
errs.WithMessage(err.Error()),
|
||||||
|
errs.WithKeyVal("signOptions", signOpts),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH")
|
||||||
}
|
}
|
||||||
|
|
||||||
var serial uint64
|
// Get actual *ssh.Certificate and continue with user and provisioner
|
||||||
if err := binary.Read(rand.Reader, binary.BigEndian, &serial); err != nil {
|
// modifiers.
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error reading random number")
|
cert := certificate.GetCertificate()
|
||||||
}
|
|
||||||
|
|
||||||
// Build base certificate with the key and some random values
|
// Use SignSSHOptions to modify the certificate.
|
||||||
cert := &ssh.Certificate{
|
|
||||||
Nonce: []byte(nonce),
|
|
||||||
Key: key,
|
|
||||||
Serial: serial,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use opts to modify the certificate
|
|
||||||
if err := opts.Modify(cert); err != nil {
|
if err := opts.Modify(cert); err != nil {
|
||||||
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use provisioner modifiers
|
// Use provisioner modifiers.
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
if err := m.Modify(cert); err != nil {
|
if err := m.Modify(cert); err != nil {
|
||||||
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
||||||
|
@ -277,20 +287,14 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
|
||||||
default:
|
default:
|
||||||
return nil, errs.InternalServer("signSSH: unexpected ssh certificate type: %d", cert.CertType)
|
return nil, errs.InternalServer("signSSH: unexpected ssh certificate type: %d", cert.CertType)
|
||||||
}
|
}
|
||||||
cert.SignatureKey = signer.PublicKey()
|
|
||||||
|
|
||||||
// Get bytes for signing trailing the signature length.
|
// Sign certificate.
|
||||||
data := cert.Marshal()
|
cert, err = sshutil.CreateCertificate(cert, signer)
|
||||||
data = data[:len(data)-4]
|
|
||||||
|
|
||||||
// Sign the certificate
|
|
||||||
sig, err := signer.Sign(rand.Reader, data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate")
|
return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate")
|
||||||
}
|
}
|
||||||
cert.Signature = sig
|
|
||||||
|
|
||||||
// User provisioners validators
|
// User provisioners validators.
|
||||||
for _, v := range validators {
|
for _, v := range validators {
|
||||||
if err := v.Valid(cert, opts); err != nil {
|
if err := v.Valid(cert, opts); err != nil {
|
||||||
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
return nil, errs.Wrap(http.StatusForbidden, err, "signSSH")
|
||||||
|
|
Loading…
Reference in a new issue