示例#1
0
ssize_t
tls_write(struct tls *ctx, const void *buf, size_t buflen)
{
	ssize_t rv = -1;
	int ssl_ret;

	tls_error_clear(&ctx->error);

	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
		if ((rv = tls_handshake(ctx)) != 0)
			goto out;
	}

	if (buflen > INT_MAX) {
		tls_set_errorx(ctx, "buflen too long");
		goto out;
	}

	ERR_clear_error();
	if ((ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen)) > 0) {
		rv = (ssize_t)ssl_ret;
		goto out;
	}
	rv = (ssize_t)tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "write");

 out:
	/* Prevent callers from performing incorrect error handling */
	errno = 0;
	return (rv);
}
示例#2
0
int
tls_close(struct tls *ctx)
{
	int ssl_ret;
	int rv = 0;

	if (ctx->ssl_conn != NULL) {
		ssl_ret = SSL_shutdown(ctx->ssl_conn);
		if (ssl_ret < 0) {
			rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret,
			    "shutdown");
			if (rv == TLS_READ_AGAIN || rv == TLS_WRITE_AGAIN)
				return (rv);
		}
	}

	if (ctx->socket != -1) {
		if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
			if (rv == 0 &&
			    errno != ENOTCONN && errno != ECONNRESET) {
				tls_set_error(ctx, "shutdown");
				rv = -1;
			}
		}
		if (close(ctx->socket) != 0) {
			if (rv == 0) {
				tls_set_error(ctx, "close");
				rv = -1;
			}
		}
		ctx->socket = -1;
	}

	return (rv);
}
示例#3
0
int
tls_close(struct tls *ctx)
{
	int ssl_ret;
	int rv = 0;

	tls_error_clear(&ctx->error);

	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
		tls_set_errorx(ctx, "invalid operation for context");
		rv = -1;
		goto out;
	}

	if (ctx->state & TLS_SSL_NEEDS_SHUTDOWN) {
		ERR_clear_error();
		ssl_ret = SSL_shutdown(ctx->ssl_conn);
		if (ssl_ret < 0) {
			rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret,
			    "shutdown");
			if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
				goto out;
		}
		ctx->state &= ~TLS_SSL_NEEDS_SHUTDOWN;
	}

	if (ctx->socket != -1) {
		if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
			if (rv == 0 &&
			    errno != ENOTCONN && errno != ECONNRESET) {
				tls_set_error(ctx, "shutdown");
				rv = -1;
			}
		}
		if (close(ctx->socket) != 0) {
			if (rv == 0) {
				tls_set_error(ctx, "close");
				rv = -1;
			}
		}
		ctx->socket = -1;
	}

	if ((ctx->state & TLS_EOF_NO_CLOSE_NOTIFY) != 0) {
		tls_set_errorx(ctx, "EOF without close notify");
		rv = -1;
	}

 out:
	/* Prevent callers from performing incorrect error handling */
	errno = 0;
	return (rv);
}
示例#4
0
文件: tls.c 项目: markokr/libusual
static int
tls_do_abort(struct tls *ctx)
{
	int ssl_ret, rv;

	ssl_ret = SSL_shutdown(ctx->ssl_conn);
	if (ssl_ret < 0) {
		rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "shutdown");
		if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
			return (rv);
	}

	tls_set_errorx(ctx, "unexpected handshake, closing connection");
	return -1;
}
示例#5
0
int
tls_handshake_client(struct tls *ctx)
{
	X509 *cert = NULL;
	int match, ssl_ret;
	int rv = -1;

	if ((ctx->flags & TLS_CLIENT) == 0) {
		tls_set_errorx(ctx, "not a client context");
		goto err;
	}

	if ((ctx->state & TLS_CONNECTED) == 0) {
		tls_set_errorx(ctx, "context not connected");
		goto err;
	}

	ctx->state |= TLS_SSL_NEEDS_SHUTDOWN;

	ERR_clear_error();
	if ((ssl_ret = SSL_connect(ctx->ssl_conn)) != 1) {
		rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "handshake");
		goto err;
	}

	if (ctx->config->verify_name) {
		cert = SSL_get_peer_certificate(ctx->ssl_conn);
		if (cert == NULL) {
			tls_set_errorx(ctx, "no server certificate");
			goto err;
		}
		if (tls_check_name(ctx, cert, ctx->servername, &match) == -1)
			goto err;
		if (!match) {
			tls_set_errorx(ctx, "name `%s' not present in"
			    " server certificate", ctx->servername);
			goto err;
		}
	}

	ctx->state |= TLS_HANDSHAKE_COMPLETE;
	rv = 0;

 err:
	X509_free(cert);

	return (rv);
}
示例#6
0
文件: tls.c 项目: flrl/openbsd
int
tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen)
{
	int ssl_ret;

	if (buflen > INT_MAX) {
		tls_set_error(ctx, "buflen too long");
		return (-1);
	}

	ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen);
	if (ssl_ret > 0) {
		*outlen = (size_t)ssl_ret;
		return (0);
	}

	return tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "write"); 
}
示例#7
0
文件: tls_server.c 项目: kitche/httpd
int
tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write)
{
	struct tls *conn_ctx = *cctx;
	int ret, err;
	
	if ((ctx->flags & TLS_SERVER) == 0) {
		tls_set_error(ctx, "not a server context");
		goto err;
	}

	if (conn_ctx == NULL) {
		if ((conn_ctx = tls_server_conn(ctx)) == NULL) {
			tls_set_error(ctx, "connection context failure");
			goto err;
		}
		*cctx = conn_ctx;

		if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
			tls_set_error(ctx, "ssl failure");
			goto err;
		}

		if (SSL_set_rfd(conn_ctx->ssl_conn, fd_read) != 1 ||
		    SSL_set_wfd(conn_ctx->ssl_conn, fd_write) != 1) {
			tls_set_error(ctx, "ssl set fd failure");
			goto err;
		}
		SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx);
	}

	if ((ret = SSL_accept(conn_ctx->ssl_conn)) != 1) {
		err = tls_ssl_error(ctx, conn_ctx->ssl_conn, ret, "accept");
		if (err == TLS_READ_AGAIN || err == TLS_WRITE_AGAIN) {
			return (err);
		}
		goto err;
	}

	return (0);

