Beispiel #1
0
// GenerateAttestation uses the signing key to generate an attestation for this
// statement.
func GenerateAttestation(s *Signer, delegation []byte, stmt auth.Says) (*Attestation, error) {
	signer := s.ToPrincipal()

	t := time.Now()
	if stmt.Time == nil {
		i := t.UnixNano()
		stmt.Time = &i
	}

	if stmt.Expiration == nil {
		i := t.Add(365 * 24 * time.Hour).UnixNano()
		stmt.Expiration = &i
	}

	ser := auth.Marshal(stmt)

	sig, err := s.Sign(ser, AttestationSigningContext)
	if err != nil {
		return nil, err
	}

	a := &Attestation{
		SerializedStatement: ser,
		Signature:           sig,
		Signer:              auth.Marshal(signer),
	}

	if len(delegation) > 0 {
		a.SerializedDelegation = delegation
	}

	return a, nil
}
Beispiel #2
0
// GenerateAttestation uses the signing key to generate an attestation for this
// statement.
func GenerateAttestation(s *Signer, delegation []byte, stmt auth.Says) (*Attestation, error) {
	t := time.Now()
	if stmt.Time == nil {
		i := t.UnixNano()
		stmt.Time = &i
	}

	if stmt.Expiration == nil {
		i := t.Add(365 * 24 * time.Hour).UnixNano()
		stmt.Expiration = &i
	}

	ser := auth.Marshal(stmt)

	sig, err := s.Sign(ser, AttestationSigningContext)
	if err != nil {
		return nil, err
	}

	a := &Attestation{
		SerializedStatement: ser,
		Signature:           sig,
		SignerType:          proto.String("key"),
		SignerKey:           s.GetVerifier().MarshalKey(),
	}

	if len(delegation) > 0 {
		a.SerializedDelegation = delegation
	}

	return a, nil
}
Beispiel #3
0
// Attest requests the Tao host sign a statement on behalf of the caller. The
// optional issuer, time and expiration will be given default values if nil.
func (tt *TPMTao) Attest(issuer *auth.Prin, start, expiration *int64, message auth.Form) (*Attestation, error) {
	if issuer == nil {
		issuer = &tt.name
	} else if !auth.SubprinOrIdentical(*issuer, tt.name) {
		return nil, errors.New("invalid issuer in statement")
	}

	// TODO(tmroeder): we assume here that the PCRs haven't changed (e.g., been
	// extended) since this TPMTao was created. If they have, then the PCRs will
	// be wrong when we extend the principal here with them as the first
	// component. This doesn't matter at the moment, since we don't currently
	// support extending the PCRs or clearing them, but it will need to be
	// changed when we do.
	stmt := auth.Says{
		Speaker:    *issuer,
		Time:       start,
		Expiration: expiration,
		Message:    message,
	}

	// This is done in GenerateAttestation, but the TPM attestation is signed
	// differently, so we do the time calculations here.
	t := time.Now()
	if stmt.Time == nil {
		i := t.UnixNano()
		stmt.Time = &i
	}

	if stmt.Expiration == nil {
		i := t.Add(365 * 24 * time.Hour).UnixNano()
		stmt.Expiration = &i
	}

	ser := auth.Marshal(stmt)
	// TODO(tmroeder): check the pcrVals for sanity once we support extending or
	// clearing the PCRs.
	sig, _, err := tpm.Quote(tt.tpmfile, tt.aikHandle, ser, tt.pcrNums, tt.srkAuth[:])
	if err != nil {
		return nil, err
	}

	// Pull off the extensions from the name to get the bare TPM key for the
	// signer.
	signer := auth.Prin{
		Type: tt.name.Type,
		Key:  tt.name.Key,
	}
	a := &Attestation{
		SerializedStatement: ser,
		Signature:           sig,
		Signer:              auth.Marshal(signer),
	}
	return a, nil
}
Beispiel #4
0
// Validate checks whether an attestation is valid and, if so, it returns the
// statement conveyed by the attestation.
func (a *Attestation) Validate() (auth.Says, error) {
	signer, err := a.ValidSigner()
	if err != nil {
		return auth.Says{}, err
	}
	f, err := auth.UnmarshalForm(a.SerializedStatement)
	if err != nil {
		return auth.Says{}, err
	}
	var stmt *auth.Says
	if ptr, ok := f.(*auth.Says); ok {
		stmt = ptr
	} else if val, ok := f.(auth.Says); ok {
		stmt = &val
	} else {
		return auth.Says{}, newError("tao: attestation statement has wrong type: %T", f)
	}
	if a.SerializedDelegation == nil {
		// Case (1), no delegation present.
		// Require that stmt.Speaker be a subprincipal of (or identical to) a.signer.
		if !auth.SubprinOrIdentical(stmt.Speaker, signer) {
			return auth.Says{}, newError("tao: attestation statement signer (%v) does not evidently speak for issuer (%v)", signer, stmt.Speaker)
		}
	} else {
		// Case (2), delegation present.
		// Require that:
		// - delegation conveys delegator says delegate speaksfor delegator,
		// - a.signer speaks for delegate
		// - and delegator speaks for s.Speaker
		var da Attestation
		if err := proto.Unmarshal(a.SerializedDelegation, &da); err != nil {
			return auth.Says{}, err
		}
		delegationStatement, err := da.Validate()
		if err != nil {
			return auth.Says{}, err
		}
		var delegation *auth.Speaksfor
		if ptr, ok := delegationStatement.Message.(*auth.Speaksfor); ok {
			delegation = ptr
		} else if val, ok := delegationStatement.Message.(auth.Speaksfor); ok {
			delegation = &val
		} else {
			return auth.Says{}, newError("tao: attestation delegation is wrong type")
		}
		if !delegationStatement.Speaker.Identical(delegation.Delegator) {
			return auth.Says{}, newError("tao: attestation delegation is invalid")
		}
		if !auth.SubprinOrIdentical(delegation.Delegate, signer) {
			return auth.Says{}, newError("tao: attestation delegation irrelevant to signer")
		}
		if !auth.SubprinOrIdentical(stmt.Speaker, delegation.Delegator) {
			return auth.Says{}, newError("tao: attestation delegation irrelevant to issuer")
		}
		if stmt.Time == nil {
			stmt.Time = delegationStatement.Time
		} else if delegationStatement.Time != nil && *stmt.Time < *delegationStatement.Time {
			stmt.Time = delegationStatement.Time
		}
		if stmt.Expiration == nil {
			stmt.Expiration = delegationStatement.Expiration
		} else if delegationStatement.Expiration != nil && *stmt.Expiration > *delegationStatement.Expiration {
			stmt.Expiration = delegationStatement.Expiration
		}
	}
	return *stmt, nil
}
Beispiel #5
0
// Attest requests the Tao host seal a statement on behalf of the caller. The
// optional issuer, time and expiration will be given default values if nil.
func (tt *TPM2Tao) Attest(issuer *auth.Prin, start, expiration *int64,
	message auth.Form) (*Attestation, error) {
	fmt.Fprintf(os.Stderr, "About to load the quote key in attest\n")
	qh, err := tt.loadQuote()
	if err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, qh)

	if issuer == nil {
		issuer = &tt.name
	} else if !auth.SubprinOrIdentical(*issuer, tt.name) {
		return nil, errors.New("invalid issuer in statement")
	}

	// TODO(tmroeder): we assume here that the PCRs haven't changed (e.g., been
	// extended) since this TPM2Tao was created. If they have, then the PCRs will
	// be wrong when we extend the principal here with them as the first
	// component. This doesn't matter at the moment, since we don't currently
	// support extending the PCRs or clearing them, but it will need to be
	// changed when we do.
	stmt := auth.Says{
		Speaker:    *issuer,
		Time:       start,
		Expiration: expiration,
		Message:    message,
	}

	// This is done in GenerateAttestation, but the TPM attestation is sealed
	// differently, so we do the time calculations here.
	t := time.Now()
	if stmt.Time == nil {
		i := t.UnixNano()
		stmt.Time = &i
	}

	if stmt.Expiration == nil {
		i := t.Add(365 * 24 * time.Hour).UnixNano()
		stmt.Expiration = &i
	}

	ser := auth.Marshal(stmt)

	var pcrVals [][]byte
	toQuote, err := tpm2.FormatTpm2Quote(ser, tt.pcrs, pcrVals)
	if err != nil {
		return nil, errors.New("Can't format tpm2 Quote")
	}

	// TODO(tmroeder): check the pcrVals for sanity once we support extending or
	// clearing the PCRs.
	quote_struct, sig, err := tpm2.Quote(tt.rw, qh, "", tt.password,
		toQuote, tt.pcrs, uint16(tpm2.AlgTPM_ALG_NULL))
	if err != nil {
		return nil, err
	}
	fmt.Printf("toQuote: %x\n", toQuote)
	fmt.Printf("Quote: %x\n", quote_struct)
	fmt.Printf("sig: %x\n", sig)

	quoteKey, err := x509.MarshalPKIXPublicKey(tt.verifier)
	if err != nil {
		return nil, err
	}

	// TODO(kwalsh) remove Tpm2QuoteStructure from Attestation structure
	a := &Attestation{
		SerializedStatement: ser,
		Signature:           sig,
		SignerType:          proto.String("tpm2"),
		SignerKey:           quoteKey,
		Tpm2QuoteStructure:  quote_struct,
	}

	return a, nil
}
Beispiel #6
0
// Create a response to a request.
func respond(req *CARequest, s *Signer, guard Guard) (resp *CAResponse) {
	resp = new(CAResponse)
	resp.Type = CAType_ERROR.Enum()

	if *req.Type == CAType_ATTESTATION && req.Attestation != nil {
		truncSays, pe, err := TruncateAttestation(s.ToPrincipal(), req.Attestation)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Couldn't truncate the attestation:", err)
			return
		}

		// TODO(tmroeder): fix this to check the time and make sure we're not
		// signing an unbounded attestation to this program.
		ra, err := GenerateAttestation(s, nil, truncSays)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Couldn't attest to the new says statement:", err)
			return
		}

		// Add an endorsement to this PrinExt Program hash so the receiver can check
		// it successfully against policy.
		endorsement := auth.Says{
			Speaker: s.ToPrincipal(),
			Message: auth.Pred{
				Name: "TrustedProgramHash",
				Arg:  []auth.Term{auth.PrinTail{Ext: []auth.PrinExt{pe}}},
			},
		}
		if truncSays.Time != nil {
			i := *truncSays.Time
			endorsement.Time = &i
		}
		if truncSays.Expiration != nil {
			i := *truncSays.Expiration
			endorsement.Expiration = &i
		}
		ea, err := GenerateAttestation(s, nil, endorsement)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Couldn't generate an endorsement for this program:", err)
			return
		}
		eab, err := proto.Marshal(ea)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Couldn't marshal an endorsement:", err)
			return
		}
		ra.SerializedEndorsements = [][]byte{eab}

		resp.Type = CAType_ATTESTATION.Enum()
		resp.Attestation = ra

	} else if *req.Type == CAType_DATALOG_POLICY {
		dg, ok := guard.(*DatalogGuard)
		if !ok {
			fmt.Fprintln(os.Stderr, "Requested wrong type")
			return
		}

		sdb, err := dg.GetSignedDatalogRules(s)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't get signed datalog rules: %s", err)
			return
		}

		resp.Type = CAType_DATALOG_POLICY.Enum()
		resp.SignedDatalogRules = sdb

	} else if *req.Type == CAType_ACL_POLICY {
		ac, ok := guard.(*ACLGuard)
		if !ok {
			fmt.Fprintln(os.Stderr, "Requested wrong type")
			return
		}

		sdb, err := ac.GetSignedACLSet(s)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't get signed ACL set: %s", err)
			return
		}
		resp.Type = CAType_ACL_POLICY.Enum()
		resp.SignedAclSet = sdb

	} else {
		resp.Type = CAType_UNDEFINED.Enum()
	}

	return
}