Exemplo n.º 1
0
        public bool IsSignatureValid(SecureChannelHandshakeKeyExchange keyExchange, SecureChannelHandshakeHello serverHello, SecureChannelHandshakeHello clientHello)
        {
            if (!SecureChannelStream.IsUserIdValid(_publicKey, _userId))
            {
                return(false);
            }

            switch (serverHello.SupportedCiphers)
            {
            case SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256:
                using (RSA rsa = RSA.Create())
                {
                    RSAParameters rsaPublicKey = DEREncoding.DecodeRSAPublicKey(_publicKey);
                    rsa.ImportParameters(rsaPublicKey);

                    if (rsa.KeySize != 2048)
                    {
                        throw new SecureChannelException(SecureChannelCode.PeerAuthenticationFailed, null, _userId, "RSA key size is not valid for selected crypto option: " + serverHello.SupportedCiphers.ToString());
                    }

                    using (MemoryStream mS = new MemoryStream())
                    {
                        mS.Write(keyExchange.EphemeralPublicKey, 0, keyExchange.EphemeralPublicKey.Length);
                        mS.Write(serverHello.Nonce.Value, 0, serverHello.Nonce.Value.Length);
                        mS.Write(clientHello.Nonce.Value, 0, clientHello.Nonce.Value.Length);
                        mS.Position = 0;

                        return(rsa.VerifyData(mS, _signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
                    }
                }

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, null, null);
            }
        }
Exemplo n.º 2
0
        public SecureChannelHandshakeKeyExchange(KeyAgreement keyAgreement, SecureChannelHandshakeHello serverHello, SecureChannelHandshakeHello clientHello, byte[] psk)
            : base(SecureChannelCode.None)
        {
            _ephemeralPublicKey = keyAgreement.GetPublicKey();

            if (serverHello.Options.HasFlag(SecureChannelOptions.PRE_SHARED_KEY_AUTHENTICATION_REQUIRED))
            {
                _pskAuth = GetPskAuthValue(serverHello.SupportedCiphers, _ephemeralPublicKey, serverHello.Nonce.Value, clientHello.Nonce.Value, psk);
            }
            else
            {
                _pskAuth = new BinaryNumber(new byte[] { });
            }
        }
Exemplo n.º 3
0
        protected void EnableEncryption(Stream inputStream, SecureChannelHandshakeHello serverHello, SecureChannelHandshakeHello clientHello, KeyAgreement keyAgreement, SecureChannelHandshakeKeyExchange otherPartyKeyExchange)
        {
            using (MemoryStream mS = new MemoryStream(128))
            {
                mS.Write(serverHello.Nonce.Value);
                mS.Write(clientHello.Nonce.Value);

                keyAgreement.HmacKey = mS.ToArray();
            }

            byte[] masterKey = keyAgreement.DeriveKeyMaterial(otherPartyKeyExchange.EphemeralPublicKey);

            switch (serverHello.SupportedCiphers)
            {
            case SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256:
            case SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256:
            case SecureChannelCipherSuite.ECDHE256_ANON_WITH_AES256_CBC_HMAC_SHA256:
            case SecureChannelCipherSuite.ECDHE256_RSA2048_WITH_AES256_CBC_HMAC_SHA256:

                //generating AES IV of 128bit block size using MD5
                byte[] eIV;
                byte[] dIV;

                using (HashAlgorithm hash = HashAlgorithm.Create("MD5"))
                {
                    if (this is SecureChannelServerStream)
                    {
                        eIV = hash.ComputeHash(serverHello.Nonce.Value);
                        dIV = hash.ComputeHash(clientHello.Nonce.Value);
                    }
                    else
                    {
                        eIV = hash.ComputeHash(clientHello.Nonce.Value);
                        dIV = hash.ComputeHash(serverHello.Nonce.Value);
                    }
                }

                //create encryptor
                _encryptionAlgo         = Aes.Create();
                _encryptionAlgo.Key     = masterKey;
                _encryptionAlgo.IV      = eIV;
                _encryptionAlgo.Padding = PaddingMode.None;     //padding is managed by secure channel
                _encryptionAlgo.Mode    = CipherMode.CBC;

                _encryptor       = _encryptionAlgo.CreateEncryptor();
                _authHMACEncrypt = new HMACSHA256(masterKey);

                //create decryptor
                _decryptionAlgo         = Aes.Create();
                _decryptionAlgo.Key     = masterKey;
                _decryptionAlgo.IV      = dIV;
                _decryptionAlgo.Padding = PaddingMode.None;     //padding is managed by secure channel
                _decryptionAlgo.Mode    = CipherMode.CBC;

                _decryptor       = _decryptionAlgo.CreateDecryptor();
                _authHMACDecrypt = new HMACSHA256(masterKey);

                //init variables
                _blockSizeBytes     = _encryptionAlgo.BlockSize / 8;
                _writeBufferPadding = new byte[_blockSizeBytes];

                _authHMACSizeBytes = _authHMACEncrypt.HashSize / 8;
                break;

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }

            //init variables
            _baseStream  = inputStream;
            _bytesSent   = 0;
            _connectedOn = DateTime.UtcNow;

            if (_renegotiationTimer == null)
            {
                if ((_renegotiateAfterBytesSent > 0) || (_renegotiateAfterSeconds > 0))
                {
                    _renegotiationTimer = new Timer(delegate(object state)
                    {
                        try
                        {
                            if (((_renegotiateAfterBytesSent > 0) && (_bytesSent > _renegotiateAfterBytesSent)) || ((_renegotiateAfterSeconds > 0) && (_connectedOn.AddSeconds(_renegotiateAfterSeconds) < DateTime.UtcNow)))
                            {
                                Debug.Write(this.GetType().Name, "Renegotiation triggered");

                                RenegotiateNow();
                            }
                        }
                        catch (Exception ex)
                        {
                            Debug.Write(this.GetType().Name, ex);
                        }
                    }, null, RENEGOTIATION_TIMER_INTERVAL, RENEGOTIATION_TIMER_INTERVAL);
                }
            }
        }
Exemplo n.º 4
0
        private void Start(Stream stream)
        {
            try
            {
                WriteBufferedStream bufferedStream;

                if (!(stream is WriteBufferedStream))
                {
                    bufferedStream = new WriteBufferedStream(stream, 8 * 1024);
                }
                else
                {
                    bufferedStream = stream as WriteBufferedStream;
                }

                //read client hello
                SecureChannelHandshakeHello clientHello = new SecureChannelHandshakeHello(bufferedStream);

                switch (clientHello.Version)
                {
                case 1:
                    ProtocolV1(bufferedStream, clientHello);
                    break;

                default:
                    throw new SecureChannelException(SecureChannelCode.ProtocolVersionNotSupported, _remotePeerEP, _remotePeerUserId, "SecureChannel protocol version not supported: " + clientHello.Version);
                }
            }
            catch (SecureChannelException ex)
            {
                if (ex.Code == SecureChannelCode.RemoteError)
                {
                    throw new SecureChannelException(ex.Code, _remotePeerEP, _remotePeerUserId, ex.Message, ex);
                }
                else
                {
                    try
                    {
                        Stream s;

                        if (_baseStream == null)
                        {
                            s = stream;
                        }
                        else
                        {
                            s = this;
                        }

                        new SecureChannelHandshakePacket(ex.Code).WriteTo(s);
                        s.Flush();
                    }
                    catch
                    { }

                    if (ex.PeerEP == null)
                    {
                        throw new SecureChannelException(ex.Code, _remotePeerEP, _remotePeerUserId, ex.Message, ex);
                    }

                    throw;
                }
            }
            catch (IOException)
            {
                throw;
            }
            catch
            {
                try
                {
                    Stream s;

                    if (_baseStream == null)
                    {
                        s = stream;
                    }
                    else
                    {
                        s = this;
                    }

                    new SecureChannelHandshakePacket(SecureChannelCode.UnknownException).WriteTo(s);
                    s.Flush();
                }
                catch
                { }

                throw;
            }
        }
Exemplo n.º 5
0
        private void ProtocolV1(WriteBufferedStream bufferedStream, SecureChannelHandshakeHello clientHello)
        {
            #region 1. hello handshake check

            //select crypto option
            SecureChannelCipherSuite availableCiphers = _supportedCiphers & clientHello.SupportedCiphers;

            if (availableCiphers == SecureChannelCipherSuite.None)
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }
            else if (availableCiphers.HasFlag(SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256))
            {
                _selectedCipher = SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256;
            }
            else if (availableCiphers.HasFlag(SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256))
            {
                _selectedCipher = SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256;
            }
            else
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }

            //match options
            if (_options != clientHello.Options)
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingOptionsAvailable, _remotePeerEP, _remotePeerUserId);
            }

            //write server hello
            SecureChannelHandshakeHello serverHello = new SecureChannelHandshakeHello(_selectedCipher, _options);
            serverHello.WriteTo(bufferedStream);

            #endregion

            #region 2. key exchange

            KeyAgreement keyAgreement;

            switch (_selectedCipher)
            {
            case SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256:
            case SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256:
                keyAgreement = new DiffieHellman(DiffieHellmanGroupType.RFC3526_GROUP14_2048BIT, KeyAgreementKeyDerivationFunction.Hmac, KeyAgreementKeyDerivationHashAlgorithm.SHA256);
                break;

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }

            //send server key exchange data
            SecureChannelHandshakeKeyExchange serverKeyExchange = new SecureChannelHandshakeKeyExchange(keyAgreement, serverHello, clientHello, _preSharedKey);
            serverKeyExchange.WriteTo(bufferedStream);
            bufferedStream.Flush();

            //read client key exchange data
            SecureChannelHandshakeKeyExchange clientKeyExchange = new SecureChannelHandshakeKeyExchange(bufferedStream);

            if (_options.HasFlag(SecureChannelOptions.PRE_SHARED_KEY_AUTHENTICATION_REQUIRED))
            {
                if (!clientKeyExchange.IsPskAuthValid(serverHello, clientHello, _preSharedKey))
                {
                    throw new SecureChannelException(SecureChannelCode.PskAuthenticationFailed, _remotePeerEP, _remotePeerUserId);
                }
            }

            #endregion

            #region 3. enable encryption

            EnableEncryption(bufferedStream, serverHello, clientHello, keyAgreement, clientKeyExchange);

            #endregion

            #region 4. UserId based authentication

            switch (_selectedCipher)
            {
            case SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256:
                if (_options.HasFlag(SecureChannelOptions.CLIENT_AUTHENTICATION_REQUIRED))
                {
                    //read client auth
                    SecureChannelHandshakeAuthentication clientAuth = new SecureChannelHandshakeAuthentication(this);
                    _remotePeerUserId = clientAuth.UserId;

                    //authenticate client
                    if (!clientAuth.IsSignatureValid(clientKeyExchange, serverHello, clientHello))
                    {
                        throw new SecureChannelException(SecureChannelCode.PeerAuthenticationFailed, _remotePeerEP, _remotePeerUserId);
                    }

                    //check if client is trusted
                    if (!clientAuth.IsTrustedUserId(_trustedUserIds))
                    {
                        throw new SecureChannelException(SecureChannelCode.UntrustedRemotePeerUserId, _remotePeerEP, _remotePeerUserId);
                    }
                }

                //write server auth
                new SecureChannelHandshakeAuthentication(serverKeyExchange, serverHello, clientHello, _userId, _privateKey).WriteTo(this);
                this.Flush();
                break;

            case SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256:
                break;     //no auth for ANON

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }

            #endregion
        }
