Пример #1
0
int
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
#if ENABLE_INLINE_FILES
    const char *pkcs12_file_inline,
#endif /* ENABLE_INLINE_FILES */
    bool load_ca_file
    )
{
  FILE *fp;
  EVP_PKEY *pkey;
  X509 *cert;
  STACK_OF(X509) *ca = NULL;
  PKCS12 *p12;
  int i;
  char password[256];

  ASSERT(NULL != ctx);

#if ENABLE_INLINE_FILES
  if (!strcmp (pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline)
    {
      BIO *b64 = BIO_new(BIO_f_base64());
      BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline,
	  (int) strlen(pkcs12_file_inline));
      ASSERT(b64 && bio);
      BIO_push(b64, bio);
      p12 = d2i_PKCS12_bio(b64, NULL);
      if (!p12)
	msg(M_SSLERR, "Error reading inline PKCS#12 file");
      BIO_free(b64);
      BIO_free(bio);
    }
  else
#endif
    {
      /* Load the PKCS #12 file */
      if (!(fp = platform_fopen(pkcs12_file, "rb")))
	msg(M_SSLERR, "Error opening file %s", pkcs12_file);
      p12 = d2i_PKCS12_fp(fp, NULL);
      fclose(fp);
      if (!p12)
	msg(M_SSLERR, "Error reading PKCS#12 file %s", pkcs12_file);
    }

  /* Parse the PKCS #12 file */
  if (!PKCS12_parse(p12, "", &pkey, &cert, &ca))
   {
     pem_password_callback (password, sizeof(password) - 1, 0, NULL);
     /* Reparse the PKCS #12 file with password */
     ca = NULL;
     if (!PKCS12_parse(p12, password, &pkey, &cert, &ca))
      {
#ifdef ENABLE_MANAGEMENT
	      if (management && (ERR_GET_REASON (ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE))
		management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
#endif
	PKCS12_free(p12);
	return 1;
      }
   }
  PKCS12_free(p12);

  /* Load Certificate */
  if (!SSL_CTX_use_certificate (ctx->ctx, cert))
   msg (M_SSLERR, "Cannot use certificate");

  /* Load Private Key */
  if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey))
   msg (M_SSLERR, "Cannot use private key");
  warn_if_group_others_accessible (pkcs12_file);

  /* Check Private Key */
  if (!SSL_CTX_check_private_key (ctx->ctx))
   msg (M_SSLERR, "Private key does not match the certificate");

  /* Set Certificate Verification chain */
  if (load_ca_file)
   {
     if (ca && sk_X509_num(ca))
      {
	for (i = 0; i < sk_X509_num(ca); i++)
	  {
	      if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
	      msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)");
	    if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i)))
	      msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)");
	  }
      }
   }
  return 0;
}
Пример #2
0
void
SecureSocket::checkResult(int status, int& retry)
{
	// ssl errors are a little quirky. the "want" errors are normal and
	// should result in a retry.

	int errorCode = SSL_get_error(m_ssl->m_ssl, status);

	switch (errorCode) {
	case SSL_ERROR_NONE:
		retry = 0;
		// operation completed
		break;

	case SSL_ERROR_ZERO_RETURN:
		// connection closed
		isFatal(true);
		LOG((CLOG_DEBUG "ssl connection closed"));
		break;

	case SSL_ERROR_WANT_READ:
		retry++;
		LOG((CLOG_DEBUG2 "want to read, error=%d, attempt=%d", errorCode, retry));
		break;

	case SSL_ERROR_WANT_WRITE:
		// Need to make sure the socket is known to be writable so the impending
		// select action actually triggers on a write. This isn't necessary for 
		// m_readable because the socket logic is always readable
		m_writable = true;
		retry++;
		LOG((CLOG_DEBUG2 "want to write, error=%d, attempt=%d", errorCode, retry));
		break;

	case SSL_ERROR_WANT_CONNECT:
		retry++;
		LOG((CLOG_DEBUG2 "want to connect, error=%d, attempt=%d", errorCode, retry));
		break;

	case SSL_ERROR_WANT_ACCEPT:
		retry++;
		LOG((CLOG_DEBUG2 "want to accept, error=%d, attempt=%d", errorCode, retry));
		break;

	case SSL_ERROR_SYSCALL:
		LOG((CLOG_ERR "ssl error occurred (system call failure)"));
		if (ERR_peek_error() == 0) {
			if (status == 0) {
				LOG((CLOG_ERR "eof violates ssl protocol"));
			}
			else if (status == -1) {
				// underlying socket I/O reproted an error
				try {
					ARCH->throwErrorOnSocket(getSocket());
				}
				catch (XArchNetwork& e) {
					LOG((CLOG_ERR "%s", e.what()));
				}
			}
		}

		isFatal(true);
		break;

	case SSL_ERROR_SSL:
		LOG((CLOG_ERR "ssl error occurred (generic failure)"));
		isFatal(true);
		break;

	default:
		LOG((CLOG_ERR "ssl error occurred (unknown failure)"));
		isFatal(true);
		break;
	}

	if (isFatal()) {
		retry = 0;
		showError();
		disconnect();
	}
}
Пример #3
0
static void loadSSL(void) {
  // SHELLINABOX_LIBSSL_SO can be used to select the specific
  // soname of libssl for systems where it is not libssl.so.
  // The feature is currently disabled.
  const char* path_libssl = NULL; // = getenv ("SHELLINABOX_LIBSSL_SO");
  if (path_libssl == NULL)
    path_libssl = "libssl.so";
  check(!SSL_library_init);
  struct {
    union {
      void *avoid_gcc_warning_about_type_punning;
      void **var;
    };
    const char *fn;
  } symbols[] = {
    { { &BIO_ctrl },                    "BIO_ctrl" },
    { { &BIO_f_buffer },                "BIO_f_buffer" },
    { { &BIO_free_all },                "BIO_free_all" },
    { { &BIO_new },                     "BIO_new" },
    { { &BIO_new_socket },              "BIO_new_socket" },
    { { &BIO_pop },                     "BIO_pop" },
    { { &BIO_push },                    "BIO_push" },
    { { &ERR_clear_error },             "ERR_clear_error" },
    { { &ERR_clear_error },             "ERR_clear_error" },
    { { &ERR_peek_error },              "ERR_peek_error" },
    { { &ERR_peek_error },              "ERR_peek_error" },
    { { &SSL_CTX_callback_ctrl },       "SSL_CTX_callback_ctrl" },
    { { &SSL_CTX_check_private_key },   "SSL_CTX_check_private_key" },
    { { &SSL_CTX_ctrl },                "SSL_CTX_ctrl" },
    { { &SSL_CTX_free },                "SSL_CTX_free" },
    { { &SSL_CTX_new },                 "SSL_CTX_new" },
    { { &SSL_CTX_use_PrivateKey_file }, "SSL_CTX_use_PrivateKey_file" },
    { { &SSL_CTX_use_PrivateKey_ASN1 }, "SSL_CTX_use_PrivateKey_ASN1" },
    { { &SSL_CTX_use_certificate_file },"SSL_CTX_use_certificate_file"},
    { { &SSL_CTX_use_certificate_ASN1 },"SSL_CTX_use_certificate_ASN1"},
    { { &SSL_ctrl },                    "SSL_ctrl" },
    { { &SSL_free },                    "SSL_free" },
    { { &SSL_get_error },               "SSL_get_error" },
    { { &SSL_get_ex_data },             "SSL_get_ex_data" },
    { { &SSL_get_rbio },                "SSL_get_rbio" },
#ifdef HAVE_TLSEXT
    { { &SSL_get_servername },          "SSL_get_servername" },
#endif
    { { &SSL_get_wbio },                "SSL_get_wbio" },
    { { &SSL_library_init },            "SSL_library_init" },
    { { &SSL_new },                     "SSL_new" },
    { { &SSL_read },                    "SSL_read" },
#ifdef HAVE_TLSEXT
    { { &SSL_set_SSL_CTX },             "SSL_set_SSL_CTX" },
#endif
    { { &SSL_set_accept_state },        "SSL_set_accept_state" },
    { { &SSL_set_bio },                 "SSL_set_bio" },
    { { &SSL_set_ex_data },             "SSL_set_ex_data" },
    { { &SSL_shutdown },                "SSL_shutdown" },
    { { &SSL_write },                   "SSL_write" },
    { { &SSLv23_server_method },        "SSLv23_server_method" },
    { { &d2i_X509 },                    "d2i_X509" },
    { { &X509_free },                   "X509_free" },
    { { &x_SSL_CTX_set_cipher_list },   "SSL_CTX_set_cipher_list" },
    { { &x_sk_zero },                   "sk_zero" }
  };
  for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
    if (!(*symbols[i].var = loadSymbol(path_libssl, symbols[i].fn))) {
      debug("Failed to load SSL support. Could not find \"%s\"",
            symbols[i].fn);
      for (unsigned j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) {
        *symbols[j].var = NULL;
      }
      return;
    }
  }
  // These are optional
  x_SSL_COMP_get_compression_methods = loadSymbol(path_libssl, "SSL_COMP_get_compression_methods");
  // ends

  SSL_library_init();
  dcheck(!ERR_peek_error());
  debug("Loaded SSL suppport");
}
Пример #4
0
/**
 * Read a file that contains our certificate in "PEM" format,
 * possibly followed by a sequence of CA certificates that should be
 * sent to the peer in the Certificate message.
 *
 * Taken from OpenSSL & Node.js - editted for style.
 */
static int
SSL_CTX_use_certificate_chain(SSL_CTX *ctx, BIO *in) {
  int ret = 0;
  X509 *x = NULL;

  x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);

  if (x == NULL) {
    SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
    goto end;
  }

  ret = SSL_CTX_use_certificate(ctx, x);

  if (ERR_peek_error() != 0) {
    /* Key/certificate mismatch doesn't imply ret==0 ... */
    ret = 0;
  }

  if (ret) {
    /* If we could set up our certificate, now proceed to the CA certificates. */
    X509 *ca;
    int r;
    unsigned long err;

    if (ctx->extra_certs != NULL) {
      sk_X509_pop_free(ctx->extra_certs, X509_free);
      ctx->extra_certs = NULL;
    }

    while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
      r = SSL_CTX_add_extra_chain_cert(ctx, ca);

      if (!r) {
        X509_free(ca);
        ret = 0;
        goto end;
      }
      /* Note that we must not free r if it was successfully
       * added to the chain (while we must free the main
       * certificate, since its reference count is increased
       * by SSL_CTX_use_certificate). */
    }

    /* When the while loop ends, it's usually just EOF. */
    err = ERR_peek_last_error();
    if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
        ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
      ERR_clear_error();
    } else  {
      /* some real error */
      ret = 0;
    }
  }

end:
  if (x != NULL) {
    X509_free(x);
  }
  return ret;
}
Пример #5
0
 /*
  * This is the actual startup routine for the connection. We expect that the
  * buffers are flushed and the "220 Ready to start TLS" was received by us,
  * so that we can immediately start the TLS handshake process.
  */
TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
{
    int     sts;
    int     protomask;
    const char *cipher_list;
    SSL_SESSION *session = 0;
    SSL_CIPHER_const SSL_CIPHER *cipher;
    X509   *peercert;
    TLS_SESS_STATE *TLScontext;
    TLS_APPL_STATE *app_ctx = props->ctx;
    char   *myserverid;
    int     log_mask = app_ctx->log_mask;

    /*
     * When certificate verification is required, log trust chain validation
     * errors even when disabled by default for opportunistic sessions. For
     * DANE this only applies when using trust-anchor associations.
     */
    if (TLS_MUST_TRUST(props->tls_level)
      && (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane)))
	log_mask |= TLS_LOG_UNTRUSTED;

    if (log_mask & TLS_LOG_VERBOSE)
	msg_info("setting up TLS connection to %s", props->namaddr);

    /*
     * First make sure we have valid protocol and cipher parameters
     * 
     * Per-session protocol restrictions must be applied to the SSL connection,
     * as restrictions in the global context cannot be cleared.
     */
    protomask = tls_protocol_mask(props->protocols);
    if (protomask == TLS_PROTOCOL_INVALID) {
	/* tls_protocol_mask() logs no warning. */
	msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session",
		 props->namaddr, props->protocols);
	return (0);
    }
    /* DANE requires SSLv3 or later, not SSLv2. */
    if (TLS_DANE_BASED(props->tls_level))
	protomask |= TLS_PROTOCOL_SSLv2;

    /*
     * Per session cipher selection for sessions with mandatory encryption
     * 
     * The cipherlist is applied to the global SSL context, since it is likely
     * to stay the same between connections, so we make use of a 1-element
     * cache to return the same result for identical inputs.
     */
    cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade,
				  props->cipher_exclusions);
    if (cipher_list == 0) {
	msg_warn("%s: %s: aborting TLS session",
		 props->namaddr, vstring_str(app_ctx->why));
	return (0);
    }
    if (log_mask & TLS_LOG_VERBOSE)
	msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list);

    /*
     * OpenSSL will ignore cached sessions that use the wrong protocol. So we
     * do not need to filter out cached sessions with the "wrong" protocol,
     * rather OpenSSL will simply negotiate a new session.
     * 
     * We salt the session lookup key with the protocol list, so that sessions
     * found in the cache are plausibly acceptable.
     * 
     * By the time a TLS client is negotiating ciphers it has already offered to
     * re-use a session, it is too late to renege on the offer. So we must
     * not attempt to re-use sessions whose ciphers are too weak. We salt the
     * session lookup key with the cipher list, so that sessions found in the
     * cache are always acceptable.
     * 
     * With DANE, (more generally any TLScontext where we specified explicit
     * trust-anchor or end-entity certificates) the verification status of
     * the SSL session depends on the specified list.  Since we verify the
     * certificate only during the initial handshake, we must segregate
     * sessions with different TA lists.  Note, that TA re-verification is
     * not possible with cached sessions, since these don't hold the complete
     * peer trust chain.  Therefore, we compute a digest of the sorted TA
     * parameters and append it to the serverid.
     */
    myserverid = tls_serverid_digest(props, protomask, cipher_list);

    /*
     * Allocate a new TLScontext for the new connection and get an SSL
     * structure. Add the location of TLScontext to the SSL to later retrieve
     * the information inside the tls_verify_certificate_callback().
     * 
     * If session caching was enabled when TLS was initialized, the cache type
     * is stored in the client SSL context.
     */
    TLScontext = tls_alloc_sess_context(log_mask, props->namaddr);
    TLScontext->cache_type = app_ctx->cache_type;

    TLScontext->serverid = myserverid;
    TLScontext->stream = props->stream;
    TLScontext->mdalg = props->mdalg;

    /* Alias DANE digest info from props */
    TLScontext->dane = props->dane;

    if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
	msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }
    if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
	msg_warn("Could not set application data for 'TLScontext->con'");
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }

    /*
     * Apply session protocol restrictions.
     */
    if (protomask != 0)
	SSL_set_options(TLScontext->con, TLS_SSL_OP_PROTOMASK(protomask));

    /*
     * XXX To avoid memory leaks we must always call SSL_SESSION_free() after
     * calling SSL_set_session(), regardless of whether or not the session
     * will be reused.
     */
    if (TLScontext->cache_type) {
	session = load_clnt_session(TLScontext);
	if (session) {
	    SSL_set_session(TLScontext->con, session);
	    SSL_SESSION_free(session);		/* 200411 */
	}
    }
