InvokeLogin.cs

Contains the login functions

InvokeLogin.cs - example

The Invokde login procedure is necessary to do when the client wants to establish contact with the server. It is only necessary to do once each session.

Poses in the UML diagram and callouts in the C# code are explained at the end of the page. The pose number in the UML diagram corresponds to the same callout number in the C# code.

How to read this example:

  • Follow the Invoke login process described in the schematic UML diagram. This shows what is done, and in what order.

  • See the corresponding C# code for code examples for the actions described in the UML diagram.

  • You can read a description of what happens in the different stages of the task in the numbered list that is referenced from the UML diagram and the code.

Invoke login - UML diagram

The UML diagram shows the processes and variables between client and server involved in the Invoke login task.

Names of variables and processes in the UML diagram are different from those used in the C# code to make it easier to read.
diagram
Figure 1. Login procedure

Invoke login - C# code example

This code example refers to other functions and libraries. To get the complete collection of the referenced code, it can be downloaded here.

Variable names that begins with a lower case s indicates that the variable is a string.
Variable names that begins with an underscore (_) indicates that the variable is an internal variable.
// ------------------------------------------------------------------------------------------
// <copyright file="InvokeLogin.cs" company="SecMaker AB">
//   SecMaker AB
// </copyright>
// <summary>
//   Defines the Client partial class.
// </summary>
// ------------------------------------------------------------------------------------------

namespace SecMaker.NiP.Client
{
	using System;
	using System.Linq;
	using System.Security.Cryptography.X509Certificates;
    using System.Text;

    public partial class Client
	{
		public string InvokeLogin(bool verbose)
		{
			var x509CltCert =
				CertificateStore.GetCertificate(_sCertHash);

			if (x509CltCert == null)
			{
				//throw new Exception("Certificate is null.");
			}

			var sCert = (1)
				Utility.ToBase64String(x509CltCert.RawData);

			var dateTime =
				DateTime.Now.ToUniversalTime();

			var sDateTime = (2)
				Utility.ToString(dateTime);

			_dateTimeKey =
				Utility.ToBytes(sDateTime);

			_sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?> (3)
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <Login xmlns=""http://www.secmaker.com/NiP"">
     <Info><SessionId></SessionId>
      <Certificate>" + sCert + "</Certificate>" +
			            "<DateTime>" + sDateTime + "</DateTime>" +
			            "</Info></Login></soap:Body></soap:Envelope>";

			_sMessage =
				InvokeMessage(verbose);

			_sSessionId = (4) (12)
				Utility.ParseXmlElem(_sMessage, "<SessionId>");

			var sSrvCert = (5)
				Utility.ParseXmlElem(_sMessage, "<Certificate>");

			var x509SrvCert =
				new X509Certificate2(Convert.FromBase64String(sSrvCert));

			var sEncrSrvNonce = (6)
				Utility.ParseXmlElem(_sMessage, "<Value>");

			var encrSrvNonce =
				Convert.FromBase64String(sEncrSrvNonce);

			var pkcs7 =
				new Pkcs7();

			_srvNonce = (9)
				pkcs7.Decrypt(encrSrvNonce, new X509Certificate2Collection(x509CltCert));

			_cltNonce = (7)
				Utility.GenerateNonce(32);

			var encrCliNonce = (8)
				pkcs7.Encrypt(_cltNonce, new X509Certificate2Collection(x509SrvCert));

			var sEncrCliNonce = (13)
				Convert.ToBase64String(encrCliNonce);

			var sessionId =
				Convert.FromBase64String(_sSessionId);

			var combinedBytes =
				_cltNonce.Concat(sessionId).ToArray();

			var hmac = (10)
				Utility.GenerateHmac(_sHashAlg, combinedBytes, _dateTimeKey);

			var signature = (10)
				pkcs7.SignData(hmac, x509CltCert, false);

			x509CltCert.Reset();

			if (signature == null)
			{
				throw new Exception("Signature is null.");
			}

			var sSignature = (14)
				Convert.ToBase64String(signature);

			_sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?> (11)
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <Login xmlns=""http://www.secmaker.com/NiP"">
     <Info>
       <SessionId>" + _sSessionId + "</SessionId>" +
			            "<Value>" + sEncrCliNonce + "</Value>" +
			            "<Signature>" + sSignature + "</Signature>" +
			            "</Info></Login></soap:Body></soap:Envelope>";

			_sMessage =
				InvokeMessage(verbose);

			// Verify the signature.
			sSignature = (15)
				Utility.ParseXmlElem(_sMessage, "<Signature>");

			signature =
				Convert.FromBase64String(sSignature);

			var verifiedData =
				pkcs7.VerifyData(signature, null);

			// Verify the signature content.
			combinedBytes =
				_srvNonce.Concat(sessionId).ToArray();

			hmac =
				Utility.GenerateHmac(_sHashAlg, combinedBytes, _dateTimeKey);

			var sVerifiedData =
				Convert.ToBase64String(verifiedData);

			var sHmac =
				Convert.ToBase64String(hmac);

			if (!sVerifiedData.Equals(sHmac))
			{
				throw new Exception("Signature could not be verified.");
			}

			return _sSessionId;
		}

