1
/* -*- c-basic-offset: 8 -*-
2
FreeRDP: A Remote Desktop Protocol client.
3
Transport Layer Security (TLS) encryption
5
Copyright (C) Marc-Andre Moreau <marcandre.moreau@gmail.com> 2010
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30
#include <openssl/ssl.h>
31
#include <openssl/err.h>
32
#include <openssl/rc4.h>
33
#include <openssl/md5.h>
34
#include <openssl/sha.h>
35
#include <openssl/bn.h>
36
#include <openssl/x509v3.h>
40
/* TODO: Implement SSL verify enforcement, disconnect when verify fails */
42
/* check the identity in a certificate against a hostname */
44
tls_verify_peer_identity(X509 *cert, const char *peer)
46
X509_NAME *subject_name = NULL;
47
X509_NAME_ENTRY *entry = NULL;
48
ASN1_STRING *asn1str = NULL;
49
//GENERAL_NAMES *subjectAltNames = NULL;
50
unsigned char *ustr = NULL;
55
/* Check cert for subjectAltName extensions */
56
/* things to check: ipv4/ipv6 address, hostname in normal form and in DC= form */
60
subjectAltNames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
65
/* Check against ip address of server */
67
/* Check commonName */
68
subject_name = X509_get_subject_name(cert);
71
printf("ssl_verify_peer_identity: failed to get subject name\n");
75
/* try to find a common name that matches the peer hostname */
76
/* TODO: cn migth also be in DC=www,DC=redhat,DC=com format? */
81
i = X509_NAME_get_index_by_NID(subject_name, NID_commonName, i);
84
entry = X509_NAME_get_entry(subject_name, i);
85
asn1str = X509_NAME_ENTRY_get_data(entry);
86
len = ASN1_STRING_to_UTF8(&ustr, asn1str);
88
if (strcmp(str, peer) == 0)
89
break; /* found a match */
94
printf("ssl_verify_peer_identity: certificate belongs to %s, but connection is to %s\n", str ? str : "unknown id", peer);
101
/* verify SSL/TLS connection integrity. 2 checks are carried out. First make sure that the
102
* certificate is assigned to the server we're connected to, and second make sure that the
103
* certificate is signed by a trusted certification authority
107
tls_verify(SSL *connection, const char *server)
109
/* TODO: Check for eku extension with server authentication purpose */
111
RD_BOOL verified = False;
112
X509 *server_cert = NULL;
115
server_cert = SSL_get_peer_certificate(connection);
118
printf("ssl_verify: failed to get the server SSL certificate\n");
122
ret = SSL_get_verify_result(connection);
123
if (ret != X509_V_OK)
125
printf("ssl_verify: error %d (see 'man 1 verify' for more information)\n", ret);
126
printf("certificate details:\n Subject:\n");
127
X509_NAME_print_ex_fp(stdout, X509_get_subject_name(server_cert), 4,
129
printf("\n Issued by:\n");
130
X509_NAME_print_ex_fp(stdout, X509_get_issuer_name(server_cert), 4,
137
verified = tls_verify_peer_identity(server_cert, server);
142
printf("The server could not be authenticated. Connection security may be compromised!\n");
146
X509_free(server_cert);
153
/* Handle an SSL error and returns True if the caller should abort (error was fatal) */
154
/* TODO: Use openssl error description functions */
156
tls_printf(char *func, SSL *connection, int val)
158
switch (SSL_get_error(connection, val))
160
case SSL_ERROR_ZERO_RETURN:
161
printf("%s: Server closed TLS connection\n", func);
163
case SSL_ERROR_WANT_READ:
164
printf("SSL_ERROR_WANT_READ\n");
165
//if (!ui_select(SSL_get_fd(connection)))
169
case SSL_ERROR_WANT_WRITE:
170
//tcp_can_send(SSL_get_fd(connection), 100);
171
printf("SSL_ERROR_WANT_WRITE\n");
173
case SSL_ERROR_SYSCALL:
174
printf("%s: I/O error\n", func);
177
printf("%s: Failure in SSL library (protocol error?)\n", func);
180
printf("%s: Unknown error\n", func);
185
/* Create TLS context */
191
SSL_load_error_strings();
194
ctx = SSL_CTX_new(TLSv1_client_method());
198
printf("SSL_CTX_new failed\n");
203
* This is necessary, because the Microsoft TLS implementation is not perfect.
204
* SSL_OP_ALL enables a couple of workarounds for buggy TLS implementations,
205
* but the most important workaround being SSL_OP_TLS_BLOCK_PADDING_BUG.
206
* As the size of the encrypted payload may give hints about its contents,
207
* block padding is normally used, but the Microsoft TLS implementation
208
* won't recognize it and will disconnect you after sending a TLS alert.
211
SSL_CTX_set_options(ctx, SSL_OP_ALL);
216
/* Initiate TLS handshake on socket */
218
tls_connect(SSL_CTX *ctx, int sockfd, char *server)
221
int connection_status;
227
printf("SSL_new failed\n");
231
if (SSL_set_fd(ssl, sockfd) < 1)
233
printf("SSL_set_fd failed\n");
239
/* SSL_WANT_READ errors are normal, just try again if it happens */
240
connection_status = SSL_connect(ssl);
242
while (SSL_get_error(ssl, connection_status) == SSL_ERROR_WANT_READ);
244
if (connection_status < 0)
246
if (tls_printf("SSL_connect", ssl, connection_status))
250
tls_verify(ssl, server);
252
printf("TLS connection established\n");
257
/* Free TLS resources */
259
tls_disconnect(SSL *ssl)
268
ret = SSL_shutdown(ssl);
271
if (tls_printf("ssl_disconnect", ssl, ret))
278
/* Send data over TLS connection */
279
int tls_write(SSL *ssl, char* b, int size)
282
int bytesWritten = 0;
284
write_status = SSL_write(ssl, b, size);
286
switch (SSL_get_error(ssl, write_status))
289
bytesWritten += write_status;
293
tls_printf("SSL_write", ssl, write_status);
297
if (bytesWritten < size)
298
return bytesWritten += tls_write(ssl, &b[bytesWritten], size - bytesWritten);
303
/* Receive data over TLS connection */
304
int tls_read(SSL *ssl, char* b, int size)
309
read_status = SSL_read(ssl, b, size);
311
switch (SSL_get_error(ssl, read_status))
314
bytesRead += read_status;
317
case SSL_ERROR_WANT_READ:
319
if (size - bytesRead < 128)
321
/* the buffer is almost full, allocate more memory */
326
bytesRead += tls_read(ssl, &b[bytesRead], size - bytesRead);
330
tls_printf("SSL_read", ssl, read_status);