Beispiel #1
0
        private static string GetFingerprint(IntPtr x509)
        {
            var bufferHandle = default(GCHandle);
            int length       = OpenSsl.EVP_MAX_MD_SIZE;
            var buffer       = new byte[length];

            try
            {
                bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                if (OpenSsl.X509_digest(x509, OpenSsl.EVP_sha256(), bufferHandle.AddrOfPinnedObject(), ref length) != 1)
                {
                    throw new Exception($"Cannot calculate digest: {OpenSsl.GetLastError()}");
                }
            }
            finally
            {
                bufferHandle.Free();
            }

            var sb = new StringBuilder("sha-256 ");

            for (var i = 0; i < length; ++i)
            {
                sb.AppendFormat("{0:X2}:", buffer[i]);
            }
            sb.Length -= 1;

            return(sb.ToString());
        }
 private void Dispose(bool disposing)
 {
     if (_ctx != IntPtr.Zero)
     {
         OpenSsl.EVP_CIPHER_CTX_free(_ctx);
     }
 }
        public void GenerateKeyStream(byte[] key, byte[] iv, byte[] output)
        {
            if (output.Length % BLOCK_SIZE != 0)
            {
                throw new Exception("Output buffer size must be aligned to BLOCK_SIZE");
            }

            var keyHandle    = default(GCHandle);
            var ivHandle     = default(GCHandle);
            var inputHandle  = default(GCHandle);
            var outputHandle = default(GCHandle);

            try
            {
                var inputBlock = new byte[BLOCK_SIZE];

                keyHandle    = GCHandle.Alloc(key, GCHandleType.Pinned);
                ivHandle     = GCHandle.Alloc(iv, GCHandleType.Pinned);
                inputHandle  = GCHandle.Alloc(inputBlock, GCHandleType.Pinned);
                outputHandle = GCHandle.Alloc(output, GCHandleType.Pinned);

                if (OpenSsl.EVP_EncryptInit_ex(_ctx, OpenSsl.EVP_aes_128_ctr(), IntPtr.Zero,
                                               keyHandle.AddrOfPinnedObject(), ivHandle.AddrOfPinnedObject()) != 1)
                {
                    throw new Exception($"Cannot initialize AES: {OpenSsl.GetLastError()}");
                }

                int outputOffset = 0;
                while (outputOffset < output.Length)
                {
                    int outputLength = 0;
                    if (OpenSsl.EVP_EncryptUpdate(_ctx,
                                                  IntPtr.Add(outputHandle.AddrOfPinnedObject(), outputOffset), ref outputLength,
                                                  inputHandle.AddrOfPinnedObject(), BLOCK_SIZE) != 1)
                    {
                        throw new Exception($"Cannot encode AES: {OpenSsl.GetLastError()}");
                    }
                    outputOffset += outputLength;
                }
            }
            finally
            {
                if (keyHandle.IsAllocated)
                {
                    keyHandle.Free();
                }
                if (ivHandle.IsAllocated)
                {
                    ivHandle.Free();
                }
                if (inputHandle.IsAllocated)
                {
                    inputHandle.Free();
                }
                if (outputHandle.IsAllocated)
                {
                    outputHandle.Free();
                }
            }
        }
 public SrtpContext()
 {
     _ctx    = OpenSsl.EVP_CIPHER_CTX_new();
     _txKey  = new byte[SRTP_MASTER_KEY_LEN];
     _txSalt = new byte[SRTP_MASTER_SALT_LEN];
     _rxKey  = new byte[SRTP_MASTER_KEY_LEN];
     _rxSalt = new byte[SRTP_MASTER_SALT_LEN];
 }
Beispiel #5
0
        private static int BioWrite(IntPtr bio, IntPtr data, int dlen)
        {
            var wrapper = (DtlsWrapper)GCHandle.FromIntPtr(OpenSsl.BIO_get_data(bio)).Target;

            var temp = new byte[dlen];

            Marshal.Copy(data, temp, 0, dlen);
            wrapper._sendCallback(wrapper._client, temp);

            return(dlen);
        }
