Ejemplo n.º 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);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Build Message 2 response for Non-IAS Connection; Used for Debug only
        /// </summary>
        /// <returns>Message 2 response to client</returns>
        private void BuildNonIasMessage2(SpSequenceCheck sigmaSequenceCheck)
        {
            // NOTE: This debugging path bypasses the IAS connection and ignores the SigRL.
            // This path is intended for temporary testing of the sigma messaging with the SGX client.
            //
            // Production Server MUST use the IAS connection for a secure check of the enclave.
            // Update the M2 response fields and add a null SigRL for this debug path.
            // m2 = gb||SPID||Quote Type||SigSP(gb||ga)||MACsmk(gb||SPID||Type||SigSP(gb||ga));SigRL

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

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

            bMessage.buildM2Response(out msg2);
            msg2.respHeader.respStatus = BitConverter.GetBytes((UInt32)enStatusCodes.raErrIasGetSuccess);
            if (SpStartup.iasConnectionMgr.SPID.Length != 16)
            {
                HttpResponseException e = new HttpResponseException(System.Net.HttpStatusCode.PreconditionFailed);
                options.LogThrownException(e);
                throw e;
            }

            // We need endianness agreement between client and server for sending each message term
            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;

            // Since this debug path does not include a dialog with the IAS server,
            // there is no sigRL to retrieve.
            // Build the sigRL message fields to reflect a sigRL of zero length.
            msg2.respMsg2Body.sigrlSize = MsgInitValues.DS_ZERO_BA4;
            msg2.respMsg2Body.sigRl     = null;
            msg2.respHeader.msgLength   = BitConverter.GetBytes((UInt32)msg2.GetMsgString().Length / 2);

            msg2.respHeader.sessionNonce  = sigmaSequenceCheck.currentNonce;
            sigmaSequenceCheck.m1Received = true;

            string msg2JsonString = JsonConvert.SerializeObject(msg2);

            log.Info("*********** Msg1 Processing Complete - Sending Msg2");
            log.DebugFormat("Msg2 JSON String: {0}", msg2JsonString);
            log.DebugFormat("Msg2 16bit encoded string: {0}", msg2.GetMsgString());

            log.Debug("BuildNonIasMessage2(.) returning.");
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Process Message 0
        /// </summary>
        /// <param name="Request">Client Provisioning request</param>
        /// <param name="sigmaSequenceCheck">Service Provider Sequence (State) Check</param>
        /// <returns>Message 0 response</returns>
        public M0ResponseMessage ProcessMessage0(HttpRequestMessage Request, SpSequenceCheck sigmaSequenceCheck)
        {
            log.Debug("ProcessMessage0(.) 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 0
            M0RequestMessage m0Received = VerifyMessage0IsValid(Request, sigmaSequenceCheck);

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

            M0ResponseMessage msg0Response = new M0ResponseMessage();

            msg0Response.respHeader.sessionNonce = m0Received.reqHeader.nonce;

            // Successful process of Message 0
            log.Debug("ProcessMessage0(.) returning.");
            return(msg0Response);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Calculate values for Diffie Hellman values
        /// </summary>
        /// <param name="sigmaSequenceCheck">Service Provider Sequence (State) Check</param>
        /// <param name="m1Received">Message 1</param>
        private void CalculateDiffieHellmanExchange(SpSequenceCheck sigmaSequenceCheck, M1RequestMessage m1Received)
        {
            log.Debug("CalculateDiffieHellmanExchange(..) started.");

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

            // (Intel Performance Primitives) IPP Wrapper
            ippApiWrapper ippWrapper = new ippApiWrapper();

            // Process message 1 and build the message 2 response.
            // Capture the GID and Base16 encode the gid field per the IAS API specificaiton:
            // "{gid} = Base 16-encoded representation of QE EPID group ID encoded as a Little Endian integer".
            // NOTE: This conversion assumes that the GID was sent without modification in the "pltfrmGid" message field.

            byte[] gidBa = m1Received.reqM1Body.pltfrmGid;

            // Required that the GID is supplied with no conversions from the SGX client and reverse the byte order
            // to convert to Big Endian integer for use later in the routine when encoding as a Base 16 string.
            Array.Reverse(gidBa);
            gidBaString = bMessage.BaToBlobStr(gidBa);

            // In crypto terms, a = Alice (Client) and b = Bob (Service provider)
            //  so ga = secret shared by client and gb = secret shared by service provide

            gaLittleEndianstr = m1Received.GetGaString();  // Received in Little Endian format

            gaXLittleEndianstr = "";
            // ga = gaX|gaY -- take the first half of ga to get gaX
            if (gaLittleEndianstr != null)
            {
                gaXLittleEndianstr = gaLittleEndianstr.Substring(0, gaLittleEndianstr.Length / 2);
            }

            gaXLittleEndian = bMessage.BlobStrToBa(gaXLittleEndianstr);
            gaXBigEndian    = bMessage.BlobStrToBa(gaXLittleEndianstr);
            Array.Reverse(gaXBigEndian, 0, gaXBigEndian.Length);
            gaXBigEndianstr = bMessage.BaToBlobStr(gaXBigEndian);

            gaYLittleEndianstr = "";
            if (gaLittleEndianstr != null)
            {
                gaYLittleEndianstr = gaLittleEndianstr.Substring(gaLittleEndianstr.Length / 2);
            }

            gaYLittleEndian = bMessage.BlobStrToBa(gaYLittleEndianstr);
            gaYBigEndian    = bMessage.BlobStrToBa(gaYLittleEndianstr);
            Array.Reverse(gaYBigEndian, 0, gaYBigEndian.Length);
            gaYBigEndianstr = bMessage.BaToBlobStr(gaYBigEndian);

            // Capture the Little Endian representation of ga for later message checking
            sigmaSequenceCheck.currentGa = bMessage.BlobStrToBa(gaXLittleEndianstr + gaYLittleEndianstr);
            {
                // Use IPP or some other alternative if the user configuration does not select MS bcrypt for Diffie-Hellman key exchange.
                // NOTE: The use of IPP allows for the use of the standard wrapper functions in the SGX SDK.
                log.Debug("Calling IPP Wrapper for Diffie-Hellman key exchange...");
                ippWrapper.InitDiffieHellman();
                ippWrapper.GetDHPublicKey(ref gbXLittleEndian, ref gbYLittleEndian);
                gbXLittleEndianstr           = bMessage.BaToBlobStr(gbXLittleEndian);
                gbYLittleEndianstr           = bMessage.BaToBlobStr(gbYLittleEndian);
                gbLittleEndianStr            = string.Concat(gbXLittleEndianstr, gbYLittleEndianstr);
                sigmaSequenceCheck.currentGb = bMessage.BlobStrToBa(gbXLittleEndianstr + gbYLittleEndianstr);
                log.DebugFormat("Server Public key: {0}", gbLittleEndianStr);
                // Derive the shared key
                byte[] sharedKey256 = new byte[Constants.SharedKeylen];
                ippWrapper.GetDHSharedSecret(gaXLittleEndian, gaYLittleEndian, ref sharedKey256);
                derivedKeyStr = bMessage.BaToBlobStr(sharedKey256);
                log.DebugFormat("Shared secret: {0}", derivedKeyStr);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Use the full 256 bits of the derived DH key to further derive our smk
            //SMK is derived from the Diffie-Hellman shared secret elliptic curve field element
            // between the service provider and the
            // application enclave:
            // First compute Key Definition Key: KDK = AES-CMAC(0x00, gab x-coordinate)
            // Then SMK = AES-CMAC ( KDK, 0x01||’SMK’||0x00||0x80||0x00)

            byte[] derivedKeyBa = bMessage.BlobStrToBa(derivedKeyStr);
            // Store the KDK for further key derivation.
            sigmaSequenceCheck.currentKDK = cmacAES.Value(MsgInitValues.DS_ZERO_BA16, derivedKeyBa);
            // Store the SMK for the current session for use in processing message 3
            sigmaSequenceCheck.currentSmk = bMessage.KeyLabelToKey(Constants.SMK, sigmaSequenceCheck.currentKDK);

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            // Build each term by retrieving elements,
            // concatenating, converting and performing crypto operations.
            string gbgaStr = gbXLittleEndianstr + gbYLittleEndianstr + gaXLittleEndianstr + gaYLittleEndianstr;

            byte[] gbgaBa = bMessage.BlobStrToBa(gbgaStr);          // gb||ga

            // Sign the gb||ga element Service Provider -- we use sigSP to notate this Service Provider signature

            // Get the Private Key from the settings file
            byte[] privateKey;
            try
            {
                privateKey = Constants.spPrivKeyBlob;// spPrivKeyBlob;
            }
            catch (Exception e)
            {
                options.LogCaughtErrorException(e);
                log.Debug("Failed to get private key: " + e.Message);
                HttpResponseException newException = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError);
                options.LogThrownException(newException);
                throw newException;
            }

            CngKey   signSgxKey = CngKey.Import(privateKey, CngKeyBlobFormat.EccPrivateBlob);
            ECDsaCng ecDsaSig   = new ECDsaCng(signSgxKey); // Elliptic Curve Digital Signature Algorithm, Signature

            ecDsaSig.HashAlgorithm = CngAlgorithm.Sha256;

            byte[] sigSPpubKey     = ecDsaSig.Key.Export(CngKeyBlobFormat.EccPublicBlob);
            string sigSPpubKeyBlob = "{ 0x" + BitConverter.ToString(sigSPpubKey).Replace("-", ", 0x") + " }";

            byte[] sigSP       = ecDsaSig.SignData(gbgaBa); // Input is LittleEndian, but output is BigEndian
            string sigSPstring = bMessage.BaToBlobStr(sigSP);

            // Separate the X and Y components of the signature -- Big Endian at this point
            string sigSPXBigEndianstr = sigSPstring.Substring(0, (sigSPstring.Length / 2));

            byte[] sigSPXBigEndian    = bMessage.BlobStrToBa(sigSPXBigEndianstr);
            string sigSPYBigEndianstr = sigSPstring.Substring(sigSPstring.Length / 2);

            byte[] sigSPYBigEndian = bMessage.BlobStrToBa(sigSPYBigEndianstr);

            // Swap the byte order of the signed data back to Little Endian and convert to combined string (X|Y)
            sigSPXLittleEndian = sigSPXBigEndian.Reverse().ToArray();
            string sigSPXLittleEndianstr = bMessage.BaToBlobStr(sigSPXLittleEndian);

            sigSPYLittleEndian = sigSPYBigEndian.Reverse().ToArray();
            string sigSPYLittleEndianstr   = bMessage.BaToBlobStr(sigSPYLittleEndian);
            string sigSPLittleEndianstring = sigSPXLittleEndianstr + sigSPYLittleEndianstr;

            // sigSPLittleEndianstring is in Little Endian format as required, ready to send to client

            // Get the signature link type
            try
            {
                if (SpStartup.iasConnectionMgr.LinkableQuotes)
                {
                    log.Debug("Using Linkable Quotes");
                    // If the SP policy setting dictates the use of linkable quotes, explicitly
                    // overwrite the default value in the sltype container.
                    // Otherwise, the default value will be an un-linkable quote type.
                    System.Buffer.BlockCopy(Constants.linkableBa, 0, Constants.sltype, 0, Constants.linkableBa.Length);
                }
            }
            catch (Exception e)
            {
                options.LogCaughtErrorException(e);
                log.Debug("Failed to get Linked Quote: " + e.Message);
                HttpResponseException newException = new HttpResponseException(System.Net.HttpStatusCode.InternalServerError);
                options.LogThrownException(newException);
                throw newException;
            }

            string sigTypeStr        = bMessage.BaToBlobStr(Constants.sltype);
            string kdfIdStr          = bMessage.BaToBlobStr(Constants.kdfId);
            string gbSpidSigSPstring = gbLittleEndianStr + bMessage.BaToBlobStr(SpStartup.iasConnectionMgr.SPID) + sigTypeStr + kdfIdStr + sigSPLittleEndianstring;

            byte[] macBlob = bMessage.BlobStrToBa(gbSpidSigSPstring);

            // Compute the CMAKsmk of (gb||SPID||Type||KDF-ID||SigSP(gb||ga))
            cMACsmk = cmacAES.Value(sigmaSequenceCheck.currentSmk, macBlob);
            string cMACsmkStr = bMessage.BaToBlobStr(cMACsmk);

            ecDsaSig.Dispose();

            log.Debug("CalculateDiffieHellmanExchange(..) returning.");
        }
Ejemplo n.º 6
0
        /// <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);
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
0
        /// <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);
        }
Ejemplo n.º 9
0
        /// <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);
        }