Exemplo n.º 1
0
Arquivo: cyassl.c Projeto: AndyUI/curl
/*
 * This function loads all the client/CA certificates and CRLs. Setup the TLS
 * layer and do all necessary magic.
 */
static CURLcode
cyassl_connect_step1(struct connectdata *conn,
                     int sockindex)
{
  char error_buffer[CYASSL_MAX_ERROR_SZ];
  struct SessionHandle *data = conn->data;
  struct ssl_connect_data* conssl = &conn->ssl[sockindex];
  SSL_METHOD* req_method = NULL;
  void* ssl_sessionid = NULL;
  curl_socket_t sockfd = conn->sock[sockindex];
#ifdef HAVE_SNI
  bool sni = FALSE;
#define use_sni(x)  sni = (x)
#else
#define use_sni(x)  Curl_nop_stmt
#endif

  if(conssl->state == ssl_connection_complete)
    return CURLE_OK;

  /* check to see if we've been told to use an explicit SSL/TLS version */
  switch(data->set.ssl.version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
    /* minimum protocol version is set later after the CTX object is created */
    req_method = SSLv23_client_method();
#else
    infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
          "TLS 1.0 is used exclusively\n");
    req_method = TLSv1_client_method();
#endif
    use_sni(TRUE);
    break;
  case CURL_SSLVERSION_TLSv1_0:
    req_method = TLSv1_client_method();
    use_sni(TRUE);
    break;
  case CURL_SSLVERSION_TLSv1_1:
    req_method = TLSv1_1_client_method();
    use_sni(TRUE);
    break;
  case CURL_SSLVERSION_TLSv1_2:
    req_method = TLSv1_2_client_method();
    use_sni(TRUE);
    break;
  case CURL_SSLVERSION_SSLv3:
    /* before WolfSSL SSLv3 was enabled by default, and starting in WolfSSL
       we check for its presence since it is built without it by default */
#if !defined(WOLFSSL_VERSION) || defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
    req_method = SSLv3_client_method();
    use_sni(FALSE);
#else
    failf(data, "No support for SSLv3");
    return CURLE_NOT_BUILT_IN;
#endif
    break;
  case CURL_SSLVERSION_SSLv2:
    failf(data, "CyaSSL does not support SSLv2");
    return CURLE_SSL_CONNECT_ERROR;
  default:
    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(!req_method) {
    failf(data, "SSL: couldn't create a method!");
    return CURLE_OUT_OF_MEMORY;
  }

  if(conssl->ctx)
    SSL_CTX_free(conssl->ctx);
  conssl->ctx = SSL_CTX_new(req_method);

  if(!conssl->ctx) {
    failf(data, "SSL: couldn't create a context!");
    return CURLE_OUT_OF_MEMORY;
  }

  switch(data->set.ssl.version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
    /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever
    minimum version of TLS was built in and at least TLS 1.0. For later library
    versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so
    we have this short circuit evaluation to find the minimum supported TLS
    version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion
    because only the former will work before the user's CTX callback is called.
    */
    if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) {
      failf(data, "SSL: couldn't set the minimum protocol version");
      return CURLE_SSL_CONNECT_ERROR;
    }
#endif
    break;
  }

#ifndef NO_FILESYSTEM
  /* load trusted cacert */
  if(data->set.str[STRING_SSL_CAFILE]) {
    if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
                                          data->set.str[STRING_SSL_CAFILE],
                                          data->set.str[STRING_SSL_CAPATH])) {
      if(data->set.ssl.verifypeer) {
        /* Fail if we insist on successfully verifying the server. */
        failf(data, "error setting certificate verify locations:\n"
              "  CAfile: %s\n  CApath: %s",
              data->set.str[STRING_SSL_CAFILE]?
              data->set.str[STRING_SSL_CAFILE]: "none",
              data->set.str[STRING_SSL_CAPATH]?
              data->set.str[STRING_SSL_CAPATH] : "none");
        return CURLE_SSL_CACERT_BADFILE;
      }
      else {
        /* Just continue with a warning if no strict certificate
           verification is required. */
        infof(data, "error setting certificate verify locations,"
              " continuing anyway:\n");
      }
    }
    else {
      /* Everything is fine. */
      infof(data, "successfully set certificate verify locations:\n");
    }
    infof(data,
          "  CAfile: %s\n"
          "  CApath: %s\n",
          data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
          "none",
          data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
          "none");
  }

  /* Load the client certificate, and private key */
  if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
    int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);

    if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
                                     file_type) != 1) {
      failf(data, "unable to use client certificate (no key or wrong pass"
            " phrase?)");
      return CURLE_SSL_CONNECT_ERROR;
    }

    file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
    if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
                                    file_type) != 1) {
      failf(data, "unable to set private key");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
#endif /* !NO_FILESYSTEM */

  /* SSL always tries to verify the peer, this only says whether it should
   * fail to connect if the verification fails, or if it should continue
   * anyway. In the latter case the result of the verification is checked with
   * SSL_get_verify_result() below. */
  SSL_CTX_set_verify(conssl->ctx,
                     data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
                     NULL);

#ifdef HAVE_SNI
  if(sni) {
    struct in_addr addr4;
#ifdef ENABLE_IPV6
    struct in6_addr addr6;
#endif
    size_t hostname_len = strlen(conn->host.name);
    if((hostname_len < USHRT_MAX) &&
       (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) &&
#ifdef ENABLE_IPV6
       (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) &&
#endif
       (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name,
                          (unsigned short)hostname_len) != 1)) {
      infof(data, "WARNING: failed to configure server name indication (SNI) "
            "TLS extension\n");
    }
  }
#endif

  /* give application a chance to interfere with SSL set up. */
  if(data->set.ssl.fsslctx) {
    CURLcode result = CURLE_OK;
    result = (*data->set.ssl.fsslctx)(data, conssl->ctx,
                                      data->set.ssl.fsslctxp);
    if(result) {
      failf(data, "error signaled by ssl ctx callback");
      return result;
    }
  }
#ifdef NO_FILESYSTEM
  else if(data->set.ssl.verifypeer) {
    failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
          " with \"no filesystem\". Either disable peer verification"
          " (insecure) or if you are building an application with libcurl you"
          " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif

  /* Let's make an SSL structure */
  if(conssl->handle)
    SSL_free(conssl->handle);
  conssl->handle = SSL_new(conssl->ctx);
  if(!conssl->handle) {
    failf(data, "SSL: couldn't create a context (handle)!");
    return CURLE_OUT_OF_MEMORY;
  }

  /* Check if there's a cached ID we can/should use here! */
  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
    /* we got a session id, use it! */
    if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
      failf(data, "SSL: SSL_set_session failed: %s",
            ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer));
      return CURLE_SSL_CONNECT_ERROR;
    }
    /* Informational message */
    infof (data, "SSL re-using session ID\n");
  }

  /* pass the raw socket into the SSL layer */
  if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
    failf(data, "SSL: SSL_set_fd failed");
    return CURLE_SSL_CONNECT_ERROR;
  }

  conssl->connecting_state = ssl_connect_2;
  return CURLE_OK;
}
Exemplo n.º 2
0
bool CSSLComm::ssl_connect(const char *host, int port, const char *certfile, const char *keyfile, const char* capath)
{
    Reset();
 
    int err;
 
    /* Load encryption & hashing algorithms for the SSL program */
    SSL_library_init();
 
    /* Load the error strings for SSL & CRYPTO APIs */
    SSL_load_error_strings();
 
    /* Create an SSL_METHOD structure (choose an SSL/TLS protocol version) */
    m_pmeth = SSLv3_method();
 
    /* Create an SSL_CTX structure */
    m_pctx = SSL_CTX_new(m_pmeth);
    if(!m_pctx)
    {
        printf("Could not get SSL Context\n");
        return false;
    }
 
    /* Load the CA from the Path */
    if(SSL_CTX_load_verify_locations(m_pctx, NULL, capath) <= 0)
    {
        /* Handle failed load here */
        printf("Failed to set CA location...\n");
        ERR_print_errors_fp(stderr);
        return false;
    }
 
    /* Load the client certificate into the SSL_CTX structure */
    if (SSL_CTX_use_certificate_file(m_pctx, certfile, SSL_FILETYPE_PEM) <= 0)
    {
        printf("Cannot use Certificate File\n");
        ERR_print_errors_fp(stderr);
        return false;
    }
 
    /* Load the private-key corresponding to the client certificate */
    if (SSL_CTX_use_PrivateKey_file(m_pctx, keyfile, SSL_FILETYPE_PEM) <= 0)
    {
        printf("Cannot use Private Key\n");
        ERR_print_errors_fp(stderr);
        return false;
    }
 
    /* Check if the client certificate and private-key matches */
    if (!SSL_CTX_check_private_key(m_pctx))
    {
        printf("Private key does not match the certificate public key\n");
        return false;
    }
 
    /* Set up a TCP socket */
    m_sockfd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(m_sockfd == -1)
    {
        printf("Could not get Socket\n");
        return false;
    }
 
    memset (&m_server_addr, '\0', sizeof(m_server_addr));
    m_server_addr.sin_family      = AF_INET;
    m_server_addr.sin_port        = htons(port);       /* Server Port number */
    m_phost_info = gethostbyname(host);
    if(m_phost_info)
    {
        /* Take the first IP */
        struct in_addr *address = (struct in_addr*)m_phost_info->h_addr_list[0];
        m_server_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*address)); /* Server IP */
 
    }
    else
    {
        printf("Could not resolve hostname %s\n", host);
        return false;
    }
 
    /* Establish a TCP/IP connection to the SSL client */
    err = connect(m_sockfd, (struct sockaddr*) &m_server_addr, sizeof(m_server_addr));
    if(err == -1)
    {
        printf("Could not connect\n");
        return false;
    }
 
    /* An SSL structure is created */
    m_pssl = SSL_new(m_pctx);
    if(!m_pssl)
    {
        printf("Could not get SSL Socket\n");
        return false;
    }
 
    /* Assign the socket into the SSL structure (SSL and socket without BIO) */
    SSL_set_fd(m_pssl, (int)m_sockfd);
 
    /* Perform SSL Handshake on the SSL client */
    err = SSL_connect(m_pssl);
    if(err < 0)
    {
        printf("Could not connect to SSL Server\n");
        return false;
    }
    return true;
 
}
Exemplo n.º 3
0
int set_tls_pk(tls_t *tls, const char *fn) {
    return SSL_CTX_use_PrivateKey_file(tls->ctx, fn, SSL_FILETYPE_PEM);
}
Exemplo n.º 4
0
/* Create a socket and connect it to 'ip' on port 'port'.
 * Returns -1 on failure (ip is NULL, socket creation/connection error)
 * Returns sock number on success.
 */
int _mosquitto_socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking)
{
	mosq_sock_t sock = INVALID_SOCKET;
	int rc;
#ifdef WITH_TLS
	int ret;
	BIO *bio;
#endif

	if(!mosq || !host || !port) return MOSQ_ERR_INVAL;

	rc = _mosquitto_try_connect(mosq, host, port, &sock, bind_address, blocking);
	if(rc > 0) return rc;

#ifdef WITH_TLS
	if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
		if(!mosq->tls_version || !strcmp(mosq->tls_version, "tlsv1.2")){
			mosq->ssl_ctx = SSL_CTX_new(TLSv1_2_client_method());
		}else if(!strcmp(mosq->tls_version, "tlsv1.1")){
			mosq->ssl_ctx = SSL_CTX_new(TLSv1_1_client_method());
		}else if(!strcmp(mosq->tls_version, "tlsv1")){
			mosq->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
		}else{
			_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version);
			COMPAT_CLOSE(sock);
			return MOSQ_ERR_INVAL;
		}
#else
		if(!mosq->tls_version || !strcmp(mosq->tls_version, "tlsv1")){
			mosq->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
		}else{
			_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version);
			COMPAT_CLOSE(sock);
			return MOSQ_ERR_INVAL;
		}
#endif
		if(!mosq->ssl_ctx){
			_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
			COMPAT_CLOSE(sock);
			return MOSQ_ERR_TLS;
		}

#if OPENSSL_VERSION_NUMBER >= 0x10000000
		/* Disable compression */
		SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
#ifdef SSL_MODE_RELEASE_BUFFERS
			/* Use even less memory per SSL connection. */
			SSL_CTX_set_mode(mosq->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
#endif

		if(mosq->tls_ciphers){
			ret = SSL_CTX_set_cipher_list(mosq->ssl_ctx, mosq->tls_ciphers);
			if(ret == 0){
				_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", mosq->tls_ciphers);
				COMPAT_CLOSE(sock);
				return MOSQ_ERR_TLS;
			}
		}
		if(mosq->tls_cafile || mosq->tls_capath){
			ret = SSL_CTX_load_verify_locations(mosq->ssl_ctx, mosq->tls_cafile, mosq->tls_capath);
			if(ret == 0){
#ifdef WITH_BROKER
				if(mosq->tls_cafile && mosq->tls_capath){
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\" and bridge_capath \"%s\".", mosq->tls_cafile, mosq->tls_capath);
				}else if(mosq->tls_cafile){
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\".", mosq->tls_cafile);
				}else{
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_capath \"%s\".", mosq->tls_capath);
				}
#else
				if(mosq->tls_cafile && mosq->tls_capath){
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\" and capath \"%s\".", mosq->tls_cafile, mosq->tls_capath);
				}else if(mosq->tls_cafile){
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\".", mosq->tls_cafile);
				}else{
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check capath \"%s\".", mosq->tls_capath);
				}
#endif
				COMPAT_CLOSE(sock);
				return MOSQ_ERR_TLS;
			}
			if(mosq->tls_cert_reqs == 0){
				SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_NONE, NULL);
			}else{
				SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_PEER, _mosquitto_server_certificate_verify);
			}

			if(mosq->tls_pw_callback){
				SSL_CTX_set_default_passwd_cb(mosq->ssl_ctx, mosq->tls_pw_callback);
				SSL_CTX_set_default_passwd_cb_userdata(mosq->ssl_ctx, mosq);
			}

			if(mosq->tls_certfile){
				ret = SSL_CTX_use_certificate_chain_file(mosq->ssl_ctx, mosq->tls_certfile);
				if(ret != 1){
#ifdef WITH_BROKER
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate, check bridge_certfile \"%s\".", mosq->tls_certfile);
#else
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate \"%s\".", mosq->tls_certfile);
#endif
					COMPAT_CLOSE(sock);
					return MOSQ_ERR_TLS;
				}
			}
			if(mosq->tls_keyfile){
				ret = SSL_CTX_use_PrivateKey_file(mosq->ssl_ctx, mosq->tls_keyfile, SSL_FILETYPE_PEM);
				if(ret != 1){
#ifdef WITH_BROKER
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file, check bridge_keyfile \"%s\".", mosq->tls_keyfile);
#else
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file \"%s\".", mosq->tls_keyfile);
#endif
					COMPAT_CLOSE(sock);
					return MOSQ_ERR_TLS;
				}
				ret = SSL_CTX_check_private_key(mosq->ssl_ctx);
				if(ret != 1){
					_mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Client certificate/key are inconsistent.");
					COMPAT_CLOSE(sock);
					return MOSQ_ERR_TLS;
				}
			}
#ifdef REAL_WITH_TLS_PSK
		}else if(mosq->tls_psk){
			SSL_CTX_set_psk_client_callback(mosq->ssl_ctx, psk_client_callback);
#endif
		}

		mosq->ssl = SSL_new(mosq->ssl_ctx);
		if(!mosq->ssl){
			COMPAT_CLOSE(sock);
			return MOSQ_ERR_TLS;
		}
		SSL_set_ex_data(mosq->ssl, tls_ex_index_mosq, mosq);
		bio = BIO_new_socket(sock, BIO_NOCLOSE);
		if(!bio){
			COMPAT_CLOSE(sock);
			return MOSQ_ERR_TLS;
		}
		SSL_set_bio(mosq->ssl, bio, bio);

		mosq->sock = sock;
		if(mosquitto__socket_connect_tls(mosq)){
			return MOSQ_ERR_TLS;
		}

	}