Beispiel #6
0
        private static int BioRead(IntPtr bio, IntPtr data, int dlen)
        {
            var wrapper = (DtlsWrapper)GCHandle.FromIntPtr(OpenSsl.BIO_get_data(bio)).Target;

            if (!wrapper._packets.TryTake(out var packet, DTLS_TIMEOUT))
            {
                return(0);
            }

            Marshal.Copy(packet, 0, data, packet.Length);
            return(packet.Length);
        }
Beispiel #7
0
 private void Dispose(bool disposing)
 {
     if (_handle.IsAllocated)
     {
         _handle.Free();
     }
     if (_ssl != IntPtr.Zero)
     {
         OpenSsl.SSL_free(_ssl); // SSL_free also free _bio
     }
     if (disposing)
     {
         _packets?.Dispose();
     }
 }
Beispiel #8
0
        public void DoHandshake(Action callback)
        {
            if (Interlocked.CompareExchange(ref _connectionState, 1, 0) == 0)
            {
                ThreadPool.QueueUserWorkItem(_ =>
                {
                    while (_packets.TryTake(out var _))
                    {
                    }

                    OpenSsl.SSL_set_connect_state(Ssl);
                    if (OpenSsl.SSL_do_handshake(Ssl) != 1)
                    {
                        Console.WriteLine($"Cannot establish DTLS: {OpenSsl.GetLastError()}");
                        Interlocked.Exchange(ref _connectionState, 0);
                        return;
                    }

                    callback();
                });
            }
        }
        public void CalcHmac(byte[] key, int keyLen, byte[] data, int dataLen, byte[] hmac)
        {
            var keyHandle  = default(GCHandle);
            var dataHandle = default(GCHandle);
            var hmacHandle = default(GCHandle);

            try
            {
                keyHandle  = GCHandle.Alloc(key, GCHandleType.Pinned);
                dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
                hmacHandle = GCHandle.Alloc(hmac, GCHandleType.Pinned);

                var outputLength = 0;
                if (OpenSsl.HMAC(OpenSsl.EVP_sha1(),
                                 keyHandle.AddrOfPinnedObject(), keyLen,
                                 dataHandle.AddrOfPinnedObject(), dataLen,
                                 hmacHandle.AddrOfPinnedObject(), ref outputLength) == IntPtr.Zero)
                {
                    throw new Exception($"Cannot calculate HMAC: {OpenSsl.GetLastError()}");
                }
            }
            finally
            {
                if (keyHandle.IsAllocated)
                {
                    keyHandle.Free();
                }
                if (dataHandle.IsAllocated)
                {
                    dataHandle.Free();
                }
                if (hmacHandle.IsAllocated)
                {
                    hmacHandle.Free();
                }
            }
        }
        public void SetMasterKeys(IntPtr ssl, bool isClient)
        {
            var keyingMaterialHandle = default(GCHandle);

            try
            {
                var keyingMaterial = new byte[2 * SRTP_MASTER_LEN];
                keyingMaterialHandle = GCHandle.Alloc(keyingMaterial, GCHandleType.Pinned);

                if (OpenSsl.SSL_export_keying_material(ssl, keyingMaterialHandle.AddrOfPinnedObject(),
                                                       2 * SRTP_MASTER_LEN,
                                                       Marshal.StringToHGlobalAnsi("EXTRACTOR-dtls_srtp"), 19,
                                                       IntPtr.Zero, 0, 0) != 1)
                {
                    throw new Exception($"Cannot export keying material: {OpenSsl.GetLastError()}");
                }

                int offset = 0;
                Array.Copy(keyingMaterial, offset, isClient ? _txKey : _rxKey, 0, SRTP_MASTER_KEY_LEN);
                offset += SRTP_MASTER_KEY_LEN;
                Array.Copy(keyingMaterial, offset, isClient ? _rxKey : _txKey, 0, SRTP_MASTER_KEY_LEN);
                offset += SRTP_MASTER_KEY_LEN;
                Array.Copy(keyingMaterial, offset, isClient ? _txSalt : _rxSalt, 0, SRTP_MASTER_SALT_LEN);
                offset += SRTP_MASTER_SALT_LEN;
                Array.Copy(keyingMaterial, offset, isClient ? _rxSalt : _txSalt, 0, SRTP_MASTER_SALT_LEN);

                _rxRoc = 0;
                _txRoc = 0;
            }
            finally
            {
                if (keyingMaterialHandle.IsAllocated)
                {
                    keyingMaterialHandle.Free();
                }
            }
        }