#ifdef TLSEXT_MAXLEN_host_name
    if (TLS_DANE_BASED(props->tls_level)
	&& strlen(props->host) <= TLSEXT_MAXLEN_host_name) {

	/*
	 * With DANE sessions, send an SNI hint.  We don't care whether the
	 * server reports finding a matching certificate or not, so no
	 * callback is required to process the server response.  Our use of
	 * SNI is limited to giving servers that are (mis)configured to use
	 * SNI the best opportunity to find the certificate they promised via
	 * the associated TLSA RRs.  (Generally, server administrators should
	 * avoid SNI, and there are no plans to support SNI in the Postfix
	 * SMTP server).
	 * 
	 * Since the hostname is DNSSEC-validated, it must be a DNS FQDN and
	 * thererefore valid for use with SNI.  Failure to set a valid SNI
	 * hostname is a memory allocation error, and thus transient.  Since
	 * we must not cache the session if we failed to send the SNI name,
	 * we have little choice but to abort.
	 */
	if (!SSL_set_tlsext_host_name(TLScontext->con, props->host)) {
	    msg_warn("%s: error setting SNI hostname to: %s", props->namaddr,
		     props->host);
	    tls_free_context(TLScontext);
	    return (0);
	}
	if (log_mask & TLS_LOG_DEBUG)
	    msg_info("%s: SNI hostname: %s", props->namaddr, props->host);
    }
#endif

    /*
     * Before really starting anything, try to seed the PRNG a little bit
     * more.
     */
    tls_int_seed();
    (void) tls_ext_seed(var_tls_daemon_rand_bytes);

    /*
     * Initialize the SSL connection to connect state. This should not be
     * necessary anymore since 0.9.3, but the call is still in the library
     * and maintaining compatibility never hurts.
     */
    SSL_set_connect_state(TLScontext->con);

    /*
     * Connect the SSL connection with the network socket.
     */
    if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) {
	msg_info("SSL_set_fd error to %s", props->namaddr);
	tls_print_errors();
	uncache_session(app_ctx->ssl_ctx, TLScontext);
	tls_free_context(TLScontext);
	return (0);
    }

    /*
     * Turn on non-blocking I/O so that we can enforce timeouts on network
     * I/O.
     */
    non_blocking(vstream_fileno(props->stream), NON_BLOCKING);

    /*
     * If the debug level selected is high enough, all of the data is dumped:
     * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will
     * dump everything.
     * 
     * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
     * Well there is a BIO below the SSL routines that is automatically
     * created for us, so we can use it for debugging purposes.
     */
    if (log_mask & TLS_LOG_TLSPKTS)
	BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);

    tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext);

    /*
     * Start TLS negotiations. This process is a black box that invokes our
     * call-backs for certificate verification.
     * 
     * Error handling: If the SSL handhake fails, we print out an error message
     * and remove all TLS state concerning this session.
     */
    sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout,
			  TLScontext);
    if (sts <= 0) {
	if (ERR_peek_error() != 0) {
	    msg_info("SSL_connect error to %s: %d", props->namaddr, sts);
	    tls_print_errors();
	} else if (errno != 0) {
	    msg_info("SSL_connect error to %s: %m", props->namaddr);
	} else {
	    msg_info("SSL_connect error to %s: lost connection",
		     props->namaddr);
	}
	uncache_session(app_ctx->ssl_ctx, TLScontext);
	tls_free_context(TLScontext);
	return (0);
    }
    /* Turn off packet dump if only dumping the handshake */
    if ((log_mask & TLS_LOG_ALLPKTS) == 0)
	BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);

    /*
     * The caller may want to know if this session was reused or if a new
     * session was negotiated.
     */
    TLScontext->session_reused = SSL_session_reused(TLScontext->con);
    if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused)
	msg_info("%s: Reusing old session", TLScontext->namaddr);

    /*
     * Do peername verification if requested and extract useful information
     * from the certificate for later use.
     */
    if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) {
	TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT;

	/*
	 * Peer name or fingerprint verification as requested.
	 * Unconditionally set peer_CN, issuer_CN and peer_cert_fprint. Check
	 * fingerprint first, and avoid logging verified as untrusted in the
	 * call to verify_extract_name().
	 */
	verify_extract_print(TLScontext, peercert, props);
	verify_extract_name(TLScontext, peercert, props);

	if (TLScontext->log_mask &
	    (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT))
	    msg_info("%s: subject_CN=%s, issuer_CN=%s, "
		     "fingerprint=%s, pkey_fingerprint=%s", props->namaddr,
		     TLScontext->peer_CN, TLScontext->issuer_CN,
		     TLScontext->peer_cert_fprint,
		     TLScontext->peer_pkey_fprint);
	X509_free(peercert);
    } else {
	TLScontext->issuer_CN = mystrdup("");
	TLScontext->peer_CN = mystrdup("");
	TLScontext->peer_cert_fprint = mystrdup("");
	TLScontext->peer_pkey_fprint = mystrdup("");
    }

    /*
     * Finally, collect information about protocol and cipher for logging
     */
    TLScontext->protocol = SSL_get_version(TLScontext->con);
    cipher = SSL_get_current_cipher(TLScontext->con);
    TLScontext->cipher_name = SSL_CIPHER_get_name(cipher);
    TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher,
					     &(TLScontext->cipher_algbits));

    /*
     * The TLS engine is active. Switch to the tls_timed_read/write()
     * functions and make the TLScontext available to those functions.
     */
    tls_stream_start(props->stream, TLScontext);

    /*
     * Fully secured only if trusted, matched and not insecure like halfdane.
     * Should perhaps also exclude "verify" (as opposed to "secure") here,
     * because that can be subject to insecure MX indirection, but that's
     * rather incompatible.  Users have been warned.
     */
    if (TLS_CERT_IS_PRESENT(TLScontext)
	&& TLS_CERT_IS_TRUSTED(TLScontext)
	&& TLS_CERT_IS_MATCHED(TLScontext)
	&& !TLS_NEVER_SECURED(props->tls_level))
	TLScontext->peer_status |= TLS_CERT_FLAG_SECURED;

    /*
     * All the key facts in a single log entry.
     */
    if (log_mask & TLS_LOG_SUMMARY)
	msg_info("%s TLS connection established to %s: %s with cipher %s "
		 "(%d/%d bits)",
		 !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" :
		 TLS_CERT_IS_SECURED(TLScontext) ? "Verified" :
		 TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
	      props->namaddr, TLScontext->protocol, TLScontext->cipher_name,
		 TLScontext->cipher_usebits, TLScontext->cipher_algbits);

    tls_int_seed();

    return (TLScontext);
}
Пример #6
0
static VALUE
ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
{
    SSL *ssl;
    int ilen, nread = 0;
    VALUE len, str;
    rb_io_t *fptr;

    rb_scan_args(argc, argv, "11", &len, &str);
    ilen = NUM2INT(len);
    if(NIL_P(str)) {
	str = rb_bstr_new();
    }
    else{
        StringValue(str);
	rb_str_modify(str);
	str = rb_str_bstr(str);
    }
    rb_bstr_resize(str, ilen);
    if(ilen == 0) return str;

    Data_Get_Struct(self, SSL, ssl);
    GetOpenFile(ossl_ssl_get_io(self), fptr);
    if (ssl) {
	if(!nonblock && SSL_pending(ssl) <= 0)
	    rb_thread_wait_fd(FPTR_TO_FD(fptr));
	for (;;){
	    nread = SSL_read(ssl, rb_bstr_bytes(str),
		    rb_bstr_length(str));
	    switch(ssl_get_error(ssl, nread)){
	    case SSL_ERROR_NONE:
		goto end;
	    case SSL_ERROR_ZERO_RETURN:
		rb_eof_error();
	    case SSL_ERROR_WANT_WRITE:
                write_would_block(nonblock);
                rb_io_wait_writable(FPTR_TO_FD(fptr));
                continue;
	    case SSL_ERROR_WANT_READ:
                read_would_block(nonblock);
                rb_io_wait_readable(FPTR_TO_FD(fptr));
		continue;
	    case SSL_ERROR_SYSCALL:
		if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
		rb_sys_fail(0);
	    default:
		ossl_raise(eSSLError, "SSL_read:");
	    }
        }
    }
    else {
        ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread");
        rb_warning("SSL session is not started yet.");
        return rb_funcall(ossl_ssl_get_io(self), meth, 2, len, str);
    }

  end:
    rb_bstr_resize(str, nread);
    OBJ_TAINT(str);

    return str;
}
Пример #7
0
int rsa_main(int argc, char **argv)
{
    ENGINE *e = NULL;
    BIO *out = NULL;
    RSA *rsa = NULL;
    const EVP_CIPHER *enc = NULL;
    char *infile = NULL, *outfile = NULL, *prog;
    char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL;
    int i;
    int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, check = 0;
    int noout = 0, modulus = 0, pubin = 0, pubout = 0, pvk_encr = 2, ret = 1;
    OPTION_CHOICE o;

    prog = opt_init(argc, argv, rsa_options);
    while ((o = opt_next()) != OPT_EOF) {
        switch (o) {
        case OPT_EOF:
        case OPT_ERR:
#ifdef OPENSSL_NO_RC4
        case OPT_PVK_STRONG:
        case OPT_PVK_WEAK:
        case OPT_PVK_NONE:
#endif
 opthelp:
            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
            goto end;
        case OPT_HELP:
            opt_help(rsa_options);
            ret = 0;
            goto end;
        case OPT_INFORM:
            if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
                goto opthelp;
            break;
        case OPT_IN:
            infile = opt_arg();
            break;
        case OPT_OUTFORM:
            if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat))
                goto opthelp;
            break;
        case OPT_OUT:
            outfile = opt_arg();
            break;
        case OPT_PASSIN:
            passinarg = opt_arg();
            break;
        case OPT_PASSOUT:
            passoutarg = opt_arg();
            break;
        case OPT_ENGINE:
            e = setup_engine(opt_arg(), 0);
            break;
        case OPT_PUBIN:
            pubin = 1;
            break;
        case OPT_PUBOUT:
            pubout = 1;
            break;
        case OPT_RSAPUBKEY_IN:
            pubin = 2;
            break;
        case OPT_RSAPUBKEY_OUT:
            pubout = 2;
            break;
#ifndef OPENSSL_NO_RC4
        case OPT_PVK_STRONG:
            pvk_encr = 2;
            break;
        case OPT_PVK_WEAK:
            pvk_encr = 1;
            break;
        case OPT_PVK_NONE:
            pvk_encr = 0;
            break;
#endif
        case OPT_NOOUT:
            noout = 1;
            break;
        case OPT_TEXT:
            text = 1;
            break;
        case OPT_MODULUS:
            modulus = 1;
            break;
        case OPT_CHECK:
            check = 1;
            break;
        case OPT_CIPHER:
            if (!opt_cipher(opt_unknown(), &enc))
                goto opthelp;
            break;
        }
    }
    argc = opt_num_rest();
    argv = opt_rest();

    if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
        BIO_printf(bio_err, "Error getting passwords\n");
        goto end;
    }

    if (check && pubin) {
        BIO_printf(bio_err, "Only private keys can be checked\n");
        goto end;
    }

    {
        EVP_PKEY *pkey;

        if (pubin) {
            int tmpformat = -1;
            if (pubin == 2) {
                if (informat == FORMAT_PEM)
                    tmpformat = FORMAT_PEMRSA;
                else if (informat == FORMAT_ASN1)
                    tmpformat = FORMAT_ASN1RSA;
            } else
                tmpformat = informat;

            pkey = load_pubkey(infile, tmpformat, 1, passin, e, "Public Key");
        } else
            pkey = load_key(infile, informat, 1, passin, e, "Private Key");

        if (pkey != NULL)
            rsa = EVP_PKEY_get1_RSA(pkey);
        EVP_PKEY_free(pkey);
    }

    if (rsa == NULL) {
        ERR_print_errors(bio_err);
        goto end;
    }

    out = bio_open_default(outfile, "w");
    if (out == NULL)
        goto end;

    if (text)
        if (!RSA_print(out, rsa, 0)) {
            perror(outfile);
            ERR_print_errors(bio_err);
            goto end;
        }

    if (modulus) {
        BIO_printf(out, "Modulus=");
        BN_print(out, rsa->n);
        BIO_printf(out, "\n");
    }

    if (check) {
        int r = RSA_check_key(rsa);

        if (r == 1)
            BIO_printf(out, "RSA key ok\n");
        else if (r == 0) {
            unsigned long err;

            while ((err = ERR_peek_error()) != 0 &&
                   ERR_GET_LIB(err) == ERR_LIB_RSA &&
                   ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY &&
                   ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) {
                BIO_printf(out, "RSA key error: %s\n",
                           ERR_reason_error_string(err));
                ERR_get_error(); /* remove e from error stack */
            }
        }

        /* should happen only if r == -1 */
        if (r == -1 || ERR_peek_error() != 0) {
            ERR_print_errors(bio_err);
            goto end;
        }
    }

    if (noout) {
        ret = 0;
        goto end;
    }
    BIO_printf(bio_err, "writing RSA key\n");
    if (outformat == FORMAT_ASN1) {
        if (pubout || pubin) {
            if (pubout == 2)
                i = i2d_RSAPublicKey_bio(out, rsa);
            else
                i = i2d_RSA_PUBKEY_bio(out, rsa);
        } else
            i = i2d_RSAPrivateKey_bio(out, rsa);
    }
