diff --git a/Driver.cpp b/Driver.cpp index 6462f1e..5d3c64a 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -336,6 +336,10 @@ VOID OvpnEvtDeviceCleanup(WDFOBJECT obj) { device->Adapter = WDF_NO_HANDLE; ExReleaseSpinLockExclusive(&device->SpinLock, irql); + // OvpnCryptoUninitAlgHandles called outside of lock because + // it requires PASSIVE_LEVEL. + OvpnCryptoUninitAlgHandles(device->AesAlgHandle, device->ChachaAlgHandle); + LOG_EXIT(); } @@ -470,6 +474,8 @@ OvpnEvtDeviceAdd(WDFDRIVER wdfDriver, PWDFDEVICE_INIT deviceInit) { GOTO_IF_NOT_NT_SUCCESS(done, status, OvpnBufferQueueCreate(&device->ControlRxBufferQueue)); GOTO_IF_NOT_NT_SUCCESS(done, status, OvpnBufferQueueCreate(&device->DataRxBufferQueue)); + GOTO_IF_NOT_NT_SUCCESS(done, status, OvpnCryptoInitAlgHandles(&device->AesAlgHandle, &device->ChachaAlgHandle)); + LOG_IF_NOT_NT_SUCCESS(status = OvpnAdapterCreate(device)); done: diff --git a/Driver.h b/Driver.h index 232ad70..9f46a49 100644 --- a/Driver.h +++ b/Driver.h @@ -92,6 +92,9 @@ struct OVPN_DEVICE { _Guarded_by_(SpinLock) WDFTIMER KeepaliveRecvTimer; + BCRYPT_ALG_HANDLE AesAlgHandle; + BCRYPT_ALG_HANDLE ChachaAlgHandle; + // set from the userspace, defines TCP Maximum Segment Size _Guarded_by_(SpinLock) UINT16 MSS; diff --git a/PropertySheet.props b/PropertySheet.props index 986dfd5..5382bfd 100644 --- a/PropertySheet.props +++ b/PropertySheet.props @@ -4,7 +4,7 @@ 1 0 - 0 + 1 diff --git a/crypto.cpp b/crypto.cpp index ce0f809..f75df88 100644 --- a/crypto.cpp +++ b/crypto.cpp @@ -221,7 +221,7 @@ OvpnCryptoEncryptAEAD(OvpnCryptoKeySlot* keySlot, UCHAR* buf, SIZE_T len) _Use_decl_annotations_ NTSTATUS -OvpnCryptoNewKey(OvpnCryptoContext* cryptoContext, POVPN_CRYPTO_DATA cryptoData) +OvpnCryptoNewKey(OvpnCryptoContext* cryptoContext, POVPN_CRYPTO_DATA cryptoData, BCRYPT_ALG_HANDLE algHandle) { OvpnCryptoKeySlot* keySlot = NULL; NTSTATUS status = STATUS_SUCCESS; @@ -249,19 +249,6 @@ OvpnCryptoNewKey(OvpnCryptoContext* cryptoContext, POVPN_CRYPTO_DATA cryptoData) keySlot->DecKey = NULL; } - BCRYPT_ALG_HANDLE algHandle = NULL; - if (cryptoData->CipherAlg == OVPN_CIPHER_ALG_AES_GCM) { - algHandle = cryptoContext->AesAlgHandle; - } - else { - if (cryptoContext->ChachaAlgHandle == NULL) { - LOG_ERROR("CHACHA20-POLY1305 is not available"); - status = STATUS_INVALID_DEVICE_REQUEST; - goto done; - } - algHandle = cryptoContext->ChachaAlgHandle; - } - // generate keys from key materials GOTO_IF_NOT_NT_SUCCESS(done, status, BCryptGenerateSymmetricKey(algHandle, &keySlot->EncKey, NULL, 0, cryptoData->Encrypt.Key, cryptoData->Encrypt.KeyLen, 0)); GOTO_IF_NOT_NT_SUCCESS(done, status, BCryptGenerateSymmetricKey(algHandle, &keySlot->DecKey, NULL, 0, cryptoData->Decrypt.Key, cryptoData->Decrypt.KeyLen, 0)); diff --git a/crypto.h b/crypto.h index dfbc688..11e277e 100644 --- a/crypto.h +++ b/crypto.h @@ -75,9 +75,6 @@ typedef OVPN_CRYPTO_DECRYPT* POVPN_CRYPTO_DECRYPT; struct OvpnCryptoContext { - BCRYPT_ALG_HANDLE AesAlgHandle; - BCRYPT_ALG_HANDLE ChachaAlgHandle; - OvpnCryptoKeySlot Primary; OvpnCryptoKeySlot Secondary; @@ -101,7 +98,7 @@ OvpnCryptoUninit(_In_ OvpnCryptoContext* cryptoContext); _Must_inspect_result_ NTSTATUS -OvpnCryptoNewKey(_In_ OvpnCryptoContext* cryptoContext, _In_ POVPN_CRYPTO_DATA cryptoData); +OvpnCryptoNewKey(_In_ OvpnCryptoContext* cryptoContext, _In_ POVPN_CRYPTO_DATA cryptoData, _In_opt_ BCRYPT_ALG_HANDLE algHandle); _Must_inspect_result_ OvpnCryptoKeySlot* diff --git a/peer.cpp b/peer.cpp index ad14df1..8b92ca0 100644 --- a/peer.cpp +++ b/peer.cpp @@ -74,13 +74,8 @@ OvpnPeerNew(POVPN_DEVICE device, WDFREQUEST request) GOTO_IF_NOT_NT_SUCCESS(done, status, OvpnSocketInit(&driver->WskProviderNpi, &driver->WskRegistration, peer->Local.Addr4.sin_family, proto_tcp, (PSOCKADDR)&peer->Local, (PSOCKADDR)&peer->Remote, remoteAddrSize, device, &socket)); - BCRYPT_ALG_HANDLE aesAlgHandle = NULL, chachaAlgHandle = NULL; - GOTO_IF_NOT_NT_SUCCESS(done, status, OvpnCryptoInitAlgHandles(&aesAlgHandle, &chachaAlgHandle)); - KIRQL kirql = ExAcquireSpinLockExclusive(&device->SpinLock); RtlZeroMemory(&device->CryptoContext, sizeof(OvpnCryptoContext)); - device->CryptoContext.AesAlgHandle = aesAlgHandle; - device->CryptoContext.ChachaAlgHandle = chachaAlgHandle; device->Socket.Socket = socket; device->Socket.Tcp = proto_tcp; RtlZeroMemory(&device->Socket.TcpState, sizeof(OvpnSocketTcpState)); @@ -112,16 +107,11 @@ OvpnPeerDel(POVPN_DEVICE device) return STATUS_INVALID_DEVICE_REQUEST; } - BCRYPT_ALG_HANDLE aesAlgHandle = NULL, chachaAlgHandle = NULL; - KIRQL kirql = ExAcquireSpinLockExclusive(&device->SpinLock); OvpnTimerDestroy(&device->KeepaliveXmitTimer); OvpnTimerDestroy(&device->KeepaliveRecvTimer); - aesAlgHandle = device->CryptoContext.AesAlgHandle; - chachaAlgHandle = device->CryptoContext.ChachaAlgHandle; - OvpnCryptoUninit(&device->CryptoContext); InterlockedExchange(&device->UserspacePid, 0); @@ -132,11 +122,9 @@ OvpnPeerDel(POVPN_DEVICE device) RtlZeroMemory(&device->Socket.TcpState, sizeof(OvpnSocketTcpState)); RtlZeroMemory(&device->Socket.UdpState, sizeof(OvpnSocketUdpState)); - // OvpnCryptoUninitAlgHandles and OvpnSocketClose require PASSIVE_LEVEL, so must release lock + // OvpnSocketClose requires PASSIVE_LEVEL, so must release lock ExReleaseSpinLockExclusive(&device->SpinLock, kirql); - OvpnCryptoUninitAlgHandles(aesAlgHandle, chachaAlgHandle); - LOG_IF_NOT_NT_SUCCESS(OvpnSocketClose(socket)); // flush buffers in control queue so that client won't get control channel messages from previous session @@ -278,7 +266,24 @@ OvpnPeerNewKey(POVPN_DEVICE device, WDFREQUEST request) NTSTATUS status; GOTO_IF_NOT_NT_SUCCESS(done, status, WdfRequestRetrieveInputBuffer(request, sizeof(OVPN_CRYPTO_DATA), (PVOID*)&cryptoData, nullptr)); - GOTO_IF_NOT_NT_SUCCESS(done, status, OvpnCryptoNewKey(&device->CryptoContext, cryptoData)); + + BCRYPT_ALG_HANDLE algHandle = NULL; + switch (cryptoData->CipherAlg) { + case OVPN_CIPHER_ALG_AES_GCM: + algHandle = device->AesAlgHandle; + break; + + case OVPN_CIPHER_ALG_CHACHA20_POLY1305: + algHandle = device->ChachaAlgHandle; + if (algHandle == NULL) { + LOG_ERROR("CHACHA20-POLY1305 is not available"); + status = STATUS_INVALID_DEVICE_REQUEST; + goto done; + } + break; + } + + GOTO_IF_NOT_NT_SUCCESS(done, status, OvpnCryptoNewKey(&device->CryptoContext, cryptoData, algHandle)); done: LOG_EXIT();