Beispiel #11
0
        public DtlsWrapper(Client client, Action <Client, byte[]> sendCallback)
        {
            _client       = client;
            _sendCallback = sendCallback;

            _bio = OpenSsl.BIO_new(_bioMeth);
            if (_bio == IntPtr.Zero)
            {
                throw new Exception("Cannot allocate exchange BIO");
            }

            _ssl = OpenSsl.SSL_new(_sslCtx);
            if (_ssl == IntPtr.Zero)
            {
                OpenSsl.BIO_free(_bio);
                throw new Exception("Cannot initialize ssl");
            }

            OpenSsl.SSL_set_bio(Ssl, _bio, _bio);

            _handle = GCHandle.Alloc(this, GCHandleType.Normal);
            OpenSsl.BIO_set_data(_bio, GCHandle.ToIntPtr(_handle));
            _packets = new BlockingCollection <byte[]>();
        }
        public void GenerateSessionKey(
            byte[] masterKey,
            byte[] masterSalt,
            byte[] sessionKey,
            byte[] sessionSalt,
            byte[] sessionAuth
            )
        {
            var keyHandle         = default(GCHandle);
            var ivHandle          = default(GCHandle);
            var inputHandle       = default(GCHandle);
            var sessionKeyHandle  = default(GCHandle);
            var sessionSaltHandle = default(GCHandle);
            var sessionAuthHandle = default(GCHandle);

            try
            {
                var inputBlock = new byte[BLOCK_SIZE];
                var sessionIv  = new byte[BLOCK_SIZE];

                keyHandle         = GCHandle.Alloc(masterKey, GCHandleType.Pinned);
                ivHandle          = GCHandle.Alloc(sessionIv, GCHandleType.Pinned);
                inputHandle       = GCHandle.Alloc(inputBlock, GCHandleType.Pinned);
                sessionKeyHandle  = GCHandle.Alloc(sessionKey, GCHandleType.Pinned);
                sessionSaltHandle = GCHandle.Alloc(sessionSalt, GCHandleType.Pinned);
                sessionAuthHandle = GCHandle.Alloc(sessionAuth, GCHandleType.Pinned);

                Array.Copy(masterSalt, sessionIv, masterSalt.Length);

                if (OpenSsl.EVP_EncryptInit_ex(_ctx, OpenSsl.EVP_aes_128_ctr(), IntPtr.Zero,
                                               keyHandle.AddrOfPinnedObject(), ivHandle.AddrOfPinnedObject()) != 1)
                {
                    throw new Exception($"Cannot initialize AES: {OpenSsl.GetLastError()}");
                }

                int outputLength = 0;
                if (OpenSsl.EVP_EncryptUpdate(_ctx,
                                              sessionKeyHandle.AddrOfPinnedObject(), ref outputLength,
                                              inputHandle.AddrOfPinnedObject(), BLOCK_SIZE) != 1)
                {
                    throw new Exception($"Cannot encode AES: {OpenSsl.GetLastError()}");
                }

                sessionIv[7] ^= 0x02;
                if (OpenSsl.EVP_EncryptInit_ex(_ctx, OpenSsl.EVP_aes_128_ctr(), IntPtr.Zero,
                                               keyHandle.AddrOfPinnedObject(), ivHandle.AddrOfPinnedObject()) != 1)
                {
                    throw new Exception($"Cannot initialize AES: {OpenSsl.GetLastError()}");
                }

                outputLength = 0;
                if (OpenSsl.EVP_EncryptUpdate(_ctx,
                                              sessionSaltHandle.AddrOfPinnedObject(), ref outputLength,
                                              inputHandle.AddrOfPinnedObject(), BLOCK_SIZE) != 1)
                {
                    throw new Exception($"Cannot encode AES: {OpenSsl.GetLastError()}");
                }

                sessionIv[7] ^= 0x03;
                if (OpenSsl.EVP_EncryptInit_ex(_ctx, OpenSsl.EVP_aes_128_ctr(), IntPtr.Zero,
                                               keyHandle.AddrOfPinnedObject(), ivHandle.AddrOfPinnedObject()) != 1)
                {
                    throw new Exception($"Cannot initialize AES: {OpenSsl.GetLastError()}");
                }

                int outputOffset = 0;
                while (outputOffset < sessionAuth.Length)
                {
                    outputLength = 0;
                    if (OpenSsl.EVP_EncryptUpdate(_ctx,
                                                  IntPtr.Add(sessionAuthHandle.AddrOfPinnedObject(), outputOffset), ref outputLength,
                                                  inputHandle.AddrOfPinnedObject(), BLOCK_SIZE) != 1)
                    {
                        throw new Exception($"Cannot encode AES: {OpenSsl.GetLastError()}");
                    }
                    outputOffset += outputLength;
                }
            }
            finally
            {
                if (keyHandle.IsAllocated)
                {
                    keyHandle.Free();
                }
                if (ivHandle.IsAllocated)
                {
                    ivHandle.Free();
                }
                if (inputHandle.IsAllocated)
                {
                    inputHandle.Free();
                }
                if (sessionKeyHandle.IsAllocated)
                {
                    sessionKeyHandle.Free();
                }
                if (sessionSaltHandle.IsAllocated)
                {
                    sessionSaltHandle.Free();
                }
                if (sessionAuthHandle.IsAllocated)
                {
                    sessionAuthHandle.Free();
                }
            }
        }
