mirror of
https://github.com/google/go-attestation.git
synced 2024-12-19 04:57:59 +00:00
Disable linux TPM12 support if build without cgo
This commit is contained in:
parent
142c9d263a
commit
5eca4dfe2a
@ -12,7 +12,7 @@
|
|||||||
// License for the specific language governing permissions and limitations under
|
// License for the specific language governing permissions and limitations under
|
||||||
// the License.
|
// the License.
|
||||||
|
|
||||||
// +build linux,!gofuzz
|
// +build linux,!gofuzz,cgo
|
||||||
|
|
||||||
package attest
|
package attest
|
||||||
|
|
||||||
|
164
attest/tpm12_linux.go
Normal file
164
attest/tpm12_linux.go
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Copyright 2020 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
// use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
// the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
// License for the specific language governing permissions and limitations under
|
||||||
|
// the License.
|
||||||
|
|
||||||
|
// +build linux,!gofuzz,cgo
|
||||||
|
|
||||||
|
package attest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
"github.com/google/go-tspi/attestation"
|
||||||
|
"github.com/google/go-tspi/tspi"
|
||||||
|
"github.com/google/go-tspi/tspiconst"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
getTPM12Impl = getTPM12
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTPM12() (*TPM, error) {
|
||||||
|
ctx, err := tspi.NewContext()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = ctx.Connect(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &TPM{tpm: &trousersTPM{ctx: ctx}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// trousersTPM interfaces with a TPM 1.2 device via tcsd.
|
||||||
|
type trousersTPM struct {
|
||||||
|
ctx *tspi.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*trousersTPM) isTPMBase() {}
|
||||||
|
|
||||||
|
func (t *trousersTPM) tpmVersion() TPMVersion {
|
||||||
|
return TPMVersion12
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trousersTPM) close() error {
|
||||||
|
return t.ctx.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func readTPM12VendorAttributes(context *tspi.Context) (TCGVendorID, string, error) {
|
||||||
|
// TPM 1.2 doesn't seem to store vendor data (other than unique ID)
|
||||||
|
vendor, err := context.GetCapability(tspiconst.TSS_TPMCAP_PROPERTY, 4, tspiconst.TSS_TPMCAP_PROP_MANUFACTURER)
|
||||||
|
if err != nil {
|
||||||
|
return TCGVendorID(0), "", fmt.Errorf("tspi::Context::GetCapability failed: %v", err)
|
||||||
|
}
|
||||||
|
if len(vendor) > 4 {
|
||||||
|
return TCGVendorID(0), "", fmt.Errorf("expecting at most 32-bit VendorID, got %d-bit ID instead", len(vendor)*8)
|
||||||
|
}
|
||||||
|
vendorID := TCGVendorID(binary.BigEndian.Uint32(vendor))
|
||||||
|
return vendorID, vendorID.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info returns information about the TPM.
|
||||||
|
func (t *trousersTPM) info() (*TPMInfo, error) {
|
||||||
|
tInfo := TPMInfo{
|
||||||
|
Version: TPMVersion12,
|
||||||
|
Interface: TPMInterfaceDaemonManaged,
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if tInfo.Manufacturer, tInfo.VendorInfo, err = readTPM12VendorAttributes(t.ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readEKCertFromNVRAM12(ctx *tspi.Context) (*x509.Certificate, error) {
|
||||||
|
ekCert, err := attestation.GetEKCert(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading EK cert: %v", err)
|
||||||
|
}
|
||||||
|
return ParseEKCertificate(ekCert)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trousersTPM) eks() ([]EK, error) {
|
||||||
|
cert, err := readEKCertFromNVRAM12(t.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("readEKCertFromNVRAM failed: %v", err)
|
||||||
|
}
|
||||||
|
return []EK{
|
||||||
|
{Public: crypto.PublicKey(cert.PublicKey), Certificate: cert},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trousersTPM) newAK(opts *AKConfig) (*AK, error) {
|
||||||
|
pub, blob, err := attestation.CreateAIK(t.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("CreateAIK failed: %v", err)
|
||||||
|
}
|
||||||
|
return &AK{ak: newTrousersKey12(blob, pub)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trousersTPM) loadAK(opaqueBlob []byte) (*AK, error) {
|
||||||
|
sKey, err := deserializeKey(opaqueBlob, TPMVersion12)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("deserializeKey() failed: %v", err)
|
||||||
|
}
|
||||||
|
if sKey.Encoding != keyEncodingEncrypted {
|
||||||
|
return nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &AK{ak: newTrousersKey12(sKey.Blob, sKey.Public)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// allPCRs12 returns a map of all the PCR values on the TPM
|
||||||
|
func allPCRs12(ctx *tspi.Context) (map[uint32][]byte, error) {
|
||||||
|
tpm := ctx.GetTPM()
|
||||||
|
PCRlist, err := tpm.GetPCRValues()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read PCRs: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
PCRs := make(map[uint32][]byte)
|
||||||
|
for i := 0; i < len(PCRlist); i++ {
|
||||||
|
PCRs[(uint32)(i)] = PCRlist[i]
|
||||||
|
}
|
||||||
|
return PCRs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trousersTPM) pcrs(alg HashAlg) ([]PCR, error) {
|
||||||
|
if alg != HashSHA1 {
|
||||||
|
return nil, fmt.Errorf("non-SHA1 algorithm %v is not supported on TPM 1.2", alg)
|
||||||
|
}
|
||||||
|
PCRs, err := allPCRs12(t.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read PCRs: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]PCR, len(PCRs))
|
||||||
|
for index, digest := range PCRs {
|
||||||
|
out[int(index)] = PCR{
|
||||||
|
Index: int(index),
|
||||||
|
Digest: digest,
|
||||||
|
DigestAlg: alg.cryptoHash(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trousersTPM) measurementLog() ([]byte, error) {
|
||||||
|
return ioutil.ReadFile("/sys/kernel/security/tpm0/binary_bios_measurements")
|
||||||
|
}
|
@ -17,8 +17,7 @@
|
|||||||
package attest
|
package attest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"errors"
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -26,11 +25,6 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/certificate-transparency-go/x509"
|
|
||||||
"github.com/google/go-tspi/attestation"
|
|
||||||
"github.com/google/go-tspi/tspi" //for tpm12 support
|
|
||||||
"github.com/google/go-tspi/tspiconst"
|
|
||||||
|
|
||||||
"github.com/google/go-tpm/tpm2"
|
"github.com/google/go-tpm/tpm2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,6 +32,9 @@ const (
|
|||||||
tpmRoot = "/sys/class/tpm"
|
tpmRoot = "/sys/class/tpm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This will be initialized if we build with CGO (needed for TPM 1.2 support).
|
||||||
|
var getTPM12Impl func() (*TPM, error)
|
||||||
|
|
||||||
func probeSystemTPMs() ([]probedTPM, error) {
|
func probeSystemTPMs() ([]probedTPM, error) {
|
||||||
var tpms []probedTPM
|
var tpms []probedTPM
|
||||||
|
|
||||||
@ -80,15 +77,10 @@ func (cc *linuxCmdChannel) MeasurementLog() ([]byte, error) {
|
|||||||
func openTPM(tpm probedTPM) (*TPM, error) {
|
func openTPM(tpm probedTPM) (*TPM, error) {
|
||||||
switch tpm.Version {
|
switch tpm.Version {
|
||||||
case TPMVersion12:
|
case TPMVersion12:
|
||||||
// TPM1.2 must be using Daemon (Connect will fail if not the case)
|
if getTPM12Impl == nil {
|
||||||
ctx, err := tspi.NewContext()
|
return nil, errors.New("support for Linux TPM 1.2 disabled (build with CGO to enable)")
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
if err = ctx.Connect(); err != nil {
|
return getTPM12Impl()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &TPM{tpm: &trousersTPM{ctx: ctx}}, nil
|
|
||||||
|
|
||||||
case TPMVersion20:
|
case TPMVersion20:
|
||||||
interf := TPMInterfaceDirect
|
interf := TPMInterfaceDirect
|
||||||
@ -119,123 +111,3 @@ func openTPM(tpm probedTPM) (*TPM, error) {
|
|||||||
return nil, fmt.Errorf("unsuported TPM version: %v", tpm.Version)
|
return nil, fmt.Errorf("unsuported TPM version: %v", tpm.Version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trousersTPM interfaces with a TPM 1.2 device via tcsd.
|
|
||||||
type trousersTPM struct {
|
|
||||||
ctx *tspi.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*trousersTPM) isTPMBase() {}
|
|
||||||
|
|
||||||
func (t *trousersTPM) tpmVersion() TPMVersion {
|
|
||||||
return TPMVersion12
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trousersTPM) close() error {
|
|
||||||
return t.ctx.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func readTPM12VendorAttributes(context *tspi.Context) (TCGVendorID, string, error) {
|
|
||||||
// TPM 1.2 doesn't seem to store vendor data (other than unique ID)
|
|
||||||
vendor, err := context.GetCapability(tspiconst.TSS_TPMCAP_PROPERTY, 4, tspiconst.TSS_TPMCAP_PROP_MANUFACTURER)
|
|
||||||
if err != nil {
|
|
||||||
return TCGVendorID(0), "", fmt.Errorf("tspi::Context::GetCapability failed: %v", err)
|
|
||||||
}
|
|
||||||
if len(vendor) > 4 {
|
|
||||||
return TCGVendorID(0), "", fmt.Errorf("expecting at most 32-bit VendorID, got %d-bit ID instead", len(vendor)*8)
|
|
||||||
}
|
|
||||||
vendorID := TCGVendorID(binary.BigEndian.Uint32(vendor))
|
|
||||||
return vendorID, vendorID.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info returns information about the TPM.
|
|
||||||
func (t *trousersTPM) info() (*TPMInfo, error) {
|
|
||||||
tInfo := TPMInfo{
|
|
||||||
Version: TPMVersion12,
|
|
||||||
Interface: TPMInterfaceDaemonManaged,
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if tInfo.Manufacturer, tInfo.VendorInfo, err = readTPM12VendorAttributes(t.ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &tInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readEKCertFromNVRAM12(ctx *tspi.Context) (*x509.Certificate, error) {
|
|
||||||
ekCert, err := attestation.GetEKCert(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("reading EK cert: %v", err)
|
|
||||||
}
|
|
||||||
return ParseEKCertificate(ekCert)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trousersTPM) eks() ([]EK, error) {
|
|
||||||
cert, err := readEKCertFromNVRAM12(t.ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("readEKCertFromNVRAM failed: %v", err)
|
|
||||||
}
|
|
||||||
return []EK{
|
|
||||||
{Public: crypto.PublicKey(cert.PublicKey), Certificate: cert},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trousersTPM) newAK(opts *AKConfig) (*AK, error) {
|
|
||||||
pub, blob, err := attestation.CreateAIK(t.ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("CreateAIK failed: %v", err)
|
|
||||||
}
|
|
||||||
return &AK{ak: newTrousersKey12(blob, pub)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trousersTPM) loadAK(opaqueBlob []byte) (*AK, error) {
|
|
||||||
sKey, err := deserializeKey(opaqueBlob, TPMVersion12)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("deserializeKey() failed: %v", err)
|
|
||||||
}
|
|
||||||
if sKey.Encoding != keyEncodingEncrypted {
|
|
||||||
return nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &AK{ak: newTrousersKey12(sKey.Blob, sKey.Public)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// allPCRs12 returns a map of all the PCR values on the TPM
|
|
||||||
func allPCRs12(ctx *tspi.Context) (map[uint32][]byte, error) {
|
|
||||||
tpm := ctx.GetTPM()
|
|
||||||
PCRlist, err := tpm.GetPCRValues()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read PCRs: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
PCRs := make(map[uint32][]byte)
|
|
||||||
for i := 0; i < len(PCRlist); i++ {
|
|
||||||
PCRs[(uint32)(i)] = PCRlist[i]
|
|
||||||
}
|
|
||||||
return PCRs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trousersTPM) pcrs(alg HashAlg) ([]PCR, error) {
|
|
||||||
if alg != HashSHA1 {
|
|
||||||
return nil, fmt.Errorf("non-SHA1 algorithm %v is not supported on TPM 1.2", alg)
|
|
||||||
}
|
|
||||||
PCRs, err := allPCRs12(t.ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read PCRs: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]PCR, len(PCRs))
|
|
||||||
for index, digest := range PCRs {
|
|
||||||
out[int(index)] = PCR{
|
|
||||||
Index: int(index),
|
|
||||||
Digest: digest,
|
|
||||||
DigestAlg: alg.cryptoHash(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trousersTPM) measurementLog() ([]byte, error) {
|
|
||||||
return ioutil.ReadFile("/sys/kernel/security/tpm0/binary_bios_measurements")
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user