commit a5ffe13b1502e01adb7da16b879eb99e3c55d49d
parent d6b9c4355d3a6e4cd4d1e0f58ad3b26d10144728
Author: parazyd <parazyd@dyne.org>
Date:   Thu,  1 Mar 2018 00:47:39 +0100
Add net functionality.
Currently supports fetching a TLS certificate fingerprint.
Diffstat:
5 files changed, 195 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
@@ -5,7 +5,7 @@
 include config.mk
 
 BIN = $(NAME)
-OBJ = $(BIN:=.o) headers.o ind.o sieve.o
+OBJ = $(BIN:=.o) headers.o ind.o sieve.o net.o
 
 all: $(BIN)
 	cp -f $(NAME) bin
diff --git a/config.mk b/config.mk
@@ -5,8 +5,10 @@ PREFIX = /usr/local
 SHAREPREFIX = $(PREFIX)/share/$(NAME)
 MANPREFIX = $(PREFIX)/share/man
 
-CFLAGS = -O2 -Wall -pedantic
-LDFLAGS = -static -s
+CFLAGS = -O2 -Wall -pedantic -std=gnu99
+LDFLAGS = -static -s -lssl -lcrypto
 
 .c.o:
 	$(CC) $(CFLAGS) -c $<
+
+CC = cc
diff --git a/net.c b/net.c
@@ -0,0 +1,164 @@
+/*
+ * Copy me if you can
+ * by 20h and parazyd
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+
+#include "arg.h"
+#include "ind.h"
+#include "net.h"
+
+char *argv0;
+
+/*
+ * net format:
+ * net!addr!service
+ */
+enum {
+	NET_NET = 0x00,
+	NET_TCP,
+	NET_TCPS
+};
+
+static char *netnames[] = {
+	[NET_NET] = "net",
+	[NET_TCP] = "tcp",
+	[NET_TCPS] = "tcps"
+};
+
+void netusage(void) {
+	die("usage: %s [-f host port]\n"
+		"    -f: fetch and print ssl certificate fingerprint\n", argv0);
+}
+
+int net_gettype(char *str) {
+	int i;
+
+	for (i = 0; i < nelem(netnames); i++)
+		if (!strcmp(netnames[i], str))
+			return i;
+	return -1;
+}
+
+net_t *net_new(char *type, char *addr, char *port) {
+	net_t *ret;
+
+	ret = malloc(sizeof(net_t));
+
+	ret->type = net_gettype(type);
+	ret->addr = addr;
+	ret->service = port;
+
+	return ret;
+}
+
+int sslfpr(net_t *net) {
+	int i;
+	unsigned int fpr_size;
+	SSL *sfd;
+	X509 *cert;
+
+	const EVP_MD *fpr_type;
+	unsigned char fpr[EVP_MAX_MD_SIZE];
+
+	struct addrinfo hints, *ai, *rp;
+
+	bzero(&hints, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = IPPROTO_TCP;
+
+
+	if (getaddrinfo(net->addr, net->service, &hints, &ai))
+		return 1;
+	if (ai == NULL)
+		return 1;
+
+	SSL_library_init();
+	OpenSSL_add_all_algorithms();
+
+	net->data[1] = SSL_CTX_new(SSLv23_client_method());
+	if (net->data[1] == NULL)
+		goto sslfprerr;
+	SSL_CTX_set_options((SSL_CTX *)net->data[1],
+			SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
+
+	for (rp = ai; rp != NULL; rp = rp->ai_next) {
+		net->fd = socket(rp->ai_family, rp->ai_socktype,
+				rp->ai_protocol);
+		if (connect(net->fd, rp->ai_addr, rp->ai_addrlen))
+			break;
+
+		if ((sfd = SSL_new((SSL_CTX *)net->data[1])) == NULL)
+			goto sslfprerr;
+		SSL_set_fd(sfd, net->fd);
+		if (SSL_connect(sfd) < 1)
+			goto sslfprerr;
+
+
+		cert = SSL_get_peer_certificate(sfd);
+		if (cert == NULL)
+			goto sslfprerr;
+
+		fpr_type = EVP_sha1();
+		if (!X509_digest(cert, fpr_type, fpr, &fpr_size))
+			goto sslfprerr;
+
+		for (i = 0; i < fpr_size; i++)
+			printf("%02X%c", fpr[i], (i+1 == fpr_size) ? '\n':':');
+
+		X509_free(cert);
+		SSL_CTX_free(net->data[1]);
+		SSL_free(sfd);
+		EVP_cleanup();
+		CRYPTO_cleanup_all_ex_data();
+		close(net->fd);
+	}
+
+	return 0;
+
+sslfprerr:
+	SSL_load_error_strings();
+	ERR_print_errors_fp(stderr);
+	ERR_free_strings();
+	return 1;
+}
+
+int netmain(int argc, char *argv[]) {
+
+	int fflag;
+
+	ARGBEGIN {
+	case 'f':
+		fflag = 1;
+		argc++; argv--;
+		break;
+	default:
+		netusage();
+	} ARGEND;
+
+	if (fflag) {
+		if (argc < 2)
+			netusage();
+
+		net_t *net;
+
+		net = net_new("tcps", argv[1], argv[2]);
+		if (sslfpr(net))
+			return 1;
+
+		return 0;
+	}
+
+	netusage();
+
+	return 0;
+}
diff --git a/net.h b/net.h
@@ -0,0 +1,24 @@
+/*
+ * Copy me if you can
+ * by parazyd
+ */
+
+#ifndef __RPNET_H__
+#define __RPNET_H__
+
+typedef struct net_t net_t;
+struct net_t {
+	int fd;
+
+	char *net;
+	char *addr;
+	char *service;
+	char *options;
+	int type;
+
+	void *data[2];
+};
+
+int netmain(int argc, char *argv[]);
+
+#endif
diff --git a/rohrpost.c b/rohrpost.c
@@ -10,6 +10,7 @@
 #include "arg.h"
 #include "headers.h"
 #include "ind.h"
+#include "net.h"
 #include "sieve.h"
 
 char *argv0;
@@ -33,6 +34,7 @@ enum {
 struct command cmds[] = {
 	{"rpheaders", DOINSTALL,   headersmain},
 	{"rpsieve",   DONTINSTALL,   sievemain},
+	{"rpnet",     DOINSTALL,       netmain},
 };
 
 int main(int argc, char *argv[]) {