Skip to content

Commit 463e500

Browse files
committed
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
1 parent 45ccd2d commit 463e500

File tree

8 files changed

+161
-145
lines changed

8 files changed

+161
-145
lines changed

common/xrdp_client_info.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ struct display_size_description
6767
unsigned int session_height;
6868
};
6969

70+
/* Values used for the security_layer */
71+
/* TODO: Make this an enum, and move it below xrdp_client_info */
72+
#define SECURITY_LAYER_NEGOTIATE 0
73+
#define SECURITY_LAYER_RDP 1
74+
#define SECURITY_LAYER_TLS 2
75+
7076
enum client_resize_mode
7177
{
7278
CRMODE_NONE,
@@ -174,7 +180,7 @@ struct xrdp_client_info
174180
int use_fast_path;
175181
int require_credentials; /* when true, credentials *must* be passed on cmd line */
176182

177-
int security_layer; /* 0 = rdp, 1 = tls , 2 = hybrid */
183+
int security_layer; /* SECURITY_LAYER_* */
178184
int multimon; /* 0 = deny , 1 = allow */
179185
struct display_size_description display_sizes;
180186

docs/man/xrdp-keygen.8.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ If \fBauto\fP is used as \fIoutfile\fP, the default file \fI@sysconfdir@/@syscon
3131
.B test
3232
Generate a test key pair and print information to standard output.
3333

34+
.SH NOTES
35+
On machines with FIPS enabled, this program will generate an empty file,
36+
and a warning. On these machines, xrdp cannot use Classic RDP encryption.
37+
3438
.SH FILES
3539
.TP
3640
.I @sysconfdir@/@sysconfsubdir@/rsakeys.ini

docs/man/xrdp.ini.5.in

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ See section \fBCHANNELS\fP below for more fine grained options.
6262
.TP
6363
\fBcrypt_level\fP=\fI[low|medium|high|fips]\fP
6464
.\" <http://blogs.msdn.com/b/openspecification/archive/2011/12/08/encryption-negotiation-in-rdp-connection.aspx>
65-
Regulate encryption level of Standard RDP Security.
65+
Regulate encryption level of Classic RDP Security.
6666
This parameter is effective only if \fBsecurity_layer\fP is set to \fBrdp\fP or \fBnegotiate\fP.
6767

68-
Encryption in Standard RDP Security is controlled by two settings: \fIEncryption Level\fP
68+
Encryption in Classic RDP Security is controlled by two settings: \fIEncryption Level\fP
6969
and \fIEncryption Method\fP. The only supported \fIEncryption Method\fP are \fB40BIT_ENCRYPTION\fP
7070
and \fB128BIT_ENCRYPTION\fP. \fB56BIT_ENCRYPTION\fP is not supported.
7171
This option controls the \fIEncryption Level\fP:
@@ -86,7 +86,8 @@ the server's maximum key strength (sever compatible).
8686
.TP
8787
.B fips
8888
All data sent between the client and server is protected using Federal Information
89-
Processing Standard 140-1 validated encryption methods.
89+
Processing Standard 140-1 validated encryption methods. Note that FIPS 140-1 is
90+
no longer considered secure.
9091
.I This level is required for Windows clients (mstsc.exe) if the client's group policy
9192
.I enforces FIPS-compliance mode.
9293
.RE
@@ -174,8 +175,9 @@ verification, and server authentication) are implemented by TLS.
174175

175176
.TP
176177
.B rdp
177-
Standard RDP Security, which is not safe from man-in-the-middle attack, is used. The encryption level
178-
of Standard RDP Security is controlled by \fBcrypt_level\fP.
178+
Classic RDP Security is used. The encryption level
179+
of Classic RDP Security is controlled by \fBcrypt_level\fP.
180+
Use this setting for testing only.
179181

180182
.TP
181183
.B negotiate

