Beispiel #1
0
// XXX Clean up this function, we MUST handle all errors possible
int krypt_set_rsa(krypt_t *kconn)
{
	if (kconn->security_level == KRYPT_RSA) {
		jlog(L_NOTICE, "the security level is already set to RSA");
		return 0;
	}

	SSL_set_cipher_list(kconn->ssl, "AES256-SHA");

	// Load the trusted certificate store into our SSL_CTX
	SSL_CTX_set_cert_store(kconn->ctx, kconn->passport->trusted_authority);

	// Force the peer cert verifying + fail if no cert is sent by the peer
	SSL_set_verify(kconn->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);

	// Set the certificate and key
	SSL_use_certificate(kconn->ssl, kconn->passport->certificate);
	SSL_use_PrivateKey(kconn->ssl, kconn->passport->keyring);

	if (kconn->conn_type == KRYPT_SERVER) {
		jlog(L_NOTICE, "set verify");

			// Change the session id to avoid resuming ADH session
		SSL_set_session_id_context(kconn->ssl, (void*)&s_server_auth_session_id_context,
							sizeof(s_server_auth_session_id_context));
	}

	kconn->security_level = KRYPT_RSA;

	return 0;
}
Beispiel #2
0
static int openssl_ssl_session(lua_State*L)
{
  SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
  SSL_SESSION*ss;

  if (lua_isnoneornil(L, 2))
  {
    ss = SSL_get1_session(s);
    PUSH_OBJECT(ss, "openssl.ssl_session");
  }
  else
  {
    if (lua_isstring(L, 3))
    {
      size_t sz;
      const char* sid_ctx = luaL_checklstring(L, 2, &sz);
      int ret = SSL_set_session_id_context(s, (unsigned char*)sid_ctx, sz);
      lua_pushboolean(L, ret);
    }
    else
    {
      ss = CHECK_OBJECT(2, SSL_SESSION, "openssl.ssl_session");
      if (lua_isnoneornil(L, 3))
      {
        int ret = SSL_set_session(s, ss);
        lua_pushboolean(L, ret);
      }
      else
      {
#ifdef SSL_add_session
        int add = auxiliar_checkboolean(L, 3);
        if (add)
          add = SSL_add_session(s, ss);
        else
          add = SSL_remove_session(s, ss);
        lua_pushboolean(L, add);
#endif
      }
    }
  }
  return 1;
}
Beispiel #3
0
Transition ConnectionHandle::SSLHandshake() {
  if (conn_SSL_context == nullptr) {
    conn_SSL_context = SSL_new(PelotonServer::ssl_context);
    if (conn_SSL_context == nullptr) {
      throw NetworkProcessException("ssl context for conn failed");
    }
    SSL_set_session_id_context(conn_SSL_context, nullptr, 0);
    if (SSL_set_fd(conn_SSL_context, sock_fd_) == 0) {
      LOG_ERROR("Failed to set SSL fd");
      return Transition::FINISH;
    }
  }

  // TODO(Yuchen): post-connection verification?
  // clear current thread's error queue before any OpenSSL call
  ERR_clear_error();
  int ssl_accept_ret = SSL_accept(conn_SSL_context);
  if (ssl_accept_ret > 0) return Transition::PROCEED;

  int err = SSL_get_error(conn_SSL_context, ssl_accept_ret);
  int ecode = ERR_get_error();
  char error_string[120];
  ERR_error_string(ecode, error_string);
  switch (err) {
    case SSL_ERROR_SSL: {
      if (ecode < 0) {
        LOG_ERROR("Could not accept SSL connection");
      } else {
        LOG_ERROR(
            "Could not accept SSL connection: EOF detected, "
            "ssl_error_ssl, %s",
            error_string);
      }
      return Transition::FINISH;
    }
    case SSL_ERROR_ZERO_RETURN: {
      LOG_ERROR(
          "Could not accept SSL connection: EOF detected, "
          "ssl_error_zero_return, %s",
          error_string);
      return Transition::FINISH;
    }
    case SSL_ERROR_SYSCALL: {
      if (ecode < 0) {
        LOG_ERROR("Could not accept SSL connection, %s", error_string);
      } else {
        LOG_ERROR(
            "Could not accept SSL connection: EOF detected, "
            "ssl_sys_call, %s",
            error_string);
      }
      return Transition::FINISH;
    }
    case SSL_ERROR_WANT_READ: {
      UpdateEventFlags(EV_READ | EV_PERSIST);
      return Transition::NEED_DATA;
    }
    case SSL_ERROR_WANT_WRITE: {
      UpdateEventFlags(EV_WRITE | EV_PERSIST);
      return Transition::NEED_DATA;
    }
    default: {
      LOG_ERROR("Unrecognized SSL error code: %d", err);
      return Transition::FINISH;
    }
  }
}
Beispiel #4
0
/*
 *	Write data to a secure connection.
 */
ssize_t
secure_write(Port *port, void *ptr, size_t len)
{
	ssize_t		n;

#ifdef USE_SSL
	if (port->ssl)
	{
		int			err;

		if (ssl_renegotiation_limit && port->count > ssl_renegotiation_limit * 1024L)
		{
			SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
									   sizeof(SSL_context));
			if (SSL_renegotiate(port->ssl) <= 0)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL renegotiation failure")));
			if (SSL_do_handshake(port->ssl) <= 0)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL renegotiation failure")));
			if (port->ssl->state != SSL_ST_OK)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL failed to send renegotiation request")));
			port->ssl->state |= SSL_ST_ACCEPT;
			SSL_do_handshake(port->ssl);
			if (port->ssl->state != SSL_ST_OK)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL renegotiation failure")));
			port->count = 0;
		}

wloop:
		errno = 0;
		n = SSL_write(port->ssl, ptr, len);
		err = SSL_get_error(port->ssl, n);
		switch (err)
		{
			case SSL_ERROR_NONE:
				port->count += n;
				break;
			case SSL_ERROR_WANT_READ:
			case SSL_ERROR_WANT_WRITE:
#ifdef WIN32
				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
											(err == SSL_ERROR_WANT_READ) ?
									FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
											INFINITE);
#endif
				goto wloop;
			case SSL_ERROR_SYSCALL:
				/* leave it to caller to ereport the value of errno */
				if (n != -1)
				{
					errno = ECONNRESET;
					n = -1;
				}
				break;
			case SSL_ERROR_SSL:
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL error: %s", SSLerrmessage())));
				/* fall through */
			case SSL_ERROR_ZERO_RETURN:
				errno = ECONNRESET;
				n = -1;
				break;
			default:
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("unrecognized SSL error code: %d",
								err)));
				n = -1;
				break;
		}
	}
	else