#endif

	mosq->sock = sock;

	return rc;
}
Exemplo n.º 5
0
SSL_CTX *setup_ssl_listen(void)
{
    const SSL_METHOD *method;

    if (sslctx)
        goto done;

    SSL_library_init();
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();
    SSL_load_error_strings();

    /* RAND_status initializes the random number generator through a variety of
       platform-dependent methods, then returns 1 if there is enough entropy or
       0 otherwise. This seems to be a good platform-independent way of seeding
       the generator, as well as of refusing to continue without enough
       entropy. */
    if (!RAND_status())
        bye("Failed to seed OpenSSL PRNG (RAND_status returned false).");

    if (!(method = SSLv23_server_method()))
        bye("SSLv23_server_method(): %s.", ERR_error_string(ERR_get_error(), NULL));
    if (!(sslctx = SSL_CTX_new(method)))
        bye("SSL_CTX_new(): %s.", ERR_error_string(ERR_get_error(), NULL));

    SSL_CTX_set_options(sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);

    /* Secure ciphers list taken from Nsock. */
    if (!SSL_CTX_set_cipher_list(sslctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"))
        bye("Unable to set OpenSSL cipher list: %s", ERR_error_string(ERR_get_error(), NULL));

    if (o.sslcert == NULL && o.sslkey == NULL) {
        X509 *cert;
        EVP_PKEY *key;
        char digest_buf[SHA1_STRING_LENGTH + 1];

        if (o.verbose)
            loguser("Generating a temporary %d-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.\n", DEFAULT_KEY_BITS);
        if (ssl_gen_cert(&cert, &key) == 0)
            bye("ssl_gen_cert(): %s.", ERR_error_string(ERR_get_error(), NULL));
        if (o.verbose) {
            char *fp;
            fp = ssl_cert_fp_str_sha1(cert, digest_buf, sizeof(digest_buf));
            ncat_assert(fp == digest_buf);
            loguser("SHA-1 fingerprint: %s\n", digest_buf);
        }
        if (SSL_CTX_use_certificate(sslctx, cert) != 1)
            bye("SSL_CTX_use_certificate(): %s.", ERR_error_string(ERR_get_error(), NULL));
        if (SSL_CTX_use_PrivateKey(sslctx, key) != 1)
            bye("SSL_CTX_use_PrivateKey(): %s.", ERR_error_string(ERR_get_error(), NULL));
        X509_free(cert);
        EVP_PKEY_free(key);
    } else {
        if (o.sslcert == NULL || o.sslkey == NULL)
            bye("The --ssl-key and --ssl-cert options must be used together.");
        if (SSL_CTX_use_certificate_chain_file(sslctx, o.sslcert) != 1)
            bye("SSL_CTX_use_certificate_chain_file(): %s.", ERR_error_string(ERR_get_error(), NULL));
        if (SSL_CTX_use_PrivateKey_file(sslctx, o.sslkey, SSL_FILETYPE_PEM) != 1)
            bye("SSL_CTX_use_Privatekey_file(): %s.", ERR_error_string(ERR_get_error(), NULL));
    }

done:
    return sslctx;
}
Exemplo n.º 6
0
Arquivo: tls.c Projeto: kaija/libre
/**
 * Allocate a new TLS context
 *
 * @param tlsp    Pointer to allocated TLS context
 * @param method  TLS method
 * @param keyfile Optional private key file
 * @param pwd     Optional password
 *
 * @return 0 if success, otherwise errorcode
 */
int tls_alloc(struct tls **tlsp, enum tls_method method, const char *keyfile,
	      const char *pwd)
{
	struct tls *tls;
	int r, err;

	if (!tlsp)
		return EINVAL;

	tls = mem_zalloc(sizeof(*tls), destructor);
	if (!tls)
		return ENOMEM;

	if (!tlsg.up) {
#ifdef SIGPIPE
		/* Set up a SIGPIPE handler */
		(void)signal(SIGPIPE, sigpipe_handle);
#endif

		SSL_library_init();
		tlsg.up = true;
	}

	if (tlsg.tlsc++ == 0) {
		DEBUG_INFO("error strings loaded\n");
		SSL_load_error_strings();
	}

	switch (method) {

	case TLS_METHOD_SSLV23:
		tls->ctx = SSL_CTX_new(SSLv23_method());
		break;

#ifdef USE_OPENSSL_DTLS
	case TLS_METHOD_DTLSV1:
		tls->ctx = SSL_CTX_new(DTLSv1_method());
		break;
#endif

	default:
		DEBUG_WARNING("tls method %d not supported\n", method);
		err = ENOSYS;
		goto out;
	}

	if (!tls->ctx) {
		err = ENOMEM;
		goto out;
	}

#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
	SSL_CTX_set_verify_depth(tls->ctx, 1);
#endif

	if (method == TLS_METHOD_DTLSV1) {
		SSL_CTX_set_read_ahead(tls->ctx, 1);
	}

	/* Load our keys and certificates */
	if (keyfile) {
		if (pwd) {
			err = str_dup(&tls->pass, pwd);
			if (err)
				goto out;

			SSL_CTX_set_default_passwd_cb(tls->ctx, password_cb);
			SSL_CTX_set_default_passwd_cb_userdata(tls->ctx, tls);
		}

		r = SSL_CTX_use_certificate_chain_file(tls->ctx, keyfile);
		if (r <= 0) {
			DEBUG_WARNING("Can't read certificate file: %s (%d)\n",
				      keyfile, r);
			err = EINVAL;
			goto out;
		}

		r = SSL_CTX_use_PrivateKey_file(tls->ctx, keyfile,
						SSL_FILETYPE_PEM);
		if (r <= 0) {
			DEBUG_WARNING("Can't read key file: %s (%d)\n",
				      keyfile, r);
			err = EINVAL;
			goto out;
		}
	}

	err = 0;
 out:
	if (err)
		mem_deref(tls);
	else
		*tlsp = tls;

	return err;
}
Exemplo n.º 7
0
Arquivo: cyassl.c Projeto: dims/curl
/*
 * This function loads all the client/CA certificates and CRLs. Setup the TLS
 * layer and do all necessary magic.
 */
static CURLcode
cyassl_connect_step1(struct connectdata *conn,
                     int sockindex)
{
  struct SessionHandle *data = conn->data;
  struct ssl_connect_data* conssl = &conn->ssl[sockindex];
  SSL_METHOD* req_method = NULL;
  void* ssl_sessionid = NULL;
  curl_socket_t sockfd = conn->sock[sockindex];

  if(conssl->state == ssl_connection_complete)
    return CURLE_OK;

  /* CyaSSL doesn't support SSLv2 */
  if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
    failf(data, "CyaSSL does not support SSLv2");
    return CURLE_SSL_CONNECT_ERROR;
  }

  /* check to see if we've been told to use an explicit SSL/TLS version */
  switch(data->set.ssl.version) {
  case CURL_SSLVERSION_DEFAULT:
    /* we try to figure out version */
    req_method = SSLv23_client_method();
    break;
  case CURL_SSLVERSION_TLSv1:
    req_method = TLSv1_client_method();
    break;
  case CURL_SSLVERSION_SSLv3:
    req_method = SSLv3_client_method();
    break;
  default:
    req_method = TLSv1_client_method();
  }

  if(!req_method) {
    failf(data, "SSL: couldn't create a method!");
    return CURLE_OUT_OF_MEMORY;
  }

  if(conssl->ctx)
    SSL_CTX_free(conssl->ctx);
  conssl->ctx = SSL_CTX_new(req_method);

  if(!conssl->ctx) {
    failf(data, "SSL: couldn't create a context!");
    return CURLE_OUT_OF_MEMORY;
  }

#ifndef NO_FILESYSTEM
  /* load trusted cacert */
  if(data->set.str[STRING_SSL_CAFILE]) {
    if(!SSL_CTX_load_verify_locations(conssl->ctx,
                                      data->set.str[STRING_SSL_CAFILE],
                                      data->set.str[STRING_SSL_CAPATH])) {
      if(data->set.ssl.verifypeer) {
        /* Fail if we insiste on successfully verifying the server. */
        failf(data,"error setting certificate verify locations:\n"
              "  CAfile: %s\n  CApath: %s\n",
              data->set.str[STRING_SSL_CAFILE]?
              data->set.str[STRING_SSL_CAFILE]: "none",
              data->set.str[STRING_SSL_CAPATH]?
              data->set.str[STRING_SSL_CAPATH] : "none");
        return CURLE_SSL_CACERT_BADFILE;
      }
      else {
        /* Just continue with a warning if no strict  certificate
           verification is required. */
        infof(data, "error setting certificate verify locations,"
              " continuing anyway:\n");
      }
    }
    else {
      /* Everything is fine. */
      infof(data, "successfully set certificate verify locations:\n");
    }
    infof(data,
          "  CAfile: %s\n"
          "  CApath: %s\n",
          data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
          "none",
          data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
          "none");
  }

  /* Load the client certificate, and private key */
  if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
    int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);

    if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
                                     file_type) != 1) {
      failf(data, "unable to use client certificate (no key or wrong pass"
            " phrase?)");
      return CURLE_SSL_CONNECT_ERROR;
    }

    file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
    if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
                                    file_type) != 1) {
      failf(data, "unable to set private key");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
#else
  if(CyaSSL_no_filesystem_verify(conssl->ctx)!= SSL_SUCCESS) {
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif /* NO_FILESYSTEM */

  /* SSL always tries to verify the peer, this only says whether it should
   * fail to connect if the verification fails, or if it should continue
   * anyway. In the latter case the result of the verification is checked with
   * SSL_get_verify_result() below. */
  SSL_CTX_set_verify(conssl->ctx,
                     data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
                     NULL);

  /* Let's make an SSL structure */
  if(conssl->handle)
    SSL_free(conssl->handle);
  conssl->handle = SSL_new(conssl->ctx);
  if(!conssl->handle) {
    failf(data, "SSL: couldn't create a context (handle)!");
    return CURLE_OUT_OF_MEMORY;
  }

  /* Check if there's a cached ID we can/should use here! */
  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
    /* we got a session id, use it! */
    if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
      failf(data, "SSL: SSL_set_session failed: %s",
            ERR_error_string(SSL_get_error(conssl->handle, 0),NULL));
      return CURLE_SSL_CONNECT_ERROR;
    }
    /* Informational message */
    infof (data, "SSL re-using session ID\n");
  }

  /* pass the raw socket into the SSL layer */
  if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
    failf(data, "SSL: SSL_set_fd failed");
    return CURLE_SSL_CONNECT_ERROR;
  }

  conssl->connecting_state = ssl_connect_2;
  return CURLE_OK;
}
Exemplo n.º 8
0
static int __ssl_setup(struct ast_tls_config *cfg, int client)
{
#ifndef DO_SSL
	cfg->enabled = 0;
	return 0;
#else
	if (!cfg->enabled) {
		return 0;
	}

	/* Get rid of an old SSL_CTX since we're about to
	 * allocate a new one
	 */
	if (cfg->ssl_ctx) {
		SSL_CTX_free(cfg->ssl_ctx);
		cfg->ssl_ctx = NULL;
	}

	if (client) {
#ifndef OPENSSL_NO_SSL2
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
		} else
#endif
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
		} else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
		} else {
			/* SSLv23_client_method() sends SSLv2, this was the original
			 * default for ssl clients before the option was given to
			 * pick what protocol a client should use.  In order not
			 * to break expected behavior it remains the default. */
			cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
		}
	} else {
		/* SSLv23_server_method() supports TLSv1, SSLv2, and SSLv3 inbound connections. */
		cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
	}

	if (!cfg->ssl_ctx) {
		ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
		cfg->enabled = 0;
		return 0;
	}
	if (!ast_strlen_zero(cfg->certfile)) {
		char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
		if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0) {
			if (!client) {
				/* Clients don't need a certificate, but if its setup we can use it */
				ast_verb(0, "SSL error loading cert file. <%s>\n", cfg->certfile);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
		if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
			if (!client) {
				/* Clients don't need a private key, but if its setup we can use it */
				ast_verb(0, "SSL error loading private key file. <%s>\n", tmpprivate);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cipher)) {
		if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
			if (!client) {
				ast_verb(0, "SSL cipher error <%s>\n", cfg->cipher);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
		if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) {
			ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
		}
	}

	ast_verb(0, "SSL certificate ok\n");
	return 1;
#endif
}
Exemplo n.º 9
0
Arquivo: ssmtp.c Projeto: fidian/sSMTP
/*
smtp_open() -- Open connection to a remote SMTP listener
*/
int smtp_open(char *host, int port)
{
#ifdef INET6
	struct addrinfo hints, *ai0, *ai;
	char servname[NI_MAXSERV];
	int s;
#else
	struct sockaddr_in name;
	struct hostent *hent;
	int i, s, namelen;
#endif

#ifdef HAVE_SSL
	int err;
	char buf[(BUF_SZ + 1)];

	/* Init SSL stuff */
	SSL_CTX *ctx;
	SSL_METHOD *meth;
	X509 *server_cert;

	SSL_load_error_strings();
	SSLeay_add_ssl_algorithms();
	meth=SSLv23_client_method();
	ctx = SSL_CTX_new(meth);
	if(!ctx) {
		log_event(LOG_ERR, "No SSL support initiated\n");
		return(-1);
	}

	if(use_cert == True) { 
		if(SSL_CTX_use_certificate_chain_file(ctx, tls_cert) <= 0) {
			perror("Use certfile");
			return(-1);
		}

		if(SSL_CTX_use_PrivateKey_file(ctx, tls_cert, SSL_FILETYPE_PEM) <= 0) {
			perror("Use PrivateKey");
			return(-1);
		}

		if(!SSL_CTX_check_private_key(ctx)) {
			log_event(LOG_ERR, "Private key does not match the certificate public key\n");
			return(-1);
		}
	}
#endif

#ifdef INET6
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = p_family;
	hints.ai_socktype = SOCK_STREAM;
	snprintf(servname, sizeof(servname), "%d", port);

	/* Check we can reach the host */
	if (getaddrinfo(host, servname, &hints, &ai0)) {
		log_event(LOG_ERR, "Unable to locate %s", host);
		return(-1);
	}

	for (ai = ai0; ai; ai = ai->ai_next) {
		/* Create a socket for the connection */
		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (s < 0) {
			continue;
		}

		if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
			s = -1;
			continue;
		}
		break;
	}

	if(s < 0) {
		log_event (LOG_ERR,
			"Unable to connect to \"%s\" port %d.\n", host, port);

		return(-1);
	}
#else
	/* Check we can reach the host */
	if((hent = gethostbyname(host)) == (struct hostent *)NULL) {
		log_event(LOG_ERR, "Unable to locate %s", host);
		return(-1);
	}

	if(hent->h_length > sizeof(hent->h_addr)) {
		log_event(LOG_ERR, "Buffer overflow in gethostbyname()");
		return(-1);
	}

	/* Create a socket for the connection */
	if((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		log_event(LOG_ERR, "Unable to create a socket");
		return(-1);
	}

	for (i = 0; ; ++i) {
		if (!hent->h_addr_list[i]) {
			log_event(LOG_ERR, "Unable to connect to %s:%d", host, port);
			return(-1);
		}

	/* This SHOULD already be in Network Byte Order from gethostbyname() */
	name.sin_addr.s_addr = ((struct in_addr *)(hent->h_addr_list[i]))->s_addr;
	name.sin_family = hent->h_addrtype;
	name.sin_port = htons(port);

	namelen = sizeof(struct sockaddr_in);
	if(connect(s, (struct sockaddr *)&name, namelen) < 0)
		continue;
	break;
	}
#endif

#ifdef HAVE_SSL
	if(use_tls == True) {
		log_event(LOG_INFO, "Creating SSL connection to host");

		if (use_starttls == True)
		{
			use_tls=False; /* need to write plain text for a while */

			if (smtp_okay(s, buf))
			{
				smtp_write(s, "EHLO %s", hostname);
				if (smtp_okay(s, buf)) {
					smtp_write(s, "STARTTLS"); /* assume STARTTLS regardless */
					if (!smtp_okay(s, buf)) {
						log_event(LOG_ERR, "STARTTLS not working");
						return(-1);
					}
				}
				else
				{
					log_event(LOG_ERR, "Invalid response: %s (%s)", buf, hostname);
				}
			}
			else
			{
				log_event(LOG_ERR, "Invalid response SMTP Server (STARTTLS)");
				return(-1);
			}
			use_tls=True; /* now continue as normal for SSL */
		}

		ssl = SSL_new(ctx);
		if(!ssl) {
			log_event(LOG_ERR, "SSL not working");
			return(-1);
		}
		SSL_set_fd(ssl, s);

		err = SSL_connect(ssl);
		if(err < 0) { 
			perror("SSL_connect");
			return(-1);
		}

		if(log_level > 0 || 1) {
			log_event(LOG_INFO, "SSL connection using %s",
				SSL_get_cipher(ssl));
		}

		server_cert = SSL_get_peer_certificate(ssl);
		if(!server_cert) {
			return(-1);
		}
		X509_free(server_cert);

		/* TODO: Check server cert if changed! */
	}
#endif

	return(s);
}
Exemplo n.º 10
0
int lws_context_init_client_ssl(struct lws_context_creation_info *info,
				struct lws_vhost *vhost)
{
#if defined(LWS_USE_POLARSSL)
	return 0;
#else
#if defined(LWS_USE_MBEDTLS)
#else
	SSL_METHOD *method;
	struct lws wsi;
	int error;
	int n;

	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
		return 0;

