示例#1
0
static lagopus_result_t
connect_tls(struct session *s, const char *host, const char *port) {
  int ret;
  BIO *sbio;

  (void) host;
  (void) port;

  lagopus_msg_info("tls handshake start.\n");

  if (IS_TLS_NOT_INIT(s)) {
    SSL_CTX *ssl_ctx;

    ssl_ctx = get_ssl_ctx(GET_TLS_CTX(s)->ca_dir, GET_TLS_CTX(s)->cert,
                          GET_TLS_CTX(s)->key);
    if (ssl_ctx == NULL) {
      lagopus_msg_warning("get_ssl_ctx() fail.\n");
      return LAGOPUS_RESULT_TLS_CONN_ERROR;
    }
    GET_TLS_CTX(s)->ctx = ssl_ctx;
  }

  if (GET_TLS_CTX(s)->ssl == NULL) {
    SSL *ssl;
    ssl = SSL_new(GET_TLS_CTX(s)->ctx);
    if (ssl == NULL) {
      lagopus_msg_warning("no memory.\n");
      return LAGOPUS_RESULT_TLS_CONN_ERROR;
    }
    GET_TLS_CTX(s)->ssl = ssl;
  }

  if (SSL_get_rbio(GET_TLS_CTX(s)->ssl) == NULL) {
    sbio = BIO_new_socket(s->sock, BIO_NOCLOSE);
    SSL_set_bio(GET_TLS_CTX(s)->ssl, sbio, sbio);
  }

  ret = SSL_connect(GET_TLS_CTX(s)->ssl);
  if (ret == 0) {
    lagopus_msg_warning("tls handshake failed.\n");
    return LAGOPUS_RESULT_TLS_CONN_ERROR;
  } else if (ret < 0
             && (SSL_get_error(GET_TLS_CTX(s)->ssl, ret) != SSL_ERROR_WANT_READ
                 && SSL_get_error(GET_TLS_CTX(s)->ssl, ret) != SSL_ERROR_WANT_READ)) {
    lagopus_msg_warning("tls error (%s:%d).\n", ERR_error_string((unsigned long)
                        SSL_get_error(GET_TLS_CTX(s)->ssl, ret), NULL),
                        (int) SSL_get_error(GET_TLS_CTX(s)->ssl, ret));
    return LAGOPUS_RESULT_TLS_CONN_ERROR;
  } else if (ret < 0) {
    lagopus_msg_info("tls error (%s:%d), but continue.\n",
                     ERR_error_string((unsigned long)
                                      SSL_get_error(GET_TLS_CTX(s)->ssl, ret), NULL),
                     (int) SSL_get_error(GET_TLS_CTX(s)->ssl, ret));
    return LAGOPUS_RESULT_EINPROGRESS;
  } else {
    ret = check_cert_chain(GET_TLS_CTX(s)->ssl);
    if (ret < 0) {
      lagopus_msg_warning("certificate error.\n");
      return LAGOPUS_RESULT_TLS_CONN_ERROR;
    }
    GET_TLS_CTX(s)->verified = true;
    lagopus_msg_info("tls handshake end.\n");
  }

  return LAGOPUS_RESULT_OK;
}
示例#2
0
文件: tls.c 项目: Zabrane/SPOCP
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;
}