Beispiel #13
0
        static DtlsWrapper()
        {
            _bioMeth = OpenSsl.BIO_meth_new(1, "dtls-wrapper");

            _bioWrite = BioWrite;
            _bioRead  = BioRead;
            _bioCtrl  = BioCtrl;

            if (_bioMeth == IntPtr.Zero)
            {
                throw new Exception($"Cannot initialize bioMeth: {OpenSsl.GetLastError()}");
            }
            if (OpenSsl.BIO_meth_set_write(_bioMeth, _bioWrite) != 1)
            {
                throw new Exception($"Cannot initialize bioMethWrite: {OpenSsl.GetLastError()}");
            }
            if (OpenSsl.BIO_meth_set_read(_bioMeth, _bioRead) != 1)
            {
                throw new Exception($"Cannot initialize bioMethRead: {OpenSsl.GetLastError()}");
            }
            if (OpenSsl.BIO_meth_set_ctrl(_bioMeth, _bioCtrl) != 1)
            {
                throw new Exception($"Cannot initialize bioMethCtrl: {OpenSsl.GetLastError()}");
            }

            _sslCtx = OpenSsl.SSL_CTX_new(OpenSsl.DTLS_method());
            if (_sslCtx == IntPtr.Zero)
            {
                throw new Exception($"Cannot create SSL_CTX: {OpenSsl.GetLastError()}");
            }

            var key = OpenSsl.EVP_PKEY_new();

            if (key == IntPtr.Zero)
            {
                throw new Exception($"Cannot create key: {OpenSsl.GetLastError()}");
            }

            var ecKey = OpenSsl.EC_KEY_new_by_curve_name(OpenSsl.NID_X9_62_prime256v1);

            if (ecKey == IntPtr.Zero)
            {
                throw new Exception($"Cannot create ecKey: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.EC_KEY_generate_key(ecKey) != 1)
            {
                throw new Exception($"Cannot generate ecKey: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.EVP_PKEY_assign(key, OpenSsl.NID_X9_62_id_ecPublicKey, ecKey) != 1)
            {
                throw new Exception($"Cannot assign ecKey to key: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.SSL_CTX_use_PrivateKey(_sslCtx, key) != 1)
            {
                throw new Exception($"Cannot set key to ctx: {OpenSsl.GetLastError()}");
            }

            var x509 = OpenSsl.X509_new();

            if (x509 == IntPtr.Zero)
            {
                throw new Exception($"Cannot create ecKey: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_set_pubkey(x509, key) != 1)
            {
                throw new Exception($"Cannot assign pubkey to x509: {OpenSsl.GetLastError()}");
            }

            var serialNumber = OpenSsl.BN_new();

            if (serialNumber == IntPtr.Zero)
            {
                throw new Exception($"Cannot create BN for serialNumber: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.BN_pseudo_rand(serialNumber, OpenSsl.SERIAL_RAND_BITS,
                                       OpenSsl.BN_RAND_TOP_ANY, OpenSsl.BN_RAND_BOTTOM_ANY) != 1)
            {
                throw new Exception($"Cannot generate random for serialNumber: {OpenSsl.GetLastError()}");
            }

            var serialNumberAddr = OpenSsl.X509_get_serialNumber(x509);

            if (serialNumberAddr == IntPtr.Zero)
            {
                throw new Exception($"Cannot take address for serialNumber: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.BN_to_ASN1_INTEGER(serialNumber, serialNumberAddr) == IntPtr.Zero)
            {
                throw new Exception($"Cannot assing serialNumber to x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_set_version(x509, 2L) != 1)
            {
                throw new Exception($"Cannot set version to x509: {OpenSsl.GetLastError()}");
            }

            var name = OpenSsl.X509_NAME_new();

            if (name == IntPtr.Zero)
            {
                throw new Exception($"Cannot create name for x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_NAME_add_entry_by_NID(name, OpenSsl.NID_commonName, OpenSsl.MBSTRING_UTF8,
                                                   Marshal.StringToHGlobalAnsi("WebRTC"), -1, 0, 0) != 1)
            {
                throw new Exception($"Cannot assign name for x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_set_subject_name(x509, name) != 1)
            {
                throw new Exception($"Cannot assign subject name to x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_set_issuer_name(x509, name) != 1)
            {
                throw new Exception($"Cannot assign issuer name to x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_gmtime_adj(OpenSsl.X509_getm_notBefore(x509), 0) == IntPtr.Zero)
            {
                throw new Exception($"Cannot assign issuer notBefore to x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_gmtime_adj(OpenSsl.X509_getm_notAfter(x509), DTLS_CERT_LIFETIME) == IntPtr.Zero)
            {
                throw new Exception($"Cannot assign issuer notAfter to x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.X509_sign(x509, key, OpenSsl.EVP_sha256()) == 0)
            {
                throw new Exception($"Cannot sign x509: {OpenSsl.GetLastError()}");
            }

            if (OpenSsl.SSL_CTX_use_certificate(_sslCtx, x509) != 1)
            {
                throw new Exception($"Cannot set cert to ctx: {OpenSsl.GetLastError()}");
            }

            Fingerprint = GetFingerprint(x509);

            if (OpenSsl.SSL_CTX_set_tlsext_use_srtp(_sslCtx, "SRTP_AES128_CM_SHA1_80") != 0)
            {
                throw new Exception($"Cannot add SRTP extension: {OpenSsl.GetLastError()}");
            }

            // TODO Free mem for unnecessary variables
        }