File: main.go

package info (click to toggle)
golang-github-google-go-tpm 0.9.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,932 kB
  • sloc: makefile: 13
file content (124 lines) | stat: -rw-r--r-- 3,827 bytes parent folder | download
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
}