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 }