Security improvements
1) In FIPS mode, Classic RDP security is not allowed at all. 2) In FIPS mode xrdp-keygen creates an empty file 3) Documentation wording improved around the security_level setting 4) Logging improved around the security negotiation 5) Warnings now generated if Classic RDP security is negotiated
This commit is contained in:
+81
-92
@@ -60,20 +60,7 @@ protocol_mask_to_str(int protocol, char *buff, int bufflen)
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int rlen = g_bitmask_to_str(protocol, bits, delim, buff, bufflen);
|
||||
|
||||
/* Append "RDP" */
|
||||
if (rlen == 0)
|
||||
{
|
||||
/* String is empty */
|
||||
rlen = g_snprintf(buff, bufflen, "RDP");
|
||||
}
|
||||
else if (rlen > 0 && rlen < bufflen)
|
||||
{
|
||||
rlen += g_snprintf(buff + rlen, bufflen - rlen, "%cRDP", delim);
|
||||
}
|
||||
|
||||
return rlen;
|
||||
return g_bitmask_to_str(protocol, bits, delim, buff, bufflen);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -105,95 +92,97 @@ xrdp_iso_delete(struct xrdp_iso *self)
|
||||
static int
|
||||
xrdp_iso_negotiate_security(struct xrdp_iso *self)
|
||||
{
|
||||
char requested_str[64];
|
||||
const char *selected_str = "";
|
||||
const char *configured_str = "";
|
||||
|
||||
int rv = 0;
|
||||
struct xrdp_client_info *client_info = &(self->mcs_layer->sec_layer->rdp_layer->client_info);
|
||||
char protostr[64];
|
||||
int got_protocol = 0;
|
||||
int security_type_mask;
|
||||
|
||||
/* Can we do TLS/SSL? (basic check) */
|
||||
int ssl_capable = g_file_readable(client_info->certificate) &&
|
||||
g_file_readable(client_info->key_file);
|
||||
/* Map the configuration from xrdp.ini to a mask of allowed
|
||||
* security types ([MS-RDPBCGR] 2.2.1.2.1)
|
||||
*
|
||||
* There's some oddness around PROTOCOL_RDP. This value is 0,
|
||||
* for compatibility reasons, and it's OK for the server to
|
||||
* suggest RDP as the fallback protocol if nothing else is
|
||||
* agreed on. Nowadays, classic RDP security should
|
||||
* not be used, if at all avoidable */
|
||||
|
||||
/* Work out what's actually configured in xrdp.ini. The
|
||||
* selection happens later, but we can do some error checking here */
|
||||
switch (client_info->security_layer)
|
||||
/* At present we only support SSL and RDP security */
|
||||
if (client_info->security_layer == SECURITY_LAYER_RDP)
|
||||
{
|
||||
case PROTOCOL_RDP:
|
||||
configured_str = "RDP";
|
||||
break;
|
||||
|
||||
case PROTOCOL_SSL:
|
||||
/* We *must* use TLS. Check we can offer it, and it's requested */
|
||||
if (ssl_capable)
|
||||
{
|
||||
configured_str = "SSL";
|
||||
if ((self->requestedProtocol & PROTOCOL_SSL) == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Server requires TLS for security, "
|
||||
"but the client did not request TLS.");
|
||||
self->failureCode = SSL_REQUIRED_BY_SERVER;
|
||||
rv = 1; /* error */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
configured_str = "";
|
||||
LOG(LOG_LEVEL_ERROR, "Cannot accept TLS connections because "
|
||||
"certificate or private key file is not readable. "
|
||||
"certificate file: [%s], private key file: [%s]",
|
||||
client_info->certificate, client_info->key_file);
|
||||
self->failureCode = SSL_CERT_NOT_ON_SERVER;
|
||||
rv = 1; /* error */
|
||||
}
|
||||
break;
|
||||
case PROTOCOL_HYBRID:
|
||||
case PROTOCOL_HYBRID_EX:
|
||||
default:
|
||||
/* We don't yet support CredSSP */
|
||||
if (ssl_capable)
|
||||
{
|
||||
configured_str = "SSL|RDP";
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Tell the user we can't offer TLS, but this isn't fatal */
|
||||
configured_str = "RDP";
|
||||
LOG(LOG_LEVEL_WARNING, "Cannot accept TLS connections because "
|
||||
"certificate or private key file is not readable. "
|
||||
"certificate file: [%s], private key file: [%s]",
|
||||
client_info->certificate, client_info->key_file);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Currently the choice comes down to RDP or SSL */
|
||||
if (rv != 0)
|
||||
{
|
||||
self->selectedProtocol = PROTOCOL_RDP;
|
||||
selected_str = "";
|
||||
}
|
||||
else if (ssl_capable && (self->requestedProtocol &
|
||||
client_info->security_layer &
|
||||
PROTOCOL_SSL) != 0)
|
||||
{
|
||||
self->selectedProtocol = PROTOCOL_SSL;
|
||||
selected_str = "SSL";
|
||||
security_type_mask = PROTOCOL_RDP;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->selectedProtocol = PROTOCOL_RDP;
|
||||
selected_str = "RDP";
|
||||
security_type_mask = PROTOCOL_SSL;
|
||||
}
|
||||
|
||||
protocol_mask_to_str(self->requestedProtocol,
|
||||
requested_str, sizeof(requested_str));
|
||||
/* Logically 'and' this value with the mask requested by the client, and
|
||||
* see what's left */
|
||||
protocol_mask_to_str(self->requestedProtocol, protostr, sizeof(protostr));
|
||||
LOG(LOG_LEVEL_INFO, "Client requested security types (RDP assumed) : %s",
|
||||
protostr);
|
||||
security_type_mask &= self->requestedProtocol;
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "Security protocol: configured [%s], requested [%s],"
|
||||
" selected [%s]",
|
||||
configured_str, requested_str, selected_str);
|
||||
/* Is there a match on SSL/TLS? */
|
||||
if ((security_type_mask & PROTOCOL_SSL) != 0)
|
||||
{
|
||||
/* Can we do TLS? (basic check) */
|
||||
if (g_file_readable(client_info->certificate) &&
|
||||
g_file_readable(client_info->key_file))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Selected TLS security");
|
||||
self->selectedProtocol = PROTOCOL_SSL;
|
||||
got_protocol = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Cannot accept TLS connections because "
|
||||
"certificate or private key file is not readable. "
|
||||
"certificate file: [%s], private key file: [%s]",
|
||||
client_info->certificate, client_info->key_file);
|
||||
|
||||
/* If we're configured to ONLY use TLS, this is a problem.
|
||||
* If not, we can fall back to RDP */
|
||||
if (client_info->security_layer == SECURITY_LAYER_TLS)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Server requires TLS (security_layer=tls)");
|
||||
self->failureCode = SSL_CERT_NOT_ON_SERVER;
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (client_info->security_layer == SECURITY_LAYER_TLS)
|
||||
{
|
||||
/* We don't have a match on TLS, but we'll accept nothing less */
|
||||
LOG(LOG_LEVEL_ERROR, "Server requires TLS (security_layer=tls)");
|
||||
self->failureCode = SSL_REQUIRED_BY_SERVER;
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
/* If we haven't got a match so far, and we haven't got a fail,
|
||||
* try RDP */
|
||||
if (!got_protocol && !rv)
|
||||
{
|
||||
if (g_fips_mode_enabled())
|
||||
{
|
||||
/* This is a FIPS-mode machine, and we don't support classic RDP
|
||||
* encryption */
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Server in FIPS mode requires TLS for security");
|
||||
self->failureCode = SSL_REQUIRED_BY_SERVER;
|
||||
rv = 1; /* error */
|
||||
}
|
||||
else
|
||||
{
|
||||
self->selectedProtocol = PROTOCOL_RDP;
|
||||
LOG(LOG_LEVEL_INFO, "Selected classic RDP security");
|
||||
LOG(LOG_LEVEL_WARNING, "Classic RDP security is not secure -"
|
||||
" please configure TLS on the client and server");
|
||||
got_protocol = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
+4
-8
@@ -193,26 +193,22 @@ xrdp_rdp_read_config(const char *xrdp_ini, struct xrdp_client_info *client_info)
|
||||
{
|
||||
if (g_strcasecmp(value, "rdp") == 0)
|
||||
{
|
||||
client_info->security_layer = PROTOCOL_RDP;
|
||||
client_info->security_layer = SECURITY_LAYER_RDP;
|
||||
}
|
||||
else if (g_strcasecmp(value, "tls") == 0)
|
||||
{
|
||||
client_info->security_layer = PROTOCOL_SSL;
|
||||
}
|
||||
else if (g_strcasecmp(value, "hybrid") == 0)
|
||||
{
|
||||
client_info->security_layer = PROTOCOL_SSL | PROTOCOL_HYBRID;
|
||||
client_info->security_layer = SECURITY_LAYER_TLS;
|
||||
}
|
||||
else if (g_strcasecmp(value, "negotiate") == 0)
|
||||
{
|
||||
client_info->security_layer = PROTOCOL_SSL | PROTOCOL_HYBRID | PROTOCOL_HYBRID_EX;
|
||||
client_info->security_layer = SECURITY_LAYER_NEGOTIATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "security_layer=%s is not "
|
||||
"recognized, will use security_layer=negotiate",
|
||||
value);
|
||||
client_info->security_layer = PROTOCOL_SSL | PROTOCOL_HYBRID | PROTOCOL_HYBRID_EX;
|
||||
client_info->security_layer = SECURITY_LAYER_NEGOTIATE;
|
||||
}
|
||||
}
|
||||
else if (g_strcasecmp(item, "certificate") == 0)
|
||||
|
||||
@@ -2276,6 +2276,15 @@ xrdp_sec_incoming(struct xrdp_sec *self)
|
||||
else
|
||||
{
|
||||
/* init rdp security */
|
||||
if (g_fips_mode_enabled())
|
||||
{
|
||||
/* We can't generate rsakeys.ini in FIPS mode. Nor should we
|
||||
* try to use it */
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_sec_incoming: "
|
||||
"Classic RDP security unavailable in FIPS mode");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (xrdp_sec_init_rdp_security(self) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_sec_incoming: xrdp_sec_init_rdp_security failed");
|
||||
|
||||
Reference in New Issue
Block a user