	if (info->provided_client_ssl_ctx) {
		/* use the provided OpenSSL context if given one */
		vhost->ssl_client_ctx = info->provided_client_ssl_ctx;
		/* nothing for lib to delete */
		vhost->user_supplied_ssl_ctx = 1;

		return 0;
	}

	if (info->port != CONTEXT_PORT_NO_LISTEN)
		return 0;

	/* basic openssl init already happened in context init */

	method = (SSL_METHOD *)SSLv23_client_method();
	if (!method) {
		error = ERR_get_error();
		lwsl_err("problem creating ssl method %lu: %s\n",
			error, ERR_error_string(error,
				      (char *)vhost->context->pt[0].serv_buf));
		return 1;
	}
	/* create context */
	vhost->ssl_client_ctx = SSL_CTX_new(method);
	if (!vhost->ssl_client_ctx) {
		error = ERR_get_error();
		lwsl_err("problem creating ssl context %lu: %s\n",
			error, ERR_error_string(error,
				      (char *)vhost->context->pt[0].serv_buf));
		return 1;
	}

#ifdef SSL_OP_NO_COMPRESSION
	SSL_CTX_set_options(vhost->ssl_client_ctx, SSL_OP_NO_COMPRESSION);
#endif
	SSL_CTX_set_options(vhost->ssl_client_ctx,
			    SSL_OP_CIPHER_SERVER_PREFERENCE);
	if (info->ssl_cipher_list)
		SSL_CTX_set_cipher_list(vhost->ssl_client_ctx,
						info->ssl_cipher_list);

#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
		/* loads OS default CA certs */
		SSL_CTX_set_default_verify_paths(vhost->ssl_client_ctx);
#endif

	/* openssl init for cert verification (for client sockets) */
	if (!info->ssl_ca_filepath) {
		if (!SSL_CTX_load_verify_locations(
			vhost->ssl_client_ctx, NULL,
					     LWS_OPENSSL_CLIENT_CERTS))
			lwsl_err(
			    "Unable to load SSL Client certs from %s "
			    "(set by --with-client-cert-dir= "
			    "in configure) --  client ssl isn't "
			    "going to work", LWS_OPENSSL_CLIENT_CERTS);
	} else
		if (!SSL_CTX_load_verify_locations(
			vhost->ssl_client_ctx, info->ssl_ca_filepath,
							  NULL))
			lwsl_err(
				"Unable to load SSL Client certs "
				"file from %s -- client ssl isn't "
				"going to work", info->ssl_ca_filepath);
		else
			lwsl_info("loaded ssl_ca_filepath\n");

	/*
	 * callback allowing user code to load extra verification certs
	 * helping the client to verify server identity
	 */

	/* support for client-side certificate authentication */
	if (info->ssl_cert_filepath) {
		n = SSL_CTX_use_certificate_chain_file(vhost->ssl_client_ctx,
						       info->ssl_cert_filepath);
		if (n != 1) {
			lwsl_err("problem getting cert '%s' %lu: %s\n",
				info->ssl_cert_filepath,
				ERR_get_error(),
				ERR_error_string(ERR_get_error(),
				(char *)vhost->context->pt[0].serv_buf));
			return 1;
		}
	}
	if (info->ssl_private_key_filepath) {
		lws_ssl_bind_passphrase(vhost->ssl_client_ctx, info);
		/* set the private key from KeyFile */
		if (SSL_CTX_use_PrivateKey_file(vhost->ssl_client_ctx,
		    info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) {
			lwsl_err("use_PrivateKey_file '%s' %lu: %s\n",
				info->ssl_private_key_filepath,
				ERR_get_error(),
				ERR_error_string(ERR_get_error(),
				      (char *)vhost->context->pt[0].serv_buf));
			return 1;
		}

		/* verify private key */
		if (!SSL_CTX_check_private_key(vhost->ssl_client_ctx)) {
			lwsl_err("Private SSL key doesn't match cert\n");
			return 1;
		}
	}

	/*
	 * give him a fake wsi with context set, so he can use
	 * lws_get_context() in the callback
	 */
	memset(&wsi, 0, sizeof(wsi));
	wsi.vhost = vhost;
	wsi.context = vhost->context;

	vhost->protocols[0].callback(&wsi,
			LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
				       vhost->ssl_client_ctx, NULL, 0);

	return 0;
#endif
#endif
}
Exemplo n.º 11
0
/*
 * This function loads all the client/CA certificates and CRLs. Setup the TLS
 * layer and do all necessary magic.
 */
static CURLcode
cyassl_connect_step1(struct connectdata *conn,
                     int sockindex)
{
  struct SessionHandle *data = conn->data;
  struct ssl_connect_data* conssl = &conn->ssl[sockindex];
  SSL_METHOD* req_method = NULL;
  void* ssl_sessionid = NULL;
  curl_socket_t sockfd = conn->sock[sockindex];

  if(conssl->state == ssl_connection_complete)
    return CURLE_OK;

  /* check to see if we've been told to use an explicit SSL/TLS version */
  switch(data->set.ssl.version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* 3.3.0 */
    /* the minimum version is set later after the SSL object is created */
    req_method = SSLv23_client_method();
#else
    infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
          "TLS 1.0 is used exclusively\n");
    req_method = TLSv1_client_method();
#endif
    break;
  case CURL_SSLVERSION_TLSv1_0:
    req_method = TLSv1_client_method();
    break;
  case CURL_SSLVERSION_TLSv1_1:
    req_method = TLSv1_1_client_method();
    break;
  case CURL_SSLVERSION_TLSv1_2:
    req_method = TLSv1_2_client_method();
    break;
  case CURL_SSLVERSION_SSLv3:
    req_method = SSLv3_client_method();
    break;
  case CURL_SSLVERSION_SSLv2:
    failf(data, "CyaSSL does not support SSLv2");
    return CURLE_SSL_CONNECT_ERROR;
  default:
    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(!req_method) {
    failf(data, "SSL: couldn't create a method!");
    return CURLE_OUT_OF_MEMORY;
  }

  if(conssl->ctx)
    SSL_CTX_free(conssl->ctx);
  conssl->ctx = SSL_CTX_new(req_method);

  if(!conssl->ctx) {
    failf(data, "SSL: couldn't create a context!");
    return CURLE_OUT_OF_MEMORY;
  }

#ifndef NO_FILESYSTEM
  /* load trusted cacert */
  if(data->set.str[STRING_SSL_CAFILE]) {
    if(!SSL_CTX_load_verify_locations(conssl->ctx,
                                      data->set.str[STRING_SSL_CAFILE],
                                      data->set.str[STRING_SSL_CAPATH])) {
      if(data->set.ssl.verifypeer) {
        /* Fail if we insist on successfully verifying the server. */
        failf(data, "error setting certificate verify locations:\n"
              "  CAfile: %s\n  CApath: %s",
              data->set.str[STRING_SSL_CAFILE]?
              data->set.str[STRING_SSL_CAFILE]: "none",
              data->set.str[STRING_SSL_CAPATH]?
              data->set.str[STRING_SSL_CAPATH] : "none");
        return CURLE_SSL_CACERT_BADFILE;
      }
      else {
        /* Just continue with a warning if no strict certificate
           verification is required. */
        infof(data, "error setting certificate verify locations,"
              " continuing anyway:\n");
      }
    }
    else {
      /* Everything is fine. */
      infof(data, "successfully set certificate verify locations:\n");
    }
    infof(data,
          "  CAfile: %s\n"
          "  CApath: %s\n",
          data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
          "none",
          data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
          "none");
  }

  /* Load the client certificate, and private key */
  if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
    int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);

    if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
                                     file_type) != 1) {
      failf(data, "unable to use client certificate (no key or wrong pass"
            " phrase?)");
      return CURLE_SSL_CONNECT_ERROR;
    }

    file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
    if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
                                    file_type) != 1) {
      failf(data, "unable to set private key");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
#endif /* !NO_FILESYSTEM */

  /* SSL always tries to verify the peer, this only says whether it should
   * fail to connect if the verification fails, or if it should continue
   * anyway. In the latter case the result of the verification is checked with
   * SSL_get_verify_result() below. */
  SSL_CTX_set_verify(conssl->ctx,
                     data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
                     NULL);

  /* give application a chance to interfere with SSL set up. */
  if(data->set.ssl.fsslctx) {
    CURLcode result = CURLE_OK;
    result = (*data->set.ssl.fsslctx)(data, conssl->ctx,
                                      data->set.ssl.fsslctxp);
    if(result) {
      failf(data, "error signaled by ssl ctx callback");
      return result;
    }
  }
#ifdef NO_FILESYSTEM
  else if(data->set.ssl.verifypeer) {
    failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
          " with \"no filesystem\". Either disable peer verification"
          " (insecure) or if you are building an application with libcurl you"
          " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif

  /* Let's make an SSL structure */
  if(conssl->handle)
    SSL_free(conssl->handle);
  conssl->handle = SSL_new(conssl->ctx);
  if(!conssl->handle) {
    failf(data, "SSL: couldn't create a context (handle)!");
    return CURLE_OUT_OF_MEMORY;
  }

  switch(data->set.ssl.version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
    /* short circuit evaluation to find minimum supported TLS version */
    if((CyaSSL_SetMinVersion(conssl->handle, CYASSL_TLSV1) != SSL_SUCCESS) &&
       (CyaSSL_SetMinVersion(conssl->handle, CYASSL_TLSV1_1) != SSL_SUCCESS) &&
       (CyaSSL_SetMinVersion(conssl->handle, CYASSL_TLSV1_2) != SSL_SUCCESS)) {
      failf(data, "SSL: couldn't set the minimum protocol version");
      return CURLE_SSL_CONNECT_ERROR;
    }
#endif
    break;
  }

  /* Check if there's a cached ID we can/should use here! */
  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
    /* we got a session id, use it! */
    if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
      failf(data, "SSL: SSL_set_session failed: %s",
            ERR_error_string(SSL_get_error(conssl->handle, 0), NULL));
      return CURLE_SSL_CONNECT_ERROR;
    }
    /* Informational message */
    infof (data, "SSL re-using session ID\n");
  }

  /* pass the raw socket into the SSL layer */
  if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
    failf(data, "SSL: SSL_set_fd failed");
    return CURLE_SSL_CONNECT_ERROR;
  }

  conssl->connecting_state = ssl_connect_2;
  return CURLE_OK;
}
Exemplo n.º 12
0
Arquivo: tls.c Projeto: flrl/openbsd
int
tls_configure_keypair(struct tls *ctx)
{
	EVP_PKEY *pkey = NULL;
	X509 *cert = NULL;
	BIO *bio = NULL;

	if (ctx->config->cert_mem != NULL) {
		if (ctx->config->cert_len > INT_MAX) {
			tls_set_error(ctx, "certificate too long");
			goto err;
		}

		if (SSL_CTX_use_certificate_chain_mem(ctx->ssl_ctx,
		    ctx->config->cert_mem, ctx->config->cert_len) != 1) {
			tls_set_error(ctx, "failed to load certificate");
			goto err;
		}
		cert = NULL;
	}
	if (ctx->config->key_mem != NULL) {
		if (ctx->config->key_len > INT_MAX) {
			tls_set_error(ctx, "key too long");
			goto err;
		}

		if ((bio = BIO_new_mem_buf(ctx->config->key_mem,
		    ctx->config->key_len)) == NULL) {
			tls_set_error(ctx, "failed to create buffer");
			goto err;
		}
		if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
		    NULL)) == NULL) {
			tls_set_error(ctx, "failed to read private key");
			goto err;
		}
		if (SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey) != 1) {
			tls_set_error(ctx, "failed to load private key");
			goto err;
		}
		BIO_free(bio);
		bio = NULL;
		EVP_PKEY_free(pkey);
		pkey = NULL;
	}

	if (ctx->config->cert_file != NULL) {
		if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx,
		    ctx->config->cert_file) != 1) {
			tls_set_error(ctx, "failed to load certificate file");
			goto err;
		}
	}
	if (ctx->config->key_file != NULL) {
		if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx,
		    ctx->config->key_file, SSL_FILETYPE_PEM) != 1) {
			tls_set_error(ctx, "failed to load private key file");
			goto err;
		}
	}

	if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1) {
		tls_set_error(ctx, "private/public key mismatch");
		goto err;
	}

	return (0);

err:
	EVP_PKEY_free(pkey);
	X509_free(cert);
	BIO_free(bio);

	return (1);
}
Exemplo n.º 13
0
LWS_VISIBLE int
lws_context_init_server_ssl(struct lws_context_creation_info *info,
			    struct lws_vhost *vhost)
{
	SSL_METHOD *method;
	struct lws_context *context = vhost->context;
	struct lws wsi;
	int error;
	int n;

	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
		vhost->use_ssl = 0;
		return 0;
	}

	if (info->port != CONTEXT_PORT_NO_LISTEN) {

		vhost->use_ssl = info->ssl_cert_filepath != NULL;

		if (vhost->use_ssl && info->ssl_cipher_list)
			lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list);

		if (vhost->use_ssl)
			lwsl_notice(" Using SSL mode\n");
		else
			lwsl_notice(" Using non-SSL mode\n");
	}

	/*
	 * give him a fake wsi with context + vhost set, so he can use
	 * lws_get_context() in the callback
	 */
	memset(&wsi, 0, sizeof(wsi));
	wsi.vhost = vhost;
	wsi.context = vhost->context;

	/*
	 * Firefox insists on SSLv23 not SSLv3
	 * Konq disables SSLv2 by default now, SSLv23 works
	 *
	 * SSLv23_server_method() is the openssl method for "allow all TLS
	 * versions", compared to e.g. TLSv1_2_server_method() which only allows
	 * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()
	 */

	method = (SSL_METHOD *)SSLv23_server_method();
	if (!method) {
		error = ERR_get_error();
		lwsl_err("problem creating ssl method %lu: %s\n",
			error, ERR_error_string(error,
					      (char *)context->pt[0].serv_buf));
		return 1;
	}
	vhost->ssl_ctx = SSL_CTX_new(method);	/* create context */
	if (!vhost->ssl_ctx) {
		error = ERR_get_error();
		lwsl_err("problem creating ssl context %lu: %s\n",
			error, ERR_error_string(error,
					      (char *)context->pt[0].serv_buf));
		return 1;
	}

	/* associate the lws context with the SSL_CTX */

	SSL_CTX_set_ex_data(vhost->ssl_ctx,
			openssl_SSL_CTX_private_data_index, vhost->context);

	/* Disable SSLv2 and SSLv3 */
	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