#endif
		n = send(port->sock, ptr, len, 0);

	return n;
}
Beispiel #5
0
void ServiceTask::run()
{
	//logger << dlib << endl;
	string ip = "invalid session";
	string alldatlg = "\ngot fd from parent";
	SSL *ssl=NULL;
	BIO *sbio=NULL;
	BIO *io=NULL,*ssl_bio=NULL;
	try
	{
		int cntlen = 0;
		char buf[MAXBUFLENM];
		strVec results;
		stringstream ss;
		string temp;
		//int bytes = -1;
		if(isSSLEnabled)
		{
			sbio=BIO_new_socket(fd,BIO_NOCLOSE);
			ssl=SSL_new(ctx);
			SSL_set_bio(ssl,sbio,sbio);

			io=BIO_new(BIO_f_buffer());
			ssl_bio=BIO_new(BIO_f_ssl());
			BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE);
			BIO_push(io,ssl_bio);

			int r = SSL_accept(ssl);
			cout << r << endl;
			int bser = SSL_get_error(ssl,r);
			cout << bser << endl;
			if(r<=0)
			{
				sslHandler.error_occurred((char*)"SSL accept error",fd,ssl);
				return;
			}


			int er=-1;
			bool flag = true;
			while(flag)
			{
				er = BIO_gets(io,buf,BUFSIZZ-1);
				cout << er << endl;
				int bser = SSL_get_error(ssl,er);
				cout << bser << endl;
				switch(bser)
				{
					case SSL_ERROR_WANT_READ:
					{
						logger << "more to read error" << endl;
						break;
					}
					case SSL_ERROR_WANT_WRITE:
					{
						logger << "more to write error" << endl;
						break;
					}
					case SSL_ERROR_NONE:
					{
						break;
					}
					case SSL_ERROR_ZERO_RETURN:
					{
						sslHandler.error_occurred((char*)"SSL error problem",fd,ssl);
						if(io!=NULL)BIO_free(io);
						return;
					}
					default:
					{
						sslHandler.error_occurred((char*)"SSL read problem",fd,ssl);
						if(io!=NULL)BIO_free(io);
						return;
					}
				}
				ss << buf;
				//logger <<buf <<endl;
				if(!strcmp(buf,"\r\n") || !strcmp(buf,"\n"))
					break;
				string temp(buf);
				if(temp=="")continue;
				temp = temp.substr(0,temp.length()-1);
				results.push_back(temp);
				//logger << temp <<endl;
				if(temp.find("Content-Length:")!=string::npos)
				{
					std::string cntle = temp.substr(temp.find(": ")+2);
					cntle = cntle.substr(0,cntle.length()-1);
					//logger << "contne-length="<<cntle <<endl;
					try
					{
						cntlen = CastUtil::lexical_cast<int>(cntle);
					}
					catch(const char* ex)
					{
						logger << "bad lexical cast" <<endl;
					}
				}
				memset(&buf[0], 0, sizeof(buf));
			}
		}
		else
		{
			int er=-1;
			bool flag = true;
			sbio=BIO_new_socket(fd,BIO_CLOSE);
			io=BIO_new(BIO_f_buffer());
			BIO_push(io,sbio);
			logger << "into run method" << endl;
			while(flag)
			{
				er = BIO_gets(io,buf,BUFSIZZ-1);
				if(er==0)
				{
					close(fd);
					logger << "\nsocket closed before being serviced" <<flush;
					return;
				}
				ss << buf;
				if(!strcmp(buf,"\r\n") || !strcmp(buf,"\n") || er<0)
					break;
				string temp(buf);
				temp = temp.substr(0,temp.length()-1);
				results.push_back(temp);
				//logger << temp <<endl;
				if(temp.find("Content-Length:")!=string::npos)
				{
					std::string cntle = temp.substr(temp.find(": ")+2);
					cntle = cntle.substr(0,cntle.length()-1);
					//logger << "contne-length="<<cntle <<endl;
					try
					{
						cntlen = CastUtil::lexical_cast<int>(cntle);
					}
					catch(const char* ex)
					{
						logger << "bad lexical cast" <<endl;
					}
				}
				memset(&buf[0], 0, sizeof(buf));
			}
		}

		ss.clear();
		if(isSSLEnabled && cntlen>0)
		{
			int er=-1;
			if(cntlen>0)
			{
				//logger << "reading conetnt " << cntlen << endl;
				er = BIO_read(io,buf,cntlen);
				switch(SSL_get_error(ssl,er))
				{
					case SSL_ERROR_NONE:
						cntlen -= er;
						break;
					case SSL_ERROR_ZERO_RETURN:
					{
						sslHandler.error_occurred((char*)"SSL error problem",fd,ssl);
						if(io!=NULL)BIO_free(io);
						return;
					}
					default:
					{
						sslHandler.error_occurred((char*)"SSL read problem",fd,ssl);
						if(io!=NULL)BIO_free(io);
						return;
					}
				}
				string temp(buf);
				results.push_back("\r");
				results.push_back(temp);
				//logger <<buf <<endl;
				memset(&buf[0], 0, sizeof(buf));
			}
		}
		else if(cntlen>0)
		{
			int er=-1;
			if(cntlen>0)
			{
				//logger << "reading conetnt " << cntlen << endl;
				er = BIO_read(io,buf,cntlen);
				if(er==0)
				{
					close(fd);
					logger << "\nsocket closed before being serviced" <<flush;
					return;
				}
				else if(er>0)
				{
					string temp(buf);
					results.push_back("\r");
					results.push_back(temp);
					//logger << temp <<endl;
					memset(&buf[0], 0, sizeof(buf));
				}
			}
		}
		alldatlg += "--read data";
		map<string,string> params1 = *params;
		string webpath = serverRootDirectory + "web/";
		HttpRequest* req= new HttpRequest(results,webpath);
		//logger << req->toString() << endl;

		if(req->getFile()=="")
		{
			logger << req->getFile() << endl;
			req->setFile("index.html");
		}
		if(req->hasCookie())
		{
			logger << "has the session id" << endl;
			if(!configData.sessatserv)
				req->getSession()->setSessionAttributes(req->getCookieInfo());
			else
			{
				string id = req->getCookieInfoAttribute("FFEADID");
				logger << id << endl;
				map<string,string> values = readFromSharedMemeory(id);
				req->getSession()->setSessionAttributes(values);
			}
		}

		if(configData.cntMap[req->getCntxt_name()]!="true")
		{
			req->setCntxt_name("default");
			req->setCntxt_root(webpath+"default");
			req->setUrl(webpath+"default"+req->getActUrl());
		}
		//logger << req->getCntxt_name() << req->getCntxt_root() << req->getUrl() << endl;

		if(configData.appMap[req->getCntxt_name()]!="false")
		{
			if(dlib == NULL)
			{
				cerr << dlerror() << endl;
				exit(-1);
			}
			string meth1 = (req->getCntxt_name()+"checkRules");
			string path1;
			void *mkr1 = dlsym(dlib, meth1.c_str());
			if(mkr1!=NULL)
			{
				typedef string (*DCPPtr1) (string,HttpSession);
				DCPPtr1 f =  (DCPPtr1)mkr1;
				path1 = f(req->getUrl(),*(req->getSession()));
				//logger << path1 << flush;
				if(path1=="FAILED")
				{
					req->setUrl("");
				}
				else if(path1!="" && path1!=req->getUrl())
				{
					req->setUrl(path1);
				}
			}
		}

		HttpResponse res;
		string ext = getFileExtension(req->getUrl());
		vector<unsigned char> test;
		string content;
		string claz;
		bool isoAuthRes = false;
		long sessionTimeoutVar = configData.sessionTimeout;
		bool isContrl = securityHandler.handle(configData.ip_address, req, res, configData.securityObjectMap, sessionTimeoutVar, dlib, configData.cntMap);

		filterHandler.handleIn(req, res, configData.filterMap, dlib, ext);

		if(!isContrl)
		{
			isContrl = authHandler.handle(configData.autMap, configData.autpattMap, req, res, configData.filterMap, dlib, ext);
		}
		string pthwofile = req->getCntxt_name()+req->getActUrl();
		if(req->getCntxt_name()!="default" && configData.cntMap[req->getCntxt_name()]=="true")
		{
			pthwofile = req->getActUrl();
		}
		if(!isContrl)
		{
			isContrl = controllerHandler.handle(req, res, configData.urlpattMap, configData.mappattMap, dlib, ext,
					configData.rstCntMap, configData.mapMap, configData.urlMap, pthwofile);
		}

		/*After going through the controller the response might be blank, just set the HTTP version*/
		res.setHttpVersion(req->getHttpVersion());
		//logger << req->toString() << endl;
		if(req->getMethod()!="TRACE")
		{
			if(isContrl)
			{

			}
			else if(ext==".form")
			{
				formHandler.handle(req, res, configData.formMap, dlib);
			}
			else if((req->getContent_type().find("application/soap+xml")!=string::npos || req->getContent_type().find("text/xml")!=string::npos)
					&& (req->getContent().find("<soap:Envelope")!=string::npos || req->getContent().find("<soapenv:Envelope")!=string::npos)
					&& configData.wsdlmap[req->getFile()]==req->getCntxt_name())
			{
				soapHandler.handle(req, res, dlib, configData.props[".xml"]);
			}
			else
			{
				bool cntrlit = scriptHandler.handle(req, res, configData.handoffs, dlib, ext, configData.props);
				logger << "html page requested" <<endl;
				if(cntrlit)
				{

				}
				else
				{
					cntrlit = extHandler.handle(req, res, dlib, configData.resourcePath, configData.tmplMap, configData.vwMap, ext, configData.props);
				}
				if(!cntrlit && ext==".fview")
				{
					content = fviewHandler.handle(req, res, configData.fviewmap);
				}
				else
				{
					if(res.getContent_str()=="")
						content = getContentStr(req->getUrl(),configData.lprops[req->getDefaultLocale()],ext);
					else
						content = res.getContent_str();
				}
				if(content.length()==0)
				{
					res.setStatusCode("404");
					res.setStatusMsg("Not Found");
					//res.setContent_len(CastUtil::lexical_cast<string>(0));
				}
				else
				{
					res.setStatusCode("200");
					res.setStatusMsg("OK");
					if(res.getContent_type()=="")res.setContent_type(configData.props[ext]);
					res.setContent_str(content);
					//res.setContent_len(CastUtil::lexical_cast<string>(content.length()));
					//sess.setAttribute("CURR",req->getUrl());
				}
			}

			filterHandler.handleOut(req, res, configData.filterMap, dlib, ext);
		}

		alldatlg += "--processed data";
		string h1;
		bool sessionchanged = !req->hasCookie();
		sessionchanged |= req->getSession()->isDirty();
		if(req->getConnection()!="")
			res.setConnection("close");
		createResponse(res,sessionchanged,req->getSession()->getSessionAttributes(),req->getCookieInfoAttribute("FFEADID"), sessionTimeoutVar, configData.sessatserv);
		//Head should behave exactly as Get but there should be no entity body
		if(req->getMethod()=="HEAD")
		{
			h1 = res.generateHeadResponse();
		}
		else if(req->getMethod()=="OPTIONS")
		{
			h1 = res.generateOptionsResponse();
		}
		else if(req->getMethod()=="TRACE")
		{
			h1 = res.generateTraceResponse(req);
		}
		else
		{
			h1 = res.generateResponse();
		}
		//logger << h1 << endl;
		if(isSSLEnabled)
		{
			int r;
			/* Now perform renegotiation if requested */
			if(configData.client_auth==CLIENT_AUTH_REHANDSHAKE){
			  SSL_set_verify(ssl,SSL_VERIFY_PEER |
				SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);

			  /* Stop the client from just resuming the
				 un-authenticated session */
			  SSL_set_session_id_context(ssl,
				(const unsigned char*)&SSLHandler::s_server_auth_session_id_context,
				sizeof(SSLHandler::s_server_auth_session_id_context));

			  if(SSL_renegotiate(ssl)<=0)
			  {
				  sslHandler.error_occurred((char*)"SSL renegotiation error",fd,ssl);
				  if(io!=NULL)BIO_free(io);
				  return;
			  }
			  if(SSL_do_handshake(ssl)<=0)
			  {
				  sslHandler.error_occurred((char*)"SSL renegotiation error",fd,ssl);
				  if(io!=NULL)BIO_free(io);
				  return;
			  }
			  ssl->state=SSL_ST_ACCEPT;
			  if(SSL_do_handshake(ssl)<=0)
			  {
				  sslHandler.error_occurred((char*)"SSL renegotiation error",fd,ssl);
				  if(io!=NULL)BIO_free(io);
				  return;
			  }
			}
			if((r=BIO_puts(io,h1.c_str()))<=0)
			{
				  sslHandler.error_occurred((char*)"send failed",fd,ssl);
				  if(io!=NULL)BIO_free(io);
				  return;
			}
			if((r=BIO_flush(io))<0)
			{
				  sslHandler.error_occurred((char*)"Error flushing BIO",fd,ssl);
				  if(io!=NULL)BIO_free(io);
				  return;
			}
			sslHandler.closeSSL(fd,ssl,io);
		}
		else
		{
			int size;
			if ((size=send(fd,&h1[0] , h1.length(), 0)) == -1)
				logger << "send failed" << flush;
			else if(size==0)
			{
				close(fd);
				memset(&buf[0], 0, sizeof(buf));
				logger << "socket closed for writing" << flush;
				return;
			}

			if(io!=NULL)BIO_free_all(io);
		}
		close(fd);
		memset(&buf[0], 0, sizeof(buf));
		ss.clear();

		//Logger::info("got new connection to process\n"+req->getFile()+" :: " + res.getStatusCode() + "\n"+req->getCntxt_name() + "\n"+req->getCntxt_root() + "\n"+req->getUrl());
		delete req;
		logger << alldatlg << "--sent data--DONE" << flush;
		//sessionMap[sessId] = sess;
	}
	catch(...)
	{
		logger << "Standard exception: " << endl;
	}
}
Beispiel #6
0
/*
 *	Write data to a secure connection.
 */
