Parses and creates SecurityControlMessages. In general, this class is not thread-safe.
The format for said packets is: [version][security params][message type][cookie local][cookie remote] [dhe length][dhe][cert length][cert][cas length][cas][signature] version, type, data length are integers the cookie and id sizes are static in a given environment the signature is static based upon the signature type
Beispiel #1
0
        /// <summary>3b) Receive a Confirm, verify the entire stack and send a Confirm
        /// 4a)Receive a Confirm, verify the entire stack and all set to go</summary>
        /// <param name="sa">A security association that we wish to perform the
        /// specified control operation on.</param>
        /// <param name="scm">The received SecurityControlMessage.</param>
        /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
        /// <param name="return_path">Where to send the result.</param>
        /// <param name="low_level_sender">We expect the return_path to not be an edge or
        /// some other type of "low level" sender, so this contains the parsed out value.</param>
        protected void HandleControlConfirm(PeerSecAssociation sa,
                                            SecurityControlMessage scm, SecurityControlMessage scm_reply,
                                            ISender return_path, ISender low_level_sender)
        {
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received Confirm from: " + low_level_sender);
            if (sa == null)
            {
                throw new Exception("No valid SA!");
            }
            HashAlgorithm sha1 = new SHA1CryptoServiceProvider();

            scm.Verify((RSACryptoServiceProvider)sa.RemoteCertificate.RSA, sha1);

            if (return_path == low_level_sender)
            {
                sa.VerifyResponse(scm.Hash);
            }
            else
            {
                sa.VerifyRequest(scm.Hash);
                scm_reply.LocalCookie  = scm.RemoteCookie;
                scm_reply.RemoteCookie = scm.LocalCookie;
                scm_reply.Hash         = sa.DHEWithCertificateAndCAsInHash.Value;
                scm_reply.Type         = SecurityControlMessage.MessageType.Confirm;
                lock (_private_key_lock) {
                    scm_reply.Sign(_private_key, sha1);
                }
                ICopyable to_send = new CopyList(SecureControl, scm_reply.Packet);
                return_path.Send(to_send);
            }
            sa.Enable();

            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful Confirm from: " + low_level_sender);
        }
Beispiel #2
0
        /// <summary>1b) Receive a Cookie which responds with a CookieResponse</summary>
        /// <param name="sa">A security association that we wish to perform the
        /// specified control operation on.</param>
        /// <param name="calc_cookie">Cookie value for the association sender.</param>
        /// <param name="scm">The received SecurityControlMessage.</param>
        /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
        /// <param name="return_path">Where to send the result.</param>
        /// <param name="low_level_sender">We expect the return_path to not be an edge or
        /// some other type of "low level" sender, so this contains the parsed out value.</param>
        protected void HandleControlCookie(PeerSecAssociation sa,
                                           MemBlock calc_cookie, SecurityControlMessage scm,
                                           SecurityControlMessage scm_reply, ISender return_path,
                                           ISender low_level_sender)
        {
            ProtocolLog.WriteIf(ProtocolLog.Security, String.Format(
                                    "{0}, Received Cookie from: {1}, In-Cookie: {2}",
                                    GetHashCode(), low_level_sender, scm.LocalCookie));
            scm_reply.Type         = SecurityControlMessage.MessageType.CookieResponse;
            scm_reply.RemoteCookie = scm.LocalCookie;
            scm_reply.LocalCookie  = calc_cookie;
            if (SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys)
            {
                scm_reply.CAs = new List <MemBlock>(0);
            }
            else
            {
                scm_reply.CAs = _ch.SupportedCAs;
            }
            ICopyable to_send = new CopyList(SecureControl, scm_reply.Packet);

            return_path.Send(to_send);
            ProtocolLog.WriteIf(ProtocolLog.Security, String.Format(
                                    "{0}, Successful Cookie from: {1}, Out-Cookie: {2}",
                                    GetHashCode(), low_level_sender, calc_cookie));
        }
Beispiel #3
0
        /// <summary>3a) Receive a DHEWithCertificate, verify the certificate and DHE and
        /// send a Confirm that you are ready to Verify the stack and start the
        /// system.</summary>
        /// <param name="sa">A security association that we wish to perform the
        /// specified control operation on.</param>
        /// <param name="scm">The received SecurityControlMessage.</param>
        /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
        /// <param name="return_path">Where to send the result.</param>
        /// <param name="low_level_sender">We expect the return_path to not be an edge or
        /// some other type of "low level" sender, so this contains the parsed out value.</param>
        protected void HandleControlDHEWithCertificates(PeerSecAssociation sa,
                                                        SecurityControlMessage scm, SecurityControlMessage scm_reply,
                                                        ISender return_path, ISender low_level_sender)
        {
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received DHEWithCertificate from: " + low_level_sender);
            if (sa == null)
            {
                throw new Exception("No valid SA!");
            }
            byte[] cert = new byte[scm.Certificate.Length];
            scm.Certificate.CopyTo(cert, 0);
            X509Certificate rcert = new X509Certificate(cert);
            HashAlgorithm   sha1  = new SHA1CryptoServiceProvider();

            scm.Verify((RSACryptoServiceProvider)rcert.RSA, sha1);
            _ch.Verify(rcert, low_level_sender);

            sa.RemoteCertificate = rcert;
            sa.RDHE.Value        = scm.DHE;

            scm_reply.LocalCookie  = scm.RemoteCookie;
            scm_reply.RemoteCookie = scm.LocalCookie;
            scm_reply.Hash         = MemBlock.Reference(sha1.ComputeHash((byte[])scm.Packet));
            scm_reply.Type         = SecurityControlMessage.MessageType.Confirm;
            lock (_private_key_lock) {
                scm_reply.Sign(_private_key, sha1);
            }

            ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);

            _rrman.SendRequest(return_path, ReqrepManager.ReqrepType.Request,
                               to_send, this, sa);
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful DHEWithCertificate from: " + low_level_sender);
        }
Beispiel #4
0
        /// <summary>After a restart of the Security system, one guy may think
        /// we still have an association and there will be no way for him to know
        /// that our side is broken, unless we notify him as such.  We notify him
        /// by sending this packet.  How he deals with that is up to him.</summary>
        protected void NoSuchSA(int spi, ISender remote_sender)
        {
            SecurityControlMessage scm_reply = new SecurityControlMessage();

            scm_reply.Version = Version;
            scm_reply.SPI     = spi;
            scm_reply.Type    = SecurityControlMessage.MessageType.NoSuchSA;
            ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);

            remote_sender.Send(to_send);
        }
