1 /*	$OpenBSD: pkcs7test.c,v 1.5 2021/04/07 17:21:40 tb Exp $	*/
2 /*
3  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <err.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include <openssl/bio.h>
24 #include <openssl/err.h>
25 #include <openssl/evp.h>
26 #include <openssl/pem.h>
27 #include <openssl/pkcs7.h>
28 #include <openssl/x509.h>
29 
30 const char certificate[] = "\
31 -----BEGIN CERTIFICATE----- \n\
32 MIIDpTCCAo2gAwIBAgIJAPYm3GvOr5eTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV \n\
33 BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT \n\
34 VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt \n\
35 ZWRpYXRlIENBMB4XDTE0MDUyNDE0NDUxMVoXDTI0MDQwMTE0NDUxMVowZDELMAkG \n\
36 A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU \n\
37 RVNUSU5HIFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgQ2xpZW50IENlcnQw \n\
38 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0ranbHRLcLVqN+0BzcZpY \n\
39 +yOLqxzDWT1LD9eW1stC4NzXX9/DCtSIVyN7YIHdGLrIPr64IDdXXaMRzgZ2rOKs \n\
40 lmHCAiFpO/ja99gGCJRxH0xwQatqAULfJVHeUhs7OEGOZc2nWifjqKvGfNTilP7D \n\
41 nwi69ipQFq9oS19FmhwVHk2wg7KZGHI1qDyG04UrfCZMRitvS9+UVhPpIPjuiBi2 \n\
42 x3/FZIpL5gXJvvFK6xHY63oq2asyzBATntBgnP4qJFWWcvRx24wF1PnZabxuVoL2 \n\
43 bPnQ/KvONDrw3IdqkKhYNTul7jEcu3OlcZIMw+7DiaKJLAzKb/bBF5gm/pwW6As9 \n\
44 AgMBAAGjTjBMMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXgMCwGCWCGSAGG \n\
45 +EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0B \n\
46 AQUFAAOCAQEAJzA4KTjkjXGSC4He63yX9Br0DneGBzjAwc1H6f72uqnCs8m7jgkE \n\
47 PQJFdTzQUKh97QPUuayZ2gl8XHagg+iWGy60Kw37gQ0+lumCN2sllvifhHU9R03H \n\
48 bWtS4kue+yQjMbrzf3zWygMDgwvFOUAIgBpH9qGc+CdNu97INTYd0Mvz51vLlxRn \n\
49 sC5aBYCWaZFnw3lWYxf9eVFRy9U+DkYFqX0LpmbDtcKP7AZGE6ZwSzaim+Cnoz1u \n\
50 Cgn+QmpFXgJKMFIZ82iSZISn+JkCCGxctZX1lMvai4Wi8Y0HxW9FTFZ6KBNwwE4B \n\
51 zjbN/ehBkgLlW/DWfi44DvwUHmuU6QP3cw== \n\
52 -----END CERTIFICATE----- \n\
53 ";
54 
55 const char private_key[] = "\
56 -----BEGIN RSA PRIVATE KEY----- \n\
57 MIIEpQIBAAKCAQEAtK2p2x0S3C1ajftAc3GaWPsji6scw1k9Sw/XltbLQuDc11/f \n\
58 wwrUiFcje2CB3Ri6yD6+uCA3V12jEc4GdqzirJZhwgIhaTv42vfYBgiUcR9McEGr \n\
59 agFC3yVR3lIbOzhBjmXNp1on46irxnzU4pT+w58IuvYqUBavaEtfRZocFR5NsIOy \n\
60 mRhyNag8htOFK3wmTEYrb0vflFYT6SD47ogYtsd/xWSKS+YFyb7xSusR2Ot6Ktmr \n\
61 MswQE57QYJz+KiRVlnL0cduMBdT52Wm8blaC9mz50PyrzjQ68NyHapCoWDU7pe4x \n\
62 HLtzpXGSDMPuw4miiSwMym/2wReYJv6cFugLPQIDAQABAoIBAAZOyc9MhIwLSU4L \n\
63 p4RgQvM4UVVe8/Id+3XTZ8NsXExJbWxXfIhiqGjaIfL8u4vsgRjcl+v1s/jo2/iT \n\
64 KMab4o4D8gXD7UavQVDjtjb/ta79WL3SjRl2Uc9YjjMkyq6WmDNQeo2NKDdafCTB \n\
65 1uzSJtLNipB8Z53ELPuHJhxX9QMHrMnuha49riQgXZ7buP9iQrHJFhImBjSzbxJx \n\
66 L+TI6rkyLSf9Wi0Pd3L27Ob3QWNfNRYNSeTE+08eSRChkur5W0RuXAcuAICdQlCl \n\
67 LBvWO/LmmvbzCqiDcgy/TliSb6CGGwgiNG7LJZmlkYNj8laGwalNlYZs3UrVv6NO \n\
68 Br2loAECgYEA2kvCvPGj0Dg/6g7WhXDvAkEbcaL1tSeCxBbNH+6HS2UWMWvyTtCn \n\
69 /bbD519QIdkvayy1QjEf32GV/UjUVmlULMLBcDy0DGjtL3+XpIhLKWDNxN1v1/ai \n\
70 1oz23ZJCOgnk6K4qtFtlRS1XtynjA+rBetvYvLP9SKeFrnpzCgaA2r0CgYEA0+KX \n\
71 1ACXDTNH5ySX3kMjSS9xdINf+OOw4CvPHFwbtc9aqk2HePlEsBTz5I/W3rKwXva3 \n\
72 NqZ/bRqVVeZB/hHKFywgdUQk2Uc5z/S7Lw70/w1HubNTXGU06Ngb6zOFAo/o/TwZ \n\
73 zTP1BMIKSOB6PAZPS3l+aLO4FRIRotfFhgRHOoECgYEAmiZbqt8cJaJDB/5YYDzC \n\
74 mp3tSk6gIb936Q6M5VqkMYp9pIKsxhk0N8aDCnTU+kIK6SzWBpr3/d9Ecmqmfyq7 \n\
75 5SvWO3KyVf0WWK9KH0abhOm2BKm2HBQvI0DB5u8sUx2/hsvOnjPYDISbZ11t0MtK \n\
76 u35Zy89yMYcSsIYJjG/ROCUCgYEAgI2P9G5PNxEP5OtMwOsW84Y3Xat/hPAQFlI+ \n\
77 HES+AzbFGWJkeT8zL2nm95tVkFP1sggZ7Kxjz3w7cpx7GX0NkbWSE9O+T51pNASV \n\
78 tN1sQ3p5M+/a+cnlqgfEGJVvc7iAcXQPa3LEi5h2yPR49QYXAgG6cifn3dDSpmwn \n\
79 SUI7PQECgYEApGCIIpSRPLAEHTGmP87RBL1smurhwmy2s/pghkvUkWehtxg0sGHh \n\
80 kuaqDWcskogv+QC0sVdytiLSz8G0DwcEcsHK1Fkyb8A+ayiw6jWJDo2m9+IF4Fww \n\
81 1Te6jFPYDESnbhq7+TLGgHGhtwcu5cnb4vSuYXGXKupZGzoLOBbv1Zw= \n\
82 -----END RSA PRIVATE KEY----- \n\
83 ";
84 
85 const char message[] = "\
86 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do \r\n\
87 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut   \r\n\
88 enim ad minim veniam, quis nostrud exercitation ullamco laboris  \r\n\
89 nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor   \r\n\
90 in reprehenderit in voluptate velit esse cillum dolore eu fugiat \r\n\
91 nulla pariatur. Excepteur sint occaecat cupidatat non proident,  \r\n\
92 sunt in culpa qui officia deserunt mollit anim id est laborum.   \r\n\
93 ";
94 
95 static int
96 x509_store_callback(int ok, X509_STORE_CTX *ctx)
97 {
98 	/* Pretend the certificate issuer is valid... */
99 	return 1;
100 }
101 
102 static void
103 fatal(const char *msg)
104 {
105 	warnx("%s", msg);
106 	ERR_print_errors_fp(stderr);
107 	exit(1);
108 }
109 
110 static void
111 message_compare(const char *out, size_t len)
112 {
113 	if (len != sizeof(message)) {
114 		fprintf(stderr, "FAILURE: length mismatch (%zu != %zu)\n",
115 		    len, sizeof(message));
116 		exit(1);
117 	}
118 	if (memcmp(out, message, len) != 0) {
119 		fprintf(stderr, "FAILURE: message mismatch\n");
120 		fprintf(stderr, "Got:\n%s\n", out);
121 		fprintf(stderr, "Want:\n%s\n", message);
122 		exit(1);
123 	}
124 }
125 
126 int
127 main(int argc, char **argv)
128 {
129 	BIO *bio_in, *bio_content, *bio_out, *bio_cert, *bio_pkey;
130 	STACK_OF(X509) *certs;
131 	const EVP_CIPHER *cipher;
132 	EVP_PKEY *pkey;
133 	X509_STORE *store;
134 	X509 *cert;
135 	PKCS7 *p7;
136 	size_t len;
137 	char *out;
138 	int flags;
139 
140 	ERR_load_crypto_strings();
141 	OpenSSL_add_all_algorithms();
142 
143 	/*
144 	 * A bunch of setup...
145 	 */
146 	cipher = EVP_aes_256_cbc();
147 	if (cipher == NULL)
148 		fatal("cipher");
149 
150 	certs = sk_X509_new_null();
151 	if (certs == NULL)
152 		fatal("sk_X509_new_null");
153 
154 	bio_cert = BIO_new_mem_buf((char *)certificate, sizeof(certificate));
155 	if (bio_cert == NULL)
156 		fatal("BIO_new_mem_buf certificate");
157 
158 	cert = PEM_read_bio_X509_AUX(bio_cert, NULL, NULL, NULL);
159 	if (cert == NULL)
160 		fatal("PEM_read_bio_X509_AUX");
161 	sk_X509_push(certs, cert);
162 
163 	store = X509_STORE_new();
164 	if (store == NULL)
165 		fatal("X509_STORE_new");
166 	X509_STORE_set_verify_cb(store, x509_store_callback);
167 
168 	bio_pkey = BIO_new_mem_buf((char *)private_key, sizeof(private_key));
169 	if (bio_pkey == NULL)
170 		fatal("BIO_new_mem_buf private_key");
171 
172 	pkey = PEM_read_bio_PrivateKey(bio_pkey, NULL, NULL, NULL);
173 	if (pkey == NULL)
174 		fatal("PEM_read_bio_PrivateKey");
175 
176 	bio_content = BIO_new_mem_buf((char *)message, sizeof(message));
177 	if (bio_content == NULL)
178 		fatal("BIO_new_mem_buf message");
179 
180 	/*
181 	 * Encrypt and then decrypt.
182 	 */
183 	if (BIO_reset(bio_content) != 1)
184 		fatal("BIO_reset");
185 	bio_out = BIO_new(BIO_s_mem());
186 	if (bio_out == NULL)
187 		fatal("BIO_new");
188 
189 	p7 = PKCS7_encrypt(certs, bio_content, cipher, 0);
190 	if (p7 == NULL)
191 		fatal("PKCS7_encrypt");
192 	if (PEM_write_bio_PKCS7(bio_out, p7) != 1)
193 		fatal("PEM_write_bio_PKCS7");
194 	PKCS7_free(p7);
195 
196 	bio_in = bio_out;
197 	bio_out = BIO_new(BIO_s_mem());
198 	if (bio_out == NULL)
199 		fatal("BIO_new");
200 
201 	p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
202 	if (p7 == NULL)
203 		fatal("PEM_read_bio_PKCS7");
204 	if (PKCS7_decrypt(p7, pkey, cert, bio_out, 0) != 1)
205 		fatal("PKCS7_decrypt");
206 	PKCS7_free(p7);
207 
208 	len = BIO_get_mem_data(bio_out, &out);
209 	message_compare(out, len);
210 
211 	BIO_free(bio_in);
212 	BIO_free(bio_out);
213 
214 	/*
215 	 * Sign and then verify.
216 	 */
217 	if (BIO_reset(bio_content) != 1)
218 		fatal("BIO_reset");
219 	bio_out = BIO_new(BIO_s_mem());
220 	if (bio_out == NULL)
221 		fatal("BIO_new");
222 
223 	p7 = PKCS7_sign(cert, pkey, certs, bio_content, 0);
224 	if (p7 == NULL)
225 		fatal("PKCS7_sign");
226 	if (PEM_write_bio_PKCS7(bio_out, p7) != 1)
227 		fatal("PEM_write_bio_PKCS7");
228 	PKCS7_free(p7);
229 
230 	bio_in = bio_out;
231 	bio_out = BIO_new(BIO_s_mem());
232 	if (bio_out == NULL)
233 		fatal("BIO_new");
234 
235 	p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
236 	if (p7 == NULL)
237 		fatal("PEM_read_bio_PKCS7");
238 	if (PKCS7_verify(p7, certs, store, NULL, bio_out, 0) != 1)
239 		fatal("PKCS7_verify");
240 	PKCS7_free(p7);
241 
242 	len = BIO_get_mem_data(bio_out, &out);
243 	message_compare(out, len);
244 
245 	BIO_free(bio_in);
246 	BIO_free(bio_out);
247 
248 	/*
249 	 * Sign and then verify with a detached signature.
250 	 */
251 	if (BIO_reset(bio_content) != 1)
252 		fatal("BIO_reset");
253 	bio_out = BIO_new(BIO_s_mem());
254 	if (bio_out == NULL)
255 		fatal("BIO_new");
256 
257 	flags = PKCS7_DETACHED|PKCS7_PARTIAL;
258 	p7 = PKCS7_sign(NULL, NULL, NULL, bio_content, flags);
259 	if (p7 == NULL)
260 		fatal("PKCS7_sign");
261 	if (PKCS7_sign_add_signer(p7, cert, pkey, NULL, flags) == NULL)
262 		fatal("PKCS7_sign_add_signer");
263 	if (PKCS7_final(p7, bio_content, flags) != 1)
264 		fatal("PKCS7_final");
265 	if (PEM_write_bio_PKCS7(bio_out, p7) != 1)
266 		fatal("PEM_write_bio_PKCS7");
267 	PKCS7_free(p7);
268 
269 	/* bio_out contains only the detached signature. */
270 	bio_in = bio_out;
271 	if (BIO_reset(bio_content) != 1)
272 		fatal("BIO_reset");
273 
274 	bio_out = BIO_new(BIO_s_mem());
275 	if (bio_out == NULL)
276 		fatal("BIO_new");
277 
278 	p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
279 	if (p7 == NULL)
280 		fatal("PEM_read_bio_PKCS7");
281 	if (PKCS7_verify(p7, certs, store, bio_content, bio_out, flags) != 1)
282 		fatal("PKCS7_verify");
283 	PKCS7_free(p7);
284 
285 	len = BIO_get_mem_data(bio_out, &out);
286 	message_compare(out, len);
287 
288 	BIO_free(bio_in);
289 	BIO_free(bio_out);
290 	BIO_free(bio_content);
291 	BIO_free(bio_cert);
292 	BIO_free(bio_pkey);
293 
294 	EVP_PKEY_free(pkey);
295 
296 	X509_free(cert);
297 	X509_STORE_free(store);
298 	sk_X509_free(certs);
299 
300 	return 0;
301 }
302