ssize_t
secure_write(Port *port, void *ptr, size_t len)
{
	ssize_t		n;

#ifdef USE_SSL
	if (port->ssl)
	{
		int			err;

		if (ssl_renegotiation_limit && port->count > ssl_renegotiation_limit * 1024L)
		{
			SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
									   sizeof(SSL_context));
			if (SSL_renegotiate(port->ssl) <= 0)
			{
				report_commerror("SSL renegotiation failure");
			}

			if (SSL_do_handshake(port->ssl) <= 0)
			{
				report_commerror("SSL renegotiation failure");
			}

			if (port->ssl->state != SSL_ST_OK)
			{
				report_commerror("SSL failed to send renegotiation request");
			}

			port->ssl->state |= SSL_ST_ACCEPT;
			SSL_do_handshake(port->ssl);
			if (port->ssl->state != SSL_ST_OK)
			{
				report_commerror("SSL renegotiation failure");
			}

			port->count = 0;
		}

wloop:
		errno = 0;
		n = SSL_write(port->ssl, ptr, len);
		err = SSL_get_error(port->ssl, n);

		const int ERR_MSG_LEN = ERROR_BUF_SIZE + 20;
		char err_msg[ERR_MSG_LEN];

		switch (err)
		{
			case SSL_ERROR_NONE:
				port->count += n;
				break;
			case SSL_ERROR_WANT_READ:
			case SSL_ERROR_WANT_WRITE:
#ifdef WIN32
				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
											(err == SSL_ERROR_WANT_READ) ?
								   FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
											INFINITE);
#endif
				goto wloop;
			case SSL_ERROR_SYSCALL:
				/* leave it to caller to ereport the value of errno */
				if (n != -1)
				{
					errno = ECONNRESET;
					n = -1;
				}
				break;
			case SSL_ERROR_SSL:
				snprintf((char *)&err_msg, ERR_MSG_LEN, "SSL error: %s", SSLerrmessage());
				report_commerror(err_msg);
				/* fall through */
			case SSL_ERROR_ZERO_RETURN:
				errno = ECONNRESET;
				n = -1;
				break;
			default:
				snprintf((char *)&err_msg, ERR_MSG_LEN, "unrecognized SSL error code: %d", err);
				report_commerror(err_msg);

				n = -1;
				break;
		}
	}
	else
