gencert: C replacement for python+rust gencert

Smaller, fewer dependencies, and quicker to cross-compile.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2024-05-03 15:33:00 +02:00
committed by Mattias Walström
parent be1c00f469
commit 39f868fc61
6 changed files with 289 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
*~
*.o
gencert
/aclocal.m4
/autom4te.cache/
/aux
/clixon.xml
/compile
/config.h
/config.h.in
/config.guess
/config.log
/config.status
/config.sub
/configure
/depcomp
/install-sh
/libtool
/ltmain.sh
/m4
/missing
GPATH
GRTAGS
GTAGS
Makefile
Makefile.in
+14
View File
@@ -0,0 +1,14 @@
Copyright (c) 2024 The KernelKit Authors
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
+8
View File
@@ -0,0 +1,8 @@
DISTCLEANFILES = *~ *.d
ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS = gencert
gencert_SOURCES = gencert.c
gencert_CFLAGS = -W -Wall -Wextra -Wno-unused
gencert_CFLAGS = $(ssl_CFLAGS)
gencert_LDADD = $(ssl_LIBS)
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
autoreconf -W portability -vifm
+64
View File
@@ -0,0 +1,64 @@
AC_PREREQ(2.61)
AC_INIT([gencert], [3.0], [https://github.com/kernelkit/infix/issues])
AM_INIT_AUTOMAKE(1.11 foreign)
AM_SILENT_RULES(yes)
AC_CONFIG_FILES([
Makefile
])
AC_PROG_CC
AC_PROG_INSTALL
# Check for pkg-config first, warn if it's not installed
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([ssl], [openssl >= 3.0.0])
test "x$prefix" = xNONE && prefix=$ac_default_prefix
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
DATAROOTDIR=`eval echo $datarootdir`
DATAROOTDIR=`eval echo $DATAROOTDIR`
AC_SUBST(DATAROOTDIR)
LIBDIR=`eval echo $libdir`
LIBDIR=`eval echo $LIBDIR`
AC_SUBST(LIBDIR)
LOCALSTATEDIR=`eval echo $localstatedir`
LOCALSTATEDIR=`eval echo $LOCALSTATEDIR`
AC_SUBST(LOCALSTATEDIR)
RUNSTATEDIR=`eval echo $runstatedir`
RUNSTATEDIR=`eval echo $RUNSTATEDIR`
AC_SUBST(RUNSTATEDIR)
SYSCONFDIR=`eval echo $sysconfdir`
SYSCONFDIR=`eval echo $SYSCONFDIR`
AC_SUBST(SYSCONFDIR)
AC_OUTPUT
cat <<EOF
------------------ Summary ------------------
$PACKAGE_NAME version $PACKAGE_VERSION
Prefix................: $prefix
Exec prefix...........: $eprefix
Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir`
System environment....: ${sysconfig_path:-${sysconfig}}
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
Linker................: $LD $LLDP_LDFLAGS $LLDP_BIN_LDFLAGS $LDFLAGS $LIBS
------------- Compiler version --------------
$($CC --version || true)
-------------- Linker version ---------------
$($LD --version || true)
---------------------------------------------
Check the above options and compile with:
${MAKE-make}
EOF
+172
View File
@@ -0,0 +1,172 @@
/* SPDX-License-Identifier: ISC */
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
extern char *__progname;
static int usage(int rc)
{
fprintf(stderr,
"Usage: %s\n"
"\n"
"Options:\n"
" --country COUNTRY Set country, default: US\n"
" --state STATE Set state or province, default: California\n"
" --city CITY Set city name, default: Berkeley\n"
" --organization ORG Set organization name, default: Acme, Inc.\n"
" --organization-unit UNIT Set organization unit name, default: Second\n"
" --common-name CN Set common name, default: none (required!)\n"
" --out-certificate FILE Output certificate\n"
" --out-key FILE Output private key\n"
, __progname);
return rc;
}
int main(int argc, char *argv[])
{
struct option opts[] = {
{"city", required_argument, 0, 'l'},
{"common-name", required_argument, 0, 'n'},
{"country", required_argument, 0, 'c'},
{"help", no_argument, 0, 'h'},
{"organization", required_argument, 0, 'o'},
{"organisation", required_argument, 0, 'o'},
{"organization-unit", required_argument, 0, 'u'},
{"organisation-unit", required_argument, 0, 'u'},
{"out-certificate", required_argument, 0, 'p'},
{"out-key", required_argument, 0, 'k'},
{"state", required_argument, 0, 's'},
{0, 0, 0, 0}
};
char *common_name = NULL, *cert = "certificate.pem", *key = "private.key";
char *country = "US", *state = "California", *locality = "Berkeley";
char *organization = "Acme, Inc.", *unit = "Second";
ASN1_INTEGER *asn1_serno;
EVP_PKEY_CTX *pkey_ctx;
BIGNUM *bn_serial;
X509_NAME *name;
EVP_PKEY *pkey;
X509 *x509;
FILE *fp;
int c;
while ((c = getopt_long(argc, argv, "c:hs:l:o:u:n:", opts, NULL)) != -1) {
switch (c) {
case 'c':
country = optarg;
break;
case 'h':
case '?':
return usage(0);
case 'k':
key = optarg;
break;
case 'l':
locality = optarg;
break;
case 'n':
common_name = optarg;
break;
case 'o':
organization = optarg;
break;
case 'p':
cert = optarg;
break;
case 's':
state = optarg;
break;
case 'u':
unit = optarg;
break;
default:
fprintf(stderr, "got here: '%c'\n", c);
abort();
}
}
if (!common_name)
return usage(1);
OpenSSL_add_all_algorithms();
/* Key generation using EVP */
pkey = EVP_PKEY_new();
pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!EVP_PKEY_keygen_init(pkey_ctx) || !EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx, 2048) ||
!EVP_PKEY_keygen(pkey_ctx, &pkey)) {
fprintf(stderr, "Error generating RSA key\n");
EVP_PKEY_CTX_free(pkey_ctx);
return 1;
}
EVP_PKEY_CTX_free(pkey_ctx);
/* Certificate creation */
x509 = X509_new();
assert(x509);
X509_set_version(x509, 2);
/* Generating a random serial number */
bn_serial = BN_new();
assert(bn_serial);
BN_rand(bn_serial, 160, 0, 0); /* Generate a 160-bit serial number */
asn1_serno = BN_to_ASN1_INTEGER(bn_serial, NULL);
assert(asn1_serno);
X509_set_serialNumber(x509, asn1_serno);
ASN1_TIME_set_string(X509_getm_notBefore(x509), "20000101000000Z");
ASN1_TIME_set_string(X509_getm_notAfter(x509), "99990101000000Z");
name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)country, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, (unsigned char *)state, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, (unsigned char *)locality, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)organization, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, (unsigned char *)unit, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)common_name, -1, -1, 0);
X509_set_issuer_name(x509, name);
X509_set_pubkey(x509, pkey);
if (!X509_sign(x509, pkey, EVP_sha256())) {
fprintf(stderr, "Error signing certificate\n");
return 1;
}
/* Saving the certificate */
fp = fopen(cert, "w");
if (!fp) {
fprintf(stderr, "Failed opening %s for writing: %s\n", cert, strerror(errno));
goto done;
}
PEM_write_X509(fp, x509);
fclose(fp);
/* Saving the private key */
fp = fopen(key, "w");
if (!fp) {
fprintf(stderr, "Failed opening %s for writing: %s\n", key, strerror(errno));
goto done;
}
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
fclose(fp);
done: /* Cleanup */
X509_free(x509);
EVP_PKEY_free(pkey);
BN_free(bn_serial);
ASN1_INTEGER_free(asn1_serno);
return 0;
}