1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-08 14:02:17 +03:00

CONC-446 For Schannel errors, provide better errors

Print error symbol (e.g S"EC_E_ILLEGAL_MESSAGE") in the error message
for some schannel errors, in addition to error message

Print error code for all errors coming from schannel.

Fix some whitespace.
This commit is contained in:
Vladislav Vaintroub
2019-11-29 11:19:48 +01:00
parent f035fc5f7f
commit c8833751cf
2 changed files with 69 additions and 63 deletions

View File

@@ -26,69 +26,73 @@
#define MAX_SSL_ERR_LEN 100 #define MAX_SSL_ERR_LEN 100
#define SCHANNEL_PAYLOAD(A) (A).cbMaximumMessage + (A).cbHeader + (A).cbTrailer #define SCHANNEL_PAYLOAD(A) (A).cbMaximumMessage + (A).cbHeader + (A).cbTrailer
void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo __attribute__((unused))); void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
static void get_schannel_error_info(DWORD err, const char** sym, const char** text)
{
#define ERR_ENTRY(a,b) {a,#a, b}
static struct {
DWORD code; /* Error code , e.g SEC_E_ILLEGAL_MESSAGE */
const char* symbol; /* Error code as string, e.g "SEC_E_ILLEGAL_MESSAGE"*/
const char* msg; /* English text message */
} errinfo[] =
{
ERR_ENTRY(SEC_E_ILLEGAL_MESSAGE, "The message received was unexpected or badly formatted"),
ERR_ENTRY(SEC_E_UNTRUSTED_ROOT, "Untrusted root certificate"),
ERR_ENTRY(SEC_E_BUFFER_TOO_SMALL, "Buffer too small"),
ERR_ENTRY(SEC_E_CRYPTO_SYSTEM_INVALID, "Cipher is not supported"),
ERR_ENTRY(SEC_E_INSUFFICIENT_MEMORY, "Out of memory"),
ERR_ENTRY(SEC_E_OUT_OF_SEQUENCE, "Invalid message sequence"),
ERR_ENTRY(SEC_E_DECRYPT_FAILURE, "The specified data could not be decrypted"),
ERR_ENTRY(SEC_I_INCOMPLETE_CREDENTIALS, "Incomplete credentials"),
ERR_ENTRY(SEC_E_ENCRYPT_FAILURE, "The specified data could not be encrypted"),
ERR_ENTRY(SEC_I_CONTEXT_EXPIRED, "The context has expired and can no longer be used"),
ERR_ENTRY(SEC_E_ALGORITHM_MISMATCH, "no cipher match"),
ERR_ENTRY(SEC_E_NO_CREDENTIALS, "no credentials"),
ERR_ENTRY(SEC_E_INVALID_TOKEN, "The token supplied to function is invalid")
};
for (int i = 0; i < sizeof(errinfo) / sizeof(errinfo[0]); i++)
{
if (errinfo[i].code == err)
{
*sym = errinfo[i].symbol;
*text = errinfo[i].msg;
return;
}
}
*sym = NULL;
*text = NULL;
}
/* {{{ void ma_schannel_set_sec_error */ /* {{{ void ma_schannel_set_sec_error */
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo) void ma_schannel_set_sec_error(MARIADB_PVIO* pvio, DWORD ErrorNo)
{ {
MYSQL *mysql= pvio->mysql; MYSQL* mysql = pvio->mysql;
const char* sym;
const char* text;
if (ErrorNo != SEC_E_OK) if (ErrorNo != SEC_E_OK)
mysql->net.extension->extended_errno= ErrorNo; mysql->net.extension->extended_errno = ErrorNo;
if (ErrorNo == SEC_E_INTERNAL_ERROR && GetLastError())
switch(ErrorNo) { {
case SEC_E_ILLEGAL_MESSAGE: ma_schannel_set_win_error(pvio, GetLastError());
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: The message received was unexpected or badly formatted"); return;
break; }
case SEC_E_UNTRUSTED_ROOT: get_schannel_error_info(ErrorNo, &sym, &text);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Untrusted root certificate"); if (sym)
break; {
case SEC_E_BUFFER_TOO_SMALL: pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Buffer too small"); "SSL connection error: %s (%s , 0x%08x)", text, sym, ErrorNo);
break; }
case SEC_E_CRYPTO_SYSTEM_INVALID: else
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Cipher is not supported"); {
break;
case SEC_E_INSUFFICIENT_MEMORY:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Out of memory");
break;
case SEC_E_OUT_OF_SEQUENCE:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Invalid message sequence");
break;
case SEC_E_DECRYPT_FAILURE:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: An error occurred during decrypting data");
break;
case SEC_I_INCOMPLETE_CREDENTIALS:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Incomplete credentials");
break;
case SEC_E_ENCRYPT_FAILURE:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: An error occurred during encrypting data");
break;
case SEC_I_CONTEXT_EXPIRED:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Context expired ");
break;
case SEC_E_ALGORITHM_MISMATCH:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: no cipher match");
break;
case SEC_E_NO_CREDENTIALS:
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: no credentials");
break;
case SEC_E_OK:
break;
case SEC_E_INTERNAL_ERROR:
if (GetLastError())
ma_schannel_set_win_error(pvio, 0);
else
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "The Local Security Authority cannot be contacted");
break;
default:
ma_schannel_set_win_error(pvio, ErrorNo); ma_schannel_set_win_error(pvio, ErrorNo);
} }
} }
/* }}} */ /* }}} */
/* {{{ void ma_schnnel_set_win_error */ /* {{{ void ma_schnnel_set_win_error */
void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo __attribute__((unused))) void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo)
{ {
ulong ssl_errno= ErrorNo ? ErrorNo : GetLastError(); ulong ssl_errno= ErrorNo ? ErrorNo : GetLastError();
char *ssl_error_reason= NULL; char *ssl_error_reason= NULL;
@@ -99,14 +103,15 @@ void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo __attribute__((
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error"); pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
return; return;
} }
/* todo: obtain error message */
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ssl_errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), NULL, ssl_errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &ssl_error_reason, 0, NULL ); (LPTSTR) &ssl_error_reason, 0, NULL );
for (p = ssl_error_reason; *p; p++) for (p = ssl_error_reason; *p; p++)
if (*p == '\n' || *p == '\r') if (*p == '\n' || *p == '\r')
*p = 0; *p = 0;
snprintf(buffer, sizeof(buffer), "SSL connection error: %s",ssl_error_reason); snprintf(buffer, sizeof(buffer), "SSL connection error: %s. Windows error %lu / 0x%08lx",ssl_error_reason,
ErrorNo, ErrorNo);
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, buffer); pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, buffer);
if (ssl_error_reason) if (ssl_error_reason)
LocalFree(ssl_error_reason); LocalFree(ssl_error_reason);
@@ -728,7 +733,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRe
{ {
if (!(pExtraData->pvBuffer= LocalAlloc(0, InBuffers[1].cbBuffer))) if (!(pExtraData->pvBuffer= LocalAlloc(0, InBuffers[1].cbBuffer)))
return SEC_E_INSUFFICIENT_MEMORY; return SEC_E_INSUFFICIENT_MEMORY;
MoveMemory(pExtraData->pvBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer ); MoveMemory(pExtraData->pvBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer );
pExtraData->BufferType = SECBUFFER_TOKEN; pExtraData->BufferType = SECBUFFER_TOKEN;
pExtraData->cbBuffer = InBuffers[1].cbBuffer; pExtraData->cbBuffer = InBuffers[1].cbBuffer;
@@ -740,7 +745,7 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRe
pExtraData->cbBuffer= 0; pExtraData->cbBuffer= 0;
} }
break; break;
case SEC_I_INCOMPLETE_CREDENTIALS: case SEC_I_INCOMPLETE_CREDENTIALS:
/* Provided credentials didn't contain a valid client certificate. /* Provided credentials didn't contain a valid client certificate.
We will try to connect anonymously, using current credentials */ We will try to connect anonymously, using current credentials */
@@ -801,10 +806,10 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls)
SC_CTX *sctx; SC_CTX *sctx;
SecBuffer ExtraData; SecBuffer ExtraData;
DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_USE_SUPPLIED_CREDS |
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
SecBufferDesc BufferOut; SecBufferDesc BufferOut;
SecBuffer BuffersOut; SecBuffer BuffersOut;
@@ -845,7 +850,7 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls)
/* send client hello packaet */ /* send client hello packaet */
if(BuffersOut.cbBuffer != 0 && BuffersOut.pvBuffer != NULL) if(BuffersOut.cbBuffer != 0 && BuffersOut.pvBuffer != NULL)
{ {
ssize_t nbytes = (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut.pvBuffer, (size_t)BuffersOut.cbBuffer); ssize_t nbytes = (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut.pvBuffer, (size_t)BuffersOut.cbBuffer);
if (nbytes <= 0) if (nbytes <= 0)
@@ -873,7 +878,9 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls)
end: end:
LocalFree(sctx->IoBuffer); LocalFree(sctx->IoBuffer);
sctx->IoBufferSize= 0; sctx->IoBufferSize= 0;
FreeContextBuffer(BuffersOut.pvBuffer); if (BuffersOut.pvBuffer)
FreeContextBuffer(BuffersOut.pvBuffer);
DeleteSecurityContext(&sctx->ctxt); DeleteSecurityContext(&sctx->ctxt);
return sRet; return sRet;
} }

View File

@@ -158,8 +158,7 @@ cipher_map[] =
#define MAX_ALG_ID 50 #define MAX_ALG_ID 50
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo); extern void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
void ma_schannel_set_win_error(MYSQL *mysql);
/* /*
Initializes SSL and allocate global Initializes SSL and allocate global