1*e4b8c6e7Stb /* $OpenBSD: pkcs7test.c,v 1.5 2021/04/07 17:21:40 tb Exp $ */
25e59aae3Sjsing /*
35e59aae3Sjsing * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
45e59aae3Sjsing *
55e59aae3Sjsing * Permission to use, copy, modify, and distribute this software for any
65e59aae3Sjsing * purpose with or without fee is hereby granted, provided that the above
75e59aae3Sjsing * copyright notice and this permission notice appear in all copies.
85e59aae3Sjsing *
95e59aae3Sjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
105e59aae3Sjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
115e59aae3Sjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
125e59aae3Sjsing * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
135e59aae3Sjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
145e59aae3Sjsing * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
155e59aae3Sjsing * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165e59aae3Sjsing */
175e59aae3Sjsing
185e59aae3Sjsing #include <err.h>
195e59aae3Sjsing #include <stdlib.h>
205e59aae3Sjsing #include <string.h>
215e59aae3Sjsing #include <unistd.h>
225e59aae3Sjsing
235e59aae3Sjsing #include <openssl/bio.h>
245e59aae3Sjsing #include <openssl/err.h>
255e59aae3Sjsing #include <openssl/evp.h>
265e59aae3Sjsing #include <openssl/pem.h>
275e59aae3Sjsing #include <openssl/pkcs7.h>
285e59aae3Sjsing #include <openssl/x509.h>
295e59aae3Sjsing
305e59aae3Sjsing const char certificate[] = "\
315e59aae3Sjsing -----BEGIN CERTIFICATE----- \n\
325e59aae3Sjsing MIIDpTCCAo2gAwIBAgIJAPYm3GvOr5eTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV \n\
335e59aae3Sjsing BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT \n\
345e59aae3Sjsing VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt \n\
355e59aae3Sjsing ZWRpYXRlIENBMB4XDTE0MDUyNDE0NDUxMVoXDTI0MDQwMTE0NDUxMVowZDELMAkG \n\
365e59aae3Sjsing A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU \n\
375e59aae3Sjsing RVNUSU5HIFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgQ2xpZW50IENlcnQw \n\
385e59aae3Sjsing ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0ranbHRLcLVqN+0BzcZpY \n\
395e59aae3Sjsing +yOLqxzDWT1LD9eW1stC4NzXX9/DCtSIVyN7YIHdGLrIPr64IDdXXaMRzgZ2rOKs \n\
405e59aae3Sjsing lmHCAiFpO/ja99gGCJRxH0xwQatqAULfJVHeUhs7OEGOZc2nWifjqKvGfNTilP7D \n\
415e59aae3Sjsing nwi69ipQFq9oS19FmhwVHk2wg7KZGHI1qDyG04UrfCZMRitvS9+UVhPpIPjuiBi2 \n\
425e59aae3Sjsing x3/FZIpL5gXJvvFK6xHY63oq2asyzBATntBgnP4qJFWWcvRx24wF1PnZabxuVoL2 \n\
435e59aae3Sjsing bPnQ/KvONDrw3IdqkKhYNTul7jEcu3OlcZIMw+7DiaKJLAzKb/bBF5gm/pwW6As9 \n\
445e59aae3Sjsing AgMBAAGjTjBMMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXgMCwGCWCGSAGG \n\
455e59aae3Sjsing +EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0B \n\
465e59aae3Sjsing AQUFAAOCAQEAJzA4KTjkjXGSC4He63yX9Br0DneGBzjAwc1H6f72uqnCs8m7jgkE \n\
475e59aae3Sjsing PQJFdTzQUKh97QPUuayZ2gl8XHagg+iWGy60Kw37gQ0+lumCN2sllvifhHU9R03H \n\
485e59aae3Sjsing bWtS4kue+yQjMbrzf3zWygMDgwvFOUAIgBpH9qGc+CdNu97INTYd0Mvz51vLlxRn \n\
495e59aae3Sjsing sC5aBYCWaZFnw3lWYxf9eVFRy9U+DkYFqX0LpmbDtcKP7AZGE6ZwSzaim+Cnoz1u \n\
505e59aae3Sjsing Cgn+QmpFXgJKMFIZ82iSZISn+JkCCGxctZX1lMvai4Wi8Y0HxW9FTFZ6KBNwwE4B \n\
515e59aae3Sjsing zjbN/ehBkgLlW/DWfi44DvwUHmuU6QP3cw== \n\
525e59aae3Sjsing -----END CERTIFICATE----- \n\
535e59aae3Sjsing ";
545e59aae3Sjsing
555e59aae3Sjsing const char private_key[] = "\
565e59aae3Sjsing -----BEGIN RSA PRIVATE KEY----- \n\
575e59aae3Sjsing MIIEpQIBAAKCAQEAtK2p2x0S3C1ajftAc3GaWPsji6scw1k9Sw/XltbLQuDc11/f \n\
585e59aae3Sjsing wwrUiFcje2CB3Ri6yD6+uCA3V12jEc4GdqzirJZhwgIhaTv42vfYBgiUcR9McEGr \n\
595e59aae3Sjsing agFC3yVR3lIbOzhBjmXNp1on46irxnzU4pT+w58IuvYqUBavaEtfRZocFR5NsIOy \n\
605e59aae3Sjsing mRhyNag8htOFK3wmTEYrb0vflFYT6SD47ogYtsd/xWSKS+YFyb7xSusR2Ot6Ktmr \n\
615e59aae3Sjsing MswQE57QYJz+KiRVlnL0cduMBdT52Wm8blaC9mz50PyrzjQ68NyHapCoWDU7pe4x \n\
625e59aae3Sjsing HLtzpXGSDMPuw4miiSwMym/2wReYJv6cFugLPQIDAQABAoIBAAZOyc9MhIwLSU4L \n\
635e59aae3Sjsing p4RgQvM4UVVe8/Id+3XTZ8NsXExJbWxXfIhiqGjaIfL8u4vsgRjcl+v1s/jo2/iT \n\
645e59aae3Sjsing KMab4o4D8gXD7UavQVDjtjb/ta79WL3SjRl2Uc9YjjMkyq6WmDNQeo2NKDdafCTB \n\
655e59aae3Sjsing 1uzSJtLNipB8Z53ELPuHJhxX9QMHrMnuha49riQgXZ7buP9iQrHJFhImBjSzbxJx \n\
665e59aae3Sjsing L+TI6rkyLSf9Wi0Pd3L27Ob3QWNfNRYNSeTE+08eSRChkur5W0RuXAcuAICdQlCl \n\
675e59aae3Sjsing LBvWO/LmmvbzCqiDcgy/TliSb6CGGwgiNG7LJZmlkYNj8laGwalNlYZs3UrVv6NO \n\
685e59aae3Sjsing Br2loAECgYEA2kvCvPGj0Dg/6g7WhXDvAkEbcaL1tSeCxBbNH+6HS2UWMWvyTtCn \n\
695e59aae3Sjsing /bbD519QIdkvayy1QjEf32GV/UjUVmlULMLBcDy0DGjtL3+XpIhLKWDNxN1v1/ai \n\
705e59aae3Sjsing 1oz23ZJCOgnk6K4qtFtlRS1XtynjA+rBetvYvLP9SKeFrnpzCgaA2r0CgYEA0+KX \n\
715e59aae3Sjsing 1ACXDTNH5ySX3kMjSS9xdINf+OOw4CvPHFwbtc9aqk2HePlEsBTz5I/W3rKwXva3 \n\
725e59aae3Sjsing NqZ/bRqVVeZB/hHKFywgdUQk2Uc5z/S7Lw70/w1HubNTXGU06Ngb6zOFAo/o/TwZ \n\
735e59aae3Sjsing zTP1BMIKSOB6PAZPS3l+aLO4FRIRotfFhgRHOoECgYEAmiZbqt8cJaJDB/5YYDzC \n\
745e59aae3Sjsing mp3tSk6gIb936Q6M5VqkMYp9pIKsxhk0N8aDCnTU+kIK6SzWBpr3/d9Ecmqmfyq7 \n\
755e59aae3Sjsing 5SvWO3KyVf0WWK9KH0abhOm2BKm2HBQvI0DB5u8sUx2/hsvOnjPYDISbZ11t0MtK \n\
765e59aae3Sjsing u35Zy89yMYcSsIYJjG/ROCUCgYEAgI2P9G5PNxEP5OtMwOsW84Y3Xat/hPAQFlI+ \n\
775e59aae3Sjsing HES+AzbFGWJkeT8zL2nm95tVkFP1sggZ7Kxjz3w7cpx7GX0NkbWSE9O+T51pNASV \n\
785e59aae3Sjsing tN1sQ3p5M+/a+cnlqgfEGJVvc7iAcXQPa3LEi5h2yPR49QYXAgG6cifn3dDSpmwn \n\
795e59aae3Sjsing SUI7PQECgYEApGCIIpSRPLAEHTGmP87RBL1smurhwmy2s/pghkvUkWehtxg0sGHh \n\
805e59aae3Sjsing kuaqDWcskogv+QC0sVdytiLSz8G0DwcEcsHK1Fkyb8A+ayiw6jWJDo2m9+IF4Fww \n\
815e59aae3Sjsing 1Te6jFPYDESnbhq7+TLGgHGhtwcu5cnb4vSuYXGXKupZGzoLOBbv1Zw= \n\
825e59aae3Sjsing -----END RSA PRIVATE KEY----- \n\
835e59aae3Sjsing ";
845e59aae3Sjsing
855e59aae3Sjsing const char message[] = "\
865e59aae3Sjsing Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do \r\n\
875e59aae3Sjsing eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \r\n\
885e59aae3Sjsing enim ad minim veniam, quis nostrud exercitation ullamco laboris \r\n\
895e59aae3Sjsing nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor \r\n\
905e59aae3Sjsing in reprehenderit in voluptate velit esse cillum dolore eu fugiat \r\n\
915e59aae3Sjsing nulla pariatur. Excepteur sint occaecat cupidatat non proident, \r\n\
925e59aae3Sjsing sunt in culpa qui officia deserunt mollit anim id est laborum. \r\n\
935e59aae3Sjsing ";
945e59aae3Sjsing
955e59aae3Sjsing static int
x509_store_callback(int ok,X509_STORE_CTX * ctx)965e59aae3Sjsing x509_store_callback(int ok, X509_STORE_CTX *ctx)
975e59aae3Sjsing {
985e59aae3Sjsing /* Pretend the certificate issuer is valid... */
995e59aae3Sjsing return 1;
1005e59aae3Sjsing }
1015e59aae3Sjsing
1025e59aae3Sjsing static void
fatal(const char * msg)1035e59aae3Sjsing fatal(const char *msg)
1045e59aae3Sjsing {
105e852c558Sbcook warnx("%s", msg);
106*e4b8c6e7Stb ERR_print_errors_fp(stderr);
1075e59aae3Sjsing exit(1);
1085e59aae3Sjsing }
1095e59aae3Sjsing
1105e59aae3Sjsing static void
message_compare(const char * out,size_t len)1115e59aae3Sjsing message_compare(const char *out, size_t len)
1125e59aae3Sjsing {
1135e59aae3Sjsing if (len != sizeof(message)) {
1145e59aae3Sjsing fprintf(stderr, "FAILURE: length mismatch (%zu != %zu)\n",
1155e59aae3Sjsing len, sizeof(message));
1165e59aae3Sjsing exit(1);
1175e59aae3Sjsing }
11891814ce8Sbcook if (memcmp(out, message, len) != 0) {
1195e59aae3Sjsing fprintf(stderr, "FAILURE: message mismatch\n");
1205e59aae3Sjsing fprintf(stderr, "Got:\n%s\n", out);
1215e59aae3Sjsing fprintf(stderr, "Want:\n%s\n", message);
1225e59aae3Sjsing exit(1);
1235e59aae3Sjsing }
1245e59aae3Sjsing }
1255e59aae3Sjsing
1265e59aae3Sjsing int
main(int argc,char ** argv)1275e59aae3Sjsing main(int argc, char **argv)
1285e59aae3Sjsing {
1295e59aae3Sjsing BIO *bio_in, *bio_content, *bio_out, *bio_cert, *bio_pkey;
1305e59aae3Sjsing STACK_OF(X509) *certs;
1315e59aae3Sjsing const EVP_CIPHER *cipher;
1325e59aae3Sjsing EVP_PKEY *pkey;
1335e59aae3Sjsing X509_STORE *store;
1345e59aae3Sjsing X509 *cert;
1355e59aae3Sjsing PKCS7 *p7;
1365e59aae3Sjsing size_t len;
1375e59aae3Sjsing char *out;
1385e59aae3Sjsing int flags;
1395e59aae3Sjsing
1405e59aae3Sjsing ERR_load_crypto_strings();
1415e59aae3Sjsing OpenSSL_add_all_algorithms();
1425e59aae3Sjsing
1435e59aae3Sjsing /*
1445e59aae3Sjsing * A bunch of setup...
1455e59aae3Sjsing */
1465e59aae3Sjsing cipher = EVP_aes_256_cbc();
1475e59aae3Sjsing if (cipher == NULL)
1485e59aae3Sjsing fatal("cipher");
1495e59aae3Sjsing
1505e59aae3Sjsing certs = sk_X509_new_null();
1515e59aae3Sjsing if (certs == NULL)
1525e59aae3Sjsing fatal("sk_X509_new_null");
1535e59aae3Sjsing
1545e59aae3Sjsing bio_cert = BIO_new_mem_buf((char *)certificate, sizeof(certificate));
1555e59aae3Sjsing if (bio_cert == NULL)
1565e59aae3Sjsing fatal("BIO_new_mem_buf certificate");
1575e59aae3Sjsing
1585e59aae3Sjsing cert = PEM_read_bio_X509_AUX(bio_cert, NULL, NULL, NULL);
1595e59aae3Sjsing if (cert == NULL)
1605e59aae3Sjsing fatal("PEM_read_bio_X509_AUX");
1615e59aae3Sjsing sk_X509_push(certs, cert);
1625e59aae3Sjsing
1635e59aae3Sjsing store = X509_STORE_new();
1645e59aae3Sjsing if (store == NULL)
1655e59aae3Sjsing fatal("X509_STORE_new");
1665e59aae3Sjsing X509_STORE_set_verify_cb(store, x509_store_callback);
1675e59aae3Sjsing
1685e59aae3Sjsing bio_pkey = BIO_new_mem_buf((char *)private_key, sizeof(private_key));
1695e59aae3Sjsing if (bio_pkey == NULL)
1705e59aae3Sjsing fatal("BIO_new_mem_buf private_key");
1715e59aae3Sjsing
1725e59aae3Sjsing pkey = PEM_read_bio_PrivateKey(bio_pkey, NULL, NULL, NULL);
1735e59aae3Sjsing if (pkey == NULL)
1745e59aae3Sjsing fatal("PEM_read_bio_PrivateKey");
1755e59aae3Sjsing
1765e59aae3Sjsing bio_content = BIO_new_mem_buf((char *)message, sizeof(message));
1775e59aae3Sjsing if (bio_content == NULL)
1785e59aae3Sjsing fatal("BIO_new_mem_buf message");
1795e59aae3Sjsing
1805e59aae3Sjsing /*
1815e59aae3Sjsing * Encrypt and then decrypt.
1825e59aae3Sjsing */
1835e59aae3Sjsing if (BIO_reset(bio_content) != 1)
1845e59aae3Sjsing fatal("BIO_reset");
1855e59aae3Sjsing bio_out = BIO_new(BIO_s_mem());
1865e59aae3Sjsing if (bio_out == NULL)
1875e59aae3Sjsing fatal("BIO_new");
1885e59aae3Sjsing
1895e59aae3Sjsing p7 = PKCS7_encrypt(certs, bio_content, cipher, 0);
1905e59aae3Sjsing if (p7 == NULL)
1915e59aae3Sjsing fatal("PKCS7_encrypt");
1925e59aae3Sjsing if (PEM_write_bio_PKCS7(bio_out, p7) != 1)
1935e59aae3Sjsing fatal("PEM_write_bio_PKCS7");
1945e59aae3Sjsing PKCS7_free(p7);
1955e59aae3Sjsing
1965e59aae3Sjsing bio_in = bio_out;
1975e59aae3Sjsing bio_out = BIO_new(BIO_s_mem());
1985e59aae3Sjsing if (bio_out == NULL)
1995e59aae3Sjsing fatal("BIO_new");
2005e59aae3Sjsing
2015e59aae3Sjsing p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
2025e59aae3Sjsing if (p7 == NULL)
2035e59aae3Sjsing fatal("PEM_read_bio_PKCS7");
2045e59aae3Sjsing if (PKCS7_decrypt(p7, pkey, cert, bio_out, 0) != 1)
2055e59aae3Sjsing fatal("PKCS7_decrypt");
206bc2cda7aSjsing PKCS7_free(p7);
2075e59aae3Sjsing
2085e59aae3Sjsing len = BIO_get_mem_data(bio_out, &out);
2095e59aae3Sjsing message_compare(out, len);
2105e59aae3Sjsing
211bc2cda7aSjsing BIO_free(bio_in);
2125e59aae3Sjsing BIO_free(bio_out);
2135e59aae3Sjsing
2145e59aae3Sjsing /*
2155e59aae3Sjsing * Sign and then verify.
2165e59aae3Sjsing */
2175e59aae3Sjsing if (BIO_reset(bio_content) != 1)
2185e59aae3Sjsing fatal("BIO_reset");
2195e59aae3Sjsing bio_out = BIO_new(BIO_s_mem());
2205e59aae3Sjsing if (bio_out == NULL)
2215e59aae3Sjsing fatal("BIO_new");
2225e59aae3Sjsing
2235e59aae3Sjsing p7 = PKCS7_sign(cert, pkey, certs, bio_content, 0);
2245e59aae3Sjsing if (p7 == NULL)
2255e59aae3Sjsing fatal("PKCS7_sign");
2265e59aae3Sjsing if (PEM_write_bio_PKCS7(bio_out, p7) != 1)
2275e59aae3Sjsing fatal("PEM_write_bio_PKCS7");
2285e59aae3Sjsing PKCS7_free(p7);
2295e59aae3Sjsing
2305e59aae3Sjsing bio_in = bio_out;
2315e59aae3Sjsing bio_out = BIO_new(BIO_s_mem());
2325e59aae3Sjsing if (bio_out == NULL)
2335e59aae3Sjsing fatal("BIO_new");
2345e59aae3Sjsing
2355e59aae3Sjsing p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
2365e59aae3Sjsing if (p7 == NULL)
2375e59aae3Sjsing fatal("PEM_read_bio_PKCS7");
2385e59aae3Sjsing if (PKCS7_verify(p7, certs, store, NULL, bio_out, 0) != 1)
2395e59aae3Sjsing fatal("PKCS7_verify");
240bc2cda7aSjsing PKCS7_free(p7);
2415e59aae3Sjsing
2425e59aae3Sjsing len = BIO_get_mem_data(bio_out, &out);
2435e59aae3Sjsing message_compare(out, len);
2445e59aae3Sjsing
2455e59aae3Sjsing BIO_free(bio_in);
2465e59aae3Sjsing BIO_free(bio_out);
2475e59aae3Sjsing
2485e59aae3Sjsing /*
2495e59aae3Sjsing * Sign and then verify with a detached signature.
2505e59aae3Sjsing */
2515e59aae3Sjsing if (BIO_reset(bio_content) != 1)
2525e59aae3Sjsing fatal("BIO_reset");
2535e59aae3Sjsing bio_out = BIO_new(BIO_s_mem());
2545e59aae3Sjsing if (bio_out == NULL)
2555e59aae3Sjsing fatal("BIO_new");
2565e59aae3Sjsing
2575e59aae3Sjsing flags = PKCS7_DETACHED|PKCS7_PARTIAL;
2585e59aae3Sjsing p7 = PKCS7_sign(NULL, NULL, NULL, bio_content, flags);
2595e59aae3Sjsing if (p7 == NULL)
2605e59aae3Sjsing fatal("PKCS7_sign");
2615e59aae3Sjsing if (PKCS7_sign_add_signer(p7, cert, pkey, NULL, flags) == NULL)
2625e59aae3Sjsing fatal("PKCS7_sign_add_signer");
2635e59aae3Sjsing if (PKCS7_final(p7, bio_content, flags) != 1)
2645e59aae3Sjsing fatal("PKCS7_final");
2655e59aae3Sjsing if (PEM_write_bio_PKCS7(bio_out, p7) != 1)
2665e59aae3Sjsing fatal("PEM_write_bio_PKCS7");
2675e59aae3Sjsing PKCS7_free(p7);
2685e59aae3Sjsing
2695e59aae3Sjsing /* bio_out contains only the detached signature. */
2705e59aae3Sjsing bio_in = bio_out;
2715e59aae3Sjsing if (BIO_reset(bio_content) != 1)
2725e59aae3Sjsing fatal("BIO_reset");
2735e59aae3Sjsing
2745e59aae3Sjsing bio_out = BIO_new(BIO_s_mem());
2755e59aae3Sjsing if (bio_out == NULL)
2765e59aae3Sjsing fatal("BIO_new");
2775e59aae3Sjsing
2785e59aae3Sjsing p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
2795e59aae3Sjsing if (p7 == NULL)
2805e59aae3Sjsing fatal("PEM_read_bio_PKCS7");
2815e59aae3Sjsing if (PKCS7_verify(p7, certs, store, bio_content, bio_out, flags) != 1)
2825e59aae3Sjsing fatal("PKCS7_verify");
283bc2cda7aSjsing PKCS7_free(p7);
2845e59aae3Sjsing
2855e59aae3Sjsing len = BIO_get_mem_data(bio_out, &out);
2865e59aae3Sjsing message_compare(out, len);
2875e59aae3Sjsing
2885e59aae3Sjsing BIO_free(bio_in);
2895e59aae3Sjsing BIO_free(bio_out);
2905e59aae3Sjsing BIO_free(bio_content);
291bc2cda7aSjsing BIO_free(bio_cert);
292bc2cda7aSjsing BIO_free(bio_pkey);
293bc2cda7aSjsing
294bc2cda7aSjsing EVP_PKEY_free(pkey);
295bc2cda7aSjsing
296bc2cda7aSjsing X509_free(cert);
297bc2cda7aSjsing X509_STORE_free(store);
298bc2cda7aSjsing sk_X509_free(certs);
2995e59aae3Sjsing
3005e59aae3Sjsing return 0;
3015e59aae3Sjsing }
302