From 2c57ef33448df9e9c20647f44874f8c888f961c2 Mon Sep 17 00:00:00 2001 From: jordan Date: Fri, 30 Aug 2024 16:37:12 -0500 Subject: [PATCH] x509 acert example. --- x509_acert/Makefile | 25 + x509_acert/README.md | 104 +++ x509_acert/certs/acert.pem | 23 + x509_acert/certs/acert_ietf.pem | 15 + x509_acert/certs/acert_ietf_pubkey.pem | 9 + x509_acert/certs/acert_pubkey.pem | 9 + x509_acert/certs/rsa_pss/acert.pem | 25 + x509_acert/certs/rsa_pss/acert_ietf.pem | 17 + x509_acert/certs/rsa_pss/acert_ietf_pkey.pem | 9 + x509_acert/certs/rsa_pss/acert_pkey.pem | 9 + x509_acert/set_env | 3 + x509_acert/test_x509_acert.c | 871 +++++++++++++++++++ 12 files changed, 1119 insertions(+) create mode 100644 x509_acert/Makefile create mode 100644 x509_acert/README.md create mode 100644 x509_acert/certs/acert.pem create mode 100644 x509_acert/certs/acert_ietf.pem create mode 100644 x509_acert/certs/acert_ietf_pubkey.pem create mode 100644 x509_acert/certs/acert_pubkey.pem create mode 100644 x509_acert/certs/rsa_pss/acert.pem create mode 100644 x509_acert/certs/rsa_pss/acert_ietf.pem create mode 100644 x509_acert/certs/rsa_pss/acert_ietf_pkey.pem create mode 100644 x509_acert/certs/rsa_pss/acert_pkey.pem create mode 100644 x509_acert/set_env create mode 100644 x509_acert/test_x509_acert.c diff --git a/x509_acert/Makefile b/x509_acert/Makefile new file mode 100644 index 00000000..23f5be2b --- /dev/null +++ b/x509_acert/Makefile @@ -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 diff --git a/x509_acert/README.md b/x509_acert/README.md new file mode 100644 index 00000000..04c267e0 --- /dev/null +++ b/x509_acert/README.md @@ -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 +``` diff --git a/x509_acert/certs/acert.pem b/x509_acert/certs/acert.pem new file mode 100644 index 00000000..4bde876d --- /dev/null +++ b/x509_acert/certs/acert.pem @@ -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----- diff --git a/x509_acert/certs/acert_ietf.pem b/x509_acert/certs/acert_ietf.pem new file mode 100644 index 00000000..1c25c867 --- /dev/null +++ b/x509_acert/certs/acert_ietf.pem @@ -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----- diff --git a/x509_acert/certs/acert_ietf_pubkey.pem b/x509_acert/certs/acert_ietf_pubkey.pem new file mode 100644 index 00000000..c7434f93 --- /dev/null +++ b/x509_acert/certs/acert_ietf_pubkey.pem @@ -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----- diff --git a/x509_acert/certs/acert_pubkey.pem b/x509_acert/certs/acert_pubkey.pem new file mode 100644 index 00000000..a382a1be --- /dev/null +++ b/x509_acert/certs/acert_pubkey.pem @@ -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----- diff --git a/x509_acert/certs/rsa_pss/acert.pem b/x509_acert/certs/rsa_pss/acert.pem new file mode 100644 index 00000000..74519df3 --- /dev/null +++ b/x509_acert/certs/rsa_pss/acert.pem @@ -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----- diff --git a/x509_acert/certs/rsa_pss/acert_ietf.pem b/x509_acert/certs/rsa_pss/acert_ietf.pem new file mode 100644 index 00000000..37f75625 --- /dev/null +++ b/x509_acert/certs/rsa_pss/acert_ietf.pem @@ -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----- diff --git a/x509_acert/certs/rsa_pss/acert_ietf_pkey.pem b/x509_acert/certs/rsa_pss/acert_ietf_pkey.pem new file mode 100644 index 00000000..f2d208d3 --- /dev/null +++ b/x509_acert/certs/rsa_pss/acert_ietf_pkey.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIDALBgkqhkiG9w0BAQoDggEPADCCAQoCggEBALg9nrRhxCl5zxFdE7Le9GXL +9M8Rzx5xU3meu6yp9lFIc3+FxNoc5E8nk7HXUK82iuEChcSlqt0j0/y03YqM+O45 +N6A9OkEkjdyL8BaeQEgNxZY16/nvhhnH0Bzg4n7DMvy3sUPQvsAu9tpbfSd+WNDT +vtO9Fe84HIBkYhRuaIv7ca1UYn7R2VQk1RXK0lfY4orCOrexmlfPciJaTJcR5Lyi +pjUj7X5lruRHVibrMY+Z+8DtvPaDZ7HFiuXzpGPQ0W907Wt7zEJfmTMUyQoOMDMM +4iSlq0ib3rdZt9y2obCggRTFAtMAFIJ29FOT9FYDagMYFSqhnrR3ohiTNzfpYNMC +AwEAAQ== +-----END PUBLIC KEY----- diff --git a/x509_acert/certs/rsa_pss/acert_pkey.pem b/x509_acert/certs/rsa_pss/acert_pkey.pem new file mode 100644 index 00000000..a0f2d828 --- /dev/null +++ b/x509_acert/certs/rsa_pss/acert_pkey.pem @@ -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----- diff --git a/x509_acert/set_env b/x509_acert/set_env new file mode 100644 index 00000000..931d443a --- /dev/null +++ b/x509_acert/set_env @@ -0,0 +1,3 @@ +#!/bin/bash +export LD_LIBRARY_PATH=/usr/local/lib64/:/usr/local/lib/ +echo "info: using env: $LD_LIBRARY_PATH" diff --git a/x509_acert/test_x509_acert.c b/x509_acert/test_x509_acert.c new file mode 100644 index 00000000..c057b3b4 --- /dev/null +++ b/x509_acert/test_x509_acert.c @@ -0,0 +1,871 @@ +/* glibc includes */ +#include +#include +#include +#include + +#if defined(USE_WOLFSSL) + /* wolfssl includes */ + #include + #include + #include + #include + #include + #include +#else + /* openssl includes */ + #include + #include + #include + #include +#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) && defined(PUBLIC_ASN) +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 && PUBLIC_ASN*/ + +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) && defined(PUBLIC_ASN) + 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 && PUBLIC_ASN*/ + + 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) && defined(PUBLIC_ASN) +/* Given an x509, retrieves the raw attributes buffer and + * length, and then parses it. + * + * 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; + int seq_len = 0; + int rc = 0; + + rc = wolfSSL_X509_ACERT_get_attr_buf(x509, &attr, &attr_len); + + if (rc != 0) { + 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; + + seq_len = GetSequence(attr + idx, &idx, &seq_len, max_idx); + + if (seq_len <= 0) { + printf("error: GetSequence(%p, %d, %d, %d) returned: %d\n", attr, + idx, seq_len, max_idx, seq_len); + return -1; + } + else { + printf("info: GetSequence(%p, %d, %d, %d) returned: %d\n", attr, + idx, seq_len, max_idx, seq_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" + +/* 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) { + if (isalnum(data[i + 2 + j])) { + printf("%c", data[i + 2 + j]); + } + else { + //printf("%d", data[i + 2 + j]); + printf("."); + } + } + 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]); + } + + printf("\n"); + } + } + + printf("\n"); + + return; +} +#endif /* if USE_WOLFSSL && PUBLIC_ASN*/ + +/* 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 \n"); + printf(" -f \n"); + printf(" -m (rsa_pss only)\n"); + printf(" -l (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); +}