1 // ssl.cpp: HyperText Transport Protocol handler for Cygnal, for Gnash.
3 // Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "gnashconfig.h"
24 #include <boost/thread/mutex.hpp>
25 #include <boost/shared_ptr.hpp>
26 #include <boost/shared_array.hpp>
27 #include <boost/scoped_array.hpp>
28 #include <boost/cstdint.hpp>
29 #include <boost/array.hpp>
30 #include <sys/types.h>
38 #include <sys/types.h>
42 #include "GnashSystemIOHeaders.h" // read()
43 #include "sslclient.h"
51 #include "diskstream.h"
54 #ifdef HAVE_OPENSSL_SSL_H
55 #include <openssl/ssl.h>
56 #include <openssl/err.h>
57 #include <openssl/rand.h>
60 #if defined(_WIN32) || defined(WIN32)
61 # define __PRETTY_FUNCTION__ __FUNCDNAME__
62 # include <winsock2.h>
66 # include <sys/param.h>
69 using namespace gnash
;
72 static boost::mutex stl_mutex
;
73 // The debug log used by all the gnash libraries.
75 static LogFile
& dbglogfile
= LogFile::getDefaultInstance();
76 RcInitFile
& rc
= RcInitFile::getDefaultInstance();
78 // This is static in this file, instead of being a private variable in
79 // the SSLCLient class, is so it's accessible from the C function callback,
80 // which can't access the private data of the class.
81 // static SSLClient::passwd_t password(SSL_PASSWD_SIZE);
82 static string password
;
87 const size_t SSL_PASSWD_SIZE
= 1024;
88 static const char *SSL_HOST
= "localhost";
89 // static const char *SSL_CA_LIST = "rootcert.pem";
90 // static const char *SSL_CLIENT_CERTFILE = "client.pem";
91 // static const char *SSL_CLIENT_ROOTPATH = "/etc/pki/tls";
93 // const char *RANDOM = "random.pem";
95 SSLClient::SSLClient()
96 : _hostname("localhost"),
97 _calist(rc
.getRootCert()),
98 _keyfile(rc
.getCertFile()),
99 _rootpath(rc
.getCertDir()),
100 _need_server_auth(true)
102 GNASH_REPORT_FUNCTION
;
104 // setPort(SSL_PORT);
105 setPassword("foobar");
107 // Initialize SSL library
109 RAND_load_file("/dev/urandom", 1024);
111 // Load the error strings so the SSL_error_*() functions work
112 SSL_load_error_strings();
115 SSLClient::~SSLClient()
117 // GNASH_REPORT_FUNCTION;
120 // Read bytes from the already opened SSL connection
122 SSLClient::sslRead(cygnal::Buffer
&buf
)
124 GNASH_REPORT_FUNCTION
;
126 return sslRead(buf
.reference(), buf
.allocated());
130 SSLClient::sslRead(boost::uint8_t *buf
, size_t size
)
132 GNASH_REPORT_FUNCTION
;
135 int ret
= SSL_read(_ssl
.get(), buf
, size
);
137 log_error("Error was: \"%s\"!", ERR_reason_error_string(ERR_get_error()));
143 // Write bytes to the already opened SSL connection
145 SSLClient::sslWrite(cygnal::Buffer
&buf
)
147 GNASH_REPORT_FUNCTION
;
149 return sslWrite(buf
.reference(), buf
.allocated());
153 SSLClient::sslWrite(const boost::uint8_t *buf
, size_t length
)
155 GNASH_REPORT_FUNCTION
;
158 int ret
= SSL_write(_ssl
.get(), buf
, length
);
160 log_error("Error was: \"%s\"!", ERR_reason_error_string(ERR_get_error()));
165 // Setup the Context for this connection
167 SSLClient::sslSetupCTX()
169 return sslSetupCTX(_keyfile
, _calist
);
173 SSLClient::sslSetupCTX(std::string
&keyspec
, std::string
&caspec
)
175 GNASH_REPORT_FUNCTION
;
182 if (keyspec
.find('/', 0) != string::npos
) {
191 if (caspec
.find('/', 0) != string::npos
) {
203 // create the context
204 _ctx
.reset(SSL_CTX_new( SSLv23_method()));
207 if (!(SSL_CTX_load_verify_locations(_ctx
.get(), cafile
.c_str(),
208 _rootpath
.c_str()))) {
209 log_error("Can't read CA list from \"%s\"!", cafile
);
210 log_error("Error was: \"%s\"!", ERR_reason_error_string(ERR_get_error()));
213 log_debug("Read CA list from \"%s\"", cafile
);
216 // Load our keys and certificates
218 if ((ret
= SSL_CTX_use_certificate_chain_file(_ctx
.get(), keyfile
.c_str())) != 1) {
219 log_error("Can't read certificate file \"%s\"!", keyfile
);
222 log_debug("Read certificate file \"%s\".", keyfile
);
225 // Set the password as a callback, otherwise we get prompted for it
226 SSL_CTX_set_default_passwd_cb(_ctx
.get(), password_cb
);
228 // Add the first private key in the keyfile to the context.
230 if((ret
= SSL_CTX_use_PrivateKey_file(_ctx
.get(), keyfile
.c_str(),
231 SSL_FILETYPE_PEM
)) != 1) {
232 log_error("Can't read CERT file \"%s\"!", keyfile
);
233 log_error("Error was: \"%s\"!", ERR_reason_error_string(ERR_get_error()));
236 log_debug("Read key file \"%s\".", keyfile
);
239 SSL_CTX_set_verify(_ctx
.get(), SSL_VERIFY_PEER
, verify_callback
);
241 #if (OPENSSL_VERSION_NUMBER < 0x00905100L)
242 SSL_CTX_set_verify_depth(_ctx
.get(), 4);
248 // Shutdown the Context for this connection
250 SSLClient::sslShutdown()
252 // GNASH_REPORT_FUNCTION;
254 // SSL_clear(_ssl.get());
255 SSL_free(_ssl
.get());
256 SSL_CTX_free(_ctx
.get());
261 // sslConnect() is how the client connects to the server
263 SSLClient::sslConnect(int fd
)
265 return sslConnect(fd
, _hostname
, 0);
269 SSLClient::sslConnect(int fd
, std::string
&hostname
, short port
)
271 GNASH_REPORT_FUNCTION
;
275 if (!sslSetupCTX()) {
280 _ssl
.reset(SSL_new(_ctx
.get()));
282 // // Make a tcp/ip connect to the server
283 // if (createClient(hostname, getPort()) == false) {
284 // log_error("Can't connect to server %s", hostname);
288 // Handshake the server
291 _bio
.reset(BIO_new_socket(fd
, BIO_NOCLOSE
));
293 // BIO_set_conn_hostname(_bio.get(), _hostname.c_str());
294 _bio
.reset(BIO_new_connect(const_cast<char *>(_hostname
.c_str())));
296 BIO_set_conn_int_port(_bio
.get(), &port
);
297 log_debug("PORT is: %d", BIO_get_conn_port(_bio
.get()));
299 if (BIO_do_connect(_bio
.get()) <= 0) {
300 log_error("Error connecting to remote machine: %s",
301 ERR_reason_error_string(ERR_get_error()));
305 SSL_set_bio(_ssl
.get(), _bio
.get(), _bio
.get());
306 SSL_set_connect_state(_ssl
.get());
308 if ((ret
= SSL_connect(_ssl
.get())) < 0) {
309 log_error("Can't connect to SSL server %s", hostname
);
310 log_error("Error was: \"%s\"!", ERR_reason_error_string(ERR_get_error()));
313 log_debug("Connected to SSL server %s", hostname
);
318 if (_need_server_auth
) {
327 SSLClient::checkCert()
329 GNASH_REPORT_FUNCTION
;
330 return checkCert(_hostname
);
334 SSLClient::checkCert(std::string
&hostname
)
336 GNASH_REPORT_FUNCTION
;
338 if (!_ssl
|| (hostname
.empty())) {
345 if (SSL_get_verify_result(_ssl
.get()) != X509_V_OK
) {
346 log_error("Certificate doesn't verify");
349 log_debug("Certificate verified.");
352 // Check the cert chain. The chain length
353 // is automatically checked by OpenSSL when
354 // we set the verify depth in the ctx
356 // Check the common name
357 if ((peer
= SSL_get_peer_certificate(_ssl
.get())) == 0) {
358 log_debug("Couldn't get Peer certificate!");
361 log_debug("Got Peer certificate.");
365 X509_NAME_get_text_by_NID (X509_get_subject_name(peer
),
366 NID_commonName
, peer_CN
, 256);
368 if (strcasecmp(peer_CN
, hostname
.c_str())) {
369 log_error("Common name doesn't match host name");
377 // GNASH_REPORT_FUNCTION;
379 boost::mutex::scoped_lock
lock(stl_mutex
);
381 log_debug (_("==== The SSL header breaks down as follows: ===="));
384 // The password is a global variable so it can be set from a C function
387 SSLClient::setPassword(std::string pw
) {
392 SSLClient::getPassword() {
398 // This is the callback required when setting up the password.
400 password_cb(char *buf
, int size
, int /* rwflag */, void * /* userdata */)
402 GNASH_REPORT_FUNCTION
;
404 log_debug("Callback executed to set the SSL password, size is: %d",
407 if(size
<= static_cast<int>(password
.size()+1)) {
408 log_error("The buffer for the password needs to be %d bytes larger",
409 password
.size() - size
);
413 // copy the password, we'll need it later
414 // std::copy(buf, buf + size, password.data());
415 std::copy(password
.begin(), password
.end(), buf
);
418 return(password
.size());
423 verify_callback(int ok
, X509_STORE_CTX
*store
)
425 GNASH_REPORT_FUNCTION
;
430 X509
*cert
= X509_STORE_CTX_get_current_cert(store
);
431 int depth
= X509_STORE_CTX_get_error_depth(store
);
432 int err
= X509_STORE_CTX_get_error(store
);
434 log_error("-Error with certificate at depth: %i\n", depth
);
435 X509_NAME_oneline(X509_get_issuer_name(cert
), data
, 256);
436 log_error(" issuer = %s\n", data
);
437 X509_NAME_oneline(X509_get_subject_name(cert
), data
, 256);
438 log_error(" subject = %s\n", data
);
439 log_error("err %i:%s\n", err
, X509_verify_cert_error_string(err
));
447 } // end of gnash namespace
452 // indent-tabs-mode: t