Beispiel #5
0
        /// <summary>2a) Receive a CookieResponse that contains a list of CAs, if you have
        /// a Certificate that supports one of the CAs send it along with a DHE
        /// and a list of your supported CAs in a DHEWithCertificateAndCAs.</summary>
        /// <param name="sa">A security association that we wish to perform the
        /// specified control operation on.</param>
        /// <param name="scm">The received SecurityControlMessage.</param>
        /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
        /// <param name="return_path">Where to send the result.</param>
        /// <param name="low_level_sender">We expect the return_path to not be an edge or
        /// some other type of "low level" sender, so this contains the parsed out value.</param>
        protected void HandleControlCookieResponse(PeerSecAssociation sa,
                                                   SecurityControlMessage scm, SecurityControlMessage scm_reply,
                                                   ISender return_path, ISender low_level_sender)
        {
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received CookieResponse from: " + low_level_sender);
            if (sa == null)
            {
                throw new Exception("No valid SA!");
            }
            // This seems like unnecessary code
            scm_reply.Type = SecurityControlMessage.MessageType.CookieResponse;
            X509Certificate lcert = null;

            if (SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys)
            {
                lcert = _ch.DefaultCertificate;
            }
            else
            {
                lcert = _ch.FindCertificate(scm.CAs);
            }

            sa.RemoteCookie.Value = scm.LocalCookie;
            sa.LocalCertificate   = lcert;
            scm_reply.Certificate = lcert.RawData;

            scm_reply.DHE          = sa.LDHE;
            scm_reply.LocalCookie  = scm.RemoteCookie;
            scm_reply.RemoteCookie = scm.LocalCookie;
            scm_reply.Type         = SecurityControlMessage.MessageType.DHEWithCertificateAndCAs;
            if (SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys)
            {
                scm_reply.CAs = new List <MemBlock>(0);
            }
            else
            {
                scm_reply.CAs = _ch.SupportedCAs;
            }
            HashAlgorithm sha1 = new SHA1CryptoServiceProvider();

            lock (_private_key_lock) {
                scm_reply.Sign(_private_key, sha1);
            }

            sa.DHEWithCertificateAndCAsOutHash.Value = sha1.ComputeHash((byte[])scm_reply.Packet);
            ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);

            _rrman.SendRequest(return_path, ReqrepManager.ReqrepType.Request,
                               to_send, this, sa);
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful CookieResponse from: " + low_level_sender);
        }
Beispiel #6
0
        /// <summary>This begins the SecurityAssociation exchange protocol over the
        /// specified SecurityAssociation.</summary>
        protected void StartSA(PeerSecAssociation sa)
        {
            SecurityControlMessage scm_reply = new SecurityControlMessage();

            scm_reply.Version     = Version;
            scm_reply.SPI         = sa.SPI;
            scm_reply.Type        = SecurityControlMessage.MessageType.Cookie;
            scm_reply.LocalCookie = CalculateCookie(sa.Sender);

            ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);

            _rrman.SendRequest(sa.Sender, ReqrepManager.ReqrepType.Request,
                               to_send, this, sa);
        }
Beispiel #7
0
        /// <summary>2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt
        /// to find a matching Certificate for the list of CAs, if you find one,
        /// finish the DHE handshake and send the certificate via a DHEWithCertificate</summary>
        /// <param name="sa">A security association that we wish to perform the
        /// specified control operation on.</param>
        /// <param name="scm">The received SecurityControlMessage.</param>
        /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
        /// <param name="return_path">Where to send the result.</param>
        /// <param name="low_level_sender">We expect the return_path to not be an edge or
        /// some other type of "low level" sender, so this contains the parsed out value.</param>
        protected void HandleControlDHEWithCertificateAndCAs(PeerSecAssociation sa,
                                                             SecurityControlMessage scm, SecurityControlMessage scm_reply,
                                                             ISender return_path, ISender low_level_sender)
        {
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received DHEWithCertificateAndCAs from: " + low_level_sender);
            if (sa == null)
            {
                sa = CreateSecurityAssociation(low_level_sender, scm.SPI, false);
            }
            byte[] cert = new byte[scm.Certificate.Length];
            scm.Certificate.CopyTo(cert, 0);
            X509Certificate rcert = new X509Certificate(cert);

            _ch.Verify(rcert, low_level_sender);
            HashAlgorithm sha1 = new SHA1CryptoServiceProvider();

            scm.Verify((RSACryptoServiceProvider)rcert.RSA, sha1);

            X509Certificate lcert = null;

            if (SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys)
            {
                lcert = _ch.DefaultCertificate;
            }
            else
            {
                lcert = _ch.FindCertificate(scm.CAs);
            }

            sa.LocalCertificate  = lcert;
            sa.RemoteCertificate = rcert;
            sa.RDHE.Value        = scm.DHE;
            sa.DHEWithCertificateAndCAsInHash.Value = MemBlock.Reference(sha1.ComputeHash((byte[])scm.Packet));

            scm_reply.LocalCookie  = scm.RemoteCookie;
            scm_reply.RemoteCookie = scm.LocalCookie;
            scm_reply.DHE          = sa.LDHE;
            scm_reply.Certificate  = MemBlock.Reference(lcert.RawData);
            scm_reply.Type         = SecurityControlMessage.MessageType.DHEWithCertificate;
            lock (_private_key_lock) {
                scm_reply.Sign(_private_key, sha1);
            }
            sa.DHEWithCertificateHash.Value = MemBlock.Reference(sha1.ComputeHash((byte[])scm_reply.Packet));

            ICopyable to_send = new CopyList(SecureControl, scm_reply.Packet);

            return_path.Send(to_send);
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful DHEWithCertificateAndCAs from: " + low_level_sender);
        }
Beispiel #8
0
        public void NoSuchSA()
        {
            SecurityControlMessage scm = new SecurityControlMessage();

            scm.Version = 5;
            scm.SPI     = 10;
            scm.Type    = SecurityControlMessage.MessageType.NoSuchSA;
            SecurityControlMessage scm_from_packet = new SecurityControlMessage(scm.Packet);

            Assert.AreEqual(scm.Version, scm_from_packet.Version, "Version");
            Assert.AreEqual(scm.SPI, scm_from_packet.SPI, "SPI");
            Assert.AreEqual(scm.Type, scm_from_packet.Type, "Type");
            Assert.AreEqual(5, scm_from_packet.Version, "Version");
            Assert.AreEqual(10, scm_from_packet.SPI, "SPI");
            Assert.AreEqual(SecurityControlMessage.MessageType.NoSuchSA, scm_from_packet.Type, "Type");
        }