# ifndef OPENSSL_NO_RC4
    else if (outformat == FORMAT_NETSCAPE) {
        unsigned char *p, *pp;
        int size;

        i = 1;
        size = i2d_RSA_NET(rsa, NULL, NULL, 0);
        if ((p = OPENSSL_malloc(size)) == NULL) {
            BIO_printf(bio_err, "Memory allocation failure\n");
            goto end;
        }
        pp = p;
        i2d_RSA_NET(rsa, &p, NULL, 0);
        BIO_write(out, (char *)pp, size);
        OPENSSL_free(pp);
    }
# endif
    else if (outformat == FORMAT_PEM) {
        if (pubout || pubin) {
            if (pubout == 2)
                i = PEM_write_bio_RSAPublicKey(out, rsa);
            else
                i = PEM_write_bio_RSA_PUBKEY(out, rsa);
        } else
            i = PEM_write_bio_RSAPrivateKey(out, rsa,
                                            enc, NULL, 0, NULL, passout);
# if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4)
    } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) {
        EVP_PKEY *pk;
        pk = EVP_PKEY_new();
        EVP_PKEY_set1_RSA(pk, rsa);
        if (outformat == FORMAT_PVK)
            i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout);
        else if (pubin || pubout)
            i = i2b_PublicKey_bio(out, pk);
        else
            i = i2b_PrivateKey_bio(out, pk);
        EVP_PKEY_free(pk);
# endif
    } else {
        BIO_printf(bio_err, "bad output format specified for outfile\n");
        goto end;
    }
    if (i <= 0) {
        BIO_printf(bio_err, "unable to write key\n");
        ERR_print_errors(bio_err);
    } else
        ret = 0;
 end:
    BIO_free_all(out);
    RSA_free(rsa);
    if (passin)
        OPENSSL_free(passin);
    if (passout)
        OPENSSL_free(passout);
    return (ret);
}
static VALUE ORPV__verify_pss_sha1(VALUE self, VALUE vPubKey, VALUE vSig, VALUE vHashData, VALUE vSaltLen) {
  enum ORPV_errors err = OK;

  BIO * pkey_bio = NULL;
  RSA * rsa_pub_key = NULL;
  EVP_PKEY * pkey = NULL;
  EVP_PKEY_CTX * pkey_ctx = NULL;
  char * pub_key = NULL;
  
  int verify_rval = -1, salt_len;
  char ossl_err_strs[(OSSL_ERR_STR_LEN + 2) * ORPV_MAX_ERRS] = "";

  if (ERR_peek_error()) {
    err = EXTERNAL;
    goto Cleanup;
  }

  vPubKey = StringValue(vPubKey);
  vSig = StringValue(vSig);
  vHashData = StringValue(vHashData);
  salt_len = NUM2INT(vSaltLen);

  if (RSTRING_LEN(vPubKey) > (long)INT_MAX) {
    err = KEY_OVERFLOW;
    goto Cleanup;
  }

  pub_key = malloc(RSTRING_LEN(vPubKey));
  if (! pub_key) {
    err = NOMEM;
    goto Cleanup;
  }
  memcpy(pub_key, StringValuePtr(vPubKey), RSTRING_LEN(vPubKey));

  pkey_bio = BIO_new_mem_buf(pub_key, (int)RSTRING_LEN(vPubKey));
  rsa_pub_key = PEM_read_bio_RSA_PUBKEY(pkey_bio, NULL, NULL, NULL);
  if (! rsa_pub_key) {
    err = PUBKEY_PARSE;
    goto Cleanup;
  }

  pkey = EVP_PKEY_new();
  if (! pkey) {
    err = PKEY_INIT;
    goto Cleanup;
  }

  if (! EVP_PKEY_set1_RSA(pkey, rsa_pub_key)) {
    err = RSA_ASSIGN;
    goto Cleanup;
  }

  pkey_ctx = EVP_PKEY_CTX_new(pkey, ENGINE_get_default_RSA());
  if (! pkey_ctx) {
    err = PKEY_CTX_INIT;
    goto Cleanup;
  }

  if (EVP_PKEY_verify_init(pkey_ctx) <= 0) {
    err = VERIFY_INIT;
    goto Cleanup;
  }

  if (EVP_PKEY_CTX_set_signature_md(pkey_ctx, EVP_sha1()) <= 0) {
    err = SET_SIG_MD;
    goto Cleanup;
  }

  if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
    err = SET_PADDING;
    goto Cleanup;
  }

  if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) <= 0) {
    err = SET_SALTLEN;
    goto Cleanup;
  }

  verify_rval = EVP_PKEY_verify(pkey_ctx, 
                                (unsigned char*)StringValuePtr(vSig), (size_t)RSTRING_LEN(vSig), 
                                (unsigned char*)StringValuePtr(vHashData), (size_t)RSTRING_LEN(vHashData));

Cleanup:
  /*
   * BIO * pkey_bio = NULL;
   * RSA * rsa_pub_key = NULL;
   * EVP_PKEY * pkey = NULL;
   * EVP_PKEY_CTX * pkey_ctx = NULL;
   * char * pub_key = NULL;
   */
  if (pkey_ctx) EVP_PKEY_CTX_free(pkey_ctx);
  if (pkey) EVP_PKEY_free(pkey);
  if (rsa_pub_key) RSA_free(rsa_pub_key);
  if (pkey_bio) BIO_free(pkey_bio);
  if (pub_key) free(pub_key);

  switch (err) {
    case OK:
      switch (verify_rval) {
        case 1:
          return Qtrue;
        case 0:
          return Qfalse;
        default:
          bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
          rb_raise(rb_cRSAError, "An error occurred during validation.\n%s", ossl_err_strs);
      }
      break;

    case EXTERNAL:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_eRuntimeError, "OpenSSL was in an error state prior to invoking this verification.\n%s", ossl_err_strs);
      break;
    case KEY_OVERFLOW:
      rb_raise(rb_cRSAError, "Your public key is too big. How is that even possible?");
      break;
    case NOMEM:
      rb_raise(rb_const_get_at(rb_mErrno, rb_intern("ENOMEM")), "Insufficient memory to allocate pubkey copy. Woof.");
      break;
    case PUBKEY_PARSE:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Error parsing public key\n%s", ossl_err_strs);
      break;
    case PKEY_INIT:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Failed to initialize PKEY\n%s", ossl_err_strs);
      break;
    case RSA_ASSIGN:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Failed to assign RSA object to PKEY\n%s", ossl_err_strs);
      break;
    case PKEY_CTX_INIT:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Failed to initialize PKEY context.\n%s", ossl_err_strs);
      break;
    case VERIFY_INIT:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Failed to initialize verification process.\n%s", ossl_err_strs);
      break;
    case SET_SIG_MD:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Failed to set signature message digest to SHA1.\n%s", ossl_err_strs);
      break;
    case SET_PADDING:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Failed to set PSS padding.\n%s", ossl_err_strs);
      break;
    case SET_SALTLEN:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_cRSAError, "Failed to set salt length.\n%s", ossl_err_strs);
      break;
    default:
      bind_err_strs(ossl_err_strs, ORPV_MAX_ERRS);
      rb_raise(rb_eRuntimeError, "Something has gone horribly wrong.\n%s", ossl_err_strs);
  }

  return Qnil;
}
Пример #9
0
char *SDMMD_ssl_strerror(SSL *ssl, uint32_t ret)
{
	static char buffer[200] = {0};
	int result = SSL_get_error(ssl, ret);
	char *err = NULL;

	switch (result) {
		case SSL_ERROR_NONE: {
			break;
		}
		case SSL_ERROR_SSL: {
			if (ERR_peek_error()) {
				snprintf(buffer, 200, "SSL_ERROR_SSL (%s)", ERR_error_string(ERR_peek_error(), NULL));
				err = buffer;
			}
			else {
				err = "SSL_ERROR_SSL unknown error";
			}
			break;
		}
		case SSL_ERROR_WANT_READ: {
			err = "SSL_ERROR_WANT_READ";
			break;
		}
		case SSL_ERROR_WANT_WRITE: {
			err = "SSL_ERROR_WANT_WRITE";
			break;
		}
		case SSL_ERROR_WANT_X509_LOOKUP: {
			err = "SSL_ERROR_WANT_X509_LOOKUP";
			break;
		}
		case SSL_ERROR_SYSCALL: {
			if (ERR_peek_error() == 0 && ret == 0) {
				err = "SSL_ERROR_SYSCALL (Early EOF reached)";
			}
			else if (ERR_peek_error() == 0 && ret == -1) {
				snprintf(buffer, 200, "SSL_ERROR_SYSCALL errno (%s)", strerror(errno));
				err = buffer;
			}
			else if (ERR_peek_error() == 0) {
				err = "SSL_ERROR_SYSCALL (WTFERROR)";
			}
			else {
				snprintf(buffer, 200, "SSL_ERROR_SYSCALL internal (%s)", ERR_error_string(ERR_peek_error(), NULL));
				err = buffer;
			}
			break;
		}
		case SSL_ERROR_ZERO_RETURN: {
			err = "SSL_ERROR_ZERO_RETURN";
			break;
		}
		case SSL_ERROR_WANT_CONNECT: {
			err = "SSL_ERROR_WANT_CONNECT";
			break;
		}
		case SSL_ERROR_WANT_ACCEPT: {
			err = "SSL_ERROR_WANT_ACCEPT";
			break;
		}
		default: {
			ERR_print_errors_fp(stderr);
			fputc('\n', stderr);
			err = "Unknown SSL error type";
			break;
		}
	}
	ERR_clear_error();
	return err;
}
Пример #10
0
/** Print errors in the TLS thread local error stack
 *
 * Drains the thread local OpenSSL error queue, and prints out errors.
 *
 * @param[in] request	The current request (may be NULL).
 * @param[in] msg	Error message describing the operation being attempted.
 * @param[in] ap	Arguments for msg.
 * @return the number of errors drained from the stack.
 */
static int tls_log_error_va(REQUEST *request, char const *msg, va_list ap)
{
	unsigned long	error;
	char		*p;
	int		in_stack = 0;
	char		buffer[256];

	int		line;
	char const	*file;
	char const	*data;
	int		flags = 0;

	/*
	 *	Pop the first error, so ERR_peek_error()
	 *	can be used to determine if there are
	 *	multiple errors.
	 */
	error = ERR_get_error_line_data(&file, &line, &data, &flags);
	if (!(flags & ERR_TXT_STRING)) data = NULL;

	if (msg) {
		p = talloc_vasprintf(request, msg, ap);

		/*
		 *	Single line mode (there's only one error)
		 */
		if (error && !ERR_peek_error()) {
			ERR_error_string_n(error, buffer, sizeof(buffer));

			/* Extra verbose */
			if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) {
				ROPTIONAL(REDEBUG, ERROR, "%s: %s[%i]:%s%c%s", p, file, line, buffer,
					  data ? ':' : '\0', data ? data : "");
			} else {
				ROPTIONAL(REDEBUG, ERROR, "%s: %s%c%s", p, buffer,
					  data ? ':' : '\0', data ? data : "");
			}

			talloc_free(p);

			return 1;
		}

		/*
		 *	Print the error we were given, irrespective
		 *	of whether there were any OpenSSL errors.
		 */
		ROPTIONAL(RERROR, ERROR, "%s", p);
		talloc_free(p);
	}

	/*
	 *	Stack mode (there are multiple errors)
	 */
	if (!error) return 0;
	do {
		if (!(flags & ERR_TXT_STRING)) data = NULL;

		ERR_error_string_n(error, buffer, sizeof(buffer));
		/* Extra verbose */
		if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) {
			ROPTIONAL(REDEBUG, ERROR, "%s[%i]:%s%c%s", file, line, buffer,
				  data ? ':' : '\0', data ? data : "");
		} else {
			ROPTIONAL(REDEBUG, ERROR, "%s%c%s", buffer,
				  data ? ':' : '\0', data ? data : "");
		}
		in_stack++;
	} while ((error = ERR_get_error_line_data(&file, &line, &data, &flags)));

	return in_stack;
}
Пример #11
0
/**
 * Accept the GSI Authentication.
 * @param sock the socket for communication.
 * @param ctx the authorization context.
 * @return the context identifier. 
 */
