Initial commit
Some checks failed
Build Kernel / Build all affected Kernels (push) Has been cancelled
Build all core packages / Build all core packages for selected target (push) Has been cancelled
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Has been cancelled
Build Toolchains / Build Toolchains for each target (push) Has been cancelled
Build host tools / Build host tools for linux and macos based systems (push) Has been cancelled
Coverity scan build / Coverity x86/64 build (push) Has been cancelled
Some checks failed
Build Kernel / Build all affected Kernels (push) Has been cancelled
Build all core packages / Build all core packages for selected target (push) Has been cancelled
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Has been cancelled
Build Toolchains / Build Toolchains for each target (push) Has been cancelled
Build host tools / Build host tools for linux and macos based systems (push) Has been cancelled
Coverity scan build / Coverity x86/64 build (push) Has been cancelled
This commit is contained in:
50
package/utils/px5g-wolfssl/Makefile
Normal file
50
package/utils/px5g-wolfssl/Makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
# Copyright (C) 2020 Paul Spooren <mail@aparcar.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=px5g-wolfssl
|
||||
PKG_RELEASE:=9
|
||||
PKG_LICENSE:=GPL-2.0-or-later
|
||||
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
PKG_MAINTAINER:=Paul Spooren <mail@aparcar.org>
|
||||
|
||||
PKG_CONFIG_DEPENDS:=CONFIG_WOLFSSL_ALT_NAMES
|
||||
|
||||
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
|
||||
|
||||
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))
|
||||
385
package/utils/px5g-wolfssl/px5g-wolfssl.c
Normal file
385
package/utils/px5g-wolfssl/px5g-wolfssl.c
Normal file
@@ -0,0 +1,385 @@
|
||||
// Copyright 2020 Paul Spooren <mail@aparcar.org>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
#include <wolfssl/wolfcrypt/ecc.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#include <wolfssl/wolfcrypt/rsa.h>
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
|
||||
#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, bool cert) {
|
||||
mode_t mode = S_IRUSR | S_IWUSR;
|
||||
ssize_t written;
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
if (cert)
|
||||
mode |= S_IRGRP | S_IROTH;
|
||||
|
||||
if (path) {
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
if (fd < 0) {
|
||||
perror("Error opening file");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fd = STDERR_FILENO;
|
||||
}
|
||||
written = write(fd, buf, bufSz);
|
||||
if (written != bufSz) {
|
||||
perror("Error write file");
|
||||
exit(1);
|
||||
}
|
||||
err = fsync(fd);
|
||||
if (err < 0) {
|
||||
perror("Error fsync file");
|
||||
exit(1);
|
||||
}
|
||||
if (path) {
|
||||
close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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, false);
|
||||
} else {
|
||||
ret = write_file(der, derSz, fName, false);
|
||||
}
|
||||
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 (!strcmp(*arg, "-der")) {
|
||||
pem = false;
|
||||
} else if (!strcmp(*arg, "-newkey") && arg[1]) {
|
||||
if (!strncmp(arg[1], "rsa:", 4)) {
|
||||
type = RSA_KEY_TYPE;
|
||||
keySz = atoi(arg[1] + 4);
|
||||
} else if (!strcmp(arg[1], "ec")) {
|
||||
type = EC_KEY_TYPE;
|
||||
} else {
|
||||
fprintf(stderr, "error: invalid algorithm\n");
|
||||
return 1;
|
||||
}
|
||||
arg++;
|
||||
} else if (!strcmp(*arg, "-days") && arg[1]) {
|
||||
days = (unsigned int)atoi(arg[1]);
|
||||
arg++;
|
||||
} else if (!strcmp(*arg, "-pkeyopt") && arg[1]) {
|
||||
if (strncmp(arg[1], "ec_paramgen_curve:", 18)) {
|
||||
fprintf(stderr, "error: invalid pkey option: %s\n", arg[1]);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(arg[1] + 18, "P-256")) {
|
||||
curve = ECC_SECP256R1;
|
||||
} else if (!strcmp(arg[1] + 18, "P-384")) {
|
||||
curve = ECC_SECP384R1;
|
||||
} else if (!strcmp(arg[1] + 18, "P-521")) {
|
||||
curve = ECC_SECP521R1;
|
||||
} else {
|
||||
fprintf(stderr, "error: invalid curve name: %s\n", arg[1] + 18);
|
||||
return 1;
|
||||
}
|
||||
arg++;
|
||||
} else if (!strcmp(*arg, "-keyout") && arg[1]) {
|
||||
keypath = arg[1];
|
||||
arg++;
|
||||
} else if (!strcmp(*arg, "-out") && 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);
|
||||
|
||||
#ifdef WOLFSSL_ALT_NAMES
|
||||
if(strlen(val) + 2 > 256) {
|
||||
fprintf(stderr, "error: CN is too long: %s\n", val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
newCert.altNames[0] = 0x30; //Sequence with one element
|
||||
newCert.altNames[1] = strlen(val) + 2; // Length of entire sequence
|
||||
newCert.altNames[2] = 0x82; //8 - String, 2 - DNS Name
|
||||
newCert.altNames[3] = strlen(val); //DNS Name length
|
||||
memcpy(newCert.altNames + 4, val, strlen(val)); //DNS Name
|
||||
newCert.altNamesSz = strlen(val) + 4;
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
|
||||
newCert.keyUsage = KEYUSE_DIGITAL_SIG | KEYUSE_CONTENT_COMMIT | KEYUSE_KEY_ENCIPHER;
|
||||
newCert.extKeyUsage = EXTKEYUSE_SERVER_AUTH;
|
||||
|
||||
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) {
|
||||
newCert.sigType = CTC_SHA256wECDSA;
|
||||
ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), NULL, &ecKey, rng);
|
||||
} else {
|
||||
newCert.sigType = CTC_SHA256wRSA;
|
||||
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) {
|
||||
ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf),
|
||||
NULL, &ecKey, rng);
|
||||
} else {
|
||||
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, true);
|
||||
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 (!strcmp(*arg, "-out") && arg[1]) {
|
||||
path = arg[1];
|
||||
arg++;
|
||||
} else if (!strcmp(*arg, "-3")) {
|
||||
exp = 3;
|
||||
} else if (!strcmp(*arg, "-der")) {
|
||||
pem = false;
|
||||
}
|
||||
arg++;
|
||||
}
|
||||
|
||||
if (*arg && type == RSA_KEY_TYPE) {
|
||||
keySz = atoi(*arg);
|
||||
} else if (*arg) {
|
||||
if (!strcmp(*arg, "P-256")) {
|
||||
curve = ECC_SECP256R1;
|
||||
} else if (!strcmp(*arg, "P-384")) {
|
||||
curve = ECC_SECP384R1;
|
||||
} else if (!strcmp(*arg, "P-521")) {
|
||||
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 (!strcmp(argv[1], "eckey"))
|
||||
return dokey(&rng, EC_KEY_TYPE, argv + 2);
|
||||
|
||||
if (!strcmp(argv[1], "rsakey"))
|
||||
return dokey(&rng, RSA_KEY_TYPE, argv + 2);
|
||||
|
||||
if (!strcmp(argv[1], "selfsigned"))
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user