        public string InvokeLoginOTP(string otp, string username, bool verbose)
        {
            var dateTime =
                DateTime.Now.ToUniversalTime();

            var sDateTime =
                Utility.ToString(dateTime);

            _dateTimeKey =
                Utility.ToBytes(sDateTime);

            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <Login xmlns=""http://www.secmaker.com/NiP"">
     <Info><SessionId></SessionId>
       <Reference>Engångskod</Reference>" +
       @"<Role>self</Role>" +
       "<DateTime>" + sDateTime + "</DateTime>" +
     "</Info></Login></soap:Body></soap:Envelope>";

            _sMessage =
                InvokeMessage(verbose);


            var sSrvCert =
                Utility.ParseXmlElem(_sMessage, "<Certificate>");

            var x509SrvCert =
                new X509Certificate2(Convert.FromBase64String(sSrvCert));

            var pkcs7 =
                new Pkcs7();
            _srvNonce =
                Encoding.UTF8.GetBytes(otp);
            var encrSrvNonce =
                pkcs7.Encrypt(_srvNonce, new X509Certificate2Collection(x509SrvCert));

            var sEncrSrvNonce =
                Convert.ToBase64String(encrSrvNonce);



            _cltNonce =
                Utility.GenerateNonce(32);

            var encrCliNonce =
                pkcs7.Encrypt(_cltNonce, new X509Certificate2Collection(x509SrvCert));

            var sEncrCliNonce =
                Convert.ToBase64String(encrCliNonce);

            _sSessionId =
                Utility.ParseXmlElem(_sMessage, "<SessionId>");
            var sessionId =
                Convert.FromBase64String(_sSessionId);

            var combinedBytes =
                _cltNonce.Concat(sessionId).ToArray();

            var hmac =
                Utility.GenerateHmac(_sHashAlg, combinedBytes, _dateTimeKey);


            _sMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
   xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
   xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soap:Body>
     <Login xmlns=""http://www.secmaker.com/NiP"">
     <Info>
       <SessionId>" + _sSessionId + "</SessionId>" +
        "<Password>" + sEncrSrvNonce+ "</Password>" +
        "<Value>" + sEncrCliNonce + "</Value>" +
        "<Role>self</Role>" +
        "<DateTime>" + sDateTime + "</DateTime>" +
        "<UserInfo>" + username + "</UserInfo>" +
                        "</Info></Login></soap:Body></soap:Envelope>";

            _sMessage =
                InvokeMessage(verbose);

            // Verify the signature.
            //var sSignature =
            //    Utility.ParseXmlElem(_sMessage, "<Signature>");

            //var signature =
            //     Convert.FromBase64String(sSignature);

            // var verifiedData =
            //     pkcs7.VerifyData(signature, null);

            // // Verify the signature content.
            // combinedBytes =
            //     _srvNonce.Concat(sessionId).ToArray();

            // hmac =
            //     Utility.GenerateHmac(_sHashAlg, combinedBytes, _dateTimeKey);

            // var sVerifiedData =
            //     Convert.ToBase64String(verifiedData);

            // var sHmac =
            //     Convert.ToBase64String(hmac);

            // if (!sVerifiedData.Equals(sHmac))
            // {
            //     throw new Exception("Signature could not be verified.");
            // }

            _sSessionId =
                Utility.ParseXmlElem(_sMessage, "<SessionId>");
            return _sSessionId;
        }
    }
}
1 sCert is the client certificate x509CltCert converted to a Base64 string.
2 sDateTime is the date and time on the client side.
3 This _sMessage is the first SOAP message sent to the server containing the sCert and sDateTime. The server will then reply with a SOAP message containing the variables SessionId, ServerCert, DateTime, and EncryptedServerNonce.
4 _sSessionId is a constant generated by the server and parsed from the server SOAP message.
5 sSrvCert is the ServerCert parsed from the server SOAP message.
6 sEncrSrvNonce is the encrypted server nonce, using the client public key, parsed from the server SOAP message.
7 _cltNonce is the generated client nonce.
8 encrCliNonce is the encryption of the client nonce.
9 _srvNonce is the decryption of the server nonce using the client’s private key.
10 The first step in creating the client signature includes using HMAC with the concatenated client nonce and session ID. The next step is to sign it using the client’s private key.
11 _sMessage is the second SOAP message sent to the server containing the session ID, encrypted client nonce, and client signature.
12 _sSessionId is a constant generated by the server and parsed from the server SOAP message.
13 sEncrCliNonce is the encrypted client nonce.
14 sSignature is the client signature.
15 This contains several step for verifying the server signature.