func()

in client/securesession/securesession.go [326:400]


func (c *SecureSessionClient) negotiateAttestation(ctx context.Context) (ret error) {
	req := &pb.NegotiateAttestationRequest{
		SessionContext: c.ctx,
	}

	// The client should always support null attestations.
	evidenceTypes := &aepb.AttestationEvidenceTypeList{
		Types: []aepb.AttestationEvidenceType{aepb.AttestationEvidenceType_NULL_ATTESTATION},
	}

	// Attempt to re-escalate execution privileges.
	if err := tryReescalatePrivileges(); err != nil {
		return fmt.Errorf("failed to re-escalate to root privileges to open TPM device: %w", err)
	}
	defer func() {
		// If failed to deescalate and there are no other errors, override the return.
		if err := tryDeescalatePrivileges(); err != nil && ret == nil {
			ret = fmt.Errorf("failed to de-escalate to user privileges: %v", err)
		}
	}()

	if _, err := tpm2.OpenTPM("/dev/tpmrm0"); err != nil {
		glog.InfoContextf(ctx, "TPM not available. Using null attestation")
	} else if _, err = os.Stat(eventLogFile); errors.Is(err, os.ErrNotExist) {
		// If the TPM is available but event log is not, log and continue with null attestation.
		glog.ErrorContextf(ctx, "TPM is available but Event Log is not. Using null attestation.")
	} else {
		// If both TPM and Event Log are available, add to supported evidence types.
		evidenceTypes.Types = append(evidenceTypes.Types, aepb.AttestationEvidenceType_TPM2_QUOTE)
		evidenceTypes.Types = append(evidenceTypes.Types, aepb.AttestationEvidenceType_TCG_EVENT_LOG)

		// Communicate to the server the nonce types that we support.
		evidenceTypes.NonceTypes = append(evidenceTypes.NonceTypes, aepb.NonceType_NONCE_EKM32)
	}

	// Write marshalled attestation evidence to TLS channel.
	marshaledEvidenceTypes, err := proto.Marshal(evidenceTypes)
	if err != nil {
		return fmt.Errorf("error marshalling evidence to proto: %v", err)
	}

	if _, err := c.tls.Write(marshaledEvidenceTypes); err != nil {
		return fmt.Errorf("error writing evidence to TLS connection: %v", err)
	}

	// Capture the TLS session-protected records and send them over the RPC.
	req.OfferedEvidenceTypesRecords = c.shim.DrainSendBuf()

	resp, err := c.client.NegotiateAttestation(ctx, req)
	if err != nil {
		return fmt.Errorf("error negotiating attestation with client: %v", err)
	}

	// Decode the records that the server responded with to figure out what
	// attestation evidence is appropriate for the finalize step. This involves
	// writing the session-encrypted records back to the TLS client.
	evidenceRecords := resp.GetRequiredEvidenceTypesRecords()
	c.shim.QueueReceiveBuf(evidenceRecords)

	readBuf := make([]byte, recordBufferSize)
	n, err := c.tls.Read(readBuf)

	if err != nil {
		return fmt.Errorf("error reading data from TLS connection: %v", err)
	}

	// Unmarshal the response written back from the TLS intercept.
	c.attestationTypes = &aepb.AttestationEvidenceTypeList{}
	if err = proto.Unmarshal(readBuf[:n], c.attestationTypes); err != nil {
		return fmt.Errorf("error parsing attestation types into a proto: %v", err)
	}

	c.state = clientStateAttestationNegotiated
	return nil
}