/// <summary>
        /// Continue transaction for Message 3/4 sequence
        /// </summary>
        /// <param name="request">Client Message 3 response/4 request</param>
        public static async Task <M4ResponseMessage> Message3(HttpRequestMessage request)
        {
            log.Debug("Message3(.) started.");

            if (request == null)
            {
                HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError);
                options.LogThrownException(e);
                throw e;
            }

            M4ResponseMessage m4Response = null;

            try
            {
                ClientTransaction mClient = GetTransaction(request, Constants.msg3Str);
                if (mClient == null)
                {
                    HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError);
                    options.LogThrownException(e);
                    throw e;
                }

                // kill client wait thread so we don't time out.
                mClient.killTimerThread();

                // NOTE: There is a potential race-condition where the client is removed from the database during the time that the cilent sends its response
                // Can choose to check to re-add the client here in that case

                log.Info("\n ***** State: Starting Message 3/4 sequence for client: " + mClient.ID + "\n");

                Msg3 msg3 = new Msg3();
                m4Response = await msg3.ProcessMessage3(request, mClient.sigmaSequenceCheck);

                log.Debug("Message3(.) returning.");
            }
            catch (HttpResponseException)
            {
                throw;
            }
            catch (Exception e)
            {
                log.Debug("Error processing Message 3/4. " + e.Message);
            }

            // Return challenge to client
            return(m4Response);
        }
        //Buid an M4 response
        public void buildM4Response(out M4ResponseMessage m4Resp)
        {
            string respond    = Constants.Respond;
            var    m4Response = new M4ResponseMessage(respond);
            var    m4Body     = new ResponseM4Body();

            m4Body.platformInfo = null;

            //m4Body.pltfrmInfoRsrvd handled by instantiation
            m4Body.attestationStatus   = MsgInitValues.DS_ZERO_BA4;
            m4Body.cmacStatus          = MsgInitValues.DS_ZERO_BA16;
            m4Body.isvCryptPayloadSize = MsgInitValues.DS_ZERO_BA4;

            m4Body.isvClearPayloadSize = MsgInitValues.DS_ZERO_BA4;

            m4Body.CryptIv          = null;
            m4Body.isvPayloadTag    = null;
            m4Body.isvPayload       = null;
            m4Response.respMsg4Body = m4Body;
            m4Resp = m4Response;
            return;
        }
Exemple #3
0
        /// <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);
        }
        public async Task <IHttpActionResult> Msg3()
        {
            log.Debug("SpSequenceCheck(.) started.");

            bool              error      = false;
            HttpStatusCode    errorCode  = System.Net.HttpStatusCode.InternalServerError;
            M4ResponseMessage m4Response = null;

            try
            {
                m4Response = await ClientDatabase.Message3(this.Request);
            }
            catch (WebException we)
            {
                error = true;
                log.Debug("Web Exception in Provisioning Request: " + we.Message);
                HttpWebResponse webResponse = we.Response as HttpWebResponse;
                errorCode = (HttpStatusCode)webResponse.StatusCode;
            }
            catch (HttpResponseException re)
            {
                error = true;
                log.Debug("HttpResponseException in Message 3/4: " + re.Message);
                errorCode = (HttpStatusCode)re.Response.StatusCode;
            }
            catch (Exception e)
            {
                error = true;
                log.Debug("Error occurred processing Message 3 or 4. " + e.Message);
                errorCode = System.Net.HttpStatusCode.InternalServerError;
            }

            // always cleanup database on Message 4
            try
            {
                ClientDatabase.RemoveTransaction(this.Request, Constants.msg3Str);
            }
            catch (HttpResponseException re)
            {
                log.Debug("HttpResponseException in Message 3/4 RemoveTransaction: " + re.Message);
                if (!error)
                {
                    error     = true;
                    errorCode = (HttpStatusCode)re.Response.StatusCode;
                }
            }
            catch (Exception e)
            {
                log.Debug("Error occurred processing Message 3 or 4 RemoveTransaction: " + e.Message);
                if (!error)
                {
                    error     = true;
                    errorCode = System.Net.HttpStatusCode.InternalServerError;
                }
            }

            if (error)
            {
                log.DebugFormat("Msg3(.) returning HTTP status code {0}.", errorCode);
                return(StatusCode(errorCode));
            }
            else
            {
                log.Debug("Msg3(.) returning HTTP status success.");
                return(Json(m4Response));
            }
        }