#endif
	{
		prepare_for_client_write();
		n = send(port->sock, ptr, len, 0);
		client_write_ended();
	}

	return n;
}
Beispiel #7
0
spocp_result_t
tls_start(conn_t * conn, ruleset_t * rs)
{
	SSL            *ssl;
	SSL_CTX        *ctx = (SSL_CTX *) conn->srv->ctx;
	int             maxbits, r, n = 0;
	char           *sid_ctx = "spocp";
	SSL_CIPHER     *cipher;

	if (conn->ssl != NULL) {
		tls_error(SPOCP_WARNING, conn,
			  "STARTTLS received on already encrypted connection");
		return SPOCP_STATE_VIOLATION;
	}

	if (!(ssl = SSL_new(ctx))) {
		tls_error(SPOCP_ERR, conn, "Error creating SSL context");
		return SPOCP_OPERATIONSERROR;
	}

	/*
	 * do these never fail ?? 
	 */

	SSL_set_session_id_context(ssl, (unsigned char *) sid_ctx,
				   strlen(sid_ctx));

	if (SSL_set_fd(ssl, conn->fd) == 0) {
		traceLog(LOG_ERR,"Couldn't set filedescriptor in SSL");
		return SPOCP_OPERATIONSERROR;
	}

	n = iobuf_content(conn->in);
	traceLog(LOG_INFO,"tls_start: %d bytes in input buffer", n);
	if (n) {
		traceLog(LOG_INFO,"tls_start: %x%x%x%x", conn->in->r[0], conn->in->r[1],
			 conn->in->r[2], conn->in->r[3]);
	}

	LOG(SPOCP_DEBUG)
	    traceLog(LOG_DEBUG,"Waiting for client on %d to initiate handshake",
		     conn->fd);

	/*
	 * waits for the client to initiate the handshake 
	 */
	{
		fd_set rset ; int retval ;
	  
		FD_ZERO( &rset );
		FD_SET( conn->fd, &rset );
		traceLog(LOG_DEBUG, "Waiting for the client" ) ;
		retval = select(conn->fd+1,&rset,NULL,NULL,0) ;
	}
	if ((r = SSL_accept(ssl)) <= 0) {
		int se ;

		if ((se = SSL_get_error(ssl, r)) == SSL_ERROR_WANT_READ) {
			traceLog(LOG_DEBUG,"Want_read");
		} else if (se == SSL_ERROR_SYSCALL) {
			unsigned long err ;

			err = ERR_get_error();
			if( err == 0L && r == 0 ) {
				traceLog(LOG_DEBUG,"EOF observed") ;
			}
			else 
				traceLog(LOG_ERR,"I/O error occured (%ld/%d)", err, r);
		} else {
			traceLog(LOG_ERR,"SSL_get_error: %d", se);
			tls_error(SPOCP_ERR, conn, "SSL accept error");
			SSL_free(ssl);
		}
		conn->status = CNST_ACTIVE;
		return SPOCP_SSL_ERR;
	}
	/*
	 * } 
	 */

	LOG(SPOCP_DEBUG) {
		traceLog(LOG_DEBUG,"SSL accept done");
		traceLog(LOG_DEBUG,"Checking client certificate");
	 }

	if (!check_cert_chain(conn, ssl, rs)) {
		traceLog(LOG_ERR,"Certificate chain check failed");
		SSL_free(ssl);
		conn->status = CNST_ACTIVE;
		return SPOCP_CERT_ERR;
	}

	/*
	 * So the cert is OK and the hostname is in the DN, but do I want to
	 * talk to this guy ?? 
	 */

	cipher = SSL_get_current_cipher(ssl);

	conn->cipher = Strdup((char *) SSL_CIPHER_get_name(cipher));

	conn->ssl_vers = Strdup(SSL_CIPHER_get_version(cipher));

	if (server_access(conn) == 0) {
		traceLog(LOG_ERR,"Client not allowed access");
		SSL_free(ssl);

		conn->status = CNST_ACTIVE;
		return SPOCP_CERT_ERR;
	}

	LOG(SPOCP_DEBUG) traceLog(LOG_DEBUG,"SSL accept done");

	/*
	 * TLS has been set up. Change input/output to read via TLS instead 
	 */

	conn->readn = ssl_socket_readn;
	conn->writen = ssl_socket_writen;
	conn->close = tls_close;

	conn->ssl = (void *) ssl;
	conn->tls_ssf = SSL_CIPHER_get_bits(cipher, &maxbits);
	conn->status = CNST_ACTIVE;

	return SPOCP_SUCCESS;
}
Beispiel #8
0
/*
 *	Write data to a secure connection.
 */
ssize_t
secure_write(Port *port, void *ptr, size_t len)
{
	ssize_t		n;

#ifdef USE_SSL
	if (port->ssl)
	{
		if (port->count > RENEGOTIATION_LIMIT)
		{
			SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
									   sizeof(SSL_context));
			if (SSL_renegotiate(port->ssl) <= 0)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL renegotiation failure")));
			if (SSL_do_handshake(port->ssl) <= 0)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL renegotiation failure")));
			if (port->ssl->state != SSL_ST_OK)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
					errmsg("SSL failed to send renegotiation request")));
			port->ssl->state |= SSL_ST_ACCEPT;
			SSL_do_handshake(port->ssl);
			if (port->ssl->state != SSL_ST_OK)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL renegotiation failure")));
			port->count = 0;
		}

wloop:
		n = SSL_write(port->ssl, ptr, len);
		switch (SSL_get_error(port->ssl, n))
		{
			case SSL_ERROR_NONE:
				port->count += n;
				break;
			case SSL_ERROR_WANT_READ:
			case SSL_ERROR_WANT_WRITE:
				goto wloop;
			case SSL_ERROR_SYSCALL:
				if (n == -1)
					ereport(COMMERROR,
							(errcode_for_socket_access(),
							 errmsg("SSL SYSCALL error: %m")));
				else
				{
					ereport(COMMERROR,
							(errcode(ERRCODE_PROTOCOL_VIOLATION),
							 errmsg("SSL SYSCALL error: EOF detected")));
					errno = ECONNRESET;
					n = -1;
				}
				break;
			case SSL_ERROR_SSL:
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL error: %s", SSLerrmessage())));
				/* fall through */
			case SSL_ERROR_ZERO_RETURN:
				errno = ECONNRESET;
				n = -1;
				break;
			default:
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("unrecognized SSL error code %d",
							SSL_get_error(port->ssl, n))));
				n = -1;
				break;
		}
	}
	else
