mirror of
https://github.com/google/go-attestation.git
synced 2024-12-19 04:57:59 +00:00
5410759ddc
PiperOrigin-RevId: 394112776 Co-authored-by: Tom D'Netto <jsonp@google.com>
567 lines
16 KiB
Go
567 lines
16 KiB
Go
// Copyright 2020 Google Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
package attest
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
"crypto/ecdsa"
|
|
"crypto/rsa"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math/big"
|
|
|
|
"github.com/google/certificate-transparency-go/asn1"
|
|
"github.com/google/go-tpm/tpm2"
|
|
"github.com/google/go-tpm/tpmutil"
|
|
)
|
|
|
|
// wrappedTPM20 interfaces with a TPM 2.0 command channel.
|
|
type wrappedTPM20 struct {
|
|
interf TPMInterface
|
|
rwc CommandChannelTPM20
|
|
tpmEkTemplate *tpm2.Public
|
|
}
|
|
|
|
func (t *wrappedTPM20) ekTemplate() (tpm2.Public, error) {
|
|
if t.tpmEkTemplate != nil {
|
|
return *t.tpmEkTemplate, nil
|
|
}
|
|
|
|
nonce, err := tpm2.NVReadEx(t.rwc, nvramEkNonceIndex, tpm2.HandleOwner, "", 0)
|
|
if err != nil {
|
|
t.tpmEkTemplate = &defaultEKTemplate // No nonce, use the default template
|
|
} else {
|
|
template := defaultEKTemplate
|
|
copy(template.RSAParameters.ModulusRaw, nonce)
|
|
t.tpmEkTemplate = &template
|
|
}
|
|
|
|
return *t.tpmEkTemplate, nil
|
|
}
|
|
|
|
func (*wrappedTPM20) isTPMBase() {}
|
|
|
|
func (t *wrappedTPM20) tpmVersion() TPMVersion {
|
|
return TPMVersion20
|
|
}
|
|
|
|
func (t *wrappedTPM20) close() error {
|
|
return t.rwc.Close()
|
|
}
|
|
|
|
// Info returns information about the TPM.
|
|
func (t *wrappedTPM20) info() (*TPMInfo, error) {
|
|
var (
|
|
tInfo = TPMInfo{
|
|
Version: TPMVersion20,
|
|
Interface: t.interf,
|
|
}
|
|
t2Info tpm20Info
|
|
err error
|
|
)
|
|
|
|
if t2Info, err = readTPM2VendorAttributes(t.rwc); err != nil {
|
|
return nil, err
|
|
}
|
|
tInfo.Manufacturer = t2Info.manufacturer
|
|
tInfo.VendorInfo = t2Info.vendor
|
|
tInfo.FirmwareVersionMajor = t2Info.fwMajor
|
|
tInfo.FirmwareVersionMinor = t2Info.fwMinor
|
|
return &tInfo, nil
|
|
}
|
|
|
|
// Return value: handle, whether we generated a new one, error
|
|
func (t *wrappedTPM20) getPrimaryKeyHandle(pHnd tpmutil.Handle) (tpmutil.Handle, bool, error) {
|
|
_, _, _, err := tpm2.ReadPublic(t.rwc, pHnd)
|
|
if err == nil {
|
|
// Found the persistent handle, assume it's the key we want.
|
|
return pHnd, false, nil
|
|
}
|
|
|
|
var keyHnd tpmutil.Handle
|
|
switch pHnd {
|
|
case commonSrkEquivalentHandle:
|
|
keyHnd, _, err = tpm2.CreatePrimary(t.rwc, tpm2.HandleOwner, tpm2.PCRSelection{}, "", "", defaultSRKTemplate)
|
|
case commonEkEquivalentHandle:
|
|
var tmpl tpm2.Public
|
|
if tmpl, err = t.ekTemplate(); err != nil {
|
|
return 0, false, fmt.Errorf("ek template: %v", err)
|
|
}
|
|
keyHnd, _, err = tpm2.CreatePrimary(t.rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", tmpl)
|
|
}
|
|
if err != nil {
|
|
return 0, false, fmt.Errorf("CreatePrimary failed: %v", err)
|
|
}
|
|
defer tpm2.FlushContext(t.rwc, keyHnd)
|
|
|
|
err = tpm2.EvictControl(t.rwc, "", tpm2.HandleOwner, keyHnd, pHnd)
|
|
if err != nil {
|
|
return 0, false, fmt.Errorf("EvictControl failed: %v", err)
|
|
}
|
|
|
|
return pHnd, true, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) eks() ([]EK, error) {
|
|
if cert, err := readEKCertFromNVRAM20(t.rwc); err == nil {
|
|
return []EK{
|
|
{Public: crypto.PublicKey(cert.PublicKey), Certificate: cert},
|
|
}, nil
|
|
}
|
|
|
|
// Attempt to create an EK.
|
|
tmpl, err := t.ekTemplate()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("ek template: %v", err)
|
|
}
|
|
|
|
ekHnd, _, err := tpm2.CreatePrimary(t.rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", tmpl)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("EK CreatePrimary failed: %v", err)
|
|
}
|
|
defer tpm2.FlushContext(t.rwc, ekHnd)
|
|
|
|
pub, _, _, err := tpm2.ReadPublic(t.rwc, ekHnd)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("EK ReadPublic failed: %v", err)
|
|
}
|
|
if pub.RSAParameters == nil {
|
|
return nil, errors.New("ECC EK not yet supported")
|
|
}
|
|
return []EK{
|
|
{
|
|
Public: &rsa.PublicKey{
|
|
E: int(pub.RSAParameters.Exponent()),
|
|
N: pub.RSAParameters.Modulus(),
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) newAK(opts *AKConfig) (*AK, error) {
|
|
// TODO(jsonp): Abstract choice of hierarchy & parent.
|
|
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get SRK handle: %v", err)
|
|
}
|
|
|
|
blob, pub, creationData, creationHash, tix, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", akTemplate)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("CreateKeyEx() failed: %v", err)
|
|
}
|
|
keyHandle, _, err := tpm2.Load(t.rwc, srk, "", pub, blob)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Load() failed: %v", err)
|
|
}
|
|
// If any errors occur, free the AK's handle.
|
|
defer func() {
|
|
if err != nil {
|
|
tpm2.FlushContext(t.rwc, keyHandle)
|
|
}
|
|
}()
|
|
|
|
// We can only certify the creation immediately afterwards, so we cache the result.
|
|
attestation, sig, err := tpm2.CertifyCreation(t.rwc, "", keyHandle, keyHandle, nil, creationHash, tpm2.SigScheme{tpm2.AlgRSASSA, tpm2.AlgSHA256, 0}, tix)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("CertifyCreation failed: %v", err)
|
|
}
|
|
// Pack the raw structure into a TPMU_SIGNATURE.
|
|
signature, err := tpmutil.Pack(tpm2.AlgRSASSA, tpm2.AlgSHA256, tpmutil.U16Bytes(sig))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to pack TPMT_SIGNATURE: %v", err)
|
|
}
|
|
return &AK{ak: newWrappedAK20(keyHandle, blob, pub, creationData, attestation, signature)}, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) {
|
|
k, ok := ak.ak.(*wrappedKey20)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected *wrappedKey20, got: %T", k)
|
|
}
|
|
|
|
parent, blob, pub, creationData, err := createKey(t, opts)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot create key: %v", err)
|
|
}
|
|
|
|
keyHandle, _, err := tpm2.Load(t.rwc, parent, "", pub, blob)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Load() failed: %v", err)
|
|
}
|
|
// If any errors occur, free the handle.
|
|
defer func() {
|
|
if err != nil {
|
|
tpm2.FlushContext(t.rwc, keyHandle)
|
|
}
|
|
}()
|
|
|
|
// Certify application key by AK
|
|
cp, err := k.certify(t, keyHandle)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("ak.Certify() failed: %v", err)
|
|
}
|
|
if !bytes.Equal(pub, cp.Public) {
|
|
return nil, fmt.Errorf("certified incorrect key, expected: %v, certified: %v", pub, cp.Public)
|
|
}
|
|
|
|
// Pack the raw structure into a TPMU_SIGNATURE.
|
|
tpmPub, err := tpm2.DecodePublic(pub)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode public key: %v", err)
|
|
}
|
|
pubKey, err := tpmPub.Key()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("access public key: %v", err)
|
|
}
|
|
return &Key{key: newWrappedKey20(keyHandle, blob, pub, creationData, cp.CreateAttestation, cp.CreateSignature), pub: pubKey, tpm: t}, nil
|
|
}
|
|
|
|
func createKey(t *wrappedTPM20, opts *KeyConfig) (tpmutil.Handle, []byte, []byte, []byte, error) {
|
|
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
|
|
if err != nil {
|
|
return 0, nil, nil, nil, fmt.Errorf("failed to get SRK handle: %v", err)
|
|
}
|
|
|
|
tmpl, err := templateFromConfig(opts)
|
|
if err != nil {
|
|
return 0, nil, nil, nil, fmt.Errorf("incorrect key options: %v", err)
|
|
}
|
|
|
|
blob, pub, creationData, _, _, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", tmpl)
|
|
if err != nil {
|
|
return 0, nil, nil, nil, fmt.Errorf("CreateKey() failed: %v", err)
|
|
}
|
|
|
|
return srk, blob, pub, creationData, err
|
|
}
|
|
|
|
func templateFromConfig(opts *KeyConfig) (tpm2.Public, error) {
|
|
var tmpl tpm2.Public
|
|
switch opts.Algorithm {
|
|
case RSA:
|
|
tmpl = rsaKeyTemplate
|
|
if opts.Size < 0 || opts.Size > 65535 { // basic sanity check
|
|
return tmpl, fmt.Errorf("incorrect size parameter")
|
|
}
|
|
tmpl.RSAParameters.KeyBits = uint16(opts.Size)
|
|
|
|
case ECDSA:
|
|
tmpl = ecdsaKeyTemplate
|
|
switch opts.Size {
|
|
case 256:
|
|
tmpl.NameAlg = tpm2.AlgSHA256
|
|
tmpl.ECCParameters.Sign.Hash = tpm2.AlgSHA256
|
|
tmpl.ECCParameters.CurveID = tpm2.CurveNISTP256
|
|
tmpl.ECCParameters.Point = tpm2.ECPoint{
|
|
XRaw: make([]byte, 32),
|
|
YRaw: make([]byte, 32),
|
|
}
|
|
case 384:
|
|
tmpl.NameAlg = tpm2.AlgSHA384
|
|
tmpl.ECCParameters.Sign.Hash = tpm2.AlgSHA384
|
|
tmpl.ECCParameters.CurveID = tpm2.CurveNISTP384
|
|
tmpl.ECCParameters.Point = tpm2.ECPoint{
|
|
XRaw: make([]byte, 48),
|
|
YRaw: make([]byte, 48),
|
|
}
|
|
case 521:
|
|
tmpl.NameAlg = tpm2.AlgSHA512
|
|
tmpl.ECCParameters.Sign.Hash = tpm2.AlgSHA512
|
|
tmpl.ECCParameters.CurveID = tpm2.CurveNISTP521
|
|
tmpl.ECCParameters.Point = tpm2.ECPoint{
|
|
XRaw: make([]byte, 65),
|
|
YRaw: make([]byte, 65),
|
|
}
|
|
default:
|
|
return tmpl, fmt.Errorf("unsupported key size: %v", opts.Size)
|
|
}
|
|
default:
|
|
return tmpl, fmt.Errorf("unsupported algorithm type: %q", opts.Algorithm)
|
|
}
|
|
|
|
return tmpl, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) deserializeAndLoad(opaqueBlob []byte) (tpmutil.Handle, *serializedKey, error) {
|
|
sKey, err := deserializeKey(opaqueBlob, TPMVersion20)
|
|
if err != nil {
|
|
return 0, nil, fmt.Errorf("deserializeKey() failed: %v", err)
|
|
}
|
|
if sKey.Encoding != keyEncodingEncrypted {
|
|
return 0, nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding)
|
|
}
|
|
|
|
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
|
|
if err != nil {
|
|
return 0, nil, fmt.Errorf("failed to get SRK handle: %v", err)
|
|
}
|
|
var hnd tpmutil.Handle
|
|
if hnd, _, err = tpm2.Load(t.rwc, srk, "", sKey.Public, sKey.Blob); err != nil {
|
|
return 0, nil, fmt.Errorf("Load() failed: %v", err)
|
|
}
|
|
return hnd, sKey, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) loadAK(opaqueBlob []byte) (*AK, error) {
|
|
hnd, sKey, err := t.deserializeAndLoad(opaqueBlob)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot load attestation key: %v", err)
|
|
}
|
|
return &AK{ak: newWrappedAK20(hnd, sKey.Blob, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature)}, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) loadKey(opaqueBlob []byte) (*Key, error) {
|
|
hnd, sKey, err := t.deserializeAndLoad(opaqueBlob)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot load signing key: %v", err)
|
|
}
|
|
tpmPub, err := tpm2.DecodePublic(sKey.Public)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode public blob: %v", err)
|
|
}
|
|
pub, err := tpmPub.Key()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("access public key: %v", err)
|
|
}
|
|
return &Key{key: newWrappedKey20(hnd, sKey.Blob, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature), pub: pub, tpm: t}, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) pcrs(alg HashAlg) ([]PCR, error) {
|
|
PCRs, err := readAllPCRs20(t.rwc, alg.goTPMAlg())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read PCRs: %v", err)
|
|
}
|
|
|
|
out := make([]PCR, len(PCRs))
|
|
for index, digest := range PCRs {
|
|
out[int(index)] = PCR{
|
|
Index: int(index),
|
|
Digest: digest,
|
|
DigestAlg: alg.cryptoHash(),
|
|
}
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func (t *wrappedTPM20) measurementLog() ([]byte, error) {
|
|
return t.rwc.MeasurementLog()
|
|
}
|
|
|
|
// wrappedKey20 represents a key manipulated through a *wrappedTPM20.
|
|
type wrappedKey20 struct {
|
|
hnd tpmutil.Handle
|
|
|
|
blob []byte
|
|
public []byte // used by both TPM1.2 and 2.0
|
|
createData []byte
|
|
createAttestation []byte
|
|
createSignature []byte
|
|
}
|
|
|
|
func newWrappedAK20(hnd tpmutil.Handle, blob, public, createData, createAttestation, createSig []byte) ak {
|
|
return &wrappedKey20{
|
|
hnd: hnd,
|
|
blob: blob,
|
|
public: public,
|
|
createData: createData,
|
|
createAttestation: createAttestation,
|
|
createSignature: createSig,
|
|
}
|
|
}
|
|
|
|
func newWrappedKey20(hnd tpmutil.Handle, blob, public, createData, createAttestation, createSig []byte) key {
|
|
return &wrappedKey20{
|
|
hnd: hnd,
|
|
blob: blob,
|
|
public: public,
|
|
createData: createData,
|
|
createAttestation: createAttestation,
|
|
createSignature: createSig,
|
|
}
|
|
}
|
|
|
|
func (k *wrappedKey20) marshal() ([]byte, error) {
|
|
return (&serializedKey{
|
|
Encoding: keyEncodingEncrypted,
|
|
TPMVersion: TPMVersion20,
|
|
|
|
Blob: k.blob,
|
|
Public: k.public,
|
|
CreateData: k.createData,
|
|
CreateAttestation: k.createAttestation,
|
|
CreateSignature: k.createSignature,
|
|
}).Serialize()
|
|
}
|
|
|
|
func (k *wrappedKey20) close(t tpmBase) error {
|
|
tpm, ok := t.(*wrappedTPM20)
|
|
if !ok {
|
|
return fmt.Errorf("expected *wrappedTPM20, got %T", t)
|
|
}
|
|
return tpm2.FlushContext(tpm.rwc, k.hnd)
|
|
}
|
|
|
|
func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential) ([]byte, error) {
|
|
t, ok := tb.(*wrappedTPM20)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
|
|
}
|
|
|
|
if len(in.Credential) < 2 {
|
|
return nil, fmt.Errorf("malformed credential blob")
|
|
}
|
|
credential := in.Credential[2:]
|
|
if len(in.Secret) < 2 {
|
|
return nil, fmt.Errorf("malformed encrypted secret")
|
|
}
|
|
secret := in.Secret[2:]
|
|
|
|
ekHnd, _, err := t.getPrimaryKeyHandle(commonEkEquivalentHandle)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sessHandle, _, err := tpm2.StartAuthSession(
|
|
t.rwc,
|
|
tpm2.HandleNull, /*tpmKey*/
|
|
tpm2.HandleNull, /*bindKey*/
|
|
make([]byte, 16), /*nonceCaller*/
|
|
nil, /*secret*/
|
|
tpm2.SessionPolicy,
|
|
tpm2.AlgNull,
|
|
tpm2.AlgSHA256)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating session: %v", err)
|
|
}
|
|
defer tpm2.FlushContext(t.rwc, sessHandle)
|
|
|
|
if _, err := tpm2.PolicySecret(t.rwc, tpm2.HandleEndorsement, tpm2.AuthCommand{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}, sessHandle, nil, nil, nil, 0); err != nil {
|
|
return nil, fmt.Errorf("tpm2.PolicySecret() failed: %v", err)
|
|
}
|
|
|
|
return tpm2.ActivateCredentialUsingAuth(t.rwc, []tpm2.AuthCommand{
|
|
{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession},
|
|
{Session: sessHandle, Attributes: tpm2.AttrContinueSession},
|
|
}, k.hnd, ekHnd, credential, secret)
|
|
}
|
|
|
|
func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
|
|
t, ok := tb.(*wrappedTPM20)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
|
|
}
|
|
hnd, ok := handle.(tpmutil.Handle)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected tpmutil.Handle, got %T", handle)
|
|
}
|
|
scheme := tpm2.SigScheme{
|
|
Alg: tpm2.AlgRSASSA,
|
|
Hash: tpm2.AlgSHA256,
|
|
}
|
|
return certify(t.rwc, hnd, k.hnd, scheme)
|
|
}
|
|
|
|
func (k *wrappedKey20) quote(tb tpmBase, nonce []byte, alg HashAlg) (*Quote, error) {
|
|
t, ok := tb.(*wrappedTPM20)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
|
|
}
|
|
return quote20(t.rwc, k.hnd, tpm2.Algorithm(alg), nonce)
|
|
}
|
|
|
|
func (k *wrappedKey20) attestationParameters() AttestationParameters {
|
|
return AttestationParameters{
|
|
Public: k.public,
|
|
CreateData: k.createData,
|
|
CreateAttestation: k.createAttestation,
|
|
CreateSignature: k.createSignature,
|
|
}
|
|
}
|
|
|
|
func (k *wrappedKey20) certificationParameters() CertificationParameters {
|
|
return CertificationParameters{
|
|
Public: k.public,
|
|
CreateAttestation: k.createAttestation,
|
|
CreateSignature: k.createSignature,
|
|
}
|
|
}
|
|
|
|
func (k *wrappedKey20) sign(tb tpmBase, digest []byte, pub crypto.PublicKey, opts crypto.SignerOpts) ([]byte, error) {
|
|
t, ok := tb.(*wrappedTPM20)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb)
|
|
}
|
|
switch pub.(type) {
|
|
case *ecdsa.PublicKey:
|
|
return signECDSA(t.rwc, k.hnd, digest)
|
|
case *rsa.PublicKey:
|
|
return signRSA(t.rwc, k.hnd, digest, opts)
|
|
}
|
|
return nil, fmt.Errorf("unsupported signing key type: %T", pub)
|
|
}
|
|
|
|
func signECDSA(rw io.ReadWriter, key tpmutil.Handle, digest []byte) ([]byte, error) {
|
|
sig, err := tpm2.Sign(rw, key, "", digest, nil, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot sign: %v", err)
|
|
}
|
|
if sig.ECC == nil {
|
|
return nil, fmt.Errorf("expected ECDSA signature, got: %v", sig.Alg)
|
|
}
|
|
return asn1.Marshal(struct {
|
|
R *big.Int
|
|
S *big.Int
|
|
}{sig.ECC.R, sig.ECC.S})
|
|
}
|
|
|
|
func signRSA(rw io.ReadWriter, key tpmutil.Handle, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
|
|
h, err := tpm2.HashToAlgorithm(opts.HashFunc())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("incorrect hash algorithm: %v", err)
|
|
}
|
|
|
|
scheme := &tpm2.SigScheme{
|
|
Alg: tpm2.AlgRSASSA,
|
|
Hash: h,
|
|
}
|
|
|
|
if pss, ok := opts.(*rsa.PSSOptions); ok {
|
|
if pss.SaltLength != rsa.PSSSaltLengthAuto && pss.SaltLength != len(digest) {
|
|
return nil, fmt.Errorf("PSS salt length %d is incorrect, expected rsa.PSSSaltLengthAuto or %d", pss.SaltLength, len(digest))
|
|
}
|
|
scheme.Alg = tpm2.AlgRSAPSS
|
|
}
|
|
|
|
sig, err := tpm2.Sign(rw, key, "", digest, nil, scheme)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot sign: %v", err)
|
|
}
|
|
if sig.RSA == nil {
|
|
return nil, fmt.Errorf("expected RSA signature, got: %v", sig.Alg)
|
|
}
|
|
return sig.RSA.Signature, nil
|
|
}
|
|
|
|
func (k *wrappedKey20) decrypt(tb tpmBase, ctxt []byte) ([]byte, error) {
|
|
return nil, fmt.Errorf("not implemented")
|
|
}
|
|
|
|
func (k *wrappedKey20) blobs() ([]byte, []byte, error) {
|
|
return k.public, k.blob, nil
|
|
}
|