Index | Thread | Search

From:
Jan Klemkow <jan@openbsd.org>
Subject:
tcpbench: key/cert generator
To:
tech@openbsd.org
Cc:
tb@openbsd.org
Date:
Tue, 5 Nov 2024 23:47:19 +0100

Download raw body.

Thread
  • Jan Klemkow:

    tcpbench: key/cert generator

Hi,

This diff add an on the fly key and self signed certificate generator
for the server mode of tcpbench using the new crypto option -c.  Thus,
using tcpbench is much more convenient with crypto traffic.  The user
still can provide his own key and certificate.

# tcpbench -sc
# tcpbench -c localhost

ok?

Bye,
Jan

Index: Makefile
===================================================================
RCS file: /cvs/src/usr.bin/tcpbench/Makefile,v
diff -u -p -r1.11 Makefile
--- Makefile	5 Nov 2024 18:12:55 -0000	1.11
+++ Makefile	5 Nov 2024 22:31:13 -0000
@@ -1,7 +1,7 @@
 #	$OpenBSD: Makefile,v 1.11 2024/11/05 18:12:55 jan Exp $
 
 PROG=	tcpbench
-LDADD=	-lm -levent -ltls -lcrypto
-DPADD=	${LIBM} ${LIBEVENT} ${LIBTLS} ${LIBCRYPTO}
+LDADD=	-lm -levent -ltls -lssl -lcrypto
+DPADD=	${LIBM} ${LIBEVENT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
 
 .include <bsd.prog.mk>
Index: tcpbench.c
===================================================================
RCS file: /cvs/src/usr.bin/tcpbench/tcpbench.c,v
diff -u -p -r1.71 tcpbench.c
--- tcpbench.c	5 Nov 2024 18:12:55 -0000	1.71
+++ tcpbench.c	5 Nov 2024 22:31:13 -0000
@@ -1098,6 +1098,92 @@ process_tls_opt(char *s)
 	return 0;
 }
 
+void
+generate_cert(uint8_t **key, size_t *key_size, uint8_t **crt, size_t *crt_size)
+{
+	EVP_PKEY	*pkey;
+	EVP_PKEY_CTX	*ctx;
+	X509		*x509;
+	X509_NAME	*name;
+	BIO		*bio;
+	BUF_MEM		 mem;
+
+	/*
+	 * Generate RSA key.
+	 */
+	if ((pkey = EVP_PKEY_new()) == NULL)
+		err(1, "EVP_PKEY_new");
+	if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL)
+		errx(1, "EVP_PKEY_CTX_new_id");
+	if (EVP_PKEY_keygen_init(ctx) <= 0)
+		errx(1, "EVP_PKEY_keygen_init");
+	if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0)
+		errx(1, "EVP_PKEY_CTX_set_rsa_keygen_bits");
+	if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
+		errx(1, "EVP_PKEY_keygen");
+
+	/* Get memory pointer of RSA key. */
+	memset(&mem, 0, sizeof mem);
+	if ((bio = BIO_new(BIO_s_mem())) == NULL)
+		errx(1, "BIO_new");
+	if (BIO_set_mem_buf(bio, &mem, BIO_NOCLOSE) <= 0)
+		errx(1, "BIO_set_mem_buf");
+	if (PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL) == 0)
+		errx(1, "PEM_write_bio_PrivateKey");
+	if (BIO_free(bio) == 0)
+		errx(1, "BIO_free");
+	*key = mem.data;
+	*key_size = mem.length;
+
+	/*
+	 * Generate self sign certificate.
+	 */
+	if ((x509 = X509_new()) == NULL)
+		err(1, "X509_new");
+
+	/* Set subject and issuer. */
+	name = X509_get_subject_name(x509);
+	if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "localhost",
+	    -1, -1, 0) == 0)
+		err(1, "X509_NAME_add_entry_by_txt");
+	X509_set_subject_name(x509, name);
+	X509_set_issuer_name(x509, name);
+
+	/* Set serial number. */
+	if (ASN1_INTEGER_set(X509_get_serialNumber(x509), 1) == 0)
+		err(1, "ASN1_INTEGER_set");
+	/* Use certificate version 3. */
+	if (X509_set_version(x509, 2) == 0)
+		err(1, "X509_set_version");
+
+	/* Expiration date: 30 days (60s * 60m * 24h * 30d) */
+	X509_gmtime_adj(X509_get_notBefore(x509), 0);
+	X509_gmtime_adj(X509_get_notAfter(x509), 2592000);
+
+	/* Sign the certificate with the key. */
+	if (X509_set_pubkey(x509, pkey) == 0)
+		err(1, "X509_set_pubkey");
+	if (X509_sign(x509, pkey, EVP_sha256()) == 0)
+		err(1, "X509_sign");
+
+	/* Get memory pointer of certificate. */
+	memset(&mem, 0, sizeof mem);
+	if ((bio = BIO_new(BIO_s_mem())) == NULL)
+		errx(1, "BIO_new");
+	if (BIO_set_mem_buf(bio, &mem, BIO_NOCLOSE) <= 0)
+		errx(1, "BIO_set_mem_buf");
+	if (PEM_write_bio_X509(bio, x509) == 0)
+		err(1, "PEM_write_bio_X509");
+	if (BIO_free(bio) == 0)
+		errx(1, "BIO_free");
+	*crt = mem.data;
+	*crt_size = mem.length;
+
+	X509_free(x509);
+	EVP_PKEY_free(pkey);
+	EVP_PKEY_CTX_free(ctx);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1253,7 +1339,8 @@ main(int argc, char **argv)
 	    (UDP_MODE && (ptb->kvars || nconn != 1 || usetls)))
 		usage();
 
-	if (ptb->sflag && usetls && (crtfile == NULL || keyfile == NULL))
+	if ((crtfile != NULL && (!ptb->sflag || !usetls || keyfile == NULL)) ||
+	    (keyfile != NULL && (!ptb->sflag || !usetls || crtfile == NULL)))
 		usage();
 
 	if (crtfile != NULL && keyfile != NULL) {
@@ -1350,6 +1437,10 @@ main(int argc, char **argv)
 			errx(1, "unable to allocate TLS config");
 
 		if (ptb->sflag) {
+			/* Generate key with selfsigned certificate. */
+			if (crt == NULL && key == NULL)
+				generate_cert(&key, &key_size, &crt, &crt_size);
+
 			if (tls_config_set_key_mem(ptb->tls_cfg, key,
 			    key_size) == -1)
 				errx(1, "%s", tls_config_error(ptb->tls_cfg));