bool
GSISocketServer::AcceptGSIAuthentication()
{
  char *name = NULL;
  long  errorcode = 0;
  int   flags;

  time_t curtime, starttime;
  int ret, accept_status;
  bool accept_timed_out = false;
  int expected = 0;
  BIO *bio = NULL;
  char *cert_file, *user_cert, *user_key, *user_proxy;
  char *serial=NULL;

  cert_file = user_cert = user_key = user_proxy = NULL;

  if (proxy_get_filenames(0, &cert_file, &cacertdir, &user_proxy, &user_cert, &user_key) == 0) {
    (void)load_credentials(user_cert, user_key, &ucert, &own_stack, &upkey, NULL);
  }

  free(cert_file);
  free(user_cert);
  free(user_key);
  free(user_proxy);

  own_cert = ucert;
  own_key = upkey;
  ctx = SSL_CTX_new(SSLv23_method());
  SSL_CTX_load_verify_locations(ctx, NULL, cacertdir);
  SSL_CTX_use_certificate(ctx, ucert);
  SSL_CTX_use_PrivateKey(ctx,upkey);
  SSL_CTX_set_cipher_list(ctx, "ALL:!LOW:!EXP:!MD5:!MD2");    
  SSL_CTX_set_purpose(ctx, X509_PURPOSE_ANY);
  SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, proxy_verify_callback);
  SSL_CTX_set_verify_depth(ctx, 100);
  SSL_CTX_set_cert_verify_callback(ctx, proxy_app_verify_callback, 0);

  if (own_stack) {
    /*
     * Certificate was a proxy with a cert. chain.
     * Add the certificates one by one to the chain.
     */
    X509_STORE_add_cert(ctx->cert_store, ucert);
    for (int i = 0; i <sk_X509_num(own_stack); ++i) {
      X509 *cert = (sk_X509_value(own_stack,i));

      if (!X509_STORE_add_cert(ctx->cert_store, cert)) {
        if (ERR_GET_REASON(ERR_peek_error()) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
          ERR_clear_error();
          continue;
        }
        else {
          SetErrorOpenSSL("Cannot add certificate to the SSL context's certificate store");
          goto err;
        }
      }
    }
  }

  flags = fcntl(newsock, F_GETFL, 0);
  (void)fcntl(newsock, F_SETFL, flags | O_NONBLOCK);

  bio = BIO_new_socket(newsock, BIO_NOCLOSE);
  (void)BIO_set_nbio(bio, 1);

  ssl = SSL_new(ctx);
  setup_SSL_proxy_handler(ssl, cacertdir);

  writeb = bio->method->bwrite;
  readb  = bio->method->bread;
  bio->method->bwrite = globusf_write;
  bio->method->bread  = globusf_read;

  SSL_set_bio(ssl, bio, bio);

  curtime = starttime = time(NULL);

  ret = accept_status = -1;
  expected = 0;

  do {

    ret = do_select(newsock, starttime, timeout, expected);
    LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Select status: %d",ret);

    curtime = time(NULL);


    if (ret == 0){

      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Select timed out.");

      if (curtime - starttime > timeout){
        accept_timed_out = true;
        break;

      }else{

        continue;
      }
      
    }
    
    if (ret > 0) {
      accept_status = SSL_accept(ssl);
      curtime = time(NULL);
      expected = errorcode = SSL_get_error(ssl, accept_status);

      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Accept status: %d",accept_status);
      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Error code: %d",errorcode);
      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "SSL_WANT_READ: %d, SSL_WANT_WRITE: %d",SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE);
    }

    if (ret < 0)
      // No more data from the select
      break;

    if (accept_status == 1)
      // SSL handshake completed
      break;

    if (timeout != -1 && (curtime - starttime > timeout)){
      // Timeout reached
      accept_timed_out = true;
      break;
    }

    if (accept_status <= 0 && ( errorcode != SSL_ERROR_WANT_READ && errorcode != SSL_ERROR_WANT_WRITE ))
      // SSL handshake error
      break;
    
  } while (true);
  
  // Error enstabilishing context
  if (accept_status != 1){

    LOGM(VARP, logh, LEV_INFO, T_PRE, "Error enstabilishing SSL context.");

    if (accept_timed_out){
      SetError("SSL Handshake failed due to server timeout!");
    }else{
      SetErrorOpenSSL("SSL Handshake error:");
    }

    goto err;
  }
  
  // Context enstabilished
  actual_cert = SSL_get_peer_certificate(ssl);
  peer_stack  = SSL_get_peer_cert_chain(ssl);

  char buffer[1000];

//  if (LogLevelMin(logh, LEV_DEBUG)) {
      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate DN: %s",
           X509_NAME_oneline(X509_get_subject_name(actual_cert), buffer, 999));
      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate CA: %s",
           X509_NAME_oneline(X509_get_issuer_name(actual_cert), buffer, 999));
      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Stack Size: %d", sk_X509_num(peer_stack));
//  }

  peer_cert = get_real_cert(actual_cert, peer_stack);

  if (peer_cert) {
    char *name = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, 0);
    own_subject = std::string(name);
    OPENSSL_free(name);
  }

  if (LogLevelMin(logh, LEV_DEBUG)){
    for (int i = 0; i < sk_X509_num(peer_stack); i++) {
      X509 *cert = sk_X509_value(peer_stack, i);
      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate DN: %s",
           X509_NAME_oneline(X509_get_subject_name(cert), buffer, 999));
      LOGM(VARP, logh, LEV_DEBUG, T_PRE, "Certificate CA: %s",
           X509_NAME_oneline(X509_get_issuer_name(cert), buffer, 999));
    }
  }

  name = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, 0);
  if (name)
    peer_subject = std::string(name); 
  OPENSSL_free(name);

  name = X509_NAME_oneline(X509_get_issuer_name(peer_cert), NULL, 0);
  if (name)
    peer_ca = std::string(name);
  OPENSSL_free(name);

  serial = get_peer_serial(actual_cert);
  peer_serial = std::string(serial ? serial : "");
  OPENSSL_free(serial);

  return true;

err:
  destroy_SSL_proxy_handler(ssl);
  SSL_free(ssl);
  SSL_CTX_free(ctx);

  return false;
}
Пример #12
0
/* Switch a socket to SSL communication
 *
 * Creates a SSL data structure for the connection;
 * Sets up callbacks and initiates a SSL handshake with the peer;
 * Reports error conditions and performs cleanup upon failure.
 *
 * flags: ssl flags, i.e connect or listen
 * verify: peer certificate verification flags
 * loglevel: is the level to output information about the connection
 * and certificates.
 * host: contains the dns name or ip address of the peer. Used for
 * verification.
 * cb: optional callback, this function will be called after the
 * handshake completes.
 *
 * Return value: 0 on success, !=0 on failure.
 */
int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host,
                  IntFunc cb)
{
  int i, err, ret;
  ssl_appdata *data;
  struct threaddata *td = threaddata();

  debug0("TLS: attempting SSL negotiation...");
  if (!ssl_ctx && ssl_init()) {
    debug0("TLS: Failed. OpenSSL not initialized properly.");
    return -1;
  }
  /* find the socket in the list */
  i = findsock(sock);
  if (i == -1) {
    debug0("TLS: socket not in socklist");
    return -2;
  }
  if (td->socklist[i].ssl) {
    debug0("TLS: handshake not required - SSL session already established");
    return 0;
  }
  td->socklist[i].ssl = SSL_new(ssl_ctx);
  if (!td->socklist[i].ssl ||
      !SSL_set_fd(td->socklist[i].ssl, td->socklist[i].sock)) {
    debug1("TLS: cannot initiate SSL session - %s",
           ERR_error_string(ERR_get_error(), 0));
    return -3;
  }

  /* Prepare a ssl appdata struct for the verify callback */
  data = nmalloc(sizeof(ssl_appdata));
  egg_bzero(data, sizeof(ssl_appdata));
  data->flags = flags & (TLS_LISTEN | TLS_CONNECT);
  data->verify = flags & ~(TLS_LISTEN | TLS_CONNECT);
  data->loglevel = loglevel;
  data->cb = cb;
  strncpyz(data->host, host ? host : "", sizeof(data->host));
  SSL_set_app_data(td->socklist[i].ssl, data);
  SSL_set_info_callback(td->socklist[i].ssl, (void *) ssl_info);
  /* We set this +1 to be able to report extra long chains properly.
   * Otherwise, OpenSSL will break the verification reporting about
   * missing certificates instead. The rest of the fix is in
   * ssl_verify()
   */
  SSL_set_verify_depth(td->socklist[i].ssl, tls_maxdepth + 1);

  SSL_set_mode(td->socklist[i].ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
               SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  if (data->flags & TLS_CONNECT) {
    SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify);
    ret = SSL_connect(td->socklist[i].ssl);
    if (!ret)
      debug0("TLS: connect handshake failed.");
  } else {
    if (data->flags & TLS_VERIFYPEER)
      SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER |
                     SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify);
    else
      SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify);
    ret = SSL_accept(td->socklist[i].ssl);
    if (!ret)
      debug0("TLS: accept handshake failed");
  }

  err = SSL_get_error(td->socklist[i].ssl, ret);
  /* Normal condition for async I/O, similar to EAGAIN */
  if (ret > 0 || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
    debug0("TLS: handshake in progress");
    return 0;
  }
  if (ERR_peek_error())
    debug0("TLS: handshake failed due to the following errors: ");
  while ((err = ERR_get_error()))
    debug1("TLS: %s", ERR_error_string(err, NULL));

  /* Attempt failed, cleanup and abort */
  SSL_shutdown(td->socklist[i].ssl);
  SSL_free(td->socklist[i].ssl);
  td->socklist[i].ssl = NULL;
  nfree(data);
  return -4;
}
Пример #13
0
NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *c,
        OCSP_REQUEST *req, char *url) {
    BIO *bio=NULL;
    OCSP_REQ_CTX *req_ctx=NULL;
    OCSP_RESPONSE *resp=NULL;
    int err;
    char *host=NULL, *port=NULL, *path=NULL;
    SOCKADDR_UNION addr;
    int ssl;

    /* parse the OCSP URL */
    if(!OCSP_parse_url(url, &host, &port, &path, &ssl)) {
        s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL");
        goto cleanup;
    }
    if(ssl) {
        s_log(LOG_ERR, "OCSP: SSL not supported for OCSP"
            " - additional stunnel service needs to be defined");
        goto cleanup;
    }
    memset(&addr, 0, sizeof addr);
    addr.in.sin_family=AF_INET;
    if(!hostport2addr(&addr, host, port)) {
        s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP server address");
        goto cleanup;
    }

    /* connect specified OCSP server (responder) */
    c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket");
    if(c->fd<0)
        goto cleanup;
    if(s_connect(c, &addr, addr_len(&addr)))
        goto cleanup;
    bio=BIO_new_fd(c->fd, BIO_NOCLOSE);
    if(!bio)
        goto cleanup;
    s_log(LOG_DEBUG, "OCSP: response retrieved");

    /* OCSP protocol communication loop */
    req_ctx=OCSP_sendreq_new(bio, path, req, -1);
    if(!req_ctx) {
        sslerror("OCSP: OCSP_sendreq_new");
        goto cleanup;
    }
    while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio));
        err=s_poll_wait(c->fds, c->opt->timeout_busy, 0);
        if(err==-1)
            sockerror("OCSP: s_poll_wait");
        if(err==0)
            s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded");
        if(err<=0)
            goto cleanup;
    }
#if 0
    s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx);
#endif
    /* http://www.mail-archive.com/[email protected]/msg61691.html */
    if(resp) {
        s_log(LOG_DEBUG, "OCSP: request completed");
    } else {
        if(ERR_peek_error())
            sslerror("OCSP: OCSP_sendreq_nbio");
        else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */
            s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error");
    }

cleanup:
    if(req_ctx)
        OCSP_REQ_CTX_free(req_ctx);
    if(bio)
        BIO_free_all(bio);
    if(c->fd>=0) {
        closesocket(c->fd);
        c->fd=-1; /* avoid double close on cleanup */
    }
    if(host)
        OPENSSL_free(host);
    if(port)
        OPENSSL_free(port);
    if(path)
        OPENSSL_free(path);
    return resp;
}
Пример #14
0
int
tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_engine,
                        const char *priv_key_file
#if ENABLE_INLINE_FILES
    , const char *priv_key_file_inline
#endif
    )
{
  int status;
  SSL_CTX *ssl_ctx = NULL;
  BIO *in = NULL;
  EVP_PKEY *pkey = NULL;
  int ret = 1;

  ASSERT(NULL != ctx);

  ssl_ctx = ctx->ctx;

#if ENABLE_INLINE_FILES
  if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline)
    in = BIO_new_mem_buf ((char *)priv_key_file_inline, -1);
  else
#endif /* ENABLE_INLINE_FILES */
    in = BIO_new_file (priv_key_file, "r");

  if (!in)
    goto end;

  if (priv_key_engine) {
    ENGINE *engine;

    ENGINE_load_builtin_engines();
    engine = ENGINE_by_id(priv_key_engine);
    if (!ENGINE_init(engine)) {
      msg (M_WARN|M_SSL, "Cannot init engine %s", priv_key_engine);
      goto end;
    }
    pkey = ENGINE_load_private_key(engine, priv_key_file, UI_OpenSSL(), NULL);
  } else {
    pkey = PEM_read_bio_PrivateKey (in, NULL,
                                    ssl_ctx->default_passwd_callback,
                                    ssl_ctx->default_passwd_callback_userdata);
  }

  if (!pkey)
    goto end;

  if (!SSL_CTX_use_PrivateKey (ssl_ctx, pkey))
    {
#ifdef ENABLE_MANAGEMENT
      if (management && (ERR_GET_REASON (ERR_peek_error()) == EVP_R_BAD_DECRYPT))
          management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
#endif
      msg (M_WARN|M_SSL, "Cannot load private key file %s", priv_key_file);
      goto end;
    }
  warn_if_group_others_accessible (priv_key_file);

  /* Check Private Key */
  if (!SSL_CTX_check_private_key (ssl_ctx))
    msg (M_SSLERR, "Private key does not match the certificate");
  ret = 0;