#endif
		n = send(port->sock, ptr, len, 0);

	return n;
}
Beispiel #9
0
static void init_local(CLI *c) {
    SOCKADDR_UNION addr;
    socklen_t addrlen;

    addrlen=sizeof addr;
    if(getpeername(c->local_rfd.fd, &addr.sa, &addrlen)<0) {
        strcpy(c->accepted_address, "NOT A SOCKET");
        c->local_rfd.is_socket=0;
        c->local_wfd.is_socket=0; /* TODO: It's not always true */
#ifdef USE_WIN32
        if(get_last_socket_error()!=ENOTSOCK) {
#else
        if(c->opt->option.transparent_src || get_last_socket_error()!=ENOTSOCK) {
#endif
            sockerror("getpeerbyname");
            longjmp(c->err, 1);
        }
        /* ignore ENOTSOCK error so 'local' doesn't have to be a socket */
    } else { /* success */
        /* copy addr to c->peer_addr */
        memcpy(&c->peer_addr.addr[0], &addr, sizeof addr);
        c->peer_addr.num=1;
        s_ntop(c->accepted_address, &c->peer_addr.addr[0]);
        c->local_rfd.is_socket=1;
        c->local_wfd.is_socket=1; /* TODO: It's not always true */
        /* it's a socket: lets setup options */
        if(set_socket_options(c->local_rfd.fd, 1)<0)
            longjmp(c->err, 1);
#ifdef USE_LIBWRAP
        libwrap_auth(c);
#endif /* USE_LIBWRAP */
        auth_user(c);
        s_log(LOG_NOTICE, "Service %s accepted connection from %s",
            c->opt->servname, c->accepted_address);
    }
}

static void init_remote(CLI *c) {
    /* create connection to host/service */
    if(c->opt->source_addr.num)
        memcpy(&c->bind_addr, &c->opt->source_addr, sizeof(SOCKADDR_LIST));
#ifndef USE_WIN32
    else if(c->opt->option.transparent_src)
        memcpy(&c->bind_addr, &c->peer_addr, sizeof(SOCKADDR_LIST));
#endif
    else {
        c->bind_addr.num=0; /* don't bind connecting socket */
    }

    /* setup c->remote_fd, now */
    if(c->opt->option.remote)
        c->remote_fd.fd=connect_remote(c);
#ifdef SO_ORIGINAL_DST
    else if(c->opt->option.transparent_dst)
        c->remote_fd.fd=connect_transparent(c);
#endif /* SO_ORIGINAL_DST */
    else /* NOT in remote mode */
        c->remote_fd.fd=connect_local(c);
    c->remote_fd.is_socket=1; /* always! */
    s_log(LOG_DEBUG, "Remote FD=%d initialized", c->remote_fd.fd);
    if(set_socket_options(c->remote_fd.fd, 2)<0)
        longjmp(c->err, 1);
}

static void init_ssl(CLI *c) {
    int i, err;
    SSL_SESSION *old_session;

    if(!(c->ssl=SSL_new(c->opt->ctx))) {
        sslerror("SSL_new");
        longjmp(c->err, 1);
    }
    SSL_set_ex_data(c->ssl, cli_index, c); /* for callbacks */
    SSL_set_session_id_context(c->ssl, (unsigned char *)sid_ctx,
        strlen(sid_ctx));
    if(c->opt->option.client) {
#ifndef OPENSSL_NO_TLSEXT
        if(c->opt->host_name) {
            s_log(LOG_DEBUG, "SNI: host name: %s", c->opt->host_name);
            if(!SSL_set_tlsext_host_name(c->ssl, c->opt->host_name)) {
                sslerror("SSL_set_tlsext_host_name");
                longjmp(c->err, 1);
            }
        }
#endif
        if(c->opt->session) {
            enter_critical_section(CRIT_SESSION);
            SSL_set_session(c->ssl, c->opt->session);
            leave_critical_section(CRIT_SESSION);
        }
        SSL_set_fd(c->ssl, c->remote_fd.fd);
        SSL_set_connect_state(c->ssl);
    } else {
        if(c->local_rfd.fd==c->local_wfd.fd)
            SSL_set_fd(c->ssl, c->local_rfd.fd);
        else {
           /* does it make sence to have SSL on STDIN/STDOUT? */
            SSL_set_rfd(c->ssl, c->local_rfd.fd);
            SSL_set_wfd(c->ssl, c->local_wfd.fd);
        }
        SSL_set_accept_state(c->ssl);
    }

    /* setup some values for transfer() function */
    if(c->opt->option.client) {
        c->sock_rfd=&(c->local_rfd);
        c->sock_wfd=&(c->local_wfd);
        c->ssl_rfd=c->ssl_wfd=&(c->remote_fd);
    } else {
        c->sock_rfd=c->sock_wfd=&(c->remote_fd);
        c->ssl_rfd=&(c->local_rfd);
        c->ssl_wfd=&(c->local_wfd);
    }

    while(1) {
#if OPENSSL_VERSION_NUMBER<0x1000002f
        /* this critical section is a crude workaround for CVE-2010-3864 *
         * see http://www.securityfocus.com/bid/44884 for details        *
         * NOTE: this critical section also covers callbacks (e.g. OCSP) */
        enter_critical_section(CRIT_SSL);
#endif /* OpenSSL version < 1.0.0b */
        if(c->opt->option.client)
            i=SSL_connect(c->ssl);
        else
            i=SSL_accept(c->ssl);
#if OPENSSL_VERSION_NUMBER<0x1000002f
        leave_critical_section(CRIT_SSL);
#endif /* OpenSSL version < 1.0.0b */
        err=SSL_get_error(c->ssl, i);
        if(err==SSL_ERROR_NONE)
            break; /* ok -> done */
        if(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE) {
            s_poll_init(&c->fds);
            s_poll_add(&c->fds, c->ssl_rfd->fd,
                err==SSL_ERROR_WANT_READ,
                err==SSL_ERROR_WANT_WRITE);
            switch(s_poll_wait(&c->fds, c->opt->timeout_busy, 0)) {
            case -1:
                sockerror("init_ssl: s_poll_wait");
                longjmp(c->err, 1);
            case 0:
                s_log(LOG_INFO, "init_ssl: s_poll_wait:"
                    " TIMEOUTbusy exceeded: sending reset");
                longjmp(c->err, 1);
            case 1:
                break; /* OK */
            default:
                s_log(LOG_ERR, "init_ssl: s_poll_wait: unknown result");
                longjmp(c->err, 1);
            }
            continue; /* ok -> retry */
        }
        if(err==SSL_ERROR_SYSCALL) {
            switch(get_last_socket_error()) {
            case EINTR:
            case EAGAIN:
                continue;
            }
        }
        if(c->opt->option.client)
            sslerror("SSL_connect");
        else
            sslerror("SSL_accept");
        longjmp(c->err, 1);
    }
    if(SSL_session_reused(c->ssl)) {
        s_log(LOG_INFO, "SSL %s: previous session reused",
            c->opt->option.client ? "connected" : "accepted");
    } else { /* a new session was negotiated */
        if(c->opt->option.client) {
            s_log(LOG_INFO, "SSL connected: new session negotiated");
            enter_critical_section(CRIT_SESSION);
            old_session=c->opt->session;
            c->opt->session=SSL_get1_session(c->ssl); /* store it */
            if(old_session)
                SSL_SESSION_free(old_session); /* release the old one */
            leave_critical_section(CRIT_SESSION);
        } else
            s_log(LOG_INFO, "SSL accepted: new session negotiated");
        print_cipher(c);
    }
}
Beispiel #10
0
/*
 *	Write data to a secure connection.
 */
ssize_t
secure_write(Port *port, void *ptr, size_t len)
{
	ssize_t		n;

#ifdef USE_SSL
	if (port->ssl)
	{
		int			err;

		/*
		 * If SSL renegotiations are enabled and we're getting close to the
		 * limit, start one now; but avoid it if there's one already in
		 * progress.  Request the renegotiation 1kB before the limit has
		 * actually expired.
		 */
		if (ssl_renegotiation_limit && !in_ssl_renegotiation &&
			port->count > (ssl_renegotiation_limit - 1) * 1024L)
		{
			in_ssl_renegotiation = true;

			/*
			 * The way we determine that a renegotiation has completed is by
			 * observing OpenSSL's internal renegotiation counter.  Make sure
			 * we start out at zero, and assume that the renegotiation is
			 * complete when the counter advances.
			 *
			 * OpenSSL provides SSL_renegotiation_pending(), but this doesn't
			 * seem to work in testing.
			 */
			SSL_clear_num_renegotiations(port->ssl);

			SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
									   sizeof(SSL_context));
			if (SSL_renegotiate(port->ssl) <= 0)
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL failure during renegotiation start")));
			else
			{
				int			retries;

				/*
				 * A handshake can fail, so be prepared to retry it, but only
				 * a few times.
				 */
				for (retries = 0; retries++;)
				{
					if (SSL_do_handshake(port->ssl) > 0)
						break;	/* done */
					ereport(COMMERROR,
							(errcode(ERRCODE_PROTOCOL_VIOLATION),
							 errmsg("SSL handshake failure on renegotiation, retrying")));
					if (retries >= 20)
						ereport(FATAL,
								(errcode(ERRCODE_PROTOCOL_VIOLATION),
								 errmsg("unable to complete SSL handshake")));
				}
			}
		}

wloop:
		errno = 0;
		n = SSL_write(port->ssl, ptr, len);
		err = SSL_get_error(port->ssl, n);
		switch (err)
		{
			case SSL_ERROR_NONE:
				port->count += n;
				break;
			case SSL_ERROR_WANT_READ:
			case SSL_ERROR_WANT_WRITE:
#ifdef WIN32
				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
											(err == SSL_ERROR_WANT_READ) ?
									FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
											INFINITE);
#endif
				goto wloop;
			case SSL_ERROR_SYSCALL:
				/* leave it to caller to ereport the value of errno */
				if (n != -1)
				{
					errno = ECONNRESET;
					n = -1;
				}
				break;
			case SSL_ERROR_SSL:
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL error: %s", SSLerrmessage())));
				/* fall through */
			case SSL_ERROR_ZERO_RETURN:
				errno = ECONNRESET;
				n = -1;
				break;
			default:
				ereport(COMMERROR,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("unrecognized SSL error code: %d",
								err)));
				errno = ECONNRESET;
				n = -1;
				break;
		}

		if (n >= 0)
		{
			/* is renegotiation complete? */
			if (in_ssl_renegotiation &&
				SSL_num_renegotiations(port->ssl) >= 1)
			{
				in_ssl_renegotiation = false;
				port->count = 0;
			}

			/*
			 * if renegotiation is still ongoing, and we've gone beyond the
			 * limit, kill the connection now -- continuing to use it can be
			 * considered a security problem.
			 */
			if (in_ssl_renegotiation &&
				port->count > ssl_renegotiation_limit * 1024L)
				ereport(FATAL,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("SSL failed to renegotiate connection before limit expired")));
		}
	}
	else
