Skip to content

Commit 3eb2564

Browse files
committed
Remove SSH cfn support and use x5rt#S256 property
1 parent e207f94 commit 3eb2564

File tree

7 files changed

+42
-47
lines changed

7 files changed

+42
-47
lines changed

command/ca/token.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func tokenCommand() cli.Command {
3030
[**--output-file**=<file>] [**--kms**=uri] [**--key**=<file>] [**--san**=<SAN>] [**--offline**]
3131
[**--revoke**] [**--x5c-cert**=<file>] [**--x5c-key**=<file>] [**--x5c-insecure**]
3232
[**--sshpop-cert**=<file>] [**--sshpop-key**=<file>]
33-
[**--cnf-file**=<file>] [**--cnf-kid**=<fingerprint>]
33+
[**--cnf**=<fingerprint>] [**--cnf-file**=<file>]
3434
[**--ssh**] [**--host**] [**--principal**=<name>] [**--k8ssa-token-path**=<file>]
3535
[**--ca-url**=<uri>] [**--root**=<file>] [**--context**=<name>]`,
3636
Description: `**step ca token** command generates a one-time token granting access to the
@@ -86,6 +86,13 @@ Get a new token that becomes valid in 30 minutes and expires 5 minutes after tha
8686
$ step ca token --not-before 30m --not-after 35m internal.example.com
8787
'''
8888
89+
Get a new token with a confirmation claim to enforce a given CSR fingerprint:
90+
'''
91+
$ step certificate fingerprint --format base64-url-raw internal.csr
92+
PJLNhtQoBE1yGN_ZKzr4Y2U5pyqIGiyyszkoz2raDOw
93+
$ step ca token --cnf PJLNhtQoBE1yGN_ZKzr4Y2U5pyqIGiyyszkoz2raDOw internal.smallstep.com
94+
'''
95+
8996
Get a new token with a confirmation claim to enforce the use of a given CSR:
9097
'''
9198
step ca token --cnf-file internal.csr internal.smallstep.com
@@ -200,8 +207,8 @@ multiple principals.`,
200207
flags.SSHPOPKey,
201208
flags.NebulaCert,
202209
flags.NebulaKey,
210+
flags.Confirmation,
203211
flags.ConfirmationFile,
204-
flags.ConfirmationKid,
205212
cli.StringFlag{
206213
Name: "key",
207214
Usage: `The private key <file> used to sign the JWT. This is usually downloaded from
@@ -258,7 +265,7 @@ func tokenAction(ctx *cli.Context) error {
258265
principals := ctx.StringSlice("principal")
259266
// confirmation claims
260267
cnfFile := ctx.String("cnf-file")
261-
cnfKid := ctx.String("cnf-kid")
268+
cnf := ctx.String("cnf")
262269

263270
switch {
264271
case isSSH && len(sans) > 0:
@@ -271,8 +278,8 @@ func tokenAction(ctx *cli.Context) error {
271278
return errs.RequiredWithFlag(ctx, "host", "ssh")
272279
case !isSSH && len(principals) > 0:
273280
return errs.RequiredWithFlag(ctx, "principal", "ssh")
274-
case cnfFile != "" && cnfKid != "":
275-
return errs.IncompatibleFlagWithFlag(ctx, "cnf-file", "cnf-kid")
281+
case cnfFile != "" && cnf != "":
282+
return errs.IncompatibleFlagWithFlag(ctx, "cnf-file", "cnf")
276283
}
277284

278285
// Default token type is always a 'Sign' token.
@@ -337,8 +344,8 @@ func tokenAction(ctx *cli.Context) error {
337344
}
338345
tokenOpts = append(tokenOpts, cautils.WithCertificateRequest(csr))
339346
}
340-
} else if cnfKid != "" {
341-
tokenOpts = append(tokenOpts, cautils.WithConfirmationKid(cnfKid))
347+
} else if cnf != "" {
348+
tokenOpts = append(tokenOpts, cautils.WithConfirmationFingerprint(cnf))
342349
}
343350

344351
// --san and --type revoke are incompatible. Revocation tokens do not support SANs.

command/certificate/fingerprint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ e2c4f12edfc1816cc610755d32e6f45d5678ba21ecda1693bb5b246e3c48c03d
5757
25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d
5858
'''
5959
60-
Get the fingerprint for a CSR using base64-url without padding encoding:
60+
Get the fingerprint for a CSR using base64-url encoding without padding:
6161
'''
6262
$ step certificate fingerprint --format base64-url-raw hello.csr
6363
PJLNhtQoBE1yGN_ZKzr4Y2U5pyqIGiyyszkoz2raDOw

flags/flags.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -379,19 +379,17 @@ be stored in the 'sshpop' header.`,
379379
be stored in the 'nebula' header.`,
380380
}
381381

