Merge pull request #455 from philljj/x509_acert_example

X509 acert example
pull/454/merge
Daniel Pouzzner 2024-09-14 00:41:50 -05:00 committed by GitHub
commit 8254f47648
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 1146 additions and 0 deletions

6
.gitignore vendored
View File

@ -274,6 +274,12 @@ embedded/tls-sock-server-ca
embedded/tls-sock-threaded
embedded/tls-threaded
# X509 Attribute Certificate (acert) example.
x509_acert/acert_new.pem
x509_acert/pkey_new.pem
x509_acert/openssl_acert
x509_acert/wolfssl_acert
hash/sha256-hash
ocsp/ocsp_nonblock/ocsp_nonblock

View File

@ -0,0 +1,25 @@
CC = gcc
WOLFSSL_INSTALL_DIR = /usr/local
OPENSSL_INSTALL_DIR = /usr/local
WOLFSSL_CFLAGS = -Werror -Wall -I$(WOLFSSL_INSTALL_DIR)/include -DUSE_WOLFSSL
WOLFSSL_LIBS = -L$(WOLFSSL_INSTALL_DIR)/lib -lm -lwolfssl
OPENSSL_CFLAGS = -Werror -Wall -I$(OPENSSL_INSTALL_DIR)/include
OPENSSL_LIBS = -L$(OPENSSL_INSTALL_DIR)/lib64/ -lm -lssl -lcrypto
DEBUG_FLAGS = -g -DDEBUG
all: wolfssl_acert openssl_acert
wolfssl_acert: test_x509_acert.c
$(CC) -o $@ $^ $(WOLFSSL_CFLAGS) $(WOLFSSL_LIBS)
openssl_acert: test_x509_acert.c
$(CC) -o $@ $^ $(OPENSSL_CFLAGS) $(OPENSSL_LIBS)
.PHONY: clean all
clean:
rm -f *.o wolfssl_acert openssl_acert

View File

@ -0,0 +1,104 @@
# Description
Simple example of ACERT (Attribute Certificate) support with wolfSSL compat layer,
and OpenSSL.
Supports:
- printing
- signing (openssl only)
- verifying
Based on this example:
- https://github.com/philljj/acert-test
## Prerequisites
Building wolfSSL: Build wolfSSL with
```sh
./configure --enable-acert --enable-opensslextra --enable-rsapss
make
make install
```
Building OpenSSL: At the time of writing this README, attribute cert support
requires openssl master. Clone and build openssl with:
```sh
git clone https://github.com/openssl/openssl.git --depth=1 || exit 1
cd openssl || exit 1
./Configure || exit 1
make || exit 1
sudo make install
```
## Building the examples
Build the wolfssl example with:
```sh
make wolfssl_acert
```
Build the openssl example with:
```sh
make wolfssl_acert
```
Note: you may need to use this script to set your environment
```sh
$ source set_env
info: using env: /usr/local/lib64/:/usr/local/lib/
```
## Examples
### ACERT verification with pubkey
```sh
$./wolfssl_acert -f acerts/acert.pem -k acerts/acert_pubkey.pem
info: using acert file: acerts/acert.pem
info: using pubkey file: acerts/acert_pubkey.pem
info: PEM_read_bio_X509_ACERT: good
info: acert version: 1
info: PEM_read_bio_PUBKEY: good
info: X509_ACERT_verify: good
info: acert_do_test: good
success
```
### Sign and generate ACERT with RSA-PSS with OpenSSL, verify with wolfSSL
1. Use `certs/acert.pem` as input `-f`, and generate new keys and sign `-s`,
use RSA-PSS `-r`, and write to file `-w`:
```sh
$./openssl_acert -f certs/acert.pem -srw
info: using acert file: certs/acert.pem
info: using rsa_pss
info: using mdname: SHA2-256
info: using mask alg: mgf1 with SHA1
info: PEM_read_bio_X509_ACERT: good
info: acert version: 1
info: X509_ACERT_sign: good
info: wrote acert to file: acert_new.pem
info: wrote pubkey to file: pkey_new.pem
info: X509_ACERT_verify: good
info: acert_do_test: good
success
```
2. Finally, test wolfssl verify using newly generated `acert_new.pem` and
`pkey_new.pem`:
```sh
$./wolfssl_acert -f acert_new.pem -k pkey_new.pem
info: using acert file: acert_new.pem
info: using pubkey file: pkey_new.pem
info: PEM_read_bio_X509_ACERT: good
info: acert version: 1
info: PEM_read_bio_PUBKEY: good
info: X509_ACERT_verify: good
info: acert_do_test: good
success
```

View File

