github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/tpm2_tao.go (about)

     1  // Copyright (c) 2014, Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tao
    16  
    17  import (
    18  	"bytes"
    19  	"crypto/rsa"
    20  	"crypto/sha1"
    21  	"crypto/x509"
    22  	"encoding/binary"
    23  	"encoding/hex"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"io/ioutil"
    28  	"net"
    29  	"os"
    30  	"path"
    31  	"runtime"
    32  	"strconv"
    33  	"strings"
    34  	"time"
    35  
    36  	"github.com/golang/protobuf/proto"
    37  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    38  	"github.com/jlmucb/cloudproxy/go/tpm2"
    39  	"github.com/jlmucb/cloudproxy/go/util"
    40  )
    41  
    42  func EncodeTwoBytes(b1 []byte, b2 []byte) []byte {
    43  	buf := new(bytes.Buffer)
    44  	err := binary.Write(buf, binary.BigEndian, uint16(len(b1)))
    45  	if err != nil {
    46  		return nil
    47  	}
    48  	err = binary.Write(buf, binary.BigEndian, b1)
    49  	if err != nil {
    50  		return nil
    51  	}
    52  	err = binary.Write(buf, binary.BigEndian, uint16(len(b2)))
    53  	if err != nil {
    54  		return nil
    55  	}
    56  	err = binary.Write(buf, binary.BigEndian, b2)
    57  	if err != nil {
    58  		return nil
    59  	}
    60  	return buf.Bytes()
    61  }
    62  
    63  func DecodeTwoBytes(b []byte) ([]byte, []byte) {
    64  	buf := bytes.NewBuffer(b)
    65  	var size uint16
    66  	err := binary.Read(buf, binary.BigEndian, &size)
    67  	if err != nil {
    68  		return nil, nil
    69  	}
    70  	b1 := make([]byte, size, size)
    71  	binary.Read(buf, binary.BigEndian, b1)
    72  	err = binary.Read(buf, binary.BigEndian, &size)
    73  	if err != nil {
    74  		return nil, nil
    75  	}
    76  	b2 := make([]byte, size, size)
    77  	binary.Read(buf, binary.BigEndian, b2)
    78  	return b1, b2
    79  }
    80  
    81  // A TPM2Tao implements the Tao using a hardware TPM device.
    82  type TPM2Tao struct {
    83  	// rw is the device through which TPM2Tao communicates with the TPM.
    84  	// usually /dev/tpm0.
    85  	rw io.ReadWriteCloser
    86  
    87  	// State path (includes config info)
    88  	path string
    89  
    90  	// quote-key cert
    91  	rootCert []byte
    92  
    93  	// password is the password.
    94  	password string
    95  
    96  	// rootContext is the context for the root handle.
    97  	rootContext []byte
    98  
    99  	// quoteContext is the context for the quote key.
   100  	quoteContext []byte
   101  	quotePublic  []byte
   102  	quoteCert    []byte
   103  
   104  	// sealContext is a the context for sealing, held by the TPM.
   105  	sealContext []byte
   106  	sealPublic  []byte
   107  
   108  	// session context is used by seal.
   109  	sessionContext []byte
   110  
   111  	// verifier is a representation of the root that can be used to verify Attestations.
   112  	verifier *rsa.PublicKey
   113  
   114  	// pcrCount is the number of PCRs in the TPM.
   115  	// implementation fixes this at 24.
   116  	pcrCount uint32
   117  	pcrNums  []int
   118  	pcrVals  [][]byte
   119  	pcrs     []int
   120  
   121  	// The name of the TPM2Tao is tpm2(...K...) with extensions that represent the
   122  	// PCR values (and maybe someday the locality).
   123  	name auth.Prin
   124  
   125  	// The current TPM2Tao code uses only locality 0, so this value is never set.
   126  	locality byte
   127  
   128  	// tpm2 parameters
   129  	nvHandle   tpm2.Handle
   130  	authString string
   131  }
   132  
   133  // Loads keys from Blobs.
   134  func (tt *TPM2Tao) loadKeyFromBlobs(ownerHandle tpm2.Handle, ownerPw string,
   135  		objectPw string, publicBlob []byte,
   136  		privateBlob []byte) (tpm2.Handle, error) {
   137  	return tpm2.LoadKeyFromBlobs(tt.rw, ownerHandle, ownerPw, objectPw, publicBlob, privateBlob)
   138  }
   139  
   140  func (tt *TPM2Tao) loadRootContext() (tpm2.Handle, error) {
   141  	rh, err := tpm2.LoadContext(tt.rw, tt.rootContext)
   142  	if err != nil {
   143  		return tpm2.Handle(0), errors.New("Load Context fails for root")
   144  	}
   145  	return rh, nil
   146  }
   147  
   148  func (tt *TPM2Tao) loadQuoteContext() (tpm2.Handle, error) {
   149  	qh, err := tpm2.LoadContext(tt.rw, tt.quoteContext)
   150  	if err != nil {
   151  		return tpm2.Handle(0), errors.New("Load Context fails for quote")
   152  	}
   153  	return qh, nil
   154  }
   155  
   156  // IAH: does it build?
   157  func (tt *TPM2Tao) loadSealContext() (tpm2.Handle, error) {
   158  	sh, err := tpm2.LoadContext(tt.rw, tt.sealContext)
   159  	if err != nil {
   160  		return tpm2.Handle(0), errors.New("Load Context fails for root")
   161  	}
   162  	return sh, nil
   163  }
   164  
   165  func (tt *TPM2Tao) loadSessionContext() (tpm2.Handle, []byte, error) {
   166  	sh, digest, err := tpm2.AssistCreateSession(tt.rw,
   167  		tpm2.AlgTPM_ALG_SHA1, tt.pcrs)
   168  	if err != nil {
   169  		return tpm2.Handle(0), nil, err
   170  	}
   171  	return sh, digest, nil
   172  }
   173  
   174  func (tt *TPM2Tao) GetPcrNums() []int {
   175  	return tt.pcrs
   176  }
   177  
   178  // TODO(jlm): Fix this to provide quoteHandle quoteHandle
   179  // in structure should no longer be used.
   180  func (tt *TPM2Tao) GetRsaTPMKey(handle tpm2.Handle) (*rsa.PublicKey, error) {
   181  	return tpm2.GetRsaKeyFromHandle(tt.rw, handle)
   182  }
   183  
   184  func (tt *TPM2Tao) Rand() io.Reader {
   185  	return tt.rw
   186  }
   187  
   188  func ReadTPM2PCRs(rw io.ReadWriter, pcrNums []int) ([][]byte, error) {
   189  	fmt.Fprintf(os.Stderr, "Getting the PCRs\n")
   190  	pcrVals := make([][]byte, len(pcrNums))
   191  	for i, v := range pcrNums {
   192  		fmt.Fprintf(os.Stderr, "Working on iteration %d\n", i)
   193  		pcr, _ := tpm2.SetShortPcrs([]int{v})
   194  		fmt.Fprintf(os.Stderr, "set short pcr %v, returned %v\n", v, pcr)
   195  		_, _, _, pv, err := tpm2.ReadPcrs(rw, byte(4), pcr)
   196  		fmt.Fprintf(os.Stderr, "got PCR value % x\n", pv)
   197  		if err != nil {
   198  			return nil, err
   199  		}
   200  		pcrVals[i] = pv
   201  	}
   202  	return pcrVals, nil
   203  }
   204  
   205  func MakeTPM2Prin(verifier *rsa.PublicKey, pcrNums []int, pcrVals [][]byte) (auth.Prin, error) {
   206  	root, err := x509.MarshalPKIXPublicKey(verifier)
   207  	if err != nil {
   208  		return auth.Prin{}, err
   209  	}
   210  
   211  	name := auth.NewTPM2Prin(root)
   212  
   213  	asp := auth.PrinExt{
   214  		Name: "PCRs",
   215  		Arg:  make([]auth.Term, 2),
   216  	}
   217  	var pcrNumStrs []string
   218  	for _, v := range pcrNums {
   219  		pcrNumStrs = append(pcrNumStrs, strconv.Itoa(v))
   220  	}
   221  	asp.Arg[0] = auth.Str(strings.Join(pcrNumStrs, ","))
   222  
   223  	var pcrValStrs []string
   224  	for _, p := range pcrVals {
   225  		pcrValStrs = append(pcrValStrs, hex.EncodeToString(p))
   226  	}
   227  	asp.Arg[1] = auth.Str(strings.Join(pcrValStrs, ","))
   228  
   229  	// The PCRs are the first extension of the name.
   230  	name.Ext = []auth.PrinExt{asp}
   231  
   232  	return name, nil
   233  }
   234  
   235  // FinalizeTPM2Tao releases the resources for the TPM2Tao.
   236  func FinalizeTPM2Tao(tt *TPM2Tao) {
   237  	// Release the file handle.
   238  	tt.rw.Close()
   239  }
   240  
   241  // GetTaoName returns the Tao principal name assigned to the caller.
   242  func (tt *TPM2Tao) GetTaoName() (name auth.Prin, err error) {
   243  	return tt.name, nil
   244  }
   245  
   246  // ExtendTaoName irreversibly extends the Tao principal name of the caller.
   247  func (tt *TPM2Tao) ExtendTaoName(subprin auth.SubPrin) error {
   248  	tt.name = tt.name.MakeSubprincipal(subprin)
   249  	return nil
   250  }
   251  
   252  // GetRandomBytes returns a slice of n random bytes.
   253  func (tt *TPM2Tao) GetRandomBytes(n int) ([]byte, error) {
   254  	if n <= 0 {
   255  		return nil, errors.New("invalid number of requested random bytes")
   256  	}
   257  	return tpm2.GetRandom(tt.rw, uint32(n))
   258  }
   259  
   260  // ReadRandom implements io.Reader to read random bytes from the TPM2Tao.
   261  func (tt *TPM2Tao) ReadRandom(p []byte) (int, error) {
   262  	bytes, err := tt.GetRandomBytes(len(p))
   263  	if err != nil {
   264  		return 0, err
   265  	}
   266  
   267  	copy(p, bytes)
   268  	return len(p), nil
   269  }
   270  
   271  // GetSharedSecret returns a slice of n secret bytes.
   272  func (tt *TPM2Tao) GetSharedSecret(n int, policy string) (bytes []byte, err error) {
   273  	return nil, errors.New("the TPM2Tao does not implement GetSharedSecret")
   274  }
   275  
   276  // NewTPM2Tao creates a new TPM2Tao and returns it under the Tao interface.
   277  func NewTPM2Tao(tpmPath string, statePath string, pcrNums []int) (Tao, error) {
   278  	var err error
   279  	tt := &TPM2Tao{pcrCount: 24,
   280  		password: ""}
   281  
   282  	tt.rw, err = tpm2.OpenTPM(tpmPath)
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  	tpm2.Flushall(tt.rw)
   287  
   288  	// Make sure the TPM2Tao releases all its resources
   289  	runtime.SetFinalizer(tt, FinalizeTPM2Tao)
   290  
   291  	tt.pcrs = pcrNums
   292  	tt.path = statePath
   293  
   294  	keySize := uint16(2048)
   295  	quotePassword := ""
   296  
   297  	quoteKeyPrivateBlobFile := path.Join(tt.path, "quote_private_key_blob")
   298  	_, quotePrivateErr := os.Stat(quoteKeyPrivateBlobFile)
   299  	quoteKeyPublicBlobFile := path.Join(tt.path, "quote_public_key_blob")
   300  	_, quotePublicErr := os.Stat(quoteKeyPublicBlobFile)
   301  
   302  	sealKeyPrivateBlobFile := path.Join(tt.path, "seal_private_key_blob")
   303  	_, sealPrivateErr := os.Stat(sealKeyPrivateBlobFile)
   304  	sealKeyPublicBlobFile := path.Join(tt.path, "seal_public_key_blob")
   305  	_, sealPublicErr := os.Stat(sealKeyPublicBlobFile)
   306  
   307  	var quoteKeyPublicBlob []byte
   308  	var quoteKeyPrivateBlob []byte
   309  	var sealKeyPublicBlob []byte
   310  	var sealKeyPrivateBlob []byte
   311  
   312  	// Create the root key.
   313  	rootHandle, err := tpm2.CreateTpm2HierarchyRoot(tt.rw, tt.pcrs, keySize, uint16(tpm2.AlgTPM_ALG_SHA1))
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  	defer tpm2.FlushContext(tt.rw, rootHandle)
   318  
   319  	if quotePrivateErr != nil || sealPrivateErr != nil || quotePublicErr != nil || sealPublicErr != nil {
   320  		quoteKeyPublicBlob, quoteKeyPrivateBlob, sealKeyPublicBlob, sealKeyPrivateBlob, err =
   321  			tpm2.CreateTpm2HierarchySubKeys(tt.rw, tt.pcrs, keySize, uint16(tpm2.AlgTPM_ALG_SHA1),
   322  				rootHandle, quotePassword)
   323  		if err != nil {
   324  			return nil, err
   325  		}
   326  		// Save the blobs
   327  		err = ioutil.WriteFile(quoteKeyPrivateBlobFile, quoteKeyPrivateBlob, 0644)
   328  		if err != nil {
   329  			return nil, errors.New("Can't write quoteKeyPrivateBlobFile")
   330  		}
   331  		err = ioutil.WriteFile(quoteKeyPublicBlobFile, quoteKeyPublicBlob, 0644)
   332  		if err != nil {
   333  			return nil, errors.New("Can't write quoteKeyPublicBlobFile")
   334  		}
   335  		err = ioutil.WriteFile(sealKeyPrivateBlobFile, sealKeyPrivateBlob, 0644)
   336  		if err != nil {
   337  			return nil, errors.New("Can't write sealKeyPrivateBlobFile")
   338  		}
   339  		err = ioutil.WriteFile(sealKeyPublicBlobFile, sealKeyPublicBlob, 0644)
   340  		if err != nil {
   341  			return nil, errors.New("Can't write sealKeyPrivateBlobFile")
   342  		}
   343  	} else {
   344  		quoteKeyPrivateBlob, err = ioutil.ReadFile(quoteKeyPrivateBlobFile)
   345  		if err != nil {
   346  			return nil, fmt.Errorf("Could not read the quote key from %s: %v", quoteKeyPrivateBlobFile, err)
   347  		}
   348  		quoteKeyPublicBlob, err = ioutil.ReadFile(quoteKeyPublicBlobFile)
   349  		if err != nil {
   350  			return nil, fmt.Errorf("Could not read the quote key from %s: %v", quoteKeyPublicBlobFile, err)
   351  		}
   352  
   353  		sealKeyPrivateBlob, err = ioutil.ReadFile(sealKeyPrivateBlobFile)
   354  		if err != nil {
   355  			return nil, fmt.Errorf("Could not read the seal key from %s: %v", sealKeyPrivateBlobFile, err)
   356  		}
   357  		sealKeyPublicBlob, err = ioutil.ReadFile(sealKeyPublicBlobFile)
   358  		if err != nil {
   359  			return nil, fmt.Errorf("Could not read the seal key from %s: %v", sealKeyPublicBlobFile, err)
   360  		}
   361  	}
   362  
   363  	// Load the sub-keys.
   364  	quoteHandle, err := tt.loadKeyFromBlobs(rootHandle, "", quotePassword, quoteKeyPublicBlob, quoteKeyPrivateBlob)
   365  	if err != nil {
   366  		return nil, fmt.Errorf("Could not load quote keys from blobs %s", err)
   367  	}
   368  	defer tpm2.FlushContext(tt.rw, quoteHandle)
   369  	sealHandle, err := tt.loadKeyFromBlobs(rootHandle, "", quotePassword, sealKeyPublicBlob, sealKeyPrivateBlob)
   370  	if err != nil {
   371  		return nil, fmt.Errorf("Could not load seal key from blobs")
   372  	}
   373  	defer tpm2.FlushContext(tt.rw, sealHandle)
   374  
   375  	// Save the contexts for later.
   376  	tt.rootContext, err = tpm2.SaveContext(tt.rw, rootHandle)
   377  	if err != nil {
   378  		return nil, fmt.Errorf("Could not save the root context")
   379  	}
   380  	tt.quoteContext, err = tpm2.SaveContext(tt.rw, quoteHandle)
   381  	if err != nil {
   382  		return nil, fmt.Errorf("Could not save the quote context")
   383  	}
   384  	tt.sealContext, err = tpm2.SaveContext(tt.rw, sealHandle)
   385  	if err != nil {
   386  		return nil, fmt.Errorf("Could not save the seal context")
   387  	}
   388  
   389  	if tt.verifier, err = tpm2.GetRsaKeyFromHandle(tt.rw, quoteHandle); err != nil {
   390  		return nil, err
   391  	}
   392  
   393  	fmt.Fprintf(os.Stderr, "Loaded the handles and the verifier\n")
   394  
   395  	// Get the pcr values for the PCR nums.
   396  	tt.pcrNums = make([]int, len(pcrNums))
   397  	for i, v := range pcrNums {
   398  		tt.pcrNums[i] = v
   399  	}
   400  
   401  	tt.pcrVals, err = ReadTPM2PCRs(tt.rw, pcrNums)
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  
   406  	// Create principal.
   407  	tt.name, err = MakeTPM2Prin(tt.verifier, tt.pcrNums, tt.pcrVals)
   408  	if err != nil {
   409  		return nil, err
   410  	}
   411  
   412  	// kwonalbert: flushing to avoid occasional 902 error..
   413  	tpm2.FlushContext(tt.rw, rootHandle)
   414  
   415  	quoteCertPath := path.Join(tt.path, "quote_cert")
   416  	if _, quoteCertErr := os.Stat(quoteCertPath); quoteCertErr != nil {
   417  		tt.quoteCert, err = getQuoteCert(tt.rw, tt.path, quoteHandle, quotePassword, tt.name, tt.verifier)
   418  		if err != nil {
   419  			return nil, err
   420  		}
   421  		err = ioutil.WriteFile(quoteCertPath, tt.quoteCert, 0644)
   422  		if err != nil {
   423  			return nil, err
   424  		}
   425  	} else {
   426  		tt.quoteCert, err = ioutil.ReadFile(quoteCertPath)
   427  		if err != nil {
   428  			return nil, err
   429  		}
   430  	}
   431  	fmt.Fprintf(os.Stderr, "Got TPM 2.0 principal name %q\n", tt.name)
   432  	return tt, nil
   433  }
   434  
   435  // getActivateResponse gets encrypted cert from attest service.
   436  func getActivateResponse(filePath string, request tpm2.AttestCertRequest) (*tpm2.AttestCertResponse, error) {
   437  
   438  	// If the file filePath/service_location exists, use that address/port, otherwise use default.
   439  	network := "tcp"
   440  	address := "localhost:8121"
   441  	serviceFileName := path.Join(filePath, "service_location")
   442  	serviceInfo, err := ioutil.ReadFile(serviceFileName)
   443  	if err == nil {
   444  		address = string(serviceInfo)
   445  	}
   446  	if len(address) > 256 {
   447  		return nil, errors.New("Bad service address string")
   448  	}
   449  
   450  	conn, err := net.Dial(network, address)
   451  	if err != nil {
   452  		return nil, err
   453  	}
   454  	defer conn.Close()
   455  	ms := util.NewMessageStream(conn)
   456  	_, err = ms.WriteMessage(&request)
   457  	if err != nil {
   458  		return nil, err
   459  	}
   460  	var response tpm2.AttestCertResponse
   461  	err = ms.ReadMessage(&response)
   462  	if err != nil {
   463  		return nil, err
   464  	}
   465  	return &response, nil
   466  }
   467  
   468  // getQuoteCert requests and acquires a certificate for the quote key.
   469  // TODO(tmroeder): for now, this returns a dummy value for the cert.
   470  func getQuoteCert(rw io.ReadWriteCloser, filePath string, quoteHandle tpm2.Handle,
   471  	quotePassword string, name auth.Prin, verifier *rsa.PublicKey) ([]byte, error) {
   472  
   473  	// Generate Ek.
   474  	ekHandle, _, err := tpm2.CreateEndorsement(rw, 2048, []int{17, 18})
   475  	if err != nil {
   476  		return nil, fmt.Errorf("Could not open endorsement handle")
   477  	}
   478  	defer tpm2.FlushContext(rw, ekHandle)
   479  
   480  	// Get endorsement cert.
   481  	endorsementFile := path.Join(filePath, "endorsement_cert")
   482  	derEndorsementCert, err := ioutil.ReadFile(endorsementFile)
   483  	if err != nil {
   484  		return nil, fmt.Errorf("Could not read endorsement from %s: %v",
   485  			endorsementFile, err)
   486  	}
   487  
   488  	request, err := tpm2.BuildAttestCertRequest(rw, quoteHandle, ekHandle,
   489  		derEndorsementCert, name.String(), quotePassword)
   490  	if err != nil {
   491  		return nil, fmt.Errorf("Could not build cert request %v", err)
   492  	}
   493  
   494  	// Send request to attest service
   495  	response, err := getActivateResponse(filePath, *request)
   496  	if err != nil {
   497  		return nil, fmt.Errorf("Could not activate quote key %v", err)
   498  	}
   499  
   500  	if response == nil || response.Error == nil || *response.Error != 0 {
   501  		return nil, fmt.Errorf("AttestCertResponse is nil or has non-zero error")
   502  	}
   503  	// Recover cert.
   504  	quoteCert, err := tpm2.GetCertFromAttestResponse(rw, quoteHandle, ekHandle,
   505  		quotePassword, *response)
   506  	if err != nil {
   507  		return nil, fmt.Errorf("Could not get cert from AttestCertResponse %v", err)
   508  	}
   509  	return quoteCert, nil
   510  }
   511  
   512  // Attest requests the Tao host seal a statement on behalf of the caller. The
   513  // optional issuer, time and expiration will be given default values if nil.
   514  func (tt *TPM2Tao) Attest(issuer *auth.Prin, start, expiration *int64,
   515  	message auth.Form) (*Attestation, error) {
   516  	fmt.Fprintf(os.Stderr, "About to load the quote key in attest\n")
   517  	qh, err := tt.loadQuoteContext()
   518  	if err != nil {
   519  		return nil, err
   520  	}
   521  	defer tpm2.FlushContext(tt.rw, qh)
   522  
   523  	if issuer == nil {
   524  		issuer = &tt.name
   525  	} else if !auth.SubprinOrIdentical(*issuer, tt.name) {
   526  		return nil, errors.New("invalid issuer in statement")
   527  	}
   528  
   529  	// TODO(tmroeder): we assume here that the PCRs haven't changed (e.g., been
   530  	// extended) since this TPM2Tao was created. If they have, then the PCRs will
   531  	// be wrong when we extend the principal here with them as the first
   532  	// component. This doesn't matter at the moment, since we don't currently
   533  	// support extending the PCRs or clearing them, but it will need to be
   534  	// changed when we do.
   535  	stmt := auth.Says{
   536  		Speaker:    *issuer,
   537  		Time:       start,
   538  		Expiration: expiration,
   539  		Message:    message,
   540  	}
   541  
   542  	// This is done in GenerateAttestation, but the TPM attestation is sealed
   543  	// differently, so we do the time calculations here.
   544  	t := time.Now()
   545  	if stmt.Time == nil {
   546  		i := t.UnixNano()
   547  		stmt.Time = &i
   548  	}
   549  
   550  	if stmt.Expiration == nil {
   551  		i := t.Add(365 * 24 * time.Hour).UnixNano()
   552  		stmt.Expiration = &i
   553  	}
   554  
   555  	ser := auth.Marshal(stmt)
   556  
   557  	var pcrVals [][]byte
   558  	toQuote, err := tpm2.FormatTpm2Quote(ser, tt.pcrs, pcrVals)
   559  	if err != nil {
   560  		return nil, errors.New("Can't format tpm2 Quote")
   561  	}
   562  
   563  	// TODO(tmroeder): check the pcrVals for sanity once we support extending or
   564  	// clearing the PCRs.
   565  	quote_struct, sig, err := tpm2.Quote(tt.rw, qh, "", tt.password,
   566  		toQuote, tt.pcrs, uint16(tpm2.AlgTPM_ALG_NULL))
   567  	if err != nil {
   568  		return nil, err
   569  	}
   570  
   571  	quoteKey, err := x509.MarshalPKIXPublicKey(tt.verifier)
   572  	if err != nil {
   573  		return nil, err
   574  	}
   575  
   576  	// TODO(kwalsh) remove Tpm2QuoteStructure from Attestation structure
   577  	a := &Attestation{
   578  		SerializedStatement: ser,
   579  		Signature:           sig,
   580  		SignerType:          proto.String("tpm2"),
   581  		SignerKey:           quoteKey,
   582  		Tpm2QuoteStructure:  quote_struct,
   583  		RootEndorsement:     tt.quoteCert,
   584  	}
   585  
   586  	return a, nil
   587  }
   588  
   589  // Seal encrypts data so only certain hosted programs can unseal it. Note that
   590  // at least some TPMs can only seal up to 149 bytes of data. So, we employ a
   591  // hybrid encryption scheme that seals a key and uses the key to encrypt the
   592  // data separately. We use the keys infrastructure to perform secure and
   593  // flexible encryption.
   594  func (tt *TPM2Tao) Seal(data []byte, policy string) ([]byte, error) {
   595  	rh, err := tt.loadRootContext()
   596  	if err != nil {
   597  		return nil, err
   598  	}
   599  	defer tpm2.FlushContext(tt.rw, rh)
   600  
   601  	sk, policy_digest, err := tt.loadSessionContext()
   602  	if err != nil {
   603  		return nil, errors.New("Can't load root key")
   604  	}
   605  	defer tpm2.FlushContext(tt.rw, sk)
   606  
   607  	if policy != SealPolicyDefault {
   608  		return nil, errors.New("tpm-specific policies are not yet implemented")
   609  	}
   610  
   611  	keyName := "SealingKey"
   612  	keyEpoch := int32(1)
   613  	keyPurpose := "crypting"
   614  	keyStatus := "active"
   615  	keyType := CrypterTypeFromSuiteName(TaoCryptoSuite)
   616  	if keyType == nil {
   617  		return nil, errors.New("unsupported sealer crypter")
   618  	}
   619  	ck := GenerateCryptoKey(*keyType, &keyName, &keyEpoch, &keyPurpose, &keyStatus)
   620  	if ck == nil {
   621  		return nil, errors.New("Can't generate sealing key")
   622  	}
   623  	crypter := CrypterFromCryptoKey(*ck)
   624  	if crypter == nil {
   625  		return nil, errors.New("Can't get crypter from sealing key")
   626  	}
   627  	defer crypter.Clear()
   628  
   629  	c, err := crypter.Encrypt(data)
   630  	if err != nil {
   631  		return nil, err
   632  	}
   633  
   634  	ckb, err := proto.Marshal(ck)
   635  	if err != nil {
   636  		return nil, err
   637  	}
   638  	defer ZeroBytes(ckb)
   639  
   640  	priv, pub, err := tpm2.AssistSeal(tt.rw, rh, ckb,
   641  		"", tt.password, tt.pcrs, policy_digest)
   642  	if err != nil {
   643  		return nil, err
   644  	}
   645  
   646  	// encode pub and priv
   647  	s := EncodeTwoBytes(pub, priv)
   648  
   649  	h := &HybridSealedData{
   650  		SealedKey:     s,
   651  		EncryptedData: c,
   652  	}
   653  
   654  	return proto.Marshal(h)
   655  }
   656  
   657  // Unseal decrypts data that has been sealed by the Seal() operation, but only
   658  // if the policy specified during the Seal() operation is satisfied.
   659  func (tt *TPM2Tao) Unseal(sealed []byte) (data []byte, policy string, err error) {
   660  	rh, err := tt.loadRootContext()
   661  	if err != nil {
   662  		return nil, "", err
   663  	}
   664  	defer tpm2.FlushContext(tt.rw, rh)
   665  
   666  	sh, policy_digest, err := tt.loadSessionContext()
   667  	if err != nil {
   668  		return nil, "", errors.New("Can't load root key")
   669  	}
   670  	defer tpm2.FlushContext(tt.rw, sh)
   671  
   672  	// The sealed data is a HybridSealedData.
   673  	var h HybridSealedData
   674  	if err := proto.Unmarshal(sealed, &h); err != nil {
   675  		return nil, "", err
   676  	}
   677  
   678  	// Decode buffer containing pub and priv blobs
   679  	pub, priv := DecodeTwoBytes(h.SealedKey)
   680  	unsealed, _, err := tpm2.AssistUnseal(tt.rw, sh,
   681  		rh, pub, priv, "", tt.password, policy_digest)
   682  	if err != nil {
   683  		return nil, "", err
   684  	}
   685  	defer ZeroBytes(unsealed)
   686  
   687  	var ck CryptoKey
   688  	if err := proto.Unmarshal(unsealed, &ck); err != nil {
   689  		return nil, "", err
   690  	}
   691  	defer ck.Clear()
   692  
   693  	crypter := CrypterFromCryptoKey(ck)
   694  	if crypter == nil {
   695  		return nil, "", errors.New("Cant get crypter from crypto key")
   696  	}
   697  	defer crypter.Clear()
   698  
   699  	m, err := crypter.Decrypt(h.EncryptedData)
   700  	if err != nil {
   701  		return nil, "", err
   702  	}
   703  
   704  	return m, SealPolicyDefault, nil
   705  }
   706  
   707  func (s *TPM2Tao) InitCounter(label string, c int64) error {
   708  	fmt.Printf("TPM2Tao.InitCounter\n")
   709  	// TODO(jlm): Change this?
   710  	if uint32(s.nvHandle) != 0 {
   711  		return nil
   712  	}
   713  	// TODO: make this more general?
   714  	var err error
   715  	s.nvHandle, err = tpm2.GetNvHandle(1000)
   716  	if err != nil {
   717  		return err
   718  	}
   719  	s.authString = "01020304"
   720  
   721  	return tpm2.InitCounter(s.rw, s.nvHandle, s.authString)
   722  }
   723  
   724  func (s *TPM2Tao) GetCounter(label string) (int64, error) {
   725  	fmt.Printf("TPM2Tao.GetCounter\n")
   726  	err := s.InitCounter(label, int64(0))
   727  	if err != nil {
   728  		return int64(0), err
   729  	}
   730  	return tpm2.GetCounter(s.rw, s.nvHandle, s.authString)
   731  }
   732  
   733  // Note:  Tpm2 counters work differently from other counters.  On startup, you
   734  // can't read a counter value before you initialize it which you do by incrementing
   735  // it.  What we do is use the (countvalue+1)/2 as the counter in RollbackSeal and Unseal.
   736  // When you seal, // if the current counter is odd, you bump it twice and use the
   737  // value (countvalue+1)/2 in the counter slot.  If the counter is even, you bump by 1.
   738  // You also need to reseal the tpm keys when you startup since you may shutdown
   739  // before a RollbackSeal and your key will bump by two and give the wrong counter value.
   740  // Programmers need to know that the value returned by GetCounter is thus different from
   741  // the value in the sealed Rollback blob.
   742  
   743  func (s *TPM2Tao) RollbackProtectedSeal(label string, data []byte, policy string) ([]byte, error) {
   744  	_ = s.InitCounter(label, int64(0))
   745  	c, err := tpm2.GetCounter(s.rw, s.nvHandle, s.authString)
   746  	if err != nil {
   747  		return nil, err
   748  	}
   749  	err = tpm2.IncrementNv(s.rw, s.nvHandle, s.authString)
   750  	if err != nil {
   751  		return nil, err
   752  	}
   753  	if (c % 2) != 0 {
   754  		err = tpm2.IncrementNv(s.rw, s.nvHandle, s.authString)
   755  		if err != nil {
   756  			return nil, err
   757  		}
   758  	}
   759  	c, err = tpm2.GetCounter(s.rw, s.nvHandle, s.authString)
   760  	if err != nil {
   761  		return nil, err
   762  	}
   763  	cmp_ctr := (c + 1) / 2
   764  	sd := new(RollbackSealedData)
   765  	sd.Entry = new(RollbackEntry)
   766  	programName := s.name.String()
   767  	sd.Entry.HostedProgramName = &programName
   768  	sd.Entry.EntryLabel = &label
   769  	sd.Entry.Counter = &cmp_ctr
   770  	sd.ProtectedData = data
   771  	toSeal, err := proto.Marshal(sd)
   772  	if err != nil {
   773  		return nil, errors.New("Can't marshal tpm2 rollback data")
   774  	}
   775  	sealed, err := s.Seal(toSeal, policy)
   776  	return sealed, err
   777  }
   778  
   779  func (s *TPM2Tao) RollbackProtectedUnseal(sealed []byte) ([]byte, string, error) {
   780  	_ = s.InitCounter("", int64(0))
   781  	unsealed, policy, err := s.Unseal(sealed)
   782  	if err != nil {
   783  		return nil, policy, err
   784  	}
   785  	c, err := tpm2.GetCounter(s.rw, s.nvHandle, s.authString)
   786  	if err != nil {
   787  		return nil, policy, err
   788  	}
   789  	cmp_ctr := (c + 1) / 2
   790  	var sd RollbackSealedData
   791  	err = proto.Unmarshal(unsealed, &sd)
   792  	if err != nil {
   793  		return nil, policy, err
   794  	}
   795  	if sd.Entry == nil || sd.Entry.Counter == nil || *sd.Entry.Counter != cmp_ctr {
   796  		return nil, policy, errors.New("tpm2tao.RollbackProtectedUnseal bad counter")
   797  	}
   798  	return sd.ProtectedData, policy, nil
   799  }
   800  
   801  // extractPCRs gets the PCRs from a tpm principal.
   802  func extractTpm2PCRs(p auth.Prin) ([]int, []byte, error) {
   803  	if p.Type != "tpm2" {
   804  		return nil, nil, errors.New("can only extract PCRs from a TPM principal")
   805  	}
   806  
   807  	// The PCRs are stored as the first subprincipal value, with name "PCRs".
   808  	if len(p.Ext) == 0 {
   809  		return nil, nil, errors.New("no subprincipals available for PCR extraction")
   810  	}
   811  
   812  	if p.Ext[0].Name != "PCRs" {
   813  		return nil, nil, errors.New("the first subprincipal must have Name 'PCRs' for PCR extraction to work")
   814  	}
   815  
   816  	sp := p.Ext[0]
   817  	if len(sp.Arg) != 2 {
   818  		return nil, nil, errors.New("the PCRs subprincipal must have exactly two arguments")
   819  	}
   820  
   821  	// auth.Str is exactly a string.
   822  	arg0, ok0 := sp.Arg[0].(auth.Str)
   823  	arg1, ok1 := sp.Arg[1].(auth.Str)
   824  	if !ok0 || !ok1 {
   825  		return nil, nil, errors.New("both Terms in the PCRs subprincipal must be strings")
   826  	}
   827  
   828  	nums := strings.Split(string(arg0), ",")
   829  	vals := strings.Split(string(arg1), ",")
   830  	if len(nums) != len(vals) {
   831  		return nil, nil, errors.New("mismatched count between PCR nums and vals")
   832  	}
   833  
   834  	pcrNums := make([]int, len(nums))
   835  	var pcrVals []byte
   836  	for i, v := range nums {
   837  		n, err := strconv.ParseInt(v, 10, 16)
   838  		if err != nil {
   839  			return nil, nil, err
   840  		}
   841  		pcrNums[i] = int(n)
   842  
   843  		b, err := hex.DecodeString(vals[i])
   844  		if err != nil {
   845  			return nil, nil, err
   846  		}
   847  		pcrVals = append(pcrVals, b...)
   848  	}
   849  	return pcrNums, pcrVals, nil
   850  }
   851  
   852  // extractTPM2Key gets an RSA public key from the TPM key material.
   853  func extractTPM2Key(material []byte) (*rsa.PublicKey, error) {
   854  	return extractTPMKey(material) // same key format as TPM 1.2
   855  }
   856  
   857  // Input: Der encoded endorsement cert and handles
   858  // quote key is certified key unlike in the tpm2.go library
   859  // Returns ProgramCertRequestMessage
   860  func Tpm2ConstructClientRequest(rw io.ReadWriter, derEkCert []byte, pcrs []int,
   861  	qh tpm2.Handle, parentPassword string, ownerPassword string,
   862  	keyName string) (*tpm2.ProgramCertRequestMessage, error) {
   863  
   864  	// Generate Request
   865  	request := new(tpm2.ProgramCertRequestMessage)
   866  	request.ProgramKey = new(tpm2.ProgramKeyParameters)
   867  	request.EndorsementCertBlob = derEkCert
   868  	req_id := "001"
   869  	request.RequestId = &req_id
   870  
   871  	// Quote key
   872  	keyBlob, tpm2QuoteName, _, err := tpm2.ReadPublic(rw, qh)
   873  	if err != nil {
   874  		return nil, err
   875  	}
   876  	rsaQuoteParams, err := tpm2.DecodeRsaBuf(keyBlob)
   877  	if err != nil {
   878  		return nil, err
   879  	}
   880  
   881  	modSize := int32(rsaQuoteParams.Mod_sz)
   882  
   883  	keyType := "rsa"
   884  	request.ProgramKey.ProgramName = &keyName
   885  	request.ProgramKey.ProgramKeyType = &keyType
   886  	request.ProgramKey.ProgramBitModulusSize = &modSize
   887  
   888  	request.ProgramKey.ProgramKeyExponent = []byte{0, 1, 0, 1}
   889  	request.ProgramKey.ProgramKeyModulus = rsaQuoteParams.Modulus
   890  	serializedProgramKey := proto.CompactTextString(request.ProgramKey)
   891  	sha1Hash := sha1.New()
   892  	sha1Hash.Write([]byte(serializedProgramKey))
   893  	hashProgramKey := sha1Hash.Sum(nil)
   894  
   895  	sigAlg := uint16(tpm2.AlgTPM_ALG_NULL)
   896  	attest, sig, err := tpm2.Quote(rw, qh, parentPassword, ownerPassword,
   897  		hashProgramKey, pcrs, sigAlg)
   898  	if err != nil {
   899  		return nil, err
   900  	}
   901  
   902  	// Quote key info.
   903  	request.QuoteKeyInfo = new(tpm2.QuoteKeyInfoMessage)
   904  	request.QuoteKeyInfo.Name = tpm2QuoteName
   905  	request.QuoteKeyInfo.PublicKey = new(tpm2.PublicKeyMessage)
   906  	request.QuoteKeyInfo.PublicKey.RsaKey = new(tpm2.RsaPublicKeyMessage)
   907  	request.QuoteKeyInfo.PublicKey.RsaKey.KeyName = &keyName
   908  
   909  	var encAlg string
   910  	var hashAlg string
   911  	if rsaQuoteParams.Enc_alg == tpm2.AlgTPM_ALG_RSA {
   912  		encAlg = "rsa"
   913  	} else {
   914  		return nil, err
   915  	}
   916  	if rsaQuoteParams.Hash_alg == tpm2.AlgTPM_ALG_SHA1 {
   917  		hashAlg = "sha1"
   918  	} else if rsaQuoteParams.Hash_alg == tpm2.AlgTPM_ALG_SHA256 {
   919  		hashAlg = "sha256"
   920  	} else {
   921  		return nil, err
   922  	}
   923  	request.QuoteKeyInfo.PublicKey.KeyType = &encAlg
   924  	request.QuoteKeyInfo.PublicKey.RsaKey.BitModulusSize = &modSize
   925  	request.QuoteKeyInfo.PublicKey.RsaKey.Modulus = rsaQuoteParams.Modulus
   926  	request.QuoteSignAlg = &encAlg
   927  	request.QuoteSignHashAlg = &hashAlg
   928  
   929  	request.ProgramKey = new(tpm2.ProgramKeyParameters)
   930  	request.ProgramKey.ProgramName = &keyName
   931  	request.ProgramKey.ProgramKeyType = &encAlg
   932  	request.ProgramKey.ProgramBitModulusSize = &modSize
   933  	request.ProgramKey.ProgramKeyModulus = rsaQuoteParams.Modulus
   934  
   935  	request.QuotedBlob = attest
   936  	request.QuoteSignature = sig
   937  	return request, nil
   938  }
   939  
   940  // Output is der encoded Program Cert
   941  func Tpm2ClientDecodeServerResponse(rw io.ReadWriter,
   942  	protectorHandle tpm2.Handle,
   943  	quoteHandle tpm2.Handle, password string,
   944  	response tpm2.ProgramCertResponseMessage) ([]byte, error) {
   945  	certBlob := append(response.IntegrityHMAC, response.EncIdentity...)
   946  	certInfo, err := tpm2.ActivateCredential(rw, quoteHandle,
   947  		protectorHandle, password, "", certBlob, response.Secret)
   948  	if err != nil {
   949  		return nil, err
   950  	}
   951  
   952  	// Decrypt cert.
   953  	_, out, err := tpm2.EncryptDataWithCredential(false,
   954  		uint16(tpm2.AlgTPM_ALG_SHA1),
   955  		certInfo, response.EncryptedCert, response.EncryptedCertHmac)
   956  	if err != nil {
   957  		return nil, err
   958  	}
   959  	return out, nil
   960  }
   961  
   962  // Return attest certificate
   963  func (tt *TPM2Tao) Tpm2Certify(network, addr string, keyName string) ([]byte, error) {
   964  	// Establish connection wtih the CA.
   965  	conn, err := net.Dial(network, addr)
   966  	if err != nil {
   967  		return nil, err
   968  	}
   969  	defer conn.Close()
   970  
   971  	rk, err := tt.loadRootContext()
   972  	if err != nil {
   973  		return nil, err
   974  	}
   975  	defer tpm2.FlushContext(tt.rw, rk)
   976  
   977  	qh, err := tt.loadQuoteContext()
   978  	if err != nil {
   979  		return nil, err
   980  	}
   981  	defer tpm2.FlushContext(tt.rw, qh)
   982  
   983  	ms := util.NewMessageStream(conn)
   984  	programCertMessage, err := Tpm2ConstructClientRequest(tt.rw,
   985  		tt.rootCert, tt.pcrs,
   986  		qh, "", tt.password, keyName)
   987  	_, err = ms.WriteMessage(programCertMessage)
   988  	if err != nil {
   989  		return nil, err
   990  	}
   991  
   992  	var resp tpm2.ProgramCertResponseMessage
   993  	err = ms.ReadMessage(&resp)
   994  	if err != nil {
   995  		return nil, err
   996  	}
   997  	attestCert, err := Tpm2ClientDecodeServerResponse(tt.rw, rk, qh,
   998  		tt.password, resp)
   999  	return attestCert, nil
  1000  }