Exemple #1
0
/** Given an SSL object and its last known state, attempt to write to it.
 * \param ssl pointer to SSL object.
 * \param state saved state of SSL object.
 * \param net_read_ready 1 if the underlying socket is ready for read.
 * \param net_write_ready 1 if the underlying socket is ready for write.
 * \param buf buffer to write.
 * \param bufsize length of buffer to write.
 * \param offset pointer to offset into buffer marking where to write next.
 * \return new state of SSL object, or -1 if the connection closed.
 */
int
ssl_write(SSL *ssl, int state, int net_read_ready, int net_write_ready,
          const char *buf, int bufsize, int *offset)
{
  int r;
  if ((net_write_ready && bufsize) || (net_read_ready && !(state & MYSSL_WBOR))) {
    state &= ~(MYSSL_WBOR | MYSSL_WB);
    r = SSL_write(ssl, buf + *offset, bufsize);
    switch (SSL_get_error(ssl, r)) {
    case SSL_ERROR_NONE:
      /* We wrote something, but maybe not all */
      *offset += r;
      break;
    case SSL_ERROR_WANT_WRITE:
      /* Underlying socket isn't ready to be written to. */
      ssl_debugdump("SSL_write wants write");
      state |= MYSSL_WB;
      break;
    case SSL_ERROR_WANT_READ:
      /* More needs to be read from the underlying socket first.
       * This can happen during a rehandshake.
       */
      ssl_debugdump("SSL_write wants read");
      state |= MYSSL_WBOR;
      break;
    default:
      /* Should never happen */
      ssl_errordump("Unknown ssl_write failure!");
    }
  }
  return state;
}
Exemple #2
0
/** Perform an SSL handshake.
 * In some cases, a handshake may block, so we may have to call this
 * function again. Accordingly, we return state information that
 * tells us if we need to do that.
 * \param ssl pointer to an SSL object.
 * \return resulting state of the object.
 */
int
ssl_handshake(SSL *ssl)
{
  int ret;
  int state = 0;

  if ((ret = SSL_do_handshake(ssl)) <= 0) {
    switch (SSL_get_error(ssl, ret)) {
    case SSL_ERROR_WANT_READ:
      /* We must want for the socket to be readable, and then repeat
       * the call.
       */
      ssl_debugdump("SSL_do_handshake wants read");
      state = MYSSL_RB | MYSSL_HANDSHAKE;
      break;
    case SSL_ERROR_WANT_WRITE:
      /* We must want for the socket to be writable, and then repeat
       * the call.
       */
      ssl_debugdump("SSL_do_handshake wants write");
      state = MYSSL_WB | MYSSL_HANDSHAKE;
      break;
    default:
      /* Oops, don't know what's wrong */
      ssl_errordump("Error in ssl_handshake");
      state = -1;
    }
  } else {
    state = ssl_accept(ssl);
  }
  return state;
}
Exemple #3
0
/** Call SSL_accept and return the connection state.
 * \param ssl pointer to an SSL object.
 * \return ssl state flags indicating success, pending, or failure.
 */
int
ssl_accept(SSL *ssl)
{
  int ret;
  int state = 0;
  X509 *peer;
  char buf[256];

  if ((ret = SSL_accept(ssl)) <= 0) {
    switch (SSL_get_error(ssl, ret)) {
    case SSL_ERROR_WANT_READ:
      /* We must want for the socket to be readable, and then repeat
       * the call.
       */
      ssl_debugdump("SSL_accept wants read");
      state = MYSSL_RB | MYSSL_ACCEPT;
      break;
    case SSL_ERROR_WANT_WRITE:
      /* We must want for the socket to be writable, and then repeat
       * the call.
       */
      ssl_debugdump("SSL_accept wants write");
      state = MYSSL_WB | MYSSL_ACCEPT;
      break;
    default:
      /* Oops, don't know what's wrong */
      ssl_errordump("Error accepting connection");
      return -1;
    }
  } else {
    /* Successful accept - report it */
    if ((peer = SSL_get_peer_certificate(ssl))) {
      if (SSL_get_verify_result(ssl) == X509_V_OK) {
        /* The client sent a certificate which verified OK */
        X509_NAME_oneline(X509_get_subject_name(peer), buf, 256);
        lock_file(stderr);
        fprintf(stderr, "SSL client certificate accepted: %s", buf);
        unlock_file(stderr);
        state |= MYSSL_VERIFIED;
      }
    }
  }

  return state;
}
Exemple #4
0
/** Given an SSL object and its last known state, attempt to read from it.
 * \param ssl pointer to SSL object.
 * \param state saved state of SSL object.
 * \param net_read_ready 1 if the underlying socket is ready for read.
 * \param net_write_ready 1 if the underlying socket is ready for write.
 * \param buf buffer to read into.
 * \param bufsize number of bytes to read.
 * \param bytes_read pointer to return the number of bytes read.
 * \return new state of SSL object, or -1 if the connection closed.
 */
