@@ -2,16 +2,24 @@ package token
22
33import (
44 "bytes"
5+ "context"
56 "crypto/tls"
67 "encoding/json"
8+ "encoding/pem"
79 "errors"
810 "fmt"
911 "net/http"
1012 "net/url"
13+ "os"
1114 "path"
15+ "time"
1216
17+ "github.com/google/go-tpm/legacy/tpm2"
1318 "github.com/google/uuid"
1419 "github.com/urfave/cli"
20+ "go.step.sm/crypto/pemutil"
21+ "go.step.sm/crypto/tpm/tss2"
22+ "go.step.sm/crypto/tpm"
1523
1624 "github.com/smallstep/cli-utils/errs"
1725 "github.com/smallstep/cli-utils/ui"
@@ -40,7 +48,7 @@ func createCommand() cli.Command {
4048: File to read the certificate (PEM format). This certificate must be signed by a trusted root configured in the Smallstep dashboard.
4149
4250<key-file>
43- : File to read the private key (PEM format).
51+ : File to read the private key (PEM format, TSS2-wrapped keys are supported ).
4452
4553## EXAMPLES
4654Use a certificate to get a new API token:
@@ -86,10 +94,60 @@ func createAction(ctx *cli.Context) (err error) {
8694 parsedURL .Path = path .Join (parsedURL .Path , "api/auth" )
8795 apiURL := parsedURL .String ()
8896
89- clientCert , err := tls . LoadX509KeyPair ( crtFile , keyFile )
97+ buf , err := os . ReadFile ( keyFile )
9098 if err != nil {
9199 return err
92100 }
101+ pem , _ := pem .Decode (buf )
102+
103+ var clientCert tls.Certificate
104+ switch pem .Type {
105+ case "TSS2 PRIVATE KEY" :
106+ chain , err := pemutil .ReadCertificateBundle (crtFile )
107+ if err != nil {
108+ return err
109+ }
110+
111+ key , err := tss2 .ParsePrivateKey (pem .Bytes )
112+ if err != nil {
113+ return err
114+ }
115+
116+ raw := make ([][]byte , len (chain ))
117+ for _ , crt := range chain {
118+ raw = append (raw , crt .Raw )
119+ }
120+
121+ rw , err := tpm2 .OpenTPM ()
122+ if err != nil {
123+ return err
124+ }
125+
126+ defer rw .Close ()
127+
128+ t , err := tpm .New ()
129+ if err != nil {
130+ return err
131+ }
132+
133+
134+ tpmCtx , cancel := context .WithTimeout (context .Background (), time .Second * 5 )
135+ defer cancel ()
136+
137+ signer , err := tpm .CreateTSS2Signer (tpmCtx , t , key )
138+
139+ clientCert = tls.Certificate {
140+ PrivateKey : signer ,
141+ Leaf : chain [0 ],
142+ Certificate : raw ,
143+ }
144+ default :
145+ clientCert , err = tls .LoadX509KeyPair (crtFile , keyFile )
146+ if err != nil {
147+ return err
148+ }
149+ }
150+
93151 b := & bytes.Buffer {}
94152 r := & createTokenReq {
95153 Bundle : clientCert .Certificate ,
0 commit comments