From 7078294b59ccbbddf641f80efa743095ca275530 Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Fri, 28 Aug 2020 22:18:53 -1000 Subject: [PATCH] px5g-wolfssl: add package This package creates certificates and private keys, just like `px5g` does. Hower it uses WolfSSL rather than MbedTLS. Signed-off-by: Paul Spooren --- package/utils/px5g-wolfssl/Makefile | 54 ++++ package/utils/px5g-wolfssl/px5g-wolfssl.c | 350 ++++++++++++++++++++++ 2 files changed, 404 insertions(+) create mode 100644 package/utils/px5g-wolfssl/Makefile create mode 100644 package/utils/px5g-wolfssl/px5g-wolfssl.c diff --git a/package/utils/px5g-wolfssl/Makefile b/package/utils/px5g-wolfssl/Makefile new file mode 100644 index 0000000000..a9f6a097ed --- /dev/null +++ b/package/utils/px5g-wolfssl/Makefile @@ -0,0 +1,54 @@ +# +# Copyright (C) 2020 Paul Spooren +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=px5g-wolfssl +PKG_RELEASE:=1 +PKG_LICENSE:=GPL-2.0-or-later + +PKG_USE_MIPS16:=0 + +PKG_MAINTAINER:=Paul Spooren + +include $(INCLUDE_DIR)/package.mk + +define Package/px5g-wolfssl + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=Encryption + TITLE:=X.509 certificate generator (using wolfssl) + DEPENDS:=+libwolfssl + PROVIDES:=px5g + VARIANT:=wolfssl +endef + +define Package/px5g-wolfssl/description + Px5g is a tiny X.509 certificate generator. + It suitable to create key files and certificates in DER + and PEM format for use with stunnel, uhttpd and others. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +TARGET_LDFLAGS += -lwolfssl + + +TARGET_CFLAGS += -Wl,--gc-sections + +define Build/Compile + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/px5g px5g-wolfssl.c $(TARGET_LDFLAGS) +endef + +define Package/px5g-wolfssl/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/px5g $(1)/usr/sbin/px5g +endef + +$(eval $(call BuildPackage,px5g-wolfssl)) diff --git a/package/utils/px5g-wolfssl/px5g-wolfssl.c b/package/utils/px5g-wolfssl/px5g-wolfssl.c new file mode 100644 index 0000000000..54ae9bb3ec --- /dev/null +++ b/package/utils/px5g-wolfssl/px5g-wolfssl.c @@ -0,0 +1,350 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HEAP_HINT NULL +#define FOURK_SZ 4096 +#define WOLFSSL_MIN_RSA_BITS 2048 + +enum { + EC_KEY_TYPE = 0, + RSA_KEY_TYPE = 1, +}; + +int write_file(byte *buf, int bufSz, char *path) { + int ret; + FILE *file; + if (path) { + file = fopen(path, "wb"); + if (file == NULL) { + perror("Error opening file"); + exit(1); + } + } else { + file = stdout; + } + ret = (int)fwrite(buf, 1, bufSz, file); + if (path) { + fclose(file); + } + if (ret > 0) { + /* ret > 0 indicates a successful file write, set to zero for return */ + ret = 0; + } + return ret; +} + +int write_key(ecc_key *ecKey, RsaKey *rsaKey, int type, int keySz, char *fName, + bool write_pem) { + int ret; + byte der[FOURK_SZ] = {}; + byte pem[FOURK_SZ] = {}; + int derSz, pemSz; + if (type == EC_KEY_TYPE) { + ret = wc_EccKeyToDer(ecKey, der, sizeof(der)); + } else { + ret = wc_RsaKeyToDer(rsaKey, der, sizeof(der)); + } + if (ret <= 0) { + fprintf(stderr, "Key To DER failed: %d\n", ret); + } + derSz = ret; + + if (write_pem) { + if (type == EC_KEY_TYPE) { + ret = wc_DerToPem(der, derSz, pem, sizeof(pem), ECC_PRIVATEKEY_TYPE); + } else { + ret = wc_DerToPem(der, derSz, pem, sizeof(pem), PRIVATEKEY_TYPE); + } + if (ret <= 0) { + fprintf(stderr, "DER to PEM failed: %d\n", ret); + } + pemSz = ret; + ret = write_file(pem, pemSz, fName); + } else { + ret = write_file(der, derSz, fName); + } + return ret; +} + +int gen_key(WC_RNG *rng, ecc_key *ecKey, RsaKey *rsaKey, int type, int keySz, + long exp, int curve) { + int ret; + + if (type == EC_KEY_TYPE) { + ret = wc_ecc_init(ecKey); + (void)rsaKey; + } else { + ret = wc_InitRsaKey(rsaKey, NULL); + (void)ecKey; + } + if (ret != 0) { + fprintf(stderr, "Key initialization failed: %d\n", ret); + return ret; + } + + if (type == EC_KEY_TYPE) { + fprintf(stderr, "Generating EC private key\n"); + ret = wc_ecc_make_key_ex(rng, 32, ecKey, curve); + } else { + fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", keySz); + ret = wc_MakeRsaKey(rsaKey, keySz, WC_RSA_EXPONENT, rng); + } + if (ret != 0) { + fprintf(stderr, "Key generation failed: %d\n", ret); + } + return ret; +} + +int selfsigned(WC_RNG *rng, char **arg) { + ecc_key ecKey; + RsaKey rsaKey; + int ret; + char *subject = ""; + int keySz = WOLFSSL_MIN_RSA_BITS; + int type = EC_KEY_TYPE; + int exp = WC_RSA_EXPONENT; + int curve = ECC_SECP256R1; + unsigned int days = 3653; // 10 years + char *keypath = NULL, *certpath = NULL; + char fstr[20], tstr[20]; + bool pem = true; + Cert newCert; +#ifdef __USE_TIME_BITS64 + time_t to, from = time(NULL); +#else + unsigned long to, from = time(NULL); +#endif + byte derBuf[FOURK_SZ] = {}; + byte pemBuf[FOURK_SZ] = {}; + int pemSz = -1; + int derSz = -1; + char *key, *val, *tmp; + + ret = wc_InitCert(&newCert); + if (ret != 0) { + fprintf(stderr, "Init Cert failed: %d\n", ret); + return ret; + } + newCert.isCA = 0; + + while (*arg && **arg == '-') { + if (!strncmp(*arg, "-der", 4)) { + pem = false; + } else if (!strncmp(*arg, "-newkey", 6) && arg[1]) { + if (!strncmp(arg[1], "rsa:", 4)) { + type = RSA_KEY_TYPE; + keySz = (unsigned int)atoi(arg[1] + 4); + } else if (!strncmp(arg[1], "ec", 2)) { + type = EC_KEY_TYPE; + } else { + fprintf(stderr, "error: invalid algorithm\n"); + return 1; + } + arg++; + } else if (!strncmp(*arg, "-days", 5) && arg[1]) { + days = (unsigned int)atoi(arg[1]); + arg++; + } else if (!strncmp(*arg, "-pkeyopt", 8) && arg[1]) { + if (strncmp(arg[1], "ec_paramgen_curve:", 18)) { + fprintf(stderr, "error: invalid pkey option: %s\n", arg[1]); + return 1; + } + if (!strncmp(arg[1] + 18, "P-256:", 5)) { + curve = ECC_SECP256R1; + } else if (!strncmp(arg[1] + 18, "P-384:", 5)) { + curve = ECC_SECP384R1; + } else if (!strncmp(arg[1] + 18, "P-521:", 5)) { + curve = ECC_SECP521R1; + } else { + fprintf(stderr, "error: invalid curve name: %s\n", arg[1] + 18); + return 1; + } + arg++; + } else if (!strncmp(*arg, "-keyout", 7) && arg[1]) { + keypath = arg[1]; + arg++; + } else if (!strncmp(*arg, "-out", 4) && arg[1]) { + certpath = arg[1]; + arg++; + } else if (!strcmp(*arg, "-subj") && arg[1]) { + subject = strdupa(arg[1]); + key = arg[1]; + do { + tmp = strchr(key, '/'); + if (tmp) + *tmp = '\0'; + + val = strchr(key, '='); + if (val) { + *val = '\0'; + ++val; + + if (!strcmp(key, "C")) + strncpy(newCert.subject.country, val, CTC_NAME_SIZE); + else if (!strcmp(key, "ST")) + strncpy(newCert.subject.state, val, CTC_NAME_SIZE); + else if (!strcmp(key, "L")) + strncpy(newCert.subject.locality, val, CTC_NAME_SIZE); + else if (!strcmp(key, "O")) + strncpy(newCert.subject.org, val, CTC_NAME_SIZE); + else if (!strcmp(key, "OU")) + strncpy(newCert.subject.unit, val, CTC_NAME_SIZE); + else if (!strcmp(key, "CN")) + strncpy(newCert.subject.commonName, val, CTC_NAME_SIZE); + else if (!strcmp(key, "EMAIL")) + strncpy(newCert.subject.email, val, CTC_NAME_SIZE); + else + printf("warning: unknown attribute %s=%s\n", key, val); + } + } while (tmp && (key = ++tmp)); + } + arg++; + } + newCert.daysValid = days; + + gen_key(rng, &ecKey, &rsaKey, type, keySz, exp, curve); + write_key(&ecKey, &rsaKey, type, keySz, keypath, pem); + + from = (from < 1000000000) ? 1000000000 : from; + strftime(fstr, sizeof(fstr), "%Y%m%d%H%M%S", gmtime(&from)); + to = from + 60 * 60 * 24 * days; + if (to < from) + to = INT_MAX; + strftime(tstr, sizeof(tstr), "%Y%m%d%H%M%S", gmtime(&to)); + + fprintf(stderr, + "Generating selfsigned certificate with subject '%s'" + " and validity %s-%s\n", + subject, fstr, tstr); + + if (type == EC_KEY_TYPE) { + ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), NULL, &ecKey, rng); + } else { + ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), &rsaKey, NULL, rng); + } + if (ret <= 0) { + fprintf(stderr, "Make Cert failed: %d\n", ret); + return ret; + } + + if (type == EC_KEY_TYPE) { + newCert.sigType = CTC_SHA256wECDSA; + ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf), + NULL, &ecKey, rng); + } else { + newCert.sigType = CTC_SHA256wRSA; + ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf), + &rsaKey, NULL, rng); + } + if (ret <= 0) { + fprintf(stderr, "Sign Cert failed: %d\n", ret); + return ret; + } + derSz = ret; + + ret = wc_DerToPem(derBuf, derSz, pemBuf, sizeof(pemBuf), CERT_TYPE); + if (ret <= 0) { + fprintf(stderr, "DER to PEM failed: %d\n", ret); + return ret; + } + pemSz = ret; + + ret = write_file(pemBuf, pemSz, certpath); + if (ret != 0) { + fprintf(stderr, "Write Cert failed: %d\n", ret); + return ret; + } + + if (type == EC_KEY_TYPE) { + wc_ecc_free(&ecKey); + } else { + wc_FreeRsaKey(&rsaKey); + } + return 0; +} + +int dokey(WC_RNG *rng, int type, char **arg) { + ecc_key ecKey; + RsaKey rsaKey; + int ret; + int curve = ECC_SECP256R1; + int keySz = WOLFSSL_MIN_RSA_BITS; + int exp = WC_RSA_EXPONENT; + char *path = NULL; + bool pem = true; + + while (*arg && **arg == '-') { + if (!strncmp(*arg, "-out", 4) && arg[1]) { + path = arg[1]; + arg++; + } else if (!strncmp(*arg, "-3", 2)) { + exp = 3; + } else if (!strncmp(*arg, "-der", 4)) { + pem = false; + } + arg++; + } + + if (*arg && type == RSA_KEY_TYPE) { + keySz = (unsigned int)atoi(*arg); + } else if (*arg) { + if (!strncmp(*arg, "P-256", 5)) { + curve = ECC_SECP256R1; + } else if (!strncmp(*arg, "P-384", 5)) { + curve = ECC_SECP384R1; + } else if (!strncmp(*arg, "P-521", 5)) { + curve = ECC_SECP521R1; + } else { + fprintf(stderr, "Invalid Curve Name: %s\n", *arg); + return 1; + } + } + + ret = gen_key(rng, &ecKey, &rsaKey, type, keySz, exp, curve); + if (ret != 0) + return ret; + + ret = write_key(&ecKey, &rsaKey, type, keySz, path, pem); + + if (type == EC_KEY_TYPE) { + wc_ecc_free(&ecKey); + } else { + wc_FreeRsaKey(&rsaKey); + } + return ret; +} + +int main(int argc, char *argv[]) { + int ret; + WC_RNG rng; + ret = wc_InitRng(&rng); + if (ret != 0) { + fprintf(stderr, "Init Rng failed: %d\n", ret); + return ret; + } + + if (argv[1]) { + if (!strncmp(argv[1], "eckey", 5)) + return dokey(&rng, EC_KEY_TYPE, argv + 2); + + if (!strncmp(argv[1], "rsakey", 5)) + return dokey(&rng, RSA_KEY_TYPE, argv + 2); + + if (!strncmp(argv[1], "selfsigned", 10)) + return selfsigned(&rng, argv + 2); + } + + fprintf(stderr, "PX5G X.509 Certificate Generator Utilit using WolfSSL\n\n"); + fprintf(stderr, "Usage: [eckey|rsakey|selfsigned]\n"); + return 1; +}