@ -0,0 +1,23 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIID4zCCAssCAQEwOaA3MB+kHTAbMRkwFwYDVQQDDBBUUE0gTWFudWZhY3R1cmVy
AhRADHoGLYO7i9GfV2Yz2rrlRFDPSqA6MDikNjA0MQswCQYDVQQGEwJVUzEUMBIG
A1UECgwLZXhhbXBsZS5jb20xDzANBgNVBAsMBlBDVGVzdDANBgkqhkiG9w0BAQsF
AAIBATAiGA8yMDE4MDEwMTA1MDAwMFoYDzIwMjgwMTAxMDUwMDAwWjCB7TALBgVn
gQUCEzECMAAwHAYFZ4EFAhExEzARMAkCAQECAQMCARYEBAAAAAEwEgYFZ4EFAhkx
CTAHBgVngQUIAjCBlQYHZ4EFBQEHAjGBiTCBhqBkMC8wDgYGZ4EFEgMBBAQAAgAB
DBJYWVogQ29tcHV0aW5nIEluYy4MATGABkFCQzEyMzAxMA4GBmeBBRIDAQQEAAcA
AgwNTm90IFNwZWNpZmllZAwDSEQxgAgxMjM0QUJDRIMB/6IeMBwMCHVuYW1lIC1y
DBA2LjUuMC0xNS1nZW5lcmljMBQGBWeBBQIXMQswCQIBAQIBAQIBETCCAScwbwYD
VR0jBGgwZoAUl46DRCrPD3GZndkBbbNDngf6ZHChOKQ2MDQxCzAJBgNVBAYTAlVT
MRQwEgYDVQQKDAtleGFtcGxlLmNvbTEPMA0GA1UECwwGUENUZXN0ghRmuv6Ey2Ja
dCAOFysMNOn9CiH45zBBBgNVHSAEOjA4MDYGAioDMDAwLgYIKwYBBQUHAgIwIgwg
VENHIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwcQYDVR0RBGowaKRmMGQx
EzARBgZngQUFAQQMB01vZGVsIEExHjAcBgZngQUFAQEMElhZWiBDb21wdXRpbmcg
SW5jLjEZMBcGBmeBBQUBBQwNTm90IFNwZWNpZmllZDESMBAGBmeBBQUBBgwGQUJD
MTIzMA0GCSqGSIb3DQEBCwUAA4IBAQB2SdELM7Dqaq2mvT+IV3pCBN7qPzRL+sO4
MZG6jpTbbblr124KM84g936zLVZxOJeAa+Ie7r0ET7GYI+zKtpLmIZrlqhZl4YkP
3g65JsIVc5PvOogxv67IxVigHu/NFKHIbFPz85drTatEVCfA8ac8BwJXXwuESLNr
cH+K/vdLWDgMhsijhco82RI8x11wBvzMXLPnM5OnkiG/0zaEW7mk1gH2tBS6oCc+
0v8y9jQ5NqyPo0mNhLJhUMonmvaGdZ3iDEFyF+iNuDc3pP5PA1YDKk/BYGXt1NUE
89mkuGoF8bwkU9uqLKQ3jpCKx/SZZ08IK5MPQyzsnwjyhrsrP3Qm
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIICPTCCASUCAQEwN6AWMBGkDzANMQswCQYDVQQDDAJDQQIBAqEdpBswGTEXMBUG
A1UEAwwOc2VydmVyLmV4YW1wbGWgLTArpCkwJzElMCMGA1UEAwwcQXR0cmlidXRl
IENlcnRpZmljYXRlIElzc3VlcjANBgkqhkiG9w0BAQsFAAIUA7WQWQKiqrVAIUS4
LE/ZgBtfV8IwIhgPMjAyMTA2MTUxMjM1MDBaGA8yMDMxMDYxMzEyMzUwMFowQTAj
BggrBgEFBQcKBDEXMBWgCYYHVGVzdHZhbDAIDAZncm91cDEwGgYDVQRIMRMwEaEP
gw1hZG1pbmlzdHJhdG9yMCwwHwYDVR0jBBgwFoAUYm7JaGdsZLtTgt0tqoCK2MrI
i10wCQYDVR04BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAlIOJ2Dj3TEUj6BIv6vUs
GqFWms05i+d10XSzWrunlUTQPoJcUjYkifOWp/7RpZ2XnRl+6hH+nIbmwSmXWwBn
ERw2bQMmw//nWuN4Qv9t7ltuovWC0pJX6VMT1IRTuTV4SxuZpFL37vkmnFlPBlb+
mn3ESSxLTjThWFIq1tip4IaxE/i5Uh32GlJglatFHM1PCGoJtyLtYb6KHDlvknw6
coDyjIcj0FZwtQw41jLwxI8jWNmrpt978wdpprB/URrRs+m02HmeQoiHFi/qvdv8
d+5vHf3Pi/ulhz/+dvr0p1vEQSoFnYxLXuty2p5m3PJPZCFmT3gURgmgR3BN9d7A
Bw==
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqvpigJZE2asRTFe63b3f
xvh0swQuX+L4hW08E7mlm0NSQvBVs8yebELNnZLL738fvocvQMwAjf+8+Lyjb1fr
FYMYvJpb6LmGA2Ysyt6Ny700dpiUValtd4mwtjSCH0/k4rCiaiCYWaN79Le9ZGwD
pZ341kVX74JkNdaXs1EJ1tkUUoq6aIu5CWYncxjA4IufduHV1Eh/dpNq1tuLHjgY
Y3NwYDJcotmN9mmIO+MAuZ1TzifhIy14tNGIspYpSZbn8j2RQpQOclhMVWeM5t0i
TWgOO+jhJngptIJMXEaQQzKPiazv6pBhk8oamAZ0Nipr+DI8iDxvzHtyFDRVToOg
1QIDAQAB
-----END PUBLIC KEY-----

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArjl1VnpENuEfQCVm2E4q
h28D62c0pX5IgN5F2RoS7siU2Oc9hsSz6Hj+9o0SRhUTEAxxrML2d7TM2SVoIJ/x
CFrchA1fIZQm7FWJa7MDFpxkRc7cNUGrZ5oyVCHtK6IbKiU4y8B/vova6+dyy6bi
j97ea0UDL8ztKNyDUH9ZntyFrHTltA/ZlEjmxGHQJQd4RBO6RdfM70R7l+YTGa2N
PflyiRY2SKNXXx8cVUURJvkOXVfLCuRUzG+NnSS62WRuWOOD0ZjiJCnwkTJZQNw0
qI+hLhWN+//05JeKOw6rNVVUHR/R0GgjPL6FIQ/+yF2Z8nCd8lVIIY+hQsM/1l/h
2QIDAQAB
-----END PUBLIC KEY-----

