1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
//go:build !windows
// Binary tpm2-ekcert reads an x509 certificate from a specific NVRAM index.
package main
import (
"crypto"
"crypto/x509"
"encoding/asn1"
"errors"
"flag"
"fmt"
"os"
"reflect"
"github.com/google/go-tpm/legacy/tpm2"
"github.com/google/go-tpm/tpmutil"
)
var (
tpmPath = flag.String("tpm-path", "/dev/tpm0", "Path to the TPM device (character device or a Unix socket)")
// Default value is defined in section 7.8, "NV Memory" of the latest version pdf on:
// https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance/
certIndex = flag.Uint("cert-index", 0x01C00002, "NVRAM index of the certificate file")
tmplIndex = flag.Uint("template-index", 0, "NVRAM index of the EK template; if zero, default RSA EK template is used")
outPath = flag.String("output", "", "File path for output; leave blank to write to stdout")
// Default EK template defined in:
// https://trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf
defaultEKTemplate = tpm2.Public{
Type: tpm2.AlgRSA,
NameAlg: tpm2.AlgSHA256,
Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent | tpm2.FlagSensitiveDataOrigin |
tpm2.FlagAdminWithPolicy | tpm2.FlagRestricted | tpm2.FlagDecrypt,
AuthPolicy: []byte{
0x83, 0x71, 0x97, 0x67, 0x44, 0x84,
0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D,
0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52,
0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64,
0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14,
0x69, 0xAA,
},
RSAParameters: &tpm2.RSAParams{
Symmetric: &tpm2.SymScheme{
Alg: tpm2.AlgAES,
KeyBits: 128,
Mode: tpm2.AlgCFB,
},
KeyBits: 2048,
ModulusRaw: make([]byte, 256),
},
}
)
func main() {
flag.Parse()
cert, err := readEKCert(*tpmPath, uint32(*certIndex), uint32(*tmplIndex))
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if *outPath == "" {
fmt.Println(string(cert))
return
}
if err := os.WriteFile(*outPath, cert, os.ModePerm); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func readEKCert(path string, certIdx, tmplIdx uint32) ([]byte, error) {
rwc, err := tpm2.OpenTPM(path)
if err != nil {
return nil, fmt.Errorf("can't open TPM at %q: %v", path, err)
}
defer rwc.Close()
ekCert, err := tpm2.NVRead(rwc, tpmutil.Handle(certIdx))
if err != nil {
return nil, fmt.Errorf("reading EK cert: %v", err)
}
// Identify if any `padding` exists in the EK cert that was read
var raw asn1.RawValue
paddingBytes, err := asn1.Unmarshal(ekCert, &raw)
if err != nil {
return nil, fmt.Errorf("ASN.1 Unmarshal failed: %v", err)
}
fmt.Printf("TPM NV Index bytes read: %d\n", len(ekCert))
fmt.Printf("Padding found from ASN.1 Unmarshal: %d\n", len(paddingBytes))
// Sanity-check that this is a valid certificate.
cert, err := x509.ParseCertificate(ekCert[0 : len(ekCert)-len(paddingBytes)])
if err != nil {
return nil, fmt.Errorf("parsing EK cert: %v", err)
}
// Initialize EK and compare public key to ekCert.PublicKey.
var ekh tpmutil.Handle
var ekPub crypto.PublicKey
if tmplIdx != 0 {
ekTemplate, err := tpm2.NVRead(rwc, tpmutil.Handle(tmplIdx))
if err != nil {
return nil, fmt.Errorf("reading EK template: %v", err)
}
ekh, ekPub, err = tpm2.CreatePrimaryRawTemplate(rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", ekTemplate)
if err != nil {
return nil, fmt.Errorf("creating EK: %v", err)
}
} else {
ekh, ekPub, err = tpm2.CreatePrimary(rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", defaultEKTemplate)
if err != nil {
return nil, fmt.Errorf("creating EK: %v", err)
}
}
defer tpm2.FlushContext(rwc, ekh)
if !reflect.DeepEqual(ekPub, cert.PublicKey) {
return nil, errors.New("public key in EK certificate differs from public key created via EK template")
}
return ekCert, nil
}
|