Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
926dd8a
RSA: replace hash_alg + mgf1_hash_alg with hash_idx + mgf1_hash_idx
karel-m Apr 11, 2026
09b3817
fix failing github action
karel-m Apr 11, 2026
55201c3
Add X.509 APIs
sjaeckel Jun 16, 2025
33281b0
Add `demos/x509_verify.c`
sjaeckel Jun 16, 2025
4a3c9b7
Add `x509_test()`
sjaeckel Sep 2, 2025
af13460
Add `x509_import_spki()` to timing.c
sjaeckel Sep 3, 2025
15ca30d
Extend coverage
sjaeckel Sep 3, 2025
6cc433d
Update makefiles
sjaeckel Oct 16, 2025
47f513f
adopt to the latest changes in new-rsa-api branch
karel-m Apr 11, 2026
a7af677
fix hash names in pka_oids
karel-m Apr 16, 2026
f944942
fix hash names in pka_oids (part 2)
karel-m Apr 16, 2026
d85a596
remove unnecessary endianness hack
karel-m Apr 16, 2026
d5dc5fd
enforce RFC 5280 4.1.1.2 (TBS and outer signatureAlgorithm must match…
karel-m Apr 16, 2026
435d067
LeakSanitizer: detected memory leak (just a test demonstrating the pr…
karel-m Apr 16, 2026
08c9198
fix memory leak (or use-after-free) from previous commit
karel-m Apr 16, 2026
6f0dee1
minor improvements to x509_import
karel-m Apr 16, 2026
2b85056
fix off-by-one x509_extensions
karel-m Apr 16, 2026
04c5a82
typo in comment (x509_get)
karel-m Apr 16, 2026
dacbab9
fix misleading param/variable names
karel-m Apr 16, 2026
4cb09d8
fix typo in comments
karel-m Apr 16, 2026
c59a0ef
remove unused variable (x)
karel-m Apr 16, 2026
6fa5979
fix improper err handling
karel-m Apr 16, 2026
5fa0683
x509_cmp_name: add check a->asn1 or b->asn1 for NULL
karel-m Apr 16, 2026
6ed2864
alg comparison now correctly returns 0 when one hash is NULL
karel-m Apr 16, 2026
de8cb4d
NOTE (not fix): we do not reject certificates with unrecognized criti…
karel-m Apr 16, 2026
3be2b1c
free proper number of elements
karel-m Apr 16, 2026
6f451e9
avoid double-free
karel-m Apr 16, 2026
8ad56cc
avoid calling s_free_x509_string_array on NULL pointer
karel-m Apr 16, 2026
02e4780
ltc_x509_time - fix confusion utc vs. utc (one of them renamed to is_…
karel-m Apr 16, 2026
585f9e4
x509_name_detail_get: not found does not mean CRYPT_INVALID_ARG
karel-m Apr 16, 2026
55f85f3
x509_cmp_name was suggesting strcmp-like semantics but was returning …
karel-m Apr 16, 2026
8d6ff59
remove unreachable code
karel-m Apr 16, 2026
b82fde0
fix CMakeLists.txt for demos
karel-m Apr 16, 2026
98dbd3d
add few missing LTC_ARGCHK
karel-m Apr 16, 2026
f7b1553
properly call s_free_extensions
karel-m Apr 16, 2026
4b627b9
instead of ipv6 like 2001:db8:0:0:0:0:0:1 rather produce 2001:0db8:00…
karel-m Apr 16, 2026
2220147
remove unnecessary #include <wchar.h> (we already handle it in tomcry…
karel-m Apr 16, 2026
9da46d3
fix cmake tests
karel-m Apr 17, 2026
be7cc72
CI tests (non-cmake) require to build demo x509_verify
karel-m Apr 17, 2026
066526e
fixup! Add `demos/x509_verify.c`
sjaeckel Apr 17, 2026
6702754
No need to check input args on internal APIs.
sjaeckel Apr 17, 2026
3d68740
Make `s_free()` take a `void**` and set that one to NULL after free'ing
sjaeckel Apr 17, 2026
a81878e
Put the macro where it should've been in the first place
sjaeckel Apr 17, 2026
5c82093
Slightly refactor extension allocation & free'ing
sjaeckel Apr 17, 2026
257d1c4
Add more extensions.
sjaeckel Apr 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions .ci/coverage_more.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ pdiv "Sizes"
pdiv "Constants"
./constants

echo "" > x509_verify.log

for n in tests/x509/*.pem; do
pdiv "X.509 verify $n"
./x509_verify $n >>x509_verify.log 2>&1
done

pdiv "X.509 verify of all certs packaged"
find tests/x509 -name '*.pem' -exec './x509_verify' {} \+ >>x509_verify.log 2>&1

pdiv "X.509 verify of all certs packaged via STDIN"
for f in $(find tests/x509 -maxdepth 2 -name '*.pem'); do echo "- - - - - - -"; echo $f; cat $f | ./x509_verify; done >>x509_verify.log 2>&1

pdiv "Generate hashsum_tv.txt"
for i in $(for j in $(echo $(./hashsum -h | awk '/Algorithms/,EOF' | tail -n +2)); do echo $j; done | sort); do
echo -n "$i: " && ./hashsum -a $i tests/test.key
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ tv_gen
tv_gen.exe
timing
timing.exe
x509_verify
x509_verify.exe

# Visual Studio special files
# ignore user specific settings
Expand Down
2 changes: 1 addition & 1 deletion demos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ endif()
# Demos that are usable but only rarely make sense to be installed
#
# -----------------------------------------------------------------------------
set(USABLE_DEMOS aesgcm constants crypt der_print_flexi latex-tables openssh-privkey openssl-enc sizes timing)
set(USABLE_DEMOS aesgcm constants crypt der_print_flexi latex-tables openssh-privkey openssl-enc sizes timing x509_verify)
list(JOIN USABLE_DEMOS " " USABLE_DEMOS_STR)
option(BUILD_USABLE_DEMOS "Build usable demos (${USABLE_DEMOS_STR})" FALSE)

Expand Down
56 changes: 56 additions & 0 deletions demos/timing.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ static LTC_INLINE ulong64 t_read(void)

static void init_timer(void)
{
#if defined(LTC_NO_ASM)
skew = 0;
fprintf(stderr, "LTC_NO_ASM\nClock Skew: %lu\n", (unsigned long)skew);
#else
ulong64 c1, c2, t1, t2;
unsigned long y1;

Expand All @@ -146,6 +150,7 @@ static void init_timer(void)
}
skew = c2 - c1;
fprintf(stderr, "Clock Skew: %lu\n", (unsigned long)skew);
#endif
}

static void time_keysched(void)
Expand Down Expand Up @@ -1400,6 +1405,56 @@ static void time_encmacs(void)
time_encmacs_(32);
}

static void time_x509_import_spki(const char *pem)
{
const ltc_x509_certificate *cert;
FILE *f;
int err, y, n;
ltc_pka_key k[8] = {0};
ulong64 t1, t2;
f = fopen(pem, "r");
if ((err = x509_import_pem_filehandle(f, &cert)) != CRYPT_OK) {
fprintf(stderr, "\nx509_import_pem_filehandle() error... %s\n", error_to_string(err));
exit(EXIT_FAILURE);
}
if ((err = x509_import_spki(cert->asn1->data, cert->asn1->size, k, NULL)) != CRYPT_OK) {
fprintf(stderr, "\nx509_import_spki() error... %s\n", error_to_string(err));
exit(EXIT_FAILURE);
}
pka_key_free(k);
#define DO1 x509_import_spki(cert->asn1->data, cert->asn1->size, &k[n++], NULL);
#define DO2 DO1 DO1
#define DO4 DO2 DO2
#define DO8 DO4 DO4
t2 = -1;
for (y = 0; y < 1000; y++) {
n = 0;
t_start();
t1 = t_read();
DO8;
t1 = (t_read() - t1)>>1;
if (t1 < t2) t2 = t1;
for (n = LTC_ARRAY_SIZE(k); n --> 0;) {
pka_key_free(&k[n]);
}
}
fprintf(stderr, "x509 %-20s: %9"PRI64"u cycles\n", strrchr(pem, '/') + 1, t2/LTC_ARRAY_SIZE(k));
x509_free(&cert);
fclose(f);
}

static void time_x509(void)
{
time_x509_import_spki("tests/x509/gnutls/cert-rsa-pss.pem");
time_x509_import_spki("tests/x509/LTC_CA.pem");
time_x509_import_spki("tests/x509/LTC_S0.pem");
time_x509_import_spki("tests/x509/LTC_SS0.pem");
time_x509_import_spki("tests/x509/secp384r1.pem");
time_x509_import_spki("tests/x509/secp521r1.pem");
time_x509_import_spki("tests/x509/invalid/LTC_SSS0.pem");
time_x509_import_spki("tests/x509/invalid/secp224r1.pem");
}

static void LTC_NORETURN die(int status)
{
FILE* o = status == EXIT_SUCCESS ? stdout : stderr;
Expand Down Expand Up @@ -1442,6 +1497,7 @@ const struct
LTC_TEST_FN(dsa),
LTC_TEST_FN(ecc),
LTC_TEST_FN(dh),
LTC_TEST_FN(x509),
};
char *single_test = NULL;
unsigned int i;
Expand Down
166 changes: 166 additions & 0 deletions demos/x509_verify.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* load a X.509 certificate chain and verify its validity */
#include <tomcrypt.h>
#include <stdarg.h>

#ifdef LTC_QUIET
static void print_err(const char *fmt, ...)
{
LTC_UNUSED_PARAM(fmt);
}

#define print_stderr(...)
#else
static void print_err(const char *fmt, ...)
{
va_list args;

va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}

#define print_stderr(...) fprintf(stderr, ##__VA_ARGS__)
#endif

#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
#define LTC_DER_PRINT_FLEXI_NO_MAIN
#include "der_print_flexi.c"

static void s_der_print_flexi(const ltc_asn1_list* l)
{
print_stderr("\n\n");
s_der_print_flexi_i(l, 0);
print_stderr("\n\n");
}
#else
static void s_der_print_flexi(const ltc_asn1_list* l)
{
LTC_UNUSED_PARAM(l);
}
#endif

static unsigned long num_certs;
static const ltc_x509_certificate *cert[256] = {0};
static FILE *f;

static void die_(int err, int line)
{
unsigned long n;
print_err("%3d: LTC sez %s\n", line, error_to_string(err));
for (n = num_certs; n --> 0;) {
x509_free(&cert[n]);
}
if (f) fclose(f);
exit(EXIT_FAILURE);
}

#define die(i) do { die_(i, __LINE__); } while(0)
#define DIE(s, ...) do { print_err("%3d: " s "\n", __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } while(0)
#ifndef LTC_ARRAY_SIZE
#define LTC_ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
#endif

int main(int argc, char **argv)
{
const unsigned char zero_cert_buf[sizeof(cert)] = {0};
int err, argn = 1;
unsigned long len, processed, n;
long tell, tot_data = 0;

if ((err = register_all_hashes()) != CRYPT_OK) {
die(err);
}
if ((err = crypt_mp_init("ltm")) != CRYPT_OK) {
die(err);
}

next:
tot_data = processed = num_certs = n = 0;
if (argc > argn) f = fopen(argv[argn], "r");
else f = stdin;
if (f == NULL) DIE("fopen sez no");
if (f != stdin) {
fseek(f, 0, SEEK_END);
tot_data = ftell(f);
fseek(f, 0, SEEK_SET);
tell = 0;
} else {
tell = -1;
}

print_stderr("-=-=-=-=-=-=-\nDecode %s\n=-=-=-=-=-=-=\n", argv[argn]);

while (tell != tot_data) {
err = x509_import_pem_filehandle(f, &cert[n]);
if (err == CRYPT_PK_ASN1_ERROR || err == CRYPT_UNKNOWN_PEM)
continue;
else if (err != CRYPT_OK)
break;
if (cert[n] && cert[n]->asn1)
s_der_print_flexi(cert[n]->asn1);
if (f != stdin) {
tell = ftell(f);
print_stderr("%2lu len: %ld - tot: %ld - processed: %lu (%s)\n", n, tell, tot_data, processed, error_to_string(err));
len = tell - processed;
processed += len;
}
n++;
if (n == LTC_ARRAY_SIZE(cert))
break;
}
num_certs = n;
print_stderr("len: %ld - tot: %ld - processed: %lu (%s)\n", tell, tot_data, processed, error_to_string(err));
if (err && argc > argn) goto check_next;
if (err && err != CRYPT_NOP) die(err);
for (n = 0; n < num_certs; ++n) {
unsigned long m = n + 1 == num_certs ? n : n + 1;
int stat;
if ((err = x509_cert_is_signed_by(cert[n], &cert[m]->tbs_certificate.subject_public_key_info, &stat)) != CRYPT_OK) {
print_err("%3d: LTC sez %s\n", __LINE__, error_to_string(err));
if (m == n) {
print_stderr("Cert is last in chain, but not self-signed.\n");
} else {
break;
}
}
{
const ltc_x509_string *subjects[4];
const ltc_x509_name *subject, *issuer;
int issuer_matches_next_subject = x509_name_eq(&cert[n]->tbs_certificate.issuer, &cert[m]->tbs_certificate.subject);
subject = &cert[n]->tbs_certificate.subject;
if (n != m) {
issuer = &cert[m]->tbs_certificate.subject;
} else {
issuer = &cert[m]->tbs_certificate.issuer;
}
x509_name_detail_get(subject, LTC_X509_CN, &subjects[0]);
x509_name_detail_get(subject, LTC_X509_O, &subjects[2]);
x509_name_detail_get(issuer, LTC_X509_CN, &subjects[1]);
x509_name_detail_get(issuer, LTC_X509_O, &subjects[3]);
#define X509_STRING_STR(s) (s) ? (s)->str : "NULL"
print_stderr("Cert: %s - %s\nCA: %s - %s\nIssuer matches next subject: %s\nVerify: %s\n",
X509_STRING_STR(subjects[0]), X509_STRING_STR(subjects[2]),
X509_STRING_STR(subjects[1]), X509_STRING_STR(subjects[3]),
issuer_matches_next_subject ? "True" : "False", stat ? "Success" : "Failed");
/* In case of LTC_QUIET this would show up as unused. */
LTC_UNUSED_PARAM(issuer_matches_next_subject);
}
}
check_next:
for (n = num_certs; n --> 0;) {
x509_free(&cert[n]);
}
if (XMEMCMP(cert, zero_cert_buf, sizeof(zero_cert_buf))) {
DIE("cert buf not completely cleaned");
}
if (f != stdin) {
fclose(f);
argn++;
if (argc > argn) {
goto next;
}
}
return 0;
}
14 changes: 13 additions & 1 deletion libtomcrypt_VS2008.vcproj
Original file line number Diff line number Diff line change
Expand Up @@ -2322,13 +2322,25 @@
>
</File>
<File
RelativePath="src\pk\asn1\x509\x509_get_pka.c"
RelativePath="src\pk\asn1\x509\x509_extensions.c"
>
</File>
<File
RelativePath="src\pk\asn1\x509\x509_get.c"
>
</File>
<File
RelativePath="src\pk\asn1\x509\x509_import.c"
>
</File>
<File
RelativePath="src\pk\asn1\x509\x509_import_spki.c"
>
</File>
<File
RelativePath="src\pk\asn1\x509\x509_utils.c"
>
</File>
</Filter>
</Filter>
<Filter
Expand Down
10 changes: 7 additions & 3 deletions makefile.mingw
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,9 @@ src/pk/asn1/oid/pk_get.o src/pk/asn1/oid/pk_oid_cmp.o src/pk/asn1/oid/pk_oid_str
src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/pkcs8/pkcs8_get.o \
src/pk/asn1/x509/x509_decode_public_key_from_certificate.o src/pk/asn1/x509/x509_decode_spki.o \
src/pk/asn1/x509/x509_decode_subject_public_key_info.o \
src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/asn1/x509/x509_get_pka.o \
src/pk/asn1/x509/x509_import_spki.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o src/pk/dh/dh_export.o \
src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/asn1/x509/x509_extensions.o \
src/pk/asn1/x509/x509_get.o src/pk/asn1/x509/x509_import.o src/pk/asn1/x509/x509_import_spki.o \
src/pk/asn1/x509/x509_utils.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o src/pk/dh/dh_export.o \
src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o src/pk/dh/dh_import.o \
src/pk/dh/dh_import_pkcs8.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o \
src/pk/dh/dh_shared_secret.o src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o \
Expand Down Expand Up @@ -245,7 +246,8 @@ tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o \
tests/no_null_termination_check_test.o tests/no_prng.o tests/padding_test.o tests/pem_test.o \
tests/pk_oid_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o \
tests/scrypt_test.o tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o
tests/scrypt_test.o tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o \
tests/x509_test.o

#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
Expand Down Expand Up @@ -309,6 +311,8 @@ timing.exe: demos/timing.o $(LIBMAIN_S)
$(CC) demos/timing.o $(LIBMAIN_S) $(LTC_LDFLAGS) -o $@
der_print_flexi.exe: demos/der_print_flexi.o $(LIBMAIN_S)
$(CC) demos/der_print_flexi.o $(LIBMAIN_S) $(LTC_LDFLAGS) -o $@
x509_verify.exe: demos/x509_verify.o $(LIBMAIN_S)
$(CC) demos/x509_verify.o $(LIBMAIN_S) $(LTC_LDFLAGS) -o $@

#Tests
test.exe: $(TOBJECTS) $(LIBMAIN_S)
Expand Down
10 changes: 7 additions & 3 deletions makefile.msvc
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,9 @@ src/pk/asn1/oid/pk_get.obj src/pk/asn1/oid/pk_oid_cmp.obj src/pk/asn1/oid/pk_oid
src/pk/asn1/pkcs8/pkcs8_decode_flexi.obj src/pk/asn1/pkcs8/pkcs8_get.obj \
src/pk/asn1/x509/x509_decode_public_key_from_certificate.obj src/pk/asn1/x509/x509_decode_spki.obj \
src/pk/asn1/x509/x509_decode_subject_public_key_info.obj \
src/pk/asn1/x509/x509_encode_subject_public_key_info.obj src/pk/asn1/x509/x509_get_pka.obj \
src/pk/asn1/x509/x509_import_spki.obj src/pk/dh/dh.obj src/pk/dh/dh_check_pubkey.obj src/pk/dh/dh_export.obj \
src/pk/asn1/x509/x509_encode_subject_public_key_info.obj src/pk/asn1/x509/x509_extensions.obj \
src/pk/asn1/x509/x509_get.obj src/pk/asn1/x509/x509_import.obj src/pk/asn1/x509/x509_import_spki.obj \
src/pk/asn1/x509/x509_utils.obj src/pk/dh/dh.obj src/pk/dh/dh_check_pubkey.obj src/pk/dh/dh_export.obj \
src/pk/dh/dh_export_key.obj src/pk/dh/dh_free.obj src/pk/dh/dh_generate_key.obj src/pk/dh/dh_import.obj \
src/pk/dh/dh_import_pkcs8.obj src/pk/dh/dh_set.obj src/pk/dh/dh_set_pg_dhparam.obj \
src/pk/dh/dh_shared_secret.obj src/pk/dsa/dsa_decrypt_key.obj src/pk/dsa/dsa_encrypt_key.obj \
Expand Down Expand Up @@ -238,7 +239,8 @@ tests/misc_test.obj tests/modes_test.obj tests/mpi_test.obj tests/multi_test.obj
tests/no_null_termination_check_test.obj tests/no_prng.obj tests/padding_test.obj tests/pem_test.obj \
tests/pk_oid_test.obj tests/pkcs_1_eme_test.obj tests/pkcs_1_emsa_test.obj tests/pkcs_1_oaep_test.obj \
tests/pkcs_1_pss_test.obj tests/pkcs_1_test.obj tests/prng_test.obj tests/rotate_test.obj tests/rsa_test.obj \
tests/scrypt_test.obj tests/ssh_test.obj tests/store_test.obj tests/test.obj tests/x25519_test.obj
tests/scrypt_test.obj tests/ssh_test.obj tests/store_test.obj tests/test.obj tests/x25519_test.obj \
tests/x509_test.obj

#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
Expand Down Expand Up @@ -296,6 +298,8 @@ timing.exe: demos/timing.c $(LIBMAIN_S)
cl $(LTC_CFLAGS) demos/timing.c tests/common.c $(LIBMAIN_S) $(LTC_LDFLAGS) /Fe$@
der_print_flexi.exe: demos/der_print_flexi.c $(LIBMAIN_S)
cl $(LTC_CFLAGS) demos/der_print_flexi.c tests/common.c $(LIBMAIN_S) $(LTC_LDFLAGS) /Fe$@
x509_verify.exe: demos/x509_verify.c $(LIBMAIN_S)
cl $(LTC_CFLAGS) demos/x509_verify.c tests/common.c $(LIBMAIN_S) $(LTC_LDFLAGS) /Fe$@

#Tests
test.exe: $(LIBMAIN_S) $(TOBJECTS)
Expand Down
Loading
Loading