1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /***************************************************************************
21  * Copyright (C) 2017-2021 ZmartZone Holding BV
22  * Copyright (C) 2013-2017 Ping Identity Corporation
23  * All rights reserved.
24  *
25  * DISCLAIMER OF WARRANTIES:
26  *
27  * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
28  * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING,
29  * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT,
30  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  NOR ARE THERE ANY
31  * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE
32  * USAGE.  FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET
33  * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE
34  * WILL BE UNINTERRUPTED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
35  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF
37  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * @Author: Hans Zandbelt - hans.zandbelt@zmartzone.eu
42  *
43  **************************************************************************/
44 
45 #include <stdio.h>
46 #include <string.h>
47 
48 #include <apr_file_io.h>
49 #include <apr_base64.h>
50 
51 #include <openssl/rsa.h>
52 #include <openssl/pem.h>
53 
54 #include <cjose/header.h>
55 #include <cjose/jws.h>
56 
57 #include <mod_auth_openidc.h>
58 
usage(int argc,char ** argv,const char * msg)59 int usage(int argc, char **argv, const char *msg) {
60 	fprintf(stderr, "Usage: %s %s\n", argv[0],
61 			msg ? msg : "[ sign | verify | decrypt | jwk2cert | key2jwk | enckey | hash_base64url | timestamp | uuid ] <options>");
62 	return -1;
63 }
64 
file_read(apr_pool_t * pool,const char * path,char ** rbuf)65 int file_read(apr_pool_t *pool, const char *path, char **rbuf) {
66 	apr_file_t *fd = NULL;
67 	char s_err[128];
68 	int rc;
69 	apr_size_t bytes_read = 0;
70 	apr_finfo_t finfo;
71 	apr_size_t len;
72 
73 	rc = apr_file_open(&fd, path, APR_FOPEN_READ | APR_FOPEN_BUFFERED,
74 			APR_OS_DEFAULT, pool);
75 	if (rc != APR_SUCCESS) {
76 		fprintf(stderr, "could not open file %s: %s", path,
77 				apr_strerror(rc, s_err, sizeof(s_err)));
78 		return -1;
79 	}
80 
81 	apr_file_info_get(&finfo, APR_FINFO_NORM, fd);
82 	len = (apr_size_t) finfo.size;
83 	*rbuf = apr_pcalloc(pool, len + 1);
84 
85 	rc = apr_file_read_full(fd, *rbuf, len, &bytes_read);
86 	if (rc != APR_SUCCESS) {
87 		fprintf(stderr, "could not read file %s: %s", path,
88 				apr_strerror(rc, s_err, sizeof(s_err)));
89 		return -1;
90 	}
91 
92 	(*rbuf)[bytes_read] = '\0';
93 
94 	bytes_read--;
95 	while ((*rbuf)[bytes_read] == '\n') {
96 		(*rbuf)[bytes_read] = '\0';
97 		bytes_read--;
98 	}
99 
100 	apr_file_close(fd);
101 
102 	return 0;
103 }
104 
sign(int argc,char ** argv,apr_pool_t * pool)105 int sign(int argc, char **argv, apr_pool_t *pool) {
106 
107 	if (argc <= 4)
108 		return usage(argc, argv, "sign <algo> <jwt-file> <jwk-file>");
109 
110 	char *s_jwt = NULL, *s_jwk = NULL;
111 	const char *cser = NULL;
112 
113 	if (file_read(pool, argv[3], &s_jwt) != 0)
114 		return -1;
115 	if (file_read(pool, argv[4], &s_jwk) != 0)
116 		return -1;
117 
118 	cjose_err cjose_err;
119 
120 	cjose_header_t *hdr = cjose_header_new(&cjose_err);
121 	cjose_header_set(hdr, "alg", argv[2], &cjose_err);
122 
123 	cjose_jwk_t *jwk = cjose_jwk_import(s_jwk, strlen(s_jwk), &cjose_err);
124 	if (jwk == NULL) {
125 		fprintf(stderr,
126 				"could not import JWK: %s [file: %s, function: %s, line: %ld]\n",
127 				cjose_err.message, cjose_err.file, cjose_err.function,
128 				cjose_err.line);
129 		return -1;
130 	}
131 
132 	cjose_jws_t *jws = cjose_jws_sign(jwk, hdr, (const uint8_t *) s_jwt,
133 			strlen(s_jwt), &cjose_err);
134 	if (jws == NULL) {
135 		fprintf(stderr,
136 				"could not sign JWS: %s [file: %s, function: %s, line: %ld]\n",
137 				cjose_err.message, cjose_err.file, cjose_err.function,
138 				cjose_err.line);
139 		return -1;
140 	}
141 
142 	if (cjose_jws_export(jws, &cser, &cjose_err) == FALSE) {
143 		fprintf(stderr,
144 				"could not serialize JWS: %s [file: %s, function: %s, line: %ld]\n",
145 				cjose_err.message, cjose_err.file, cjose_err.function,
146 				cjose_err.line);
147 		return -1;
148 	}
149 
150 	fprintf(stdout, "%s", cser);
151 
152 	cjose_jws_release(jws);
153 	cjose_jwk_release(jwk);
154 
155 	return 0;
156 }
157 
verify(int argc,char ** argv,apr_pool_t * pool)158 int verify(int argc, char **argv, apr_pool_t *pool) {
159 
160 	if (argc <= 3)
161 		return usage(argc, argv, "verify <serialized-jwt-file> <jwk-file>");
162 
163 	char *s_jwt = NULL, *s_jwk = NULL;
164 
165 	if (file_read(pool, argv[2], &s_jwt) != 0)
166 		return -1;
167 	if (file_read(pool, argv[3], &s_jwk) != 0)
168 		return -1;
169 
170 	cjose_err cjose_err;
171 
172 	cjose_jws_t *jws = cjose_jws_import(s_jwt, strlen(s_jwt), &cjose_err);
173 	if (jws == NULL) {
174 		fprintf(stderr,
175 				"could not import JWS: %s [file: %s, function: %s, line: %ld]\n",
176 				cjose_err.message, cjose_err.file, cjose_err.function,
177 				cjose_err.line);
178 		return -1;
179 	}
180 
181 	oidc_jose_error_t oidc_err;
182 	oidc_jwk_t *jwk = oidc_jwk_parse(pool, s_jwk, &oidc_err);
183 	if (jwk == NULL) {
184 		fprintf(stderr,
185 				"could not import JWK: %s [file: %s, function: %s, line: %d]\n",
186 				oidc_err.text, oidc_err.source, oidc_err.function,
187 				oidc_err.line);
188 		return -1;
189 	}
190 
191 	if (cjose_jws_verify(jws, jwk->cjose_jwk, &cjose_err) == FALSE) {
192 		fprintf(stderr,
193 				"could not verify JWS: %s [file: %s, function: %s, line: %ld]\n",
194 				cjose_err.message, cjose_err.file, cjose_err.function,
195 				cjose_err.line);
196 		return -1;
197 	}
198 
199 	uint8_t *plaintext = NULL;
200 	size_t plaintext_len = 0;
201 	if (cjose_jws_get_plaintext(jws, &plaintext, &plaintext_len,
202 			&cjose_err) == FALSE) {
203 		fprintf(stderr,
204 				"could not get plaintext: %s [file: %s, function: %s, line: %ld]\n",
205 				cjose_err.message, cjose_err.file, cjose_err.function,
206 				cjose_err.line);
207 		return -1;
208 	}
209 
210 	fprintf(stdout, "%s", plaintext);
211 
212 	cjose_jws_release(jws);
213 	oidc_jwk_destroy(jwk);
214 
215 	return 0;
216 }
217 
decrypt(int argc,char ** argv,apr_pool_t * pool)218 int decrypt(int argc, char **argv, apr_pool_t *pool) {
219 
220 	if (argc <= 3)
221 		return usage(argc, argv, "decrypt <serialized-jwt-file> <jwk-file>");
222 
223 	char *s_jwt = NULL, *s_jwk = NULL;
224 
225 	if (file_read(pool, argv[2], &s_jwt) != 0)
226 		return -1;
227 	if (file_read(pool, argv[3], &s_jwk) != 0)
228 		return -1;
229 
230 
231 	apr_hash_t *keys = apr_hash_make(pool);
232 	oidc_jose_error_t oidc_err;
233 
234 	oidc_jwk_t *jwk = oidc_jwk_parse(pool, s_jwk, &oidc_err);
235 	if (jwk == NULL) {
236 		fprintf(stderr,
237 				"could not import JWK: %s [file: %s, function: %s, line: %d]\n",
238 				oidc_err.text, oidc_err.source, oidc_err.function,
239 				oidc_err.line);
240 		return -1;
241 	}
242 
243 	apr_hash_set(keys, jwk->kid ? jwk->kid : "dummy", APR_HASH_KEY_STRING, jwk);
244 
245 	char *plaintext = NULL;
246 	if (oidc_jwe_decrypt(pool, s_jwt, keys, &plaintext, &oidc_err, TRUE) == FALSE) {
247 		fprintf(stderr,
248 				"oidc_jwe_decrypt failed: %s [file: %s, function: %s, line: %d]\n",
249 				oidc_err.text, oidc_err.source, oidc_err.function,
250 				oidc_err.line);
251 		return -1;
252 	}
253 
254 	fprintf(stdout, "%s", plaintext);
255 	oidc_jwk_destroy(jwk);
256 
257 	return 0;
258 }
259 
260 
mkcert(RSA * rsa,X509 ** x509p,EVP_PKEY ** pkeyp,int serial,int days)261 int mkcert(RSA *rsa, X509 **x509p, EVP_PKEY **pkeyp, int serial, int days) {
262 	X509 *x;
263 	EVP_PKEY *pk;
264 	X509_NAME *name = NULL;
265 
266 	if ((pkeyp == NULL) || (*pkeyp == NULL)) {
267 		if ((pk = EVP_PKEY_new()) == NULL)
268 			return -1;
269 	} else
270 		pk = *pkeyp;
271 
272 	if ((x509p == NULL) || (*x509p == NULL)) {
273 		if ((x = X509_new()) == NULL)
274 			return -1;
275 	} else
276 		x = *x509p;
277 
278 	if (!EVP_PKEY_assign_RSA(pk, rsa))
279 		return -1;
280 
281 	X509_set_version(x, 2);
282 	ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
283 	X509_gmtime_adj(X509_get_notBefore(x), 0);
284 	X509_gmtime_adj(X509_get_notAfter(x), (long) 60 * 60 * 24 * days);
285 	X509_set_pubkey(x, pk);
286 
287 	name = X509_get_subject_name(x);
288 
289 	X509_NAME_add_entry_by_txt(name, "C",
290 			MBSTRING_ASC, (const unsigned char *) "NL", -1, -1, 0);
291 	X509_NAME_add_entry_by_txt(name, "CN",
292 			MBSTRING_ASC, (const unsigned char *) "Ping Identity", -1, -1, 0);
293 
294 	X509_set_issuer_name(x, name);
295 
296 	if (!X509_sign(x, pk, EVP_md5()))
297 		return -1;
298 
299 	*x509p = x;
300 	*pkeyp = pk;
301 
302 	return 0;
303 }
304 
jwk2cert(int argc,char ** argv,apr_pool_t * pool)305 int jwk2cert(int argc, char **argv, apr_pool_t *pool) {
306 
307 	if (argc <= 2)
308 		return usage(argc, argv, "jwk2cert <jwk-file>");
309 
310 	char *s_jwk = NULL;
311 
312 	if (file_read(pool, argv[2], &s_jwk) != 0)
313 		return -1;
314 
315 	cjose_err cjose_err;
316 
317 	cjose_jwk_t *jwk = cjose_jwk_import(s_jwk, strlen(s_jwk), &cjose_err);
318 	if (jwk == NULL) {
319 		fprintf(stderr,
320 				"could not import JWK: %s [file: %s, function: %s, line: %ld]\n",
321 				cjose_err.message, cjose_err.file, cjose_err.function,
322 				cjose_err.line);
323 		return -1;
324 	}
325 
326 	if (cjose_jwk_get_kty(jwk, &cjose_err) != CJOSE_JWK_KTY_RSA) {
327 		fprintf(stderr, "wrong key type");
328 		return -1;
329 	}
330 
331 	RSA *rsa = cjose_jwk_get_keydata(jwk, &cjose_err);
332 	//PEM_write_RSAPublicKey(stdout, rsa);
333 	PEM_write_RSA_PUBKEY(stdout, rsa);
334 
335 	X509 *x509 = NULL;
336 	EVP_PKEY *pkey = NULL;
337 
338 	if (mkcert(rsa, &x509, &pkey, 0, 365) != 0)
339 		return -1;
340 
341 	//RSA_print_fp(stdout,pkey->pkey.rsa,0);
342 	//X509_print_fp(stdout,x509);
343 
344 	//PEM_write_PrivateKey(stdout,pkey,NULL,NULL,0,NULL, NULL);
345 	PEM_write_X509(stdout, x509);
346 
347 	X509_free(x509);
348 	EVP_PKEY_free(pkey);
349 
350 	return 0;
351 }
352 
key2jwk(int argc,char ** argv,apr_pool_t * pool)353 int key2jwk(int argc, char **argv, apr_pool_t *pool) {
354 
355 	if (argc <= 2)
356 		return usage(argc, argv, "key2jwk <pem-file> <is_private_key>");
357 
358 	oidc_jwk_t *jwk = NULL;
359 	oidc_jose_error_t err;
360 
361 	int is_private_key = (argc > 3);
362 
363 	if (is_private_key) {
364 		if (oidc_jwk_parse_rsa_private_key(pool, NULL, argv[2], &jwk,
365 				&err) == FALSE) {
366 			fprintf(stderr, "oidc_jwk_parse_rsa_private_key failed: %s",
367 					oidc_jose_e2s(pool, err));
368 			return -1;
369 		}
370 	} else {
371 		if (oidc_jwk_parse_rsa_public_key(pool, NULL, argv[2], &jwk,
372 				&err) == FALSE) {
373 			fprintf(stderr, "oidc_jwk_parse_rsa_public_key failed: %s",
374 					oidc_jose_e2s(pool, err));
375 			return -1;
376 		}
377 	}
378 
379 	char *s_json = NULL;
380 	if (oidc_jwk_to_json(pool, jwk, &s_json, &err) == FALSE) {
381 		fprintf(stderr, "oidc_jwk_to_json failed: %s",
382 				oidc_jose_e2s(pool, err));
383 		return -1;
384 	}
385 
386 	fprintf(stdout, "%s", s_json);
387 
388 	oidc_jwk_destroy(jwk);
389 
390 	return 0;
391 }
392 
393 extern module AP_MODULE_DECLARE_DATA auth_openidc_module;
394 
395 typedef struct oidc_dir_cfg oidc_dir_cfg;
396 
request_setup(apr_pool_t * pool)397 static request_rec * request_setup(apr_pool_t *pool) {
398 	const unsigned int kIdx = 0;
399 	const unsigned int kEls = kIdx + 1;
400 	request_rec *request = (request_rec *) apr_pcalloc(pool,
401 			sizeof(request_rec));
402 
403 	request->pool = pool;
404 
405 	request->headers_in = apr_table_make(request->pool, 0);
406 	request->headers_out = apr_table_make(request->pool, 0);
407 	request->err_headers_out = apr_table_make(request->pool, 0);
408 
409 	apr_table_set(request->headers_in, "Host", "www.example.com");
410 	apr_table_set(request->headers_in, "OIDC_foo", "some-value");
411 	apr_table_set(request->headers_in, "Cookie", "foo=bar; "
412 			"mod_auth_openidc_session" "=0123456789abcdef; baz=zot");
413 
414 	request->server = apr_pcalloc(request->pool, sizeof(struct server_rec));
415 	request->server->process = apr_pcalloc(request->pool,
416 			sizeof(struct process_rec));
417 	request->server->process->pool = request->pool;
418 	request->connection = apr_pcalloc(request->pool, sizeof(struct conn_rec));
419 	request->connection->local_addr = apr_pcalloc(request->pool,
420 			sizeof(apr_sockaddr_t));
421 
422 	apr_pool_userdata_set("https", "scheme", NULL, request->pool);
423 	request->server->server_hostname = "www.example.com";
424 	request->connection->local_addr->port = 443;
425 	request->unparsed_uri = "/bla?foo=bar&param1=value1";
426 	request->args = "foo=bar&param1=value1";
427 	apr_uri_parse(request->pool,
428 			"https://www.example.com/bla?foo=bar&param1=value1",
429 			&request->parsed_uri);
430 
431 	auth_openidc_module.module_index = kIdx;
432 	oidc_cfg *cfg = oidc_create_server_config(request->pool, request->server);
433 	cfg->provider.issuer = "https://idp.example.com";
434 	cfg->provider.authorization_endpoint_url =
435 			"https://idp.example.com/authorize";
436 	cfg->provider.scope = "openid";
437 	cfg->provider.client_id = "client_id";
438 	cfg->redirect_uri = "https://www.example.com/protected/";
439 
440 	oidc_dir_cfg *d_cfg = oidc_create_dir_config(request->pool, NULL);
441 
442 	request->server->module_config = apr_pcalloc(request->pool,
443 			sizeof(ap_conf_vector_t *) * kEls);
444 	request->per_dir_config = apr_pcalloc(request->pool,
445 			sizeof(ap_conf_vector_t *) * kEls);
446 	ap_set_module_config(request->server->module_config, &auth_openidc_module,
447 			cfg);
448 	ap_set_module_config(request->per_dir_config, &auth_openidc_module, d_cfg);
449 
450 	cfg->cache = &oidc_cache_shm;
451 	cfg->cache_cfg = NULL;
452 	cfg->cache_shm_size_max = 500;
453 	cfg->cache_shm_entry_size_max = 16384 + 255 + 17;
454 	if (cfg->cache->post_config(request->server) != OK) {
455 		printf("cfg->cache->post_config failed!\n");
456 		exit(-1);
457 	}
458 
459 	return request;
460 }
461 
enckey(int argc,char ** argv,apr_pool_t * pool)462 int enckey(int argc, char **argv, apr_pool_t *pool) {
463 
464 	if (argc <= 2)
465 		return usage(argc, argv, "enckey <secret> [hash] [key-length]");
466 
467 	request_rec *r = request_setup(pool);
468 
469 	oidc_jwk_t *jwk = NULL;
470 	if (oidc_util_create_symmetric_key(r, argv[2], argc > 4 ? atoi(argv[4]) : 0,
471 			argc > 3 ? argv[3] : NULL, FALSE, &jwk) == FALSE) {
472 		fprintf(stderr, "oidc_util_create_symmetric_key failed");
473 		return -1;
474 	}
475 
476 	oidc_jose_error_t err;
477 	char *s_json = NULL;
478 	if (oidc_jwk_to_json(pool, jwk, &s_json, &err) == FALSE) {
479 		fprintf(stderr, "oidc_jwk_to_json failed");
480 		return -1;
481 	}
482 
483 	cjose_err cjose_err;
484 	int src_len = cjose_jwk_get_keysize(jwk->cjose_jwk, &cjose_err) / 8;
485 	int enc_len = apr_base64_encode_len(src_len);
486 	char *b64 = apr_palloc(r->pool, enc_len);
487 	apr_base64_encode(b64,
488 			(const char *) cjose_jwk_get_keydata(jwk->cjose_jwk, &cjose_err),
489 			src_len);
490 
491 	fprintf(stdout, "\nJWK:\n%s\n\nbase64:\n%s\n\n", s_json, b64);
492 
493 	return 0;
494 }
495 
hash_base64url(int argc,char ** argv,apr_pool_t * pool)496 int hash_base64url(int argc, char **argv, apr_pool_t *pool) {
497 	if (argc <= 2)
498 		return usage(argc, argv,
499 				"hash_base64url <string> [algo] [base64url-decode-first]");
500 
501 	char *algo = argc > 3 ? argv[3] : "sha256";
502 	int base64url_decode_first = argc > 4 ? (strcmp(argv[4], "yes") == 0) : 0;
503 	char *output = NULL;
504 
505 	request_rec *r = request_setup(pool);
506 
507 	if (base64url_decode_first) {
508 
509 		uint8_t *bytes = NULL;
510 		size_t outlen = 0;
511 		cjose_err err;
512 		if (cjose_base64url_decode(argv[2], strlen(argv[2]), &bytes, &outlen,
513 				&err) == FALSE) {
514 			fprintf(stderr, "cjose_base64_decode failed: %s", err.message);
515 			return -1;
516 		}
517 		if (oidc_jose_hash_and_base64url_encode(r->pool, algo,
518 				(const char *) bytes, outlen, &output) == FALSE) {
519 			fprintf(stderr, "oidc_jose_hash_and_base64url_encode failed");
520 			return -1;
521 		}
522 	} else {
523 		if (oidc_util_hash_string_and_base64url_encode(r, algo, argv[2],
524 				&output) == FALSE) {
525 			fprintf(stderr,
526 					"oidc_util_hash_string_and_base64url_encode failed");
527 			return -1;
528 		}
529 	}
530 
531 	fprintf(stdout, "%s\n", output);
532 
533 	return 0;
534 }
535 
timestamp(int argc,char ** argv,apr_pool_t * pool)536 int timestamp(int argc, char **argv, apr_pool_t *pool) {
537 	if (argc <= 2)
538 		return usage(argc, argv, "timestamp <seconds>");
539 	long delta = strtol(argv[2], NULL, 10);
540 	apr_time_t t1 = apr_time_now() + apr_time_from_sec(delta);
541 	char *s = apr_psprintf(pool, "%" APR_TIME_T_FMT, t1);
542 	fprintf(stderr, "timestamp (1) = %s\n", s);
543 
544 	apr_time_t t2;
545 	sscanf(s, "%" APR_TIME_T_FMT, &t2);
546 	fprintf(stderr, "timestamp (2) = %" APR_TIME_T_FMT "\n", t2);
547 
548 	char buf[APR_RFC822_DATE_LEN + 1];
549 	apr_rfc822_date(buf, t2);
550 	fprintf(stderr, "timestamp (3): %s (%" APR_TIME_T_FMT " secs from now)\n",
551 			buf, apr_time_sec(t2 - apr_time_now()));
552 
553 	return 0;
554 }
555 
uuid(int argc,char ** argv,apr_pool_t * pool)556 int uuid(int argc, char **argv, apr_pool_t *pool) {
557 	char s_uuid[APR_UUID_FORMATTED_LENGTH + 1];
558 	const unsigned long e = 1000000;
559 	unsigned long n = 10000000;
560 	unsigned long i = 0;
561 
562 	if (argc > 2)
563 		n = atoi(argv[2]);
564 
565 	apr_hash_t *entries = apr_hash_make(pool);
566 	apr_uuid_t *uuid;
567 	while (i < n) {
568 		uuid = (apr_uuid_t *) apr_pcalloc(pool, sizeof(apr_uuid_t));
569 		apr_uuid_get(uuid);
570 		if (apr_hash_get(entries, (const void *) uuid,
571 				sizeof(apr_uuid_t)) != NULL) {
572 			apr_uuid_format((char *) &s_uuid, uuid);
573 			fprintf(stderr, "duplicate found: %s\n", s_uuid);
574 			exit(-1);
575 		} else {
576 			apr_hash_set(entries, (const void *) uuid, sizeof(apr_uuid_t),
577 					(const void *) 1);
578 		}
579 		i++;
580 		if (i % e == 0)
581 			fprintf(stderr, "\r %lu  ", i / e);
582 	}
583 	fprintf(stderr, "\n");
584 	return 0;
585 }
586 
main(int argc,char ** argv,char ** env)587 int main(int argc, char **argv, char **env) {
588 
589 	if (argc <= 1)
590 		return usage(argc, argv, NULL);
591 
592 	if (apr_app_initialize(&argc, (const char * const **) argv,
593 			(const char * const **) env) != APR_SUCCESS) {
594 		printf("apr_app_initialize failed\n");
595 		return -1;
596 	}
597 
598 	OpenSSL_add_all_algorithms();
599 
600 	apr_pool_t *pool = NULL;
601 	apr_pool_create(&pool, NULL);
602 
603 	if (strcmp(argv[1], "sign") == 0)
604 		return sign(argc, argv, pool);
605 
606 	if (strcmp(argv[1], "verify") == 0)
607 		return verify(argc, argv, pool);
608 
609 	if (strcmp(argv[1], "decrypt") == 0)
610 		return decrypt(argc, argv, pool);
611 
612 	if (strcmp(argv[1], "jwk2cert") == 0)
613 		return jwk2cert(argc, argv, pool);
614 
615 	if (strcmp(argv[1], "key2jwk") == 0)
616 		return key2jwk(argc, argv, pool);
617 
618 	if (strcmp(argv[1], "enckey") == 0)
619 		return enckey(argc, argv, pool);
620 
621 	if (strcmp(argv[1], "hash_base64url") == 0)
622 		return hash_base64url(argc, argv, pool);
623 
624 	if (strcmp(argv[1], "timestamp") == 0)
625 		return timestamp(argc, argv, pool);
626 
627 	if (strcmp(argv[1], "uuid") == 0)
628 		return uuid(argc, argv, pool);
629 
630 	apr_pool_destroy(pool);
631 	apr_terminate();
632 
633 	return usage(argc, argv, NULL);
634 }
635