Example #1
0
// Seal encrypts data so only certain hosted programs can unseal it. Note that
// at least some TPMs can only seal up to 149 bytes of data. So, we employ a
// hybrid encryption scheme that seals a key and uses the key to encrypt the
// data separately. We use the keys infrastructure to perform secure and
// flexible encryption.
func (tt *TPM2Tao) Seal(data []byte, policy string) ([]byte, error) {
	rh, err := tt.loadRoot()
	if err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, rh)

	sk, policy_digest, err := tt.loadSession()
	if err != nil {
		return nil, errors.New("Can't load root key")
	}
	defer tpm2.FlushContext(tt.rw, sk)

	if policy != SealPolicyDefault {
		return nil, errors.New("tpm-specific policies are not yet implemented")
	}

	crypter, err := GenerateCrypter()
	if err != nil {
		return nil, err
	}
	defer ZeroBytes(crypter.aesKey)
	defer ZeroBytes(crypter.hmacKey)

	c, err := crypter.Encrypt(data)
	if err != nil {
		return nil, err
	}

	ck, err := MarshalCrypterProto(crypter)
	if err != nil {
		return nil, err
	}
	defer ZeroBytes(ck.Key)

	ckb, err := proto.Marshal(ck)
	if err != nil {
		return nil, err
	}
	defer ZeroBytes(ckb)

	priv, pub, err := tpm2.AssistSeal(tt.rw, rh, ckb,
		"", tt.password, tt.pcrs, policy_digest)
	if err != nil {
		return nil, err
	}

	// encode pub and priv
	s := EncodeTwoBytes(pub, priv)

	h := &HybridSealedData{
		SealedKey:     s,
		EncryptedData: c,
	}

	return proto.Marshal(h)
}
Example #2
0
// Unseal decrypts data that has been sealed by the Seal() operation, but only
// if the policy specified during the Seal() operation is satisfied.
func (tt *TPM2Tao) Unseal(sealed []byte) (data []byte, policy string, err error) {
	rh, err := tt.loadRoot()
	if err != nil {
		return nil, "", err
	}
	defer tpm2.FlushContext(tt.rw, rh)

	sh, policy_digest, err := tt.loadSession()
	if err != nil {
		return nil, "", errors.New("Can't load root key")
	}
	defer tpm2.FlushContext(tt.rw, sh)

	// The sealed data is a HybridSealedData.
	var h HybridSealedData
	if err := proto.Unmarshal(sealed, &h); err != nil {
		return nil, "", err
	}

	// Decode buffer containing pub and priv blobs
	pub, priv := DecodeTwoBytes(h.SealedKey)
	unsealed, _, err := tpm2.AssistUnseal(tt.rw, sh,
		rh, pub, priv, "", tt.password, policy_digest)
	if err != nil {
		return nil, "", err
	}
	defer ZeroBytes(unsealed)

	var ck CryptoKey
	if err := proto.Unmarshal(unsealed, &ck); err != nil {
		return nil, "", err
	}
	defer ZeroBytes(ck.Key)

	crypter, err := UnmarshalCrypterProto(&ck)
	if err != nil {
		return nil, "", err
	}
	defer ZeroBytes(crypter.aesKey)
	defer ZeroBytes(crypter.hmacKey)

	m, err := crypter.Decrypt(h.EncryptedData)
	if err != nil {
		return nil, "", err
	}

	return m, SealPolicyDefault, nil
}
Example #3
0
// FinalizeTPM2Tao releases the resources for the TPM2Tao.
func FinalizeTPM2Tao(tt *TPM2Tao) {
	if tt.sessionHandle != 0 {
		tpm2.FlushContext(tt.rw, tpm2.Handle(tt.sessionHandle))
	}
	tt.sessionHandle = 0
	if tt.rootHandle != 0 {
		tpm2.FlushContext(tt.rw, tpm2.Handle(tt.rootHandle))
	}
	tt.rootHandle = 0
	if tt.sealHandle != 0 {
		tpm2.FlushContext(tt.rw, tpm2.Handle(tt.sealHandle))
	}
	tt.sealHandle = 0

	// Release the file handle.
	tt.rw.Close()
}
Example #4
0
// Return attest certificate
func (tt *TPM2Tao) Tpm2Certify(network, addr string, keyName string) ([]byte, error) {
	// Establish connection wtih the CA.
	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	rk, err := tt.loadRoot()
	if err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, rk)

	qh, err := tt.loadQuote()
	if err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, qh)

	ms := util.NewMessageStream(conn)
	programCertMessage, err := Tpm2ConstructClientRequest(tt.rw,
		tt.rootCert, tt.pcrs,
		qh, "", tt.password, keyName)
	_, err = ms.WriteMessage(programCertMessage)
	if err != nil {
		return nil, err
	}

	var resp tpm2.ProgramCertResponseMessage
	err = ms.ReadMessage(&resp)
	if err != nil {
		return nil, err
	}
	attestCert, err := Tpm2ClientDecodeServerResponse(tt.rw, rk, qh,
		tt.password, resp)
	return attestCert, nil
}
Example #5
0
// Attest requests the Tao host seal a statement on behalf of the caller. The
// optional issuer, time and expiration will be given default values if nil.
func (tt *TPM2Tao) Attest(issuer *auth.Prin, start, expiration *int64,
	message auth.Form) (*Attestation, error) {
	fmt.Fprintf(os.Stderr, "About to load the quote key in attest\n")
	qh, err := tt.loadQuote()
	if err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, qh)

	if issuer == nil {
		issuer = &tt.name
	} else if !auth.SubprinOrIdentical(*issuer, tt.name) {
		return nil, errors.New("invalid issuer in statement")
	}

	// TODO(tmroeder): we assume here that the PCRs haven't changed (e.g., been
	// extended) since this TPM2Tao was created. If they have, then the PCRs will
	// be wrong when we extend the principal here with them as the first
	// component. This doesn't matter at the moment, since we don't currently
	// support extending the PCRs or clearing them, but it will need to be
	// changed when we do.
	stmt := auth.Says{
		Speaker:    *issuer,
		Time:       start,
		Expiration: expiration,
		Message:    message,
	}

	// This is done in GenerateAttestation, but the TPM attestation is sealed
	// differently, so we do the time calculations here.
	t := time.Now()
	if stmt.Time == nil {
		i := t.UnixNano()
		stmt.Time = &i
	}

	if stmt.Expiration == nil {
		i := t.Add(365 * 24 * time.Hour).UnixNano()
		stmt.Expiration = &i
	}

	ser := auth.Marshal(stmt)

	var pcrVals [][]byte
	toQuote, err := tpm2.FormatTpm2Quote(ser, tt.pcrs, pcrVals)
	if err != nil {
		return nil, errors.New("Can't format tpm2 Quote")
	}

	// TODO(tmroeder): check the pcrVals for sanity once we support extending or
	// clearing the PCRs.
	quote_struct, sig, err := tpm2.Quote(tt.rw, qh, "", tt.password,
		toQuote, tt.pcrs, uint16(tpm2.AlgTPM_ALG_NULL))
	if err != nil {
		return nil, err
	}
	fmt.Printf("toQuote: %x\n", toQuote)
	fmt.Printf("Quote: %x\n", quote_struct)
	fmt.Printf("sig: %x\n", sig)

	quoteKey, err := x509.MarshalPKIXPublicKey(tt.verifier)
	if err != nil {
		return nil, err
	}

	// TODO(kwalsh) remove Tpm2QuoteStructure from Attestation structure
	a := &Attestation{
		SerializedStatement: ser,
		Signature:           sig,
		SignerType:          proto.String("tpm2"),
		SignerKey:           quoteKey,
		Tpm2QuoteStructure:  quote_struct,
	}

	return a, nil
}
Example #6
0
// NewTPM2Tao creates a new TPM2Tao and returns it under the Tao interface.
func NewTPM2Tao(tpmPath string, statePath string, pcrNums []int) (Tao, error) {
	var err error
	tt := &TPM2Tao{pcrCount: 24,
		password: ""}

	tt.rw, err = tpm2.OpenTPM(tpmPath)
	if err != nil {
		return nil, err
	}

	// Make sure the TPM2Tao releases all its resources
	runtime.SetFinalizer(tt, FinalizeTPM2Tao)

	tt.pcrs = pcrNums
	tt.path = statePath

	// Create the root key.
	keySize := uint16(2048)
	quotePassword := ""
	//var empty []byte

	rootSaveContext := path.Join(tt.path, "root_context")
	_, rootErr := os.Stat(rootSaveContext)

	quoteSaveContext := path.Join(tt.path, "quote_context")
	_, quoteErr := os.Stat(quoteSaveContext)

	sealSaveContext := path.Join(tt.path, "seal_context")
	_, sealErr := os.Stat(sealSaveContext)

	if rootErr != nil || quoteErr != nil || sealErr != nil {
		if err := tpm2.InitTpm2Keys(tt.rw, tt.pcrs, keySize, uint16(tpm2.AlgTPM_ALG_SHA1), quotePassword, rootSaveContext, quoteSaveContext, sealSaveContext); err != nil {
			return nil, err
		}
	}

	// Read the contexts and public info and use them to load the handles.
	if tt.rootContext, err = ioutil.ReadFile(rootSaveContext); err != nil {
		return nil, fmt.Errorf("Could not read the root context from %s: %v", rootSaveContext, err)
	}

	if tt.quoteContext, err = ioutil.ReadFile(quoteSaveContext); err != nil {
		return nil, fmt.Errorf("Could not read the quote context from %s: %v", quoteSaveContext, err)
	}

	if tt.sealContext, err = ioutil.ReadFile(sealSaveContext); err != nil {
		return nil, fmt.Errorf("Could not read the seal context from %s: %v", sealSaveContext, err)
	}

	if tt.quoteHandle, err = tt.loadQuote(); err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, tt.quoteHandle)

	if tt.verifier, err = tpm2.GetRsaKeyFromHandle(tt.rw, tt.quoteHandle); err != nil {
		return nil, err
	}

	fmt.Fprintf(os.Stderr, "Loaded the handles and the verifier\n")

	// Get the pcr values for the PCR nums.
	tt.pcrNums = make([]int, len(pcrNums))
	for i, v := range pcrNums {
		tt.pcrNums[i] = v
	}

	tt.pcrVals, err = ReadTPM2PCRs(tt.rw, pcrNums)
	if err != nil {
		return nil, err
	}

	// Create principal.
	tt.name, err = MakeTPM2Prin(tt.verifier, tt.pcrNums, tt.pcrVals)
	if err != nil {
		return nil, err
	}

	quoteCertPath := path.Join(tt.path, "quote_cert")
	if _, quoteCertErr := os.Stat(quoteCertPath); quoteCertErr != nil {
		tt.quoteCert, err = getQuoteCert(tt.rw, tt.path, tt.quoteHandle,
			quotePassword, tt.name, tt.verifier)
		if err != nil {
			return nil, err
		}

		if err := ioutil.WriteFile(quoteCertPath, tt.quoteCert, 0644); err != nil {
			return nil, err
		}
	} else {
		if tt.quoteCert, err = ioutil.ReadFile(quoteCertPath); err != nil {
			return nil, err
		}
	}
	fmt.Fprintf(os.Stderr, "Got TPM 2.0 principal name %q\n", tt.name)

	return tt, nil
}
// This program makes the endorsement certificate given the Policy key.
func main() {
	keySize := flag.Int("modulus size", 2048, "Modulus size for keys")
	keyName := flag.String("Endorsement key name",
		"JohnsHw", "endorsement key name")
	endorsementCertFile := flag.String("Endorsement save file",
		"endorsement.cert.der", "endorsement save file")
	policyCertFile := flag.String("Policy cert file",
		"policy.cert.go.der", "cert file")
	policyKeyFile := flag.String("Policy key file", "policy.go.bin",
		"policy save file")
	policyKeyPassword := flag.String("Policy key password", "xxzzy",
		"policy key password")
	flag.Parse()
	fmt.Printf("Policy key password: %s\n", *policyKeyPassword)

	// TODO
	pcrs := []int{7}

	// Open tpm
	rw, err := tpm2.OpenTPM("/dev/tpm0")
	if err != nil {
		fmt.Printf("OpenTPM failed %s\n", err)
		return
	}
	defer rw.Close()

	// Flushall
	err = tpm2.Flushall(rw)
	if err != nil {
		fmt.Printf("Flushall failed\n")
		return
	}

	var notBefore time.Time
	notBefore = time.Now()
	validFor := 365 * 24 * time.Hour
	notAfter := notBefore.Add(validFor)

	serializePolicyKey, err := ioutil.ReadFile(*policyKeyFile)
	if err != nil {
		fmt.Printf("Can't get serialized policy key\n")
		return
	}
	derPolicyCert, err := ioutil.ReadFile(*policyCertFile)
	if err != nil {
		fmt.Printf("Can't get policy cert %s\n", *policyCertFile)
		return
	}

	policyKey, err := tpm2.DeserializeRsaKey(serializePolicyKey)
	if err != nil {
		fmt.Printf("Can't get deserialize policy key\n")
		return
	}

	ekHandle, _, err := tpm2.CreateEndorsement(rw, uint16(*keySize), pcrs)
	if err != nil {
		fmt.Printf("Can't CreateEndorsement\n")
		return
	}
	defer tpm2.FlushContext(rw, ekHandle)
	endorsementCert, err := tpm2.GenerateHWCert(rw, ekHandle,
		*keyName, notBefore, notAfter, tpm2.GetSerialNumber(),
		derPolicyCert, policyKey)
	if err != nil {
		fmt.Printf("Can't create endorsement cert\n")
	}
	fmt.Printf("Endorsement cert: %x\n", endorsementCert)
	ioutil.WriteFile(*endorsementCertFile, endorsementCert, 0644)
	fmt.Printf("Endorsement cert created")
}