/* * 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 #include 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); }