keygen/keygen.c

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,13 @@ save_all(const char *e_data, int e_len, const char *n_data, int n_len,
371371

372372
if (fd != -1)
373373
{
374+
if (e_data == NULL)
375+
{
376+
/* FIPS mode */
377+
g_file_close(fd);
378+
return 0;
379+
}
380+
374381
if (g_file_write(fd, "[keys]\n", 7) == -1)
375382
{
376383
g_writeln("problem writing to %s, maybe no rights", filename);
@@ -397,48 +404,49 @@ save_all(const char *e_data, int e_len, const char *n_data, int n_len,
397404
static int
398405
key_gen(const char *path_and_file_name)
399406
{
400-
char *e_data;
401-
char *n_data;
402-
char *d_data;
403-
char *sign_data;
404-
int e_len;
405-
int n_len;
406-
int d_len;
407-
int sign_len;
408-
int error;
409-
410-
e_data = (char *)g_exponent;
411-
n_data = (char *)g_malloc(256, 0);
412-
d_data = (char *)g_malloc(256, 0);
413-
sign_data = (char *)g_malloc(64, 0);
414-
e_len = 4;
415-
n_len = g_key_size_bits / 8;
416-
d_len = n_len;
417-
sign_len = 64;
418-
error = 0;
419-
g_writeln("%s", "");
420-
g_writeln("Generating %d bit rsa key...", g_key_size_bits);
421-
g_writeln("%s", "");
422-
423-
if (error == 0)
407+
char *e_data = NULL;
408+
char n_data[256] = {0};
409+
char d_data[256] = {0};
410+
char sign_data[64] = {0};
411+
int e_len = 4;
412+
int n_len = g_key_size_bits / 8;
413+
int d_len = n_len;
414+
int sign_len = sizeof(sign_data);
415+
int error = 0;
416+
417+
if (g_fips_mode_enabled())
424418
{
425-
error = ssl_gen_key_xrdp1(g_key_size_bits, e_data, e_len, n_data, n_len,
426-
d_data, d_len);
427-
if (error != 0)
428-
{
429-
g_writeln("error %d in key_gen, ssl_gen_key_xrdp1", error);
430-
}
419+
g_writeln("%s", "");
420+
g_writeln("This machine is running in FIPS mode - keys will not be generated");
421+
g_writeln("%s", "");
431422
}
432-
433-
if (error == 0)
423+
else
434424
{
435-
g_writeln("ssl_gen_key_xrdp1 ok");
425+
e_data = (char *)g_exponent;
426+
g_writeln("%s", "");
427+
g_writeln("Generating %d bit rsa key...", g_key_size_bits);
436428
g_writeln("%s", "");
437-
error = sign_key(e_data, e_len, n_data, n_len, sign_data, sign_len);
438429

439-
if (error != 0)
430+
if (error == 0)
440431
{
441-
g_writeln("error %d in key_gen, sign_key", error);
432+
error = ssl_gen_key_xrdp1(g_key_size_bits, e_data, e_len, n_data, n_len,
433+
d_data, d_len);
434+
if (error != 0)
435+
{
436+
g_writeln("error %d in key_gen, ssl_gen_key_xrdp1", error);
437+
}
438+
}
439+
440+
if (error == 0)
441+
{
442+
g_writeln("ssl_gen_key_xrdp1 ok");
443+
g_writeln("%s", "");
444+
error = sign_key(e_data, e_len, n_data, n_len, sign_data, sign_len);
445+
446+
if (error != 0)
447+
{
448+
g_writeln("error %d in key_gen, sign_key", error);
449+
}
442450
}
443451
}
444452

@@ -453,9 +461,6 @@ key_gen(const char *path_and_file_name)
453461
}
454462
}
455463

456-
g_free(n_data);
457-
g_free(d_data);
458-
g_free(sign_data);
459464
return error;
460465
}
461466

libxrdp/xrdp_iso.c

Lines changed: 79 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,7 @@ protocol_mask_to_str(int protocol, char *buff, int bufflen)
6060
BITMASK_STRING_END_OF_LIST
6161
};
6262

63-
int rlen = g_bitmask_to_str(protocol, bits, delim, buff, bufflen);
64-
65-
/* Append "RDP" */
66-
if (rlen == 0)
67-
{
68-
/* String is empty */
69-
rlen = g_snprintf(buff, bufflen, "RDP");
70-
}
71-
else if (rlen > 0 && rlen < bufflen)
72-
{
73-
rlen += g_snprintf(buff + rlen, bufflen - rlen, "%cRDP", delim);
74-
}
75-
76-
return rlen;
63+
return g_bitmask_to_str(protocol, bits, delim, buff, bufflen);
7764
}
7865

