Files
mcias/vendor/github.com/google/go-tpm/tpm2/crypto.go
Kyle Isom 115f23a3ea Add Nix flake for mciasctl and mciasgrpcctl
Vendor dependencies and expose control program binaries via
nix build. Uses nixpkgs-unstable for Go 1.26 support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:01:21 -07:00

194 lines
4.7 KiB
Go

package tpm2
import (
"crypto"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"fmt"
"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)
if sensitive.SensitiveType != TPMAlgRSA {
return nil, fmt.Errorf("sensitive type is not equal to public type")
}
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)
rsaKey := &rsa.PrivateKey{
PublicKey: *publicKey,
D: D,
Primes: []*big.Int{P, Q},
}
rsaKey.Precompute()
privateKey = rsaKey
case TPMAlgECC:
publicKey := publicKey.(*ecdsa.PublicKey)
if sensitive.SensitiveType != TPMAlgECC {
return nil, fmt.Errorf("sensitive type is not equal to public type")
}
d, err := sensitive.Sensitive.ECC()
if err != nil {
return nil, fmt.Errorf("failed to retrieve the ECC")
}
D := new(big.Int).SetBytes(d.Buffer)
ecdsaKey := &ecdsa.PrivateKey{
PublicKey: *publicKey,
D: D,
}
privateKey = ecdsaKey
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{
N: big.NewInt(0).SetBytes(pub.Buffer),
E: int(parms.Exponent),
}
// TPM considers 65537 to be the default RSA public exponent, and 0 in
// the parms
// indicates so.
if result.E == 0 {
result.E = 65537
}
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()
}
// ECCPoint returns an uncompressed ECC Point
func ECCPoint(pubKey *ecdh.PublicKey) (*big.Int, *big.Int, error) {
b := pubKey.Bytes()
size, err := elementLength(pubKey.Curve())
if err != nil {
return nil, nil, fmt.Errorf("ECCPoint: %w", err)
}
return big.NewInt(0).SetBytes(b[1 : size+1]),
big.NewInt(0).SetBytes(b[size+1:]), nil
}
func elementLength(c ecdh.Curve) (int, error) {
switch c {
case ecdh.P256():
// crypto/internal/nistec/fiat.p256ElementLen
return 32, nil
case ecdh.P384():
// crypto/internal/nistec/fiat.p384ElementLen
return 48, nil
case ecdh.P521():
// crypto/internal/nistec/fiat.p521ElementLen
return 66, nil
default:
return 0, fmt.Errorf("unknown element length for curve: %v", c)
}
}