382+
// Confirmation is a cli.Flag used to add a confirmation claim in the token.
383+
Confirmation = cli.StringFlag{
384+
Name: "cnf",
385+
Usage: `The <fingerprint> of the CSR to restrict this token for.`,
386+
}
387+
382388
// ConfirmationFile is a cli.Flag used to add a confirmation claim in the
383-
// tokens. It will add a confirmation kid with the fingerprint of the CSR or
384-
// an SSH public key.
389+
// tokens. It will add a confirmation kid with the fingerprint of the CSR.
385390
ConfirmationFile = cli.StringFlag{
386391
Name: "cnf-file",
387-
Usage: `The CSR or SSH public key <file> to restrict this token for.`,
388-
}
389-
390-
// ConfirmationKid is a cli.Flag used to add a confirmation claim in the
391-
// token.
392-
ConfirmationKid = cli.StringFlag{
393-
Name: "cnf-kid",
394-
Usage: `The <fingerprint> of the CSR or SSH public key to restrict this token for.`,
392+
Usage: `The CSR <file> to restrict this token for.`,
395393
}
396394

397395
// Team is a cli.Flag used to pass the team ID.

token/options.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"go.step.sm/crypto/jose"
2121
"go.step.sm/crypto/pemutil"
2222
"go.step.sm/crypto/x25519"
23-
"golang.org/x/crypto/ssh"
2423
)
2524

2625
// Options is a function that set claims.
@@ -87,38 +86,35 @@ func WithSSH(v interface{}) Options {
8786
})
8887
}
8988