err:
	return (-1);
}
示例#8
0
int
tls_handshake_server(struct tls *ctx)
{
	int ssl_ret;
	int rv = -1;

	if ((ctx->flags & TLS_SERVER_CONN) == 0) {
		tls_set_errorx(ctx, "not a server connection context");
		goto err;
	}

	ERR_clear_error();
	if ((ssl_ret = SSL_accept(ctx->ssl_conn)) != 1) {
		rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "handshake");
		goto err;
	}

	ctx->state |= TLS_HANDSHAKE_COMPLETE;
	rv = 0;

 err:
	return (rv);
}
示例#9
0
int
tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen)
{
	int ssl_ret;

	*outlen = 0;

	if (buflen > INT_MAX) {
		tls_set_errorx(ctx, "buflen too long");
		return (-1);
	}

	if (ctx->state & TLS_STATE_ABORT)
		return tls_do_abort(ctx);

	ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen);
	if (ssl_ret > 0) {
		*outlen = (size_t)ssl_ret;
		return (0);
	}

	return tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "write"); 
}
示例#10
0
int
tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
    const char *servername)
{
	union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
	X509 *cert = NULL;
	int ret, err;

	if (ctx->flags & TLS_CONNECTING)
		goto connecting;

	if ((ctx->flags & TLS_CLIENT) == 0) {
		tls_set_error(ctx, "not a client context");
		goto err;
	}

	if (fd_read < 0 || fd_write < 0) {
		tls_set_error(ctx, "invalid file descriptors");
		return (-1);
	}

	if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
		tls_set_error(ctx, "ssl context failure");
		goto err;
	}

	if (tls_configure_ssl(ctx) != 0)
		goto err;

	if (ctx->config->verify_name) {
		if (servername == NULL) {
			tls_set_error(ctx, "server name not specified");
			goto err;
		}
	}

	if (ctx->config->verify_cert) {
		SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);

		if (ctx->config->ca_mem != NULL) {
			if (ctx->config->ca_len > INT_MAX) {
				tls_set_error(ctx, "ca too long");
				goto err;
			}

			if (SSL_CTX_load_verify_mem(ctx->ssl_ctx,
			    ctx->config->ca_mem, ctx->config->ca_len) != 1) {
				tls_set_error(ctx,
				    "ssl verify memory setup failure");
				goto err;
			}
		} else if (SSL_CTX_load_verify_locations(ctx->ssl_ctx,
		    ctx->config->ca_file, ctx->config->ca_path) != 1) {
			tls_set_error(ctx, "ssl verify setup failure");
			goto err;
		}
		if (ctx->config->verify_depth >= 0)
			SSL_CTX_set_verify_depth(ctx->ssl_ctx,
			    ctx->config->verify_depth);
	}

	if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
		tls_set_error(ctx, "ssl connection failure");
		goto err;
	}
	if (SSL_set_rfd(ctx->ssl_conn, fd_read) != 1 ||
	    SSL_set_wfd(ctx->ssl_conn, fd_write) != 1) {
		tls_set_error(ctx, "ssl file descriptor failure");
		goto err;
	}

	/*
	 * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not
	 * permitted in "HostName".
	 */
	if (servername != NULL &&
	    inet_pton(AF_INET, servername, &addrbuf) != 1 &&
	    inet_pton(AF_INET6, servername, &addrbuf) != 1) {
		if (SSL_set_tlsext_host_name(ctx->ssl_conn, servername) == 0) {
			tls_set_error(ctx, "server name indication failure");
			goto err;
		}
	}

 connecting:
	if ((ret = SSL_connect(ctx->ssl_conn)) != 1) {
		err = tls_ssl_error(ctx, ret, "connect");
		if (err == TLS_READ_AGAIN || err == TLS_WRITE_AGAIN) {
			ctx->flags |= TLS_CONNECTING;
			return (err);
		}
		goto err;
	}
	ctx->flags &= ~TLS_CONNECTING;

	if (ctx->config->verify_name) {
		cert = SSL_get_peer_certificate(ctx->ssl_conn);
		if (cert == NULL) {
			tls_set_error(ctx, "no server certificate");
			goto err;
		}
		if ((ret = tls_check_servername(ctx, cert, servername)) != 0) {
			if (ret != -2)
				tls_set_error(ctx, "name `%s' not present in"
				    " server certificate", servername);
			goto err;
		}
	}

	return (0);

err:
	X509_free(cert);

	return (-1);
}