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
}