#ifdef SSL_OP_NO_COMPRESSION
	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE);
	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
	if (info->ssl_cipher_list)
		SSL_CTX_set_cipher_list(vhost->ssl_ctx,
						info->ssl_cipher_list);

	/* as a server, are we requiring clients to identify themselves? */

	if (lws_check_opt(info->options, LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) {
		int verify_options = SSL_VERIFY_PEER;

		if (!lws_check_opt(info->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
			verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;

		SSL_CTX_set_session_id_context(vhost->ssl_ctx,
				(unsigned char *)context, sizeof(void *));

		/* absolutely require the client cert */

		SSL_CTX_set_verify(vhost->ssl_ctx,
		       verify_options, OpenSSL_verify_callback);
	}

#ifndef OPENSSL_NO_TLSEXT
	SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx,
					       lws_ssl_server_name_cb);
#endif

	/*
	 * give user code a chance to load certs into the server
	 * allowing it to verify incoming client certs
	 */

	if (info->ssl_ca_filepath &&
	    !SSL_CTX_load_verify_locations(vhost->ssl_ctx,
					   info->ssl_ca_filepath, NULL)) {
		lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__);
	}

	if (vhost->use_ssl) {
		if (lws_context_ssl_init_ecdh_curve(info, vhost))
			return -1;

		vhost->protocols[0].callback(&wsi,
			LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
			vhost->ssl_ctx, NULL, 0);
	}

	if (lws_check_opt(info->options, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))
		/* Normally SSL listener rejects non-ssl, optionally allow */
		vhost->allow_non_ssl_on_ssl_port = 1;

	if (vhost->use_ssl) {
		/* openssl init for server sockets */

		/* set the local certificate from CertFile */
		n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx,
					info->ssl_cert_filepath);
		if (n != 1) {
			error = ERR_get_error();
			lwsl_err("problem getting cert '%s' %lu: %s\n",
				info->ssl_cert_filepath,
				error,
				ERR_error_string(error,
					      (char *)context->pt[0].serv_buf));
			return 1;
		}
		lws_ssl_bind_passphrase(vhost->ssl_ctx, info);

		if (info->ssl_private_key_filepath != NULL) {
			/* set the private key from KeyFile */
			if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx,
				     info->ssl_private_key_filepath,
						       SSL_FILETYPE_PEM) != 1) {
				error = ERR_get_error();
				lwsl_err("ssl problem getting key '%s' %lu: %s\n",
					 info->ssl_private_key_filepath, error,
					 ERR_error_string(error,
					      (char *)context->pt[0].serv_buf));
				return 1;
			}
		} else
			if (vhost->protocols[0].callback(&wsi,
				LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
				vhost->ssl_ctx, NULL, 0)) {
				lwsl_err("ssl private key not set\n");

				return 1;
			}

		/* verify private key */
		if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) {
			lwsl_err("Private SSL key doesn't match cert\n");
			return 1;
		}

		if (lws_context_ssl_init_ecdh(vhost))
			return 1;

		/*
		 * SSL is happy and has a cert it's content with
		 * If we're supporting HTTP2, initialize that
		 */

		lws_context_init_http2_ssl(context);
	}

	return 0;
}
Exemplo n.º 14
0
int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts)
{
	int rc = 1;
	char* ciphers = NULL;

	FUNC_ENTRY;
	if (net->ctx == NULL)
		if ((net->ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)	/* SSLv23 for compatibility with SSLv2, SSLv3 and TLSv1 */
		{
			SSLSocket_error("SSL_CTX_new", NULL, net->socket, rc);
			goto exit;
		}

	if (opts->keyStore)
	{
		if ((rc = SSL_CTX_use_certificate_chain_file(net->ctx, opts->keyStore)) != 1)
		{
			SSLSocket_error("SSL_CTX_use_certificate_chain_file", NULL, net->socket, rc);
			goto free_ctx; /*If we can't load the certificate (chain) file then loading the privatekey won't work either as it needs a matching cert already loaded */
		}

		if (opts->privateKey == NULL)
			opts->privateKey = opts->keyStore;   /* the privateKey can be included in the keyStore */

        if (opts->privateKeyPassword != NULL)
        {
            SSL_CTX_set_default_passwd_cb(net->ctx, pem_passwd_cb);
            SSL_CTX_set_default_passwd_cb_userdata(net->ctx, (void*)opts->privateKeyPassword);
        }

		/* support for ASN.1 == DER format? DER can contain only one certificate? */
		if ((rc = SSL_CTX_use_PrivateKey_file(net->ctx, opts->privateKey, SSL_FILETYPE_PEM)) != 1)
		{
			SSLSocket_error("SSL_CTX_use_PrivateKey_file", NULL, net->socket, rc);
			goto free_ctx;
		}
	}

	if (opts->trustStore)
	{
		if ((rc = SSL_CTX_load_verify_locations(net->ctx, opts->trustStore, NULL)) != 1)
		{
			SSLSocket_error("SSL_CTX_load_verify_locations", NULL, net->socket, rc);
			goto free_ctx;
		}
	}
	else if ((rc = SSL_CTX_set_default_verify_paths(net->ctx)) != 1)
	{
		SSLSocket_error("SSL_CTX_set_default_verify_paths", NULL, net->socket, rc);
		goto free_ctx;
	}

	if (opts->enabledCipherSuites == NULL)
        ciphers = "DEFAULT";
    else
        ciphers = opts->enabledCipherSuites;

	if ((rc = SSL_CTX_set_cipher_list(net->ctx, ciphers)) != 1)
	{
		SSLSocket_error("SSL_CTX_set_cipher_list", NULL, net->socket, rc);
		goto free_ctx;
	}

	SSL_CTX_set_mode(net->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

	goto exit;
free_ctx:
	SSL_CTX_free(net->ctx);
	net->ctx = NULL;

exit:
	FUNC_EXIT_RC(rc);
	return rc;
}
Exemplo n.º 15
0
retcode_t tb_initSSL(Socket_t    S, 
										 enum ssl_mode  mode,       // SSL_CLIENT | SSL_SERVER
										 ssl_meth_t  method,     // SSL1 | SSL2 | SSL3 | TLS1
										 char      * CA_path,
										 char      * CA_file,
										 char      * cert,
										 char      * pwd,
										 char      * cipher) {
	SSL_METHOD * meth;
	sock_ssl_t m;

	tb_info("tb_initSSL in\n");

	if(!TB_VALID(S, TB_SOCKET)) {
		set_tb_errno(TB_ERR_INVALID_TB_OBJECT);
		return TB_ERR;
	}
	if(XSock(S)->ssl != NULL ) {
		tb_warn("tb_initSSL: Socket_t allready SSL initialized\n");
		set_tb_errno(TB_ERR_ALLREADY);
		return TB_ERR;
	}

	m = tb_xcalloc(1, sizeof(struct sock_ssl));
	XSock(S)->ssl = m;
	m->ssl_method = method;

	m->mode = method;


	if( CA_path ) m->CA_path = tb_xstrdup(CA_path);
	if( CA_file ) m->CA_file = tb_xstrdup(CA_file);
	if( cert ) 		m->cert    = tb_xstrdup(cert);
	if( pwd ) 		m->pwd     = tb_xstrdup(pwd);		
	if( cipher ) 	m->cipher  = tb_xstrdup(cipher);
	

	__tb_init_SSL_once();

	switch (m->ssl_method) {
  case 1:
		meth = (mode == SSL_CLIENT) ? SSLv23_client_method() : SSLv23_server_method();
    break;
  case 2:
		meth = (mode == SSL_CLIENT) ? SSLv2_client_method() : SSLv2_server_method();
    break;
  case 3:
		meth = (mode == SSL_CLIENT) ? SSLv3_client_method() : SSLv3_server_method();
    break;
  case 4:
		meth = (mode == SSL_CLIENT) ? TLSv1_client_method() : TLSv1_server_method();
    break;
	default:
		meth = NULL;
		goto err;
  }


	if (!(m->ctx = SSL_CTX_new(meth))) {
    tb_warn("tb_initSSL: Cannot create new SSL context\n");
    ERR_print_errors_fp(stderr);
		XSock(S)->status = TB_BROKEN;
		return TB_ERR; 
  }

	if(tb_errorlevel == TB_DEBUG) SSL_CTX_set_info_callback(m->ctx,info_cb);

  if(m->pwd) {
		SSL_CTX_set_default_passwd_cb(m->ctx, pass_cb);
		SSL_CTX_set_default_passwd_cb_userdata(m->ctx, S);
	}
	

	if(m->cert ) {
		if(SSL_CTX_use_certificate_file(m->ctx, m->cert, SSL_FILETYPE_PEM) <= 0) {
			ERR_print_errors_fp(stderr);
			goto err;
		}
		if (SSL_CTX_use_PrivateKey_file(m->ctx, m->cert, SSL_FILETYPE_PEM) <= 0) {
			tb_error("tb_initSSL: Unable to get private key from '%s'\n", 
							 m->cert);
			ERR_print_errors_fp(stderr);
			goto err;
		}
		tb_info("privkey loaded\n");		
		if (!SSL_CTX_check_private_key(m->ctx)) {
			tb_error("tb_initSSL: Private key does not match the certificate public key\n");
			goto err;
		}
		tb_info("tb_initSSL: privkey validated\n");
		tb_info("tb_initSSL: certificate loaded\n");
	}

	if(mode == SSL_CLIENT) {
		SSL_CTX_set_session_cache_mode(m->ctx, SSL_SESS_CACHE_CLIENT);
	} else {
		SSL_CTX_set_session_cache_mode(m->ctx, SSL_SESS_CACHE_SERVER);
		SSL_CTX_set_session_id_context(m->ctx,  "try this one", 12);
	}

  if(m->CA_file || m->CA_path) {
		tb_info("tb_initSSL: loading CAs ...\n");
    if(!SSL_CTX_load_verify_locations(m->ctx, m->CA_file, m->CA_path)) {
			XSock(S)->status = TB_BROKEN;
      tb_warn("tb_initSSL: Cannot load verify locations %s and %s\n",
              m->CA_file, m->CA_path);
      ERR_print_errors_fp(stderr);
			goto err;
    }
		tb_info("tb_initSSL: CA  <%s/%s> loaded\n", m->CA_path, m->CA_file);
		SSL_CTX_set_verify(m->ctx, SSL_VERIFY_PEER, verify_cb);
		SSL_CTX_set_default_verify_paths(m->ctx);
  }

 /* Create and configure SSL connection. */

  if (!(m->cx = (SSL *)SSL_new(m->ctx))) {
    tb_warn("tb_initSSL: Cannot create new SSL context\n");
    ERR_print_errors_fp(stderr);
		goto err;
  }
	tb_info("tb_initSSL: ssl ctx initialized\n");

  /* Use OpenSSL ciphers -v to see the cipher strings and their SSL
   * versions, key exchange, authentication, encryption, and message
   * digest algorithms, and key length restrictions.  See the OpenSSL
   * for the syntax to combine ciphers, e.g. !SSLv2:RC4-MD5:RC4-SHA.
   * If you don't specify anything, you get the same as "DEFAULT", which
   * means "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP".
   */
  if(m->cipher) {
    if(!SSL_CTX_set_cipher_list(m->ctx, m->cipher)) {
      tb_warn("tb_inittSSL: Cannot use cipher list %s\n", m->cipher);
			goto err;
    }
		tb_info("tb_initSSL: cipher set to <%s>\n", m->cipher);
	}


	tb_info("tb_initSSL out\n");
	return TB_OK;

 err:
	// fixme: context not totally freed (CA_path, pwd ...)
	SSL_CTX_free(m->ctx);
	m->ctx = NULL;
	XSock(S)->status = TB_BROKEN;
	return TB_ERR;
}
Exemplo n.º 16
0
R_API int r_socket_listen (RSocket *s, const char *port, const char *certfile) {
	int optval = 1;
	int ret;
	struct linger linger = { 0 };
	if (r_sandbox_enable (0))
		return R_FALSE;
#if __WINDOWS__
	WSADATA wsadata;
	if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) {
		eprintf ("Error creating socket.");
		return R_FALSE;
	}
#endif
	if ((s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP))<0)
		return R_FALSE;
#if __UNIX__
	linger.l_onoff = 1;
	linger.l_linger = 1;
	ret = setsockopt (s->fd, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof (linger));
	if (ret < 0)
		return R_FALSE;
	{ // fix close after write bug //
	int x = 1500; // FORCE MTU
	ret = setsockopt (s->fd, SOL_SOCKET, SO_SNDBUF, (void*)&x, sizeof (int));
	if (ret < 0)
		return R_FALSE;
	}
	ret = setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof optval);
	if (ret < 0)
		return R_FALSE;
#endif
	memset (&s->sa, 0, sizeof (s->sa));
	s->sa.sin_family = AF_INET;
	s->sa.sin_addr.s_addr = htonl (s->local? INADDR_LOOPBACK: INADDR_ANY);
	s->port = r_socket_port_by_name (port);
	if (s->port <1)
		return R_FALSE;
	s->sa.sin_port = htons (s->port); // TODO honor etc/services

	if (bind (s->fd, (struct sockaddr *)&s->sa, sizeof(s->sa)) < 0) {
		r_sys_perror ("bind");
		close (s->fd);
		return R_FALSE;
	}
#if __UNIX_
	signal (SIGPIPE, SIG_IGN);
#endif
	if (listen (s->fd, 32) < 0) {
		close (s->fd);
		return R_FALSE;
	}
#if HAVE_LIB_SSL
	if (s->is_ssl) {
		s->ctx = SSL_CTX_new (SSLv23_method ());
		if (s->ctx == NULL) {
			r_socket_free (s);
			return R_FALSE;
		}
		if (!SSL_CTX_use_certificate_chain_file (s->ctx, certfile)) {
			r_socket_free (s);
			return R_FALSE;
		}
		if (!SSL_CTX_use_PrivateKey_file (s->ctx, certfile, SSL_FILETYPE_PEM)) {
			r_socket_free (s);
			return R_FALSE;
		}
		SSL_CTX_set_verify_depth (s->ctx, 1);
	}
#endif
	return R_TRUE;
}
Exemplo n.º 17
0
BIO *
httpsGetFileDesc(char * hostname, int port, char * remotename,
	char *extraHeaders, int *errorcode, char **returnedHeaders) 
{
	char *buf;
	char headers[4096];
	char *nextChar = headers;
	char *hstr;
	int sock;
	int rc;
	int checkedCode;
	int headerslen;

	int bufsize;
	int byteswritten;
	struct loaderData_s * loaderData;
	SSL_CTX *ssl_context;
	SSL *ssl;
	BIO *sbio = 0;
	X509 *server_cert;

	*errorcode = 0;

	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (sock < 0) {
		logMessage(ERROR,
			"ROCKS:httpsGetFileDesc:Could not get a socket");
		*errorcode = FTPERR_FAILED_CONNECT;
		return NULL;
	}

	/* OpenSSL_add_all_algorithms(); */
	SSLeay_add_ssl_algorithms();

	ssl_context = SSL_CTX_new(SSLv23_client_method());
	if (!ssl_context) {
		logMessage(ERROR, "Could not create SSLv2,3 context");
		*errorcode = FTPERR_FAILED_CONNECT;
		goto error;
	}

	/* Pull in the Global Loader Data structure. */
	loaderData = rocks_global_loaderData;

	/* I have a Certificate */
	if (loaderData->cert_filename) {
		rc = SSL_CTX_use_certificate_file(ssl_context, 
			loaderData->cert_filename,
			SSL_FILETYPE_PEM);
		if (!rc) {
			logMessage(ERROR, "Could not read Cluster Certificate");
			*errorcode = FTPERR_CLIENT_SECURITY;
			goto error;
		}

		rc = SSL_CTX_use_PrivateKey_file(ssl_context, 
			loaderData->priv_filename,
			SSL_FILETYPE_PEM);
		if (!rc) {
			logMessage(ERROR,
				"Could not read Cluster cert private key");
			*errorcode = FTPERR_CLIENT_SECURITY;
			goto error;
		}

		/* Only connect to servers that have certs signed by
		 * our trusted CA. */
		if (loaderData->authParent) {
			rc = SSL_CTX_load_verify_locations(ssl_context,
				loaderData->ca_filename, 0);
			if (!rc) {
				logMessage(ERROR,
					"Could not read Server CA cert");
				*errorcode = FTPERR_CLIENT_SECURITY;
				goto error;
			}
			SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, 0);
			SSL_CTX_set_verify_depth(ssl_context, 1);
		}
	}

	sbio = BIO_new_ssl_connect(ssl_context);
	if (!sbio) {
		logMessage(ERROR, "Could not create SSL object");
		*errorcode = FTPERR_CLIENT_SECURITY;
		goto error;
	}

	BIO_get_ssl(sbio, &ssl);
	if (!ssl) {
		logMessage(ERROR, "Could not find ssl pointer.");
		*errorcode = FTPERR_CLIENT_SECURITY;
		goto error;
	}

	SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

	BIO_set_conn_hostname(sbio, hostname);
	BIO_set_conn_port(sbio, "https");

	rc = BIO_do_connect(sbio);
	if (rc<=0) {
		rc = SSL_get_verify_result(ssl);
		if (rc) {
			logMessage(ERROR, "Could not verify %s's identity",
				hostname);	
			*errorcode = FTPERR_REFUSED;
			goto error;
		}
		logMessage(ERROR, "Could not connect to %s:https", hostname);
		*errorcode = FTPERR_FAILED_CONNECT;
		goto error;
	}

	rc = BIO_do_handshake(sbio);
	if (rc<=0) {
		logMessage(ERROR,
			"Could not establish HTTPS connection with %s", 
			hostname);
		*errorcode = FTPERR_FAILED_CONNECT;
		goto error;
	}

	server_cert = SSL_get_peer_certificate(ssl);

	/* Show credentials if appropriate. */
	/* Don't Show Credentials */
	if ( (0 == 1)  && !loaderData->cert_filename 
			&& !loaderData->ekv
			&& !loaderData->dropCert) {

		rc = show_cert(server_cert);
		if (rc != 1) {
			*errorcode = FTPERR_REFUSED;
			goto error;
		}
	}

	if (extraHeaders)
		hstr = extraHeaders;
	else
		hstr = "";

	bufsize = strlen(remotename) + strlen(hostname) + strlen(hstr) + 30;

	if ((buf = malloc(bufsize)) == NULL) {
			logMessage(ERROR,
				"ROCKS:httpsGetFileDesc:malloc failed");
			*errorcode = FTPERR_FAILED_CONNECT;
			goto error;
	}

	sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n%s\r\n", remotename, 
		hostname, hstr);

	byteswritten = BIO_puts(sbio, buf);

	logMessage(INFO,
		"ROCKS:httpsGetFileDesc:byteswritten(%d)", byteswritten);
	logMessage(INFO,
		"ROCKS:httpsGetFileDesc:bufsize(%d)", (int)strlen(buf));

	free(buf);

	/* This is fun; read the response a character at a time until we:
	1) Get our first \r\n; which lets us check the return code
	2) Get a \r\n\r\n, which means we're done */

	*nextChar = '\0';
	checkedCode = 0;
	headerslen = 0;
	while (!strstr(headers, "\r\n\r\n")) {

		if (BIO_read(sbio, nextChar, 1) != 1) {
			*errorcode = FTPERR_SERVER_SECURITY;
			goto error;
		}

		nextChar++;
		*nextChar = '\0';
		++headerslen;

		if (nextChar - headers == sizeof(headers)) {
			goto error;
		}

		if (!checkedCode && strstr(headers, "\r\n")) {
			char * start, * end;

			checkedCode = 1;
			start = headers;
			while (!isspace(*start) && *start) start++;
			if (!*start) {
				goto error;
			}

			while (isspace(*start) && *start) start++;

			end = start;
			while (!isspace(*end) && *end) end++;
			if (!*end) {
				goto error;
			}

			logMessage(INFO,
				"ROCKS:httpsGetFileDesc:status %s.", start);

			*end = '\0';
			if (!strcmp(start, "404"))
				goto error;
			else if (!strcmp(start, "403")) {
				*errorcode = FTPERR_SERVER_SECURITY;
				goto error;
			}
			else if (!strcmp(start, "503")) {
				/* A server nack - busy */
				logMessage(WARNING, "ROCKS:server busy");
				watchdog_reset();
				*errorcode = FTPERR_FAILED_DATA_CONNECT;
				goto error;
			}
			else if (strcmp(start, "200")) {
				*errorcode = FTPERR_BAD_SERVER_RESPONSE;
				goto error;
			}

			*end = ' ';
		}
	}

	if ((*returnedHeaders = (char *)malloc(headerslen + 1)) != NULL) {
		memcpy(*returnedHeaders, headers, headerslen + 1);
	}

	return sbio;

