libfreerdp-core: send Access Denied TLS alert when server-side NLA fails

This commit is contained in:
Marc-André Moreau 2013-12-18 19:44:18 -05:00
parent 652dbfd50d
commit 51ad85e0ee
4 changed files with 80 additions and 4 deletions

View File

@ -34,6 +34,35 @@
#include <winpr/stream.h>
#define TLS_ALERT_LEVEL_WARNING 1
#define TLS_ALERT_LEVEL_FATAL 2
#define TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY 0
#define TLS_ALERT_DESCRIPTION_UNEXPECTED_MESSAGE 10
#define TLS_ALERT_DESCRIPTION_BAD_RECORD_MAC 20
#define TLS_ALERT_DESCRIPTION_DECRYPTION_FAILED 21
#define TLS_ALERT_DESCRIPTION_RECORD_OVERFLOW 22
#define TLS_ALERT_DESCRIPTION_DECOMPRESSION_FAILURE 30
#define TLS_ALERT_DESCRIPTION_HANSHAKE_FAILURE 40
#define TLS_ALERT_DESCRIPTION_NO_CERTIFICATE 41
#define TLS_ALERT_DESCRIPTION_BAD_CERTIFICATE 42
#define TLS_ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE 43
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_REVOKED 44
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_EXPIRED 45
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN 46
#define TLS_ALERT_DESCRIPTION_ILLEGAL_PARAMETER 47
#define TLS_ALERT_DESCRIPTION_UNKNOWN_CA 48
#define TLS_ALERT_DESCRIPTION_ACCESS_DENIED 49
#define TLS_ALERT_DESCRIPTION_DECODE_ERROR 50
#define TLS_ALERT_DESCRIPTION_DECRYPT_ERROR 51
#define TLS_ALERT_DESCRIPTION_EXPORT_RESTRICTION 60
#define TLS_ALERT_DESCRIPTION_PROTOCOL_VERSION 70
#define TLS_ALERT_DESCRIPTION_INSUFFICIENT_SECURITY 71
#define TLS_ALERT_DESCRIPTION_INTERNAL_ERROR 80
#define TLS_ALERT_DESCRIPTION_USER_CANCELED 90
#define TLS_ALERT_DESCRIPTION_NO_RENEGOTIATION 100
#define TLS_ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION 110
typedef struct rdp_tls rdpTls;
struct rdp_tls
@ -51,6 +80,8 @@ struct rdp_tls
rdpCertificateStore* certificate_store;
char* hostname;
int port;
int alertLevel;
int alertDescription;
};
FREERDP_API BOOL tls_connect(rdpTls* tls);
@ -65,6 +96,8 @@ FREERDP_API int tls_write_all(rdpTls* tls, BYTE* data, int length);
FREERDP_API int tls_wait_read(rdpTls* tls);
FREERDP_API int tls_wait_write(rdpTls* tls);
FREERDP_API int tls_set_alert_code(rdpTls* tls, int level, int description);
FREERDP_API BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname);
FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint, char* hosts_file);

View File

@ -623,7 +623,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
{
fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status);
return -1;
return -1; /* Access Denied */
}
/* send authentication token */

View File

@ -452,6 +452,9 @@ BOOL transport_accept_nla(rdpTransport* transport)
fprintf(stderr, "client authentication failure\n");
credssp_free(transport->credssp);
transport->credssp = NULL;
tls_set_alert_code(transport->TlsIn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DESCRIPTION_ACCESS_DENIED);
return FALSE;
}

View File

@ -110,8 +110,6 @@ BOOL tls_connect(rdpTls* tls)
CryptoCert cert;
long options = 0;
int connection_status;
char *hostname;
int port;
tls->ctx = SSL_CTX_new(TLSv1_client_method());
@ -360,7 +358,38 @@ BOOL tls_disconnect(rdpTls* tls)
return FALSE;
if (tls->ssl)
SSL_shutdown(tls->ssl);
{
if (tls->alertDescription != TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY)
{
/**
* OpenSSL doesn't really expose an API for sending a TLS alert manually.
*
* The following code disables the sending of the default "close notify"
* and then proceeds to force sending a custom TLS alert before shutting down.
*
* Manually sending a TLS alert is necessary in certain cases,
* like when server-side NLA results in an authentication failure.
*/
SSL_set_quiet_shutdown(tls->ssl, 1);
if ((tls->alertLevel == TLS_ALERT_LEVEL_FATAL) && (tls->ssl->session))
SSL_CTX_remove_session(tls->ssl->ctx, tls->ssl->session);
tls->ssl->s3->alert_dispatch = 1;
tls->ssl->s3->send_alert[0] = tls->alertLevel;
tls->ssl->s3->send_alert[1] = tls->alertDescription;
if (tls->ssl->s3->wbuf.left == 0)
tls->ssl->method->ssl_dispatch_alert(tls->ssl);
SSL_shutdown(tls->ssl);
}
else
{
SSL_shutdown(tls->ssl);
}
}
return TRUE;
}
@ -549,6 +578,14 @@ BOOL tls_print_error(char* func, SSL* connection, int value)
}
}
int tls_set_alert_code(rdpTls* tls, int level, int description)
{
tls->alertLevel = level;
tls->alertDescription = description;
return 0;
}
BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname)
{
if (strlen(hostname) == pattern_length)
@ -868,6 +905,9 @@ rdpTls* tls_new(rdpSettings* settings)
tls->settings = settings;
tls->certificate_store = certificate_store_new(settings);
tls->alertLevel = TLS_ALERT_LEVEL_WARNING;
tls->alertDescription = TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY;
}
return tls;