Rename files in runtime/base, part 6
[hiphop-php.git] / hphp / runtime / base / ssl-socket.cpp
blob3d941c57a0f92ee116b3416a53a6895adb53f7b7
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/ssl-socket.h"
18 #include "hphp/runtime/base/complex_types.h"
19 #include "hphp/runtime/base/runtime-error.h"
20 #include "hphp/util/util.h"
21 #include <poll.h>
23 namespace HPHP {
24 ///////////////////////////////////////////////////////////////////////////////
26 StaticString SSLSocket::s_class_name("SSLSocket");
27 StaticString Certificate::s_class_name("OpenSSL X.509");
29 ///////////////////////////////////////////////////////////////////////////////
31 Mutex SSLSocket::s_mutex;
32 int SSLSocket::s_ex_data_index = -1;
33 int SSLSocket::GetSSLExDataIndex() {
34 if (s_ex_data_index >= 0) {
35 return s_ex_data_index;
37 Lock lock(s_mutex);
38 if (s_ex_data_index < 0) {
39 s_ex_data_index = SSL_get_ex_new_index(0, (void*)"PHP stream index",
40 nullptr, nullptr, nullptr);
41 assert(s_ex_data_index >= 0);
43 return s_ex_data_index;
46 const StaticString
47 s_allow_self_signed("allow_self_signed"),
48 s_verify_depth("verify_depth");
50 static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
51 int ret = preverify_ok;
53 /* determine the status for the current cert */
54 X509_STORE_CTX_get_current_cert(ctx);
55 int err = X509_STORE_CTX_get_error(ctx);
56 int depth = X509_STORE_CTX_get_error_depth(ctx);
58 /* conjure the stream & context to use */
59 SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data
60 (ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
61 SSLSocket *stream =
62 (SSLSocket*)SSL_get_ex_data(ssl, SSLSocket::GetSSLExDataIndex());
64 /* if allow_self_signed is set, make sure that verification succeeds */
65 if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT &&
66 stream->getContext()[s_allow_self_signed].toBoolean()) {
67 ret = 1;
70 /* check the depth */
71 Variant vdepth = stream->getContext()[s_verify_depth];
72 if (vdepth.toBoolean() && depth > vdepth.toInt64()) {
73 ret = 0;
74 X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
77 return ret;
80 const StaticString s_passphrase("passphrase");
82 static int passwd_callback(char *buf, int num, int verify, void *data) {
83 /* TODO: could expand this to make a callback into PHP user-space */
84 SSLSocket *stream = (SSLSocket *)data;
85 String passphrase = stream->getContext()[s_passphrase].toString();
86 if (!passphrase.empty() && passphrase.size() < num - 1) {
87 memcpy(buf, passphrase.data(), passphrase.size() + 1);
88 return passphrase.size();
90 return 0;
93 const StaticString
94 s_verify_peer("verify_peer"),
95 s_cafile("cafile"),
96 s_capath("capath"),
97 s_ciphers("ciphers"),
98 s_local_cert("local_cert");
100 SSL *SSLSocket::createSSL(SSL_CTX *ctx) {
101 ERR_clear_error();
103 /* look at options in the stream and set appropriate verification flags */
104 if (m_context[s_verify_peer].toBoolean()) {
105 /* turn on verification callback */
106 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
108 /* CA stuff */
109 String cafile = m_context[s_cafile].toString();
110 String capath = m_context[s_capath].toString();
112 if (!cafile.empty() || !capath.empty()) {
113 if (!SSL_CTX_load_verify_locations(ctx, cafile.data(), capath.data())) {
114 raise_warning("Unable to set verify locations `%s' `%s'",
115 cafile.data(), capath.data());
116 return nullptr;
120 int64_t depth = m_context[s_verify_depth].toInt64();
121 if (depth) {
122 SSL_CTX_set_verify_depth(ctx, depth);
124 } else {
125 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr);
128 /* callback for the passphrase (for localcert) */
129 if (!m_context[s_passphrase].toString().empty()) {
130 SSL_CTX_set_default_passwd_cb_userdata(ctx, this);
131 SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
134 String cipherlist = m_context[s_ciphers].toString();
135 if (cipherlist.empty()) {
136 cipherlist = "DEFAULT";
138 SSL_CTX_set_cipher_list(ctx, cipherlist.data());
140 String certfile = m_context[s_local_cert].toString();
141 if (!certfile.empty()) {
142 String resolved_path_buff = File::TranslatePath(certfile);
143 if (!resolved_path_buff.empty()) {
144 /* a certificate to use for authentication */
145 if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff.data())
146 != 1) {
147 raise_warning("Unable to set local cert chain file `%s'; Check "
148 "that your cafile/capath settings include details of "
149 "your certificate and its issuer", certfile.data());
150 return nullptr;
153 if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff.data(),
154 SSL_FILETYPE_PEM) != 1) {
155 raise_warning("Unable to set private key file `%s'",
156 resolved_path_buff.data());
157 return nullptr;
160 SSL *tmpssl = SSL_new(ctx);
161 X509 *cert = SSL_get_certificate(tmpssl);
162 if (cert) {
163 EVP_PKEY *key = X509_get_pubkey(cert);
164 EVP_PKEY_copy_parameters(key, SSL_get_privatekey(tmpssl));
165 EVP_PKEY_free(key);
167 SSL_free(tmpssl);
169 if (!SSL_CTX_check_private_key(ctx)) {
170 raise_warning("Private key does not match certificate!");
175 SSL *ssl = SSL_new(ctx);
176 if (ssl) {
177 SSL_set_ex_data(ssl, GetSSLExDataIndex(), this); /* map SSL => stream */
179 return ssl;
182 ///////////////////////////////////////////////////////////////////////////////
183 // constructors and destructor
185 SSLSocket::SSLSocket()
186 : m_handle(nullptr), m_ssl_active(false), m_method((CryptoMethod)-1),
187 m_client(false), m_connect_timeout(0), m_enable_on_connect(false),
188 m_state_set(false), m_is_blocked(true) {
191 SSLSocket::SSLSocket(int sockfd, int type, const char *address /* = NULL */,
192 int port /* = 0 */)
193 : Socket(sockfd, type, address, port),
194 m_handle(nullptr), m_ssl_active(false), m_method((CryptoMethod)-1),
195 m_client(false), m_connect_timeout(0), m_enable_on_connect(false),
196 m_state_set(false), m_is_blocked(true) {
199 SSLSocket::~SSLSocket() {
200 m_context.reset(); // for sweeping
201 closeImpl();
204 bool SSLSocket::onConnect() {
205 return setupCrypto() && enableCrypto();
208 bool SSLSocket::onAccept() {
209 if (m_fd >= 0 && m_enable_on_connect) {
210 switch (m_method) {
211 case CryptoMethod::ClientSSLv23:
212 m_method = CryptoMethod::ServerSSLv23;
213 break;
214 case CryptoMethod::ClientSSLv2:
215 m_method = CryptoMethod::ServerSSLv2;
216 break;
217 case CryptoMethod::ClientSSLv3:
218 m_method = CryptoMethod::ServerSSLv3;
219 break;
220 case CryptoMethod::ClientTLS:
221 m_method = CryptoMethod::ServerTLS;
222 break;
223 default:
224 assert(false);
227 if (setupCrypto() && enableCrypto()) {
228 return true;
231 raise_warning("Failed to enable crypto");
232 close();
234 return false;
237 ///////////////////////////////////////////////////////////////////////////////
239 bool SSLSocket::handleError(int64_t nr_bytes, bool is_init) {
240 char esbuf[512];
241 string ebuf;
242 unsigned long ecode;
244 bool retry = true;
245 int err = SSL_get_error(m_handle, nr_bytes);
246 switch (err) {
247 case SSL_ERROR_ZERO_RETURN:
248 /* SSL terminated (but socket may still be active) */
249 retry = false;
250 break;
251 case SSL_ERROR_WANT_READ:
252 case SSL_ERROR_WANT_WRITE:
253 /* re-negotiation, or perhaps the SSL layer needs more
254 * packets: retry in next iteration */
255 errno = EAGAIN;
256 retry = (is_init || m_is_blocked);
257 break;
258 case SSL_ERROR_SYSCALL:
259 if (ERR_peek_error() == 0) {
260 if (nr_bytes == 0) {
261 if (ERR_get_error()) {
262 raise_warning("SSL: fatal protocol error");
264 SSL_set_shutdown(m_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
265 m_eof = true;
266 retry = false;
267 } else {
268 string estr = Util::safe_strerror(errno);
269 raise_warning("SSL: %s", estr.c_str());
270 retry = false;
272 break;
274 /* fall through */
275 default:
276 /* some other error */
277 ecode = ERR_get_error();
278 switch (ERR_GET_REASON(ecode)) {
279 case SSL_R_NO_SHARED_CIPHER:
280 raise_warning("SSL_R_NO_SHARED_CIPHER: no suitable shared cipher "
281 "could be used. This could be because the server is "
282 "missing an SSL certificate (local_cert context "
283 "option)");
284 retry = false;
285 break;
287 default:
288 do {
289 // NULL is automatically added
290 ERR_error_string_n(ecode, esbuf, sizeof(esbuf));
291 if (!ebuf.empty()) {
292 ebuf += '\n';
294 ebuf += esbuf;
295 } while ((ecode = ERR_get_error()) != 0);
297 raise_warning("SSL operation failed with code %d. %s%s",
298 err, !ebuf.empty() ? "OpenSSL Error messages:\n" : "",
299 !ebuf.empty() ? ebuf.c_str() : "");
302 retry = false;
303 errno = 0;
306 return retry;
309 ///////////////////////////////////////////////////////////////////////////////
311 SSLSocket *SSLSocket::Create(const char *&name, int port, double timeout) {
312 CryptoMethod method;
313 if (strncmp(name, "ssl://", 6) == 0) {
314 name += 6;
315 method = CryptoMethod::ClientSSLv23;
316 } else if (strncmp(name, "sslv2://", 8) == 0) {
317 name += 8;
318 method = CryptoMethod::ClientSSLv2;
319 } else if (strncmp(name, "sslv3://", 8) == 0) {
320 name += 8;
321 method = CryptoMethod::ClientSSLv3;
322 } else if (strncmp(name, "tls://", 6) == 0) {
323 name += 6;
324 method = CryptoMethod::ClientTLS;
325 } else {
326 return nullptr;
329 int domain = AF_INET;
330 int type = SOCK_STREAM;
331 SSLSocket *sock = new SSLSocket(socket(domain, type, 0), domain, name, port);
332 sock->m_method = method;
333 sock->m_connect_timeout = timeout;
334 sock->m_enable_on_connect = true;
336 return sock;
339 bool SSLSocket::close() {
340 return closeImpl();
343 bool SSLSocket::closeImpl() {
344 if (m_ssl_active) {
345 SSL_shutdown(m_handle);
346 m_ssl_active = false;
348 if (m_handle) {
349 SSL_free(m_handle);
350 m_handle = nullptr;
352 return Socket::closeImpl();
355 int64_t SSLSocket::readImpl(char *buffer, int64_t length) {
356 int64_t nr_bytes = 0;
357 if (m_ssl_active) {
358 bool retry = true;
359 do {
360 if (m_is_blocked) {
361 Socket::waitForData();
362 if (m_timedOut) {
363 break;
365 // could get here and we only have parts of an SSL packet
367 nr_bytes = SSL_read(m_handle, buffer, length);
368 if (nr_bytes > 0) break; /* we got the data */
369 retry = handleError(nr_bytes, false);
370 m_eof = (!retry && errno != EAGAIN && !SSL_pending(m_handle));
371 } while (retry);
372 } else {
373 nr_bytes = Socket::readImpl(buffer, length);
375 return nr_bytes < 0 ? 0 : nr_bytes;
378 int64_t SSLSocket::writeImpl(const char *buffer, int64_t length) {
379 int didwrite;
380 if (m_ssl_active) {
381 bool retry = true;
382 do {
383 didwrite = SSL_write(m_handle, buffer, length);
384 if (didwrite > 0) break;
385 retry = handleError(didwrite, false);
386 } while (retry);
387 } else {
388 didwrite = Socket::writeImpl(buffer, length);
390 return didwrite < 0 ? 0 : didwrite;
393 bool SSLSocket::setupCrypto(SSLSocket *session /* = NULL */) {
394 if (m_handle) {
395 raise_warning("SSL/TLS already set-up for this stream");
396 return false;
399 /* need to do slightly different things, based on client/server method,
400 * so lets remember which method was selected */
401 #if OPENSSL_VERSION_NUMBER < 0x00909000L
402 SSL_METHOD *smethod;
403 #else
404 const SSL_METHOD *smethod;
405 #endif
406 switch (m_method) {
407 case CryptoMethod::ClientSSLv23:
408 m_client = true;
409 smethod = SSLv23_client_method();
410 break;
411 case CryptoMethod::ClientSSLv3:
412 m_client = true;
413 smethod = SSLv3_client_method();
414 break;
415 case CryptoMethod::ClientTLS:
416 m_client = true;
417 smethod = TLSv1_client_method();
418 break;
419 case CryptoMethod::ServerSSLv23:
420 m_client = false;
421 smethod = SSLv23_server_method();
422 break;
423 case CryptoMethod::ServerSSLv3:
424 m_client = false;
425 smethod = SSLv3_server_method();
426 break;
428 /* SSLv2 protocol might be disabled in the OpenSSL library */
429 #ifndef OPENSSL_NO_SSL2
430 case CryptoMethod::ClientSSLv2:
431 m_client = true;
432 smethod = SSLv2_client_method();
433 break;
434 case CryptoMethod::ServerSSLv2:
435 m_client = false;
436 smethod = SSLv2_server_method();
437 break;
438 #else
439 case CryptoMethod::ClientSSLv2:
440 case CryptoMethod::ServerSSLv2:
441 raise_warning("OpenSSL library does not support SSL2 protocol");
442 return false;
443 break;
444 #endif
446 case CryptoMethod::ServerTLS:
447 m_client = false;
448 smethod = TLSv1_server_method();
449 break;
450 default:
451 return false;
454 SSL_CTX *ctx = SSL_CTX_new(smethod);
455 if (ctx == nullptr) {
456 raise_warning("failed to create an SSL context");
457 return false;
460 SSL_CTX_set_options(ctx, SSL_OP_ALL);
461 m_handle = createSSL(ctx);
462 if (m_handle == nullptr) {
463 raise_warning("failed to create an SSL handle");
464 SSL_CTX_free(ctx);
465 return false;
468 if (!SSL_set_fd(m_handle, m_fd)) {
469 handleError(0, true);
471 if (session) {
472 SSL_copy_session_id(m_handle, session->m_handle);
474 return true;
477 const StaticString s_CN_match("CN_match");
479 bool SSLSocket::applyVerificationPolicy(X509 *peer) {
480 /* verification is turned off */
481 if (!m_context[s_verify_peer].toBoolean()) {
482 return true;
485 if (peer == nullptr) {
486 raise_warning("Could not get peer certificate");
487 return false;
490 int err = SSL_get_verify_result(m_handle);
491 switch (err) {
492 case X509_V_OK:
493 /* fine */
494 break;
495 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
496 if (m_context[s_allow_self_signed].toBoolean()) {
497 /* allowed */
498 break;
500 /* not allowed, so fall through */
501 default:
502 raise_warning("Could not verify peer: code:%d %s", err,
503 X509_verify_cert_error_string(err));
504 return false;
507 /* if the cert passed the usual checks, apply our own local policies now */
509 /* Does the common name match ? (used primarily for https://) */
510 String cnmatch = m_context[s_CN_match].toString();
511 if (!cnmatch.empty()) {
512 X509_NAME *name = X509_get_subject_name(peer);
513 char buf[1024];
514 int name_len = X509_NAME_get_text_by_NID(name, NID_commonName, buf,
515 sizeof(buf));
517 if (name_len < 0) {
518 raise_warning("Unable to locate peer certificate CN");
519 return false;
520 } else if (name_len != (int)strlen(buf)) {
521 raise_warning("Peer certificate CN=`%.*s' is malformed", name_len, buf);
522 return false;
525 bool match = (strcmp(cnmatch.c_str(), buf) == 0);
526 if (!match && strlen(buf) > 3 && buf[0] == '*' && buf[1] == '.') {
527 /* Try wildcard */
528 if (strchr(buf+2, '.')) {
529 const char* cnmatch_str = cnmatch.c_str();
530 const char *tmp = strstr(cnmatch_str, buf+1);
531 match = tmp && strcmp(tmp, buf+2) && tmp == strchr(cnmatch_str, '.');
535 if (!match) {
536 /* didn't match */
537 raise_warning("Peer certificate CN=`%.*s' did not match expected CN=`%s'",
538 name_len, buf, cnmatch.c_str());
539 return false;
543 return true;
546 const StaticString
547 s_capture_peer_cert("capture_peer_cert"),
548 s_peer_certificate("peer_certificate"),
549 s_capture_peer_cert_chain("capture_peer_cert_chain"),
550 s_peer_certificate_chain("peer_certificate_chain");
552 bool SSLSocket::enableCrypto(bool activate /* = true */) {
553 if (activate && !m_ssl_active) {
554 double timeout = m_connect_timeout;
555 bool blocked = m_is_blocked;
556 if (!m_state_set) {
557 if (m_client) {
558 SSL_set_connect_state(m_handle);
559 } else {
560 SSL_set_accept_state(m_handle);
562 m_state_set = true;
565 if (m_client && setBlocking(false)) {
566 m_is_blocked = false;
569 int n;
570 bool retry = true;
571 do {
572 if (m_client) {
573 struct timeval tvs, tve;
574 struct timezone tz;
576 gettimeofday(&tvs, &tz);
577 n = SSL_connect(m_handle);
578 gettimeofday(&tve, &tz);
580 timeout -= (tve.tv_sec + (double) tve.tv_usec / 1000000) -
581 (tvs.tv_sec + (double) tvs.tv_usec / 1000000);
582 if (timeout < 0) {
583 raise_warning("SSL: connection timeout");
584 return -1;
586 } else {
587 n = SSL_accept(m_handle);
590 if (n <= 0) {
591 retry = handleError(n, true);
592 } else {
593 break;
595 } while (retry);
597 if (m_client && m_is_blocked != blocked && setBlocking(blocked)) {
598 m_is_blocked = blocked;
601 if (n == 1) {
602 X509 *peer_cert = SSL_get_peer_certificate(m_handle);
603 if (!applyVerificationPolicy(peer_cert)) {
604 SSL_shutdown(m_handle);
605 } else {
606 m_ssl_active = true;
608 /* allow the script to capture the peer cert
609 * and/or the certificate chain */
610 if (m_context[s_capture_peer_cert].toBoolean()) {
611 Resource cert(new Certificate(peer_cert));
612 m_context.set(s_peer_certificate, cert);
613 peer_cert = nullptr;
616 if (m_context[s_capture_peer_cert_chain].toBoolean()) {
617 Array arr;
618 STACK_OF(X509) *chain = SSL_get_peer_cert_chain(m_handle);
619 if (chain) {
620 for (int i = 0; i < sk_X509_num(chain); i++) {
621 X509 *mycert = X509_dup(sk_X509_value(chain, i));
622 arr.append(Resource(new Certificate(mycert)));
625 m_context.set(s_peer_certificate_chain, arr);
629 if (peer_cert) {
630 X509_free(peer_cert);
632 } else {
633 n = errno == EAGAIN ? 0 : -1;
636 return n >= 0;
638 } else if (!activate && m_ssl_active) {
639 /* deactivate - common for server/client */
640 SSL_shutdown(m_handle);
641 m_ssl_active = false;
643 return true;
646 bool SSLSocket::checkLiveness() {
647 if (m_fd == -1) {
648 return false;
651 pollfd p;
652 p.fd = m_fd;
653 p.events = POLLIN | POLLERR | POLLHUP | POLLPRI;
654 p.revents = 0;
655 if (poll(&p, 1, 0) > 0 && p.revents > 0) {
656 char buf;
657 if (m_ssl_active) {
658 while (true) {
659 int n = SSL_peek(m_handle, &buf, sizeof(buf));
660 if (n <= 0) {
661 int err = SSL_get_error(m_handle, n);
662 if (err == SSL_ERROR_SYSCALL) {
663 return errno == EAGAIN;
666 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
667 /* re-negotiate */
668 continue;
671 /* any other problem is a fatal error */
672 return false;
674 /* either peek succeeded or there was an error; we
675 * have set the alive flag appropriately */
676 break;
678 } else if (0 == recv(m_fd, &buf, sizeof(buf), MSG_PEEK) &&
679 errno != EAGAIN) {
680 return false;
683 return true;
686 ///////////////////////////////////////////////////////////////////////////////
687 // Certificate
689 BIO *Certificate::ReadData(CVarRef var, bool *file /* = NULL */) {
690 if (var.isString() || var.isObject()) {
691 String svar = var.toString();
692 if (svar.substr(0, 7) == "file://") {
693 if (file) *file = true;
694 BIO *ret = BIO_new_file((char*)svar.substr(7).data(), "r");
695 if (ret == nullptr) {
696 raise_warning("error opening the file, %s", svar.data());
698 return ret;
701 if (file) *file = false;
702 return BIO_new_mem_buf((char*)svar.data(), svar.size());
704 return nullptr;
708 Resource Certificate::Get(CVarRef var) {
709 if (var.isResource()) {
710 return var.toResource();
712 if (var.isString() || var.isObject()) {
713 bool file;
714 BIO *in = ReadData(var, &file);
715 if (in == nullptr) return Resource();
717 X509 *cert;
719 if (file) {
720 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
721 } else {
722 cert = (X509 *)PEM_ASN1_read_bio
723 ((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
726 cert = PEM_read_bio_X509(in, nullptr, nullptr, nullptr);
727 BIO_free(in);
728 if (cert) {
729 return Resource(new Certificate(cert));
732 return Resource();
735 ///////////////////////////////////////////////////////////////////////////////