github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tpm2/tpm2_attest_protocol_support.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 // http://www.apache.org/licenses/LICENSE-2.0 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, 9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // See the License for the specific language governing permissions and 11 // limitations under the License. 12 // 13 // File: tpm2_attest_protocol_support.go 14 15 package tpm2 16 17 import ( 18 "crypto/ecdsa" 19 "crypto/rand" 20 "crypto/rsa" 21 "crypto/sha1" 22 "crypto/sha256" 23 "crypto/tls" 24 "crypto/x509" 25 "crypto/x509/pkix" 26 "errors" 27 "fmt" 28 "io" 29 "log" 30 "math/big" 31 "net" 32 "time" 33 34 // "github.com/jlmucb/cloudproxy/go/tao" 35 "github.com/jlmucb/cloudproxy/go/util" 36 ) 37 38 // TODO(jlm): Remove Printf's. 39 40 func CreateTemporaryChannelKey() (*rsa.PrivateKey, []byte, error) { 41 requestingKey, err := rsa.GenerateKey(rand.Reader, 2048) 42 if err != nil { 43 return nil, nil, err 44 } 45 46 // Self sign the cert 47 notBefore := time.Now() 48 validFor := 365 * 24 * time.Hour 49 notAfter := notBefore.Add(validFor) 50 51 us := "US" 52 issuerName := "RequestDomainQuoteCert" 53 localhost := "localhost" 54 x509SubjectName := &pkix.Name{ 55 Organization: []string{issuerName}, 56 OrganizationalUnit: []string{issuerName}, 57 CommonName: localhost, 58 Country: []string{us}, 59 } 60 var sn big.Int 61 certificateTemplate := x509.Certificate{ 62 SerialNumber: &sn, 63 Issuer: *x509SubjectName, 64 Subject: *x509SubjectName, 65 NotBefore: notBefore, 66 NotAfter: notAfter, 67 KeyUsage: x509.KeyUsageCertSign | 68 x509.KeyUsageKeyAgreement | x509.KeyUsageDigitalSignature, 69 } 70 71 channelCert, err := x509.CreateCertificate(rand.Reader, &certificateTemplate, 72 &certificateTemplate, requestingKey, 73 requestingKey) 74 if err != nil { 75 return nil, nil, errors.New("RequestDomainQuoteCert: Can't self sign tls cert") 76 } 77 return requestingKey, channelCert, nil 78 } 79 80 func BuildAttestCertRequest(tpmDevice io.ReadWriter, quoteHandle Handle, endorsementHandle Handle, endorsementCert []byte, 81 taoName string, ownerPw string) (*AttestCertRequest, error) { 82 83 // Get Quote key. 84 tpm2QuoteKeyBlob, tpm2QuoteKeyName, _, err := ReadPublic(tpmDevice, quoteHandle) 85 if err != nil { 86 return nil, err 87 } 88 rsaQuoteParams, err := DecodeRsaBuf(tpm2QuoteKeyBlob) 89 if err != nil { 90 return nil, err 91 } 92 93 quoteKey := new(rsa.PublicKey) 94 quoteKey.N = new(big.Int) 95 quoteKey.N.SetBytes(rsaQuoteParams.Modulus) 96 quoteKey.E = int(rsaQuoteParams.Exp) 97 98 request := new(AttestCertRequest) 99 100 // DER encoded subject key 101 derSubjectKey, err := x509.MarshalPKIXPublicKey(quoteKey) 102 if err != nil { 103 return nil, err 104 } 105 106 var hashedQuoteKey []byte 107 if rsaQuoteParams.Hash_alg == AlgTPM_ALG_SHA1 { 108 sha1Str := "sha1" 109 request.HashType = &sha1Str 110 sha1Hash := sha1.New() 111 sha1Hash.Write([]byte(derSubjectKey)) 112 hashedQuoteKey = sha1Hash.Sum(nil) 113 } else if rsaQuoteParams.Hash_alg == AlgTPM_ALG_SHA256 { 114 sha256Str := "sha256" 115 request.HashType = &sha256Str 116 sha256Hash := sha256.New() 117 sha256Hash.Write([]byte(derSubjectKey)) 118 hashedQuoteKey = sha256Hash.Sum(nil) 119 } else { 120 return nil, errors.New("RequestDomainQuoteCert: Quote key has unknown cert type") 121 } 122 123 sigAlg := uint16(AlgTPM_ALG_NULL) 124 tpm2AttestBlob, tpm2SigBlob, err := Quote(tpmDevice, quoteHandle, ownerPw, ownerPw, 125 hashedQuoteKey, []int{17, 18}, sigAlg) 126 if err != nil { 127 return nil, err 128 } 129 130 request.AttestBlob = tpm2AttestBlob 131 request.SigBlob = tpm2SigBlob 132 request.KeyName = &taoName 133 request.SubjectPublicKey = derSubjectKey 134 request.DerEndorsementCert = endorsementCert 135 if rsaQuoteParams.Enc_alg == AlgTPM_ALG_RSA { 136 rsaStr := "rsa" 137 request.KeyType = &rsaStr 138 139 } else { 140 return nil, errors.New("RequestDomainQuoteCert: Bad quote key type") 141 } 142 request.Tpm2KeyName = tpm2QuoteKeyName 143 // TODO: request.CertChain 144 return request, nil 145 } 146 147 func GetCertFromAttestResponse(tpmDevice io.ReadWriter, quoteHandle Handle, endorsementHandle Handle, 148 password string, response AttestCertResponse) ([]byte, error) { 149 // Decrypt cert 150 certBlob := append(response.IntegrityHmac, response.EncIdentity...) 151 certInfo, err := ActivateCredential(tpmDevice, quoteHandle, endorsementHandle, 152 password, "", certBlob, response.EncryptedSecret) 153 if err != nil { 154 return nil, err 155 } 156 fmt.Printf("certInfo: %x\n", certInfo) 157 158 // Decrypt cert. 159 _, decryptedCert, err := EncryptDataWithCredential(false, uint16(AlgTPM_ALG_SHA1), 160 certInfo, response.EncryptedCert, response.EncryptedCertHmac) 161 if err != nil { 162 return nil, err 163 } 164 return decryptedCert, nil 165 } 166 167 // RequestDomainQuoteCert requests the Quote Cert 168 func RequestDomainQuoteCert(network, addr string, endorsementCert []byte, tpmDevice io.ReadWriter, 169 quoteHandle Handle, endorsementHandle Handle, taoName string, 170 ownerPw string) ([]byte, error) { 171 172 requestingKey, derChannelCert, err := CreateTemporaryChannelKey() 173 if err != nil || requestingKey == nil { 174 return nil, err 175 } 176 channelCert, err := x509.ParseCertificate(derChannelCert) 177 if err != nil || channelCert == nil { 178 return nil, err 179 } 180 181 // Contact domain service. 182 conn, err := tls.Dial(network, addr, &tls.Config{ 183 RootCAs: x509.NewCertPool(), 184 // Certificates: []tls.Certificate{tls.Certificate(*channelCert)}, 185 InsecureSkipVerify: true, 186 }) 187 if err != nil { 188 return nil, err 189 } 190 defer conn.Close() 191 192 // Build request. 193 request, err := BuildAttestCertRequest(tpmDevice, quoteHandle, endorsementHandle, endorsementCert, taoName, ownerPw) 194 if err != nil { 195 return nil, err 196 } 197 198 // Send request 199 ms := util.NewMessageStream(conn) 200 _, err = ms.WriteMessage(request) 201 if err != nil { 202 return nil, err 203 } 204 205 // Read the new cert 206 var response AttestCertResponse 207 err = ms.ReadMessage(&response) 208 if err != nil { 209 return nil, err 210 } 211 212 return GetCertFromAttestResponse(tpmDevice, quoteHandle, endorsementHandle, ownerPw, response) 213 } 214 215 // This is the operation of the server. It computes the AttestResponse. 216 func ProcessQuoteDomainRequest(request AttestCertRequest, policyKey *ecdsa.PrivateKey, derPolicyCert []byte) (*AttestCertResponse, error) { 217 218 if *request.KeyType != "rsa" { 219 return nil, errors.New("HandleQuoteDomainRequest: Unsuported key algorithm") 220 } 221 if *request.HashType != "sha1" && *request.HashType != "sha256" { 222 return nil, errors.New("HandleQuoteDomainRequest: Unsuported hash algorithm") 223 } 224 225 // Get Key information from der 226 attestKey, err := x509.ParsePKIXPublicKey(request.SubjectPublicKey) 227 if err != nil { 228 return nil, err 229 } 230 231 // Sign certificate. 232 notBefore := time.Now() 233 validFor := 365 * 24 * time.Hour 234 notAfter := notBefore.Add(validFor) 235 236 us := "US" 237 issuerName := "Google" 238 localhost := "localhost" 239 x509SubjectName := &pkix.Name{ 240 Organization: []string{*request.KeyName}, 241 OrganizationalUnit: []string{*request.KeyName}, 242 CommonName: localhost, 243 Country: []string{us}, 244 } 245 x509IssuerName := &pkix.Name{ 246 Organization: []string{issuerName}, 247 OrganizationalUnit: []string{issuerName}, 248 CommonName: localhost, 249 Country: []string{us}, 250 } 251 252 // issuerName := tao.NewX509Name(&details) 253 var sn big.Int 254 certificateTemplate := x509.Certificate{ 255 SerialNumber: &sn, 256 Issuer: *x509IssuerName, 257 Subject: *x509SubjectName, 258 NotBefore: notBefore, 259 NotAfter: notAfter, 260 KeyUsage: x509.KeyUsageCertSign | 261 x509.KeyUsageKeyAgreement | x509.KeyUsageDigitalSignature, 262 } 263 264 policyCert, err := x509.ParseCertificate(derPolicyCert) 265 if err != nil { 266 return nil, err 267 } 268 269 attestCert, err := x509.CreateCertificate(rand.Reader, &certificateTemplate, 270 policyCert, attestKey, policyKey) 271 if err != nil { 272 fmt.Printf("Can't create attest certificate: ", err, "\n") 273 return nil, err 274 } 275 276 response := new(AttestCertResponse) 277 // response.CertChain= append(request.CertChain, policyKey.Cert.Raw) 278 279 // hash and verify quotekey. 280 var hashAlgId uint16 281 var hashedQuoteKey []byte 282 if *request.HashType == "sha256" { 283 hashAlgId = uint16(AlgTPM_ALG_SHA256) 284 sha256Hash := sha256.New() 285 sha256Hash.Write([]byte(request.SubjectPublicKey)) 286 hashedQuoteKey = sha256Hash.Sum(nil) 287 } else if *request.HashType == "sha1" { 288 hashAlgId = uint16(AlgTPM_ALG_SHA1) 289 sha1Hash := sha1.New() 290 sha1Hash.Write([]byte(request.SubjectPublicKey)) 291 hashedQuoteKey = sha1Hash.Sum(nil) 292 } else { 293 return nil, errors.New("Unsuported hash algorithm") 294 } 295 if len(hashedQuoteKey) < 10 { 296 } 297 298 subjectKey, err := x509.ParsePKIXPublicKey(request.SubjectPublicKey) 299 if err != nil { 300 return nil, err 301 } 302 rsaQuoteKey := subjectKey.(*rsa.PublicKey) 303 if !VerifyRsaQuote(hashedQuoteKey, rsaQuoteKey, 304 hashAlgId, request.AttestBlob, request.SigBlob, ValidPcr) { 305 return nil, errors.New("Can't verify quote") 306 } 307 308 // Get Endorsement blob 309 endorsement_cert, err := x509.ParseCertificate(request.DerEndorsementCert) 310 if err != nil { 311 return nil, err 312 } 313 314 // Verify Endorsement Cert 315 ok, err := VerifyDerCert(request.DerEndorsementCert, derPolicyCert) 316 if !ok { 317 return nil, errors.New("Bad endorsement cert") 318 } 319 var protectorPublic *rsa.PublicKey 320 switch k := endorsement_cert.PublicKey.(type) { 321 case *rsa.PublicKey: 322 protectorPublic = k 323 case *rsa.PrivateKey: 324 protectorPublic = &k.PublicKey 325 default: 326 return nil, errors.New("endorsement cert not an rsa key") 327 } 328 329 // Generate credential 330 var credential [16]byte 331 rand.Read(credential[0:16]) 332 fmt.Printf("Credential: %x, hashid: %x\n", credential, hashAlgId) 333 encrypted_secret, encIdentity, integrityHmac, err := MakeCredential( 334 protectorPublic, hashAlgId, credential[0:16], request.Tpm2KeyName) 335 if err != nil { 336 return nil, err 337 } 338 339 // Response 340 response.IntegrityAlg = request.HashType 341 response.IntegrityHmac = integrityHmac 342 response.EncIdentity = encIdentity 343 response.EncryptedSecret = encrypted_secret 344 345 // Encrypt cert with credential 346 cert_hmac, cert_out, err := EncryptDataWithCredential(true, hashAlgId, 347 credential[0:16], attestCert, nil) 348 if err != nil { 349 return nil, err 350 } 351 response.EncryptedCert = cert_out 352 response.EncryptedCertHmac = cert_hmac 353 354 // Need to set required error field to 0. 355 noError := int32(0) 356 response.Error = &noError 357 return response, nil 358 } 359 360 func HandleQuoteDomainRequest(conn net.Conn, policyKey *ecdsa.PrivateKey, derPolicyCert []byte) (bool, error) { 361 log.Printf("HandleQuoteDomainRequest\n") 362 363 // Expect a request with attestation from client. 364 ms := util.NewMessageStream(conn) 365 var request AttestCertRequest 366 err := ms.ReadMessage(&request) 367 if err != nil { 368 log.Printf("HandleQuoteDomainRequest: Couldn't read attest request from channel") 369 return false, err 370 } 371 372 resp, err := ProcessQuoteDomainRequest(request, policyKey, derPolicyCert) 373 if err != nil { 374 return false, err 375 } 376 377 _, err = ms.WriteMessage(resp) 378 if err != nil { 379 log.Printf("HandleQuoteDomainRequest: Couldn't return the attestation on the channel") 380 log.Printf("\n") 381 return false, err 382 } 383 return false, nil 384 }