// ValidSigner checks the signature on an attestation and, if so, returns the signer.
func (a *Attestation) ValidSigner() (auth.Prin, error) {
	signer, err := auth.UnmarshalPrin(a.Signer)
	if err != nil {
		return auth.Prin{}, err
	}
	if len(signer.Ext) != 0 {
		return auth.Prin{}, newError("tao: attestation signer principal malformed: %s", signer)
	}
	switch signer.Type {
	case "tpm":
		// The PCRs are contained in the Speaker of an auth.Says statement that
		// makes up the a.SerializedStatement.
		f, err := auth.UnmarshalForm(a.SerializedStatement)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err)
		}

		// A TPM attestation must be an auth.Says.
		says, ok := f.(auth.Says)
		if !ok {
			return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement")
		}

		// Signer is tpm; use tpm-specific signature verification. Extract the
		// PCRs from the issuer name, unmarshal the key as an RSA key, and call
		// tpm.VerifyQuote().
		speaker, ok := says.Speaker.(auth.Prin)
		if !ok {
			return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin")
		}
		pcrNums, pcrVals, err := ExtractPCRs(speaker)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract PCRs from the signer: %s", err)
		}

		pk, err := ExtractAIK(speaker)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract the AIK from the signer: %s", err)
		}
		if err := tpm.VerifyQuote(pk, a.SerializedStatement, a.Signature, pcrNums, pcrVals); err != nil {
			return auth.Prin{}, newError("tao: TPM quote failed verification: %s", err)
		}

		return signer, nil
	case "key":
		// Signer is ECDSA key, use Tao signature verification.
		v, err := FromPrincipal(signer)
		if err != nil {
			return auth.Prin{}, err
		}
		ok, err := v.Verify(a.SerializedStatement, AttestationSigningContext, a.Signature)
		if err != nil {
			return auth.Prin{}, err
		}
		if !ok {
			return auth.Prin{}, newError("tao: attestation signature invalid")
		}
		return signer, nil
	default:
		return auth.Prin{}, newError("tao: attestation signer principal unrecognized: %s", signer.String())
	}
}
Exemple #2
0
// ValidSigner checks the signature on an attestation and, if so, returns the
// principal name for the signer.
func (a *Attestation) ValidSigner() (auth.Prin, error) {
	signer := auth.NewPrin(*a.SignerType, a.SignerKey)
	switch *a.SignerType {
	case "tpm":
		// The PCRs are contained in the Speaker of an auth.Says statement that
		// makes up the a.SerializedStatement.
		f, err := auth.UnmarshalForm(a.SerializedStatement)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err)
		}

		// A TPM attestation must be an auth.Says.
		says, ok := f.(auth.Says)
		if !ok {
			return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement")
		}

		// Signer is tpm; use tpm-specific signature verification. Extract the
		// PCRs from the issuer name, unmarshal the key as an RSA key, and call
		// tpm.VerifyQuote().
		speaker, ok := says.Speaker.(auth.Prin)
		if !ok {
			return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin")
		}
		pcrNums, pcrVals, err := extractPCRs(speaker)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err)
		}

		pk, err := extractTPMKey(a.SignerKey)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err)
		}
		if err := tpm.VerifyQuote(pk, a.SerializedStatement, a.Signature, pcrNums, pcrVals); err != nil {
			return auth.Prin{}, newError("tao: TPM quote failed verification: %s", err)
		}

		return signer, nil
	case "tpm2":
		// TODO -- tpm2
		// The PCRs are contained in the Speaker of an auth.Says statement that
		// makes up the a.SerializedStatement.
		f, err := auth.UnmarshalForm(a.SerializedStatement)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err)
		}

		// put this back in
		// A TPM attestation must be an auth.Says.
		says, ok := f.(auth.Says)
		if !ok {
			return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement")
		}

		// Signer is tpm; use tpm-specific signature verification. Extract the
		// PCRs from the issuer name, unmarshal the key as an RSA key, and call
		// tpm2.VerifyQuote().
		speaker, ok := says.Speaker.(auth.Prin)
		if !ok {
			return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin")
		}

		key, err := extractTPM2Key(a.SignerKey)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err)
		}
		pcrNums, pcrVal, err := extractTpm2PCRs(speaker)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err)
		}

		ok, err = tpm2.VerifyTpm2Quote(a.SerializedStatement,
			pcrNums, pcrVal, a.Tpm2QuoteStructure, a.Signature,
			key)
		if err != nil {
			return auth.Prin{}, newError("tao: TPM quote verification error")
		}
		if !ok {
			return auth.Prin{}, newError("tao: TPM quote failed verification")
		}
		return signer, nil
	case "key":
		// Signer is ECDSA key, use Tao signature verification.
		v, err := UnmarshalKey(a.SignerKey)
		if err != nil {
			return auth.Prin{}, err
		}
		ok, err := v.Verify(a.SerializedStatement, AttestationSigningContext, a.Signature)
		if err != nil {
			return auth.Prin{}, err
		}
		if !ok {
			return auth.Prin{}, newError("tao: attestation signature invalid")
		}
		return signer, nil
	default:
		return auth.Prin{}, newError("tao: attestation signer principal unrecognized: %s", signer.String())
	}
}