end:
  if (pkey)
    EVP_PKEY_free (pkey);
  if (in)
    BIO_free (in);
  return ret;
}
Пример #15
0
static int
asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
{
	BUF_MEM *b;
	unsigned char *p;
	int i;
	ASN1_const_CTX c;
	size_t want = HEADER_SIZE;
	int eos = 0;
	size_t off = 0;
	size_t len = 0;

	b = BUF_MEM_new();
	if (b == NULL) {
		ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
		return -1;
	}

	ERR_clear_error();
	for (;;) {
		if (want >= (len - off)) {
			want -= (len - off);

			if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) {
				ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
				goto err;
			}
			i = BIO_read(in, &(b->data[len]), want);
			if ((i < 0) && ((len - off) == 0)) {
				ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA);
				goto err;
			}
			if (i > 0) {
				if (len + i < len) {
					ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
					goto err;
				}
				len += i;
			}
		}
		/* else data already loaded */

		p = (unsigned char *) & (b->data[off]);
		c.p = p;
		c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag),
		    &(c.xclass), len - off);
		if (c.inf & 0x80) {
			unsigned long e;

			e = ERR_GET_REASON(ERR_peek_error());
			if (e != ASN1_R_TOO_LONG)
				goto err;
			else
				ERR_clear_error(); /* clear error */
		}
		i = c.p - p;	/* header length */
		off += i;	/* end of data */

		if (c.inf & 1) {
			/* no data body so go round again */
			eos++;
			if (eos < 0) {
				ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_HEADER_TOO_LONG);
				goto err;
			}
			want = HEADER_SIZE;
		} else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) {
			/* eos value, so go back and read another header */
			eos--;
			if (eos <= 0)
				break;
			else
				want = HEADER_SIZE;
		} else {
			/* suck in c.slen bytes of data */
			want = c.slen;
			if (want > (len - off)) {
				want -= (len - off);
				if (want > INT_MAX /* BIO_read takes an int length */ ||
				    len+want < len) {
					ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
					goto err;
				}
				if (!BUF_MEM_grow_clean(b, len + want)) {
					ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
					goto err;
				}
				while (want > 0) {
					i = BIO_read(in, &(b->data[len]), want);
					if (i <= 0) {
						ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
						    ASN1_R_NOT_ENOUGH_DATA);
						goto err;
					}
					/* This can't overflow because
					 * |len+want| didn't overflow. */
					len += i;
					want -= i;
				}
			}
			if (off + c.slen < off) {
				ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
				goto err;
			}
			off += c.slen;
			if (eos <= 0) {
				break;
			} else
				want = HEADER_SIZE;
		}
	}

	if (off > INT_MAX) {
		ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
		goto err;
	}

	*pb = b;
	return off;

err:
	if (b != NULL)
		BUF_MEM_free(b);
	return -1;
}
Пример #16
0
static int
openssl_iostream_handle_error_full(struct ssl_iostream *ssl_io, int ret,
				   const char *func_name, bool write_error)
{
	const char *errstr = NULL;
	int err;

	err = SSL_get_error(ssl_io->ssl, ret);
	switch (err) {
	case SSL_ERROR_WANT_WRITE:
		if (!openssl_iostream_bio_sync(ssl_io)) {
			if (!write_error)
				i_panic("SSL ostream buffer size not unlimited");
			return 0;
		}
		if (ssl_io->closed) {
			if (ssl_io->plain_stream_errstr != NULL)
				openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr);
			errno = ssl_io->plain_stream_errno != 0 ?
				ssl_io->plain_stream_errno : EPIPE;
			return -1;
		}
		return 1;
	case SSL_ERROR_WANT_READ:
		ssl_io->want_read = TRUE;
		(void)openssl_iostream_bio_sync(ssl_io);
		if (ssl_io->closed) {
			if (ssl_io->plain_stream_errstr != NULL)
				openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr);
			errno = ssl_io->plain_stream_errno != 0 ?
				ssl_io->plain_stream_errno : EPIPE;
			return -1;
		}
		return ssl_io->want_read ? 0 : 1;
	case SSL_ERROR_SYSCALL:
		/* eat up the error queue */
		if (ERR_peek_error() != 0) {
			errstr = openssl_iostream_error();
			errno = EINVAL;
		} else if (ret != 0) {
			i_assert(errno != 0);
			errstr = strerror(errno);
		} else {
			/* EOF. */
			errno = EPIPE;
			errstr = "Disconnected";
			break;
		}
		errstr = t_strdup_printf("%s syscall failed: %s",
					 func_name, errstr);
		break;
	case SSL_ERROR_ZERO_RETURN:
		/* clean connection closing */
		errno = EPIPE;
		i_free_and_null(ssl_io->last_error);
		return -1;
	case SSL_ERROR_SSL:
		errstr = t_strdup_printf("%s failed: %s",
					 func_name, openssl_iostream_error());
		errno = EINVAL;
		break;
	default:
		errstr = t_strdup_printf("%s failed: unknown failure %d (%s)",
					 func_name, err,
					 openssl_iostream_error());
		errno = EINVAL;
		break;
	}

	openssl_iostream_set_error(ssl_io, errstr);
	return -1;
}
Пример #17
0
/**
 * NOTE: From node.js
 *
 * Read a file that contains our certificate in "PEM" format,
 * possibly followed by a sequence of CA certificates that should be
 * sent to the peer in the Certificate message.
 *
 * Taken from OpenSSL - editted for style.
 */
int bud_context_use_certificate_chain(bud_context_t* ctx, BIO *in) {
  int ret;
  X509* x;
  X509* ca;
  X509_STORE* store;
  X509_STORE_CTX store_ctx;
  int r;
  unsigned long err;

  ERR_clear_error();

  ret = 0;
  x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);

  if (x == NULL) {
    SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
    goto end;
  }

  ret = SSL_CTX_use_certificate(ctx->ctx, x);
  ctx->cert = x;
  ctx->issuer = NULL;

  if (ERR_peek_error() != 0) {
    /* Key/certificate mismatch doesn't imply ret==0 ... */
    ret = 0;
  }

  if (ret) {
    /**
     * If we could set up our certificate, now proceed to
     * the CA certificates.
     */
    if (ctx->ctx->extra_certs != NULL) {
      sk_X509_pop_free(ctx->ctx->extra_certs, X509_free);
      ctx->ctx->extra_certs = NULL;
    }

    while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
      r = SSL_CTX_add_extra_chain_cert(ctx->ctx, ca);

      if (!r) {
        X509_free(ca);
        ret = 0;
        goto end;
      }
      /**
       * Note that we must not free r if it was successfully
       * added to the chain (while we must free the main
       * certificate, since its reference count is increased
       * by SSL_CTX_use_certificate).
       */

      /* Find issuer */
      if (ctx->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK)
        continue;
      ctx->issuer = ca;
    }

    /* When the while loop ends, it's usually just EOF. */
    err = ERR_peek_last_error();
    if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
        ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
      ERR_clear_error();
    } else  {
      /* some real error */
      ret = 0;
    }
  }

end:
  if (ret) {
    /* Try getting issuer from cert store */
    if (ctx->issuer == NULL) {
      store = SSL_CTX_get_cert_store(ctx->ctx);
      ret = X509_STORE_CTX_init(&store_ctx, store, NULL, NULL);
      if (!ret)
        goto fatal;

      ret = X509_STORE_CTX_get1_issuer(&ctx->issuer, &store_ctx, ctx->cert);
      X509_STORE_CTX_cleanup(&store_ctx);

      ret = ret < 0 ? 0 : 1;
      /* NOTE: get_cert_store doesn't increment reference count */
    } else {
      /* Increment issuer reference count */
      CRYPTO_add(&ctx->issuer->references, 1, CRYPTO_LOCK_X509);
    }

    if (ctx->issuer != NULL) {
      /* Get ocsp_id */
      ctx->ocsp_id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
      if (ctx->ocsp_id == NULL) {
        ctx->issuer = NULL;
        goto fatal;
      }
    }
  } else {
    if (ctx->issuer != NULL)
      X509_free(ctx->issuer);
  }

fatal:
  if (ctx->cert != x && x != NULL)
    X509_free(x);

  return ret;
}
Пример #18
0
/* Read a file that contains our certificate in "PEM" format, possibly followed
 * by a sequence of CA certificates that should be sent to the peer in the
 * Certificate message. */
int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) {
  BIO *in;
  int ret = 0;
  X509 *x = NULL;

  ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */

  in = BIO_new(BIO_s_file());
  if (in == NULL) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
    goto end;
  }

  if (BIO_read_filename(in, file) <= 0) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
    goto end;
  }

  x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback,
                            ctx->default_passwd_callback_userdata);
  if (x == NULL) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB);
    goto end;
  }

  ret = SSL_CTX_use_certificate(ctx, x);

  if (ERR_peek_error() != 0) {
    ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */
  }

  if (ret) {
    /* If we could set up our certificate, now proceed to the CA
     * certificates. */
    X509 *ca;
    int r;
    uint32_t err;

    SSL_CTX_clear_chain_certs(ctx);

    while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
                                   ctx->default_passwd_callback_userdata)) !=
           NULL) {
      r = SSL_CTX_add0_chain_cert(ctx, ca);
      if (!r) {
        X509_free(ca);
        ret = 0;
        goto end;
      }
      /* Note that we must not free r if it was successfully added to the chain
       * (while we must free the main certificate, since its reference count is
       * increased by SSL_CTX_use_certificate). */
    }

    /* When the while loop ends, it's usually just EOF. */
    err = ERR_peek_last_error();
    if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
        ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
      ERR_clear_error();
    } else {
      ret = 0; /* some real error */
    }
  }

end:
  X509_free(x);
  BIO_free(in);
  return ret;
}
Пример #19
0
/*
 * Read a file that contains our certificate in "PEM" format, possibly
 * followed by a sequence of CA certificates that should be sent to the peer
 * in the Certificate message.
 */
