
// Configure a client connection context.  Send a hendshake for the
// highest supported TLS version, and disable compression.
const SSL_METHOD *const req_method = SSLv23_client_method();
SSL_CTX *const ctx = SSL_CTX_new(req_method);
if (ctx == NULL) {
  ERR_print_errors(bio_err);
  exit(1);
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);

// Adjust the ciphers list based on a whitelist.  First enable all
// ciphers of at least medium strength, to get the list which is
// compiled into OpenSSL.
if (SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM") != 1) {
  ERR_print_errors(bio_err);
  exit(1);
}
{
  // Create a dummy SSL session to obtain the cipher list.
  SSL *ssl = SSL_new(ctx);
  if (ssl == NULL) {
    ERR_print_errors(bio_err);
    exit(1);
  }
  STACK_OF(SSL_CIPHER) *active_ciphers = SSL_get_ciphers(ssl);
  if (active_ciphers == NULL) {
    ERR_print_errors(bio_err);
    exit(1);
  }
  // Whitelist of candidate ciphers.
  static const char *const candidates[] =  {
    "AES128-GCM-SHA256", "AES128-SHA256", "AES256-SHA256", // strong ciphers
    "AES128-SHA", "AES256-SHA", // strong ciphers, also in older versions
    "RC4-SHA", "RC4-MD5", // backwards compatibility, supposed to be weak
    "DES-CBC3-SHA", "DES-CBC3-MD5", // more backwards compatibility
    NULL
  };
  // Actually selected ciphers.
  char ciphers[300];
  ciphers[0] = '\0';
  for (const char *const *c = candidates; *c; ++c) {
    for (int i = 0; i < sk_SSL_CIPHER_num(active_ciphers); ++i) {
	if (strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(active_ciphers, i)),
		   *c) == 0) {
	  if (*ciphers) {
	    strcat(ciphers, ":");
	  }
	  strcat(ciphers, *c);
	  break;
	}
    }
  }
  SSL_free(ssl);
  // Apply final cipher list.
  if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) {
    ERR_print_errors(bio_err);
    exit(1);
  }
}

// Load the set of trusted root certificates.
if (!SSL_CTX_set_default_verify_paths(ctx)) {
  ERR_print_errors(bio_err);
  exit(1);
}

