diff options
Diffstat (limited to 'libvncserver/rfbssl_openssl.c')
-rw-r--r-- | libvncserver/rfbssl_openssl.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/libvncserver/rfbssl_openssl.c b/libvncserver/rfbssl_openssl.c new file mode 100644 index 0000000..cbd6865 --- /dev/null +++ b/libvncserver/rfbssl_openssl.c @@ -0,0 +1,135 @@ +/* + * rfbssl_openssl.c - Secure socket funtions (openssl version) + */ + +/* + * Copyright (C) 2011 Gernot Tenchio + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "rfbssl.h" +#include <openssl/ssl.h> +#include <openssl/err.h> + +struct rfbssl_ctx { + SSL_CTX *ssl_ctx; + SSL *ssl; +}; + +static void rfbssl_error(void) +{ + char buf[1024]; + unsigned long e = ERR_get_error(); + rfbErr("%s (%ld)\n", ERR_error_string(e, buf), e); +} + +int rfbssl_init(rfbClientPtr cl) +{ + char *keyfile; + int r, ret = -1; + struct rfbssl_ctx *ctx; + + SSL_library_init(); + SSL_load_error_strings(); + + if (cl->screen->sslkeyfile && *cl->screen->sslkeyfile) { + keyfile = cl->screen->sslkeyfile; + } else { + keyfile = cl->screen->sslcertfile; + } + + if (NULL == (ctx = malloc(sizeof(struct rfbssl_ctx)))) { + rfbErr("OOM\n"); + } else if (!cl->screen->sslcertfile || !cl->screen->sslcertfile[0]) { + rfbErr("SSL connection but no cert specified\n"); + } else if (NULL == (ctx->ssl_ctx = SSL_CTX_new(TLSv1_server_method()))) { + rfbssl_error(); + } else if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, keyfile, SSL_FILETYPE_PEM) <= 0) { + rfbErr("Unable to load private key file %s\n", keyfile); + } else if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, cl->screen->sslcertfile, SSL_FILETYPE_PEM) <= 0) { + rfbErr("Unable to load certificate file %s\n", cl->screen->sslcertfile); + } else if (NULL == (ctx->ssl = SSL_new(ctx->ssl_ctx))) { + rfbErr("SSL_new failed\n"); + rfbssl_error(); + } else if (!(SSL_set_fd(ctx->ssl, cl->sock))) { + rfbErr("SSL_set_fd failed\n"); + rfbssl_error(); + } else { + while ((r = SSL_accept(ctx->ssl)) < 0) { + if (SSL_get_error(ctx->ssl, r) != SSL_ERROR_WANT_READ) + break; + } + if (r < 0) { + rfbErr("SSL_accept failed %d\n", SSL_get_error(ctx->ssl, r)); + } else { + cl->sslctx = (rfbSslCtx *)ctx; + ret = 0; + } + } + return ret; +} + +int rfbssl_write(rfbClientPtr cl, const char *buf, int bufsize) +{ + int ret; + struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx; + + while ((ret = SSL_write(ctx->ssl, buf, bufsize)) <= 0) { + if (SSL_get_error(ctx->ssl, ret) != SSL_ERROR_WANT_WRITE) + break; + } + return ret; +} + +int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize) +{ + int ret; + struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx; + + while ((ret = SSL_peek(ctx->ssl, buf, bufsize)) <= 0) { + if (SSL_get_error(ctx->ssl, ret) != SSL_ERROR_WANT_READ) + break; + } + return ret; +} + +int rfbssl_read(rfbClientPtr cl, char *buf, int bufsize) +{ + int ret; + struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx; + + while ((ret = SSL_read(ctx->ssl, buf, bufsize)) <= 0) { + if (SSL_get_error(ctx->ssl, ret) != SSL_ERROR_WANT_READ) + break; + } + return ret; +} + +int rfbssl_pending(rfbClientPtr cl) +{ + struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx; + return SSL_pending(ctx->ssl); +} + +void rfbssl_destroy(rfbClientPtr cl) +{ + struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx; + if (ctx->ssl) + SSL_free(ctx->ssl); + if (ctx->ssl_ctx) + SSL_CTX_free(ctx->ssl_ctx); +} |