diff --git a/tpm2/crypto.go b/tpm2/crypto.go index 3082cccb..b54f25bf 100644 --- a/tpm2/crypto.go +++ b/tpm2/crypto.go @@ -1,6 +1,7 @@ package tpm2 import ( + "crypto" "crypto/ecdh" "crypto/ecdsa" "crypto/elliptic" @@ -9,6 +10,87 @@ import ( "math/big" ) +// Priv converts a TPM private key into one recognized by the crypto package. +func Priv(public TPMTPublic, sensitive TPMTSensitive) (crypto.PrivateKey, error) { + + var privateKey crypto.PrivateKey + + publicKey, err := Pub(public) + if err != nil { + return nil, err + } + + switch public.Type { + case TPMAlgRSA: + publicKey := publicKey.(*rsa.PublicKey) + + prime, err := sensitive.Sensitive.RSA() + if err != nil { + return nil, fmt.Errorf("failed to retrieve the RSA prime number") + } + + P := new(big.Int).SetBytes(prime.Buffer) + Q := new(big.Int).Div(publicKey.N, P) + phiN := new(big.Int).Mul(new(big.Int).Sub(P, big.NewInt(1)), new(big.Int).Sub(Q, big.NewInt(1))) + D := new(big.Int).ModInverse(big.NewInt(int64(publicKey.E)), phiN) + + privateKey = rsa.PrivateKey{ + PublicKey: *publicKey, + D: D, + Primes: []*big.Int{P, Q}, + } + privateKey := privateKey.(rsa.PrivateKey) + + privateKey.Precompute() + default: + return nil, fmt.Errorf("unsupported public key type: %v", public.Type) + } + + return privateKey, nil +} + +// Pub converts a TPM public key into one recognized by the crypto package. +func Pub(public TPMTPublic) (crypto.PublicKey, error) { + var publicKey crypto.PublicKey + + switch public.Type { + case TPMAlgRSA: + parameters, err := public.Parameters.RSADetail() + if err != nil { + return nil, fmt.Errorf("failed to retrieve the RSA parameters") + } + + n, err := public.Unique.RSA() + if err != nil { + return nil, fmt.Errorf("failed to parse and retrieve the RSA modulus") + } + + publicKey, err = RSAPub(parameters, n) + if err != nil { + return nil, fmt.Errorf("failed to retrieve the RSA public key") + } + case TPMAlgECC: + parameters, err := public.Parameters.ECCDetail() + if err != nil { + return nil, fmt.Errorf("failed to retrieve the ECC parameters") + } + + pub, err := public.Unique.ECC() + if err != nil { + return nil, fmt.Errorf("failed to parse and retrieve the ECC point") + } + + publicKey, err = ECDSAPub(parameters, pub) + if err != nil { + return nil, fmt.Errorf("failed to retrieve the ECC public key") + } + default: + return nil, fmt.Errorf("unsupported public key type: %v", public.Type) + } + + return publicKey, nil +} + // RSAPub converts a TPM RSA public key into one recognized by the rsa package. func RSAPub(parms *TPMSRSAParms, pub *TPM2BPublicKeyRSA) (*rsa.PublicKey, error) { result := rsa.PublicKey{ @@ -24,6 +106,41 @@ func RSAPub(parms *TPMSRSAParms, pub *TPM2BPublicKeyRSA) (*rsa.PublicKey, error) return &result, nil } +// ECDSAPub converts a TPM ECC public key into one recognized by the ecdh package +func ECDSAPub(parms *TPMSECCParms, pub *TPMSECCPoint) (*ecdsa.PublicKey, error) { + + var c elliptic.Curve + switch parms.CurveID { + case TPMECCNistP256: + c = elliptic.P256() + case TPMECCNistP384: + c = elliptic.P384() + case TPMECCNistP521: + c = elliptic.P521() + default: + return nil, fmt.Errorf("unknown curve: %v", parms.CurveID) + } + + pubKey := ecdsa.PublicKey{ + Curve: c, + X: big.NewInt(0).SetBytes(pub.X.Buffer), + Y: big.NewInt(0).SetBytes(pub.Y.Buffer), + } + + return &pubKey, nil +} + +// ECDHPub converts a TPM ECC public key into one recognized by the ecdh package +func ECDHPub(parms *TPMSECCParms, pub *TPMSECCPoint) (*ecdh.PublicKey, error) { + + pubKey, err := ECDSAPub(parms, pub) + if err != nil { + return nil, err + } + + return pubKey.ECDH() +} + // ECDHPubKey converts a TPM ECC public key into one recognized by the ecdh package func ECDHPubKey(curve ecdh.Curve, pub *TPMSECCPoint) (*ecdh.PublicKey, error) { diff --git a/tpm2/structures.go b/tpm2/structures.go index 11a0261e..fb4685cc 100644 --- a/tpm2/structures.go +++ b/tpm2/structures.go @@ -2868,6 +2868,38 @@ func New2BTemplate[C TemplateContents](data C) TPM2BTemplate { } } +// Sym returns the 'sym' member of the union. +func (u *TPMUSensitiveComposite) Sym() (*TPM2BSymKey, error) { + if u.selector == TPMAlgSymCipher { + return u.contents.(*TPM2BSymKey), nil + } + return nil, fmt.Errorf("did not contain sym (selector value was %v)", u.selector) +} + +// Bits returns the 'bits' member of the union. +func (u *TPMUSensitiveComposite) Bits() (*TPM2BSensitiveData, error) { + if u.selector == TPMAlgKeyedHash { + return u.contents.(*TPM2BSensitiveData), nil + } + return nil, fmt.Errorf("did not contain bits (selector value was %v)", u.selector) +} + +// RSA returns the 'rsa' member of the union. +func (u *TPMUSensitiveComposite) RSA() (*TPM2BPrivateKeyRSA, error) { + if u.selector == TPMAlgRSA { + return u.contents.(*TPM2BPrivateKeyRSA), nil + } + return nil, fmt.Errorf("did not contain rsa (selector value was %v)", u.selector) +} + +// ECC returns the 'ecc' member of the union. +func (u *TPMUSensitiveComposite) ECC() (*TPM2BECCParameter, error) { + if u.selector == TPMAlgECC { + return u.contents.(*TPM2BECCParameter), nil + } + return nil, fmt.Errorf("did not contain ecc (selector value was %v)", u.selector) +} + // TPMUSensitiveComposite represents a TPMU_SENSITIVE_COMPOSITE. // See definition in Part 2: Structures, section 12.3.2.3. type TPMUSensitiveComposite struct {