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>
194 lines
4.7 KiB
Go
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)
|
|
}
|
|
}
|