Each SP supports a specific SymmetricAlgorithm and HashAlgorithm. This class is thread-safe.
예제 #1
0
        /// <summary>This is SecureData that needs to get to an SA.</summary>
        protected void HandleData(MemBlock b, ISender return_path)
        {
            SecurityDataMessage sdm = new SecurityDataMessage(b);
            Dictionary <ISender, SecurityAssociation> sender_to_sa = null;
            SecurityAssociation sa = null;

            try {
                sender_to_sa = _spi[sdm.SPI];
                sa           = sender_to_sa[return_path];
                sa.HandleData(b, return_path, null);
            } catch {
                if (sender_to_sa == null && !SecurityPolicy.Supports(sdm.SPI))
                {
                    throw new Exception("Invalid SPI: " + sdm.SPI);
                }
                else if (sa == null)
                {
                    NoSuchSA(sdm.SPI, return_path);
                    throw new Exception("No SA for: " + return_path);
                }
                else if (sa.Closed)
                {
                    throw new Exception("SA has been closed.");
                }
                else
                {
                    throw;
                }
            }
        }
예제 #2
0
        public override bool Equals(object o)
        {
            SecurityPolicy sp = o as SecurityPolicy;

            if (o == null)
            {
                return(false);
            }

            return((sp.Index == this.Index) && sp.Encryptor.Equals(this.Encryptor) &&
                   sp.Authenticator.Equals(this.Authenticator));
        }
예제 #3
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(SecurityAssociation 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.Value = 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);
        }
예제 #4
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(SecurityAssociation 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);
            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.Value  = lcert;
            sa.RemoteCertificate.Value = 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);
        }
예제 #5
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(SecurityAssociation sa,
                                           MemBlock calc_cookie, SecurityControlMessage scm,
                                           SecurityControlMessage scm_reply, ISender return_path,
                                           ISender low_level_sender)
        {
            ProtocolLog.WriteIf(ProtocolLog.Security, GetHashCode() + " Received Cookie from: " + low_level_sender);
            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, GetHashCode() + " Successful Cookie from: " + low_level_sender);
        }
예제 #6
0
        /// <summary>This (idempotently) returns a new SecurityAssociation for the
        /// specified sender using the specified SA.</summary>
        virtual protected SecurityAssociation CreateSecurityAssociation(ISender Sender, int SPI)
        {
            if (!SecurityPolicy.Supports(SPI))
            {
                throw new Exception("Unsupported SPI");
            }

            SecurityAssociation sa = null;
            int count = 0;

            lock (_sync) {
                Dictionary <ISender, SecurityAssociation> sender_to_sa = null;
                if (_spi.ContainsKey(SPI))
                {
                    sender_to_sa = _spi[SPI];
                }
                else
                {
                    sender_to_sa = new Dictionary <ISender, SecurityAssociation>();
                    _spi[SPI]    = sender_to_sa;
                }

                if (sender_to_sa.ContainsKey(Sender))
                {
                    sa = sender_to_sa[Sender];
                }
                else
                {
                    sa = new SecurityAssociation(Sender, SPI);
                    sa.Subscribe(this, null);
                    sa.StateChange      += SAStateChange;
                    sa.RequestUpdate    += SARequestUpdate;
                    sender_to_sa[Sender] = sa;
                }
            }
            return(sa);
        }
