static bool login_via_cert(PgSocket *client)
{
struct tls *tls = client->sbuf.tls;
- struct tls_cert *cert;
- struct tls_cert_dname *subj;
if (!tls) {
disconnect_client(client, true, "TLS connection required");
return false;
}
- if (tls_get_peer_cert(client->sbuf.tls, &cert, NULL) < 0 || !cert) {
+ if (!tls_peer_cert_provided(client->sbuf.tls)) {
disconnect_client(client, true, "TLS client certificate required");
return false;
}
- subj = &cert->subject;
- log_debug("TLS cert login: CN=%s/C=%s/L=%s/ST=%s/O=%s/OU=%s",
- subj->common_name ? subj->common_name : "(null)",
- subj->country_name ? subj->country_name : "(null)",
- subj->locality_name ? subj->locality_name : "(null)",
- subj->state_or_province_name ? subj->state_or_province_name : "(null)",
- subj->organization_name ? subj->organization_name : "(null)",
- subj->organizational_unit_name ? subj->organizational_unit_name : "(null)");
- if (!subj->common_name) {
- disconnect_client(client, true, "Invalid TLS certificate");
- goto fail;
- }
- if (strcmp(subj->common_name, client->auth_user->name) != 0) {
+ log_debug("TLS cert login: %s", tls_peer_cert_subject(client->sbuf.tls));
+ if (!tls_peer_cert_contains_name(client->sbuf.tls, client->auth_user->name)) {
disconnect_client(client, true, "TLS certificate name mismatch");
- goto fail;
+ return false;
}
- tls_cert_free(cert);
/* login successful */
return finish_client_login(client);
-fail:
- tls_cert_free(cert);
- return false;
}
static bool login_as_unix_peer(PgSocket *client)
tls_sbufio_send,
tls_sbufio_close
};
-static void sbuf_tls_accept_cb(int fd, short flags, void *_sbuf);
-static void sbuf_tls_connect_cb(int fd, short flags, void *_sbuf);
+static void sbuf_tls_handshake_cb(int fd, short flags, void *_sbuf);
#endif
/*********************************
log_error("Invalid %s_cert_file: %s", pfx, certfile);
}
- if (sslmode == SSLMODE_VERIFY_FULL) {
- tls_config_verify(conf);
- } else if (sslmode == SSLMODE_VERIFY_CA) {
- tls_config_insecure_noverifyname(conf);
+ if (does_connect) {
+ /* TLS client, check server? */
+ if (sslmode == SSLMODE_VERIFY_FULL) {
+ tls_config_verify(conf);
+ } else if (sslmode == SSLMODE_VERIFY_CA) {
+ tls_config_verify(conf);
+ tls_config_insecure_noverifyname(conf);
+ } else {
+ tls_config_insecure_noverifycert(conf);
+ tls_config_insecure_noverifyname(conf);
+ }
} else {
- tls_config_insecure_noverifycert(conf);
- tls_config_insecure_noverifyname(conf);
+ /* TLS server, check client? */
+ if (sslmode == SSLMODE_VERIFY_FULL) {
+ tls_config_verify_client_optional(conf);
+ } else if (sslmode == SSLMODE_VERIFY_CA) {
+ tls_config_verify_client_optional(conf);
+ }
}
}
}
/*
- * Accept TLS connection.
+ * TLS handshake
*/
-static bool handle_tls_accept(struct SBuf *sbuf)
+static bool handle_tls_handshake(SBuf *sbuf)
{
int err;
- err = tls_accept_fds(client_accept_base, &sbuf->tls, sbuf->sock, sbuf->sock);
- log_noise("tls_accept_fds: err=%d", err);
- if (err == TLS_READ_AGAIN) {
- return sbuf_use_callback_once(sbuf, EV_READ, sbuf_tls_accept_cb);
- } else if (err == TLS_WRITE_AGAIN) {
- return sbuf_use_callback_once(sbuf, EV_WRITE, sbuf_tls_accept_cb);
+ err = tls_handshake(sbuf->tls);
+ log_noise("tls_handshake: err=%d", err);
+ if (err == TLS_WANT_POLLIN) {
+ return sbuf_use_callback_once(sbuf, EV_READ, sbuf_tls_handshake_cb);
+ } else if (err == TLS_WANT_POLLOUT) {
+ return sbuf_use_callback_once(sbuf, EV_WRITE, sbuf_tls_handshake_cb);
} else if (err == 0) {
sbuf_call_proto(sbuf, SBUF_EV_TLS_READY);
return true;
} else {
- log_warning("TLS accept error: %s", tls_error(sbuf->tls));
+ log_warning("TLS handshake error: %s", tls_error(sbuf->tls));
return false;
}
}
-static void sbuf_tls_accept_cb(int fd, short flags, void *_sbuf)
+static void sbuf_tls_handshake_cb(int fd, short flags, void *_sbuf)
{
SBuf *sbuf = _sbuf;
sbuf->wait_type = W_NONE;
- if (!handle_tls_accept(sbuf))
+ if (!handle_tls_handshake(sbuf))
sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED);
}
-bool sbuf_tls_accept(SBuf *sbuf)
-{
- sbuf->ops = &tls_sbufio_ops;
- return handle_tls_accept(sbuf);
-}
-
/*
- * Connect to remote TLS host.
+ * Accept TLS connection.
*/
-static bool handle_tls_connect(SBuf *sbuf)
+bool sbuf_tls_accept(SBuf *sbuf)
{
int err;
- err = tls_connect_fds(sbuf->tls, sbuf->sock, sbuf->sock, sbuf->tls_host);
- log_noise("tls_connect_fds: err=%d", err);
- if (err == TLS_READ_AGAIN) {
- return sbuf_use_callback_once(sbuf, EV_READ, sbuf_tls_connect_cb);
- } else if (err == TLS_WRITE_AGAIN) {
- return sbuf_use_callback_once(sbuf, EV_WRITE, sbuf_tls_connect_cb);
- } else if (err == 0) {
- sbuf_call_proto(sbuf, SBUF_EV_TLS_READY);
- return true;
- } else {
- log_warning("TLS connect error: %s", tls_error(sbuf->tls));
+ sbuf->ops = &tls_sbufio_ops;
+
+ err = tls_accept_fds(client_accept_base, &sbuf->tls, sbuf->sock, sbuf->sock);
+ log_noise("tls_accept_fds: err=%d", err);
+ if (err < 0) {
+ log_warning("TLS accept error: %s", tls_error(sbuf->tls));
return false;
}
-}
-static void sbuf_tls_connect_cb(int fd, short flags, void *_sbuf)
-{
- SBuf *sbuf = _sbuf;
- sbuf->wait_type = W_NONE;
- if (!handle_tls_connect(sbuf))
- sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED);
+ return handle_tls_handshake(sbuf);
}
+/*
+ * Connect to remote TLS host.
+ */
+
bool sbuf_tls_connect(SBuf *sbuf, const char *hostname)
{
struct tls *ctls;
if (!ctls)
return false;
err = tls_configure(ctls, server_connect_conf);
- if (err) {
+ if (err < 0) {
log_error("tls client config failed: %s", tls_error(ctls));
tls_free(ctls);
return false;
sbuf->tls_host = hostname;
sbuf->ops = &tls_sbufio_ops;
- return handle_tls_connect(sbuf);
+ err = tls_connect_fds(sbuf->tls, sbuf->sock, sbuf->sock, sbuf->tls_host);
+ if (err < 0) {
+ log_warning("TLS connect error: %s", tls_error(sbuf->tls));
+ return false;
+ }
+
+ return handle_tls_handshake(sbuf);
}
/*
static int tls_sbufio_recv(struct SBuf *sbuf, void *dst, unsigned int len)
{
- int err;
- size_t out = 0;
+ ssize_t out = 0;
- err = tls_read(sbuf->tls, dst, len, &out);
- log_noise("tls_read: req=%u err=%d out=%d", len, err, (int)out);
- if (!err) {
+ out = tls_read(sbuf->tls, dst, len);
+ log_noise("tls_read: req=%u out=%d", len, (int)out);
+ if (out >= 0) {
return out;
- } else if (err == TLS_READ_AGAIN) {
+ } else if (out == TLS_WANT_POLLIN) {
errno = EAGAIN;
- } else if (err == TLS_WRITE_AGAIN) {
- log_warning("tls_sbufio_recv: got TLS_WRITE_AGAIN");
+ } else if (out == TLS_WANT_POLLOUT) {
+ log_warning("tls_sbufio_recv: got TLS_WANT_POLLOUT");
errno = EIO;
} else {
log_warning("tls_sbufio_recv: %s", tls_error(sbuf->tls));
static int tls_sbufio_send(struct SBuf *sbuf, const void *data, unsigned int len)
{
- size_t out = 0;
- int err;
+ ssize_t out;
- err = tls_write(sbuf->tls, data, len, &out);
- log_noise("tls_write: req=%u err=%d out=%d", len, err, (int)out);
- if (!err) {
+ out = tls_write(sbuf->tls, data, len);
+ log_noise("tls_write: req=%u out=%d", len, (int)out);
+ if (out >= 0) {
return out;
- } else if (err == TLS_WRITE_AGAIN) {
+ } else if (out == TLS_WANT_POLLOUT) {
errno = EAGAIN;
- } else if (err == TLS_READ_AGAIN) {
- log_warning("tls_sbufio_send: got TLS_READ_AGAIN");
+ } else if (out == TLS_WANT_POLLIN) {
+ log_warning("tls_sbufio_send: got TLS_WANT_POLLIN");
errno = EIO;
} else {
log_warning("tls_sbufio_send: %s", tls_error(sbuf->tls));