error:
	close(sock);
	if (sbio)
		BIO_free_all(sbio);
	if (!*errorcode)
		*errorcode = FTPERR_SERVER_IO_ERROR;
	logMessage(ERROR, "ROCKS:httpsGetFileDesc:Error %s", 
		ftpStrerror(*errorcode, URL_METHOD_HTTP));
	return NULL;
}
Exemplo n.º 18
0
gboolean fbConnSpecInitTLS(
    fbConnSpec_t        *spec,
    gboolean            passive,
    GError              **err)
{
    SSL_METHOD          *tlsmeth = NULL;
    SSL_CTX             *ssl_ctx = NULL;
    gboolean            ok = TRUE;

    /* Initialize the library and error strings */
    SSL_library_init();
    SSL_load_error_strings();

    /*
     * Select a TLS method based on passivity and transport.
     * Shortcircuit on no TLS initialization necessary for sockets.
     */
    switch (spec->transport) {
#if FB_ENABLE_SCTP
    case FB_SCTP:
#endif
    case FB_TCP:
    case FB_UDP:
        return TRUE;
#if HAVE_OPENSSL_DTLS_SCTP
    case FB_DTLS_SCTP:
        tlsmeth = passive ? DTLSv1_server_method() : DTLSv1_client_method();
        break;
#endif
    case FB_TLS_TCP:
        tlsmeth = passive ? TLSv1_server_method() : TLSv1_client_method();
        break;
#if HAVE_OPENSSL_DTLS
    case FB_DTLS_UDP:
        tlsmeth = passive ? DTLSv1_server_method() : DTLSv1_client_method();
        break;
#endif
    default:
        g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_IMPL,
                    "Unsupported TLS method.");
        return FALSE;
    }

    /* Verify we have all the files we need */
    g_assert(spec->ssl_ca_file);
    g_assert(spec->ssl_cert_file);
    g_assert(spec->ssl_key_file);

    /* nuke the old context if there is one */
    if (spec->vssl_ctx) {
        SSL_CTX_free((SSL_CTX *)spec->vssl_ctx);
        spec->vssl_ctx = NULL;
    }

    /* create an SSL_CTX object */
    ssl_ctx = SSL_CTX_new(tlsmeth);

    if (!ssl_ctx) {
        g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_CONN,
                    "Cannot create SSL context: %s",
                    ERR_error_string(ERR_get_error(), NULL));
        while (ERR_get_error());
        ok = FALSE;
        goto end;
    }

    /* Set up password callback */
    SSL_CTX_set_default_passwd_cb(ssl_ctx, fbConnSpecGetTLSPassword);
    SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, spec->ssl_key_pass);

    /* Load CA certificate */
    if (SSL_CTX_load_verify_locations(ssl_ctx,
                                      spec->ssl_ca_file, NULL) != 1) {
        ok = FALSE;
        g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_CONN,
                    "Failed to load certificate authority file %s: %s",
                    spec->ssl_ca_file, ERR_error_string(ERR_get_error(), NULL));
        while (ERR_get_error());
        goto end;
    }

    /* Load certificate */
    if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
                                           spec->ssl_cert_file) != 1) {
        ok = FALSE;
        g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_CONN,
                    "Failed to load certificate file %s: %s",
                    spec->ssl_cert_file,
                    ERR_error_string(ERR_get_error(), NULL));
        while (ERR_get_error());
        goto end;
    }

    /* Load private key */
    if (SSL_CTX_use_PrivateKey_file(ssl_ctx,
                                    spec->ssl_key_file,
                                    SSL_FILETYPE_PEM) != 1) {
        ok = FALSE;
        g_set_error(err, FB_ERROR_DOMAIN, FB_ERROR_CONN,
                    "Failed to load private key file %s: %s",
                    spec->ssl_cert_file,
                    ERR_error_string(ERR_get_error(), NULL));
        while (ERR_get_error());
        goto end;
    }

    /* Require verification */
    SSL_CTX_set_verify(ssl_ctx,
                       SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
                       fbConnSpecVerifyTLSCert);

    /* Stash SSL context in specifier */
    spec->vssl_ctx = ssl_ctx;