#endif
		n = send(port->sock, ptr, len, 0);

	return n;
}
Beispiel #11
0
static int init_ssl(CLI *c) {
    int i, err;

    if(!(c->ssl=SSL_new(ctx))) {
        sslerror("SSL_new");
        return -1;
    }
#if SSLEAY_VERSION_NUMBER >= 0x0922
    SSL_set_session_id_context(c->ssl, sid_ctx, strlen(sid_ctx));
#endif
    if(options.option.client) {
        /* Attempt to use the most recent id in the session cache */
#ifndef HAVE_YASSL /* yassl add, ctx members available */
        if(ctx->session_cache_head)
            if(!SSL_set_session(c->ssl, ctx->session_cache_head))
                log(LOG_WARNING, "Cannot set SSL session id to most recent used");
#endif /* yassl end add */
        SSL_set_fd(c->ssl, c->remote_fd.fd);
        SSL_set_connect_state(c->ssl);
    } else {
        if(c->local_rfd.fd==c->local_wfd.fd)
            SSL_set_fd(c->ssl, c->local_rfd.fd);
        else {
           /* Does it make sence to have SSL on STDIN/STDOUT? */
            SSL_set_rfd(c->ssl, c->local_rfd.fd);
            SSL_set_wfd(c->ssl, c->local_wfd.fd);
        }
        SSL_set_accept_state(c->ssl);
    }

    /* Setup some values for transfer() function */
    if(options.option.client) {
        c->sock_rfd=&(c->local_rfd);
        c->sock_wfd=&(c->local_wfd);
        c->ssl_rfd=c->ssl_wfd=&(c->remote_fd);
    } else {
        c->sock_rfd=c->sock_wfd=&(c->remote_fd);
        c->ssl_rfd=&(c->local_rfd);
        c->ssl_wfd=&(c->local_wfd);
    }

    while(1) {
        if(options.option.client)
            i=SSL_connect(c->ssl);
        else
            i=SSL_accept(c->ssl);
        err=SSL_get_error(c->ssl, i);
        if(err==SSL_ERROR_NONE)
            break; /* ok -> done */
        if(err==SSL_ERROR_WANT_READ) {
            if(waitforsocket(c->ssl_rfd->fd, 0, c->opt->timeout_busy)==1)
                continue; /* ok -> retry */
            return -1; /* timeout or error */
        }
        if(err==SSL_ERROR_WANT_WRITE) {
            if(waitforsocket(c->ssl_wfd->fd, 1, c->opt->timeout_busy)==1)
                continue; /* ok -> retry */
            return -1; /* timeout or error */
        }
        if(err==SSL_ERROR_SYSCALL) {
            switch(get_last_socket_error()) {
            case EINTR:
            case EAGAIN:
                continue; 
            }
        }
        if(options.option.client)
            sslerror("SSL_connect");
        else
            sslerror("SSL_accept");
        return -1;
    }
    print_cipher(c);
    return 0; /* OK */
}
static int http_serve(SSL *ssl, int s)
{
	char buf[BUFSIZZ];
	int r,len;
	BIO *io,*ssl_bio;

	io=BIO_new(BIO_f_buffer());
	ssl_bio=BIO_new(BIO_f_ssl());
	BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE);
	BIO_push(io,ssl_bio);

	while(1){
		r=BIO_gets(io,buf,BUFSIZZ-1);

		switch(SSL_get_error(ssl,r)){
		case SSL_ERROR_NONE:
			len=r;
			break;
		case SSL_ERROR_ZERO_RETURN:
			goto shutdown;
			break;
		default:
			berr_exit("SSL read problem");
		}

		/* Look for the blank line that signals
		   the end of the HTTP headers */
		if(!strcmp(buf,"\r\n") ||
			!strcmp(buf,"\n"))
			break;
	}

	/* Now perform renegotiation if requested */
	if(client_auth==CLIENT_AUTH_REHANDSHAKE){
		SSL_set_verify(ssl,SSL_VERIFY_PEER |
			SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);

		/* Stop the client from just resuming the
		   un-authenticated session */
		SSL_set_session_id_context(ssl,
			(void *)&s_server_auth_session_id_context,
			sizeof(s_server_auth_session_id_context));

		if(SSL_renegotiate(ssl)<=0)
			berr_exit("SSL renegotiation error");
		if(SSL_do_handshake(ssl)<=0)
			berr_exit("SSL renegotiation error");
		ssl->state=SSL_ST_ACCEPT;
		if(SSL_do_handshake(ssl)<=0)
			berr_exit("SSL renegotiation error");
	}

	if((r=BIO_puts
			(io,"HTTP/1.0 200 OK\r\n"))<=0)
		err_exit("Write error");
	if((r=BIO_puts
			(io,"Server: EKRServer\r\n\r\n"))<=0)
		err_exit("Write error");
	if((r=BIO_puts
			(io,"Server test page\r\n"))<=0)
		err_exit("Write error");

	if((r=BIO_flush(io))<0)
		err_exit("Error flushing BIO");


shutdown:
	r=SSL_shutdown(ssl);
	if(!r){
		/* If we called SSL_shutdown() first then
		   we always get return value of '0'. In
		   this case, try again, but first send a
		   TCP FIN to trigger the other side's
		   close_notify*/
		shutdown(s,1);
		r=SSL_shutdown(ssl);
	}

	switch(r){  
	case 1:
		break; /* Success */
	case 0:
	case -1:
	default:
		berr_exit("Shutdown failed");
	}

	SSL_free(ssl);
	close(s);

	return(0);
}
Beispiel #13
0
/** Create a new server TLS session
 *
 * Configures a new server TLS session, configuring options, setting callbacks etc...
 *
 * @param ctx		to alloc session data in. Should usually be NULL unless the lifetime of the
 *			session is tied to another talloc'd object.
 * @param conf		values for this TLS session.
 * @param request	The current #REQUEST.
 * @param client_cert	Whether to require a client_cert.
 * @return
 *	- A new session on success.
 *	- NULL on error.
 */
