secur32: Add support for sending TLS alerts.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55086
This commit is contained in:
parent
aaf051ffff
commit
11afc2da02
5 changed files with 166 additions and 30 deletions
|
@ -63,7 +63,9 @@ struct schan_context
|
|||
ULONG req_ctx_attr;
|
||||
const CERT_CONTEXT *cert;
|
||||
SIZE_T header_size;
|
||||
BOOL shutdown_requested;
|
||||
enum control_token control_token;
|
||||
unsigned int alert_type;
|
||||
unsigned int alert_number;
|
||||
};
|
||||
|
||||
static struct schan_handle *schan_handle_table;
|
||||
|
@ -865,9 +867,9 @@ static SECURITY_STATUS establish_context(
|
|||
unsigned char *ptr;
|
||||
|
||||
if (phContext && !(ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX))) return SEC_E_INVALID_HANDLE;
|
||||
if (!pInput && !ctx->shutdown_requested && !is_dtls_context(ctx)) return SEC_E_INCOMPLETE_MESSAGE;
|
||||
if (!pInput && !ctx->control_token && !is_dtls_context(ctx)) return SEC_E_INCOMPLETE_MESSAGE;
|
||||
|
||||
if (!ctx->shutdown_requested && pInput)
|
||||
if (!ctx->control_token && pInput)
|
||||
{
|
||||
if (!validate_input_buffers(pInput)) return SEC_E_INVALID_TOKEN;
|
||||
if ((idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_TOKEN)) == -1) return SEC_E_INCOMPLETE_MESSAGE;
|
||||
|
@ -940,8 +942,10 @@ static SECURITY_STATUS establish_context(
|
|||
params.input_offset = &input_offset;
|
||||
params.output_buffer_idx = &output_buffer_idx;
|
||||
params.output_offset = &output_offset;
|
||||
params.control_token = ctx->shutdown_requested ? control_token_shutdown : control_token_none;
|
||||
ctx->shutdown_requested = FALSE;
|
||||
params.control_token = ctx->control_token;
|
||||
params.alert_type = ctx->alert_type;
|
||||
params.alert_number = ctx->alert_number;
|
||||
ctx->control_token = CONTROL_TOKEN_NONE;
|
||||
ret = GNUTLS_CALL( handshake, ¶ms );
|
||||
|
||||
if (output_buffer_idx != -1)
|
||||
|
@ -1588,23 +1592,43 @@ static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context
|
|||
static SECURITY_STATUS SEC_ENTRY schan_ApplyControlToken(PCtxtHandle context_handle, PSecBufferDesc input)
|
||||
{
|
||||
struct schan_context *ctx;
|
||||
DWORD type;
|
||||
|
||||
TRACE("%p %p\n", context_handle, input);
|
||||
|
||||
dump_buffer_desc(input);
|
||||
|
||||
if (!context_handle) return SEC_E_INVALID_HANDLE;
|
||||
if (!context_handle || !(ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX)))
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
if (!input) return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
if (input->cBuffers != 1) return SEC_E_INVALID_TOKEN;
|
||||
if (input->pBuffers[0].BufferType != SECBUFFER_TOKEN) return SEC_E_INVALID_TOKEN;
|
||||
if (input->pBuffers[0].cbBuffer < sizeof(DWORD)) return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
if (*(DWORD *)input->pBuffers[0].pvBuffer != SCHANNEL_SHUTDOWN) return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
if (input->pBuffers[0].cbBuffer < sizeof(type)) return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
type = *(DWORD *)input->pBuffers[0].pvBuffer;
|
||||
|
||||
ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
|
||||
ctx->shutdown_requested = TRUE;
|
||||
switch (type)
|
||||
{
|
||||
case SCHANNEL_SHUTDOWN:
|
||||
ctx->control_token = CONTROL_TOKEN_SHUTDOWN;
|
||||
ctx->alert_type = TLS1_ALERT_WARNING;
|
||||
ctx->alert_number = TLS1_ALERT_CLOSE_NOTIFY;
|
||||
return SEC_E_OK;
|
||||
|
||||
return SEC_E_OK;
|
||||
case SCHANNEL_ALERT:
|
||||
{
|
||||
SCHANNEL_ALERT_TOKEN *alert = input->pBuffers[0].pvBuffer;
|
||||
if (input->pBuffers[0].cbBuffer < sizeof(*alert)) return SEC_E_INVALID_TOKEN;
|
||||
ctx->control_token = CONTROL_TOKEN_ALERT;
|
||||
ctx->alert_type = alert->dwAlertType;
|
||||
ctx->alert_number = alert->dwAlertNumber;
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
default:
|
||||
FIXME("token type %lu not supported\n", type);
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
}
|
||||
|
||||
static const SecurityFunctionTableA schanTableA = {
|
||||
|
|
|
@ -84,6 +84,7 @@ static void *libgnutls_handle;
|
|||
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
|
||||
MAKE_FUNCPTR(gnutls_alert_get);
|
||||
MAKE_FUNCPTR(gnutls_alert_get_name);
|
||||
MAKE_FUNCPTR(gnutls_alert_send);
|
||||
MAKE_FUNCPTR(gnutls_certificate_allocate_credentials);
|
||||
MAKE_FUNCPTR(gnutls_certificate_free_credentials);
|
||||
MAKE_FUNCPTR(gnutls_certificate_get_peers);
|
||||
|
@ -121,7 +122,6 @@ MAKE_FUNCPTR(gnutls_x509_crt_deinit);
|
|||
MAKE_FUNCPTR(gnutls_x509_crt_import);
|
||||
MAKE_FUNCPTR(gnutls_x509_crt_init);
|
||||
MAKE_FUNCPTR(gnutls_x509_privkey_deinit);
|
||||
MAKE_FUNCPTR(gnutls_alert_send);
|
||||
#undef MAKE_FUNCPTR
|
||||
|
||||
#if GNUTLS_VERSION_MAJOR < 3
|
||||
|
@ -566,6 +566,74 @@ static NTSTATUS schan_set_session_target( void *args )
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static gnutls_alert_level_t map_alert_type(unsigned int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TLS1_ALERT_WARNING: return GNUTLS_AL_WARNING;
|
||||
case TLS1_ALERT_FATAL: return GNUTLS_AL_FATAL;
|
||||
default:
|
||||
FIXME( "unknown type %u\n", type );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static gnutls_alert_description_t map_alert_number(unsigned int number)
|
||||
{
|
||||
switch (number)
|
||||
{
|
||||
case TLS1_ALERT_CLOSE_NOTIFY: return GNUTLS_A_CLOSE_NOTIFY;
|
||||
case TLS1_ALERT_UNEXPECTED_MESSAGE: return GNUTLS_A_UNEXPECTED_MESSAGE;
|
||||
case TLS1_ALERT_BAD_RECORD_MAC: return GNUTLS_A_BAD_RECORD_MAC;
|
||||
case TLS1_ALERT_DECRYPTION_FAILED: return GNUTLS_A_DECRYPTION_FAILED;
|
||||
case TLS1_ALERT_RECORD_OVERFLOW: return GNUTLS_A_RECORD_OVERFLOW;
|
||||
case TLS1_ALERT_DECOMPRESSION_FAIL: return GNUTLS_A_DECOMPRESSION_FAILURE;
|
||||
case TLS1_ALERT_HANDSHAKE_FAILURE: return GNUTLS_A_HANDSHAKE_FAILURE;
|
||||
case TLS1_ALERT_BAD_CERTIFICATE: return GNUTLS_A_BAD_CERTIFICATE;
|
||||
case TLS1_ALERT_UNSUPPORTED_CERT: return GNUTLS_A_UNSUPPORTED_CERTIFICATE;
|
||||
case TLS1_ALERT_CERTIFICATE_REVOKED: return GNUTLS_A_CERTIFICATE_REVOKED;
|
||||
case TLS1_ALERT_CERTIFICATE_EXPIRED: return GNUTLS_A_CERTIFICATE_EXPIRED;
|
||||
case TLS1_ALERT_CERTIFICATE_UNKNOWN: return GNUTLS_A_CERTIFICATE_UNKNOWN;
|
||||
case TLS1_ALERT_ILLEGAL_PARAMETER: return GNUTLS_A_ILLEGAL_PARAMETER;
|
||||
case TLS1_ALERT_UNKNOWN_CA: return GNUTLS_A_UNKNOWN_CA;
|
||||
case TLS1_ALERT_ACCESS_DENIED: return GNUTLS_A_ACCESS_DENIED;
|
||||
case TLS1_ALERT_DECODE_ERROR: return GNUTLS_A_DECODE_ERROR;
|
||||
case TLS1_ALERT_DECRYPT_ERROR: return GNUTLS_A_DECRYPT_ERROR;
|
||||
case TLS1_ALERT_EXPORT_RESTRICTION: return GNUTLS_A_EXPORT_RESTRICTION;
|
||||
case TLS1_ALERT_PROTOCOL_VERSION: return GNUTLS_A_PROTOCOL_VERSION;
|
||||
case TLS1_ALERT_INSUFFIENT_SECURITY: return GNUTLS_A_INSUFFICIENT_SECURITY;
|
||||
case TLS1_ALERT_INTERNAL_ERROR: return GNUTLS_A_INTERNAL_ERROR;
|
||||
case TLS1_ALERT_USER_CANCELED: return GNUTLS_A_USER_CANCELED;
|
||||
case TLS1_ALERT_NO_RENEGOTIATION: return GNUTLS_A_NO_RENEGOTIATION;
|
||||
case TLS1_ALERT_UNSUPPORTED_EXT: return GNUTLS_A_UNSUPPORTED_EXTENSION;
|
||||
case TLS1_ALERT_UNKNOWN_PSK_IDENTITY: return GNUTLS_A_UNKNOWN_PSK_IDENTITY;
|
||||
case TLS1_ALERT_NO_APP_PROTOCOL: return GNUTLS_A_NO_APPLICATION_PROTOCOL;
|
||||
default:
|
||||
FIXME("unhandled alert %u\n", number);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS send_alert(gnutls_session_t session, unsigned int type, unsigned int number)
|
||||
{
|
||||
gnutls_alert_level_t level = map_alert_type(type);
|
||||
gnutls_alert_description_t desc = map_alert_number(number);
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = pgnutls_alert_send(session, level, desc);
|
||||
}
|
||||
while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
pgnutls_perror(ret);
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS schan_handshake( void *args )
|
||||
{
|
||||
const struct handshake_params *params = args;
|
||||
|
@ -578,22 +646,9 @@ static NTSTATUS schan_handshake( void *args )
|
|||
t->in.limit = params->input_size;
|
||||
init_schan_buffers(&t->out, params->output);
|
||||
|
||||
if (params->control_token == control_token_shutdown)
|
||||
if (params->control_token)
|
||||
{
|
||||
err = pgnutls_alert_send(s, GNUTLS_AL_WARNING, GNUTLS_A_CLOSE_NOTIFY);
|
||||
if (err == GNUTLS_E_SUCCESS)
|
||||
{
|
||||
status = SEC_E_OK;
|
||||
}
|
||||
else if (err == GNUTLS_E_AGAIN)
|
||||
{
|
||||
status = SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
pgnutls_perror(err);
|
||||
status = SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
status = send_alert(s, params->alert_type, params->alert_number);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -1431,6 +1486,7 @@ static NTSTATUS process_attach( void *args )
|
|||
|
||||
LOAD_FUNCPTR(gnutls_alert_get)
|
||||
LOAD_FUNCPTR(gnutls_alert_get_name)
|
||||
LOAD_FUNCPTR(gnutls_alert_send)
|
||||
LOAD_FUNCPTR(gnutls_certificate_allocate_credentials)
|
||||
LOAD_FUNCPTR(gnutls_certificate_free_credentials)
|
||||
LOAD_FUNCPTR(gnutls_certificate_get_peers)
|
||||
|
@ -1468,7 +1524,6 @@ static NTSTATUS process_attach( void *args )
|
|||
LOAD_FUNCPTR(gnutls_x509_crt_import)
|
||||
LOAD_FUNCPTR(gnutls_x509_crt_init)
|
||||
LOAD_FUNCPTR(gnutls_x509_privkey_deinit)
|
||||
LOAD_FUNCPTR(gnutls_alert_send)
|
||||
#undef LOAD_FUNCPTR
|
||||
|
||||
if (!(pgnutls_cipher_get_block_size = dlsym(libgnutls_handle, "gnutls_cipher_get_block_size")))
|
||||
|
@ -1751,6 +1806,8 @@ static NTSTATUS wow64_schan_handshake( void *args )
|
|||
PTR32 output_buffer_idx;
|
||||
PTR32 output_offset;
|
||||
enum control_token control_token;
|
||||
unsigned int alert_type;
|
||||
unsigned int alert_number;
|
||||
} const *params32 = args;
|
||||
struct handshake_params params =
|
||||
{
|
||||
|
@ -1762,6 +1819,8 @@ static NTSTATUS wow64_schan_handshake( void *args )
|
|||
ULongToPtr(params32->output_buffer_idx),
|
||||
ULongToPtr(params32->output_offset),
|
||||
params32->control_token,
|
||||
params32->alert_type,
|
||||
params32->alert_number,
|
||||
};
|
||||
if (params32->input)
|
||||
{
|
||||
|
|
|
@ -147,8 +147,9 @@ struct get_unique_channel_binding_params
|
|||
|
||||
enum control_token
|
||||
{
|
||||
control_token_none,
|
||||
control_token_shutdown,
|
||||
CONTROL_TOKEN_NONE,
|
||||
CONTROL_TOKEN_SHUTDOWN,
|
||||
CONTROL_TOKEN_ALERT,
|
||||
};
|
||||
|
||||
struct handshake_params
|
||||
|
@ -161,6 +162,8 @@ struct handshake_params
|
|||
int *output_buffer_idx;
|
||||
ULONG *output_offset;
|
||||
enum control_token control_token;
|
||||
unsigned int alert_type;
|
||||
unsigned int alert_number;
|
||||
};
|
||||
|
||||
struct recv_params
|
||||
|
|
|
@ -1963,6 +1963,7 @@ static void test_connection_shutdown(void)
|
|||
CredHandle cred_handle;
|
||||
SCHANNEL_CRED cred;
|
||||
SecBuffer *buf;
|
||||
SCHANNEL_ALERT_TOKEN alert;
|
||||
ULONG attrs;
|
||||
void *tmp;
|
||||
|
||||
|
@ -2075,6 +2076,18 @@ static void test_connection_shutdown(void)
|
|||
ok( buf->cbBuffer == sizeof(message), "got cbBuffer %#lx.\n", buf->cbBuffer );
|
||||
ok( !memcmp( buf->pvBuffer, message, sizeof(message) ), "message data mismatch.\n" );
|
||||
|
||||
alert.dwTokenType = SCHANNEL_ALERT;
|
||||
alert.dwAlertType = TLS1_ALERT_FATAL;
|
||||
alert.dwAlertNumber = TLS1_ALERT_BAD_CERTIFICATE;
|
||||
memcpy(buf->pvBuffer, &alert, sizeof(alert));
|
||||
buf->cbBuffer = sizeof(alert);
|
||||
status = ApplyControlToken( &context, buffers );
|
||||
ok( status == SEC_E_OK, "got %08lx.\n", status );
|
||||
|
||||
status = InitializeSecurityContextA( &cred_handle, &context, NULL, 0, 0, 0,
|
||||
NULL, 0, NULL, &buffers[1], &attrs, NULL );
|
||||
ok( status == SEC_E_OK, "got %08lx.\n", status );
|
||||
|
||||
free_buffers( &buffers[0] );
|
||||
free_buffers( &buffers[1] );
|
||||
DeleteSecurityContext( &context );
|
||||
|
|
|
@ -88,6 +88,43 @@ static const WCHAR SCHANNEL_NAME_W[] = { 'S','c','h','a','n','n','e','l',0 };
|
|||
#define SCHANNEL_ALERT 2
|
||||
#define SCHANNEL_SESSION 3
|
||||
|
||||
typedef struct _SCHANNEL_ALERT_TOKEN
|
||||
{
|
||||
DWORD dwTokenType;
|
||||
DWORD dwAlertType;
|
||||
DWORD dwAlertNumber;
|
||||
} SCHANNEL_ALERT_TOKEN;
|
||||
|
||||
#define TLS1_ALERT_WARNING 1
|
||||
#define TLS1_ALERT_FATAL 2
|
||||
|
||||
#define TLS1_ALERT_CLOSE_NOTIFY 0
|
||||
#define TLS1_ALERT_UNEXPECTED_MESSAGE 10
|
||||
#define TLS1_ALERT_BAD_RECORD_MAC 20
|
||||
#define TLS1_ALERT_DECRYPTION_FAILED 21
|
||||
#define TLS1_ALERT_RECORD_OVERFLOW 22
|
||||
#define TLS1_ALERT_DECOMPRESSION_FAIL 30
|
||||
#define TLS1_ALERT_HANDSHAKE_FAILURE 40
|
||||
#define TLS1_ALERT_BAD_CERTIFICATE 42
|
||||
#define TLS1_ALERT_UNSUPPORTED_CERT 43
|
||||
#define TLS1_ALERT_CERTIFICATE_REVOKED 44
|
||||
#define TLS1_ALERT_CERTIFICATE_EXPIRED 45
|
||||
#define TLS1_ALERT_CERTIFICATE_UNKNOWN 46
|
||||
#define TLS1_ALERT_ILLEGAL_PARAMETER 47
|
||||
#define TLS1_ALERT_UNKNOWN_CA 48
|
||||
#define TLS1_ALERT_ACCESS_DENIED 49
|
||||
#define TLS1_ALERT_DECODE_ERROR 50
|
||||
#define TLS1_ALERT_DECRYPT_ERROR 51
|
||||
#define TLS1_ALERT_EXPORT_RESTRICTION 60
|
||||
#define TLS1_ALERT_PROTOCOL_VERSION 70
|
||||
#define TLS1_ALERT_INSUFFIENT_SECURITY 71
|
||||
#define TLS1_ALERT_INTERNAL_ERROR 80
|
||||
#define TLS1_ALERT_USER_CANCELED 90
|
||||
#define TLS1_ALERT_NO_RENEGOTIATION 100
|
||||
#define TLS1_ALERT_UNSUPPORTED_EXT 110
|
||||
#define TLS1_ALERT_UNKNOWN_PSK_IDENTITY 115
|
||||
#define TLS1_ALERT_NO_APP_PROTOCOL 120
|
||||
|
||||
#define SP_PROT_ALL 0xffffffff
|
||||
#define SP_PROT_UNI_CLIENT 0x80000000
|
||||
#define SP_PROT_UNI_SERVER 0x40000000
|
||||
|
|
Loading…
Add table
Reference in a new issue