Beispiel #9
0
    public void Incoming() {
      Random rand = new Random();
      byte[] local_cookie = new byte[SecurityControlMessage.CookieLength];
      byte[] remote_cookie = new byte[SecurityControlMessage.CookieLength];
      byte[] dhe = new byte[144];
      byte[] cas = new byte[120];
      byte[] cert = new byte[100];
      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
      HashAlgorithm hash = new SHA1CryptoServiceProvider();

      rand.NextBytes(local_cookie);
      rand.NextBytes(remote_cookie);
      rand.NextBytes(dhe);
      rand.NextBytes(cas);
      rand.NextBytes(cert);

      MemBlock mlocal_cookie = MemBlock.Reference(local_cookie);
      MemBlock mremote_cookie = MemBlock.Reference(remote_cookie);
      MemBlock mdhe = MemBlock.Reference(dhe);
      MemBlock mcert = MemBlock.Reference(cert);
      MemBlock mcas = MemBlock.Reference(cas);
      List<MemBlock> lcas = new List<MemBlock>();
      for(int i = 0; i < cas.Length; i+= SecurityControlMessage.CALength) {
        lcas.Add(MemBlock.Reference(mcas.Slice(i, SecurityControlMessage.CALength)));
      }

      int length = 4 + 4 + 4 + 2 * SecurityControlMessage.CookieLength +
        4 + cas.Length + 4 + dhe.Length +
        4 + cert.Length;

      byte[] b = new byte[length];
      int pos = 0;
      NumberSerializer.WriteInt(5, b, pos);
      pos += 4;
      NumberSerializer.WriteInt(12345, b, pos);
      pos += 4;
      NumberSerializer.WriteInt((int) SecurityControlMessage.MessageType.DHEWithCertificateAndCAs, b, pos);
      pos += 4;
      local_cookie.CopyTo(b, pos);
      pos += SecurityControlMessage.CookieLength;
      remote_cookie.CopyTo(b, pos);
      pos += SecurityControlMessage.CookieLength;

      NumberSerializer.WriteInt(dhe.Length, b, pos);
      pos += 4;
      dhe.CopyTo(b, pos);
      pos += dhe.Length;

      NumberSerializer.WriteInt(cert.Length, b, pos);
      pos += 4;
      cert.CopyTo(b, pos);
      pos += cert.Length;

      NumberSerializer.WriteInt(cas.Length, b, pos);
      pos += 4;
      mcas.CopyTo(b, pos);
      pos += cas.Length;

      byte[] signature = rsa.SignData(b, hash);
      byte[] nb = new byte[b.Length + signature.Length];
      b.CopyTo(nb, 0);
      signature.CopyTo(nb, b.Length);
      MemBlock packet = MemBlock.Reference(nb);

      // check 
      SecurityControlMessage scm = new SecurityControlMessage(packet);
      Assert.AreEqual(5, scm.Version, "Version");
      Assert.AreEqual(12345, scm.SPI, "SPI");
      Assert.AreEqual(SecurityControlMessage.MessageType.DHEWithCertificateAndCAs, scm.Type, "Type");
      Assert.AreEqual(mlocal_cookie, scm.LocalCookie, "LocalCookie");
      Assert.AreEqual(mremote_cookie, scm.RemoteCookie, "RemoteCookie");
      Assert.AreEqual(mdhe, scm.DHE, "DHE");
      Assert.AreEqual(mcert, scm.Certificate, "Certificate");
      int contains = 0;
      foreach(MemBlock ca in scm.CAs) {
        if(scm.CAs.Contains(ca)) {
          contains++;
        }
      }
      Assert.AreEqual(contains, lcas.Count, "Contains CAs");
      Assert.IsTrue(scm.Verify(rsa, hash), "Signature");
      Assert.AreEqual(packet, scm.Packet, "Packet");

      // change a few things around and check again!
      scm.Version = 0;
      SecurityControlMessage scm1 = new SecurityControlMessage(scm.Packet);
      scm1.Sign(rsa, hash);
      Assert.AreEqual(scm1.Version, scm.Version, "Version 1");
      Assert.AreEqual(scm1.SPI, scm.SPI, "SPI 1");
      Assert.AreEqual(scm1.Type, scm.Type, "Type 1");
      Assert.AreEqual(scm1.LocalCookie, scm.LocalCookie, "LocalCookie 1");
      Assert.AreEqual(scm1.RemoteCookie, scm.RemoteCookie, "RemoteCookie 1");
      Assert.AreEqual(mdhe, scm.DHE, "DHE 1");
      Assert.AreEqual(mcert, scm.Certificate, "Certificate 1");
      contains = 0;
      foreach(MemBlock ca in scm.CAs) {
        if(scm.CAs.Contains(ca)) {
          contains++;
        }
      }
      Assert.AreEqual(contains, lcas.Count, "Contains CAs 1");
      Assert.IsTrue(scm1.Signature != scm.Signature, "Signature 1");
      Assert.AreEqual(scm1.Packet.Slice(4, scm1.Signature.Length),
          scm.Packet.Slice(4, scm.Signature.Length), "Packet 1");
    }
Beispiel #10
0
    /// <summary>3a) Receive a DHEWithCertificate, verify the certificate and DHE and
    /// send a Confirm that you are ready to Verify the stack and start the
    /// system.</summary>
    /// <param name="sa">A security association that we wish to perform the
    /// specified control operation on.</param>
    /// <param name="scm">The received SecurityControlMessage.</param>
    /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
    /// <param name="return_path">Where to send the result.</param>
    /// <param name="low_level_sender">We expect the return_path to not be an edge or
    /// some other type of "low level" sender, so this contains the parsed out value.</param>
    protected void HandleControlDHEWithCertificate(PeerSecAssociation sa,
        SecurityControlMessage scm, SecurityControlMessage scm_reply,
        ISender return_path, ISender low_level_sender)
    {
      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received DHEWithCertificate from: " + low_level_sender);
      if(sa == null) {
        throw new Exception("No valid SA!");
      }
      byte[] cert = new byte[scm.Certificate.Length];
      scm.Certificate.CopyTo(cert, 0);
      X509Certificate rcert = new X509Certificate(cert);
      HashAlgorithm sha1 = new SHA1CryptoServiceProvider();
      scm.Verify((RSACryptoServiceProvider) rcert.RSA, sha1);
      _ch.Verify(rcert, low_level_sender);

      sa.RemoteCertificate = rcert;
      sa.RDHE.Value = scm.DHE;

      scm_reply.LocalCookie = scm.RemoteCookie;
      scm_reply.RemoteCookie = scm.LocalCookie;
      scm_reply.Hash = MemBlock.Reference(sha1.ComputeHash((byte[]) scm.Packet));
      scm_reply.Type = SecurityControlMessage.MessageType.Confirm;
      lock(_private_key_lock) {
        scm_reply.Sign(_private_key, sha1);
      }

      ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);
      _rrman.SendRequest(return_path, ReqrepManager.ReqrepType.Request,
          to_send, this, sa);
      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful DHEWithCertificate from: " + low_level_sender);
    }