tls_session_t *tls_session_init_server(TALLOC_CTX *ctx, fr_tls_conf_t *conf, REQUEST *request, bool client_cert)
{
	tls_session_t	*session = NULL;
	SSL		*new_tls = NULL;
	int		verify_mode = 0;
	VALUE_PAIR	*vp;
	SSL_CTX		*ssl_ctx;

	rad_assert(request != NULL);
	rad_assert(conf->ctx_count > 0);

	RDEBUG2("Initiating new TLS session");

	ssl_ctx = conf->ctx[(conf->ctx_count == 1) ? 0 : conf->ctx_next++ % conf->ctx_count];	/* mutex not needed */
	rad_assert(ssl_ctx);

	new_tls = SSL_new(ssl_ctx);
	if (new_tls == NULL) {
		tls_log_error(request, "Error creating new TLS session");
		return NULL;
	}

	session = talloc_zero(ctx, tls_session_t);
	if (session == NULL) {
		RERROR("Error allocating memory for TLS session");
		SSL_free(new_tls);

		return NULL;
	}
	session_init(session);
	session->ctx = ssl_ctx;
	session->ssl = new_tls;

	talloc_set_destructor(session, _tls_session_free);

	/*
	 *	Initialize callbacks
	 */
	session->record_init = record_init;
	session->record_close = record_close;
	session->record_from_buff = record_from_buff;
	session->record_to_buff = record_to_buff;

	/*
	 *	Create & hook the BIOs to handle the dirty side of the
	 *	SSL.  This is *very important* as we want to handle
	 *	the transmission part.  Now the only IO interface
	 *	that SSL is aware of, is our defined BIO buffers.
	 *
	 *	This means that all SSL IO is done to/from memory,
	 *	and we can update those BIOs from the packets we've
	 *	received.
	 */
	session->into_ssl = BIO_new(BIO_s_mem());
	session->from_ssl = BIO_new(BIO_s_mem());
	SSL_set_bio(session->ssl, session->into_ssl, session->from_ssl);

	/*
	 *	Add the message callback to identify what type of
	 *	message/handshake is passed
	 */
	SSL_set_msg_callback(new_tls, tls_session_msg_cb);
	SSL_set_msg_callback_arg(new_tls, session);
	SSL_set_info_callback(new_tls, tls_session_info_cb);

	/*
	 *	This sets the context sessions can be resumed in.
	 *	This is to prevent sessions being created by one application
	 *	and used by another.  In our case it prevents sessions being
	 *	reused between modules, or TLS server components such as
	 *	RADSEC.
	 *
	 *	A context must always be set when doing session resumption
	 *	otherwise session resumption will fail.
	 *
	 *	As the context ID must be <= 32, we digest the context
	 *	data with sha256.
	 */
	rad_assert(conf->session_id_name);
	{
		char		*context_id;
		EVP_MD_CTX	*md_ctx;
		uint8_t		digest[SHA256_DIGEST_LENGTH];

		static_assert(sizeof(digest) <= SSL_MAX_SSL_SESSION_ID_LENGTH,
			      "SSL_MAX_SSL_SESSION_ID_LENGTH must be >= SHA256_DIGEST_LENGTH");

		if (tmpl_aexpand(session, &context_id, request, conf->session_id_name, NULL, NULL) < 0) {
			RPEDEBUG("Failed expanding session ID");
			talloc_free(session);
		}

		MEM(md_ctx = EVP_MD_CTX_create());
		EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL);
		EVP_DigestUpdate(md_ctx, context_id, talloc_array_length(context_id) - 1);
		EVP_DigestFinal_ex(md_ctx, digest, NULL);
		EVP_MD_CTX_destroy(md_ctx);
		talloc_free(context_id);

		if (!fr_cond_assert(SSL_set_session_id_context(session->ssl, digest, sizeof(digest)) == 1)) {
			talloc_free(session);
			return NULL;
		}
	}

	/*
	 *	Add the session certificate to the session.
	 */
	vp = fr_pair_find_by_da(request->control, attr_tls_session_cert_file, TAG_ANY);
	if (vp) {
		RDEBUG2("Loading TLS session certificate \"%s\"", vp->vp_strvalue);

		if (SSL_use_certificate_file(session->ssl, vp->vp_strvalue, SSL_FILETYPE_PEM) != 1) {
			tls_log_error(request, "Failed loading TLS session certificate \"%s\"",
				      vp->vp_strvalue);
			talloc_free(session);
			return NULL;
		}

		if (SSL_use_PrivateKey_file(session->ssl, vp->vp_strvalue, SSL_FILETYPE_PEM) != 1) {
			tls_log_error(request, "Failed loading TLS session certificate \"%s\"",
				      vp->vp_strvalue);
			talloc_free(session);
			return NULL;
		}

		if (SSL_check_private_key(session->ssl) != 1) {
			tls_log_error(request, "Failed validating TLS session certificate \"%s\"",
				      vp->vp_strvalue);
			talloc_free(session);
			return NULL;
		}
	/*
	 *	Better to perform explicit checks, than rely
	 *	on OpenSSL's opaque error messages.
	 */
	} else {
		if (!conf->chains || !conf->chains[0]->private_key_file) {
			ERROR("TLS Server requires a private key file");
			talloc_free(session);
			return NULL;
		}

		if (!conf->chains || !conf->chains[0]->certificate_file) {
			ERROR("TLS Server requires a certificate file");
			talloc_free(session);
			return NULL;
		}
	}

	/*
	 *	In Server mode we only accept.
	 *
	 *	This sets up the SSL session to work correctly with
	 *	tls_session_handhsake.
	 */
	SSL_set_accept_state(session->ssl);

	/*
	 *	Verify the peer certificate, if asked.
	 */
	if (client_cert) {
		RDEBUG2("Setting verify mode to require certificate from client");
		verify_mode = SSL_VERIFY_PEER;
		verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
		verify_mode |= SSL_VERIFY_CLIENT_ONCE;
	}
	SSL_set_verify(session->ssl, verify_mode, tls_validate_cert_cb);

	SSL_set_ex_data(session->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf);
	SSL_set_ex_data(session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (void *)session);

	/*
	 *	We use default fragment size, unless the Framed-MTU
	 *	tells us it's too big.  Note that we do NOT account
	 *	for the EAP-TLS headers if conf->fragment_size is
	 *	large, because that config item looks to be confusing.
	 *
	 *	i.e. it should REALLY be called MTU, and the code here
	 *	should figure out what that means for TLS fragment size.
	 *	asking the administrator to know the internal details
	 *	of EAP-TLS in order to calculate fragment sizes is
	 *	just too much.
	 */
	session->mtu = conf->fragment_size;
	vp = fr_pair_find_by_da(request->packet->vps, attr_framed_mtu, TAG_ANY);
	if (vp && (vp->vp_uint32 > 100) && (vp->vp_uint32 < session->mtu)) {
		RDEBUG2("Setting fragment_len to %u from &Framed-MTU", vp->vp_uint32);
		session->mtu = vp->vp_uint32;
	}

	if (conf->session_cache_server) session->allow_session_resumption = true; /* otherwise it's false */

	return session;
}
Beispiel #14
0
static int init_ssl(CLI *c) {
    int i, err;
    SSL_SESSION *old_session;

    if(!(c->ssl=SSL_new(ctx))) {
        sslerror("SSL_new");
        return -1;
    }
#if SSLEAY_VERSION_NUMBER >= 0x0922
    SSL_set_session_id_context(c->ssl, sid_ctx, strlen(sid_ctx));
#endif
    if(options.option.client) {
        if(c->opt->session) {
            enter_critical_section(CRIT_SESSION);
            SSL_set_session(c->ssl, c->opt->session);
            leave_critical_section(CRIT_SESSION);
        }
        SSL_set_fd(c->ssl, c->remote_fd.fd);
        SSL_set_connect_state(c->ssl);
    } else {
        if(c->local_rfd.fd==c->local_wfd.fd)
            SSL_set_fd(c->ssl, c->local_rfd.fd);
        else {
           /* Does it make sence to have SSL on STDIN/STDOUT? */
            SSL_set_rfd(c->ssl, c->local_rfd.fd);
            SSL_set_wfd(c->ssl, c->local_wfd.fd);
        }
        SSL_set_accept_state(c->ssl);
    }

    /* Setup some values for transfer() function */
    if(options.option.client) {
        c->sock_rfd=&(c->local_rfd);
        c->sock_wfd=&(c->local_wfd);
        c->ssl_rfd=c->ssl_wfd=&(c->remote_fd);
    } else {
        c->sock_rfd=c->sock_wfd=&(c->remote_fd);
        c->ssl_rfd=&(c->local_rfd);
        c->ssl_wfd=&(c->local_wfd);
    }

    while(1) {
        if(options.option.client)
            i=SSL_connect(c->ssl);
        else
            i=SSL_accept(c->ssl);
        err=SSL_get_error(c->ssl, i);
        if(err==SSL_ERROR_NONE)
            break; /* ok -> done */
        if(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE) {
            s_poll_zero(&c->fds);
            s_poll_add(&c->fds, c->ssl_rfd->fd,
                err==SSL_ERROR_WANT_READ,
                err==SSL_ERROR_WANT_WRITE);
            switch(s_poll_wait(&c->fds, c->opt->timeout_busy)) {
            case -1:
                sockerror("init_ssl: s_poll_wait");
                return -1; /* error */
            case 0:
                s_log(LOG_INFO, "init_ssl: s_poll_wait timeout");
                return -1; /* timeout */
            case 1:
                break; /* OK */
            default:
                s_log(LOG_ERR, "init_ssl: s_poll_wait unknown result");
                return -1; /* error */
            }
            continue; /* ok -> retry */
        }
        if(err==SSL_ERROR_SYSCALL) {
            switch(get_last_socket_error()) {
            case EINTR:
            case EAGAIN:
                continue;
            }
        }
        if(options.option.client)
            sslerror("SSL_connect");
        else
            sslerror("SSL_accept");
        return -1;
    }
    if(SSL_session_reused(c->ssl)) {
        s_log(LOG_INFO, "SSL %s: previous session reused",
            options.option.client ? "connected" : "accepted");
    } else { /* a new session was negotiated */
        if(options.option.client) {
            s_log(LOG_INFO, "SSL connected: new session negotiated");
            enter_critical_section(CRIT_SESSION);
            old_session=c->opt->session;
            c->opt->session=SSL_get1_session(c->ssl); /* store it */
            if(old_session)
                SSL_SESSION_free(old_session); /* release the old one */
            leave_critical_section(CRIT_SESSION);
        } else
            s_log(LOG_INFO, "SSL accepted: new session negotiated");
        print_cipher(c);
    }
    return 0; /* OK */
}
/*
 *	Write data to a secure connection.
 */
