You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
CONC-567 Schannel - handle SEC_I_RENEGOTIATE, prepare for TLSv1.3
There is no real renegotiation in TLSv1.3 protocol, so it is some internal schannel thing, that makes DecryptMessage() to return SEC_I_RENEGOTIATE, to replay a handshake step. This pops up when TLSv1.3 is enabled.
This commit is contained in:
@@ -100,6 +100,13 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRe
|
|||||||
return SEC_E_INSUFFICIENT_MEMORY;
|
return SEC_E_INSUFFICIENT_MEMORY;
|
||||||
|
|
||||||
cbIoBuffer = 0;
|
cbIoBuffer = 0;
|
||||||
|
|
||||||
|
if (!InitialRead && pExtraData->cbBuffer)
|
||||||
|
{
|
||||||
|
memcpy(IoBuffer, pExtraData->pvBuffer,pExtraData->cbBuffer);
|
||||||
|
cbIoBuffer= pExtraData->cbBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
fDoRead = InitialRead;
|
fDoRead = InitialRead;
|
||||||
|
|
||||||
/* handshake loop: We will leave if handshake is finished
|
/* handshake loop: We will leave if handshake is finished
|
||||||
@@ -282,6 +289,8 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls)
|
|||||||
SecBufferDesc BufferOut;
|
SecBufferDesc BufferOut;
|
||||||
SecBuffer BuffersOut;
|
SecBuffer BuffersOut;
|
||||||
|
|
||||||
|
SecBufferDesc *pBuffersIn= NULL;
|
||||||
|
|
||||||
if (!ctls || !ctls->pvio)
|
if (!ctls || !ctls->pvio)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -445,7 +454,7 @@ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio,
|
|||||||
} while (sRet == SEC_E_INCOMPLETE_MESSAGE); /* Continue reading until full message arrives */
|
} while (sRet == SEC_E_INCOMPLETE_MESSAGE); /* Continue reading until full message arrives */
|
||||||
|
|
||||||
|
|
||||||
if (sRet != SEC_E_OK)
|
if (sRet != SEC_E_OK && sRet != SEC_I_RENEGOTIATE)
|
||||||
{
|
{
|
||||||
ma_schannel_set_sec_error(pvio, sRet);
|
ma_schannel_set_sec_error(pvio, sRet);
|
||||||
return sRet;
|
return sRet;
|
||||||
@@ -462,7 +471,7 @@ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (sctx->dataBuf.cbBuffer)
|
if (sctx->dataBuf.cbBuffer || sRet == SEC_I_RENEGOTIATE)
|
||||||
{
|
{
|
||||||
assert(sctx->dataBuf.pvBuffer);
|
assert(sctx->dataBuf.pvBuffer);
|
||||||
/*
|
/*
|
||||||
@@ -470,12 +479,13 @@ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio,
|
|||||||
Store the rest (if any) to be processed next time.
|
Store the rest (if any) to be processed next time.
|
||||||
*/
|
*/
|
||||||
nbytes = MIN(sctx->dataBuf.cbBuffer, ReadBufferSize);
|
nbytes = MIN(sctx->dataBuf.cbBuffer, ReadBufferSize);
|
||||||
memcpy((char *)ReadBuffer, sctx->dataBuf.pvBuffer, nbytes);
|
if (nbytes)
|
||||||
|
memcpy((char *)ReadBuffer, sctx->dataBuf.pvBuffer, nbytes);
|
||||||
sctx->dataBuf.cbBuffer -= (unsigned long)nbytes;
|
sctx->dataBuf.cbBuffer -= (unsigned long)nbytes;
|
||||||
sctx->dataBuf.pvBuffer = (char *)sctx->dataBuf.pvBuffer + nbytes;
|
sctx->dataBuf.pvBuffer = (char *)sctx->dataBuf.pvBuffer + nbytes;
|
||||||
|
|
||||||
*DecryptLength = (DWORD)nbytes;
|
*DecryptLength = (DWORD)nbytes;
|
||||||
return SEC_E_OK;
|
return sRet;
|
||||||
}
|
}
|
||||||
// No data buffer, loop
|
// No data buffer, loop
|
||||||
}
|
}
|
||||||
|
@@ -472,13 +472,50 @@ ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
|
|||||||
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
|
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
|
||||||
MARIADB_PVIO *pvio= ctls->pvio;
|
MARIADB_PVIO *pvio= ctls->pvio;
|
||||||
DWORD dlength= 0;
|
DWORD dlength= 0;
|
||||||
SECURITY_STATUS status = ma_schannel_read_decrypt(pvio, &sctx->hCtxt, &dlength, (uchar *)buffer, (DWORD)length);
|
SECURITY_STATUS status;
|
||||||
if (status == SEC_I_CONTEXT_EXPIRED)
|
SecBuffer tmp_extra_buf= {0};
|
||||||
return 0; /* other side shut down the connection. */
|
|
||||||
if (status == SEC_I_RENEGOTIATE)
|
|
||||||
return -1; /* Do not handle renegotiate yet */
|
|
||||||
|
|
||||||
return (status == SEC_E_OK)? (ssize_t)dlength : -1;
|
retry:
|
||||||
|
status= ma_schannel_read_decrypt(pvio, &sctx->hCtxt, &dlength,
|
||||||
|
(uchar *) buffer, (DWORD) length);
|
||||||
|
if (tmp_extra_buf.cbBuffer)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This memory was allocated in renegotiation processing
|
||||||
|
below, free it.
|
||||||
|
*/
|
||||||
|
LocalFree(tmp_extra_buf.pvBuffer);
|
||||||
|
tmp_extra_buf.cbBuffer= 0;
|
||||||
|
}
|
||||||
|
switch (status) {
|
||||||
|
case SEC_E_OK:
|
||||||
|
return (ssize_t) dlength;
|
||||||
|
case SEC_I_CONTEXT_EXPIRED:
|
||||||
|
/* Other side shut down the connection. */
|
||||||
|
return 0;
|
||||||
|
case SEC_I_RENEGOTIATE:
|
||||||
|
/* Rerun handshake steps */
|
||||||
|
tmp_extra_buf= sctx->extraBuf;
|
||||||
|
tmp_extra_buf.BufferType= SECBUFFER_TOKEN;
|
||||||
|
sctx->extraBuf.cbBuffer= 0;
|
||||||
|
sctx->extraBuf.pvBuffer= NULL;
|
||||||
|
status= ma_schannel_handshake_loop(pvio, FALSE, &tmp_extra_buf);
|
||||||
|
sctx->extraBuf= tmp_extra_buf;
|
||||||
|
if (status != SEC_E_OK)
|
||||||
|
return -1;
|
||||||
|
/*
|
||||||
|
If decrypt returned some decrypted bytes prior to
|
||||||
|
renegotiation, return them.
|
||||||
|
Otherwise, retry the read-decrypt again
|
||||||
|
*/
|
||||||
|
if (dlength)
|
||||||
|
return dlength;
|
||||||
|
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
|
ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
|
||||||
|
Reference in New Issue
Block a user