Beispiel #11
0
    /// <summary>3b) Receive a Confirm, verify the entire stack and send a Confirm
    /// 4a)Receive a Confirm, verify the entire stack and all set to go</summary>
    /// <param name="sa">A security association that we wish to perform the
    /// specified control operation on.</param>
    /// <param name="scm">The received SecurityControlMessage.</param>
    /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
    /// <param name="return_path">Where to send the result.</param>
    /// <param name="low_level_sender">We expect the return_path to not be an edge or
    /// some other type of "low level" sender, so this contains the parsed out value.</param>
    protected void HandleControlConfirm(PeerSecAssociation sa,
        SecurityControlMessage scm, SecurityControlMessage scm_reply,
        ISender return_path, ISender low_level_sender)
    {
      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received Confirm from: " + low_level_sender);
      if(sa == null) {
        throw new Exception("No valid SA!");
      }
      HashAlgorithm sha1 = new SHA1CryptoServiceProvider();
      scm.Verify((RSACryptoServiceProvider) sa.RemoteCertificate.RSA, sha1);

      if(return_path == low_level_sender) {
        sa.VerifyResponse(scm.Hash);
      } else {
        sa.VerifyRequest(scm.Hash);
        scm_reply.LocalCookie = scm.RemoteCookie;
        scm_reply.RemoteCookie = scm.LocalCookie;
        scm_reply.Hash = sa.DHEWithCertificateAndCAsInHash.Value;
        scm_reply.Type = SecurityControlMessage.MessageType.Confirm;
        lock(_private_key_lock) {
          scm_reply.Sign(_private_key, sha1);
        }
        ICopyable to_send = new CopyList(SecureControl, scm_reply.Packet);
        return_path.Send(to_send);
      }
      sa.Enable();

      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful Confirm from: " + low_level_sender);
    }
Beispiel #12
0
    /// <summary>2a) Receive a CookieResponse that contains a list of CAs, if you have
    /// a Certificate that supports one of the CAs send it along with a DHE
    /// and a list of your supported CAs in a DHEWithCertificateAndCAs.</summary>
    /// <param name="sa">A security association that we wish to perform the
    /// specified control operation on.</param>
    /// <param name="scm">The received SecurityControlMessage.</param>
    /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
    /// <param name="return_path">Where to send the result.</param>
    /// <param name="low_level_sender">We expect the return_path to not be an edge or
    /// some other type of "low level" sender, so this contains the parsed out value.</param>
    protected void HandleControlCookieResponse(PeerSecAssociation sa,
        SecurityControlMessage scm, SecurityControlMessage scm_reply,
        ISender return_path, ISender low_level_sender)
    {
      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received CookieResponse from: " + low_level_sender);
      if(sa == null) {
        throw new Exception("No valid SA!");
      }
      // This seems like unnecessary code
      scm_reply.Type = SecurityControlMessage.MessageType.CookieResponse;
      X509Certificate lcert = null;
      if(SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys) {
        lcert = _ch.DefaultCertificate;
      } else {
        lcert = _ch.FindCertificate(scm.CAs);
      }

      sa.RemoteCookie.Value = scm.LocalCookie;
      sa.LocalCertificate = lcert;
      scm_reply.Certificate = lcert.RawData;

      scm_reply.DHE = sa.LDHE;
      scm_reply.LocalCookie = scm.RemoteCookie;
      scm_reply.RemoteCookie = scm.LocalCookie;
      scm_reply.Type = SecurityControlMessage.MessageType.DHEWithCertificateAndCAs;
      if(SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys) {
        scm_reply.CAs = new List<MemBlock>(0);
      } else {
        scm_reply.CAs = _ch.SupportedCAs;
      }
      HashAlgorithm sha1 = new SHA1CryptoServiceProvider();
      lock(_private_key_lock) {
        scm_reply.Sign(_private_key, sha1);
      }

      sa.DHEWithCertificateAndCAsOutHash.Value = sha1.ComputeHash((byte[]) scm_reply.Packet);
      ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);
      _rrman.SendRequest(return_path, ReqrepManager.ReqrepType.Request,
          to_send, this, sa);
      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful CookieResponse from: " + low_level_sender);
    }
Beispiel #13
0
    /// <summary>2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt
    /// to find a matching Certificate for the list of CAs, if you find one,
    /// finish the DHE handshake and send the certificate via a DHEWithCertificate</summary>
    /// <param name="sa">A security association that we wish to perform the
    /// specified control operation on.</param>
    /// <param name="scm">The received SecurityControlMessage.</param>
    /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
    /// <param name="return_path">Where to send the result.</param>
    /// <param name="low_level_sender">We expect the return_path to not be an edge or
    /// some other type of "low level" sender, so this contains the parsed out value.</param>
    protected void HandleControlDHEWithCertificateAndCAs(PeerSecAssociation sa,
        SecurityControlMessage scm, SecurityControlMessage scm_reply,
        ISender return_path, ISender low_level_sender)
    {
      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received DHEWithCertificateAndCAs from: " + low_level_sender);
      if(sa == null) {
        sa = CreateSecurityAssociation(low_level_sender, scm.SPI, false);
      }
      byte[] cert = new byte[scm.Certificate.Length];
      scm.Certificate.CopyTo(cert, 0);
      X509Certificate rcert = new X509Certificate(cert);
      _ch.Verify(rcert, low_level_sender);
      HashAlgorithm sha1 = new SHA1CryptoServiceProvider();
      scm.Verify((RSACryptoServiceProvider) rcert.RSA, sha1);

      X509Certificate lcert = null;
      if(SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys) {
        lcert = _ch.DefaultCertificate;
      } else {
        lcert = _ch.FindCertificate(scm.CAs);
      }

      sa.LocalCertificate = lcert;
      sa.RemoteCertificate = rcert;
      sa.RDHE.Value = scm.DHE;
      sa.DHEWithCertificateAndCAsInHash.Value = MemBlock.Reference(sha1.ComputeHash((byte[]) scm.Packet));

      scm_reply.LocalCookie = scm.RemoteCookie;
      scm_reply.RemoteCookie = scm.LocalCookie;
      scm_reply.DHE = sa.LDHE;
      scm_reply.Certificate = MemBlock.Reference(lcert.RawData);
      scm_reply.Type = SecurityControlMessage.MessageType.DHEWithCertificate;
      lock(_private_key_lock) {
        scm_reply.Sign(_private_key, sha1);
      }
      sa.DHEWithCertificateHash.Value = MemBlock.Reference(sha1.ComputeHash((byte[]) scm_reply.Packet));

      ICopyable to_send = new CopyList(SecureControl, scm_reply.Packet);
      return_path.Send(to_send);
      ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Successful DHEWithCertificateAndCAs from: " + low_level_sender);
    }
