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]; }
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); }
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); }
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(); } }
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(); } } }
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(); } } }
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 }