github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/support_infrastructure/domain_service/domain_service.go (about)

     1  // Copyright (c) 2016, 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  package domain_service
    14  
    15  import (
    16  	"bytes"
    17  	"crypto/rsa"
    18  	"crypto/sha256"
    19  	"crypto/x509"
    20  	"crypto/x509/pkix"
    21  	"errors"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"log"
    25  	"math/big"
    26  	"time"
    27  
    28  	"github.com/golang/protobuf/proto"
    29  	"github.com/jlmucb/cloudproxy/go/tao"
    30  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    31  )
    32  
    33  func VerifyAttestation(serializedHostAttestation []byte, domain *tao.Domain) (*auth.Prin,
    34  	*auth.Prin, *auth.Prin, error) {
    35  	var hostAttestation tao.Attestation
    36  	err := proto.Unmarshal(serializedHostAttestation, &hostAttestation)
    37  	if err != nil {
    38  		return nil, nil, nil, err
    39  	}
    40  	signer, err := hostAttestation.ValidSigner()
    41  	if err != nil {
    42  		return nil, nil, nil, err
    43  	}
    44  	f, err := auth.UnmarshalForm(hostAttestation.SerializedStatement)
    45  	if err != nil {
    46  		return nil, nil, nil, err
    47  	}
    48  	var stmt *auth.Says
    49  	if ptr, ok := f.(*auth.Says); ok {
    50  		stmt = ptr
    51  	} else if val, ok := f.(auth.Says); ok {
    52  		stmt = &val
    53  	} else {
    54  		return nil, nil, nil, errors.New(fmt.Sprintf(
    55  			"tao: attestation statement has wrong type: %T", f))
    56  	}
    57  	speaker, key, program, err := parseSaysStatement(stmt)
    58  	if err != nil {
    59  		return nil, nil, nil, err
    60  	}
    61  	// Validate signer
    62  	if auth.SubprinOrIdentical(speaker, signer) {
    63  		// Case 1: speaker is identical or subprincipal of signing principal.
    64  		// Check if signer is either
    65  		// - policy key
    66  		// - TPM key with valid hardware endorsement cert signed by policy key.
    67  		if signer.Identical(domain.Keys.SigningKey.ToPrincipal()) {
    68  			return speaker, key, program, nil
    69  		}
    70  		if *hostAttestation.SignerType == "tpm" || *hostAttestation.SignerType == "tpm2" {
    71  			if hostAttestation.RootEndorsement == nil {
    72  				return nil, nil, nil, errors.New("TPM attestation is missing HW endorsement cert")
    73  			}
    74  			cert, err := x509.ParseCertificate(hostAttestation.RootEndorsement)
    75  			if err != nil {
    76  				return nil, nil, nil, err
    77  			}
    78  			certPool := x509.NewCertPool()
    79  			certPool.AddCert(domain.Keys.Cert)
    80  			verifyOptions := x509.VerifyOptions{Roots: certPool}
    81  			_, err = cert.Verify(verifyOptions)
    82  			if err != nil {
    83  				return nil, nil, nil, err
    84  			}
    85  			hwPublicKey, ok := cert.PublicKey.(*rsa.PublicKey)
    86  			if !ok {
    87  				key, ok := cert.PublicKey.(rsa.PublicKey)
    88  				if !ok {
    89  					return nil, nil, nil,
    90  						errors.New("endorsement cert does not contain a valid RSA public key")
    91  				}
    92  				hwPublicKey = &key
    93  			}
    94  			tpmKey, err := x509.MarshalPKIXPublicKey(hwPublicKey)
    95  			if err != nil {
    96  				return nil, nil, nil, err
    97  			}
    98  			if !bytes.Equal(hostAttestation.SignerKey, tpmKey) {
    99  				return nil, nil, nil, errors.New("HW endorsement cert public key does not match signer key")
   100  			}
   101  			return speaker, key, program, nil
   102  		}
   103  		// SignerType is a Tao key principal. Check if the key is endorsed by the policy key.
   104  		if hostAttestation.RootEndorsement != nil {
   105  			cert, err := x509.ParseCertificate(hostAttestation.RootEndorsement)
   106  			if err != nil {
   107  				return nil, nil, nil, err
   108  			}
   109  			certPool := x509.NewCertPool()
   110  			certPool.AddCert(domain.Keys.Cert)
   111  			verifyOptions := x509.VerifyOptions{Roots: certPool}
   112  			_, err = cert.Verify(verifyOptions)
   113  			if err != nil {
   114  				return nil, nil, nil, err
   115  			}
   116  			verifier, err := tao.UnmarshalKey(hostAttestation.SignerKey)
   117  			if err != nil {
   118  				return nil, nil, nil, err
   119  			}
   120  			if !verifier.KeyEqual(cert) {
   121  				return nil, nil, nil, errors.New("Endorsement cert is irrelevant to attestation signer")
   122  			}
   123  			return speaker, key, program, nil
   124  		}
   125  		return nil, nil, nil, errors.New("attestation signer is not endorsed by policy key")
   126  	} else {
   127  		// Case 2: speaker is not a subprincipal of the signing principal.
   128  		// Look for delegation and require that:
   129  		// - delegation conveys delegator says delegate speaksfor delegator,
   130  		// - a.signer speaks for delegate
   131  		// - and delegator speaks for s.Speaker
   132  		if hostAttestation.SerializedDelegation == nil {
   133  			return nil, nil, nil, errors.New("attestation missing delegation")
   134  		}
   135  		var da tao.Attestation
   136  		if err := proto.Unmarshal(hostAttestation.SerializedDelegation, &da); err != nil {
   137  			return nil, nil, nil, err
   138  		}
   139  		delegationStatement, err := da.Validate()
   140  		if err != nil {
   141  			return nil, nil, nil, err
   142  		}
   143  		var delegation *auth.Speaksfor
   144  		if ptr, ok := delegationStatement.Message.(*auth.Speaksfor); ok {
   145  			delegation = ptr
   146  		} else if val, ok := delegationStatement.Message.(auth.Speaksfor); ok {
   147  			delegation = &val
   148  		} else {
   149  			return nil, nil, nil, errors.New("tao: attestation delegation is wrong type")
   150  		}
   151  		if !delegationStatement.Speaker.Identical(delegation.Delegator) {
   152  			return nil, nil, nil, errors.New("tao: attestation delegation is invalid")
   153  		}
   154  		if !auth.SubprinOrIdentical(delegation.Delegate, signer) {
   155  			return nil, nil, nil, errors.New("tao: attestation delegation irrelevant to signer")
   156  		}
   157  		if !auth.SubprinOrIdentical(stmt.Speaker, delegation.Delegator) {
   158  			return nil, nil, nil, errors.New("tao: attestation delegation irrelevant to issuer")
   159  		}
   160  		return speaker, key, program, nil
   161  	}
   162  }
   163  
   164  // This function makes the following checks
   165  // (1) Checks if the attestation signature is valid and the statement is of the form
   166  //     'Speaker says Key speaks for Program'.
   167  // (2) Checks that 'Program' in the above statement is allowed to Execute in the domain policy.
   168  //     In particular, the policy should allow the predicate:
   169  //     Authorized(ProgramTaoName, "Execute")
   170  // (3) Checks that 'Speaker' in the above statement is a key principal endorsed by the policy key,
   171  //     or rootCerts, via an endorsement chain. Each endorsement in this chain endorses the key
   172  //     signing the previous endorsement (starting with the 'Speaker' key).
   173  //
   174  //     An endorsement endorses either a host key, in which case it is an attestation,
   175  //     or the root hardware key, in which case it is certificate.
   176  //     This function also checks that each host or root hardware encoutered along this endorsement
   177  //     chain is allowed as per domain policy. In particular the policy should allow the predicates
   178  //     Authorized(HostTaoName, "Host") and Authorized(EncodedMachineInformation, "Root")
   179  //
   180  //     A valid attestation chain must either end in a attestation signed by the policy key
   181  //     or a certificate signed by one of the rootCerts.
   182  //
   183  // If all above checks go through, the function returns the principals: Speaker, Key, Program.
   184  func VerifyHostAttestation(serializedHostAttestation []byte, domain *tao.Domain,
   185  	rootCerts *x509.CertPool) (*auth.Prin, *auth.Prin, *auth.Prin, error) {
   186  	var hostAttestation tao.Attestation
   187  	err := proto.Unmarshal(serializedHostAttestation, &hostAttestation)
   188  	if err != nil {
   189  		return nil, nil, nil, errors.New(
   190  			"domain_service: error deserialiaizng host attestation: " + err.Error())
   191  	}
   192  
   193  	// First check if attestation is valid.
   194  	statement, err := hostAttestation.Validate()
   195  	if err != nil {
   196  		return nil, nil, nil, errors.New(
   197  			"host attestation fails validation check: " + err.Error())
   198  	}
   199  
   200  	// Next, check if SpeaksFor delegator is authorized to execute (i.e. the program is allowed to
   201  	// run as per policy).
   202  	speaker, key, prog, err := parseSaysStatement(&statement)
   203  	if err != nil {
   204  		return nil, nil, nil, err
   205  	}
   206  	if !domain.Guard.IsAuthorized(*prog, "Execute", []string{}) {
   207  		return nil, nil, nil, errors.New(
   208  			"program not authorized to run in this domain")
   209  	}
   210  
   211  	// Look for endorsement cert(s), rooted in the policy key, that ultimately certify the
   212  	// key of the signer.
   213  	signingKey := hostAttestation.GetSignerKey()
   214  	if hostAttestation.SignerType == nil {
   215  		return nil, nil, nil, errors.New("host attestation missing SignerType field")
   216  	}
   217  	signingPrin := auth.NewPrin(*hostAttestation.SignerType, signingKey)
   218  	if !speaker.Identical(signingPrin) {
   219  		// TODO: endorsement endorses speaker or signer?
   220  	}
   221  
   222  	// Look for endorsement(s) of signer, rooted in policy key.
   223  	serializedEndorsements := hostAttestation.GetSerializedEndorsements()
   224  	var realErr error
   225  	var kPrin *auth.Prin
   226  	kPrin = &signingPrin
   227  	for _, serializedEndorsement := range serializedEndorsements {
   228  		// serializedEndorsement could be X.509 certificate or Tao attestation.
   229  		var attestation tao.Attestation
   230  		err := proto.Unmarshal(serializedEndorsement, &attestation)
   231  		if err == nil {
   232  			kPrin, realErr = validateEndorsementAttestation(&attestation, domain.Guard, kPrin)
   233  			if realErr != nil {
   234  				return nil, nil, nil, realErr
   235  			}
   236  		} else if cert, err1 := x509.ParseCertificate(serializedEndorsement); err1 == nil {
   237  			realErr = validateEndorsementCertificate(cert, domain.Guard, kPrin, rootCerts)
   238  			if realErr != nil {
   239  				return nil, nil, nil, realErr
   240  			} else {
   241  				// Endorsement certs are the root of the endorsement chain.
   242  				// If they are valid, then no more checking is required.
   243  				return speaker, key, prog, nil
   244  			}
   245  
   246  		} else {
   247  			return nil, nil, nil, errors.New("error parsing host endorsement")
   248  		}
   249  	}
   250  	if domain.Keys.SigningKey.ToPrincipal().Identical(*kPrin) {
   251  		return speaker, key, prog, nil
   252  	}
   253  	return nil, nil, nil, errors.New("endorsement chain does not terminate in policy key")
   254  
   255  }
   256  
   257  // Checks the following:
   258  // (1) the endorsement attestation is valid
   259  // (2) the key being endorsed is kPrin
   260  // (3) the subject being endorsed is a trusted host
   261  // Finally the function returns the key principal signing the endorsement
   262  func validateEndorsementAttestation(attestation *tao.Attestation, guard tao.Guard,
   263  	kPrin *auth.Prin) (*auth.Prin, error) {
   264  	saysStatement, err := attestation.Validate()
   265  	if err != nil {
   266  		return nil, err
   267  	}
   268  	_, key, host, err := parseSaysStatement(&saysStatement)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  	if !key.Identical(kPrin) {
   273  		return nil, errors.New("endorsement does not endorse signer of (previous) attestaton")
   274  	}
   275  	if !guard.IsAuthorized(*host, "Host", []string{}) {
   276  		return nil, errors.New("endorsement host not authorized to run in this domain")
   277  	}
   278  	signerType := attestation.SignerType
   279  	if signerType == nil {
   280  		return nil, errors.New("endorsement chain has attestation with missing SignerType")
   281  	}
   282  	signerPrin := auth.NewPrin(*signerType, attestation.SignerKey)
   283  	return &signerPrin, nil
   284  }
   285  
   286  // Checks the following:
   287  // (1) cert is valid according to one of the rootCerts.
   288  // (2) the subject key of cert corresponds to kPrin.
   289  // (3) the subject CommonName of cert is allowed by guard.
   290  func validateEndorsementCertificate(cert *x509.Certificate, guard tao.Guard,
   291  	kPrin *auth.Prin, rootCerts *x509.CertPool) error {
   292  	verifyOptions := x509.VerifyOptions{Roots: rootCerts}
   293  	_, err := cert.Verify(verifyOptions)
   294  	if err != nil {
   295  		return err
   296  	}
   297  	var hwPublicKey *rsa.PublicKey
   298  	hwPublicKey, ok := cert.PublicKey.(*rsa.PublicKey)
   299  	if !ok {
   300  		key, ok := cert.PublicKey.(rsa.PublicKey)
   301  		if !ok {
   302  			return errors.New("endorsement cert does not contain a valid RSA public key")
   303  		}
   304  		hwPublicKey = &key
   305  	}
   306  	ek, err := x509.MarshalPKIXPublicKey(hwPublicKey)
   307  	if err != nil {
   308  		return err
   309  	}
   310  	hashedCertKey := sha256.Sum256(ek)
   311  	if kPrin.Type != "tpm" && kPrin.Type != "tpm2" {
   312  		return errors.New("key principal to be endorsed is not a TPM key, but it's expected to be")
   313  	}
   314  	hashedBytes, ok := kPrin.KeyHash.(auth.Bytes)
   315  	if !ok {
   316  		return errors.New("key principal to be endorsed does not have bytes as its auth.Term")
   317  	}
   318  	if !bytes.Equal(hashedBytes, hashedCertKey[:]) {
   319  		return errors.New(fmt.Sprintf(
   320  			"endorsement cert endorses %v but needs to endorse %v", hashedCertKey, hashedBytes))
   321  	}
   322  	machinePrin := auth.Prin{
   323  		Type:    "MachineInfo",
   324  		KeyHash: auth.Str(cert.Subject.CommonName),
   325  	}
   326  	if !guard.IsAuthorized(machinePrin, "Root", []string{}) {
   327  		return errors.New(
   328  			"machine endorsed by certificate is not authorized by policy")
   329  	}
   330  	return nil
   331  }
   332  
   333  func parseSaysStatement(saysStatement *auth.Says) (*auth.Prin, *auth.Prin, *auth.Prin, error) {
   334  	if saysStatement.Speaker == nil {
   335  		return nil, nil, nil,
   336  			errors.New("attestation 'Says' does not have a speaker")
   337  	}
   338  	speaker, ok := saysStatement.Speaker.(auth.Prin)
   339  	if !ok {
   340  		return nil, nil, nil, errors.New(
   341  			"attestation 'Says' speaker is not a auth.Prin")
   342  	}
   343  	if saysStatement.Message == nil {
   344  		return nil, nil, nil, errors.New(
   345  			"attestation 'Says' does not have a message")
   346  	}
   347  	sf, ok := saysStatement.Message.(auth.Speaksfor)
   348  	if !ok {
   349  		return nil, nil, nil, errors.New(
   350  			"attestation statement does not have a 'SpeaksFor'")
   351  	}
   352  	if sf.Delegator == nil {
   353  		return nil, nil, nil, errors.New(
   354  			"attestation 'speaksFor' has no delegator")
   355  	}
   356  	delegator, ok := sf.Delegator.(auth.Prin)
   357  	if !ok {
   358  		return nil, nil, nil, errors.New(
   359  			"attestation 'speaksFor' delegator is not a auth.Prin")
   360  	}
   361  	if sf.Delegate == nil {
   362  		return nil, nil, nil, errors.New(
   363  			"attestation 'speaksFor' has no delegate.")
   364  	}
   365  	delegate, ok := sf.Delegate.(auth.Prin)
   366  	if !ok {
   367  		return nil, nil, nil, errors.New(
   368  			"ttestation 'speaksFor' delegate is not a auth.Prin")
   369  	}
   370  	return &speaker, &delegate, &delegator, nil
   371  }
   372  
   373  // This function generates a Program Certificate. In particular, it generates an attestation
   374  // signed by the domain policy key, with a statement of the form
   375  // 'policyKey says programCert speaksFor program'
   376  // where programCert is a X509 cert signed by the policy key with subject CommonName being the
   377  // Tao name of the program and subject public key being programKey.
   378  // Certificate expiration time is one year from issuing time.
   379  func GenerateProgramCert(domain *tao.Domain, serialNumber int, programPrin *auth.Prin,
   380  	verifier *tao.Verifier, now, expiry time.Time) (*x509.Certificate, error) {
   381  
   382  	policyCert := domain.Keys.Cert
   383  	x509Info := domain.Config.GetX509Info()
   384  	programName := programPrin.String()
   385  	localhost := "localhost"
   386  	x509Info.CommonName = &localhost
   387  	x509Info.OrganizationalUnit = &programName
   388  	subjectName := tao.NewX509Name(x509Info)
   389  	pkInt := tao.PublicKeyAlgFromSignerAlg(*domain.Keys.SigningKey.Header.KeyType)
   390  	sigInt := tao.SignatureAlgFromSignerAlg(*domain.Keys.SigningKey.Header.KeyType)
   391  	clientCert, err := domain.Keys.SigningKey.CreateSignedX509(
   392  		policyCert, serialNumber, verifier, pkInt, sigInt, subjectName)
   393  	if err != nil {
   394  		return nil, err
   395  	}
   396  	return clientCert, nil
   397  }
   398  
   399  // This function reads in trusted entities from a file at trustedEntitiesPath. In particular,
   400  // this file contains the text representation of a trusted_entities proto message, which contains
   401  // the Tao names of trusted programs and hosts, information about trusted machines and trusted
   402  // machine certificates.
   403  // For each such trusted entity, this function adds ACL rules to the domain guard, and saves
   404  // the changes before returning.
   405  func InitAcls(domain *tao.Domain, trustedEntitiesPath string) error {
   406  	text, err := ioutil.ReadFile(trustedEntitiesPath)
   407  	if err != nil {
   408  		log.Printf("Can't open trusted entities file: %s", trustedEntitiesPath)
   409  		return err
   410  	}
   411  	trustedEntities := TrustedEntities{}
   412  	err = proto.UnmarshalText(string(text), &trustedEntities)
   413  	if err != nil {
   414  		log.Printf("Can't parse trusted entities file: %s", trustedEntitiesPath)
   415  		return err
   416  	}
   417  	for _, programTaoName := range trustedEntities.GetTrustedProgramTaoNames() {
   418  		var programPrin auth.Prin
   419  		_, err := fmt.Sscanf(programTaoName, "%v", &programPrin)
   420  		if err != nil {
   421  			log.Printf("Can't create program principal from: %s\nError: %s",
   422  				programTaoName, err)
   423  			return err
   424  		}
   425  		err = domain.Guard.Authorize(programPrin, "Execute", []string{})
   426  		if err != nil {
   427  			log.Printf("Can't authorize principal: %s\nError: %s", programPrin, err)
   428  			return err
   429  		}
   430  	}
   431  	for _, hostTaoName := range trustedEntities.GetTrustedHostTaoNames() {
   432  		var hostPrin auth.Prin
   433  		_, err := fmt.Sscanf(hostTaoName, "%v", &hostPrin)
   434  		if err != nil {
   435  			log.Printf("Can't create host principal from: %s\nError: %s",
   436  				hostTaoName, err)
   437  			return err
   438  		}
   439  		err = domain.Guard.Authorize(hostPrin, "Host", []string{})
   440  		if err != nil {
   441  			log.Printf("Can't authorize principal: %s\nError: %s", hostPrin, err)
   442  			return err
   443  		}
   444  	}
   445  	for _, machineInfo := range trustedEntities.GetTrustedMachineInfos() {
   446  		machinePrin := auth.Prin{
   447  			Type:    "MachineInfo",
   448  			KeyHash: auth.Str(machineInfo),
   449  		}
   450  		err = domain.Guard.Authorize(machinePrin, "Root", []string{})
   451  		if err != nil {
   452  			log.Printf("Can't authorize principal: %s\nError: %s", machinePrin, err)
   453  			return err
   454  		}
   455  	}
   456  	err = domain.Save()
   457  	if err != nil {
   458  		log.Println("Can't save domain.", err)
   459  	}
   460  	return err
   461  }
   462  
   463  // This function helps process a certificate revocation request.
   464  // It expects serAtt to be a serialized attestation signed by the domain policy key,
   465  // with a statement of the form:
   466  // policyKey says revoke certificateSerialNumber
   467  // This function gets a list of revoked certificates, updates it if the cert revocation
   468  // request is valid, and returns the updated list.
   469  func RevokeCertificate(serAtt []byte, revokedCerts []pkix.RevokedCertificate,
   470  	domain *tao.Domain) ([]pkix.RevokedCertificate, error) {
   471  
   472  	var policyAtt tao.Attestation
   473  	err := proto.Unmarshal(serAtt, &policyAtt)
   474  	if err != nil {
   475  		return revokedCerts, err
   476  	}
   477  	if signer, err := policyAtt.ValidSigner(); err != nil {
   478  		return revokedCerts, err
   479  	} else if !signer.Identical(domain.Keys.SigningKey.ToPrincipal()) {
   480  		return revokedCerts, errors.New("revoke cert request not signed by the policy key")
   481  	}
   482  	saysStmt, err := policyAtt.Validate()
   483  	if err != nil {
   484  		return revokedCerts, err
   485  	}
   486  	if saysStmt.Message == nil {
   487  		return revokedCerts, errors.New("policy attestation 'Says' does not have a message")
   488  	}
   489  	pred, ok := saysStmt.Message.(auth.Pred)
   490  	if !ok {
   491  		return revokedCerts,
   492  			errors.New("policy attestation 'Says' does not have a auth.Pred message")
   493  	}
   494  	if pred.Name != "revoke" {
   495  		return revokedCerts, errors.New("policy attestation predicate name is not 'revoke'")
   496  	}
   497  	if len(pred.Arg) != 1 {
   498  		return revokedCerts,
   499  			errors.New("policy attestation predicate has more or less than one Arg")
   500  	}
   501  	serialNumberBytes, ok := pred.Arg[0].(auth.Bytes)
   502  	if !ok {
   503  		return revokedCerts,
   504  			errors.New("policy attestation serial number is not bytes")
   505  	}
   506  	serialNumber := new(big.Int)
   507  	serialNumber.SetBytes(serialNumberBytes)
   508  	revokedCert := pkix.RevokedCertificate{
   509  		SerialNumber:   serialNumber,
   510  		RevocationTime: time.Now()}
   511  	return append(revokedCerts, revokedCert), nil
   512  }