static int use_certificate_chain_file(SSL_CTX *ctx, SSL *ssl, const char *file)
{
    BIO *in;
    int ret = 0;
    X509 *x = NULL;
    pem_password_cb *passwd_callback;
    void *passwd_callback_userdata;

    ERR_clear_error();          /* clear error stack for
                                 * SSL_CTX_use_certificate() */

    if (ctx != NULL) {
        passwd_callback = ctx->default_passwd_callback;
        passwd_callback_userdata = ctx->default_passwd_callback_userdata;
    } else {
        passwd_callback = ssl->default_passwd_callback;
        passwd_callback_userdata = ssl->default_passwd_callback_userdata;
    }

    in = BIO_new(BIO_s_file());
    if (in == NULL) {
        SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB);
        goto end;
    }

    if (BIO_read_filename(in, file) <= 0) {
        SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_SYS_LIB);
        goto end;
    }

    x = PEM_read_bio_X509_AUX(in, NULL, passwd_callback,
                              passwd_callback_userdata);
    if (x == NULL) {
        SSLerr(SSL_F_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
        goto end;
    }

    if (ctx)
        ret = SSL_CTX_use_certificate(ctx, x);
    else
        ret = SSL_use_certificate(ssl, x);

    if (ERR_peek_error() != 0)
        ret = 0;                /* Key/certificate mismatch doesn't imply
                                 * ret==0 ... */
    if (ret) {
        /*
         * If we could set up our certificate, now proceed to the CA
         * certificates.
         */
        X509 *ca;
        int r;
        unsigned long err;

        if (ctx)
            r = SSL_CTX_clear_chain_certs(ctx);
        else
            r = SSL_clear_chain_certs(ssl);

        if (r == 0) {
            ret = 0;
            goto end;
        }

        while ((ca = PEM_read_bio_X509(in, NULL, passwd_callback,
                                       passwd_callback_userdata))
                != NULL) {
            if (ctx)
                r = SSL_CTX_add0_chain_cert(ctx, ca);
            else
                r = SSL_add0_chain_cert(ssl, ca);
            /*
             * Note that we must not free ca if it was successfully added to
             * the chain (while we must free the main certificate, since its
             * reference count is increased by SSL_CTX_use_certificate).
             */
            if (!r) {
                X509_free(ca);
                ret = 0;
                goto end;
            }
        }
        /* When the while loop ends, it's usually just EOF. */
        err = ERR_peek_last_error();
        if (ERR_GET_LIB(err) == ERR_LIB_PEM
            && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
            ERR_clear_error();
        else
            ret = 0;            /* some real error */
    }

 end:
    X509_free(x);
    BIO_free(in);
    return (ret);
}
Пример #20
0
int MAIN(int argc, char **argv)
	{
	ENGINE *e = NULL;
	int ret=1;
	RSA *rsa=NULL;
	int i,badops=0, sgckey=0;
	const EVP_CIPHER *enc=NULL;
	BIO *out=NULL;
	int informat,outformat,text=0,check=0,noout=0;
	int pubin = 0, pubout = 0;
	char *infile,*outfile,*prog;
	char *passargin = NULL, *passargout = NULL;
	char *passin = NULL, *passout = NULL;
#ifndef OPENSSL_NO_ENGINE
	char *engine=NULL;
#endif
	int modulus=0;

	int pvk_encr = 2;

	apps_startup();

	if (bio_err == NULL)
		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
			BIO_set_fp(bio_err,OPENSSL_TYPE__FILE_STDERR,BIO_NOCLOSE|BIO_FP_TEXT);

	if (!load_config(bio_err, NULL))
		goto end;

	infile=NULL;
	outfile=NULL;
	informat=FORMAT_PEM;
	outformat=FORMAT_PEM;

	prog=argv[0];
	argc--;
	argv++;
	while (argc >= 1)
		{
		if 	(TINYCLR_SSL_STRCMP(*argv,"-inform") == 0)
			{
			if (--argc < 1) goto bad;
			informat=str2fmt(*(++argv));
			}
		else if (TINYCLR_SSL_STRCMP(*argv,"-outform") == 0)
			{
			if (--argc < 1) goto bad;
			outformat=str2fmt(*(++argv));
			}
		else if (TINYCLR_SSL_STRCMP(*argv,"-in") == 0)
			{
			if (--argc < 1) goto bad;
			infile= *(++argv);
			}
		else if (TINYCLR_SSL_STRCMP(*argv,"-out") == 0)
			{
			if (--argc < 1) goto bad;
			outfile= *(++argv);
			}
		else if (TINYCLR_SSL_STRCMP(*argv,"-passin") == 0)
			{
			if (--argc < 1) goto bad;
			passargin= *(++argv);
			}
		else if (TINYCLR_SSL_STRCMP(*argv,"-passout") == 0)
			{
			if (--argc < 1) goto bad;
			passargout= *(++argv);
			}
#ifndef OPENSSL_NO_ENGINE
		else if (TINYCLR_SSL_STRCMP(*argv,"-engine") == 0)
			{
			if (--argc < 1) goto bad;
			engine= *(++argv);
			}
#endif
		else if (TINYCLR_SSL_STRCMP(*argv,"-sgckey") == 0)
			sgckey=1;
		else if (TINYCLR_SSL_STRCMP(*argv,"-pubin") == 0)
			pubin=1;
		else if (TINYCLR_SSL_STRCMP(*argv,"-pubout") == 0)
			pubout=1;
		else if (TINYCLR_SSL_STRCMP(*argv,"-RSAPublicKey_in") == 0)
			pubin = 2;
		else if (TINYCLR_SSL_STRCMP(*argv,"-RSAPublicKey_out") == 0)
			pubout = 2;
		else if (TINYCLR_SSL_STRCMP(*argv,"-pvk-strong") == 0)
			pvk_encr=2;
		else if (TINYCLR_SSL_STRCMP(*argv,"-pvk-weak") == 0)
			pvk_encr=1;
		else if (TINYCLR_SSL_STRCMP(*argv,"-pvk-none") == 0)
			pvk_encr=0;
		else if (TINYCLR_SSL_STRCMP(*argv,"-noout") == 0)
			noout=1;
		else if (TINYCLR_SSL_STRCMP(*argv,"-text") == 0)
			text=1;
		else if (TINYCLR_SSL_STRCMP(*argv,"-modulus") == 0)
			modulus=1;
		else if (TINYCLR_SSL_STRCMP(*argv,"-check") == 0)
			check=1;
		else if ((enc=EVP_get_cipherbyname(&(argv[0][1]))) == NULL)
			{
			BIO_printf(bio_err,"unknown option %s\n",*argv);
			badops=1;
			break;
			}
		argc--;
		argv++;
		}

	if (badops)
		{
bad:
		BIO_printf(bio_err,"%s [options] <infile >outfile\n",prog);
		BIO_printf(bio_err,"where options are\n");
		BIO_printf(bio_err," -inform arg     input format - one of DER NET PEM\n");
		BIO_printf(bio_err," -outform arg    output format - one of DER NET PEM\n");
		BIO_printf(bio_err," -in arg         input file\n");
		BIO_printf(bio_err," -sgckey         Use IIS SGC key format\n");
		BIO_printf(bio_err," -passin arg     input file pass phrase source\n");
		BIO_printf(bio_err," -out arg        output file\n");
		BIO_printf(bio_err," -passout arg    output file pass phrase source\n");
		BIO_printf(bio_err," -des            encrypt PEM output with cbc des\n");
		BIO_printf(bio_err," -des3           encrypt PEM output with ede cbc des using 168 bit key\n");
#ifndef OPENSSL_NO_IDEA
		BIO_printf(bio_err," -idea           encrypt PEM output with cbc idea\n");
#endif
#ifndef OPENSSL_NO_SEED
		BIO_printf(bio_err," -seed           encrypt PEM output with cbc seed\n");
#endif
#ifndef OPENSSL_NO_AES
		BIO_printf(bio_err," -aes128, -aes192, -aes256\n");
		BIO_printf(bio_err,"                 encrypt PEM output with cbc aes\n");
#endif
#ifndef OPENSSL_NO_CAMELLIA
		BIO_printf(bio_err," -camellia128, -camellia192, -camellia256\n");
		BIO_printf(bio_err,"                 encrypt PEM output with cbc camellia\n");
#endif
		BIO_printf(bio_err," -text           print the key in text\n");
		BIO_printf(bio_err," -noout          don't print key out\n");
		BIO_printf(bio_err," -modulus        print the RSA key modulus\n");
		BIO_printf(bio_err," -check          verify key consistency\n");
		BIO_printf(bio_err," -pubin          expect a public key in input file\n");
		BIO_printf(bio_err," -pubout         output a public key\n");
#ifndef OPENSSL_NO_ENGINE
		BIO_printf(bio_err," -engine e       use engine e, possibly a hardware device.\n");
#endif
		goto end;
		}

	ERR_load_crypto_strings();

#ifndef OPENSSL_NO_ENGINE
        e = setup_engine(bio_err, engine, 0);
#endif

	if(!app_passwd(bio_err, passargin, passargout, &passin, &passout)) {
		BIO_printf(bio_err, "Error getting passwords\n");
		goto end;
	}

	if(check && pubin) {
		BIO_printf(bio_err, "Only private keys can be checked\n");
		goto end;
	}

	out=BIO_new(BIO_s_file());

	{
		EVP_PKEY	*pkey;

		if (pubin)
			{
			int tmpformat=-1;
			if (pubin == 2)
				{
				if (informat == FORMAT_PEM)
					tmpformat = FORMAT_PEMRSA;
				else if (informat == FORMAT_ASN1)
					tmpformat = FORMAT_ASN1RSA;
				}
			else if (informat == FORMAT_NETSCAPE && sgckey)
				tmpformat = FORMAT_IISSGC;
			else
				tmpformat = informat;
					
			pkey = load_pubkey(bio_err, infile, tmpformat, 1,
				passin, e, "Public Key");
			}
		else
			pkey = load_key(bio_err, infile,
				(informat == FORMAT_NETSCAPE && sgckey ?
					FORMAT_IISSGC : informat), 1,
				passin, e, "Private Key");

		if (pkey != NULL)
			rsa = EVP_PKEY_get1_RSA(pkey);
		EVP_PKEY_free(pkey);
	}

	if (rsa == NULL)
		{
		ERR_print_errors(bio_err);
		goto end;
		}

	if (outfile == NULL)
		{
		BIO_set_fp(out,OPENSSL_TYPE__FILE_STDOUT,BIO_NOCLOSE);
#ifdef OPENSSL_SYS_VMS
		{
		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
		out = BIO_push(tmpbio, out);
		}
#endif
		}
	else
		{
		if (BIO_write_filename(out,outfile) <= 0)
			{
			TINYCLR_SSL_PERROR(outfile);
			goto end;
			}
		}

	if (text) 
		if (!RSA_print(out,rsa,0))
			{
			TINYCLR_SSL_PERROR(outfile);
			ERR_print_errors(bio_err);
			goto end;
			}

	if (modulus)
		{
		BIO_printf(out,"Modulus=");
		BN_print(out,rsa->n);
		BIO_printf(out,"\n");
		}

	if (check)
		{
		int r = RSA_check_key(rsa);

		if (r == 1)
			BIO_printf(out,"RSA key ok\n");
		else if (r == 0)
			{
			unsigned long err;

			while ((err = ERR_peek_error()) != 0 &&
				ERR_GET_LIB(err) == ERR_LIB_RSA &&
				ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY &&
				ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE)
				{
				BIO_printf(out, "RSA key error: %s\n", ERR_reason_error_string(err));
				ERR_get_error(); /* remove e from error stack */
				}
			}
		
		if (r == -1 || ERR_peek_error() != 0) /* should happen only if r == -1 */
			{
			ERR_print_errors(bio_err);
			goto end;
			}
		}
		
	if (noout)
		{
		ret = 0;
		goto end;
		}
	BIO_printf(bio_err,"writing RSA key\n");
	if 	(outformat == FORMAT_ASN1) {
		if(pubout || pubin) 
			{
			if (pubout == 2)
				i=i2d_RSAPublicKey_bio(out,rsa);
			else
				i=i2d_RSA_PUBKEY_bio(out,rsa);
			}
		else i=i2d_RSAPrivateKey_bio(out,rsa);
	}
#ifndef OPENSSL_NO_RC4
	else if (outformat == FORMAT_NETSCAPE)
		{
		unsigned char *p,*pp;
		int size;

		i=1;
		size=i2d_RSA_NET(rsa,NULL,NULL, sgckey);
		if ((p=(unsigned char *)OPENSSL_malloc(size)) == NULL)
			{
			BIO_printf(bio_err,"Memory allocation failure\n");
			goto end;
			}
		pp=p;
		i2d_RSA_NET(rsa,&p,NULL, sgckey);
		BIO_write(out,(char *)pp,size);
		OPENSSL_free(pp);
		}
#endif
	else if (outformat == FORMAT_PEM) {
		if(pubout || pubin)
			{
			if (pubout == 2)
		    		i=PEM_write_bio_RSAPublicKey(out,rsa);
			else
		    		i=PEM_write_bio_RSA_PUBKEY(out,rsa);
			}
		else i=PEM_write_bio_RSAPrivateKey(out,rsa,
						enc,NULL,0,NULL,passout);
#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4)
	} else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) {
		EVP_PKEY *pk;
		pk = EVP_PKEY_new();
		EVP_PKEY_set1_RSA(pk, rsa);
		if (outformat == FORMAT_PVK)
			i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout);
		else if (pubin || pubout)
			i = i2b_PublicKey_bio(out, pk);
		else
			i = i2b_PrivateKey_bio(out, pk);
		EVP_PKEY_free(pk);
#endif
	} else	{
		BIO_printf(bio_err,"bad output format specified for outfile\n");
		goto end;
		}
	if (i <= 0)
		{
		BIO_printf(bio_err,"unable to write key\n");
		ERR_print_errors(bio_err);
		}
	else
		ret=0;
end:
	if(out != NULL) BIO_free_all(out);
	if(rsa != NULL) RSA_free(rsa);
	if(passin) OPENSSL_free(passin);
	if(passout) OPENSSL_free(passout);
	apps_shutdown();
	OPENSSL_EXIT(ret);
	}
