in server/server.go [313:399]
func (s *SecureSessionService) NegotiateAttestation(ctx context.Context, req *sspb.NegotiateAttestationRequest) (*sspb.NegotiateAttestationResponse, error) {
if err := s.verifyToken(ctx); err != nil {
return nil, fmt.Errorf("failed to verify JWT: %w", err)
}
connID := base64.StdEncoding.EncodeToString(req.SessionContext)
ch, found := s.channels[connID]
if !found {
return nil, fmt.Errorf("session with id: %v not found", connID)
}
if ch.state != ServerStateHandshakeCompleted {
return nil, fmt.Errorf("session with id: %v in unexpected state: %d. Expecting: %d", connID, ch.state, ServerStateHandshakeCompleted)
}
if len(req.OfferedEvidenceTypesRecords) == 0 {
return nil, fmt.Errorf("TLS records were empty")
}
ch.shim.QueueReceiveBuf(req.OfferedEvidenceTypesRecords)
buf := make([]byte, len(req.OfferedEvidenceTypesRecords))
bufLen, err := ch.conn.Read(buf)
if err != nil {
ch.state = ServerStateFailed
return nil, fmt.Errorf("failed to read client's OfferedEvidenceTypeRecords message from tls connection : %v", err)
}
var clientAttList attpb.AttestationEvidenceTypeList
err = proto.Unmarshal(buf[:bufLen], &clientAttList)
if err != nil {
ch.state = ServerStateFailed
return nil, fmt.Errorf("failed to unmarshal AttestationEvidenceTypeList: %v", err)
}
serverSelection := attpb.AttestationEvidenceTypeList{}
offeredMap := make(map[attpb.AttestationEvidenceType]bool)
for _, tp := range clientAttList.Types {
switch tp {
case attpb.AttestationEvidenceType_NULL_ATTESTATION:
offeredMap[attpb.AttestationEvidenceType_NULL_ATTESTATION] = true
case attpb.AttestationEvidenceType_TPM2_QUOTE:
offeredMap[attpb.AttestationEvidenceType_TPM2_QUOTE] = true
case attpb.AttestationEvidenceType_TCG_EVENT_LOG:
offeredMap[attpb.AttestationEvidenceType_TCG_EVENT_LOG] = true
}
}
if offeredMap[attpb.AttestationEvidenceType_TCG_EVENT_LOG] != offeredMap[attpb.AttestationEvidenceType_TPM2_QUOTE] {
return nil, errors.New("if offering either the TPM2 Quote or the TCG Event Log, must offer both")
}
if offeredMap[attpb.AttestationEvidenceType_TPM2_QUOTE] {
serverSelection.Types = []attpb.AttestationEvidenceType{attpb.AttestationEvidenceType_TPM2_QUOTE, attpb.AttestationEvidenceType_TCG_EVENT_LOG}
} else if offeredMap[attpb.AttestationEvidenceType_NULL_ATTESTATION] {
serverSelection.Types = []attpb.AttestationEvidenceType{attpb.AttestationEvidenceType_NULL_ATTESTATION}
}
if len(serverSelection.Types) == 0 {
return nil, fmt.Errorf("unable to negotiate any acceptable attestation evidence types")
}
ch.attestationEvidenceTypes = serverSelection.Types
buf, err = proto.Marshal(&serverSelection)
if err != nil {
ch.state = ServerStateFailed
return nil, fmt.Errorf("failed to marshal server's AttestationEvidenceTypeList: %v", err)
}
go func() {
_, err := ch.conn.Write(buf)
if err != nil {
ch.state = ServerStateFailed
glog.Warningf("server failed to send selected evidence via TLS connection: %v", err.Error())
}
}()
rep := &sspb.NegotiateAttestationResponse{}
rep.RequiredEvidenceTypesRecords = ch.shim.DrainSendBuf()
ch.state = ServerStateAttestationNegotiated
return rep, nil
}