ssize_t
be_tls_write(Port *port, void *ptr, size_t len, int *waitfor)
{
	ssize_t		n;
	int			err;

	/*
	 * If SSL renegotiations are enabled and we're getting close to the
	 * limit, start one now; but avoid it if there's one already in
	 * progress.  Request the renegotiation 1kB before the limit has
	 * actually expired.
	 */
	if (ssl_renegotiation_limit && !in_ssl_renegotiation &&
		port->count > (ssl_renegotiation_limit - 1) * 1024L)
	{
		in_ssl_renegotiation = true;

		/*
		 * The way we determine that a renegotiation has completed is by
		 * observing OpenSSL's internal renegotiation counter.  Make sure
		 * we start out at zero, and assume that the renegotiation is
		 * complete when the counter advances.
		 *
		 * OpenSSL provides SSL_renegotiation_pending(), but this doesn't
		 * seem to work in testing.
		 */
		SSL_clear_num_renegotiations(port->ssl);

		/* without this, renegotiation fails when a client cert is used */
		SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
								   sizeof(SSL_context));

		if (SSL_renegotiate(port->ssl) <= 0)
			ereport(COMMERROR,
					(errcode(ERRCODE_PROTOCOL_VIOLATION),
					 errmsg("SSL failure during renegotiation start")));
	}

	errno = 0;
	n = SSL_write(port->ssl, ptr, len);
	err = SSL_get_error(port->ssl, n);
	switch (err)
	{
		case SSL_ERROR_NONE:
			port->count += n;
			break;
		case SSL_ERROR_WANT_READ:
			*waitfor = WL_SOCKET_READABLE;
			errno = EWOULDBLOCK;
			n = -1;
			break;
		case SSL_ERROR_WANT_WRITE:
			*waitfor = WL_SOCKET_WRITEABLE;
			errno = EWOULDBLOCK;
			n = -1;
			break;
		case SSL_ERROR_SYSCALL:
			/* leave it to caller to ereport the value of errno */
			if (n != -1)
			{
				errno = ECONNRESET;
				n = -1;
			}
			break;
		case SSL_ERROR_SSL:
			ereport(COMMERROR,
					(errcode(ERRCODE_PROTOCOL_VIOLATION),
					 errmsg("SSL error: %s", SSLerrmessage())));
			/* fall through */
		case SSL_ERROR_ZERO_RETURN:
			errno = ECONNRESET;
			n = -1;
			break;
		default:
			ereport(COMMERROR,
					(errcode(ERRCODE_PROTOCOL_VIOLATION),
					 errmsg("unrecognized SSL error code: %d",
							err)));
			errno = ECONNRESET;
			n = -1;
			break;
	}

	if (n >= 0)
	{
		/* is renegotiation complete? */
		if (in_ssl_renegotiation &&
			SSL_num_renegotiations(port->ssl) >= 1)
		{
			in_ssl_renegotiation = false;
			port->count = 0;
		}

		/*
		 * if renegotiation is still ongoing, and we've gone beyond the
		 * limit, kill the connection now -- continuing to use it can be
		 * considered a security problem.
		 */
		if (in_ssl_renegotiation &&
			port->count > ssl_renegotiation_limit * 1024L)
			ereport(FATAL,
					(errcode(ERRCODE_PROTOCOL_VIOLATION),
					 errmsg("SSL failed to renegotiate connection before limit expired")));
	}

	return n;
}
int ssl_init_ssl_connection(conn_rec *c)
{
    SSLSrvConfigRec *sc;
    SSL *ssl;
    SSLConnRec *sslconn = myConnConfig(c);
    char *vhost_md5;
    modssl_ctx_t *mctx;
    server_rec *server;

    if (!sslconn) {
        sslconn = ssl_init_connection_ctx(c);
    }
    server = sslconn->server;
    sc = mySrvConfig(server);

    /*
     * Seed the Pseudo Random Number Generator (PRNG)
     */
    ssl_rand_seed(server, c->pool, SSL_RSCTX_CONNECT, "");

    mctx = sslconn->is_proxy ? sc->proxy : sc->server;

    /*
     * Create a new SSL connection with the configured server SSL context and
     * attach this to the socket. Additionally we register this attachment
     * so we can detach later.
     */
    if (!(ssl = SSL_new(mctx->ssl_ctx))) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
                      "Unable to create a new SSL connection from the SSL "
                      "context");
        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);

        c->aborted = 1;

        return DECLINED; /* XXX */
    }

    vhost_md5 = ap_md5_binary(c->pool, (unsigned char *)sc->vhost_id,
                              sc->vhost_id_len);

    if (!SSL_set_session_id_context(ssl, (unsigned char *)vhost_md5,
                                    APR_MD5_DIGESTSIZE*2))
    {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
                      "Unable to set session id context to `%s'", vhost_md5);
        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);

        c->aborted = 1;

        return DECLINED; /* XXX */
    }

    SSL_set_app_data(ssl, c);
    SSL_set_app_data2(ssl, NULL); /* will be request_rec */

    sslconn->ssl = ssl;

    /*
     *  Configure callbacks for SSL connection
     */
    SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA);
    SSL_set_tmp_dh_callback(ssl,  ssl_callback_TmpDH);

    SSL_set_verify_result(ssl, X509_V_OK);

    ssl_io_filter_init(c, ssl);

    return APR_SUCCESS;
}
Beispiel #17
0
SSL* SSLMakeSession(SYS_SOCKET SockFD,
                    int iTimeOut,
                    int iIsServerCtx)
{
    char szSessionId[256];
    SYS_INET_ADDR addrInfo;
    const char* pszServerId = "Xmail_Server";
    const char* pszClientId = "Xmail_Client";
    const char* pszId = NULL;
    SSL_CTX* pSSLCtx = NULL;
    SSL* pSSLSession = NULL;

    ZeroData(addrInfo);

    SysGetPeerInfo(SockFD,
                   addrInfo);

    SysInetNToA(addrInfo,
                szSessionId, sizeof(szSessionId)); /* [i_a] */

    if(iSSLInit)
    {
        if(iIsServerCtx)
        {
            pSSLCtx = pSSLSrvCtx;
            pszId = pszServerId;
        }
        else
        {
            pSSLCtx = pSSLCliCtx;
            pszId = pszClientId;
        }

        StrNCat(szSessionId,
                pszId,
                CStringSize(szSessionId) - strlen(szSessionId));

        pSSLSession = SSL_new(pSSLCtx);

        if(pSSLSession != NULL)
        {
#ifdef DEBUG_SSL
            SSL_set_msg_callback(pSSLSession, msg_cb);
#endif
#if SSLEAY_VERSION_NUMBER >= 0x0922
            SSL_set_session_id_context(pSSLSession,
                                       (const unsigned char*)&szSessionId,
                                       (unsigned int)strlen(szSessionId));
#endif
            BIO_set_tcp_ndelay(SockFD, 1); /* [i_a] */
            SSL_set_fd(pSSLSession,
                       SockFD);

            if(iIsServerCtx)
            {
                SSL_set_accept_state(pSSLSession);
            }
            else
            {
                SSL_set_connect_state(pSSLSession);
            }

            time_t tTimeOut = time(NULL) + iTimeOut;

            for(;;)
            {
                int iResult;

                if(iIsServerCtx)
                {
                    iResult = SSL_accept(pSSLSession);
                }
                else
                {
                    iResult = SSL_connect(pSSLSession);
                }

                iResult = SSL_get_error(pSSLSession,
                                        iResult);
                switch(iResult)
                {
                case SSL_ERROR_NONE:

                    break;

                case SSL_ERROR_WANT_READ:
                case SSL_ERROR_WANT_WRITE:
                case SSL_ERROR_WANT_X509_LOOKUP:

                    if(time(NULL) < tTimeOut)
                    {
                        SysMsSleep(1);
                        continue;
                    }

                default:

                    SSL_free(pSSLSession);
                    pSSLSession = NULL;
                }

                break;
            }
        }
    }

    return (pSSLSession);
}