Exemplo n.º 6
0
        public SecureChannelHandshakeAuthentication(SecureChannelHandshakeKeyExchange keyExchange, SecureChannelHandshakeHello serverHello, SecureChannelHandshakeHello clientHello, BinaryNumber userId, byte[] privateKey)
            : base(SecureChannelCode.None)
        {
            switch (serverHello.SupportedCiphers)
            {
            case SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256:
                _userId = userId;

                using (RSA rsa = RSA.Create())
                {
                    RSAParameters rsaPrivateKey = DEREncoding.DecodeRSAPrivateKey(privateKey);
                    rsa.ImportParameters(rsaPrivateKey);

                    if (rsa.KeySize != 2048)
                    {
                        throw new SecureChannelException(SecureChannelCode.PeerAuthenticationFailed, null, _userId, "RSA key size is not valid for selected crypto option: " + serverHello.SupportedCiphers.ToString());
                    }

                    _publicKey = DEREncoding.EncodeRSAPublicKey(rsaPrivateKey);

                    if (!SecureChannelStream.IsUserIdValid(_publicKey, _userId))
                    {
                        throw new SecureChannelException(SecureChannelCode.PeerAuthenticationFailed, null, _userId, "UserId does not match with public key.");
                    }

                    using (MemoryStream mS = new MemoryStream())
                    {
                        mS.Write(keyExchange.EphemeralPublicKey, 0, keyExchange.EphemeralPublicKey.Length);
                        mS.Write(serverHello.Nonce.Value, 0, serverHello.Nonce.Value.Length);
                        mS.Write(clientHello.Nonce.Value, 0, clientHello.Nonce.Value.Length);
                        mS.Position = 0;

                        _signature = rsa.SignData(mS, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
                    }
                }
                break;

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, null, null);
            }
        }
Exemplo n.º 7
0
        public bool IsPskAuthValid(SecureChannelHandshakeHello serverHello, SecureChannelHandshakeHello clientHello, byte[] psk)
        {
            BinaryNumber generatedPskAuthValue = GetPskAuthValue(serverHello.SupportedCiphers, _ephemeralPublicKey, serverHello.Nonce.Value, clientHello.Nonce.Value, psk);

            return(_pskAuth.Equals(generatedPskAuthValue));
        }