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  }