Beispiel #14
0
    /// <summary>This is the control state machine.  There are three paths in
    /// the state machine, iniator, receiver, and bidirectional.  The
    /// bidirectional case occurs when two remote ISenders that are matched
    /// together initiate a handshake at the same time, otherwise the initiator
    /// /receiver pattern is followed.  The high level overview for the states
    /// are:
    /// 1a) Send a Cookie
    /// 1b) Receive a Cookie which responds with a CookieResponse
    /// 2a) Receive a CookieResponse that contains a list of CAs, if you have
    /// a Certificate that supports one of the CAs send it along with a DHE
    /// and a list of your supported CAs in a DHEWithCertificateAndCAs.
    /// 2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt
    /// to find a matching Certificate for the list of CAs, if you find one,
    /// finish the DHE handshake and send the certificate via a DHEWithCertificate
    /// 3a) Receive a DHEWithCertificate, verify the certificate and DHE and
    /// send a Confirm that you are ready to Verify the stack and start the
    /// system.
    /// 3b) Receive a Confirm, verify the entire stack and send a Confirm
    /// 4a)Receive a Confirm, verify the entire stack and all set to go
    /// </summary>
    protected void HandleControl(MemBlock b, ISender return_path) {
      ISender low_level_sender = return_path;
      if(low_level_sender is ReqrepManager.ReplyState) {
        low_level_sender = ((ReqrepManager.ReplyState) low_level_sender).ReturnPath;
      }

      SecurityControlMessage scm = new SecurityControlMessage(b);
      MemBlock calc_cookie = CalculateCookie(low_level_sender);

      if(scm.Version != Version) {
        ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
              "Invalid version expected {0}, found {1}, from {2}, message: {3}",
              Version, scm.Version, low_level_sender, scm));
        return;
      } else if(!SecurityPolicy.Supports(scm.SPI)) {
        ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
              "Unsupported SPI, from {0}, message: {1}", low_level_sender, scm));
        return;
      } else if((scm.Type != SecurityControlMessage.MessageType.Cookie &&
            scm.Type != SecurityControlMessage.MessageType.NoSuchSA) &&
          !scm.RemoteCookie.Equals(calc_cookie))
      {
        ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
              "Invalid cookie, Expected {0}, Found {1}, From {2}, Message {3}",
              calc_cookie, scm.RemoteCookie, low_level_sender, scm));
        return;
      }

      SecurityControlMessage scm_reply = new SecurityControlMessage();
      scm_reply.Version = Version;
      scm_reply.SPI = scm.SPI;

      PeerSecAssociation sa = null;
      // This can be in a try statement since this is best effort anyway
      try {
        Dictionary<ISender, PeerSecAssociation> sender_to_sa = _spi[scm.SPI];
        sa = sender_to_sa[low_level_sender];
      } catch { }

      if(sa != null) {
        // Reset cases where no state has been set yet or state is attempting
        // to be re-established, if other message types arrive, they will
        // expect pre-set state and will fail.  The mechanisms instilled thus
        // far should prevent this, but this makes it explicit.  Now only
        // wayward messages will arrive to other states.
        if(scm.Type == SecurityControlMessage.MessageType.NoSuchSA ||
            scm.Type == SecurityControlMessage.MessageType.Cookie ||
            scm.Type == SecurityControlMessage.MessageType.CookieResponse ||
            scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs)
        {
          sa.TryReset();
        }

        if(sa.Closed) {
          ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed, clearing SA state! " + sa);
          sa = null;
        } else if(sa.State == SecurityAssociation.States.Active &&
            // Two nodes can demand a confirm at the same time, if this
            // message doesn't pass, then one side will close due to timeout
            scm.Type != SecurityControlMessage.MessageType.Confirm)
        {
          ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
                "{0}, {1}: {2}", GetHashCode(), "SA Active, received message",
                scm.Type));
          return;
        }
      }

      try {
        switch(scm.Type) {
          case SecurityControlMessage.MessageType.NoSuchSA:
            HandleControlNoSuchSA(sa);
            break;
          case SecurityControlMessage.MessageType.Cookie:
            HandleControlCookie(sa, calc_cookie, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.CookieResponse:
            HandleControlCookieResponse(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.DHEWithCertificateAndCAs:
            HandleControlDHEWithCertificateAndCAs(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.DHEWithCertificate:
            HandleControlDHEWithCertificate(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.Confirm:
            HandleControlConfirm(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          default:
            throw new Exception("Invalid message!");
        }
      } catch(Exception e) {
        if(scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs ||
            scm.Type == SecurityControlMessage.MessageType.DHEWithCertificate ||
            scm.Type == SecurityControlMessage.MessageType.Confirm)
        {
          NoSuchSA(scm.SPI, return_path);
        }
        if(sa != null && sa.Closed) {
          ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed! " + sa);
          return;
        }
        ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
              "Error in {0}, unhandled exception from {1}, message: {2}, exception: {3}",
              GetHashCode(), low_level_sender, scm, e));
      }
    }
Beispiel #15
0
 /// <summary>1b) Receive a Cookie which responds with a CookieResponse</summary>
 /// <param name="sa">A security association that we wish to perform the
 /// specified control operation on.</param>
 /// <param name="calc_cookie">Cookie value for the association sender.</param>
 /// <param name="scm">The received SecurityControlMessage.</param>
 /// <param name="scm_reply">A prepared reply message (with headers and such.</param>
 /// <param name="return_path">Where to send the result.</param>
 /// <param name="low_level_sender">We expect the return_path to not be an edge or
 /// some other type of "low level" sender, so this contains the parsed out value.</param>
 protected void HandleControlCookie(PeerSecAssociation sa,
     MemBlock calc_cookie, SecurityControlMessage scm,
     SecurityControlMessage scm_reply, ISender return_path,
     ISender low_level_sender)
 {
   ProtocolLog.WriteIf(ProtocolLog.Security, String.Format(
         "{0}, Received Cookie from: {1}, In-Cookie: {2}",
         GetHashCode(), low_level_sender, scm.LocalCookie));
   scm_reply.Type = SecurityControlMessage.MessageType.CookieResponse;
   scm_reply.RemoteCookie = scm.LocalCookie;
   scm_reply.LocalCookie = calc_cookie;
   if(SecurityPolicy.GetPolicy(scm.SPI).PreExchangedKeys) {
     scm_reply.CAs = new List<MemBlock>(0);
   } else {
     scm_reply.CAs = _ch.SupportedCAs;
   }
   ICopyable to_send = new CopyList(SecureControl, scm_reply.Packet);
   return_path.Send(to_send);
   ProtocolLog.WriteIf(ProtocolLog.Security, String.Format(
         "{0}, Successful Cookie from: {1}, Out-Cookie: {2}",
         GetHashCode(), low_level_sender, calc_cookie));
 }
Beispiel #16
0
    /// <summary>This begins the SecurityAssociation exchange protocol over the
    /// specified SecurityAssociation.</summary>
    protected void StartSA(PeerSecAssociation sa) {
      SecurityControlMessage scm_reply = new SecurityControlMessage();
      scm_reply.Version = Version;
      scm_reply.SPI = sa.SPI;
      scm_reply.Type = SecurityControlMessage.MessageType.Cookie;
      scm_reply.LocalCookie = CalculateCookie(sa.Sender);

      ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);

      _rrman.SendRequest(sa.Sender, ReqrepManager.ReqrepType.Request,
          to_send, this, sa);
    }
Beispiel #17
0
 /// <summary>After a restart of the Security system, one guy may think
 /// we still have an association and there will be no way for him to know
 /// that our side is broken, unless we notify him as such.  We notify him
 /// by sending this packet.  How he deals with that is up to him.</summary>
 protected void NoSuchSA(int spi, ISender remote_sender) {
   SecurityControlMessage scm_reply = new SecurityControlMessage();
   scm_reply.Version = Version;
   scm_reply.SPI = spi;
   scm_reply.Type = SecurityControlMessage.MessageType.NoSuchSA;
   ICopyable to_send = new CopyList(Security, SecureControl, scm_reply.Packet);
   remote_sender.Send(to_send);
 }
 public void NoSuchSA() {
   SecurityControlMessage scm = new SecurityControlMessage();
   scm.Version = 5;
   scm.SPI = 10;
   scm.Type = SecurityControlMessage.MessageType.NoSuchSA;
   SecurityControlMessage scm_from_packet = new SecurityControlMessage(scm.Packet);
   Assert.AreEqual(scm.Version, scm_from_packet.Version, "Version");
   Assert.AreEqual(scm.SPI, scm_from_packet.SPI, "SPI");
   Assert.AreEqual(scm.Type, scm_from_packet.Type, "Type");
   Assert.AreEqual(5, scm_from_packet.Version, "Version");
   Assert.AreEqual(10, scm_from_packet.SPI, "SPI");
   Assert.AreEqual(SecurityControlMessage.MessageType.NoSuchSA, scm_from_packet.Type, "Type");
 }
Beispiel #19
0
        /// <summary>This is the control state machine.  There are three paths in
        /// the state machine, iniator, receiver, and bidirectional.  The
        /// bidirectional case occurs when two remote ISenders that are matched
        /// together initiate a handshake at the same time, otherwise the initiator
        /// /receiver pattern is followed.  The high level overview for the states
        /// are:
        /// 1a) Send a Cookie
        /// 1b) Receive a Cookie which responds with a CookieResponse
        /// 2a) Receive a CookieResponse that contains a list of CAs, if you have
        /// a Certificate that supports one of the CAs send it along with a DHE
        /// and a list of your supported CAs in a DHEWithCertificateAndCAs.
        /// 2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt
        /// to find a matching Certificate for the list of CAs, if you find one,
        /// finish the DHE handshake and send the certificate via a DHEWithCertificate
        /// 3a) Receive a DHEWithCertificate, verify the certificate and DHE and
        /// send a Confirm that you are ready to Verify the stack and start the
        /// system.
        /// 3b) Receive a Confirm, verify the entire stack and send a Confirm
        /// 4a)Receive a Confirm, verify the entire stack and all set to go
        /// </summary>
        protected void HandleControl(MemBlock b, ISender return_path)
        {
            ISender low_level_sender = return_path;

            if (low_level_sender is ReqrepManager.ReplyState)
            {
                low_level_sender = ((ReqrepManager.ReplyState)low_level_sender).ReturnPath;
            }

            SecurityControlMessage scm = new SecurityControlMessage(b);
            MemBlock calc_cookie       = CalculateCookie(low_level_sender);

            if (scm.Version != Version)
            {
                ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
                                        "Invalid version expected {0}, found {1}, from {2}, message: {3}",
                                        Version, scm.Version, low_level_sender, scm));
                return;
            }
            else if (!SecurityPolicy.Supports(scm.SPI))
            {
                ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
                                        "Unsupported SPI, from {0}, message: {1}", low_level_sender, scm));
                return;
            }
            else if ((scm.Type != SecurityControlMessage.MessageType.Cookie &&
                      scm.Type != SecurityControlMessage.MessageType.NoSuchSA) &&
                     !scm.RemoteCookie.Equals(calc_cookie))
            {
                ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
                                        "Invalid cookie, Expected {0}, Found {1}, From {2}, Message {3}",
                                        calc_cookie, scm.RemoteCookie, low_level_sender, scm));
                return;
            }

            SecurityControlMessage scm_reply = new SecurityControlMessage();

            scm_reply.Version = Version;
            scm_reply.SPI     = scm.SPI;

            PeerSecAssociation sa = null;

            // This can be in a try statement since this is best effort anyway
            try {
                Dictionary <ISender, PeerSecAssociation> sender_to_sa = _spi[scm.SPI];
                sa = sender_to_sa[low_level_sender];
            } catch { }

            if (sa != null)
            {
                // Reset cases where no state has been set yet or state is attempting
                // to be re-established, if other message types arrive, they will
                // expect pre-set state and will fail.  The mechanisms instilled thus
                // far should prevent this, but this makes it explicit.  Now only
                // wayward messages will arrive to other states.
                if (scm.Type == SecurityControlMessage.MessageType.NoSuchSA ||
                    scm.Type == SecurityControlMessage.MessageType.Cookie ||
                    scm.Type == SecurityControlMessage.MessageType.CookieResponse ||
                    scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs)
                {
                    sa.TryReset();
                }

                if (sa.Closed)
                {
                    ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed, clearing SA state! " + sa);
                    sa = null;
                }
                else if (sa.State == SecurityAssociation.States.Active &&
                         // Two nodes can demand a confirm at the same time, if this
                         // message doesn't pass, then one side will close due to timeout
                         scm.Type != SecurityControlMessage.MessageType.Confirm)
                {
                    ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
                                            "{0}, {1}: {2}", GetHashCode(), "SA Active, received message",
                                            scm.Type));
                    return;
                }
            }

            try {
                switch (scm.Type)
                {
                case SecurityControlMessage.MessageType.NoSuchSA:
                    HandleControlNoSuchSA(sa);
                    break;

                case SecurityControlMessage.MessageType.Cookie:
                    HandleControlCookie(sa, calc_cookie, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.CookieResponse:
                    HandleControlCookieResponse(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.DHEWithCertificateAndCAs:
                    HandleControlDHEWithCertificateAndCAs(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.DHEWithCertificate:
                    HandleControlDHEWithCertificate(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.Confirm:
                    HandleControlConfirm(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                default:
                    throw new Exception("Invalid message!");
                }
            } catch (Exception e) {
                if (scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs ||
                    scm.Type == SecurityControlMessage.MessageType.DHEWithCertificate ||
                    scm.Type == SecurityControlMessage.MessageType.Confirm)
                {
                    NoSuchSA(scm.SPI, return_path);
                }
                if (sa != null && sa.Closed)
                {
                    ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed! " + sa);
                    return;
                }
                ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
                                        "Error in {0}, unhandled exception from {1}, message: {2}, exception: {3}",
                                        GetHashCode(), low_level_sender, scm, e));
            }
        }
Beispiel #20
0
    /// <summary>This is the control state machine.  There are three paths in
    /// the state machine, iniator, receiver, and bidirectional.  The
    /// bidirectional case occurs when two remote ISenders that are matched
    /// together initiate a handshake at the same time, otherwise the initiator
    /// /receiver pattern is followed.  The high level overview for the states
    /// are:
    /// 1a) Send a Cookie
    /// 1b) Receive a Cookie which responds with a CookieResponse
    /// 2a) Receive a CookieResponse that contains a list of CAs, if you have
    /// a Certificate that supports one of the CAs send it along with a DHE
    /// and a list of your supported CAs in a DHEWithCertificateAndCAs.
    /// 2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt
    /// to find a matching Certificate for the list of CAs, if you find one,
    /// finish the DHE handshake and send the certificate via a DHEWithCertificate
    /// 3a) Receive a DHEWithCertificate, verify the certificate and DHE and
    /// send a Confirm that you are ready to Verify the stack and start the
    /// system.
    /// 3b) Receive a Confirm, verify the entire stack and send a Confirm
    /// 4a)Receive a Confirm, verify the entire stack and all set to go
    /// </summary>
    protected void HandleControl(MemBlock b, ISender return_path) {
      ISender low_level_sender = return_path;
      if(low_level_sender is ReqrepManager.ReplyState) {
        low_level_sender = ((ReqrepManager.ReplyState) low_level_sender).ReturnPath;
      }

      SecurityControlMessage scm = new SecurityControlMessage(b);
      MemBlock calc_cookie = CalculateCookie(low_level_sender);

      if(scm.Version != Version) {
        throw new Exception("Invalid version: " + scm.Version);
      } else if(!SecurityPolicy.Supports(scm.SPI)) {
        throw new Exception("No support for SPI: " + scm.SPI);
      } else if(!scm.RemoteCookie.Equals(calc_cookie)) {
        if(scm.Type != SecurityControlMessage.MessageType.Cookie &&
            scm.Type != SecurityControlMessage.MessageType.NoSuchSA) {
          throw new Exception("Invalid cookie!");
        }
      }

      SecurityControlMessage scm_reply = new SecurityControlMessage();
      scm_reply.Version = Version;
      scm_reply.SPI = scm.SPI;

      PeerSecAssociation sa = null;
      // This can be in a try statement since this is best effort anyway
      try {
        Dictionary<ISender, PeerSecAssociation> sender_to_sa = _spi[scm.SPI];
        sa = sender_to_sa[low_level_sender];
      } catch { }

      if(sa != null) {
        sa.Reset();
        if(sa.Closed) {
          throw new Exception("SA closed!");
        } else if(sa.State == SecurityAssociation.States.Active) {
          return;
        }
      }

      try {
        switch(scm.Type) {
          case SecurityControlMessage.MessageType.NoSuchSA:
            HandleControlNoSuchSA(sa);
            break;
          case SecurityControlMessage.MessageType.Cookie:
            HandleControlCookie(sa, calc_cookie, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.CookieResponse:
            HandleControlCookieResponse(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.DHEWithCertificateAndCAs:
            HandleControlDHEWithCertificateAndCAs(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.DHEWithCertificate:
            HandleControlDHEWithCertificates(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          case SecurityControlMessage.MessageType.Confirm:
            HandleControlConfirm(sa, scm, scm_reply, return_path, low_level_sender);
            break;
          default:
            throw new Exception("Invalid message!");
        }
      } catch {
        if(sa != null && sa.Closed) {
          throw new Exception("SA closed.");
        } else {
          throw;
        }
      }
    }
        public void Incoming()
        {
            Random rand = new Random();

            byte[] local_cookie           = new byte[SecurityControlMessage.CookieLength];
            byte[] remote_cookie          = new byte[SecurityControlMessage.CookieLength];
            byte[] dhe                    = new byte[144];
            byte[] cas                    = new byte[120];
            byte[] cert                   = new byte[100];
            RSACryptoServiceProvider rsa  = new RSACryptoServiceProvider();
            HashAlgorithm            hash = new SHA1CryptoServiceProvider();

            rand.NextBytes(local_cookie);
            rand.NextBytes(remote_cookie);
            rand.NextBytes(dhe);
            rand.NextBytes(cas);
            rand.NextBytes(cert);

            MemBlock        mlocal_cookie  = MemBlock.Reference(local_cookie);
            MemBlock        mremote_cookie = MemBlock.Reference(remote_cookie);
            MemBlock        mdhe           = MemBlock.Reference(dhe);
            MemBlock        mcert          = MemBlock.Reference(cert);
            MemBlock        mcas           = MemBlock.Reference(cas);
            List <MemBlock> lcas           = new List <MemBlock>();

            for (int i = 0; i < cas.Length; i += SecurityControlMessage.CALength)
            {
                lcas.Add(MemBlock.Reference(mcas.Slice(i, SecurityControlMessage.CALength)));
            }

            int length = 4 + 4 + 4 + 2 * SecurityControlMessage.CookieLength +
                         4 + cas.Length + 4 + dhe.Length +
                         4 + cert.Length;

            byte[] b   = new byte[length];
            int    pos = 0;

            NumberSerializer.WriteInt(5, b, pos);
            pos += 4;
            NumberSerializer.WriteInt(12345, b, pos);
            pos += 4;
            NumberSerializer.WriteInt((int)SecurityControlMessage.MessageType.DHEWithCertificateAndCAs, b, pos);
            pos += 4;
            local_cookie.CopyTo(b, pos);
            pos += SecurityControlMessage.CookieLength;
            remote_cookie.CopyTo(b, pos);
            pos += SecurityControlMessage.CookieLength;

            NumberSerializer.WriteInt(dhe.Length, b, pos);
            pos += 4;
            dhe.CopyTo(b, pos);
            pos += dhe.Length;

            NumberSerializer.WriteInt(cert.Length, b, pos);
            pos += 4;
            cert.CopyTo(b, pos);
            pos += cert.Length;

            NumberSerializer.WriteInt(cas.Length, b, pos);
            pos += 4;
            mcas.CopyTo(b, pos);
            pos += cas.Length;

            byte[] signature = rsa.SignData(b, hash);
            byte[] nb        = new byte[b.Length + signature.Length];
            b.CopyTo(nb, 0);
            signature.CopyTo(nb, b.Length);
            MemBlock packet = MemBlock.Reference(nb);

            // check
            SecurityControlMessage scm = new SecurityControlMessage(packet);

            Assert.AreEqual(5, scm.Version, "Version");
            Assert.AreEqual(12345, scm.SPI, "SPI");
            Assert.AreEqual(SecurityControlMessage.MessageType.DHEWithCertificateAndCAs, scm.Type, "Type");
            Assert.AreEqual(mlocal_cookie, scm.LocalCookie, "LocalCookie");
            Assert.AreEqual(mremote_cookie, scm.RemoteCookie, "RemoteCookie");
            Assert.AreEqual(mdhe, scm.DHE, "DHE");
            Assert.AreEqual(mcert, scm.Certificate, "Certificate");
            int contains = 0;

            foreach (MemBlock ca in scm.CAs)
            {
                if (scm.CAs.Contains(ca))
                {
                    contains++;
                }
            }
            Assert.AreEqual(contains, lcas.Count, "Contains CAs");
            Assert.IsTrue(scm.Verify(rsa, hash), "Signature");
            Assert.AreEqual(packet, scm.Packet, "Packet");

            // change a few things around and check again!
            scm.Version = 0;
            SecurityControlMessage scm1 = new SecurityControlMessage(scm.Packet);

            scm1.Sign(rsa, hash);
            Assert.AreEqual(scm1.Version, scm.Version, "Version 1");
            Assert.AreEqual(scm1.SPI, scm.SPI, "SPI 1");
            Assert.AreEqual(scm1.Type, scm.Type, "Type 1");
            Assert.AreEqual(scm1.LocalCookie, scm.LocalCookie, "LocalCookie 1");
            Assert.AreEqual(scm1.RemoteCookie, scm.RemoteCookie, "RemoteCookie 1");
            Assert.AreEqual(mdhe, scm.DHE, "DHE 1");
            Assert.AreEqual(mcert, scm.Certificate, "Certificate 1");
            contains = 0;
            foreach (MemBlock ca in scm.CAs)
            {
                if (scm.CAs.Contains(ca))
                {
                    contains++;
                }
            }
            Assert.AreEqual(contains, lcas.Count, "Contains CAs 1");
            Assert.IsTrue(scm1.Signature != scm.Signature, "Signature 1");
            Assert.AreEqual(scm1.Packet.Slice(4, scm1.Signature.Length),
                            scm.Packet.Slice(4, scm.Signature.Length), "Packet 1");
        }
Beispiel #22
0
        /// <summary>This is the control state machine.  There are three paths in
        /// the state machine, iniator, receiver, and bidirectional.  The
        /// bidirectional case occurs when two remote ISenders that are matched
        /// together initiate a handshake at the same time, otherwise the initiator
        /// /receiver pattern is followed.  The high level overview for the states
        /// are:
        /// 1a) Send a Cookie
        /// 1b) Receive a Cookie which responds with a CookieResponse
        /// 2a) Receive a CookieResponse that contains a list of CAs, if you have
        /// a Certificate that supports one of the CAs send it along with a DHE
        /// and a list of your supported CAs in a DHEWithCertificateAndCAs.
        /// 2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt
        /// to find a matching Certificate for the list of CAs, if you find one,
        /// finish the DHE handshake and send the certificate via a DHEWithCertificate
        /// 3a) Receive a DHEWithCertificate, verify the certificate and DHE and
        /// send a Confirm that you are ready to Verify the stack and start the
        /// system.
        /// 3b) Receive a Confirm, verify the entire stack and send a Confirm
        /// 4a)Receive a Confirm, verify the entire stack and all set to go
        /// </summary>
        protected void HandleControl(MemBlock b, ISender return_path)
        {
            ISender low_level_sender = return_path;

            if (low_level_sender is ReqrepManager.ReplyState)
            {
                low_level_sender = ((ReqrepManager.ReplyState)low_level_sender).ReturnPath;
            }

            SecurityControlMessage scm = new SecurityControlMessage(b);
            MemBlock calc_cookie       = CalculateCookie(low_level_sender);

            if (scm.Version != Version)
            {
                throw new Exception("Invalid version: " + scm.Version);
            }
            else if (!SecurityPolicy.Supports(scm.SPI))
            {
                throw new Exception("No support for SPI: " + scm.SPI);
            }
            else if (!scm.RemoteCookie.Equals(calc_cookie))
            {
                if (scm.Type != SecurityControlMessage.MessageType.Cookie &&
                    scm.Type != SecurityControlMessage.MessageType.NoSuchSA)
                {
                    throw new Exception("Invalid cookie!");
                }
            }

            SecurityControlMessage scm_reply = new SecurityControlMessage();

            scm_reply.Version = Version;
            scm_reply.SPI     = scm.SPI;

            PeerSecAssociation sa = null;

            // This can be in a try statement since this is best effort anyway
            try {
                Dictionary <ISender, PeerSecAssociation> sender_to_sa = _spi[scm.SPI];
                sa = sender_to_sa[low_level_sender];
            } catch { }

            if (sa != null)
            {
                sa.Reset();
                if (sa.Closed)
                {
                    throw new Exception("SA closed!");
                }
                else if (sa.State == SecurityAssociation.States.Active)
                {
                    return;
                }
            }

            try {
                switch (scm.Type)
                {
                case SecurityControlMessage.MessageType.NoSuchSA:
                    HandleControlNoSuchSA(sa);
                    break;

                case SecurityControlMessage.MessageType.Cookie:
                    HandleControlCookie(sa, calc_cookie, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.CookieResponse:
                    HandleControlCookieResponse(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.DHEWithCertificateAndCAs:
                    HandleControlDHEWithCertificateAndCAs(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.DHEWithCertificate:
                    HandleControlDHEWithCertificates(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                case SecurityControlMessage.MessageType.Confirm:
                    HandleControlConfirm(sa, scm, scm_reply, return_path, low_level_sender);
                    break;

                default:
                    throw new Exception("Invalid message!");
                }
            } catch {
                if (sa != null && sa.Closed)
                {
                    throw new Exception("SA closed.");
                }
                else
                {
                    throw;
                }
            }
        }