@@ -10,16 +10,19 @@ import (
1010 "crypto/sha256"
1111 "crypto/x509"
1212 "encoding/base64"
13+ "encoding/pem"
1314 "errors"
1415 "fmt"
1516 "net/url"
17+ "os"
1618 "time"
1719
1820 "go.step.sm/crypto/kms/apiv1"
1921 "go.step.sm/crypto/kms/uri"
2022 "go.step.sm/crypto/tpm"
2123 "go.step.sm/crypto/tpm/attestation"
2224 "go.step.sm/crypto/tpm/storage"
25+ "go.step.sm/crypto/tpm/tss2"
2326)
2427
2528func init () {
@@ -188,6 +191,7 @@ func New(_ context.Context, opts apiv1.Options) (kms *TPMKMS, err error) {
188191//
189192// - name=<name>: specify the name to identify the key with
190193// - ak=true: if set to true, an Attestation Key (AK) will be created instead of an application key
194+ // - tss2=true: is set to true, the PrivateKey response will contain a [tss2.TPMKey].
191195// - attest-by=<akName>: attest an application key at creation time with the AK identified by `akName`
192196// - qualifying-data=<random>: hexadecimal coded binary data that can be used to guarantee freshness when attesting creation of a key
193197//
@@ -240,6 +244,8 @@ func (k *TPMKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespons
240244 }
241245
242246 ctx := context .Background ()
247+
248+ var privateKey any
243249 if properties .ak {
244250 ak , err := k .tpm .CreateAK (ctx , properties .name ) // NOTE: size is never passed for AKs; it's hardcoded to 2048 in lower levels.
245251 if err != nil {
@@ -248,10 +254,20 @@ func (k *TPMKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespons
248254 }
249255 return nil , fmt .Errorf ("failed creating AK: %w" , err )
250256 }
257+
258+ if properties .tss2 {
259+ tpmKey , err := ak .ToTSS2 (ctx )
260+ if err != nil {
261+ return nil , fmt .Errorf ("failed exporting AK to TSS2: %w" , err )
262+ }
263+ privateKey = tpmKey
264+ }
265+
251266 createdAKURI := fmt .Sprintf ("tpmkms:name=%s;ak=true" , ak .Name ())
252267 return & apiv1.CreateKeyResponse {
253- Name : createdAKURI ,
254- PublicKey : ak .Public (),
268+ Name : createdAKURI ,
269+ PublicKey : ak .Public (),
270+ PrivateKey : privateKey ,
255271 }, nil
256272 }
257273
@@ -283,6 +299,14 @@ func (k *TPMKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespons
283299 }
284300 }
285301
302+ if properties .tss2 {
303+ tpmKey , err := key .ToTSS2 (ctx )
304+ if err != nil {
305+ return nil , fmt .Errorf ("failed exporting key to TSS2: %w" , err )
306+ }
307+ privateKey = tpmKey
308+ }
309+
286310 signer , err := key .Signer (ctx )
287311 if err != nil {
288312 return nil , fmt .Errorf ("failed getting signer for key: %w" , err )
@@ -294,8 +318,9 @@ func (k *TPMKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespons
294318 }
295319
296320 return & apiv1.CreateKeyResponse {
297- Name : createdKeyURI ,
298- PublicKey : signer .Public (),
321+ Name : createdKeyURI ,
322+ PublicKey : signer .Public (),
323+ PrivateKey : privateKey ,
299324 CreateSignerRequest : apiv1.CreateSignerRequest {
300325 SigningKey : createdKeyURI ,
301326 Signer : signer ,
@@ -304,39 +329,76 @@ func (k *TPMKMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespons
304329}
305330
306331// CreateSigner creates a signer using a key present in the TPM KMS.
332+ //
333+ // The `signingKey` in the [apiv1.CreateSignerRequest] can be used to specify
334+ // some key properties. These are as follows:
335+ //
336+ // - name=<name>: specify the name to identify the key with
337+ // - path=<file>: specify the TSS2 PEM file to use
307338func (k * TPMKMS ) CreateSigner (req * apiv1.CreateSignerRequest ) (crypto.Signer , error ) {
308339 if req .Signer != nil {
309340 return req .Signer , nil
310341 }
311342
312- if req .SigningKey == "" {
313- return nil , errors .New ("createSignerRequest 'signingKey' cannot be empty" )
314- }
343+ var pemBytes []byte
315344
316- properties , err := parseNameURI (req .SigningKey )
317- if err != nil {
318- return nil , fmt .Errorf ("failed parsing %q: %w" , req .SigningKey , err )
319- }
345+ switch {
346+ case req .SigningKey != "" :
347+ properties , err := parseNameURI (req .SigningKey )
348+ if err != nil {
349+ return nil , fmt .Errorf ("failed parsing %q: %w" , req .SigningKey , err )
350+ }
351+ if properties .ak {
352+ return nil , fmt .Errorf ("signing with an AK currently not supported" )
353+ }
320354
321- if properties .ak {
322- return nil , fmt .Errorf ("signing with an AK currently not supported" )
355+ switch {
356+ case properties .name != "" :
357+ ctx := context .Background ()
358+ key , err := k .tpm .GetKey (ctx , properties .name )
359+ if err != nil {
360+ return nil , err
361+ }
362+ signer , err := key .Signer (ctx )
363+ if err != nil {
364+ return nil , fmt .Errorf ("failed getting signer for key %q: %w" , properties .name , err )
365+ }
366+ return signer , nil
367+ case properties .path != "" :
368+ if pemBytes , err = os .ReadFile (properties .path ); err != nil {
369+ return nil , fmt .Errorf ("failed reading key from %q: %w" , properties .path , err )
370+ }
371+ default :
372+ return nil , fmt .Errorf ("failed parsing %q: name and path cannot be empty" , req .SigningKey )
373+ }
374+ case len (req .SigningKeyPEM ) > 0 :
375+ pemBytes = req .SigningKeyPEM
376+ default :
377+ return nil , errors .New ("createSignerRequest 'signingKey' and 'signingKeyPEM' cannot be empty" )
323378 }
324379
325- ctx := context . Background ()
326- key , err := k . tpm . GetKey ( ctx , properties . name )
380+ // Create a signer from a TSS2 PEM block
381+ key , err := parseTSS2 ( pemBytes )
327382 if err != nil {
328383 return nil , err
329384 }
330385
331- signer , err := key .Signer (ctx )
386+ ctx := context .Background ()
387+ signer , err := tpm .CreateTSS2Signer (ctx , k .tpm , key )
332388 if err != nil {
333- return nil , fmt .Errorf ("failed getting signer for key %q : %w" , properties . name , err )
389+ return nil , fmt .Errorf ("failed getting signer for TSS2 PEM : %w" , err )
334390 }
335-
336391 return signer , nil
337392}
338393
339- // GetPublicKey returns the public key ....
394+ // GetPublicKey returns the public key present in the TPM KMS.
395+ //
396+ // The `name` in the [apiv1.GetPublicKeyRequest] can be used to specify some key
397+ // properties. These are as follows:
398+ //
399+ // - name=<name>: specify the name to identify the key with
400+ // - ak=true: if set to true, an Attestation Key (AK) will be read instead of an application key
401+ // - path=<file>: specify the TSS2 PEM file to read from
340402func (k * TPMKMS ) GetPublicKey (req * apiv1.GetPublicKeyRequest ) (crypto.PublicKey , error ) {
341403 if req .Name == "" {
342404 return nil , errors .New ("getPublicKeyRequest 'name' cannot be empty" )
@@ -348,29 +410,48 @@ func (k *TPMKMS) GetPublicKey(req *apiv1.GetPublicKeyRequest) (crypto.PublicKey,
348410 }
349411
350412 ctx := context .Background ()
351- if properties .ak {
352- ak , err := k .tpm .GetAK (ctx , properties .name )
413+ switch {
414+ case properties .name != "" :
415+ if properties .ak {
416+ ak , err := k .tpm .GetAK (ctx , properties .name )
417+ if err != nil {
418+ return nil , err
419+ }
420+ akPub := ak .Public ()
421+ if akPub == nil {
422+ return nil , errors .New ("failed getting AK public key" )
423+ }
424+ return akPub , nil
425+ }
426+
427+ key , err := k .tpm .GetKey (ctx , properties .name )
353428 if err != nil {
354429 return nil , err
355430 }
356- akPub := ak .Public ()
357- if akPub == nil {
358- return nil , errors .New ("failed getting AK public key" )
359- }
360- return akPub , nil
361- }
362431
363- key , err := k . tpm . GetKey (ctx , properties . name )
364- if err != nil {
365- return nil , err
366- }
432+ signer , err := key . Signer (ctx )
433+ if err != nil {
434+ return nil , fmt . Errorf ( "failed getting signer for key %q: %w" , properties . name , err )
435+ }
367436
368- signer , err := key .Signer (ctx )
369- if err != nil {
370- return nil , fmt .Errorf ("failed getting signer for key %q: %w" , properties .name , err )
437+ return signer .Public (), nil
438+ case properties .path != "" :
439+ pemBytes , err := os .ReadFile (properties .path )
440+ if err != nil {
441+ return nil , fmt .Errorf ("failed reading key from %q: %w" , properties .path , err )
442+ }
443+ key , err := parseTSS2 (pemBytes )
444+ if err != nil {
445+ return nil , err
446+ }
447+ pub , err := key .Public ()
448+ if err != nil {
449+ return nil , fmt .Errorf ("error decoding public key from %q: %w" , properties .path , err )
450+ }
451+ return pub , nil
452+ default :
453+ return nil , fmt .Errorf ("failed parsing %q: name and path cannot be empty" , req .Name )
371454 }
372-
373- return signer .Public (), nil
374455}
375456
376457// LoadCertificate loads the certificate for the key identified by name from the TPMKMS.
@@ -757,6 +838,26 @@ func ekURL(keyID []byte) *url.URL {
757838 }
758839}
759840
841+ func parseTSS2 (pemBytes []byte ) (* tss2.TPMKey , error ) {
842+ var block * pem.Block
843+ for len (pemBytes ) > 0 {
844+ block , pemBytes = pem .Decode (pemBytes )
845+ if block == nil {
846+ break
847+ }
848+ if block .Type != "TSS2 PRIVATE KEY" {
849+ continue
850+ }
851+
852+ key , err := tss2 .ParsePrivateKey (block .Bytes )
853+ if err != nil {
854+ return nil , fmt .Errorf ("failed parsing TSS2 PEM: %w" , err )
855+ }
856+ return key , nil
857+ }
858+ return nil , fmt .Errorf ("failed parsing TSS2 PEM: block not found" )
859+ }
860+
760861var _ apiv1.KeyManager = (* TPMKMS )(nil )
761862var _ apiv1.Attester = (* TPMKMS )(nil )
762863var _ apiv1.CertificateManager = (* TPMKMS )(nil )
0 commit comments