Пример #21
0
bool SSLSocket::handleError(int64_t nr_bytes, bool is_init) {
  char esbuf[512];
  std::string ebuf;
  unsigned long ecode;

  bool retry = true;
  int err = SSL_get_error(m_data->m_handle, nr_bytes);
  switch (err) {
  case SSL_ERROR_ZERO_RETURN:
    /* SSL terminated (but socket may still be active) */
    retry = false;
    break;
  case SSL_ERROR_WANT_READ:
  case SSL_ERROR_WANT_WRITE:
    /* re-negotiation, or perhaps the SSL layer needs more
     * packets: retry in next iteration */
    errno = EAGAIN;
    retry = (is_init || m_data->m_is_blocked);
    break;
  case SSL_ERROR_SYSCALL:
    if (ERR_peek_error() == 0) {
      if (nr_bytes == 0) {
        if (ERR_get_error()) {
          raise_warning("SSL: fatal protocol error");
        }
        SSL_set_shutdown(m_data->m_handle,
                         SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
        setEof(true);
        retry = false;
      } else {
        raise_warning("SSL: %s", folly::errnoStr(errno).c_str());
        retry = false;
      }
      break;
    }
    /* fall through */
  default:
    /* some other error */
    ecode = ERR_get_error();
    switch (ERR_GET_REASON(ecode)) {
    case SSL_R_NO_SHARED_CIPHER:
      raise_warning("SSL_R_NO_SHARED_CIPHER: no suitable shared cipher "
                    "could be used.  This could be because the server is "
                    "missing an SSL certificate (local_cert context "
                    "option)");
      retry = false;
      break;

    default:
      do {
        // NULL is automatically added
        ERR_error_string_n(ecode, esbuf, sizeof(esbuf));
        if (!ebuf.empty()) {
          ebuf += '\n';
        }
        ebuf += esbuf;
      } while ((ecode = ERR_get_error()) != 0);

      raise_warning("SSL operation failed with code %d. %s%s",
                    err, !ebuf.empty() ? "OpenSSL Error messages:\n" : "",
                    !ebuf.empty() ? ebuf.c_str() : "");
    }

    retry = false;
    errno = 0;
  }

  return retry;
}
Пример #22
0
int
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
    const char *pkcs12_file_inline,
    bool load_ca_file
    )
{
  FILE *fp;
  EVP_PKEY *pkey;
  X509 *cert;
  STACK_OF(X509) *ca = NULL;
  PKCS12 *p12;
  int i;
  char password[256];

  ASSERT(NULL != ctx);

  if (!strcmp (pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline)
    {
      BIO *b64 = BIO_new(BIO_f_base64());
      BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline,
	  (int) strlen(pkcs12_file_inline));
      ASSERT(b64 && bio);
      BIO_push(b64, bio);
      p12 = d2i_PKCS12_bio(b64, NULL);
      if (!p12)
	msg(M_SSLERR, "Error reading inline PKCS#12 file");
      BIO_free(b64);
      BIO_free(bio);
    }
  else
    {
      /* Load the PKCS #12 file */
      if (!(fp = platform_fopen(pkcs12_file, "rb")))
	msg(M_SSLERR, "Error opening file %s", pkcs12_file);
      p12 = d2i_PKCS12_fp(fp, NULL);
      fclose(fp);
      if (!p12)
	msg(M_SSLERR, "Error reading PKCS#12 file %s", pkcs12_file);
    }

  /* Parse the PKCS #12 file */
  if (!PKCS12_parse(p12, "", &pkey, &cert, &ca))
   {
     pem_password_callback (password, sizeof(password) - 1, 0, NULL);
     /* Reparse the PKCS #12 file with password */
     ca = NULL;
     if (!PKCS12_parse(p12, password, &pkey, &cert, &ca))
      {
#ifdef ENABLE_MANAGEMENT
	      if (management && (ERR_GET_REASON (ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE))
		management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
#endif
	PKCS12_free(p12);
	return 1;
      }
   }
  PKCS12_free(p12);

  /* Load Certificate */
  if (!SSL_CTX_use_certificate (ctx->ctx, cert))
   msg (M_SSLERR, "Cannot use certificate");

  /* Load Private Key */
  if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey))
   msg (M_SSLERR, "Cannot use private key");
  warn_if_group_others_accessible (pkcs12_file);

  /* Check Private Key */
  if (!SSL_CTX_check_private_key (ctx->ctx))
   msg (M_SSLERR, "Private key does not match the certificate");

  /* Set Certificate Verification chain */
  if (load_ca_file)
   {
     /* Add CAs from PKCS12 to the cert store and mark them as trusted. 
      * They're also used to fill in the chain of intermediate certs as
      * necessary.
      */
     if (ca && sk_X509_num(ca))
      {
	for (i = 0; i < sk_X509_num(ca); i++)
	  {
	    if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
	      msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)");
	    if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i)))
	      msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)");
	  }
      }
   } else {
     /* If trusted CA certs were loaded from a PEM file, and we ignore the
      * ones in PKCS12, do load PKCS12-provided certs to the client extra
      * certs chain just in case they include intermediate CAs needed to
      * prove my identity to the other end. This does not make them trusted.
      */
     if (ca && sk_X509_num(ca))
      {
	for (i = 0; i < sk_X509_num(ca); i++)
	  {
	    if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i)))
	      msg (M_SSLERR, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)");
	  }
      }
   }
  return 0;
}
Пример #23
0
static int ma_tls_set_certs(MYSQL *mysql)
{
  char *certfile= mysql->options.ssl_cert,
       *keyfile= mysql->options.ssl_key;
  
  /* add cipher */
  if ((mysql->options.ssl_cipher && 
        mysql->options.ssl_cipher[0] != 0) &&
      SSL_CTX_set_cipher_list(SSL_context, mysql->options.ssl_cipher) == 0)
    goto error;

  /* ca_file and ca_path */
  if (SSL_CTX_load_verify_locations(SSL_context, 
                                    mysql->options.ssl_ca,
                                    mysql->options.ssl_capath) == 0)
  {
    if (mysql->options.ssl_ca || mysql->options.ssl_capath)
      goto error;
    if (SSL_CTX_set_default_verify_paths(SSL_context) == 0)
      goto error;
  }

  if (keyfile && !certfile)
    certfile= keyfile;
  if (certfile && !keyfile)
    keyfile= certfile;

  /* set cert */
  if (certfile  && certfile[0] != 0)  
    if (SSL_CTX_use_certificate_file(SSL_context, certfile, SSL_FILETYPE_PEM) != 1)
      goto error; 

  /* If the private key file is encrypted, we need to register a callback function
   * for providing password. */
  if (OPT_HAS_EXT_VAL(mysql, tls_pw))
  {
    SSL_CTX_set_default_passwd_cb_userdata(SSL_context, (void *)mysql->options.extension->tls_pw);
    SSL_CTX_set_default_passwd_cb(SSL_context, ma_tls_get_password);
  }

  if (keyfile && keyfile[0])
  {
    if (SSL_CTX_use_PrivateKey_file(SSL_context, keyfile, SSL_FILETYPE_PEM) != 1)
    {
      unsigned long err= ERR_peek_error();
      if (!(ERR_GET_LIB(err) == ERR_LIB_X509 &&
	  ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE))
        goto error;
    }
  }
  if (OPT_HAS_EXT_VAL(mysql, tls_pw))
  {
    SSL_CTX_set_default_passwd_cb_userdata(SSL_context, NULL);
    SSL_CTX_set_default_passwd_cb(SSL_context, NULL);
  }
  /* verify key */
  if (certfile && !SSL_CTX_check_private_key(SSL_context))
    goto error;
  
  if (mysql->options.extension &&
      (mysql->options.extension->ssl_crl || mysql->options.extension->ssl_crlpath))
  {
    X509_STORE *certstore;

    if ((certstore= SSL_CTX_get_cert_store(SSL_context)))
    {
      if (X509_STORE_load_locations(certstore, mysql->options.extension->ssl_crl,
                                               mysql->options.extension->ssl_crlpath) == 0)
        goto error;

      X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
    }
  }
  return 0;

error:
  ma_tls_set_error(mysql);
  return 1;
}
Пример #24
0
int
ssl_ctx_use_certificate_chain(SSL_CTX *ctx, char *buf, off_t len)
{
	int		 ret;
	BIO		*in;
	X509		*x;
	X509		*ca;
	unsigned long	 err;

	ret = 0;
	x = ca = NULL;

	if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB);
		goto end;
	}

	if ((x = PEM_read_bio_X509(in, NULL,
	    ctx->default_passwd_callback,
	    ctx->default_passwd_callback_userdata)) == NULL) {
		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
		goto end;
	}

	if (!SSL_CTX_use_certificate(ctx, x) || ERR_peek_error() != 0)
		goto end;

	/* If we could set up our certificate, now proceed to
	 * the CA certificates.
	 */

	if (ctx->extra_certs != NULL) {
		sk_X509_pop_free(ctx->extra_certs, X509_free);
		ctx->extra_certs = NULL;
	}

	while ((ca = PEM_read_bio_X509(in, NULL,
	    ctx->default_passwd_callback,
	    ctx->default_passwd_callback_userdata)) != NULL) {

		if (!SSL_CTX_add_extra_chain_cert(ctx, ca))
			goto end;
	}

	err = ERR_peek_last_error();
	if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
	    ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
		ERR_clear_error();
	else
		goto end;

	ret = 1;
end:
	if (ca != NULL)
		X509_free(ca);
	if (x != NULL)
		X509_free(x);
	if (in != NULL)
		BIO_free(in);
	return (ret);
}
Пример #25
0
/**
 * NOTE: From node.js
 *
 * Read a file that contains our certificate in "PEM" format,
 * possibly followed by a sequence of CA certificates that should be
 * sent to the peer in the Certificate message.
 *
 * Taken from OpenSSL - editted for style.
 */
int bud_context_use_certificate_chain(bud_context_t* ctx, BIO *in) {
  int ret;
  X509* x;
  X509* ca;
  int r;
  unsigned long err;
  bud_context_pkey_type_t type;
  bud_context_pem_t* pem;

  ERR_clear_error();

  ret = 0;
  x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
  pem = NULL;

  if (x == NULL) {
    SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
    goto end;
  }

  ret = SSL_CTX_use_certificate(ctx->ctx, x);
  SSL_CTX_select_current_cert(ctx->ctx, x);
  type = bud_config_pkey_type(x->cert_info->key->pkey);

  pem = &ctx->pem[type];
  pem->cert = x;
  pem->issuer = NULL;

  if (ERR_peek_error() != 0) {
    /* Key/certificate mismatch doesn't imply ret==0 ... */
    ret = 0;
  }

  if (ret) {
    while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
      /*
       * Extra cert - add it to store to make OpenSSL pick and send proper
       * certs automatically
       */
      r = SSL_CTX_add1_chain_cert(ctx->ctx, ca);
      if (!r) {
        X509_free(ca);
        ret = 0;
        goto end;
      }

      /**
       * Note that we must not free r if it was successfully
       * added to the chain (while we must free the main
       * certificate, since its reference count is increased
       * by SSL_CTX_use_certificate).
       */

      /* Find issuer */
      if (pem->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK)
        continue;
      pem->issuer = ca;
    }

    /* When the while loop ends, it's usually just EOF. */
    err = ERR_peek_last_error();
    if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
        ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
      ERR_clear_error();
    } else  {
      /* some real error */
      ret = 0;
    }
  }

end:
  if (ret) {
    /* Try getting issuer from cert store */
    if (pem->issuer == NULL) {
      X509_STORE* store;
      X509_STORE_CTX store_ctx;

      store = SSL_CTX_get_cert_store(ctx->ctx);
      ret = X509_STORE_CTX_init(&store_ctx, store, NULL, NULL);
      if (!ret)
        goto fatal;

      ret = X509_STORE_CTX_get1_issuer(&pem->issuer, &store_ctx, pem->cert);
      X509_STORE_CTX_cleanup(&store_ctx);

      ret = ret < 0 ? 0 : 1;
      /* NOTE: get_cert_store doesn't increment reference count */
    } else {
      /* Increment issuer reference count */
      CRYPTO_add(&pem->issuer->references, 1, CRYPTO_LOCK_X509);
    }

    if (pem->issuer != NULL) {
      /* Get ocsp_id */
      pem->ocsp_id = OCSP_cert_to_id(NULL, pem->cert, pem->issuer);
      if (pem->ocsp_id == NULL)
        goto fatal;
    }
  }

fatal:
  if (!ret && pem != NULL && pem->issuer != NULL) {
    X509_free(pem->issuer);
    pem->issuer = NULL;
  }

  if (!(pem != NULL && pem->cert == x) && x != NULL)
    X509_free(x);

  return ret;
}
Пример #26
0
void context_init(void) { /* init SSL */
    int i;

#if SSLEAY_VERSION_NUMBER >= 0x00907000L
    /* Load all bundled ENGINEs into memory and make them visible */
    ENGINE_load_builtin_engines();
    /* Register all of them for every algorithm they collectively implement */
    ENGINE_register_all_complete();
#endif
    if(!init_prng())
        log(LOG_INFO, "PRNG seeded successfully");
    SSLeay_add_ssl_algorithms();
    SSL_load_error_strings();
    if(options.option.client) {
        ctx=SSL_CTX_new(SSLv3_client_method());
    } else { /* Server mode */
        ctx=SSL_CTX_new(SSLv23_server_method());
#ifndef NO_RSA
        SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
#endif /* NO_RSA */
        if(init_dh())
            log(LOG_WARNING, "Diffie-Hellman initialization failed");
    }
    if(options.ssl_options) {
        log(LOG_DEBUG, "Configuration SSL options: 0x%08lX",
            options.ssl_options);
        log(LOG_DEBUG, "SSL options set: 0x%08lX", 
            SSL_CTX_set_options(ctx, options.ssl_options));
    }
#if SSLEAY_VERSION_NUMBER >= 0x00906000L
    SSL_CTX_set_mode(ctx,
        SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif /* OpenSSL-0.9.6 */

    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
    SSL_CTX_set_timeout(ctx, options.session_timeout);
    if(options.option.cert) {
        if(!SSL_CTX_use_certificate_chain_file(ctx, options.cert)) {
            log(LOG_ERR, "Error reading certificate file: %s", options.cert);
            sslerror("SSL_CTX_use_certificate_chain_file");
            exit(1);
        }
        log(LOG_DEBUG, "Certificate: %s", options.cert);
        log(LOG_DEBUG, "Key file: %s", options.key);
#ifdef USE_WIN32
        SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
#endif
        for(i=0; i<3; i++) {
#ifdef NO_RSA
            if(SSL_CTX_use_PrivateKey_file(ctx, options.key,
                    SSL_FILETYPE_PEM))
#else /* NO_RSA */
            if(SSL_CTX_use_RSAPrivateKey_file(ctx, options.key,
                    SSL_FILETYPE_PEM))
#endif /* NO_RSA */
                break;
            if(i<2 && ERR_GET_REASON(ERR_peek_error())==EVP_R_BAD_DECRYPT) {
                sslerror_stack(); /* dump the error stack */
                log(LOG_ERR, "Wrong pass phrase: retrying");
                continue;
            }
#ifdef NO_RSA
            sslerror("SSL_CTX_use_PrivateKey_file");
#else /* NO_RSA */
            sslerror("SSL_CTX_use_RSAPrivateKey_file");
#endif /* NO_RSA */
            exit(1);
        }
        if(!SSL_CTX_check_private_key(ctx)) {
            sslerror("Private key does not match the certificate");
            exit(1);
        }
    }

    verify_init(); /* Initialize certificate verification */

    SSL_CTX_set_info_callback(ctx, info_callback);

    if(options.cipher_list) {
        if (!SSL_CTX_set_cipher_list(ctx, options.cipher_list)) {
            sslerror("SSL_CTX_set_cipher_list");
            exit(1);
        }
    }
}
Пример #27
0
/* Read a file that contains our certificate in "PEM" format,
 * possibly followed by a sequence of CA certificates that should be
 * sent to the peer in the Certificate message.
 */
int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
	{
	BIO *in;
	int ret=0;
	X509 *x=NULL;

	ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */

	in=BIO_new(BIO_s_file_internal());
	if (in == NULL)
		{
		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_BUF_LIB);
		goto end;
		}

	if (BIO_read_filename(in,file) <= 0)
		{
		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_SYS_LIB);
		goto end;
		}

	x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
	if (x == NULL)
		{
		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_PEM_LIB);
		goto end;
		}

	ret=SSL_CTX_use_certificate(ctx,x);
	if (ERR_peek_error() != 0)
		ret = 0;  /* Key/certificate mismatch doesn't imply ret==0 ... */
	if (ret)
		{
		/* If we could set up our certificate, now proceed to
		 * the CA certificates.
		 */
		X509 *ca;
		int r;
		unsigned long err;
		
		if (ctx->extra_certs != NULL) 
			{
			sk_X509_pop_free(ctx->extra_certs, X509_free);
			ctx->extra_certs = NULL;
			}

		while ((ca = PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata))
			!= NULL)
			{
			r = SSL_CTX_add_extra_chain_cert(ctx, ca);
			if (!r) 
				{
				X509_free(ca);
				ret = 0;
				goto end;
				}
			/* Note that we must not free r if it was successfully
			 * added to the chain (while we must free the main
			 * certificate, since its reference count is increased
			 * by SSL_CTX_use_certificate). */
			}
		/* When the while loop ends, it's usually just EOF. */
		err = ERR_peek_last_error();
		if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
			ERR_clear_error();
		else 
			ret = 0; /* some real error */
		}

