/// <summary> /// Build Message 2 /// </summary> /// <param name="sigmaSequenceCheck">Service Provider Sequence (State) Check</param> /// <param name="m1Received">Message 1</param> /// <returns>Message 2 Repsonse to Client</returns> public M2ResponseMessage BuildMessage2(SpSequenceCheck sigmaSequenceCheck, M1RequestMessage m1Received, String gidBaString, byte[] gbXLittleEndian, byte[] gbYLittleEndian, byte[] sigSPXLittleEndian, byte[] sigSPYLittleEndian, byte[] cMACsmk) { log.Debug("BuildMessage2(.) started."); if (sigmaSequenceCheck == null || m1Received == null) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(e); throw e; } // Update Client state if (!sigmaSequenceCheck.UpdateState(Constants.SequenceState.Msg2)) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.PreconditionFailed); options.LogThrownException(e); throw e; } SetDiffieHellmanExchange(gidBaString, gbXLittleEndian, gbYLittleEndian, sigSPXLittleEndian, sigSPYLittleEndian, cMACsmk); // Check that Diffie Hellman values are initialized if (!initialized) { return(null); } log.Debug("Building message 2"); if (SpStartup.iasConnectionMgr.UseIAS) { // Connect to IAS for Signature Revocation List BuildIASMessage2(sigmaSequenceCheck); } else { // Simulate IAS // For testing the SGX client connection only, override the IAS connection settings by setting "UseIAS" to false. // This setting should be temporary, and once the SGX messaging is working, set "UseIAS" to true. BuildNonIasMessage2(sigmaSequenceCheck); } log.Debug("BuildMessage2(.) returning."); return(msg2); }
/// <summary> /// Verify that Message 1 is valid /// </summary> /// <param name="Request">Client Message 1 Response</param> /// <param name="sigmaSequenceCheck">Service Provider Sequence (State) Check</param> /// <returns>Parsed and validated Message 1</returns> private M1RequestMessage VerifyMessage1IsValid(HttpRequestMessage request, SpSequenceCheck sigmaSequenceCheck) { log.Debug("VerifyMessage1IsValid(.) started."); if (request == null || sigmaSequenceCheck == null) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(e); throw e; } // Update Client state if (!sigmaSequenceCheck.UpdateState(Constants.SequenceState.Msg1)) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.PreconditionFailed); options.LogThrownException(e); throw e; } // Check m1 and if valid, process, create a nonce, get the sigRL and return m2. // M1 = msg1 = m1 = s1 = ga||GID var result = request.Content.ReadAsStringAsync(); string jsonMsg1Request = result.Result; M1RequestMessage m1Received = new M1RequestMessage(); try { m1Received = JsonConvert.DeserializeObject <M1RequestMessage>(jsonMsg1Request); } catch (Exception msg1reqError) { options.LogCaughtErrorException(msg1reqError); log.DebugFormat("******* Message 1 JSON Content Error: {0}", msg1reqError); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(e); throw e; } string m1ReceivedString = m1Received.GetMsgString(); log.Info("******* Received M1 Request"); log.DebugFormat("{0}{1}", request.Headers, jsonMsg1Request); log.DebugFormat("M1 Base 16 Encoded String: {0}", m1ReceivedString); // Check the nonce and the base16 encoded length of the inbound request bool nonceCheckSuccess = false; try { log.Debug("Checking nonce"); nonceCheckSuccess = sigmaSequenceCheck.currentNonce.SequenceEqual(m1Received.reqHeader.nonce); } catch (Exception e) { options.LogCaughtErrorException(e); log.DebugFormat("****Message 1 Nonce Error: {0}", e); HttpResponseException newException = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(newException); throw newException; } if (!nonceCheckSuccess) { log.Debug("Msg1 Nonce check failed"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Compare the reported length against the actual length (base16 string length/2) // Could BigEndian a replay attempt if the nonce field does not match. // Could also be other tampering if other fields do not pass checks. // Restart the session, and reject the request. if (!(BitConverter.ToUInt32(m1Received.reqHeader.msgLength, 0) == (m1ReceivedString.Length / 2))) { log.Debug("Msg1 Message length check failed"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } if (m1Received.reqM1Body.gaX.SequenceEqual(MsgInitValues.DS_EMPTY_BA32)) { log.Debug("Msg1 GaX check failed"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } if (m1Received.reqM1Body.gaY.SequenceEqual(MsgInitValues.DS_EMPTY_BA32)) { log.Debug("Msg1 GaY check failed"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } if (m1Received.reqM1Body.pltfrmGid.SequenceEqual(MsgInitValues.DS_EMPTY_BA32)) { log.Debug("Msg1 Platform Group ID check failed"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } log.Debug("VerifyMessage1IsValid(.) returning."); return(m1Received); }
/// <summary> /// Process Message 3 and Build Message 4 /// </summary> /// <param name="Request">Message 3 Client Response</param> /// <param name="sigmaSequenceCheck">Service Provider Sequence (State) Check</param> /// <returns>Message 4 Repsonse to Client</returns> public async Task <M4ResponseMessage> ProcessMessage3(HttpRequestMessage Request, SpSequenceCheck sigmaSequenceChk) { log.Debug("ProcessMessage3(.) started."); if (Request == null || sigmaSequenceChk == null) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.PreconditionFailed); options.LogThrownException(e); throw e; } sigmaSequenceCheck = sigmaSequenceChk; // Update Client state if (!sigmaSequenceCheck.UpdateState(Constants.SequenceState.Msg3)) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.PreconditionFailed); options.LogThrownException(e); throw e; } var result = Request.Content.ReadAsStringAsync(); string jsonMsg3Request = result.Result; M3RequestMessage m3Received = new M3RequestMessage(); try { // Attempt to parse request in message 3 m3Received = JsonConvert.DeserializeObject <M3RequestMessage>(jsonMsg3Request); } catch (Exception msg3ReqError) { log.DebugFormat("******* Message 3 JSON Content Error: {0}", msg3ReqError); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(e); throw e; } if (m3Received == null) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.PreconditionFailed); options.LogThrownException(e); throw e; } // Check the nonce and the base16 encoded length of the inbound request string m3ReceivedString = m3Received.GetMsgString(); log.Info("******* Received M3 Request"); log.DebugFormat("{0}{1}", Request.Headers, jsonMsg3Request); log.DebugFormat("M3 Base16 Encoded String: {0}", m3ReceivedString); // If failed a check, throw an error // Getting to this point means there was a problem with the M3 content (including possible quote check failure). // Reset the state machine and return "Forbidden" // Check whether to use Nonce or not, and is valid bool nonceCheck = sigmaSequenceCheck.currentNonce.SequenceEqual(m3Received.reqHeader.nonce); if (!nonceCheck) { log.Debug("Invalid Message 3 Nonce"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Check the message has the correct length bool lengthCheck = CheckMessageLength(m3Received, m3ReceivedString); if (!lengthCheck) { log.Debug("Invalid Message 3 Length"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Check the M3 components & Ga byte[] m3Ga = new byte[m3Received.reqM3Body.gaX.Length + m3Received.reqM3Body.gaY.Length]; System.Buffer.BlockCopy(m3Received.reqM3Body.gaX, 0, m3Ga, 0, m3Received.reqM3Body.gaX.Length); System.Buffer.BlockCopy(m3Received.reqM3Body.gaY, 0, m3Ga, m3Received.reqM3Body.gaX.Length, m3Received.reqM3Body.gaY.Length); string m3GaStr = bMessage.BaToBlobStr(m3Ga); string currentGaStr = bMessage.BaToBlobStr(sigmaSequenceCheck.currentGa); // Check the ga is correct bool gaCheck = CheckGa(currentGaStr, m3GaStr); if (!gaCheck) { log.Debug("Invalid Message 3 ga"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Check that the CMAC is correct bool cmacCheck = CheckCmac(m3Received, m3GaStr); if (!cmacCheck) { log.Debug("Invalid Message 3 CMAC"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } string m3QuoteStr = bMessage.BaToBlobStr(m3Received.reqM3Body.quote); if (String.IsNullOrEmpty(m3QuoteStr)) { log.Debug("Message 3 Quote is NULL"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Get MRSIGNER and ISVPRODID from the Quote to find the correct enclave type from Enclave.json string MRSIGNERString = m3QuoteStr.Substring((int)Constants.QuoteInfo.MRSIGNEROffset * 2, Constants.QuoteInfo.MRSIGNERSize * 2); // MR Enclave String from Quote log.InfoFormat("Quote came from enclave with MRSIGNER: {0}", MRSIGNERString); ushort ISVPRODID = (ushort)BitConverter.ToInt16(bMessage.BlobStrToBa(m3QuoteStr.Substring((int)Constants.QuoteInfo.ISVPRODIDOffset * 2, 4)), 0); log.DebugFormat("ISVPRODID:\t{0}", ISVPRODID); sigmaSequenceCheck.SetEnclaveType(MRSIGNERString, ISVPRODID); bool quoteOk = CheckQuoteOk(m3Received, m3QuoteStr, currentGaStr); if (!quoteOk) { log.Debug("Invalid Message 3 Quote"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Check whether using Debug quote or not bool debugCheck = CheckDebug(m3QuoteStr); if (!debugCheck) { log.Debug("Invalid Message 3 - Using Debug or Production quote when opposite is expected"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Check Signature Type bool sigTypeCheck = CheckSignatureType(m3QuoteStr); if (!sigTypeCheck) { log.Debug("Invalid Message 3 Signature"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Check ISV SVN bool isvSVNCheck = CheckISVSVN(m3QuoteStr); if (!isvSVNCheck) { log.Debug("Invalid Message 3 ISV SVN"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Successful // At this point, we know that a valid message 3 was received and we can send the quote to IAS. // Complete the state transition. M4ResponseMessage msg4Respsonse = new M4ResponseMessage(); try { sigmaSequenceCheck.m3Received = true; Msg4Builder msgProcessor = new Msg4Builder(); msg4Respsonse = await msgProcessor.BuildMessage4(sigmaSequenceCheck, m3Received); } catch (HttpRequestException re) { options.LogCaughtErrorException(re); log.Debug("Failed to create Message 4. " + re.Message); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(e); throw e; } log.Debug("ProcessMessage3(.) returning."); return(msg4Respsonse); }
/// <summary> /// Verify that Message 0 is valid /// </summary> /// <param name="Request">Client Message 0 Response</param> /// <param name="sigmaSequenceCheck">Service Provider Sequence (State) Check</param> /// <returns>Parsed and validated Message 0</returns> private M0RequestMessage VerifyMessage0IsValid(HttpRequestMessage request, SpSequenceCheck sigmaSequenceCheck) { log.Debug("VerifyMessage0IsValid(.) started."); if (request == null || sigmaSequenceCheck == null) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(e); throw e; } // Update Client state if (!sigmaSequenceCheck.UpdateState(Constants.SequenceState.Msg0)) { HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.PreconditionFailed); options.LogThrownException(e); throw e; } // Check m0 and if valid, process var result = request.Content.ReadAsStringAsync(); string jsonMsg0Request = result.Result; M0RequestMessage m0Received = new M0RequestMessage(); try { m0Received = JsonConvert.DeserializeObject <M0RequestMessage>(jsonMsg0Request); } catch (Exception msg0reqError) { options.LogCaughtErrorException(msg0reqError); log.DebugFormat("******* Message 0 JSON Content Error: {0}", msg0reqError); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(e); throw e; } string m0ReceivedString = m0Received.GetMsgString(); log.Info("******* Received M0 Request"); log.DebugFormat("{0}{1}", request.Headers, jsonMsg0Request); log.DebugFormat("M0 Base 16 Encoded String: {0}", m0ReceivedString); // Check the nonce and the base16 encoded length of the inbound request bool nonceCheckSuccess = false; try { log.Debug("Checking nonce"); nonceCheckSuccess = sigmaSequenceCheck.currentNonce.SequenceEqual(m0Received.reqHeader.nonce); } catch (Exception e) { options.LogCaughtErrorException(e); log.DebugFormat("****Message 0 Nonce Error: {0}", e); HttpResponseException newException = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError); options.LogThrownException(newException); throw newException; } if (!nonceCheckSuccess) { log.Debug("Msg0 Nonce check failed"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // Compare the reported length against the actual length (base16 string length/2) // Could BigEndian a replay attempt if the nonce field does not match. // Could also be other tampering if other fields do not pass checks. // Restart the session, and reject the request. if (!(BitConverter.ToUInt32(m0Received.reqHeader.msgLength, 0) == (m0ReceivedString.Length / 2))) { log.Debug("Msg0 Message length check failed"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } if (m0Received.reqM0Body.ExtGID.SequenceEqual(MsgInitValues.DS_EMPTY_BA4)) { log.Debug("Msg0: Extended GID wasn't sent"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Forbidden); options.LogThrownException(e); throw e; } // NOTE: Extended GID = 0 indicates that IAS is selected for enclave verification. // This Service Provider only supports IAS for enclave verification at this time. // Note to ISV: if non-Intel Attestation Service (i.e. Extended GID != 0) is being used, replace this logic // to point to your service. if (!m0Received.reqM0Body.ExtGID.SequenceEqual(MsgInitValues.DS_ZERO_BA4)) { log.Debug("Msg0: Invalid Extended GID. This server only processes Extended GID = 0"); HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.Unauthorized); options.LogThrownException(e); throw e; } log.Debug("VerifyMessage0IsValid(.) returning."); return(m0Received); }