diff --git a/authority/provisioner/x5c.go b/authority/provisioner/x5c.go index ff01b151..ee05078e 100644 --- a/authority/provisioner/x5c.go +++ b/authority/provisioner/x5c.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certificates/errs" + "github.com/smallstep/certificates/sshutil" "github.com/smallstep/certificates/x509util" "github.com/smallstep/cli/jose" ) @@ -25,14 +26,15 @@ type x5cPayload struct { // signature requests. type X5C struct { *base - Type string `json:"type"` - Name string `json:"name"` - Roots []byte `json:"roots"` - Claims *Claims `json:"claims,omitempty"` - Options *Options `json:"options,omitempty"` - claimer *Claimer - audiences Audiences - rootPool *x509.CertPool + Type string `json:"type"` + Name string `json:"name"` + Roots []byte `json:"roots"` + Claims *Claims `json:"claims,omitempty"` + Options *Options `json:"options,omitempty"` + SSHOptions *SSHOptions `json:"sshOptions,omitempty"` + claimer *Claimer + audiences Audiences + rootPool *x509.CertPool } // GetID returns the provisioner unique identifier. The name and credential id @@ -249,14 +251,37 @@ func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, sshCertOptionsValidator(*opts), } - // Add modifiers from custom claims - // FIXME: this is also set in the sign method using SSHOptions.Modify. + // Default template attributes. + certType := sshutil.UserCert + keyID := claims.Subject + principals := []string{claims.Subject} + + // Use options in the token. if opts.CertType != "" { - signOptions = append(signOptions, sshCertTypeModifier(opts.CertType)) + if certType, err = sshutil.CertTypeFromString(opts.CertType); err != nil { + return nil, errs.Wrap(http.StatusBadRequest, err, "jwk.AuthorizeSSHSign") + } + } + if opts.KeyID != "" { + keyID = opts.KeyID } if len(opts.Principals) > 0 { - signOptions = append(signOptions, sshCertPrincipalsModifier(opts.Principals)) + principals = opts.Principals } + + // Certificate templates. + data := sshutil.CreateTemplateData(certType, keyID, principals) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } + + templateOptions, err := TemplateSSHOptions(p.SSHOptions, data) + if err != nil { + return nil, errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSign") + } + signOptions = append(signOptions, templateOptions) + + // Add modifiers from custom claims t := now() if !opts.ValidAfter.IsZero() { signOptions = append(signOptions, sshCertValidAfterModifier(opts.ValidAfter.RelativeTime(t).Unix())) @@ -264,17 +289,8 @@ func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, if !opts.ValidBefore.IsZero() { signOptions = append(signOptions, sshCertValidBeforeModifier(opts.ValidBefore.RelativeTime(t).Unix())) } - // Make sure to define the the KeyID - if opts.KeyID == "" { - signOptions = append(signOptions, sshCertKeyIDModifier(claims.Subject)) - } - - // Default to a user certificate with no principals if not set - signOptions = append(signOptions, sshCertDefaultsModifier{CertType: SSHUserCert}) return append(signOptions, - // Set the default extensions. - &sshDefaultExtensionModifier{}, // Checks the validity bounds, and set the validity if has not been set. &sshLimitDuration{p.claimer, claims.chains[0][0].NotAfter}, // set the key id to the token subject