예제 #7
0
        ///<summary>Enables the SA if it has been properly setup.</summary>
        public void Enable()
        {
            // If both parties setup simultaneous SAs we could end up calling this
            // twice, once as a client and the other as server, this way we only
            // go through the whole process once.
            lock (_sync) {
                if (_called_enable == 1)
                {
                    return;
                }
                else if (_closed == 1)
                {
                    throw new Exception("Cannot enable a closed SA!");
                }
                else if (_ldhe == null)
                {
                    throw new Exception("Local DHE not set.");
                }
                else if (RDHE.Value == null)
                {
                    throw new Exception("Remote DHE not set.");
                }
                else if (!_hash_verified)
                {
                    throw new Exception("Hash is not verified!");
                }
                else if (TimedOut)
                {
                    throw new Exception("Timed out on this one!");
                }
                _called_enable = 1;

                // Deriving the DHE exchange and determing the order of keys
                // Specifically, we need up to 4 keys for the sender/receiver encryption/
                // authentication codes.  So to determine the order, we say whomever has
                // the smallest gets the first set of keys.
                byte[] rdhe = (byte[])RDHE.Value;
                RDHE = null;
                byte[] key = _dh.DecryptKeyExchange(rdhe);
                _dh.Clear();
                _dh = null;
                int i = 0;
                while (i < _ldhe.Length && _ldhe[i] == rdhe[i])
                {
                    i++;
                }
                bool same  = i == _ldhe.Length;
                bool first = !same && (_ldhe[i] < rdhe[i]);
                _ldhe = null;
                // Gathering our security parameter objects
                SecurityPolicy     sp     = SecurityPolicy.GetPolicy(_spi);
                SymmetricAlgorithm in_sa  = sp.CreateSymmetricAlgorithm();
                HashAlgorithm      in_ha  = sp.CreateHashAlgorithm();
                SymmetricAlgorithm out_sa = sp.CreateSymmetricAlgorithm();
                HashAlgorithm      out_ha = sp.CreateHashAlgorithm();

                // Generating the total key length
                int key_length             = key.Length + 2 + (in_sa.KeySize / 8 + in_sa.BlockSize / 8) * 2;
                KeyedHashAlgorithm in_kha  = in_ha as KeyedHashAlgorithm;
                KeyedHashAlgorithm out_kha = out_ha as KeyedHashAlgorithm;
                if (in_kha != null)
                {
                    key_length += (in_kha.HashSize / 8) * 2;
                }

                // Generating a key by repeatedly hashing the DHE value and the key so far
                SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
                int usable_key_offset          = key.Length;
                while (key.Length < key_length)
                {
                    byte[] hash    = sha1.ComputeHash(key);
                    byte[] tmp_key = new byte[hash.Length + key.Length];
                    key.CopyTo(tmp_key, 0);
                    hash.CopyTo(tmp_key, key.Length);
                    key = tmp_key;
                }

                // Like a sub-session ID (see DTLS)
                short epoch = (short)((key[usable_key_offset] << 8) + key[usable_key_offset + 1]);
                usable_key_offset += 2;

                byte[] key0 = new byte[in_sa.KeySize / 8];
                Array.Copy(key, usable_key_offset, key0, 0, key0.Length);
                usable_key_offset += key0.Length;

                byte[] key1 = new byte[in_sa.KeySize / 8];
                Array.Copy(key, usable_key_offset, key1, 0, key1.Length);
                usable_key_offset += key1.Length;

                // Same may occur if we are forming a session with ourselves!
                if (same)
                {
                    in_sa.Key  = key0;
                    out_sa.Key = key0;
                }
                else if (first)
                {
                    in_sa.Key  = key0;
                    out_sa.Key = key1;
                }
                else
                {
                    out_sa.Key = key0;
                    in_sa.Key  = key1;
                }

                if (in_kha != null)
                {
                    byte[] hkey0 = new byte[in_kha.HashSize / 8];
                    Array.Copy(key, usable_key_offset, hkey0, 0, hkey0.Length);
                    usable_key_offset += hkey0.Length;

                    byte[] hkey1 = new byte[in_kha.HashSize / 8];
                    Array.Copy(key, usable_key_offset, hkey1, 0, hkey1.Length);
                    usable_key_offset += hkey1.Length;

                    if (same)
                    {
                        in_kha.Key  = hkey0;
                        out_kha.Key = hkey0;
                    }
                    else if (first)
                    {
                        in_kha.Key  = hkey0;
                        out_kha.Key = hkey1;
                    }
                    else
                    {
                        out_kha.Key = hkey0;
                        in_kha.Key  = hkey1;
                    }
                }

                SecurityHandler sh = new SecurityHandler(in_sa, out_sa, in_ha, out_ha, epoch);
                sh.Update += UpdateSH;
                SecurityHandler to_close = _current_sh;
                if (to_close != null)
                {
                    to_close.Close();
                }
                _current_sh    = sh;
                _last_epoch    = _current_epoch;
                _current_epoch = epoch;
            }
            // All finished set the state (which will probably fire an event)
            State = SAState.Active;
        }
예제 #8
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;

            SecurityAssociation sa = null;

            // This can be in a try statement since this is best effort anyway
            try {
                Dictionary <ISender, SecurityAssociation> 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.SAState.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;
                }
            }
        }