90-
// WithConfirmationKid returns an Options function that sets the cnf claim with
91-
// the given kid.
92-
func WithConfirmationKid(kid string) Options {
89+
// WithConfirmationFingerprint returns an Options function that sets the cnf
90+
// claim with the given CSR fingerprint.
91+
func WithConfirmationFingerprint(fp string) Options {
9392
return func(c *Claims) error {
9493
c.Set(ConfirmationClaim, map[string]string{
95-
"kid": kid,
94+
"x5rt#S256": fp,
9695
})
9796
return nil
9897
}
9998
}
10099

101-
// WithFingerprint returns an Options function that the cnf claims with the kid
102-
// representing the fingerprint of the certificate request or the ssh public
103-
// key.
100+
// WithFingerprint returns an Options function that the cnf claims with
101+
// "x5rt#S256" representing the fingerprint of the CSR
104102
func WithFingerprint(v interface{}) Options {
105103
return func(c *Claims) error {
106104
var data []byte
107105
switch vv := v.(type) {
108106
case *x509.CertificateRequest:
109107
data = vv.Raw
110-
case ssh.PublicKey:
111-
data = vv.Marshal()
112108
default:
113-
return fmt.Errorf("unsupported fingerprint for %T", vv)
109+
return fmt.Errorf("unsupported fingerprint for %T", v)
114110
}
115111

116112
kid, err := fingerprint.New(data, crypto.SHA256, fingerprint.Base64RawURLFingerprint)
117113
if err != nil {
118114
return err
119115
}
120116
c.Set(ConfirmationClaim, map[string]string{
121-
"kid": kid,
117+
"x5rt#S256": kid,
122118
})
123119
return nil
124120
}

token/options_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func TestOptions(t *testing.T) {
8686
{"WithNebulaCurve25519Cert empty file fail", WithNebulaCert(emptyFile.Name(), nil), empty, true},
8787
{"WithNebulaCurve25519Cert invalid content fail", WithNebulaCert(c25519CertFilename, nil), empty, true},
8888
{"WithNebulaCurve25519Cert mismatching key fail", WithNebulaCert(c25519CertFilename, p256Signer), empty, true},
89-
{"WithConfirmationKid ok", WithConfirmationKid("my-kid"), &Claims{ExtraClaims: map[string]any{"cnf": map[string]string{"kid": "my-kid"}}}, false},
89+
{"WithConfirmationFingerprint ok", WithConfirmationFingerprint("my-kid"), &Claims{ExtraClaims: map[string]any{"cnf": map[string]string{"kid": "my-kid"}}}, false},
9090
{"WithFingerprint csr ok", WithFingerprint(testCSR), &Claims{ExtraClaims: map[string]any{"cnf": map[string]string{"kid": "ak6j6CwuZbd_mOQ-pNOUwhpmtSN0mY0xrLvaQL4J5l8"}}}, false},
9191
{"WithFingerprint ssh ok", WithFingerprint(testSSH), &Claims{ExtraClaims: map[string]any{"cnf": map[string]string{"kid": "hpTQOoB7fIRxTp-FhXCIm94mGBv7_dzr_5SxLn1Pnwk"}}}, false},
9292
{"WithFingerprint fail", WithFingerprint("unexpected type"), empty, true},

utils/cautils/certificate_flow.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ type CertificateFlow struct {
3737
}
3838

3939
type flowContext struct {
40-
DisableCustomSANs bool
41-
SSHPublicKey ssh.PublicKey
42-
CertificateRequest *x509.CertificateRequest
43-
ConfirmationKid string
40+
DisableCustomSANs bool
41+
SSHPublicKey ssh.PublicKey
42+
CertificateRequest *x509.CertificateRequest
43+
ConfirmationFingerprint string
4444
}
4545

4646
// sharedContext is used to share information between commands.
@@ -78,10 +78,11 @@ func WithCertificateRequest(cr *x509.CertificateRequest) Option {
7878
})
7979
}
8080

81-
// WithConfirmationKid sets the confirmation kid used in the request.
82-
func WithConfirmationKid(kid string) Option {
81+
// WithConfirmationFingerprint sets the confirmation fingerprint used in the
82+
// request.
83+
func WithConfirmationFingerprint(fp string) Option {
8384
return newFuncFlowOption(func(fo *flowContext) {
84-
fo.ConfirmationKid = kid
85+
fo.ConfirmationFingerprint = fp
8586
})
8687
}
8788

utils/cautils/token_generator.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ func (t *TokenGenerator) SignToken(sub string, sans []string, opts ...token.Opti
102102
// Tie certificate request to the token used in the JWK and X5C provisioners
103103
if sharedContext.CertificateRequest != nil {
104104
opts = append(opts, token.WithFingerprint(sharedContext.CertificateRequest))
105-
} else if sharedContext.ConfirmationKid != "" {
106-
opts = append(opts, token.WithConfirmationKid(sharedContext.ConfirmationKid))
105+
} else if sharedContext.ConfirmationFingerprint != "" {
106+
opts = append(opts, token.WithConfirmationFingerprint(sharedContext.ConfirmationFingerprint))
107107
}
108108

109109
return t.Token(sub, opts...)
@@ -124,13 +124,6 @@ func (t *TokenGenerator) SignSSHToken(sub, certType string, principals []string,
124124
ValidBefore: notAfter,
125125
})}, opts...)
126126

127-
// Tie SSH public key to the token used in the JWK and X5C provisioners
128-
if sharedContext.SSHPublicKey != nil {
129-
opts = append(opts, token.WithFingerprint(sharedContext.SSHPublicKey))
130-
} else if sharedContext.ConfirmationKid != "" {
131-
opts = append(opts, token.WithConfirmationKid(sharedContext.ConfirmationKid))
132-
}
133-
134127
return t.Token(sub, opts...)
135128
}
136129

0 commit comments

Comments
 (0)