int
ssl_read(SSL *ssl, int state, int net_read_ready, int net_write_ready,
         char *buf, int bufsize, int *bytes_read)
{
  if ((net_read_ready && !(state & MYSSL_WBOR)) ||
      (net_write_ready && (state & MYSSL_RBOW))) {
    do {
      state &= ~(MYSSL_RB | MYSSL_RBOW);
      *bytes_read = SSL_read(ssl, buf, bufsize);
      switch (SSL_get_error(ssl, *bytes_read)) {
      case SSL_ERROR_NONE:
        /* Yay */
        return state;
      case SSL_ERROR_ZERO_RETURN:
        /* End of data on this socket */
        return -1;
      case SSL_ERROR_WANT_READ:
        /* More needs to be read from the underlying socket */
        ssl_debugdump("SSL_read wants read");
        state |= MYSSL_RB;
        break;
      case SSL_ERROR_WANT_WRITE:
        /* More needs to be written to the underlying socket.
         * This can happen during a rehandshake.
         */
        ssl_debugdump("SSL_read wants write");
        state |= MYSSL_RBOW;
        break;
      default:
        /* Should never happen */
        ssl_errordump("Unknown ssl_read failure!");
        return -1;
      }
    } while (SSL_pending(ssl) && !(state & MYSSL_RB));
  }
  return state;
}
Exemple #5
0
/** Initialize the SSL context.
 * \return pointer to SSL context object.
 */
SSL_CTX *
ssl_init(char *private_key_file, char *ca_file, int req_client_cert)
{
  const SSL_METHOD *meth;       /* If this const gives you a warning, you're
                                   using an old version of OpenSSL. Walker, this means you! */
  /* uint8_t context[128]; */
  DH *dh;
  unsigned int reps = 1;

  if (!bio_err) {
    if (!SSL_library_init())
      return NULL;
    SSL_load_error_strings();
    /* Error write context */
    bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
  }

  lock_file(stderr);
  fputs("Seeding OpenSSL random number pool.\n", stderr);
  unlock_file(stderr);
  while (!RAND_status()) {
    /* At this point, a system with /dev/urandom or a EGD file in the usual
       places will have enough entropy. Otherwise, be lazy and use random numbers
       until it's satisfied. */
    uint32_t gibberish[4];
    int n;

    /* sfmt_fill_array32 requires a much larger array. */
    for (n = 0; n < 4; n++)
      gibberish[n] = sfmt_genrand_uint32(&rand_state);

    RAND_seed(gibberish, sizeof gibberish);

    reps += 1;
  }

  lock_file(stderr);
  fprintf(stderr, "Seeded after %u %s.\n", reps, reps > 1 ? "cycles" : "cycle");
  unlock_file(stderr);

  /* Set up SIGPIPE handler here? */

  /* Create context */
  meth = SSLv23_server_method();
  ctx = SSL_CTX_new(meth);

  /* Load keys/certs */
  if (private_key_file && *private_key_file) {
    if (!SSL_CTX_use_certificate_chain_file(ctx, private_key_file)) {
      ssl_errordump
        ("Unable to load server certificate - only anonymous ciphers supported.");
    }
    if (!SSL_CTX_use_PrivateKey_file(ctx, private_key_file, SSL_FILETYPE_PEM)) {
      ssl_errordump
        ("Unable to load private key - only anonymous ciphers supported.");
    }
  }

  /* Load trusted CAs */
  if (ca_file && *ca_file) {
    if (!SSL_CTX_load_verify_locations(ctx, ca_file, NULL)) {
      ssl_errordump("Unable to load CA certificates");
    } else {
      if (req_client_cert)
        SSL_CTX_set_verify(ctx,
                           SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
                           client_verify_callback);
      else
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, client_verify_callback);
#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
      SSL_CTX_set_verify_depth(ctx, 1);
#endif
    }
  }

  SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE | SSL_OP_ALL);
  SSL_CTX_set_mode(ctx,
                   SSL_MODE_ENABLE_PARTIAL_WRITE |
                   SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

  /* Set up DH callback */
  dh = get_dh1024();
  SSL_CTX_set_tmp_dh(ctx, dh);
  /* The above function makes a private copy of this */
  DH_free(dh);

  /* Set the cipher list to the usual default list, except that
   * we'll allow anonymous diffie-hellman, too.
   */
  SSL_CTX_set_cipher_list(ctx, "ALL:ADH:RC4+RSA:+SSLv2:@STRENGTH");

  /* Set up session cache if we can */
  /*
     strncpy((char *) context, MUDNAME, 128);
     SSL_CTX_set_session_id_context(ctx, context, strlen(context));
   */

  return ctx;
}
Exemple #6
0
/** Initialize the SSL context.
 * \return pointer to SSL context object.
 */
