openbsd-ports/comms/amtterm/patches/patch-ssl_c
2022-03-11 18:26:24 +00:00

460 lines
8.9 KiB
Plaintext

Add SSL/auth code
https://github.com/Openwsman/wsmancli/issues/10#issuecomment-751253133
Index: ssl.c
--- ssl.c.orig
+++ ssl.c
@@ -0,0 +1,452 @@
+/*
+ * SSL helper functions.
+ *
+ * Copyright (C) 2014 Andreas Steinmetz <ast@domdv.de>
+ *
+ * This program 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 program 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 program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#if defined(USE_OPENSSL)
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#elif defined(USE_GNUTLS)
+#include <gnutls/gnutls.h>
+#endif
+
+#include "ssl.h"
+
+struct ctx
+{
+ int fd;
+#if defined(USE_OPENSSL)
+ SSL *ssl;
+ SSL_CTX *ctx;
+#elif defined(USE_GNUTLS)
+ gnutls_session_t ssl;
+ gnutls_certificate_credentials_t cred;
+#endif
+};
+
+static struct ctx *newctx(int fd)
+{
+ struct ctx *ctx;
+
+ if(!(ctx=malloc(sizeof(struct ctx))))
+ {
+ perror("malloc");
+ return NULL;
+ }
+
+ memset(ctx,0,sizeof(struct ctx));
+
+ ctx->fd=fd;
+
+ return ctx;
+}
+
+#if defined(USE_OPENSSL)
+
+struct ctx *sslinit(int fd,char *cacert)
+{
+ int r;
+ int c=0;
+ struct ctx *ctx;
+
+ if(!(ctx=newctx(fd)))return NULL;
+
+ if(!cacert)return ctx;
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ if(!(ctx->ctx=SSL_CTX_new(SSLv23_client_method())))
+ {
+ ERR_print_errors_fp(stderr);
+ goto err1;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ SSL_CTX_set_options(ctx->ctx,
+ SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2);
+#endif
+
+ if(!SSL_CTX_load_verify_locations(ctx->ctx,cacert,NULL))
+ {
+ ERR_print_errors_fp(stderr);
+ goto err2;
+ }
+
+ SSL_CTX_set_verify_depth(ctx->ctx,5);
+ SSL_CTX_set_verify(ctx->ctx,SSL_VERIFY_PEER,NULL);
+
+ if(!(ctx->ssl=SSL_new(ctx->ctx)))
+ {
+ ERR_print_errors_fp(stderr);
+ goto err2;
+ }
+
+ if(!SSL_set_fd(ctx->ssl,ctx->fd))
+ {
+ ERR_print_errors_fp(stderr);
+ goto err3;
+ }
+
+repeat: if((r=SSL_connect(ctx->ssl))!=1)
+ {
+ switch(SSL_get_error(ctx->ssl,r))
+ {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ if(++c<100)
+ {
+ usleep(10000);
+ goto repeat;
+ }
+ }
+ ERR_print_errors_fp(stderr);
+ goto err3;
+ }
+
+ return ctx;
+
+err3: SSL_free(ctx->ssl);
+err2: SSL_CTX_free(ctx->ctx);
+err1: free(ctx);
+ return NULL;
+}
+
+void sslexit(struct ctx *ctx)
+{
+ if(ctx->ssl)
+ {
+ SSL_shutdown(ctx->ssl);
+ SSL_free(ctx->ssl);
+ SSL_CTX_free(ctx->ctx);
+ }
+ free(ctx);
+}
+
+int sslready(struct ctx *ctx)
+{
+ if(ctx->ssl)return SSL_pending(ctx->ssl);
+ else return 0;
+}
+
+ssize_t sslread(struct ctx *ctx,void *buf,size_t count)
+{
+ int l;
+ int c=0;
+
+ if(!ctx->ssl)return read(ctx->fd,buf,count);
+ if(!count)return 0;
+
+repeat: if((l=SSL_read(ctx->ssl,buf,count))>0)return l;
+
+ switch(SSL_get_error(ctx->ssl,l))
+ {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ if(++c<100)
+ {
+ usleep(10000);
+ goto repeat;
+ }
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return -1;
+ case SSL_ERROR_ZERO_RETURN:
+ return 0;
+ case SSL_ERROR_SSL:
+ ERR_print_errors_fp(stderr);
+ }
+
+ return -1;
+}
+
+ssize_t sslwrite(struct ctx *ctx,const void *buf,size_t count)
+{
+ int l;
+ int c=0;
+
+ if(!ctx->ssl)return write(ctx->fd,buf,count);
+ if(!count)return 0;
+
+repeat: if((l=SSL_write(ctx->ssl,buf,count))>0)return l;
+
+ switch(SSL_get_error(ctx->ssl,l))
+ {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ if(++c<100)
+ {
+ usleep(10000);
+ goto repeat;
+ }
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return -1;
+ case SSL_ERROR_ZERO_RETURN:
+ return 0;
+ case SSL_ERROR_SSL:
+ ERR_print_errors_fp(stderr);
+ }
+
+ return -1;
+}
+
+#elif defined(USE_GNUTLS)
+
+static int vrycb(gnutls_session_t ssl)
+{
+ int r;
+ int type;
+ unsigned int status;
+ gnutls_datum_t msg;
+
+ if((r=gnutls_certificate_verify_peers3(ssl,NULL,&status))<0)
+ {
+ fprintf(stderr,"gnutls_certificate_verify_peers3: %s\n",
+ gnutls_strerror(r));
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ if(status)
+ {
+ type=gnutls_certificate_type_get(ssl);
+ if((r=gnutls_certificate_verification_status_print(status,type,
+ &msg,0))<0)
+ {
+ fprintf(stderr,"gnutls_certificate_verification_"
+ "status_print %s\n",gnutls_strerror(r));
+ }
+ else
+ {
+ fprintf(stderr,"certificate status: %s\n",msg.data);
+ gnutls_free(msg.data);
+ }
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ return 0;
+}
+
+struct ctx *sslinit(int fd,char *cacert)
+{
+ int r;
+ const char *e;
+ struct ctx *ctx;
+
+ if(!(ctx=newctx(fd)))return NULL;
+
+ if(!cacert)return ctx;
+
+ if((r=gnutls_global_init()))
+ {
+ fprintf(stderr,"gnutls_global_init: %s\n",gnutls_strerror(r));
+ goto err1;
+ }
+
+ if((r=gnutls_certificate_allocate_credentials(&ctx->cred)))
+ {
+ fprintf(stderr,"gnutls_certificate_allocate_credentials: "
+ "%s\n",gnutls_strerror(r));
+ goto err2;
+ }
+
+ if((r=gnutls_certificate_set_x509_trust_file(ctx->cred,cacert,
+ GNUTLS_X509_FMT_PEM))<0)
+ {
+ fprintf(stderr,"gnutls_certificate_set_x509_trust_file: "
+ "%s\n",gnutls_strerror(r));
+ goto err3;
+ }
+
+ gnutls_certificate_set_verify_function(ctx->cred,vrycb);
+
+ if((r=gnutls_init(&ctx->ssl,GNUTLS_CLIENT)))
+ {
+ fprintf(stderr,"gnutls_init: %s\n",gnutls_strerror(r));
+ goto err3;
+ }
+
+ /* oh well, isn't _that_ easy ?!? :-( ... compare to openssl ... */
+ if((r=gnutls_priority_set_direct(ctx->ssl,"NONE:+AES-256-CBC:"
+ "+AES-128-CBC:+3DES-CBC:+COMP-NULL:+CTYPE-X509:+VERS-SSL3.0:"
+ "+SHA256:+SHA1:+RSA:%UNSAFE_RENEGOTIATION",&e)))
+ {
+ fprintf(stderr,"gnutls_priority_set_direct: %s\n",
+ gnutls_strerror(r));
+ if(r==GNUTLS_E_INVALID_REQUEST)
+ fprintf(stderr,"additional info: %s\n",e);
+ goto err4;
+ }
+
+ if((r=gnutls_credentials_set(ctx->ssl,GNUTLS_CRD_CERTIFICATE,
+ ctx->cred)))
+ {
+ fprintf(stderr,"gnutls_credentials_set: %s\n",
+ gnutls_strerror(r));
+ goto err4;
+ }
+
+ gnutls_transport_set_int(ctx->ssl,ctx->fd);
+
+ gnutls_handshake_set_timeout(ctx->ssl,GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+
+ do
+ {
+ r=gnutls_handshake(ctx->ssl);
+ } while(r<0&&!gnutls_error_is_fatal(r));
+ if(r<0)
+ {
+ fprintf(stderr,"gnutls_handshake: %s\n",gnutls_strerror(r));
+ goto err4;
+ }
+
+ return ctx;
+
+err4: gnutls_deinit(ctx->ssl);
+err3: gnutls_certificate_free_credentials(ctx->cred);
+err2: gnutls_global_deinit();
+err1: free(ctx);
+ return NULL;
+}
+
+void sslexit(struct ctx *ctx)
+{
+ if(ctx->ssl)
+ {
+ gnutls_deinit(ctx->ssl);
+ gnutls_certificate_free_credentials(ctx->cred);
+ gnutls_global_deinit();
+ }
+ free(ctx);
+}
+
+int sslready(struct ctx *ctx)
+{
+ if(ctx->ssl)return gnutls_record_check_pending(ctx->ssl);
+ else return 0;
+}
+
+ssize_t sslread(struct ctx *ctx,void *buf,size_t count)
+{
+ ssize_t l;
+ int c=0;
+ int r;
+
+ if(!ctx->ssl)return read(ctx->fd,buf,count);
+ if(!count)return 0;
+
+repeat: if((l=gnutls_record_recv(ctx->ssl,buf,count))>0)return l;
+
+ switch(l)
+ {
+ case GNUTLS_E_REHANDSHAKE:
+ do
+ {
+ r=gnutls_handshake(ctx->ssl);
+ } while(r<0&&!gnutls_error_is_fatal(r));
+ if(r<0)
+ {
+ fprintf(stderr,"gnutls_handshake: %s\n",
+ gnutls_strerror(r));
+ return -1;
+ }
+ case GNUTLS_E_INTERRUPTED:
+ case GNUTLS_E_AGAIN:
+ if(++c<100)
+ {
+ usleep(10000);
+ goto repeat;
+ }
+ default:fprintf(stderr,"gnutls_record_recv: %s\n",gnutls_strerror(l));
+ case GNUTLS_E_PUSH_ERROR:
+ case GNUTLS_E_PULL_ERROR:
+ return -1;
+ }
+}
+
+ssize_t sslwrite(struct ctx *ctx,const void *buf,size_t count)
+{
+ ssize_t l;
+ int c=0;
+ int r;
+
+ if(!ctx->ssl)return write(ctx->fd,buf,count);
+ if(!count)return 0;
+
+repeat: if((l=gnutls_record_send(ctx->ssl,buf,count))>0)return l;
+
+ switch(l)
+ {
+ case GNUTLS_E_REHANDSHAKE:
+ do
+ {
+ r=gnutls_handshake(ctx->ssl);
+ } while(r<0&&!gnutls_error_is_fatal(r));
+ if(r<0)
+ {
+ fprintf(stderr,"gnutls_handshake: %s\n",
+ gnutls_strerror(r));
+ return -1;
+ }
+ case GNUTLS_E_INTERRUPTED:
+ case GNUTLS_E_AGAIN:
+ if(++c<100)
+ {
+ usleep(10000);
+ goto repeat;
+ }
+ default:fprintf(stderr,"gnutls_record_send: %s\n",gnutls_strerror(l));
+ case GNUTLS_E_PUSH_ERROR:
+ case GNUTLS_E_PULL_ERROR:
+ return -1;
+ }
+}
+
+#else
+
+struct ctx *sslinit(int fd,char *cacert)
+{
+ return newctx(fd);
+}
+
+void sslexit(struct ctx *ctx)
+{
+ free(ctx);
+}
+
+int sslready(struct ctx *ctx)
+{
+ return 0;
+}
+
+ssize_t sslread(struct ctx *ctx,void *buf,size_t count)
+{
+ return read(ctx->fd,buf,count);
+}
+
+ssize_t sslwrite(struct ctx *ctx,const void *buf,size_t count)
+{
+ return write(ctx->fd,buf,count);
+}
+
+#endif