View File

@ -0,0 +1,25 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIESzCCAv8CAQEwOaA3MB+kHTAbMRkwFwYDVQQDDBBUUE0gTWFudWZhY3R1cmVy
AhRADHoGLYO7i9GfV2Yz2rrlRFDPSqA6MDikNjA0MQswCQYDVQQGEwJVUzEUMBIG
A1UECgwLZXhhbXBsZS5jb20xDzANBgNVBAsMBlBDVGVzdDBBBgkqhkiG9w0BAQow
NKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUA
ogMCASACAQEwIhgPMjAxODAxMDEwNTAwMDBaGA8yMDI4MDEwMTA1MDAwMFowge0w
CwYFZ4EFAhMxAjAAMBwGBWeBBQIRMRMwETAJAgEBAgEDAgEWBAQAAAABMBIGBWeB
BQIZMQkwBwYFZ4EFCAIwgZUGB2eBBQUBBwIxgYkwgYagZDAvMA4GBmeBBRIDAQQE
AAIAAQwSWFlaIENvbXB1dGluZyBJbmMuDAExgAZBQkMxMjMwMTAOBgZngQUSAwEE
BAAHAAIMDU5vdCBTcGVjaWZpZWQMA0hEMYAIMTIzNEFCQ0SDAf+iHjAcDAh1bmFt
ZSAtcgwQNi41LjAtMTUtZ2VuZXJpYzAUBgVngQUCFzELMAkCAQECAQECAREwggEn
MG8GA1UdIwRoMGaAFJeOg0Qqzw9xmZ3ZAW2zQ54H+mRwoTikNjA0MQswCQYDVQQG
EwJVUzEUMBIGA1UECgwLZXhhbXBsZS5jb20xDzANBgNVBAsMBlBDVGVzdIIUZrr+
hMtiWnQgDhcrDDTp/Qoh+OcwQQYDVR0gBDowODA2BgIqAzAwMC4GCCsGAQUFBwIC
MCIMIFRDRyBUcnVzdGVkIFBsYXRmb3JtIEVuZG9yc2VtZW50MHEGA1UdEQRqMGik
ZjBkMRMwEQYGZ4EFBQEEDAdNb2RlbCBBMR4wHAYGZ4EFBQEBDBJYWVogQ29tcHV0
aW5nIEluYy4xGTAXBgZngQUFAQUMDU5vdCBTcGVjaWZpZWQxEjAQBgZngQUFAQYM
BkFCQzEyMzBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZI
hvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASADggEBAH4FGu9CJJ/NraWxXoB+EuHu
Ec95MPJDHnsDLea45z5TXkdxCd8Tb5EBuWYFCI6nkpWtkiF5UaLncQD/1ag0ECjZ
duhmoaM01t8TERP1x2xOotpiS0nDGiAqn3twBS3NZlxgEDRMvW92tM49Vvlk7JwD
Kxv9+qXidCXt62dcDNJoe1Uj9HXxuOO2NaO9OQHlPkY5GctKbcDBwaDUlEz40J9k
PoXDNurLmI/nNgMDgicKdzdmhMT/BSXSt7Z228p7QcgROgJ5xTEVIMm+lGcBg1Sc
RnWTVNjrIG+/nzYZENr+F40nrIKbkIIZTLCqwAN6fFFt/jNc44SdoJMNsKe1bTM=
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIICpTCCAVkCAQEwN6AWMBGkDzANMQswCQYDVQQDDAJDQQIBAqEdpBswGTEXMBUG
A1UEAwwOc2VydmVyLmV4YW1wbGWgLTArpCkwJzElMCMGA1UEAwwcQXR0cmlidXRl
IENlcnRpZmljYXRlIElzc3VlcjBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQC
AQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASACFAO1kFkCoqq1
QCFEuCxP2YAbX1fCMCIYDzIwMjEwNjE1MTIzNTAwWhgPMjAzMTA2MTMxMjM1MDBa
MEEwIwYIKwYBBQUHCgQxFzAVoAmGB1Rlc3R2YWwwCAwGZ3JvdXAxMBoGA1UESDET
MBGhD4MNYWRtaW5pc3RyYXRvcjAsMB8GA1UdIwQYMBaAFGJuyWhnbGS7U4LdLaqA
itjKyItdMAkGA1UdOAQCBQAwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgEF
AKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgA4IBAQCX18Lyj2CR
AJL9JAwxYgWbk7fWif2mG5IiQ264Rd0W6ugqw1hYseKHnRI5LpxsRVF5kEaFs2ta
FhwxxOtAo8YvbxMC4emuatbqwOlWQYwk9wPLbZb1nd1FItPtO98FK7/vF0263eJu
A+UFxmDvLlao3SzP19mtCOcUjGsVxcJ2PN05wDUzITu2vGXuJAdjHcYX+s1UMLwk
WMwHsz7EK2Al/FavI1MfZp0lVFi++CMOAdLIRbTjlACATDq6Q6kPc+bTqvMYoca2
bGLw1jSig6T3DvGa3O/BwRMOhyqCtJNQYY7MYxcZhPR4Y0RLmyFnFiSzwypL6oMk
QMaW0z/K5YO2
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIDALBgkqhkiG9w0BAQoDggEPADCCAQoCggEBALg9nrRhxCl5zxFdE7Le9GXL
9M8Rzx5xU3meu6yp9lFIc3+FxNoc5E8nk7HXUK82iuEChcSlqt0j0/y03YqM+O45
N6A9OkEkjdyL8BaeQEgNxZY16/nvhhnH0Bzg4n7DMvy3sUPQvsAu9tpbfSd+WNDT
vtO9Fe84HIBkYhRuaIv7ca1UYn7R2VQk1RXK0lfY4orCOrexmlfPciJaTJcR5Lyi
pjUj7X5lruRHVibrMY+Z+8DtvPaDZ7HFiuXzpGPQ0W907Wt7zEJfmTMUyQoOMDMM
4iSlq0ib3rdZt9y2obCggRTFAtMAFIJ29FOT9FYDagMYFSqhnrR3ohiTNzfpYNMC
AwEAAQ==
-----END PUBLIC KEY-----

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIDALBgkqhkiG9w0BAQoDggEPADCCAQoCggEBAL0P9mcosJbMQavKMo6FvjK/
vC5PZAFYxsbQnDiG3kb3gCsshI8HQzHNIuw4wN3waJrqnFmsmsUqMENtsC0J2Fty
DOI5791Ma7JUKT31RW6f5eU2Gjx1+evNWtWs2WzupsZdPS3DlgEQJsTSw3Fs1q5w
JVLVHhtOjCwdj2QO9Xr17Nt0ZOfKoJdqth3LAVujMnOw9gbyTbCrCB+z1Mkq+dK4
K0v6IPZqY76LVhR42y/lyG+MZ8jswg4I4qAE+iIwPi/9Tz9UdNwMfSr3gdD13pa3
VqnGZG83prqPLEHwsSNpWGdDx7pQxgBkAPztO+7LPrMd1ck8Uugsq36pusLjdQ0C
AwEAAQ==
-----END PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
#!/bin/bash
export LD_LIBRARY_PATH=/usr/local/lib64/:/usr/local/lib/
echo "info: using env: $LD_LIBRARY_PATH"