SSL_CTX *
ssl_init(char *private_key_file, char *ca_file, char *ca_dir,
         int req_client_cert)
{
  const SSL_METHOD
    *meth; /* If this const gives you a warning, you're
              using an old version of OpenSSL. Walker, this means you! */
  /* uint8_t context[128]; */
  unsigned int reps = 1;
  pcg32_random_t rand_state;
  uint64_t seeds[2];
  bool seeded = false;

  if (!bio_err) {
    if (!SSL_library_init())
      return NULL;
    SSL_load_error_strings();
    /* Error write context */
    bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
  }

  lock_file(stderr);
  fputs("Seeding OpenSSL random number pool.\n", stderr);
  unlock_file(stderr);
  while (!RAND_status()) {
    /* At this point, a system with /dev/urandom or a EGD file in the usual
       places will have enough entropy. Otherwise, be lazy and use random
       numbers until it's satisfied. */
    uint32_t gibberish[8];
    int n;

    if (!seeded) {
      generate_seed(seeds);
      pcg32_srandom_r(&rand_state, seeds[0], seeds[1]);
      seeded = 1;
    }

    for (n = 0; n < 8; n++)
      gibberish[n] = pcg32_random_r(&rand_state);

    RAND_seed(gibberish, sizeof gibberish);

    reps += 1;
  }

  lock_file(stderr);
  fprintf(stderr, "Seeded after %u %s.\n", reps, reps > 1 ? "cycles" : "cycle");
  unlock_file(stderr);

  /* Set up SIGPIPE handler here? */

  /* Create context */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
  meth = TLS_server_method();
#else
  meth = SSLv23_server_method();
#endif
  ctx = SSL_CTX_new(meth);
  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);

  /* Load keys/certs */
  if (private_key_file && *private_key_file) {
    if (!SSL_CTX_use_certificate_chain_file(ctx, private_key_file)) {
      ssl_errordump("Unable to load server certificate - only anonymous "
                    "ciphers supported.");
    }
    if (!SSL_CTX_use_PrivateKey_file(ctx, private_key_file, SSL_FILETYPE_PEM)) {
      ssl_errordump(
        "Unable to load private key - only anonymous ciphers supported.");
    }
  }

  /* Load trusted CAs */
  if ((ca_file && *ca_file) || (ca_dir && *ca_dir)) {
    if (!SSL_CTX_load_verify_locations(ctx,
                                       (ca_file && *ca_file) ? ca_file : NULL,
                                       (ca_dir && *ca_dir) ? ca_dir : NULL)) {
      ssl_errordump("Unable to load CA certificates");
    }
    {
      STACK_OF(X509_NAME) *certs = NULL;
      if (ca_file && *ca_file)
        certs = SSL_load_client_CA_file(ca_file);
      if (certs)
        SSL_CTX_set_client_CA_list(ctx, certs);

      if (req_client_cert)
        SSL_CTX_set_verify(ctx,
                           SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
                           client_verify_callback);
      else
        SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, client_verify_callback);
#if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
      SSL_CTX_set_verify_depth(ctx, 1);
#endif
    }
  }

  SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE | SSL_OP_ALL);
  SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |
                          SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

  /* Set up DH key */
  {
    DH *dh;
    dh = get_dh2048();
    SSL_CTX_set_tmp_dh(ctx, dh);
    DH_free(dh);
  }

#ifdef NID_X9_62_prime256v1
  /* Set up ECDH key */
  {
    EC_KEY *ecdh = NULL;
    ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
    SSL_CTX_set_tmp_ecdh(ctx, ecdh);
    EC_KEY_free(ecdh);
  }
#endif

  /* Set the cipher list to the usual default list, except that
   * we'll allow anonymous diffie-hellman, too.
   */
  SSL_CTX_set_cipher_list(ctx, "ALL:ECDH:ADH:!LOW:!MEDIUM:@STRENGTH");

  /* Set up session cache if we can */
  /*
     strncpy((char *) context, MUDNAME, 128);
     SSL_CTX_set_session_id_context(ctx, context, strlen(context));
   */

  return ctx;
}