end:
    /* free incomplete SSL context */
    if (!ok) SSL_CTX_free(ssl_ctx);
    return ok;
}
Exemplo n.º 19
0
bud_error_t bud_config_init(bud_config_t* config) {
  int i;
  int r;
  bud_context_t* ctx;
  bud_error_t err;
  const char* cert_file;
  const char* key_file;
  BIO* cert_bio;

  /* Get addresses of frontend and backend */
  r = bud_config_str_to_addr(config->frontend.host,
                             config->frontend.port,
                             &config->frontend.addr);
  if (r != 0)
    return bud_error_num(kBudErrPton, r);

  for (i = 0; i < config->backend_count; i++) {
    r = bud_config_str_to_addr(config->backend[i].host,
                               config->backend[i].port,
                               &config->backend[i].addr);
    if (r != 0)
      return bud_error_num(kBudErrPton, r);
  }

  err = bud_config_format_proxyline(config);
  if (!bud_is_ok(err))
    return err;

  /* Balance str to enum */
  if (strcmp(config->balance, "sni") == 0)
    config->balance_e = kBudBalanceSNI;
  else
    config->balance_e = kBudBalanceRoundRobin;

  i = 0;

  if (config->backend_count == 0 && config->balance_e == kBudBalanceRoundRobin)
    return bud_error(kBudErrNoBackend);

  /* Get indexes for SSL_set_ex_data()/SSL_get_ex_data() */
  if (kBudSSLClientIndex == -1) {
    kBudSSLClientIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
    kBudSSLSNIIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
    kBudSSLTicketKeyIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
    if (kBudSSLClientIndex == -1 ||
        kBudSSLSNIIndex == -1 ||
        kBudSSLTicketKeyIndex == -1) {
      err = bud_error(kBudErrNoSSLIndex);
      goto fatal;
    }
  }

#ifndef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
  if (config->context_count != 0) {
    err = bud_error(kBudErrSNINotSupported);
    goto fatal;
  }
#endif  /* !SSL_CTRL_SET_TLSEXT_SERVERNAME_CB */

  /* Allocate workers */
  if (!config->is_worker && config->worker_count != 0) {
    config->workers = calloc(config->worker_count, sizeof(*config->workers));
    if (config->workers == NULL) {
      err = bud_error_str(kBudErrNoMem, "workers");
      goto fatal;
    }
  }

  /* Initialize logger */
  config->logger = bud_logger_new(config, &err);
  if (!bud_is_ok(err))
    goto fatal;

  if (config->is_worker || config->worker_count == 0) {
    /* Connect to SNI server */
    if (config->sni.enabled) {
      config->sni.pool = bud_http_pool_new(config,
                                           config->sni.host,
                                           config->sni.port,
                                           &err);
      if (config->sni.pool == NULL)
        goto fatal;
    }

    /* Connect to OCSP Stapling server */
    if (config->stapling.enabled) {
      config->stapling.pool = bud_http_pool_new(config,
                                                config->stapling.host,
                                                config->stapling.port,
                                                &err);
      if (config->stapling.pool == NULL)
        goto fatal;
    }
  }

  /* Load all contexts */
  for (i = 0; i < config->context_count + 1; i++) {
    ctx = &config->contexts[i];

    err = bud_config_new_ssl_ctx(config, ctx);
    if (!bud_is_ok(err))
      goto fatal;

    /* Default context */
    if (i == 0) {
      cert_file = config->frontend.cert_file;
      key_file = config->frontend.key_file;
    } else {
      cert_file = ctx->cert_file;
      key_file = ctx->key_file;
    }

    cert_bio = BIO_new_file(cert_file, "r");
    if (cert_bio == NULL) {
      err = bud_error_str(kBudErrLoadCert, cert_file);
      goto fatal;
    }

    r = bud_context_use_certificate_chain(ctx, cert_bio);
    BIO_free_all(cert_bio);
    if (!r) {
      err = bud_error_str(kBudErrParseCert, cert_file);
      goto fatal;
    }

    if (!SSL_CTX_use_PrivateKey_file(ctx->ctx,
                                     key_file,
                                     SSL_FILETYPE_PEM)) {
      err = bud_error_str(kBudErrParseKey, key_file);
      goto fatal;
    }
  }

  return bud_ok();

fatal:
  /* Free all allocated contexts */
  do
    bud_context_free(&config->contexts[i--]);
  while (i >= 0);

  return err;
}
Exemplo n.º 20
0
void Context::init(const Params& params)
{
	Poco::Crypto::OpenSSLInitializer::initialize();
	
	createSSLContext();

	try
	{
		int errCode = 0;
		if (!params.caLocation.empty())
		{
			Poco::File aFile(params.caLocation);
			if (aFile.isDirectory())
				errCode = SSL_CTX_load_verify_locations(_pSSLContext, 0, Poco::Path::transcode(params.caLocation).c_str());
			else
				errCode = SSL_CTX_load_verify_locations(_pSSLContext, Poco::Path::transcode(params.caLocation).c_str(), 0);
			if (errCode != 1)
			{
				std::string msg = Utility::getLastError();
				throw SSLContextException(std::string("Cannot load CA file/directory at ") + params.caLocation, msg);
			}
		}

		if (params.loadDefaultCAs)
		{
			errCode = SSL_CTX_set_default_verify_paths(_pSSLContext);
			if (errCode != 1)
			{
				std::string msg = Utility::getLastError();
				throw SSLContextException("Cannot load default CA certificates", msg);
			}
		}

		if (!params.privateKeyFile.empty())
		{
			errCode = SSL_CTX_use_PrivateKey_file(_pSSLContext, Poco::Path::transcode(params.privateKeyFile).c_str(), SSL_FILETYPE_PEM);
			if (errCode != 1)
			{
				std::string msg = Utility::getLastError();
				throw SSLContextException(std::string("Error loading private key from file ") + params.privateKeyFile, msg);
			}
		}

		if (!params.certificateFile.empty())
		{
			errCode = SSL_CTX_use_certificate_chain_file(_pSSLContext, Poco::Path::transcode(params.certificateFile).c_str());
			if (errCode != 1)
			{
				std::string errMsg = Utility::getLastError();
				throw SSLContextException(std::string("Error loading certificate from file ") + params.certificateFile, errMsg);
			}
		}

		if (isForServerUse())
			SSL_CTX_set_verify(_pSSLContext, params.verificationMode, &SSLManager::verifyServerCallback);
		else
			SSL_CTX_set_verify(_pSSLContext, params.verificationMode, &SSLManager::verifyClientCallback);

		SSL_CTX_set_cipher_list(_pSSLContext, params.cipherList.c_str());
		SSL_CTX_set_verify_depth(_pSSLContext, params.verificationDepth);
		SSL_CTX_set_mode(_pSSLContext, SSL_MODE_AUTO_RETRY);
		SSL_CTX_set_session_cache_mode(_pSSLContext, SSL_SESS_CACHE_OFF);
		
		initDH(params.dhParamsFile);
		initECDH(params.ecdhCurve);
	}
	catch (...)
	{
		SSL_CTX_free(_pSSLContext);
		throw;
	}
}
Exemplo n.º 21
0
SSL *SSLSocket::createSSL(SSL_CTX *ctx) {
  ERR_clear_error();

  /* look at options in the stream and set appropriate verification flags */
  if (m_context[s_verify_peer].toBoolean()) {
    /* turn on verification callback */
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);

    /* CA stuff */
    String cafile = m_context[s_cafile].toString();
    String capath = m_context[s_capath].toString();

    if (!cafile.empty() || !capath.empty()) {
      if (!SSL_CTX_load_verify_locations(ctx, cafile.data(), capath.data())) {
        raise_warning("Unable to set verify locations `%s' `%s'",
                      cafile.data(), capath.data());
        return nullptr;
      }
    }

    int64_t depth = m_context[s_verify_depth].toInt64();
    if (depth) {
      SSL_CTX_set_verify_depth(ctx, depth);
    }
  } else {
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr);
  }

  /* callback for the passphrase (for localcert) */
  if (!m_context[s_passphrase].toString().empty()) {
    SSL_CTX_set_default_passwd_cb_userdata(ctx, this);
    SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
  }

  String cipherlist = m_context[s_ciphers].toString();
  if (cipherlist.empty()) {
    cipherlist = "DEFAULT";
  }
  SSL_CTX_set_cipher_list(ctx, cipherlist.data());

  String certfile = m_context[s_local_cert].toString();
  if (!certfile.empty()) {
    String resolved_path_buff = File::TranslatePath(certfile);
    if (!resolved_path_buff.empty()) {
      /* a certificate to use for authentication */
      if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff.data())
          != 1) {
        raise_warning("Unable to set local cert chain file `%s'; Check "
                      "that your cafile/capath settings include details of "
                      "your certificate and its issuer", certfile.data());
        return nullptr;
      }

      if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff.data(),
                                      SSL_FILETYPE_PEM) != 1) {
        raise_warning("Unable to set private key file `%s'",
                      resolved_path_buff.data());
        return nullptr;
      }

      SSL *tmpssl = SSL_new(ctx);
      X509 *cert = SSL_get_certificate(tmpssl);
      if (cert) {
        EVP_PKEY *key = X509_get_pubkey(cert);
        EVP_PKEY_copy_parameters(key, SSL_get_privatekey(tmpssl));
        EVP_PKEY_free(key);
      }
      SSL_free(tmpssl);

      if (!SSL_CTX_check_private_key(ctx)) {
        raise_warning("Private key does not match certificate!");
      }
    }
  }

  SSL *ssl = SSL_new(ctx);
  if (ssl) {
    SSL_set_ex_data(ssl, GetSSLExDataIndex(), this); /* map SSL => stream */
  }
  return ssl;
}
Exemplo n.º 22
0
apn_return apn_ssl_connect(apn_ctx_t *const ctx) {
    assert(ctx);

    SSL_CTX *ssl_ctx = NULL;
    if (NULL == (ssl_ctx = SSL_CTX_new(TLSv1_client_method()))) {
        apn_log(ctx, APN_LOG_LEVEL_ERROR, "Could not initialize SSL context: %s",
                  ERR_error_string(ERR_get_error(), NULL));
        return APN_ERROR;
    }

    SSL_CTX_set_ex_data(ssl_ctx, 0, ctx);
    SSL_CTX_set_info_callback(ssl_ctx, __apn_ssl_info_callback);

    X509 *cert = NULL;

    if (ctx->pkcs12_file && ctx->pkcs12_pass) {
        FILE *pkcs12_file = NULL;
#ifdef _WIN32
        fopen_s(&pkcs12_file, ctx->pkcs12_file, "r");
#else
        pkcs12_file = fopen(ctx->pkcs12_file, "r");
#endif
        if (!pkcs12_file) {
            char *error = apn_error_string(errno);
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to open file %s: %s (errno: %d)", ctx->pkcs12_file, error,
                      errno);
            free(error);
            SSL_CTX_free(ssl_ctx);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12;
            return APN_ERROR;
        }

        PKCS12 *pkcs12_cert = NULL;
        d2i_PKCS12_fp(pkcs12_file, &pkcs12_cert);
        fclose(pkcs12_file);

        EVP_PKEY *private_key = NULL;

        if (!PKCS12_parse(pkcs12_cert, ctx->pkcs12_pass, &private_key, &cert, NULL)) {
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified PKCS#12 file: %s",
                      ERR_error_string(ERR_get_error(), NULL));
            PKCS12_free(pkcs12_cert);
            SSL_CTX_free(ssl_ctx);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12;
            return APN_ERROR;
        }
        PKCS12_free(pkcs12_cert);

        if (!SSL_CTX_use_certificate(ssl_ctx, cert)) {
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified PKCS#12 file: %s",
                      ERR_error_string(ERR_get_error(), NULL));
            X509_free(cert);
            EVP_PKEY_free(private_key);
            SSL_CTX_free(ssl_ctx);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12;
            return APN_ERROR;
        }

        if (!SSL_CTX_use_PrivateKey(ssl_ctx, private_key)) {
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified PKCS#12 file: %s",
                      ERR_error_string(ERR_get_error(), NULL));
            X509_free(cert);
            EVP_PKEY_free(private_key);
            SSL_CTX_free(ssl_ctx);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PKCS12;
            return APN_ERROR;
        }
        EVP_PKEY_free(private_key);
    } else {
        FILE *cert_file = NULL;
#ifdef _WIN32
        fopen_s(&cert_file, ctx->certificate_file, "r");
#else
        cert_file = fopen(ctx->certificate_file, "r");
#endif
        if (!cert_file) {
            char *error = apn_error_string(errno);
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to open file %s: %s (errno: %d)", ctx->pkcs12_file, error,
                      errno);
            free(error);
            X509_free(cert);
            SSL_CTX_free(ssl_ctx);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE;
            return APN_ERROR;
        }

        cert = PEM_read_X509(cert_file, NULL, NULL, NULL);
        if (!cert) {
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified certificate: %s",
                      ERR_error_string(ERR_get_error(), NULL));
            SSL_CTX_free(ssl_ctx);
            fclose(cert_file);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE;
            return EXIT_FAILURE;
        }
        fclose(cert_file);

        if (!SSL_CTX_use_certificate(ssl_ctx, cert)) {
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified certificate: %s",
                      ERR_error_string(ERR_get_error(), NULL));
            X509_free(cert);
            SSL_CTX_free(ssl_ctx);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE;
            return APN_ERROR;
        }

        SSL_CTX_set_default_passwd_cb(ssl_ctx, __apn_ssl_password_callback);
        char *password = NULL;
        if (ctx->private_key_pass) {
            password = apn_strndup(ctx->private_key_pass, strlen(ctx->private_key_pass));
            if (!password) {
                X509_free(cert);
                SSL_CTX_free(ssl_ctx);
                return APN_ERROR;
            }
            SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, password);
        } else {
            SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL);
        }

        if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, ctx->private_key_file, SSL_FILETYPE_PEM)) {
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified private key: %s",
                      ERR_error_string(ERR_get_error(), NULL));
            apn_strfree(&password);
            X509_free(cert);
            SSL_CTX_free(ssl_ctx);
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY;
            return APN_ERROR;
        }

        apn_strfree(&password);

        if (!SSL_CTX_check_private_key(ssl_ctx)) {
            apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to use specified private key: %s",
                      ERR_error_string(ERR_get_error(), NULL));
            errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY;
            X509_free(cert);
            SSL_CTX_free(ssl_ctx);
            return APN_ERROR;
        }
    }

    if(cert) {
        char *subject = __apn_cert_subject_string(cert);
        apn_log(ctx, APN_LOG_LEVEL_INFO, "Local certificate subject: %s", subject);

        char *issuer = __apn_cert_issuer_string(cert);
        apn_log(ctx, APN_LOG_LEVEL_INFO, "Local certificate issuer: %s", issuer);

        free(subject);
        free(issuer);

        char *cn = __apn_cert_subject_value_by_nib(cert, __APN_X509_ENTRY_CN);
        X509_free(cert);
        if(cn) {
            uint8_t invalid_cert = 0;
            if(apn_mode(ctx) == APN_MODE_PRODUCTION && 0 != strncmp("Apple Production", cn, 16)) {
                invalid_cert = 1;
                apn_log(ctx, APN_LOG_LEVEL_ERROR, "Invalid certificate. You are using a PRODUCTION mode, but certificate was created for usage in SANDBOX");
            } else if (apn_mode(ctx) == APN_MODE_SANDBOX && 0 != strncmp("Apple Development", cn, 17)) {
                invalid_cert = 1;
                apn_log(ctx, APN_LOG_LEVEL_ERROR, "Invalid certificate. You are using a SANDBOX mode, but certificate was created for usage in PRODUCTION");
            }
            free(cn);
            if(1 == invalid_cert) {
                SSL_CTX_free(ssl_ctx);
                errno = APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE;
                return APN_ERROR;
            }
        }
    }

    ctx->ssl = SSL_new(ssl_ctx);
    SSL_CTX_free(ssl_ctx);

    if (!ctx->ssl) {
        apn_log(ctx, APN_LOG_LEVEL_ERROR, "Could not initialize SSL");
        errno = APN_ERR_UNABLE_TO_ESTABLISH_SSL_CONNECTION;
        return APN_ERROR;
    }

    int ret = 0;

    if (-1 == (ret = SSL_set_fd(ctx->ssl, ctx->sock))) {
        apn_log(ctx, APN_LOG_LEVEL_ERROR, "Unable to attach socket to SSL: SSL_set_fd() failed (%d)",
                  SSL_get_error(ctx->ssl, ret));
        errno = APN_ERR_UNABLE_TO_ESTABLISH_SSL_CONNECTION;
        return APN_ERROR;
    }

    if (1 > (ret = SSL_connect(ctx->ssl))) {
        char *error = apn_error_string(errno);
        apn_log(ctx, APN_LOG_LEVEL_ERROR,
                  "Could not initialize SSL connection: SSL_connect() failed: %s, %s (errno: %d):",
                  ERR_error_string((unsigned long) SSL_get_error(ctx->ssl, ret), NULL), error, errno);
        free(error);
        return APN_ERROR;
    }
    apn_log(ctx, APN_LOG_LEVEL_INFO, "SSL connection has been established");

    X509 *remote_cert = SSL_get_peer_certificate(ctx->ssl);
    if (remote_cert) {
        char *subject = __apn_cert_subject_string(remote_cert);
        apn_log(ctx, APN_LOG_LEVEL_INFO, "Remote certificate subject: %s", subject);

        char *issuer = __apn_cert_issuer_string(remote_cert);
        apn_log(ctx, APN_LOG_LEVEL_INFO, "Remote certificate issuer: %s", issuer);

        free(subject);
        free(issuer);
        X509_free(remote_cert);
    }
    return APN_SUCCESS;
}
Exemplo n.º 23
0
int
main(int argc, char *argv[])
{
    struct hostent *server_host;
    char *server_host_str = "localhost";
    char *certificate_file = NULL;
    char *key_file = NULL;
    char *password_file = NULL;
    char *token_file = NULL;
    char *username = "******";
    int port = 64738;
    int ret;
    int development_mode = 0;

    int socket_fd;
    struct sockaddr_in server_addr;

    SSLRead socket_watcher;
    ev_io user_thread_watcher;
    ev_timer ping_watcher;
    ev_signal signal_watcher;
    ev_loop_main = EV_DEFAULT;

    /*
     * Lua initialization
     */
    lua = luaL_newstate();
    if (lua == NULL) {
        fprintf(stderr, "%s: could not initialize Lua\n", PIEPAN_NAME);
        return 1;
    }
    luaL_openlibs(lua);
    if (luaL_loadbuffer(lua, (const char *)src_piepan_impl_luac,
            src_piepan_impl_luac_len, "piepan_impl") != LUA_OK) {
        fprintf(stderr, "%s: could not load piepan implementation\n", PIEPAN_NAME);
        return 1;
    }
    lua_call(lua, 0, 0);

    lua_getglobal(lua, "piepan");
    lua_getfield(lua, -1, "internal");
    lua_getfield(lua, -1, "api");
    lua_pushcfunction(lua, api_init);
    lua_setfield(lua, -2, "apiInit");
    lua_settop(lua, 0);

    /*
     * Argument parsing
     */
    {
        int opt;
        int i;
        int show_help = 0;
        int show_version = 0;
        lua_getglobal(lua, "piepan");
        lua_getfield(lua, -1, "internal");
        lua_getfield(lua, -1, "events");
        lua_getfield(lua, -1, "onArgument");
        opterr = 0;
        while ((opt = getopt(argc, argv, "u:c:k:s:t:p:-:dhv")) != -1) {
            switch (opt) {
                case 'u':
                    username = optarg;
                    break;
                case 'c':
                    certificate_file = optarg;
                    if (key_file == NULL) {
                        key_file = certificate_file;
                    }
                    break;
                case 'k':
                    key_file = optarg;
                    break;
                case 's': {
                    char *port_str;
                    server_host_str = optarg;
                    port_str = strrchr(server_host_str, ':');
                    if (port_str != NULL) {
                        *port_str = '\0';
                        port = atoi(++port_str);
                    }
                    break;
                }
                case 't':
                    token_file = optarg;
                    break;
                case 'p':
                    password_file = optarg;
                    break;
                case '-': {
                    char *key = optarg;
                    char *value = strchr(key, '=');
                    if (key == value) {
                        break;
                    }
                    if (value != NULL) {
                        *value++ = 0;
                    }
                    lua_pushvalue(lua, -1);
                    lua_pushstring(lua, key);
                    lua_pushstring(lua, value);
                    lua_call(lua, 2, 0);
                    break;
                }
                case 'd':
                    development_mode = 1;
                    break;
                case 'h':
                    usage(stdout);
                    return 0;
                case 'v':
                    printf("%s %s (compiled on " __DATE__ " " __TIME__ ")\n",
                           PIEPAN_NAME, PIEPAN_VERSION);
                    return 0;
                default:
                    fprintf(stderr, "%s: unknown or incomplete option '%c'\n",
                            PIEPAN_NAME, optopt);
                    return 1;
            }
        }
        lua_settop(lua, 0);
    }

    /*
     * Load user scripts
     */
    {
        int i;
        lua_getglobal(lua, "piepan");
        lua_getfield(lua, -1, "internal");
        lua_getfield(lua, -1, "events");
        lua_getfield(lua, -1, "onLoadScript");
        for (i = optind; i < argc; i++) {
            lua_pushvalue(lua, -1);
            lua_pushstring(lua, argv[i]);
            if (development_mode) {
                lua_newuserdata(lua, sizeof(ScriptStat));
            } else {
                lua_pushnil(lua);
            }
            lua_call(lua, 2, 3);
            if (lua_toboolean(lua, -3)) {
                if (development_mode) {
                    ScriptStat *item = lua_touserdata(lua, -1);
                    item->lua = lua;
                    item->id = lua_tointeger(lua, -2);
                    item->filename = argv[i];
                    ev_stat_init(&item->ev, script_stat_event, item->filename, 0);
                    ev_stat_start(ev_loop_main, &item->ev);
                }
            } else {
                fprintf(stderr, "%s: %s\n", PIEPAN_NAME, lua_tostring(lua, -2));
            }
            lua_pop(lua, 3);
        }
        lua_settop(lua, 0);
    }

    /*
     * Initialize Opus
     */
    {
        OpusEncoder *encoder;
        int error;

        lua_getglobal(lua, "piepan");
        lua_getfield(lua, -1, "internal");
        lua_getfield(lua, -1, "opus");
        encoder = lua_newuserdata(lua, opus_encoder_get_size(1));
        lua_setfield(lua, -2, "encoder");

        error = opus_encoder_init(encoder, 48000, 1, OPUS_APPLICATION_AUDIO);
        if (error != OPUS_OK) {
            fprintf(stderr, "%s: could not initialize the Opus encoder: %s\n",
                    PIEPAN_NAME, opus_strerror(error));
            return 1;
        }
        opus_encoder_ctl(encoder, OPUS_SET_VBR(0));
        /* TODO: set this to the server's max bitrate */
        opus_encoder_ctl(encoder, OPUS_SET_BITRATE(40000));

        lua_settop(lua, 0);
    }

    /*
     * SSL initialization
     */
    SSL_library_init();

    ssl_context = SSL_CTX_new(SSLv23_client_method());
    if (ssl_context == NULL) {
        fprintf(stderr, "%s: could not create SSL context\n", PIEPAN_NAME);
        return 1;
    }

    if (certificate_file != NULL) {
        if (!SSL_CTX_use_certificate_chain_file(ssl_context, certificate_file) ||
                !SSL_CTX_use_PrivateKey_file(ssl_context, key_file,
                                                SSL_FILETYPE_PEM) ||
                !SSL_CTX_check_private_key(ssl_context)) {
            fprintf(stderr, "%s: could not load certificate and/or key file\n",
                    PIEPAN_NAME);
            return 1;
        }
    }

    /*
     * Socket initialization and connection
     */
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0) {
        fprintf(stderr, "%s: could not create socket\n", PIEPAN_NAME);
        return 1;
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);

    server_host = gethostbyname(server_host_str);
    if (server_host == NULL || server_host->h_addr_list[0] == NULL ||
            server_host->h_addrtype != AF_INET) {
        fprintf(stderr, "%s: could not parse server address\n", PIEPAN_NAME);
        return 1;
    }
    memmove(&server_addr.sin_addr, server_host->h_addr_list[0],
            server_host->h_length);

    ret = connect(socket_fd, (struct sockaddr *) &server_addr,
                  sizeof(server_addr));
    if (ret != 0) {
        fprintf(stderr, "%s: could not connect to server\n", PIEPAN_NAME);
        return 1;
    }

    ssl = SSL_new(ssl_context);
    if (ssl == NULL) {
        fprintf(stderr, "%s: could not create SSL object\n", PIEPAN_NAME);
        return 1;
    }

    if (SSL_set_fd(ssl, socket_fd) == 0) {
        fprintf(stderr, "%s: could not set SSL file descriptor\n", PIEPAN_NAME);
        return 1;
    }

    if (SSL_connect(ssl) != 1) {
        fprintf(stderr, "%s: could not create secure connection\n", PIEPAN_NAME);
        return 1;
    }

    /*
     * User thread pipe
     */
    if (pipe(user_thread_pipe) != 0) {
        fprintf(stderr, "%s: could not create user thread pipe\n", PIEPAN_NAME);
        return 1;
    }

    /*
     * Trigger initial event
     */
    lua_getglobal(lua, "piepan");
    lua_getfield(lua, -1, "internal");
    lua_getfield(lua, -1, "initialize");
    lua_newtable(lua);
    lua_pushstring(lua, username);
    lua_setfield(lua, -2, "username");
    if (password_file != NULL) {
        lua_pushstring(lua, password_file);
        lua_setfield(lua, -2, "passwordFile");
    }
    if (token_file != NULL) {
        lua_pushstring(lua, token_file);
        lua_setfield(lua, -2, "tokenFile");
    }
    lua_pushlightuserdata(lua, lua);
    lua_setfield(lua, -2, "state");
    lua_call(lua, 1, 0);
    lua_settop(lua, 0);

    /*
     * Event loop
     */
    ev_signal_init(&signal_watcher, signal_event, SIGINT);
    ev_signal_start(ev_loop_main, &signal_watcher);

    ev_io_init(&socket_watcher.ev, socket_read_event, socket_fd, EV_READ);
    socket_watcher.lua = lua;
    socket_watcher.ssl = ssl;
    ev_io_start(ev_loop_main, &socket_watcher.ev);

    ev_io_init(&user_thread_watcher, user_thread_event, user_thread_pipe[0],
               EV_READ);
    ev_io_start(ev_loop_main, &user_thread_watcher);

    ev_timer_init(&ping_watcher, ping_event, PING_TIMEOUT, PING_TIMEOUT);
    ev_timer_start(ev_loop_main, &ping_watcher);

    ev_run(ev_loop_main, 0);

    /*
     * Cleanup
     */
    lua_getglobal(lua, "piepan");
    lua_getfield(lua, -1, "internal");
    lua_getfield(lua, -1, "events");
    lua_getfield(lua, -1, "onDisconnect");
    if (lua_isfunction(lua, -1)) {
        lua_newtable(lua);
        lua_call(lua, 1, 0);
    }

    SSL_shutdown(ssl); /* TODO:  sigpipe is triggered here if connection breaks */
    close(socket_fd);
    lua_close(lua);

    return 0;
}
Exemplo n.º 24
0
int main(int argc, char **argv)
{
	int rc = 0;
	SSL_METHOD *meth = NULL;
	SSL * ssl = NULL;
	SSL_CTX * ctx = NULL;
	X509 *server_cert = NULL;
	long res;
	char *srv;
	int sd, ferr;
	unsigned long addr;
	struct sockaddr_in saddr;
	unsigned short port = 4422;
	int lcipher;
	struct string_list arglist;
	char *dir, *name;
	char path[PATH_MAX+1];

	if ( argc < 3 )
		usage(basename(argv[0]), 1);
	if (parse_cmd_line(argc, argv))
		usage(basename(argv[0]), 1);

	if (argc <= optind+1)
		usage(basename(argv[0]), 1);
	srv = argv[optind];
	strncpy(path, argv[optind+1], sizeof(path));
	name = basename(path);
	dir = dirname(path);

	if ((addr = inet_addr(srv)) == INADDR_NONE) {
		/* need to resolve address */
		struct hostent *host;
		if ((host = gethostbyname(srv)) == NULL) {
			fprintf(stderr, "gethostbyname(%s) err : %m\n", srv);
			return 1;
		}
		memcpy(&addr, host->h_addr, sizeof(addr));
	}

	if (crtfile == NULL)
		crtfile = strdup("certificate.pem");
	if (keyfile == NULL)
		keyfile = strdup("private.key");
	if (ciphers == NULL)
		lcipher = 0;
	else if (strcasecmp(ciphers, "none") == 0)
		lcipher = 0;
	else
		lcipher = 1;

	string_list_init(&arglist);
	string_list_add(&arglist, "tar");
	string_list_add(&arglist, "-c");
	string_list_add(&arglist, "-S");
	string_list_add(&arglist, "--ignore-failed-read");
	string_list_add(&arglist, "-f");
	string_list_add(&arglist, "-");
	string_list_add(&arglist, "-C");
	string_list_add(&arglist, dir);
	string_list_add(&arglist, name);

	/* Set up the library */
	SSL_library_init();
	SSL_load_error_strings();

	/* Create SSL context (framework) */
	meth = SSLv23_client_method();
	if ((ctx = SSL_CTX_new(meth)) == NULL) {
		fprintf(stderr, "SSL_CTX_new() : %m\n");
		ERR_print_errors_fp(stderr);
		rc = 1;
		goto cleanup_0;
	}

	/* load certificat from file */
	if(SSL_CTX_use_certificate_file(ctx, crtfile, SSL_FILETYPE_PEM) < 1) {
		ERR_print_errors_fp(stderr);
		rc = 1;
		goto cleanup_1;
	}
	if(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM) < 1) {
		ERR_print_errors_fp(stdout);
		rc = 1;
		goto cleanup_1;
	}
	if (lcipher) {
		/* load available cipher list */
		if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
			fprintf(stderr, "Error loading cipher list\n");
			ERR_print_errors_fp(stderr);
			rc = 1;
			goto cleanup_1;
		}
	}
	SSL_CTX_set_verify(ctx,
		SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);

	/* ----------------------------------------------- */
	/* Create a socket and connect to server using normal socket calls. */
	if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
		fprintf(stderr, "socket() err : %m\n");
		rc = 1;
		goto cleanup_1;
	}

	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = addr;
	saddr.sin_port = htons(port);

	if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr))) {
		// if (errno != EINPROGRESS) - for NONBLOCK
		fprintf(stderr, "connect() : %m\n");
		rc = 1;
		goto cleanup_1;
	}
	/* ----------------------------------------------- */
	/* Now we have TCP connection. Start SSL negotiation. */

	/* Create SSL obj */
	if ((ssl = SSL_new(ctx)) == NULL) {
		fprintf(stderr, "Error creating SSL object\n");
		ERR_print_errors_fp(stderr);
		rc = 1;
		goto cleanup_1;
	}

	SSL_set_fd(ssl, sd);
	SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

	/* try to connect */
	if(SSL_connect(ssl) <= 0) {
		fprintf(stderr, "Error attempting to connect\n");
		/* TODO SSL_get_error() */
		ERR_print_errors_fp(stderr);
		rc = 1;
		goto cleanup_2;
	}

	/* Get server's certificate. Note: dynamic allocation */
	if ((server_cert = SSL_get_peer_certificate(ssl)) == NULL) {
		fprintf(stderr, "Can't get peer certificate\n");
		ERR_print_errors_fp(stderr);
		rc = 1;
		goto cleanup_2;
	}

	X509_free(server_cert);

	/* verify the certificate
	From SSL_get_verify_result() man page:
	If no peer certificate was presented, the returned result code is
	X509_V_OK. This is because no verification error occurred, it does how-
	ever not indicate success. SSL_get_verify_result() is only useful in
	connection with SSL_get_peer_certificate(3).
	*/
	res = SSL_get_verify_result(ssl);
	/* will use expired certificate for test */
	if (	(res != X509_V_OK) &&
		(res != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) &&
		(res != X509_V_ERR_CERT_HAS_EXPIRED)) {
		fprintf(stderr, "Certificate verification error: %ld\n", res);
		fprintf(stderr, "See verify man page for more info\n");
		ERR_print_errors_fp(stderr);
		rc = 1;
		goto cleanup_2;
	}
	printf("Server certificate verified\n");

	ferr = dup(STDERR_FILENO);
	if (lcipher)
		;
	else {
		rc = run_rw(sd, sd, ferr, &arglist);
	}
	close(ferr);
	printf("rc = %d\n", rc);

	SSL_shutdown(ssl);

	/* Close the connection and free the context */