end:
	if (x != NULL) X509_free(x);
	if (in != NULL) BIO_free(in);
	return(ret);
	}
Пример #28
0
int main(int argc, char *argv[])
{
    const char *hostport = HOSTPORT;
    const char *CAfile = CAFILE;
    char *hostname;
    char *cp;
    BIO *out = NULL;
    char buf[1024 * 10], *p;
    SSL_CTX *ssl_ctx = NULL;
    SSL *ssl;
    BIO *ssl_bio;
    int i, len, off, ret = EXIT_FAILURE;

    if (argc > 1)
        hostport = argv[1];
    if (argc > 2)
        CAfile = argv[2];

    hostname = OPENSSL_strdup(hostport);
    if ((cp = strchr(hostname, ':')) != NULL)
        *cp = 0;

#ifdef WATT32
    dbug_init();
    sock_init();
#endif

    ssl_ctx = SSL_CTX_new(TLS_client_method());

    /* Enable trust chain verification */
    SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_load_verify_locations(ssl_ctx, CAfile, NULL);

    /* Lets make a SSL structure */
    ssl = SSL_new(ssl_ctx);
    SSL_set_connect_state(ssl);

    /* Enable peername verification */
    if (SSL_set1_host(ssl, hostname) <= 0)
        goto err;

    /* Use it inside an SSL BIO */
    ssl_bio = BIO_new(BIO_f_ssl());
    BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);

    /* Lets use a connect BIO under the SSL BIO */
    out = BIO_new(BIO_s_connect());
    BIO_set_conn_hostname(out, hostport);
    BIO_set_nbio(out, 1);
    out = BIO_push(ssl_bio, out);

    p = "GET / HTTP/1.0\r\n\r\n";
    len = strlen(p);

    off = 0;
    for (;;) {
        i = BIO_write(out, &(p[off]), len);
        if (i <= 0) {
            if (BIO_should_retry(out)) {
                fprintf(stderr, "write DELAY\n");
                sleep(1);
                continue;
            } else {
                goto err;
            }
        }
        off += i;
        len -= i;
        if (len <= 0)
            break;
    }

    for (;;) {
        i = BIO_read(out, buf, sizeof(buf));
        if (i == 0)
            break;
        if (i < 0) {
            if (BIO_should_retry(out)) {
                fprintf(stderr, "read DELAY\n");
                sleep(1);
                continue;
            }
            goto err;
        }
        fwrite(buf, 1, i, stdout);
    }

    ret = EXIT_SUCCESS;
    goto done;

 err:
    if (ERR_peek_error() == 0) { /* system call error */
        fprintf(stderr, "errno=%d ", errno);
        perror("error");
    } else {
        ERR_print_errors_fp(stderr);
    }
 done:
    BIO_free_all(out);
    SSL_CTX_free(ssl_ctx);
    return ret;
}
Пример #29
0
void ssl_log(server_rec *s, int level, const char *msg, ...)
{
    char tstr[80];
    char lstr[20];
    char vstr[1024];
    char str[1024];
    char nstr[2];
    int timz;
    struct tm *t;
    va_list ap;
    int add;
    int i;
    char *astr;
    int safe_errno;
    unsigned long e;
    SSLSrvConfigRec *sc;
    char *cpE;
    char *cpA;

    /*  initialization  */
    va_start(ap, msg);
    safe_errno = errno;
    sc = mySrvConfig(s);

    /*  strip out additional flags  */
    add   = (level & ~SSL_LOG_MASK);
    level = (level & SSL_LOG_MASK);

    /*  reduce flags when not reasonable in context  */
    if (add & SSL_ADD_ERRNO && errno == 0)
        add &= ~SSL_ADD_ERRNO;
    if (add & SSL_ADD_SSLERR && ERR_peek_error() == 0)
        add &= ~SSL_ADD_SSLERR;

    /*  we log only levels below, except for errors */
    if (   sc->fileLogFile == NULL
        && !(level & SSL_LOG_ERROR))
        return;
    if (   level > sc->nLogLevel
        && !(level & SSL_LOG_ERROR))
        return;

    /*  determine the time entry string  */
    if (add & SSL_NO_TIMESTAMP)
        tstr[0] = NUL;
    else {
        t = ap_get_gmtoff(&timz);
        strftime(tstr, 80, "[%d/%b/%Y %H:%M:%S", t);
        i = strlen(tstr);
        ap_snprintf(tstr+i, 80-i, " %05d] ", (unsigned int)getpid());
    }

    /*  determine whether newline should be written */
    if (add & SSL_NO_NEWLINE)
        nstr[0] = NUL;
    else {
        nstr[0] = '\n';
        nstr[1] = NUL;
    }

    /*  determine level name  */
    lstr[0] = NUL;
    if (!(add & SSL_NO_LEVELID)) {
        for (i = 0; ssl_log_level2string[i].nLevel != 0; i++) {
            if (ssl_log_level2string[i].nLevel == level) {
                ap_snprintf(lstr, sizeof(lstr), "[%s]", ssl_log_level2string[i].szLevel);
                break;
            }
        }
        for (i = strlen(lstr); i <= 7; i++)
            lstr[i] = ' ';
        lstr[i] = NUL;
    }

    /*  create custom message  */
    ap_vsnprintf(vstr, sizeof(vstr), msg, ap);

    /*  write out SSLog message  */
    if ((add & SSL_ADD_ERRNO) && (add & SSL_ADD_SSLERR))
        astr = " (System and " SSL_LIBRARY_NAME " library errors follow)";
    else if (add & SSL_ADD_ERRNO)
        astr = " (System error follows)";
    else if (add & SSL_ADD_SSLERR)
        astr = " (" SSL_LIBRARY_NAME " library error follows)";
    else
        astr = "";
    if (level <= sc->nLogLevel && sc->fileLogFile != NULL) {
        ap_snprintf(str, sizeof(str), "%s%s%s%s%s", tstr, lstr, vstr, astr, nstr);
        fprintf(sc->fileLogFile, "%s", str);
    }
    if (level & SSL_LOG_ERROR)
        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s,
                     "mod_ssl: %s%s", vstr, astr);

    /*  write out additional attachment messages  */
    if (add & SSL_ADD_ERRNO) {
        if (level <= sc->nLogLevel && sc->fileLogFile != NULL) {
            ap_snprintf(str, sizeof(str), "%s%sSystem: %s (errno: %d)%s",
                        tstr, lstr, strerror(safe_errno), safe_errno, nstr);
            fprintf(sc->fileLogFile, "%s", str);
        }
        if (level & SSL_LOG_ERROR)
            ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s,
                         "System: %s (errno: %d)",
                         strerror(safe_errno), safe_errno);
    }
    if (add & SSL_ADD_SSLERR) {
        while ((e = ERR_get_error())) {
            cpE = ERR_error_string(e, NULL);
            cpA = ssl_log_annotation(cpE);
            if (level <= sc->nLogLevel && sc->fileLogFile != NULL) {
                ap_snprintf(str, sizeof(str), "%s%s%s: %s%s%s%s%s",
                            tstr, lstr, SSL_LIBRARY_NAME, cpE,
                            cpA != NULL ? " [Hint: " : "",
                            cpA != NULL ? cpA : "", cpA != NULL ? "]" : "",
                            nstr);
                fprintf(sc->fileLogFile, "%s", str);
            }
            if (level & SSL_LOG_ERROR)
                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s,
                             "%s: %s%s%s%s", SSL_LIBRARY_NAME, cpE,
                             cpA != NULL ? " [Hint: " : "",
                             cpA != NULL ? cpA : "", cpA != NULL ? "]" : "");
        }
    }
    /* make sure the next log starts from a clean base */
    /* ERR_clear_error(); */

    /*  cleanup and return  */
    if (sc->fileLogFile != NULL)
        fflush(sc->fileLogFile);
    errno = safe_errno;
    va_end(ap);
    return;
}
Пример #30
0
bool TLS_SOCKET_CLASS::writeBinary(const BYTE *buffer_ptr, UINT length)

//  DESCRIPTION     : Write given data to socket.
//  PRECONDITIONS   :
//  POSTCONDITIONS  :
//  EXCEPTIONS      : 
//  NOTES           :
//<<===========================================================================
{
	int written_bytes = 0;
	int readFileDesc;
	int writeFileDesc;
	struct fd_set readFds;
	struct fd_set writeFds;
	bool waitOnWrite;
	int timeoutRemaining; // the amount of time left in the timeout period
	struct timeval tv = {1, 0}; // always timeout in 1 second

	if (terminatingM)
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - In process of terminating.  Cannot write.");
		}

		// return - in process of termintating
		return false;
	}

	if (loggerM_ptr) 
	{
		loggerM_ptr->text(LOG_DEBUG, 1, "Secure Socket - tls::write(%d bytes)", length);
	}

	if (!connectedM) 
	{
		if (loggerM_ptr) 
		{
			loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Not connected to peer - can't write data");
		}

		return false;
	}

	// get the file descriptors and set up the file descriptor sets for select()
	readFileDesc = SSL_get_rfd(sslM_ptr);
	if (readFileDesc == -1)
	{
		openSslError("getting read socket file descriptor");
		return false;
	}

	writeFileDesc = SSL_get_wfd(sslM_ptr);
	if (writeFileDesc == -1)
	{
		openSslError("getting write socket file descriptor");
		return false;
	}

	waitOnWrite = true;
	timeoutRemaining = socketTimeoutM;

	// write the buffer contents to socket
	while (written_bytes < (int) length)
	{
		int bytes;
		int sel;

		if (waitOnWrite)
		{
			FD_ZERO(&writeFds);
			FD_SET(writeFileDesc, &writeFds);

			// wait for something to write
			sel = select(writeFileDesc + 1, NULL, &writeFds, NULL, &tv);
		}
		else
		{
			FD_ZERO(&readFds);
			FD_SET(readFileDesc, &readFds);

			// wait for something to read
			sel = select(readFileDesc + 1, &readFds, NULL, NULL, &tv);
		}

		if (terminatingM)
		{
			return false;
		}

		waitOnWrite = true;

		if (sel == 1)
		{
			// data read to write (or possibly read - but use the same call)
			bytes = SSL_write(sslM_ptr, (char *)(buffer_ptr + written_bytes), (length - written_bytes));
			if (bytes > 0)
			{
				// wrote some data
				written_bytes += bytes;
				timeoutRemaining = socketTimeoutM; // reset the timeout
			}
			else if (bytes == 0)
			{
				// socket closed
				if (loggerM_ptr)
				{
					loggerM_ptr->text(LOG_ERROR, 1, "Secure Socket - Secure connection closed during socket write");
				}
				return false;
			}
			else
			{
				// operation did not complete, see what happened
				int err = SSL_get_error(sslM_ptr, bytes);
				if (err == SSL_ERROR_WANT_READ)
				{
					// need to wait for data to be available for reading, and then retry the same operation
					waitOnWrite = false;
					timeoutRemaining = socketTimeoutM; // reset the timeout
				}
				if (err == SSL_ERROR_WANT_WRITE)
				{
					// need to wait for the write file descriptor to be able to write and then try again
					timeoutRemaining = socketTimeoutM; // reset the timeout
				}
				else
				{
					// an error occured
					if ((err == SSL_ERROR_SYSCALL) && (ERR_peek_error() == 0) && (bytes == -1))
					{
						// an error in the system call occured
						openSslError("writing to secure socket");
						if (loggerM_ptr && (loggerM_ptr->getLogMask() & LOG_ERROR))
						{
							loggerM_ptr->text(LOG_NONE, 1, "    write() error code = %d", WSAGetLastError());
						}
					}
					else
					{
						openSslError("reading from secure socket");
					}
					return false;
				}
			}
		}
		else if (sel == 0)
		{
			// no data at the end of the timeout
			if (--timeoutRemaining > 0)
			{
				// still have time left on the timeout, go back and wait some more
			}
			else
			{
				// timeout expired
				if (loggerM_ptr)
				{
					loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Connection timed-out while waiting to send data");
				}
				return false;
			}
		}
		else if (sel == SOCKET_ERROR)
		{
			// socket error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Error waiting to send data (error code %d)", WSAGetLastError());
			}
			return false;
		}
		else
		{
			// unknown error
			if (loggerM_ptr)
			{
				loggerM_ptr->text(LOG_ERROR, 2, "Secure Socket - Unknown error while waiting to send data (select returned %d)", sel);
			}
			return false;
		}
	}

	return (written_bytes == (int) length) ? true : false;
}