7966
/*****************************************************************************/
@@ -105,96 +92,98 @@ xrdp_iso_delete(struct xrdp_iso *self)
10592
static int
10693
xrdp_iso_negotiate_security(struct xrdp_iso *self)
10794
{
108-
char requested_str[64];
109-
const char *selected_str = "";
110-
const char *configured_str = "";
111-
11295
int rv = 0;
11396
struct xrdp_client_info *client_info = &(self->mcs_layer->sec_layer->rdp_layer->client_info);
97+
char protostr[64];
98+
int got_protocol = 0;
99+
int security_type_mask;
114100

115-
/* Can we do TLS/SSL? (basic check) */
116-
int ssl_capable = g_file_readable(client_info->certificate) &&
117-
g_file_readable(client_info->key_file);
118-
119-
/* Work out what's actually configured in xrdp.ini. The
120-
* selection happens later, but we can do some error checking here */
121-
switch (client_info->security_layer)
101+
/* Map the configuration from xrdp.ini to a mask of allowed
102+
* security types ([MS-RDPBCGR] 2.2.1.2.1)
103+
*
104+
* There's some oddness around PROTOCOL_RDP. This value is 0,
105+
* for compatibility reasons, and it's OK for the server to
106+
* suggest RDP as the fallback protocol if nothing else is
107+
* agreed on. Nowadays, classic RDP security should
108+
* not be used, if at all avoidable */
109+
110+
/* At present we only support SSL and RDP security */
111+
if (client_info->security_layer == SECURITY_LAYER_RDP)
112+
{
113+
security_type_mask = PROTOCOL_RDP;
114+
}
115+
else
122116
{
123-
case PROTOCOL_RDP:
124-
configured_str = "RDP";
125-
break;
117+
security_type_mask = PROTOCOL_SSL;
118+
}
126119

127-
case PROTOCOL_SSL:
128-
/* We *must* use TLS. Check we can offer it, and it's requested */
129-
if (ssl_capable)
130-
{
131-
configured_str = "SSL";
132-
if ((self->requestedProtocol & PROTOCOL_SSL) == 0)
133-
{
134-
LOG(LOG_LEVEL_ERROR, "Server requires TLS for security, "
135-
"but the client did not request TLS.");
136-
self->failureCode = SSL_REQUIRED_BY_SERVER;
137-
rv = 1; /* error */
138-
}
139-
}
140-
else
120+
/* Logically 'and' this value with the mask requested by the client, and
121+
* see what's left */
122+
protocol_mask_to_str(self->requestedProtocol, protostr, sizeof(protostr));
123+
LOG(LOG_LEVEL_INFO, "Client requested security types (RDP assumed) : %s",
124+
protostr);
125+
security_type_mask &= self->requestedProtocol;
126+
127+
/* Is there a match on SSL/TLS? */
128+
if ((security_type_mask & PROTOCOL_SSL) != 0)
129+
{
130+
/* Can we do TLS? (basic check) */
131+
if (g_file_readable(client_info->certificate) &&
132+
g_file_readable(client_info->key_file))
133+
{
134+
LOG(LOG_LEVEL_INFO, "Selected TLS security");
135+
self->selectedProtocol = PROTOCOL_SSL;
136+
got_protocol = 1;
137+
}
138+
else
139+
{
140+
LOG(LOG_LEVEL_WARNING, "Cannot accept TLS connections because "
141+
"certificate or private key file is not readable. "
142+
"certificate file: [%s], private key file: [%s]",
143+
client_info->certificate, client_info->key_file);
144+
145+
/* If we're configured to ONLY use TLS, this is a problem.
146+
* If not, we can fall back to RDP */
147+
if (client_info->security_layer == SECURITY_LAYER_TLS)
141148
{
142-
configured_str = "";
143-
LOG(LOG_LEVEL_ERROR, "Cannot accept TLS connections because "
144-
"certificate or private key file is not readable. "
145-
"certificate file: [%s], private key file: [%s]",
146-
client_info->certificate, client_info->key_file);
149+
LOG(LOG_LEVEL_ERROR,
150+
"Server requires TLS (security_layer=tls)");
147151
self->failureCode = SSL_CERT_NOT_ON_SERVER;
148-
rv = 1; /* error */
149-
}
150-
break;
151-
case PROTOCOL_HYBRID:
152-
case PROTOCOL_HYBRID_EX:
153-
default:
154-
/* We don't yet support CredSSP */
155-
if (ssl_capable)
156-
{
157-
configured_str = "SSL|RDP";
152+
rv = 1;
158153
}
159-
else
160-
{
161-
/*
162-
* Tell the user we can't offer TLS, but this isn't fatal */
163-
configured_str = "RDP";
164-
LOG(LOG_LEVEL_WARNING, "Cannot accept TLS connections because "
165-
"certificate or private key file is not readable. "
166-
"certificate file: [%s], private key file: [%s]",
167-
client_info->certificate, client_info->key_file);
168-
}
169-
break;
170-
}
171-
172-
/* Currently the choice comes down to RDP or SSL */
173-
if (rv != 0)
174-
{
175-
self->selectedProtocol = PROTOCOL_RDP;
176-
selected_str = "";
154+
}
177155
}
178-
else if (ssl_capable && (self->requestedProtocol &
179-
client_info->security_layer &
180-
PROTOCOL_SSL) != 0)
156+
else if (client_info->security_layer == SECURITY_LAYER_TLS)
181157
{
182-
self->selectedProtocol = PROTOCOL_SSL;
183-
selected_str = "SSL";
158+
/* We don't have a match on TLS, but we'll accept nothing less */
159+
LOG(LOG_LEVEL_ERROR, "Server requires TLS (security_layer=tls)");
160+
self->failureCode = SSL_REQUIRED_BY_SERVER;
161+
rv = 1;
184162
}
185-
else
163+
164+
/* If we haven't got a match so far, and we haven't got a fail,
165+
* try RDP */
166+
if (!got_protocol && !rv)
186167
{
187-
self->selectedProtocol = PROTOCOL_RDP;
188-
selected_str = "RDP";
168+
if (g_fips_mode_enabled())
169+
{
170+
/* This is a FIPS-mode machine, and we don't support classic RDP
171+
* encryption */
172+
LOG(LOG_LEVEL_ERROR,
173+
"Server in FIPS mode requires TLS for security");
174+
self->failureCode = SSL_REQUIRED_BY_SERVER;
175+
rv = 1; /* error */
176+
}
177+
else
178+
{
179+
self->selectedProtocol = PROTOCOL_RDP;
180+
LOG(LOG_LEVEL_INFO, "Selected classic RDP security");
181+
LOG(LOG_LEVEL_WARNING, "Classic RDP security is not secure -"
182+
" please configure TLS on the client and server");
183+
got_protocol = 1;
184+
}
189185
}
190186

191-
protocol_mask_to_str(self->requestedProtocol,
192-
requested_str, sizeof(requested_str));
193-
194-
LOG(LOG_LEVEL_INFO, "Security protocol: configured [%s], requested [%s],"
195-
" selected [%s]",
196-
configured_str, requested_str, selected_str);
197-
198187
return rv;
199188
}
200189

0 commit comments

Comments
 (0)