cleanup_2:
	if (ssl)
		SSL_free(ssl);

cleanup_1:
	if (ctx)
		SSL_CTX_free(ctx);

cleanup_0:
	string_list_clean(&arglist);

	return rc;
}
Exemplo n.º 25
0
int rehash_ssl(void)
{
    DH *dh_tmp = NULL;

    if(ircdssl_ctx)
    {
	SSL_CTX_free(ircdssl_ctx);
    }

    if(!(ircdssl_ctx = SSL_CTX_new(SSLv23_server_method())))
    {
	disable_ssl(1);
	return 0;
    }

    /* Kill SSLv2 support */
    SSL_CTX_set_options(ircdssl_ctx, SSL_OP_NO_SSLv2);

    if (SSL_CTX_use_certificate_file(ircdssl_ctx,
		IRCDSSL_CPATH, SSL_FILETYPE_PEM) <= 0)
    {
	disable_ssl(1);

	return 0;
    }

    if (SSL_CTX_use_PrivateKey_file(ircdssl_ctx,
		IRCDSSL_KPATH, SSL_FILETYPE_PEM) <= 0)
    {
	disable_ssl(1);

	return 0;
    }

    if (!SSL_CTX_check_private_key(ircdssl_ctx)) 
    {
	sendto_realops("SSL ERROR: Server certificate does not match server key");
	disable_ssl(0);

	return 0;
    }

    if (!SSL_CTX_set_cipher_list(ircdssl_ctx, IRCD_CIPHER_LIST))
    {
	disable_ssl(1);
	return 0;
    }

    if ((dh_tmp = get_dh1024()) == NULL)
    {
	disable_ssl(1);
	return 0;
    }

    if (!SSL_CTX_set_tmp_dh(ircdssl_ctx, dh_tmp))
    {
	disable_ssl(1);
	DH_free(dh_tmp);
	return 0;
    }
    DH_free(dh_tmp);

    return 1;
}
Exemplo n.º 26
0
/**
 * Initializes a ssl connection for server use.
 * @param pemfilename Filename for the key/cert file
 * @return An ssl connection, or NULL if an error occured.
 */
ssl_server_connection *init_ssl_server(char *pemfile, char *clientpemfile) {
        SSL_METHOD *server_method = NULL;
        ssl_server_connection *ssl_server;
        
        ASSERT(pemfile);
        
        if (!ssl_initialized)
                start_ssl();
        
        ssl_server = new_ssl_server_connection(pemfile, clientpemfile);
#ifdef OPENSSL_FIPS
        if (FIPS_mode())
                server_method = TLSv1_server_method();
        else
#endif
                server_method = SSLv23_server_method();
        if (!(ssl_server->method = server_method)) {
                LogError("%s: Cannot initialize the SSL method -- %s\n", prog, SSLERROR);
                goto sslerror;
        }
        
        if (!(ssl_server->ctx = SSL_CTX_new(ssl_server->method))) {
                LogError("%s: Cannot initialize SSL server certificate handler -- %s\n", prog, SSLERROR);
                goto sslerror;
        }
        
        if (SSL_CTX_use_certificate_chain_file(ssl_server->ctx, pemfile) != 1) {
                LogError("%s: Cannot initialize SSL server certificate -- %s\n", prog, SSLERROR);
                goto sslerror;
        }
        
        if (SSL_CTX_use_PrivateKey_file(ssl_server->ctx, pemfile, SSL_FILETYPE_PEM) != 1) {
                LogError("%s: Cannot initialize SSL server private key -- %s\n", prog, SSLERROR);
                goto sslerror;
        }
        
        if (SSL_CTX_check_private_key(ssl_server->ctx) != 1) {
                LogError("%s: The private key doesn't match the certificate public key -- %s\n", prog, SSLERROR);
                goto sslerror;
        }
        
        /* Disable session cache */
        SSL_CTX_set_session_cache_mode(ssl_server->ctx, SSL_SESS_CACHE_OFF);
        
        /*
         * We need this to force transmission of client certs
         */
        if (!verify_init(ssl_server)) {
                LogError("%s: Verification engine was not properly initialized -- %s\n", prog, SSLERROR);
                goto sslerror;
        }
        
        if (ssl_server->clientpemfile) {
                STACK_OF(X509_NAME) *stack = SSL_CTX_get_client_CA_list(ssl_server->ctx);
                LogInfo("%s: Found %d client certificates\n", prog, sk_X509_NAME_num(stack));
        }
        
        return ssl_server;
        
sslerror:
        delete_ssl_server_socket(ssl_server);
        return NULL;
}
Exemplo n.º 27
0
static int __ssl_setup(struct ast_tls_config *cfg, int client)
{
#ifndef DO_SSL
	cfg->enabled = 0;
	return 0;
#else
	int disable_ssl = 0;
	long ssl_opts = 0;

	if (!cfg->enabled) {
		return 0;
	}

	/* Get rid of an old SSL_CTX since we're about to
	 * allocate a new one
	 */
	if (cfg->ssl_ctx) {
		SSL_CTX_free(cfg->ssl_ctx);
		cfg->ssl_ctx = NULL;
	}

	if (client) {
#ifndef OPENSSL_NO_SSL2
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
			ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
			cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
		} else
#endif
		if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) {
			ast_log(LOG_WARNING, "Usage of SSLv3 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
			cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
		} else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
			cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
		} else {
			disable_ssl = 1;
			cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
		}
	} else {
		disable_ssl = 1;
		cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
	}

	if (!cfg->ssl_ctx) {
		ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
		cfg->enabled = 0;
		return 0;
	}

	/* Due to the POODLE vulnerability, completely disable
	 * SSLv2 and SSLv3 if we are not explicitly told to use
	 * them. SSLv23_*_method supports TLSv1+.
	 */
	if (disable_ssl) {
		ssl_opts |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
	}

	if (ast_test_flag(&cfg->flags, AST_SSL_SERVER_CIPHER_ORDER)) {
		ssl_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE;
	}

	if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV1)) {
		ssl_opts |= SSL_OP_NO_TLSv1;
	}
#if defined(HAVE_SSL_OP_NO_TLSV1_1) && defined(HAVE_SSL_OP_NO_TLSV1_2)
	if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV11)) {
		ssl_opts |= SSL_OP_NO_TLSv1_1;
	}
	if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV12)) {
		ssl_opts |= SSL_OP_NO_TLSv1_2;
	}
#else
	ast_log(LOG_WARNING, "Your version of OpenSSL leaves you potentially vulnerable "
			"to the SSL BEAST attack. Please upgrade to OpenSSL 1.0.1 or later\n");
#endif

	SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts);

	SSL_CTX_set_verify(cfg->ssl_ctx,
		ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE,
		NULL);

	if (!ast_strlen_zero(cfg->certfile)) {
		char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
		if (SSL_CTX_use_certificate_chain_file(cfg->ssl_ctx, cfg->certfile) == 0) {
			if (!client) {
				/* Clients don't need a certificate, but if its setup we can use it */
				ast_log(LOG_ERROR, "TLS/SSL error loading cert file. <%s>\n", cfg->certfile);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
		if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
			if (!client) {
				/* Clients don't need a private key, but if its setup we can use it */
				ast_log(LOG_ERROR, "TLS/SSL error loading private key file. <%s>\n", tmpprivate);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cipher)) {
		if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
			if (!client) {
				ast_log(LOG_ERROR, "TLS/SSL cipher error <%s>\n", cfg->cipher);
				cfg->enabled = 0;
				SSL_CTX_free(cfg->ssl_ctx);
				cfg->ssl_ctx = NULL;
				return 0;
			}
		}
	}
	if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
		if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) {
			ast_log(LOG_ERROR, "TLS/SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
		}
	}

#ifdef HAVE_OPENSSL_EC

	if (!ast_strlen_zero(cfg->pvtfile)) {
		BIO *bio = BIO_new_file(cfg->pvtfile, "r");
		if (bio != NULL) {
			DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
			if (dh != NULL) {
				if (SSL_CTX_set_tmp_dh(cfg->ssl_ctx, dh)) {
					long options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;
					options = SSL_CTX_set_options(cfg->ssl_ctx, options);
					ast_verb(2, "TLS/SSL DH initialized, PFS cipher-suites enabled\n");
				}
				DH_free(dh);
			}
			BIO_free(bio);
		}
	}
	#ifndef SSL_CTRL_SET_ECDH_AUTO
		#define SSL_CTRL_SET_ECDH_AUTO 94
	#endif
	/* SSL_CTX_set_ecdh_auto(cfg->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */
	if (SSL_CTX_ctrl(cfg->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) {
		ast_verb(2, "TLS/SSL ECDH initialized (automatic), faster PFS ciphers enabled\n");
	} else {
		/* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */
		EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
		if (ecdh != NULL) {
			if (SSL_CTX_set_tmp_ecdh(cfg->ssl_ctx, ecdh)) {
				ast_verb(2, "TLS/SSL ECDH initialized (secp256r1), faster PFS cipher-suites enabled\n");
			}
			EC_KEY_free(ecdh);
		}
	}

#endif /* #ifdef HAVE_OPENSSL_EC */

	ast_verb(2, "TLS/SSL certificate ok\n");	/* We should log which one that is ok. This message doesn't really make sense in production use */
	return 1;
#endif
}
Exemplo n.º 28
0
/**
 * Generate a new ssl connection
 * @return ssl connection container
 */
ssl_connection *new_ssl_connection(char *clientpemfile, int sslversion) {
        ssl_connection *ssl;
        
        if (!ssl_initialized)
                start_ssl();
        
        NEW(ssl);
        ssl->socket_bio = NULL; 
        ssl->handler = NULL;
        ssl->cert = NULL;
        ssl->cipher = NULL;
        ssl->socket = 0;
        ssl->next = NULL;
        ssl->accepted = FALSE;
        ssl->cert_md5 = NULL;
        ssl->cert_md5_len = 0;
        ssl->clientpemfile = clientpemfile ? Str_dup(clientpemfile) : NULL;
        
        switch (sslversion) {
                        
                case SSL_VERSION_AUTO:
#ifdef OPENSSL_FIPS
                        if (FIPS_mode()) {
                                ssl->method = TLSv1_client_method();
                        } else
#endif
                                ssl->method = SSLv23_client_method();
                        break;
                        
                case SSL_VERSION_SSLV2:
#ifdef OPENSSL_NO_SSL2
                        LogError("SSLv2 is not allowed - use either SSLv3 or TLSv1");
                        goto sslerror;
#else
#ifdef OPENSSL_FIPS
                        if (FIPS_mode()) {
                                LogError("SSLv2 is not allowed in FIPS mode - use TLSv1");
                                goto sslerror;
                        } else
#endif
                                ssl->method = SSLv2_client_method();
#endif
                        break;
                        
                case SSL_VERSION_SSLV3:
#ifdef OPENSSL_FIPS
                        if (FIPS_mode()) {
                                LogError("SSLv3 is not allowed in FIPS mode - use TLSv1");
                                goto sslerror;
                        } else
#endif
                                ssl->method = SSLv3_client_method();
                        break;
                        
                case SSL_VERSION_TLS:
                        /* fall through */
                default:
                        ssl->method = TLSv1_client_method();
                        break;
                        
        }
        
        if (!ssl->method) {
                LogError("%s: Cannot initialize SSL method -- %s\n", prog, SSLERROR);
                goto sslerror;
        } 
        
        if (!(ssl->ctx = SSL_CTX_new(ssl->method))) {
                LogError("%s: Cannot initialize SSL server certificate handler -- %s\n", prog, SSLERROR);
                goto sslerror;
        }
        
        if (ssl->clientpemfile) {
                
                if (SSL_CTX_use_certificate_chain_file(ssl->ctx, ssl->clientpemfile) <= 0) {
                        LogError("%s: Cannot initialize SSL server certificate -- %s\n", prog, SSLERROR);
                        goto sslerror;
                }
                
                if (SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->clientpemfile, SSL_FILETYPE_PEM) <= 0) {
                        LogError("%s: Cannot initialize SSL server private key -- %s\n", prog, SSLERROR);
                        goto sslerror;
                }
                
                if (!SSL_CTX_check_private_key(ssl->ctx)) {
                        LogError("%s: Private key does not match the certificate public key -- %s\n", prog, SSLERROR);
                        goto sslerror;
                }
                
        }
        
        return ssl;
        
