github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/tpm_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 "crypto/rsa" 19 "crypto/x509" 20 "encoding/hex" 21 "errors" 22 "io" 23 "os" 24 "runtime" 25 "strconv" 26 "strings" 27 "time" 28 29 "github.com/golang/protobuf/proto" 30 "github.com/google/go-tpm/tpm" 31 "github.com/jlmucb/cloudproxy/go/tao/auth" 32 ) 33 34 // A TPMTao implements the Tao using a hardware TPM device. 35 type TPMTao struct { 36 // tpmfile is the file through which TPMTao communicates with the TPM. E.g., 37 // on Linux, this is usually /dev/tpm0. 38 tpmfile *os.File 39 40 // srkAuth is the authenticator for the SRK. In most simple cases, it's 20 41 // bytes of zeros. That value is called the "well-known authentictor" 42 srkAuth [20]byte 43 44 // aikHandle is an integer handle for an AIK held by the TPM. This key is 45 // used for creating Quote values from the TPM. 46 aikHandle tpm.Handle 47 48 // verifier is a representation of the AIK that can be used to verify Quote 49 // and Quote2 attestations. 50 verifier *rsa.PublicKey 51 52 // DER encoded endorsement certificate for the AIK 53 aikCert []byte 54 55 // pcrCount is the number of PCRs in the TPM. The current go-tpm 56 // implementation fixes this at 24. 57 pcrCount uint32 58 pcrNums []int 59 pcrVals [][]byte 60 61 // The name of the TPMTao is tpm(...K...) with extensions that represent the 62 // PCR values (and maybe someday the locality). 63 name auth.Prin 64 65 // The current TPMTao code uses only locality 0, so this value is never set. 66 locality byte 67 } 68 69 // NewTPMTao creates a new TPMTao and returns it under the Tao interface. 70 func NewTPMTao(tpmPath string, aikblob []byte, pcrNums []int, aikCert []byte) (Tao, error) { 71 var err error 72 tt := &TPMTao{pcrCount: 24} 73 tt.tpmfile, err = os.OpenFile(tpmPath, os.O_RDWR, 0) 74 if err != nil { 75 return nil, err 76 } 77 78 // Make sure the TPMTao releases all its resources 79 runtime.SetFinalizer(tt, FinalizeTPMTao) 80 81 // For now, the SRK Auth value is all zero, which is the well-known value. 82 // So, we don't set it here. 83 // TODO(tmroeder): add support for general SRK auth values. 84 85 // TODO(tmroeder): the current tpm implementation in go-tpm assumes 24 PCRs. 86 // This is not true in general, and it should be generalized there then 87 // changed here. 88 tt.aikHandle, err = tpm.LoadKey2(tt.tpmfile, aikblob, tt.srkAuth[:]) 89 if err != nil { 90 return nil, err 91 } 92 93 tt.verifier, err = tpm.UnmarshalRSAPublicKey(aikblob) 94 if err != nil { 95 return nil, err 96 } 97 98 tt.aikCert = aikCert 99 100 // Get the pcr values for the PCR nums. 101 tt.pcrNums = make([]int, len(pcrNums)) 102 for i, v := range pcrNums { 103 tt.pcrNums[i] = v 104 } 105 106 tt.pcrVals, err = ReadPCRs(tt.tpmfile, pcrNums) 107 if err != nil { 108 return nil, err 109 } 110 111 // Create principal. 112 tt.name, err = MakeTPMPrin(tt.verifier, tt.pcrNums, tt.pcrVals) 113 if err != nil { 114 return nil, err 115 } 116 117 return tt, nil 118 } 119 120 // FinalizeTPMTao releases the resources for the TPMTao. 121 func FinalizeTPMTao(tt *TPMTao) { 122 // Flush the AIK. 123 tt.aikHandle.CloseKey(tt.tpmfile) 124 125 // Release the file handle. 126 tt.tpmfile.Close() 127 } 128 129 // GetTaoName returns the Tao principal name assigned to the caller. 130 func (tt *TPMTao) GetTaoName() (name auth.Prin, err error) { 131 return tt.name, nil 132 } 133 134 // ExtendTaoName irreversibly extends the Tao principal name of the caller. 135 func (tt *TPMTao) ExtendTaoName(subprin auth.SubPrin) error { 136 tt.name = tt.name.MakeSubprincipal(subprin) 137 return nil 138 } 139 140 // GetRandomBytes returns a slice of n random bytes. 141 func (tt *TPMTao) GetRandomBytes(n int) ([]byte, error) { 142 if n <= 0 { 143 return nil, errors.New("invalid number of requested random bytes") 144 } 145 return tpm.GetRandom(tt.tpmfile, uint32(n)) 146 } 147 148 // Read implements io.Reader to read random bytes from the TPMTao. 149 func (tt *TPMTao) Read(p []byte) (int, error) { 150 bytes, err := tt.GetRandomBytes(len(p)) 151 if err != nil { 152 return 0, err 153 } 154 155 copy(p, bytes) 156 return len(p), nil 157 } 158 159 // Rand produces an io.Reader for random bytes from this Tao. 160 func (tt *TPMTao) Rand() io.Reader { 161 return tt 162 } 163 164 // GetSharedSecret returns a slice of n secret bytes. 165 func (tt *TPMTao) GetSharedSecret(n int, policy string) (bytes []byte, err error) { 166 return nil, errors.New("the TPMTao does not implement GetSharedSecret") 167 } 168 169 // Attest requests the Tao host sign a statement on behalf of the caller. The 170 // optional issuer, time and expiration will be given default values if nil. 171 func (tt *TPMTao) Attest(issuer *auth.Prin, start, expiration *int64, message auth.Form) (*Attestation, error) { 172 if issuer == nil { 173 issuer = &tt.name 174 } else if !auth.SubprinOrIdentical(*issuer, tt.name) { 175 return nil, errors.New("invalid issuer in statement") 176 } 177 178 // TODO(tmroeder): we assume here that the PCRs haven't changed (e.g., been 179 // extended) since this TPMTao was created. If they have, then the PCRs will 180 // be wrong when we extend the principal here with them as the first 181 // component. This doesn't matter at the moment, since we don't currently 182 // support extending the PCRs or clearing them, but it will need to be 183 // changed when we do. 184 stmt := auth.Says{ 185 Speaker: *issuer, 186 Time: start, 187 Expiration: expiration, 188 Message: message, 189 } 190 191 // This is done in GenerateAttestation, but the TPM attestation is signed 192 // differently, so we do the time calculations here. 193 t := time.Now() 194 if stmt.Time == nil { 195 i := t.UnixNano() 196 stmt.Time = &i 197 } 198 199 if stmt.Expiration == nil { 200 i := t.Add(365 * 24 * time.Hour).UnixNano() 201 stmt.Expiration = &i 202 } 203 204 ser := auth.Marshal(stmt) 205 // TODO(tmroeder): check the pcrVals for sanity once we support extending or 206 // clearing the PCRs. 207 sig, _, err := tpm.Quote(tt.tpmfile, tt.aikHandle, ser, tt.pcrNums, tt.srkAuth[:]) 208 if err != nil { 209 return nil, err 210 } 211 212 aik, err := x509.MarshalPKIXPublicKey(tt.verifier) 213 if err != nil { 214 return nil, err 215 } 216 a := &Attestation{ 217 SerializedStatement: ser, 218 Signature: sig, 219 SignerType: proto.String("tpm"), 220 SignerKey: aik, 221 RootEndorsement: tt.aikCert, 222 } 223 return a, nil 224 } 225 226 // Seal encrypts data so only certain hosted programs can unseal it. Note that 227 // at least some TPMs can only seal up to 149 bytes of data. So, we employ a 228 // hybrid encryption scheme that seals a key and uses the key to encrypt the 229 // data separately. We use the keys infrastructure to perform secure and 230 // flexible encryption. 231 func (tt *TPMTao) Seal(data []byte, policy string) (sealed []byte, err error) { 232 if policy != SealPolicyDefault { 233 return nil, errors.New("tpm-specific policies are not yet implemented") 234 } 235 236 keyName := "SealingKey" 237 keyEpoch := int32(1) 238 keyPurpose := "crypting" 239 keyStatus := "active" 240 keyType := CrypterTypeFromSuiteName(TaoCryptoSuite) 241 if keyType == nil { 242 return nil, errors.New("unsupported sealer crypter") 243 } 244 ck := GenerateCryptoKey(*keyType, &keyName, &keyEpoch, &keyPurpose, &keyStatus) 245 if ck == nil { 246 return nil, errors.New("Can't generate sealing key") 247 } 248 crypter := CrypterFromCryptoKey(*ck) 249 if crypter == nil { 250 return nil, errors.New("Can't get crypter from sealing key") 251 } 252 defer crypter.Clear() 253 254 c, err := crypter.Encrypt(data) 255 if err != nil { 256 return nil, err 257 } 258 259 ckb, err := proto.Marshal(ck) 260 if err != nil { 261 return nil, err 262 } 263 defer ZeroBytes(ckb) 264 265 s, err := tpm.Seal(tt.tpmfile, tt.locality, tt.pcrNums, ckb, tt.srkAuth[:]) 266 if err != nil { 267 return nil, err 268 } 269 270 h := &HybridSealedData{ 271 SealedKey: s, 272 EncryptedData: c, 273 } 274 275 return proto.Marshal(h) 276 } 277 278 // Unseal decrypts data that has been sealed by the Seal() operation, but only 279 // if the policy specified during the Seal() operation is satisfied. 280 func (tt *TPMTao) Unseal(sealed []byte) (data []byte, policy string, err error) { 281 // The sealed data is a HybridSealedData. 282 var h HybridSealedData 283 if err := proto.Unmarshal(sealed, &h); err != nil { 284 return nil, "", err 285 } 286 287 unsealed, err := tpm.Unseal(tt.tpmfile, h.SealedKey, tt.srkAuth[:]) 288 if err != nil { 289 return nil, "", err 290 } 291 defer ZeroBytes(unsealed) 292 293 var ck CryptoKey 294 if err := proto.Unmarshal(unsealed, &ck); err != nil { 295 return nil, "", err 296 } 297 defer ck.Clear() 298 299 crypter := CrypterFromCryptoKey(ck) 300 if err == nil { 301 return nil, "", errors.New("Cant get crypter from crypto key") 302 } 303 304 m, err := crypter.Decrypt(h.EncryptedData) 305 if err != nil { 306 return nil, "", err 307 } 308 309 return m, SealPolicyDefault, nil 310 } 311 312 func (s *TPMTao) InitCounter(label string, c int64) (error) { 313 return errors.New("InitCounter for tpm not implemented") 314 } 315 316 func (s *TPMTao) GetCounter(label string) (int64, error) { 317 return int64(0), errors.New("GetCounter for tpm not implemented") 318 } 319 320 func (s *TPMTao) RollbackProtectedSeal(label string, data []byte, policy string) ([]byte, error) { 321 return nil, errors.New("RollbackProtectedSeal for tpm not implemented") 322 } 323 324 func (s *TPMTao) RollbackProtectedUnseal(sealed []byte) ([]byte, string, error) { 325 return nil, "", errors.New("RollbackProtectedUnseal for tpm not implemented") 326 } 327 328 // extractPCRs gets the PCRs from a tpm principal. 329 func extractPCRs(p auth.Prin) ([]int, []byte, error) { 330 if p.Type != "tpm" { 331 return nil, nil, errors.New("can only extract PCRs from a TPM principal") 332 } 333 334 // The PCRs are stored as the first subprincipal value, with name "PCRs". 335 if len(p.Ext) == 0 { 336 return nil, nil, errors.New("no subprincipals available for PCR extraction") 337 } 338 339 if p.Ext[0].Name != "PCRs" { 340 return nil, nil, errors.New("the first subprincipal must have Name 'PCRs' for PCR extraction to work") 341 } 342 343 sp := p.Ext[0] 344 if len(sp.Arg) != 2 { 345 return nil, nil, errors.New("the PCRs subprincipal must have exactly two arguments") 346 } 347 348 // auth.Str is exactly a string. 349 arg0, ok0 := sp.Arg[0].(auth.Str) 350 arg1, ok1 := sp.Arg[1].(auth.Str) 351 if !ok0 || !ok1 { 352 return nil, nil, errors.New("both Terms in the PCRs subprincipal must be strings") 353 } 354 355 nums := strings.Split(string(arg0), ",") 356 vals := strings.Split(string(arg1), ",") 357 if len(nums) != len(vals) { 358 return nil, nil, errors.New("mismatched count between PCR nums and vals") 359 } 360 361 pcrNums := make([]int, len(nums)) 362 var pcrVals []byte 363 for i, v := range nums { 364 n, err := strconv.ParseInt(v, 10, 16) 365 if err != nil { 366 return nil, nil, err 367 } 368 pcrNums[i] = int(n) 369 370 b, err := hex.DecodeString(vals[i]) 371 if err != nil { 372 return nil, nil, err 373 } 374 pcrVals = append(pcrVals, b...) 375 } 376 return pcrNums, pcrVals, nil 377 } 378 379 // extractTPMKey gets an RSA public key from the TPM key material. 380 func extractTPMKey(material []byte) (*rsa.PublicKey, error) { 381 // The principal's Key should be a binary SubjectPublicKeyInfo. 382 pk, err := x509.ParsePKIXPublicKey(material) 383 if err != nil { 384 return nil, err 385 } 386 387 aik, ok := pk.(*rsa.PublicKey) 388 if !ok { 389 return nil, errors.New("wrong type of public key: only RSA is supported for AIKs") 390 } 391 392 return aik, nil 393 } 394 395 func ReadPCRs(tpmfile *os.File, pcrNums []int) ([][]byte, error) { 396 pcrVals := make([][]byte, len(pcrNums)) 397 for i, v := range pcrNums { 398 pv, err := tpm.ReadPCR(tpmfile, uint32(v)) 399 if err != nil { 400 return nil, err 401 } 402 pcrVals[i] = pv 403 } 404 return pcrVals, nil 405 } 406 407 func MakeTPMPrin(verifier *rsa.PublicKey, pcrNums []int, pcrVals [][]byte) (auth.Prin, error) { 408 aik, err := x509.MarshalPKIXPublicKey(verifier) 409 if err != nil { 410 return auth.Prin{}, err 411 } 412 413 name := auth.NewTPMPrin(aik) 414 415 asp := auth.PrinExt{ 416 Name: "PCRs", 417 Arg: make([]auth.Term, 2), 418 } 419 var pcrNumStrs []string 420 for _, v := range pcrNums { 421 pcrNumStrs = append(pcrNumStrs, strconv.Itoa(v)) 422 } 423 asp.Arg[0] = auth.Str(strings.Join(pcrNumStrs, ",")) 424 425 var pcrValStrs []string 426 for _, p := range pcrVals { 427 pcrValStrs = append(pcrValStrs, hex.EncodeToString(p)) 428 } 429 asp.Arg[1] = auth.Str(strings.Join(pcrValStrs, ",")) 430 431 // The PCRs are the first extension of the name. 432 name.Ext = []auth.PrinExt{asp} 433 434 return name, nil 435 } 436 437 // CleanUpTPMTao runs the finalizer for TPMTao early then unsets it so it 438 // doesn't run later. Normal code will only create one instance of TPMTao, so 439 // the finalizer will work correctly. But this test code creates multiple such 440 // instances, so it needs to call the finalizer early. 441 func CleanUpTPMTao(tt *TPMTao) { 442 FinalizeTPMTao(tt) 443 runtime.SetFinalizer(tt, nil) 444 }