View File

@ -0,0 +1,892 @@
/* glibc includes */
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#if defined(USE_WOLFSSL)
/* wolfssl includes */
#include <wolfssl/options.h>
#include <wolfssl/openssl/bio.h>
#include <wolfssl/openssl/evp.h>
#include <wolfssl/openssl/pem.h>
#include <wolfssl/openssl/ssl.h>
#include <wolfssl/ssl.h>
#else
/* openssl includes */
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/x509_acert.h>
#endif
static int acert_check_opts(const char * file, const char * cert,
const char * pkey_file);
static void acert_err(const char * what, int rc);
static int acert_print_usage_and_die(void) __attribute__((noreturn));
static int acert_do_test(const char * file, const char * cert,
const char * pkey_file);
static X509_ACERT * acert_read(const char * file);
#if !defined(USE_WOLFSSL)
static int acert_write(const char * file, const X509_ACERT * acert);
static int acert_write_pubkey(const char * file, EVP_PKEY * pkey);
#endif /* if !USE_WOLFSSL */
static EVP_PKEY * acert_read_pubkey(const char * file);
static int acert_print(X509_ACERT * x509);
static EVP_PKEY * acert_read_x509_pubkey(const char * cert);
static int acert_test_api_misc(X509_ACERT * x509);
#if defined(USE_WOLFSSL)
static int acert_parse_attr(const X509_ACERT * x509);
static void acert_dump_hex(const char * what, const byte * data,
size_t len);
#endif /* if USE_WOLFSSL */
static int dump = 0;
static int parse = 0;
static const char * mdname = "SHA2-256";
static const char * mgf1_mdname = "SHA1";
static int salt_len = 0;
static int rsa_pss = 0;
static int print = 0;
static int sign = 0;
static int write_acert = 0;
static int verbose = 0;
int
main(int argc,
char * argv[])
{
const char * cert = NULL;
const char * file = NULL;
const char * pkey_file = NULL;
int opt = 0;
int rc = 0;
while ((opt = getopt(argc, argv, "c:f:g:k:l:m:dpqrsvw?")) != -1) {
switch (opt) {
case 'c':
cert = optarg;
break;
case 'd':
dump = 1;
break;
case 'f':
file = optarg;
break;
case 'k':
pkey_file = optarg;
break;
case 'l':
salt_len = atoi(optarg);
if (salt_len <= 0) {
printf("error: invalid -s salt_len: %d\n", salt_len);
return EXIT_FAILURE;
}
break;
case 'm':
mgf1_mdname = optarg;
break;
case 'p':
print = 1;
break;
case 'q':
parse = 1;
break;
case 'r':
rsa_pss = 1;
break;
case 's':
sign = 1;
break;
case 'v':
verbose = 1;
break;
case 'w':
write_acert = 1;
break;
case '?':
default:
acert_print_usage_and_die();
break;
}
}
#if defined(USE_WOLFSSL)
wolfSSL_Init();
if (verbose) {
wolfSSL_Debugging_ON();
}
#endif /* if USE_WOLFSSL */
rc = acert_check_opts(file, cert, pkey_file);
if (rc < 0) {
return EXIT_FAILURE;
}
if (file == NULL) {
printf("error: file: NULL\n");
return EXIT_FAILURE;
}
rc = acert_do_test(file, cert, pkey_file);
if (rc == 0) {
printf("info: acert_do_test: good\n");
printf("success\n");
}
else {
printf("error: acert_do_test returned: %d\n", rc);
printf("fail\n");
}
return (rc == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int
acert_check_opts(const char * file,
const char * cert,
const char * pkey_file)
{
if (file == NULL) {
printf("error: acert file required\n");
return -1;
}
printf("info: using acert file: %s\n", file);
if (cert != NULL) {
printf("info: using cert file: %s\n", cert);
}
if (pkey_file != NULL) {
printf("info: using pubkey file: %s\n", pkey_file);
}
if (pkey_file != NULL && cert != NULL) {
printf("error: -c and -k are mutually exclusive\n");
return -1;
}
if ((pkey_file != NULL || cert != NULL) && sign != 0) {
printf("error: -c[k] and -s are mutually exclusive\n");
return -1;
}
if (rsa_pss) {
printf("info: using rsa_pss\n");
printf("info: using mdname: %s\n", mdname);
printf("info: using mask alg: mgf1 with %s\n", mgf1_mdname);
}
return 0;
}
static int
acert_do_test(const char * file,
const char * cert,
const char * pkey_file)
{
EVP_PKEY * pkey = NULL;
X509_ACERT * x509 = NULL;
uint8_t fail = 0;
int rc = 0;
#if !defined(USE_WOLFSSL)
EVP_PKEY_CTX * pctx = NULL;
#endif /* ! USE_WOLFSSL */
x509 = acert_read(file);
if (x509 == NULL) {
printf("error: acert_read returned: NULL\n");
fail = 1;
goto end_acert_do_test;
}
rc = acert_print(x509);
if (rc) {
printf("error: acert_print returned: %d\n", rc);
fail = 1;
goto end_acert_do_test;
}
rc = acert_test_api_misc(x509);
if (rc) {
printf("error: acert_test_api_misc returned: %d\n", rc);
fail = 1;
goto end_acert_do_test;
}
#if defined(USE_WOLFSSL)
rc = acert_parse_attr(x509);
if (rc) {
printf("error: acert_parse_attr returned: %d\n", rc);
fail = 1;
goto end_acert_do_test;
}
#endif /* if USE_WOLFSSL */
if (cert) {
pkey = acert_read_x509_pubkey(cert);
if (pkey == NULL) {
printf("error: acert_read_print_pubkey returned: NULL\n");
fail = 1;
goto end_acert_do_test;
}
}
else if (pkey_file) {
pkey = acert_read_pubkey(pkey_file);
if (pkey == NULL) {
printf("error: acert_read_pubkey returned: NULL\n");
fail = 1;
goto end_acert_do_test;
}
}
#if !defined(USE_WOLFSSL)
/* todo: wolfssl sign acert support */
if (sign) {
/* Generate a new pkey, and sign the x509 acert.
* The pkey should not be loaded yet. */
if (pkey != NULL) {
printf("error: pkey already exists: %p\n", pkey);
fail = 1;
goto end_acert_do_test;
}
if (!rsa_pss) {
/* Use normal boring RSA keygen. */
pkey = EVP_RSA_gen(2048);
if (pkey != NULL) {
printf("info: EVP_RSA_gen(2048): good\n");
}
else {
printf("error: EVP_RSA_gen returned: NULL\n");
fail = 1;
goto end_acert_do_test;
}
}
else {
int pss_rc = 0;
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA_PSS, NULL);
if (pctx == NULL) {
printf("error: EVP_PKEY_CTX_new_id returned: NULL\n");
fail = 1;
goto end_acert_do_test;
}
pss_rc = EVP_PKEY_keygen_init(pctx);
if (pss_rc <= 0) {
printf("error: EVP_PKEY_keygen_init returned: %d\n", pss_rc);
fail = 1;
goto end_acert_do_test;
}
pss_rc = EVP_PKEY_CTX_set_rsa_pss_keygen_md_name(pctx, mdname, NULL);
if (pss_rc <= 0) {
acert_err("EVP_PKEY_CTX_set_rsa_pss_keygen_md_name", pss_rc);
fail = 1;
goto end_acert_do_test;
}
pss_rc = EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md_name(pctx, mgf1_mdname);
if (pss_rc <= 0) {
acert_err("EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md_name", pss_rc);
fail = 1;
goto end_acert_do_test;
}
if (salt_len) {
pss_rc = EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(pctx, salt_len);
if (pss_rc <= 0) {
acert_err("EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen", pss_rc);
fail = 1;
goto end_acert_do_test;
}
}
pss_rc = EVP_PKEY_keygen(pctx, &pkey);
if (pss_rc <= 0) {
printf("error: EVP_PKEY_keygen returned: %d\n", pss_rc);
fail = 1;
goto end_acert_do_test;
}
if (pkey == NULL) {
printf("error: EVP_PKEY_keygen returned: NULL\n");
fail = 1;
goto end_acert_do_test;
}
}
}
if (sign && pkey) {
int sign_rc = X509_ACERT_sign(x509, pkey, EVP_sha256());
if (sign_rc > 0) {
printf("info: X509_ACERT_sign: good\n");
}
else {
acert_err("X509_ACERT_sign", sign_rc);
fail = 1;
goto end_acert_do_test;
}
}
if (write_acert) {
/* Save the signed acert to file. */
int write_rc = acert_write("acert_new.pem", x509);
if (write_rc) {
fail = 1;
goto end_acert_do_test;
}
}
if (write_acert && pkey) {
/* Save the new pubkey to file. */
int write_rc = acert_write_pubkey("pkey_new.pem", pkey);
if (write_rc) {
fail = 1;
goto end_acert_do_test;
}
}
#endif /* if !USE_WOLFSSL */
if (pkey) {
int verify_rc = X509_ACERT_verify(x509, pkey);
if (verify_rc == 1) {
printf("info: X509_ACERT_verify: good\n");
}
else {
acert_err("X509_ACERT_verify", verify_rc);
fail = 1;
goto end_acert_do_test;
}
}
end_acert_do_test:
if (x509 != NULL) {
X509_ACERT_free(x509);
x509 = NULL;
}
#if !defined(USE_WOLFSSL)
if (pctx) {
EVP_PKEY_CTX_free(pctx);
pctx = NULL;
}
#endif /* ! USE_WOLFSSL */
if (pkey) {
EVP_PKEY_free(pkey);
pkey = NULL;
}
return fail ? -1 : 0;
}
static int
acert_test_api_misc(X509_ACERT * x509)
{
int rc = 0;
int ver = 0;
if (x509 == NULL) {
return -1;
}
ver = X509_ACERT_get_version(x509);
if (ver <= 0) {
printf("error: X509_ACERT_get_version returned: %d\n", ver);
return -1;
}
printf("info: acert version: %x\n", (uint8_t) ver);
return rc;
}
#if defined(USE_WOLFSSL)
/* Given an x509 acert, retrieve the raw attributes buffer and
* length, and then parses it a little.
*
* Returns 0 on success.
* Returns < 0 on error.
* */
static int
acert_parse_attr(const X509_ACERT * x509)
{
const byte * attr = NULL;
word32 attr_len = 0;
word32 idx = 0;
word32 max_idx = 0;
byte tag;
int rc = 0;
int len = 0;
rc = wolfSSL_X509_ACERT_get_attr_buf(x509, &attr, &attr_len);
if (rc != SSL_SUCCESS) {
printf("error: wolfSSL_X509_ACERT_get_attr_buf returned: %d\n", rc);
return -1;
}
if (attr == NULL || attr_len <= 0) {
printf("error: attr = %p, attr_len = %d\n", attr, attr_len);
return -1;
}
if (!parse) {
/* Just verify we could get the buffer and length and return early. */
return 0;
}
/* Try to parse the attributes. This is WIP. */
acert_dump_hex("Attributes", attr, attr_len);
max_idx = attr_len;
rc = GetASNTag(attr + idx, &idx, &tag, max_idx);
if (rc < 0) {
printf("error: GetASNTag(%p, %d, %d, %d) returned: %d\n", attr + idx,
idx, tag, max_idx, tag);
return -1;
}
printf("info: GetASNTag(%p, %d, %d, %d): found tag: 0x%0x\n", attr + idx,
idx, tag, max_idx, tag);
len = GetLength(attr + idx, &idx, &len, max_idx);
if (len <= 0) {
printf("error: GetLength(%p, %d, %d, %d) returned: %d\n", attr + idx,
idx, len, max_idx, len);
return -1;
}
printf("info: GetLength(%p, %d, %d, %d) returned: %d\n", attr + idx,
idx, len, max_idx, len);
return rc;
}
#define BOLDRED "\033[1m\033[31m"
#define BOLDGREEN "\033[1m\033[32m"
#define BOLDWHITE "\033[1m\033[37m"
#define BOLDBLUE "\033[1m\033[34m"
#define BOLDYELLOW "\033[1m\033[33m"
#define RESET "\033[0m"
static void
acert_print_data(const byte * data,
size_t i,
size_t j)
{
if (isprint(data[i + 2 + j])) {
printf("%c", data[i + 2 + j]);
}
else {
printf(".");
}
return;
}
/* Dump data as hex, with some pretty color coding.
* Kind of a silly work in progress, for debugging use.
* */
static void
acert_dump_hex(const char * what,
const byte * data,
size_t len)
{
uint8_t seq_list[1024];
uint16_t n_seq = 0;
uint8_t str_list[1024];
uint16_t n_str = 0;
memset(str_list, 0, sizeof(str_list));
if (!dump) {
return;
}
printf("\ninfo: %s\n", what);
for (size_t i = 0; i < len; ++i) {
if (i % 8 == 0) {
/* indent first element */
printf(" ");
}
if (data[i] == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
seq_list[n_seq] = i;
n_seq++;
printf(BOLDRED "0x%02x " RESET, data[i]);
if ((i + 1) % 8 == 0) {
printf("\n");
}
++i;
printf(BOLDGREEN "0x%02x " RESET, data[i]);
}
else if (data[i] == ASN_PRINTABLE_STRING) {
str_list[n_str] = i;
n_str++;
printf(BOLDBLUE "0x%02x " RESET, data[i]);
if ((i + 1) % 8 == 0) {
printf("\n");
}
++i;
printf(BOLDYELLOW "0x%02x " RESET, data[i]);
}
else {
printf("0x%02x ", data[i]);
}
if ((i + 1) % 8 == 0) {
printf("\n");
}
}
printf("\n\n");
if (n_seq) {
printf("constructed sequences\n");
for (size_t n = 0; n < n_seq; ++n) {
size_t i = seq_list[n];
uint8_t seq_len = data[i + 1];
printf(BOLDRED " 0x%02x " RESET, data[i]);
printf(BOLDGREEN "0x%02x " RESET, data[i + 1]);
for (size_t j = 0; j < seq_len; ++j) {
acert_print_data(data, i, j);
}
printf("\n");
}
}
printf("\n");
if (n_str) {
printf("printable strings\n");
for (size_t n = 0; n < n_str; ++n) {
size_t i = str_list[n];
uint8_t str_len = data[i + 1];
printf(BOLDBLUE " 0x%02x " RESET, data[i]);
printf(BOLDYELLOW "0x%02x " RESET, data[i + 1]);
for (size_t j = 0; j < str_len; ++j) {
printf("%c", data[i + 2 + j]);
acert_print_data(data, i, j);
}
printf("\n");
}
}
printf("\n");
return;
}
#endif /* if USE_WOLFSSL */
/* Reads and print pubkey certificate.
* */
static EVP_PKEY *
acert_read_x509_pubkey(const char * cert)
{
BIO * bp = NULL;
BIO * bout = NULL;
X509 * x509 = NULL;
EVP_PKEY * pkey = NULL;
int rc = -1;
bp = BIO_new_file(cert, "r");
if (bp == NULL) {
printf("error: BIO_new_file returned: NULL\n");
goto end_cert_read;
}
bout = BIO_new_fp(stderr, BIO_NOCLOSE);
if (bout == NULL) {
printf("error: BIO_new_fp returned: NULL\n");
goto end_cert_read;
}
x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL);
if (x509 == NULL) {
printf("error: PEM_read_bio_X509 returned: NULL\n");
goto end_cert_read;
}
printf("info: PEM_read_bio_X509: good\n");
if (print) {
rc = X509_print(bout, x509);
if (rc != 1) {
printf("error: X509_print returned: %d\n", rc);
}
}
pkey = X509_get_pubkey(x509);
if (pkey == NULL) {
printf("error: X509_get_pubkey(%p) returned: NULL\n", x509);
goto end_cert_read;
}
end_cert_read:
if (bp != NULL) {
BIO_free(bp);
bp = NULL;
}
if (bout != NULL) {
BIO_free(bout);
bout = NULL;
}
if (x509 != NULL) {
X509_free(x509);
x509 = NULL;
}
return pkey;
}
/* Reads an x509 acert from file.
*
* Returns: X509_ACERT * on success.
* Returns: NULL on failure.
* */
static X509_ACERT *
acert_read(const char * file)
{
BIO * bp = NULL;
X509_ACERT * x509 = NULL;
bp = BIO_new_file(file, "r");
if (bp == NULL) {
printf("error: BIO_new_file returned: NULL\n");
return NULL;
}
x509 = PEM_read_bio_X509_ACERT(bp, NULL, NULL, NULL);
BIO_free(bp);
bp = NULL;
if (x509 == NULL) {
printf("error: PEM_read_bio_X509_ACERT returned: NULL\n");
return NULL;
}
printf("info: PEM_read_bio_X509_ACERT: good\n");
return x509;
}
#if !defined(USE_WOLFSSL)
/* Writes an x509 acert to file.
*
* Not supported in wolfSSL yet.
* */
static int
acert_write(const char * file,
const X509_ACERT * acert)
{
BIO * bp = NULL;
int ret = 0;
bp = BIO_new_file(file, "w");
if (bp == NULL) {
printf("error: BIO_new_file returned: NULL\n");
return -1;
}
ret = PEM_write_bio_X509_ACERT(bp, acert);
BIO_free(bp);
bp = NULL;
if (ret != 1) {
printf("error: PEM_write_bio_X509_ACERT: %d\n", ret);
return -1;
}
printf("info: wrote acert to file: %s\n", file);
return 0;
}
static int
acert_write_pubkey(const char * file,
EVP_PKEY * pkey)
{
BIO * bp = NULL;
int ret = 0;
bp = BIO_new_file(file, "w");
if (bp == NULL) {
printf("error: BIO_new_file returned: NULL\n");
return -1;
}
ret = PEM_write_bio_PUBKEY(bp, pkey);
BIO_free(bp);
bp = NULL;
if (ret != 1) {
printf("error: PEM_write_bio_PUBKEY: %d\n", ret);
return -1;
}
printf("info: wrote pubkey to file: %s\n", file);
return 0;
}
#endif /* if !USE_WOLFSSL */
static EVP_PKEY *
acert_read_pubkey(const char * file)
{
BIO * bp = NULL;
EVP_PKEY * pkey = NULL;
bp = BIO_new_file(file, "r");
if (bp == NULL) {
printf("error: BIO_new_file returned: NULL\n");
return NULL;
}
pkey = PEM_read_bio_PUBKEY(bp, &pkey, NULL, NULL);
BIO_free(bp);
bp = NULL;
if (pkey == NULL) {
printf("error: PEM_read_bio_PUBKEY returned: NULL\n");
return NULL;
}
printf("info: PEM_read_bio_PUBKEY: good\n");
return pkey;
}
static int
acert_print(X509_ACERT * x509)
{
BIO * bout = NULL;
int print_rc = 0;
if (!print) {
/* Nothing to do. */
return 0;
}
bout = BIO_new_fp(stderr, BIO_NOCLOSE);
if (bout == NULL) {
printf("error: BIO_new_fp returned: NULL\n");
return -1;
}
print_rc = X509_ACERT_print(bout, x509);
BIO_free(bout);
bout = NULL;
if (print_rc == 1) {
printf("info: X509_ACERT_print: good\n");
}
else {
printf("error: X509_ACERT_print returned: %d\n", print_rc);
return -1;
}
return 0;
}
static void
acert_err(const char * what,
int rc)
{
unsigned long err = ERR_get_error();
printf("error: %s returned: %d: %lu, %s\n",
what, rc, err, ERR_error_string(err, NULL));
return;
}
static int
acert_print_usage_and_die(void)
{
printf("options:\n");
printf(" -c <path to pub key cert>\n");
printf(" -f <path to acert file\n");
printf(" -k <path to pub key file>\n");
printf(" -m <mask function> (rsa_pss only)\n");
printf(" -l <salt len> (rsa_pss only)\n");
printf(" -r (use rsa_pss)\n");
printf(" -s (resign and verify)\n");
printf(" -v (verbose)\n");
printf(" -w (write signed acert to file)\n");
printf("\n");
printf("usage:\n");
printf(" verifying acert with pub key file:\n");
printf(" $./test/test_acert -f certs/signed/acert.pem -k certs/signed/acert_pubkey.pem\n");
printf(" info: using acert file: certs/signed/acert.pem\n");
printf(" info: using pubkey file: certs/signed/acert_pubkey.pem\n");
printf(" info: PEM_read_bio_X509_ACERT: good\n");
printf(" info: acert version: 1\n");
printf(" info: PEM_read_bio_PUBKEY: good\n");
printf(" info: X509_ACERT_verify: good\n");
printf(" info: acert_do_test: good\n");
printf(" success\n");
exit(EXIT_FAILURE);
}