sslerror:
        delete_ssl_socket(ssl);
        return NULL;
}
//创建监听套接字,该函数被network_init调用
int network_server_init(server *srv, buffer *host_token, specific_config *s) {
	int val;
	socklen_t addr_len;
	server_socket *srv_socket;
	char *sp;
	unsigned int port = 0;
	const char *host;
	buffer *b;

//判断是否为unix域套接字
	int is_unix_domain_socket = 0;

	int fd;

#ifdef SO_ACCEPTFILTER
	struct accept_filter_arg afa;
#endif

#ifdef __WIN32
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD( 2, 2 );

	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		    /* Tell the user that we could not find a usable */
		    /* WinSock DLL.                                  */
		    return -1;
	}
#endif
//为srv_socket分配内存空间并赋值
	srv_socket = calloc(1, sizeof(*srv_socket));
	srv_socket->fd = -1;
	srv_socket->srv_token = buffer_init();
	buffer_copy_string_buffer(srv_socket->srv_token, host_token);




/* ipv4:port
 * [ipv6]:port
 */
//分割IP与端口号
	b = buffer_init();
	buffer_copy_string_buffer(b, host_token);
	if (NULL == (sp = strrchr(b->ptr, ':'))) { 
		log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);

		return -1;
	}

//获取地址
	host = b->ptr;


//去除[ipv6]中的’[‘、’]‘号
	if (b->ptr[0] == '[' && *(sp-1) == ']') {
//去掉']'		
		*(sp-1) = '\0'; 
//去掉'['		
		host++;		
//该地址是ipv6
		srv_socket->use_ipv6 = 1;
	}


//去除‘:’号
	*(sp++) = '\0';


//获取port
	port = strtol(sp, NULL, 10); //字符转长整型数



//若其地址为’/‘开头的,则是unix域套接字的创建
	if (host[0] == '/') { 
	/*
		使用UNIX域协议,UNIX域协议关联一个以空字符结尾的路径名(此路径名必须是绝对路径名而不是一个相对路径名,所以字符串第一个字符应该为字符'/'),
		因此这里通过检测传递的地址字符串第一个字符是否为'/'字符来判断是否使用UNIX域协议。
		PS:UNIX域主要用来做同一域内的进程间通信,在处理一个进程和多个进程间通信执行类似于服务器/客户通信时,UNIX域是一种比较方便和快速的办法。
			它所使用的API与在不同的主机上执行服务器/客户所用的API(套接口API)完全相同,便于代码共享。UNIX域也提供了两类套接口:字节流套接口和数据
			报套接口。总的来说,在同一台主机上的多个进程之间通信,UNIX域有如下优点:(1)利用常规的SOCKET编写的TCP套接口
			快;(2)UNIX域套接口可以在不同进程之间传递描述字;(3)UNIX域套接口较新的实现把客户的凭证(用户ID和组ID)提供给服务器,从而能够
			提供额外的安全检查措施。
	*/
//该地址是路径名
		is_unix_domain_socket = 1;
	} 


//检查端口号是否正确
	else if (port == 0 || port > 65535) {
		log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);

		return -1;
	}

//地址为空
	if (*host == '\0') host = NULL;



//创建使用UNIX域协议的套接口
	if (is_unix_domain_socket) { 
#ifdef HAVE_SYS_UN_H

		srv_socket->addr.plain.sa_family = AF_UNIX;
		if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) { 
			return -1;
		}
#else
		log_error_write(srv, __FILE__, __LINE__, "s",
				"ERROR: Unix Domain sockets are not supported.");
		return -1;
#endif
	}





//创建使用IPv6协议的字节流套接口,使用TCP传输协议。
#ifdef HAVE_IPV6
	if (s->use_ipv6) { 
		srv_socket->addr.plain.sa_family = AF_INET6;

		if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
			return -1;
		}
		srv_socket->use_ipv6 = 1;
	}
#endif



//未创建使用IPv6协议的字节流套接口或创建失败的情况下则创建使用IPv4协议的字节流套接口,使用TCP传输协议。
	if (srv_socket->fd == -1) { 
		srv_socket->addr.plain.sa_family = AF_INET;
		if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
			return -1;
		}
	}




//记录最近使用的套接字 
	srv->cur_fds = srv_socket->fd;

	



//设置套接口选项,SO_REUSEADDR套接口选项的作用就是允许重用本地地址。
	val = 1;
	if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { 
		log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
		return -1;
	}




//创建套接字地址结构体
	switch(srv_socket->addr.plain.sa_family) {
#ifdef HAVE_IPV6
	case AF_INET6:
		memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in6));
		srv_socket->addr.ipv6.sin6_family = AF_INET6;
//未指定绑定地址则使用通配地址in6addr_any
		if (host == NULL) { 
			srv_socket->addr.ipv6.sin6_addr = in6addr_any;
		} 
//使用用户指定ip
		else {
			struct addrinfo hints, *res; 
			int r;

			memset(&hints, 0, sizeof(hints)); 

			hints.ai_family   = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;

			if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) { //函数getaddrinfo()是IPv6新引入的API,它是协议无关的,既可以用于IPv4也可以用于IPv6.该函数用于获得一个addrinfo结构体列表,该列表通过第四个参数隐性传出,调用执行成功返回0,否则返回非0值。
				log_error_write(srv, __FILE__, __LINE__,
						"sssss", "getaddrinfo failed: ",
						gai_strerror(r), "'", host, "'");

				return -1;
			}

			memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);

			freeaddrinfo(res); 
		}
//port赋值
		srv_socket->addr.ipv6.sin6_port = htons(port);
		addr_len = sizeof(struct sockaddr_in6);
		break;
#endif
//ipv4
	case AF_INET:
		memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in));
		srv_socket->addr.ipv4.sin_family = AF_INET;
		if (host == NULL) {
			srv_socket->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY); //将主机字节顺序的无符号长整型数转换成网络字节顺序格式
		} else {
			struct hostent *he; //hostent结构体定义在/usr/include/netdb.h内
			if (NULL == (he = gethostbyname(host))) { //函数gethostbyname()返回对应于给定主机名的包含主机名字和地址等信息的hostent结构指针。
				log_error_write(srv, __FILE__, __LINE__,
						"sds", "gethostbyname failed: ",
						h_errno, host);
				return -1;
			}

			if (he->h_addrtype != AF_INET) {
				log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
				return -1;
			}

			if (he->h_length != sizeof(struct in_addr)) {
				log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
				return -1;
			}

			memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
		}
		srv_socket->addr.ipv4.sin_port = htons(port);

		addr_len = sizeof(struct sockaddr_in);

		break;
//unix域套接字
	case AF_UNIX:
		srv_socket->addr.un.sun_family = AF_UNIX;
		strcpy(srv_socket->addr.un.sun_path, host);

#ifdef SUN_LEN
		addr_len = SUN_LEN(&srv_socket->addr.un); //SUN_LEN宏定义在/usr/include/sys/un.h SUN_lEN(ptr) ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
		//从定义内容可以看到,宏SUN_LEN 用于计算一个sockaddr_un结构体(通过ptr指针指向)的长度大小,这个长度并不是为该结构体分配的字节空间的长度,注意其中路径名sun_path字段仅计算其中的非空格字符在内。
#else
		/* stevens says: */
		addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family);
#endif

		/* check if the socket exists and try to connect to it. */
		if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) { //检测一下是否可以连接上,正常情况下这里当然是失败的(因为套接字的端口和IP尚未被绑定),但是如果连接上了则说明有其他进程或服务在使用本套接口,因此报错退出。
			close(fd);

			log_error_write(srv, __FILE__, __LINE__, "ss",
				"server socket is still in use:",
				host);


			return -1;
		}

		/* connect failed */
		switch(errno) {
		case ECONNREFUSED: //虽然被服务器端拒绝属于正常情况,但是当监听套接口队列已满是也会设置ECONNREFUSED错误码。
			unlink(host); //删除先前某次运行生成的或已经存在的路径名
			break;
		case ENOENT: //路径名不存在,属于我们想要的正常情况
			break;
		default: //其他错误属于异常,报错返回
			log_error_write(srv, __FILE__, __LINE__, "sds",
				"testing socket failed:",
				host, strerror(errno));

			return -1;
		}

		break;
	default:
		addr_len = 0;

		return -1;
	}






//使用bind邦定ip和port
	if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) { 
		switch(srv_socket->addr.plain.sa_family) {
		case AF_UNIX:
			log_error_write(srv, __FILE__, __LINE__, "sds",
					"can't bind to socket:",
					host, strerror(errno));
			break;
		default:
			log_error_write(srv, __FILE__, __LINE__, "ssds",
					"can't bind to port:",
					host, port, strerror(errno));
			break;
		}
		return -1;
	}





//使用listen函数使其套接字变成监听套接字
	if (-1 == listen(srv_socket->fd, 128 * 8)) { 
		log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
		return -1;
	}










	if (s->is_ssl) {  //这里是对SSL的处理
#ifdef USE_OPENSSL
		if (srv->ssl_is_init == 0) {
			SSL_load_error_strings();
			SSL_library_init();
			srv->ssl_is_init = 1;

			if (0 == RAND_status()) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						"not enough entropy in the pool");
				return -1;
			}
		}

		if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
					ERR_error_string(ERR_get_error(), NULL));
			return -1;
		}

		if (!s->ssl_use_sslv2) {
			/* disable SSLv2 */
			if (SSL_OP_NO_SSLv2 != SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2)) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						ERR_error_string(ERR_get_error(), NULL));
				return -1;
			}
		}

		if (!buffer_is_empty(s->ssl_cipher_list)) {
			/* Disable support for low encryption ciphers */
			if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
						ERR_error_string(ERR_get_error(), NULL));
				return -1;
			}
		}

		if (buffer_is_empty(s->ssl_pemfile)) {
			log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
			return -1;
		}

		if (!buffer_is_empty(s->ssl_ca_file)) {
			if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
				log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
						ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
				return -1;
			}
		}

		if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
			log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
					ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
			return -1;
		}

		if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
			log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
					ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
			return -1;
		}

		if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
			log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
					"Private key does not match the certificate public key, reason:",
					ERR_error_string(ERR_get_error(), NULL),
					s->ssl_pemfile);
			return -1;
		}
		SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1);
		SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

		srv_socket->ssl_ctx = s->ssl_ctx;
#else

		buffer_free(srv_socket->srv_token);
		free(srv_socket);

		buffer_free(b);

		log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
				"ssl requested but openssl support is not compiled in");

		return -1;
#endif
	} 
else {
#ifdef SO_ACCEPTFILTER
		/*
			SO_ACCEPTFILTER是FreeBSD支持的一个选项SOL_SOCKET,称为“接收过滤器”(accept filter),其主要用来推迟函数accept()调用的返回,即只有当HTTP状态发生改变时(如一个HTTP请求到达),
			进程才从函数accept()阻塞中返回,因此延缓了对该连接进行处理的子进程需求,这样做的好处就是对于一定数量的子进程能处理更多的链接。另外由于accept()调用返回就表示有请求到达,
			所以使得子进程能迅速地完成请求响应,减少上下文切换。
		*/
		/*
		 * FreeBSD accf_http filter
		 *
		 */
		memset(&afa, 0, sizeof(afa));
		strcpy(afa.af_name, "httpready");
		if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
			if (errno != ENOENT) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
			}
		}
#endif
	}

	srv_socket->is_ssl = s->is_ssl;

	srv_socket->fde_ndx = -1;



/*记录已经创建了的监听套接口*/
	if (srv->srv_sockets.size == 0) {
		srv->srv_sockets.size = 4;
		srv->srv_sockets.used = 0;
		srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket));
	} else if (srv->srv_sockets.used == srv->srv_sockets.size) {
		srv->srv_sockets.size += 4;
		srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
	}
	srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
	buffer_free(b);

	return 0;
}
Exemplo n.º 30
0
/* Return -1 on error, 0 or success. */
int
ssl_connect(struct socket *socket)
{
	int ret;
	unsigned char *server_name;
	struct connection *conn = (struct connection *)socket->conn;

	/* TODO: Recode server_name to UTF-8.  */
	server_name = get_uri_string(conn->proxied_uri, URI_HOST);
	if (!server_name) {
		socket->ops->done(socket, connection_state(S_OUT_OF_MEM));
		return -1;
	}

	/* RFC 3546 says literal IPv4 and IPv6 addresses are not allowed.  */
	if (is_ip_address(server_name, strlen((const char *)server_name)))
		mem_free_set(&server_name, NULL);

	if (init_ssl_connection(socket, server_name) == S_SSL_ERROR) {
		mem_free_if(server_name);
		socket->ops->done(socket, connection_state(S_SSL_ERROR));
		return -1;
	}

	mem_free_if(server_name);

	if (socket->no_tls)
		ssl_set_no_tls(socket);

#ifdef USE_OPENSSL
	SSL_set_fd((SSL *)socket->ssl, socket->fd);

	if (get_opt_bool((const unsigned char *)"connection.ssl.cert_verify", NULL))
		SSL_set_verify((SSL *)socket->ssl, SSL_VERIFY_PEER
					  | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
			       verify_callback);

	if (get_opt_bool((const unsigned char *)"connection.ssl.client_cert.enable", NULL)) {
		unsigned char *client_cert;

#ifdef CONFIG_NSS_COMPAT_OSSL
		client_cert = get_opt_str(
				(const unsigned char *)"connection.ssl.client_cert.nickname", NULL);
#else
		client_cert = get_opt_str(
				(const unsigned char *)"connection.ssl.client_cert.file", NULL);
#endif
		if (!*client_cert) {
			client_cert = (unsigned char *)getenv("X509_CLIENT_CERT");
			if (client_cert && !*client_cert)
				client_cert = NULL;
		}

		if (client_cert) {
#ifdef CONFIG_NSS_COMPAT_OSSL
			SSL_CTX_use_certificate_chain_file(
					(SSL *) socket->ssl,
					(const char *)client_cert);
#else
			SSL_CTX *ctx = ((SSL *) socket->ssl)->ctx;

			SSL_CTX_use_certificate_chain_file(ctx, (const char *)client_cert);
			SSL_CTX_use_PrivateKey_file(ctx, (const char *)client_cert,
						    SSL_FILETYPE_PEM);
#endif
		}
	}

#elif defined(CONFIG_GNUTLS)
	/* GnuTLS uses function pointers for network I/O.  The default
	 * functions take a file descriptor, but it must be passed in
	 * as a pointer.  GnuTLS uses the GNUTLS_INT_TO_POINTER and
	 * GNUTLS_POINTER_TO_INT macros for these conversions, but
	 * those are unfortunately not in any public header.  So
	 * ELinks must just cast the pointer the best it can and hope
	 * that the conversions match.  */
	gnutls_transport_set_ptr(*((ssl_t *) socket->ssl),
				 (gnutls_transport_ptr_t) (longptr_T) socket->fd);

	/* TODO: Some certificates fuss. --pasky */
#endif

	ret = ssl_do_connect(socket);

	switch (ret) {
		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_READ2:
			socket->ops->set_state(socket, connection_state(S_SSL_NEG));
			set_handlers(socket->fd, (select_handler_T) ssl_want_read,
				     NULL, (select_handler_T) dns_exception, socket);
			return -1;

		case SSL_ERROR_NONE:
#ifdef CONFIG_GNUTLS
			if (!get_opt_bool((const unsigned char *)"connection.ssl.cert_verify", NULL))
				break;

			if (!verify_certificates(socket))
#endif
				break;

		default:
			if (ret != SSL_ERROR_NONE) {
				/* DBG("sslerr %s", gnutls_strerror(ret)); */
				socket->no_tls = !socket->no_tls;
			}

			connect_socket(socket, connection_state(S_SSL_ERROR));
			return -1;
	}

	return 0;
}