Exemple #1
0
        /// <summary>
        /// Process Message 1 and create Message 2
        /// </summary>
        /// <param name="Request">Client Provisioning request</param>
        /// <param name="sigmaSequenceCheck">Service Provider Sequence (State) Check</param>
        /// <returns>Message 2 content</returns>
        public M2ResponseMessage ProcessMessage1(HttpRequestMessage Request, SpSequenceCheck sigmaSequenceCheck)
        {
            log.Debug("ProcessMessage1(.) started.");

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

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

            // Check and parse Message 1
            M1RequestMessage m1Received = VerifyMessage1IsValid(Request, sigmaSequenceCheck);

            CalculateDiffieHellmanExchange(sigmaSequenceCheck, m1Received);

            // Successful process of Message 1
            // Create Message 2
            Msg2Builder       msgProcessor = new Msg2Builder();
            M2ResponseMessage msg2Response = msgProcessor.BuildMessage2(sigmaSequenceCheck, m1Received, gidBaString, gbXLittleEndian, gbYLittleEndian, sigSPXLittleEndian, sigSPYLittleEndian, cMACsmk);

            log.Debug("ProcessMessage1(.) returning.");
            return(msg2Response);
        }
        /// <summary>
        /// Process message 1 and create message 2 for the client
        /// </summary>
        /// <param name="data">Thread Data, input parameter (HttpRequestMessage) from the client</param>
        public void ProcessMessage(object data)
        {
            msg2Response = null;

            log.Debug("ProcessMessage(.) started.");

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

                HttpRequestMessage request = (HttpRequestMessage)data;

                mClient = ClientDatabase.GetTransaction(request, Constants.msg1Str);
                if (mClient == null)
                {
                    Exception 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.Debug("\n ***** State: Starting Message 1/2 sequence for client: " + mClient.ID + "\n");

                Msg1 m1 = new Msg1();
                M2ResponseMessage m2Response = m1.ProcessMessage1(request, mClient.sigmaSequenceCheck);

                // Set Client State
                msg2Response = m2Response;
            }
            catch (HttpResponseException re)
            {
                options.LogCaughtException(re);
                httpRE = re;
            }
            catch (Exception ex)
            {
                options.LogCaughtException(ex);
                threadException = ex;
            }
            finally
            {
                log.Debug("ProcessMessage(.) returning.");
            }
        }
        public async Task <IHttpActionResult> Msg1()
        {
            log.Debug("Msg1(.) started.");

            bool              error      = false;
            HttpStatusCode    errorCode  = System.Net.HttpStatusCode.InternalServerError;
            M2ResponseMessage m2Response = null;

            try
            {
                m2Response = await ClientDatabase.Message1(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 1/2: " + re.Message);
                errorCode = (HttpStatusCode)re.Response.StatusCode;
            }
            catch (Exception e)
            {
                error = true;
                log.Debug("******* M1 Content Error");
                log.Debug("Error: " + e.Message);
                errorCode = System.Net.HttpStatusCode.InternalServerError;
            }

            // Return response to client
            if (error)
            {
                log.DebugFormat("Msg1(.) returning HTTP status code {0}.", errorCode);
                try
                {
                    ClientDatabase.RemoveTransaction(this.Request, Constants.msg1Str);
                }
                catch (Exception e)  // This catches HttpResponseException also, which is what we want here
                {
                    log.Debug("Exception in Message 1/2 while error cleanup RemoveTransaction(): " + e.Message);
                }
                return(StatusCode(errorCode));
            }
            else
            {
                log.Debug("Msg1(.) returning HTTP status success.");
                return(Json(m2Response));
            }
        }
        /// <summary>
        /// Create a Message 2 for error condition
        /// </summary>
        /// <returns>Message 2 error message</returns>
        private M2ResponseMessage CreateErrorMessage(Exception errorMessage)
        {
            log.Debug("CreateErrorMessage(.) started.");

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

            // Handle the case where there is no HTTP response from IAS
            // There was a problem with the GET SigRL request - respond to Msg1 and abort the sequence.
            log.Debug("\n****** IAS GET Failure - aborting message sequence");
            log.DebugFormat("**** IAS Error **** \n{0}", errorMessage);
            log.Debug("******");
            // Create an "Empty" Msg2 instance to return error information
            M2ResponseMessage msg2ErrorMsg       = new M2ResponseMessage();
            string            msg2ErrorMsgString = msg2ErrorMsg.GetMsgString();

            // NOTE: Additional HTTP errors and exceptions should be handled here
            string exceptionString = errorMessage.InnerException.Message;

            switch (exceptionString)
            {
            case "An error occurred while sending the request.":
                msg2ErrorMsg.respHeader.respStatus = BitConverter.GetBytes((UInt32)RaSpRef.enStatusCodes.raErrIasUnknown);
                break;

            default:
                msg2ErrorMsg.respHeader.respStatus = BitConverter.GetBytes((UInt32)RaSpRef.enStatusCodes.raErrUnknown);
                break;
            }

            // Update the length field even though it should be the same as the default length.
            msg2ErrorMsg.respHeader.msgLength = BitConverter.GetBytes((UInt32)msg2ErrorMsgString.Length / 2);
            string msg2ErrorMsgJsonString = JsonConvert.SerializeObject(msg2ErrorMsg);

            log.Debug("****** Sending Msg2 Error Response");
            log.Debug("SigRL Response Status: " + BitConverter.ToString(msg2.respHeader.respStatus));
            log.Debug(msg2ErrorMsgJsonString);

            log.Debug("M2ResponseMessage(.) returning.");
            return(msg2ErrorMsg);
        }
        //Build an M2 response
        public void buildM2Response(out M2ResponseMessage m2Resp)
        {
            string respond = Constants.Respond;

            byte[] tempM2Bytes = { 0x00 };

            var m2Body     = new ResponseM2Body();
            var m2Response = new M2ResponseMessage(respond);


            //Populate message body components
            m2Response.respMsg2Body.gbX         = Constants.sampleGbXba;
            m2Response.respMsg2Body.gbY         = Constants.sampleGbYba;
            m2Response.respMsg2Body.spId        = SpStartup.iasConnectionMgr.SPID;
            m2Response.respMsg2Body.sigLinkType = Constants.sltype;
            m2Response.respMsg2Body.kdfId       = Constants.kdfId;

            //the m2 slReserved field is automatically initialized in the instance
            m2Response.respMsg2Body.sigSpX = Constants.sigSpXba;
            m2Response.respMsg2Body.sigSpY = Constants.sigSpYba;

            using (RNGCryptoServiceProvider nonceGen = new RNGCryptoServiceProvider())
            {
                if (nonceGen == null)
                {
                    Exception e = new Exception("Internal Error: nonceGen is Null");
                    options.LogThrownException(e);
                    throw e;
                }

                byte[] sessionNonce = Constants.sn2;
                nonceGen.GetBytes(sessionNonce);  //Generate a new nonce
                m2Response.respMsg2Body.cmacsmk   = sessionNonce;
                m2Response.respMsg2Body.sigrlSize = MsgInitValues.DS_EMPTY_BA4;
                m2Response.respMsg2Body.sigRl     = null;

                //Copy each reference to its output parameter
                m2Resp = m2Response;
            }

            return;
        }
        /// <summary>
        /// Builds Message 2 using connection IAS
        /// </summary>
        /// <param name="sigmaSequenceCheck">Service Provider Sequence (state) check</param>
        /// <returns>Boolean whether the message creation was successful or not</returns>
        private Boolean BuildIASMessage2(SpSequenceCheck sigmaSequenceCheck)
        {
            string iasGetRequestString = null;

            log.Debug("BuildIASMessage2(.) started.");

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

            try
            {
                log.Debug("Using IAS");

                // Get URI to IAS
                iasGetRequestString = SpStartup.iasConnectionMgr.iasUri + Constants.SigRLUri + _gidBaString;
                log.DebugFormat("Sending IAS GET Request using: {0}", iasGetRequestString);
            }
            catch (Exception getReqError)
            {
                options.LogCaughtErrorException(getReqError);

                log.Debug("Failed to get IAS Uri");

                // Copy error msg2 object to that which will be returned
                msg2 = CreateErrorMessage(getReqError);
                log.Debug("BuildIASMessage2(.) returning false.");
                return(false);
            }

            try
            {
                // Check connectivity with IAS Server

                // Use the received m1 as a trigger to check for a sigRL
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                int retryCount = Constants.retryCount;
                HttpResponseMessage iasSigRlResponse = null;
                byte[] internalError = BitConverter.GetBytes((UInt32)enStatusCodes.raErrIasInternal);
                while (retryCount-- > 0)
                {
                    // Instantiate an HttResponseMessage object for the GET SigRL request with IAS.
                    var iasResult = sigmaSequenceCheck.iasClient.GetAsync(iasGetRequestString);
                    iasSigRlResponse = iasResult.Result;

                    // retry if we have an internal IAS error
                    if (iasSigRlResponse.StatusCode == HttpStatusCode.InternalServerError)
                    {
                        log.Debug("IAS error. Retrying...");
                    }
                    else
                    {
                        break;
                    }
                }

                // Check for failure on max attempts
                if (iasSigRlResponse.StatusCode == HttpStatusCode.InternalServerError)
                {
                    throw new HttpResponseException(System.Net.HttpStatusCode.ServiceUnavailable);
                }

                log.DebugFormat("******* IAS GET Response:  {0}", iasSigRlResponse.ReasonPhrase);
                var    result       = iasSigRlResponse.Content.ReadAsStringAsync(); // Signature Revocation List response from IAS
                string nnSigRlInput = result.Result;

                Boolean error       = false;
                String  errorReason = "Unknown Error";

                // Check Signature Revocation List status code
                switch (iasSigRlResponse.StatusCode)
                {
                case HttpStatusCode.OK:
                {
                    // With a successful IAS GET Response, finish building Msg2.
                    // Decode the sigRl from the IAS response and populate the M2 sigRL fields,
                    // store GID, and ga until the Sigma sequence is complete.
                    //
                    // Update the M2 response fields for a successful response and add the SigRL
                    // if the IAS server returned a non-null list.
                    //
                    // m2 = gb||SPID||Quote Type||SigSP(gb||ga)||MACsmk(gb||SPID||Type||SigSP(gb||ga));SigRL

                    bMessage.buildM2Response(out msg2);
                    msg2.respHeader.respStatus = BitConverter.GetBytes((UInt32)enStatusCodes.raErrIasGetSuccess);

                    // We need endianness agreement between client and server for sending each message term.
                    // This protocol implementation assumes LittleEndian between client and server.
                    msg2.respMsg2Body.gbX         = _gbXLittleEndian;
                    msg2.respMsg2Body.gbY         = _gbYLittleEndian;
                    msg2.respMsg2Body.spId        = SpStartup.iasConnectionMgr.SPID;
                    msg2.respMsg2Body.sigLinkType = Constants.sltype;
                    msg2.respMsg2Body.kdfId       = Constants.kdfId;
                    msg2.respMsg2Body.sigSpX      = _sigSPXLittleEndian;
                    msg2.respMsg2Body.sigSpY      = _sigSPYLittleEndian;
                    msg2.respMsg2Body.cmacsmk     = _cMACsmk;

                    // Check for Null Signature Revocation List
                    if (iasSigRlResponse.Content.Headers.ContentLength == 0)
                    {
                        msg2.respMsg2Body.sigrlSize = MsgInitValues.DS_ZERO_BA4;
                        msg2.respMsg2Body.sigRl     = null;
                    }
                    else
                    {
                        // The SigRL can have a variable content length; so just accept the length from
                        // the IAS response as long as the size fits a predetermined practical size limit.
                        if (iasSigRlResponse.Content.Headers.ContentLength <= MsgFieldLimits.UINT32_PRACTICAL_SIZE_LIMIT)
                        {
                            msg2.respMsg2Body.sigrlSize = BitConverter.GetBytes((UInt32)iasSigRlResponse.Content.Headers.ContentLength);
                            // Parse non-null content and test with a non-null SigRL if IAS can deliver base64 encoded content similar to:
                            // AAIADgAAAAEAAAABAAAAAHPUffSvHLYJc1GcvVLdoHZSfTo1qY7YqCtL3lqnWz4WI/JeLqDkU7eXpm5tdn1PoXEULgOSPJA8DJigmj4rBEU=
                            // NOTE: testing was done with simulated content as shown above.
                            //////////////////////////////////////////////////////////
                            byte[] nnSigRlBa = null;
                            nnSigRlBa = Convert.FromBase64String(nnSigRlInput);
                            msg2.respMsg2Body.sigrlSize = BitConverter.GetBytes((UInt32)nnSigRlBa.Length);          // Report the length of the actual SigRl data, not the base64 string
                            msg2.respMsg2Body.sigRl     = nnSigRlBa;
                            //////////////////////////////////////////////////////////
                        }
                        else         //Signature Revocation List is too big; May allow for larger sizes
                        {
                            log.Debug("****** Error SigRL Exceeds Internal Limit ******");
                            break;
                        }
                    }

                    // Update the length field in the message header
                    msg2.respHeader.msgLength = BitConverter.GetBytes((UInt32)msg2.GetMsgString().Length / 2);
                    // Update the state machine
                    // Capture the message nonce as the "current nonce"
                    msg2.respHeader.sessionNonce = sigmaSequenceCheck.currentNonce;
                    // Complete the state transition
                    sigmaSequenceCheck.m1Received = true;
                    string msg2JsonString = JsonConvert.SerializeObject(msg2);
                    log.Debug("*********** Msg1 Processing Complete - Sending Msg2");
                    log.DebugFormat("{0}", msg2JsonString);
                    break;
                }

                case HttpStatusCode.Unauthorized:
                {
                    msg2.respHeader.respStatus = BitConverter.GetBytes((UInt32)RaSpRef.enStatusCodes.raErrIasUnauth);
                    errorReason = "****** Sending Msg2 \"Unauthorized\" Error Response";
                    break;
                }

                case HttpStatusCode.NotFound:
                {
                    msg2.respHeader.respStatus = BitConverter.GetBytes((UInt32)RaSpRef.enStatusCodes.raErrIasNotFound);
                    errorReason = "****** Sending Msg2 \"Not Found\" Error Response";
                    break;
                }

                case HttpStatusCode.InternalServerError:        // This should never be executed
                {
                    msg2.respHeader.respStatus = BitConverter.GetBytes((UInt32)RaSpRef.enStatusCodes.raErrIasInternal);
                    errorReason = "****** Sending Msg2 \"Internal Server Error\" Error Response";
                    break;
                }

                default:
                {
                    msg2.respHeader.respStatus = BitConverter.GetBytes((UInt32)RaSpRef.enStatusCodes.raErrUnknown);
                    errorReason = "****** Sending Msg2 \"Unknown\" Error Response";
                    break;
                }
                }

                // Print messages on error
                if (error)
                {
                    string msg2ErrorMsgString = msg2.GetMsgString();
                    msg2.respHeader.protocolVer = MsgInitValues.PROTOCOL;
                    msg2.respHeader.msgLength   = BitConverter.GetBytes((UInt32)msg2ErrorMsgString.Length / 2);
                    string msg2ErrorMsgJsonString = JsonConvert.SerializeObject(msg2);

                    log.Debug(errorReason);
                    log.Debug("SigRL Response Status: " + BitConverter.ToString(msg2.respHeader.respStatus));
                    log.DebugFormat("{0}", msg2ErrorMsgJsonString);
                }

                iasSigRlResponse.Dispose();
            }
            catch (HttpResponseException)
            {
                // This catch block is to prevent subsequent catch blocks from catching HttpResponseExceptions.
                // Because we are using Visual Studio 2012, we are limited to an older version of the C#
                // language that does not support exception filters. When C# 6 is available to us, it may
                // be decided that exception filters are a better solution than this catch block.
                throw;
            }
            catch (Exception getReqError)
            {
                // Copy error msg2 object to that which will be returned
                msg2 = CreateErrorMessage(getReqError);
                log.Debug("BuildIASMessage2(.) returning false.");
                return(false);
            }

            // Success
            log.Debug("BuildIASMessage2(.) returning true.");
            return(true);
        }