1 /* zxbench.c - Benchmark zxid libraries
2 * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 * Copyright (c) 2006 Symlabs (symlabs@symlabs.com), All Rights Reserved.
4 * Author: Sampo Kellomaki (sampo@iki.fi)
5 * This is confidential unpublished proprietary source code of the author.
6 * NO WARRANTY, not even implied warranties. Contains trade secrets.
7 * Distribution prohibited unless authorized in writing.
8 * Licensed under Apache License 2.0, see file COPYING.
9 * $Id: zxbench.c,v 1.25 2009-11-24 23:53:40 sampo Exp $
10 *
11 * 1.7.2006, started --Sampo
12 *
13 * Test encoding and decoding SAML 2.0 assertions and other related stuff.
14 *
15 * ./zxbench -d -i 1 <t/hp-idp-post-resp.xml
16 *
17 * WARNING: This code appears to be seriously out of date and historical as of Oct-2010. --Sampo
18 */
19
20 #include <signal.h>
21 #include <fcntl.h>
22 #include <netdb.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <openssl/x509.h>
31
32 #include "errmac.h"
33
34 #include "zx.h"
35 #include "zxid.h"
36 #include "c/zx-data.h"
37 #include "c/zx-const.h"
38 #include "c/zx-ns.h"
39 #include "c/zxidvers.h"
40
41 int read_all_fd(int fd, char* p, int want, int* got_all);
42 int write_all_fd(int fd, char* p, int pending);
43
44 const char* help =
45 "zxbench - SAML 2.0 encoding and decoding benchmark - R" ZXID_REL "\n\
46 SAML 2.0 is a standard for federated identity and Single Sign-On.\n\
47 Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.\n\
48 Copyright (c) 2006 Symlabs (symlabs@symlabs.com), All Rights Reserved.\n\
49 Author: Sampo Kellomaki (sampo@iki.fi)\n\
50 NO WARRANTY, not even implied warranties. Licensed under Apache License v2.0\n\
51 See http://www.apache.org/licenses/LICENSE-2.0\n\
52 Send well researched bug reports to the author. Home: zxid.org\n\
53 \n\
54 Usage: zxbench [options] <saml-assertion.xml >reencoded-a7n.xml\n\
55 -i N Number of iterations to benchmark.\n\
56 -t SECONDS Timeout. Default: 0=no timeout.\n\
57 -c CIPHER Enable crypto on DTS interface using specified cipher. Use '?' for list.\n\
58 -k FDNUMBER File descriptor for reading symmetric key. Use 0 for stdin.\n\
59 -egd PATH Specify path of Entropy Gathering Daemon socket, default on\n\
60 Solaris: /tmp/entropy. On Linux /dev/urandom is used instead\n\
61 See http://www.lothar.com/tech/crypto/ or\n\
62 http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html\n\
63 -rand PATH Location of random number seed file. On Solaris EGD is used.\n\
64 On Linux the default is /dev/urandom. See RFC1750.\n\
65 -uid UID:GID If run as root, drop privileges and assume specified uid and gid.\n\
66 -v Verbose messages.\n\
67 -q Be extra quiet.\n\
68 -d Turn on debugging.\n\
69 -license Show licensing and NO WARRANTY details.\n\
70 -h This help message\n\
71 -- End of options\n";
72
73 #define DIE(reason) MB fprintf(stderr, "%s\n", reason); exit(2); ME
74
75 int ak_buf_size = 0;
76 int verbose = 1;
77 extern int errmac_debug;
78 int timeout = 0;
79 int gcthreshold = 0;
80 int leak_free = 0;
81 extern int assert_nonfatal;
82 int drop_uid = 0;
83 int drop_gid = 0;
84 char* rand_path;
85 char* egd_path;
86 char symmetric_key[1024];
87 int symmetric_key_len;
88 int n_iter = 1;
89
90 /* Called by: main x8, zxbusd_main, zxbuslist_main, zxbustailf_main, zxcall_main, zxcot_main, zxdecode_main */
opt(int * argc,char *** argv,char *** env)91 void opt(int* argc, char*** argv, char*** env)
92 {
93 if (*argc <= 1) goto argerr;
94
95 while (1) {
96 ++(*argv); --(*argc);
97
98 if (!(*argc) || ((*argv)[0][0] != '-')) break; /* probably the remote host and port */
99
100 switch ((*argv)[0][1]) {
101 case '-': if ((*argv)[0][2]) break;
102 ++(*argv); --(*argc);
103 DD("End of options by --");
104 return; /* -- ends the options */
105
106 case 'i': if ((*argv)[0][2]) break;
107 ++(*argv); --(*argc);
108 if (!(*argc)) break;
109 n_iter = atoi((*argv)[0]);
110 continue;
111
112 case 't': if ((*argv)[0][2]) break;
113 ++(*argv); --(*argc);
114 if (!(*argc)) break;
115 timeout = atoi((*argv)[0]);
116 continue;
117
118 case 'd':
119 switch ((*argv)[0][2]) {
120 case '\0':
121 ++errmac_debug;
122 continue;
123 case 'i': if ((*argv)[0][3]) break;
124 ++(*argv); --(*argc);
125 if (!(*argc)) break;
126 strcpy(errmac_instance, (*argv)[0]);
127 continue;
128 }
129 break;
130
131 case 'v':
132 switch ((*argv)[0][2]) {
133 case '\0':
134 ++verbose;
135 continue;
136 }
137 break;
138
139 case 'q':
140 switch ((*argv)[0][2]) {
141 case '\0':
142 verbose = 0;
143 continue;
144 }
145 break;
146
147 case 'e':
148 switch ((*argv)[0][2]) {
149 case 'g': if ((*argv)[0][3] != 'd' || (*argv)[0][4]) break;
150 ++(*argv); --(*argc);
151 if (!(*argc)) break;
152 egd_path = (*argv)[0];
153 continue;
154 }
155 break;
156
157 case 'r':
158 switch ((*argv)[0][2]) {
159 case 'f':
160 /*AK_TS(LEAK, 0, "memory leaks enabled");*/
161 #if 1
162 ERR("*** WARNING: You have turned memory frees to memory leaks. We will (eventually) run out of memory. Using -rf is not recommended. %d\n", 0);
163 #endif
164 ++leak_free;
165 continue;
166 #if 0
167 case 'e':
168 if ((*argv)[0][3]) break;
169 ++(*argv); --(*argc);
170 if ((*argc) < 4) break;
171 sscanf((*argv)[0], "%i", &abort_funcno);
172 ++(*argv); --(*argc);
173 sscanf((*argv)[0], "%i", &abort_line);
174 ++(*argv); --(*argc);
175 sscanf((*argv)[0], "%i", &abort_error_code);
176 ++(*argv); --(*argc);
177 sscanf((*argv)[0], "%i", &abort_iter);
178 fprintf(stderr, "Will force core upon %x:%x err=%d iter=%d\n",
179 abort_funcno, abort_line, abort_error_code, abort_iter);
180 continue;
181 #endif
182 case 'g':
183 if ((*argv)[0][3]) break;
184 ++(*argv); --(*argc);
185 if (!(*argc)) break;
186 gcthreshold = atoi((*argv)[0]);
187 if (!gcthreshold)
188 ERR("*** WARNING: You have disabled garbage collection. This may lead to increased memory consumption for scripts that handle a lot of PDUs or run for long time. Using `-rg 0' is not recommended. %d\n", 0);
189 continue;
190 case 'a':
191 if ((*argv)[0][3] == 0) {
192 /*AK_TS(ASSERT_NONFATAL, 0, "assert nonfatal enabled");*/
193 #if 1
194 ERR("*** WARNING: YOU HAVE TURNED ASSERTS OFF USING -ra FLAG. THIS MEANS THAT YOU WILL NOT BE ABLE TO OBTAIN ANY SUPPORT. IF PROGRAM NOW TRIES TO ASSERT IT MAY MYSTERIOUSLY AND UNPREDICTABLY CRASH INSTEAD, AND NOBODY WILL BE ABLE TO FIGURE OUT WHAT WENT WRONG OR HOW MUCH DAMAGE MAY BE DONE. USING -ra IS NOT RECOMMENDED. %d\n", assert_nonfatal);
195 #endif
196 ++assert_nonfatal;
197 continue;
198 }
199 if (!strcmp((*argv)[0],"-rand")) {
200 ++(*argv); --(*argc);
201 if (!(*argc)) break;
202 rand_path = (*argv)[0];
203 continue;
204 }
205 break;
206 }
207 break;
208
209 case 'k':
210 switch ((*argv)[0][2]) {
211 case '\0':
212 ++(*argv); --(*argc);
213 if (!(*argc)) break;
214 read_all_fd(atoi((*argv)[0]), symmetric_key, sizeof(symmetric_key), &symmetric_key_len);
215 D("Got %d characters of symmetric key", symmetric_key_len);
216 continue;
217 }
218 break;
219
220 case 'c': if ((*argv)[0][2]) break;
221 ++(*argv); --(*argc);
222 if (!(*argc)) break;
223 #ifndef ENCRYPTION
224 ERR("Encryption not compiled in. %d",0);
225 #endif
226 continue;
227
228 case 'u':
229 switch ((*argv)[0][2]) {
230 case 'i': if ((*argv)[0][3] != 'd' || (*argv)[0][4]) break;
231 ++(*argv); --(*argc);
232 if (!(*argc)) break;
233 sscanf((*argv)[0], "%i:%i", &drop_uid, &drop_gid);
234 continue;
235 }
236 break;
237
238 case 'l':
239 switch ((*argv)[0][2]) {
240 case 'i':
241 if (!strcmp((*argv)[0],"-license")) {
242 extern char* license;
243 fprintf(stderr, "%s", license);
244 exit(0);
245 }
246 break;
247 }
248 break;
249
250 }
251 /* fall thru means unrecognized flag */
252 if (*argc)
253 fprintf(stderr, "Unrecognized flag `%s'\n", (*argv)[0]);
254 argerr:
255 fprintf(stderr, "%s", help);
256 exit(3);
257 }
258 }
259
260 /* ============== M A I N ============== */
261
262 /* Called by: */
main(int argc,char ** argv,char ** env)263 int main(int argc, char** argv, char** env)
264 {
265 struct zx_str* eid;
266 struct zx_root_s* r;
267 struct zxsig_ref refs;
268 zxid_entity* ent;
269 zxid_conf* cf;
270 int got_all, len_so, len_wo, res;
271 char buf[256*1024];
272 char out[256*1024];
273 char* p;
274 char wo_out[256*1024];
275 char* wo_p;
276 opt(&argc, &argv, &env);
277
278 /*if (stats_prefix) init_cmdline(argc, argv, env, stats_prefix);*/
279 CMDLINE("init");
280
281 #ifndef MINGW
282 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { /* Ignore SIGPIPE */
283 perror("INIT: signal ignore pipe");
284 exit(2);
285 }
286
287 /* Cause exit(3) to be called with the intent that any gcov profiling will get
288 * written to disk before we die. If dsproxy is not stopped `kill -USR1' but you
289 * use plain kill instead, the profile will indicate many unexecuted (#####) lines. */
290 if (signal(SIGUSR1, exit) == SIG_ERR) {
291 perror("INIT: signal USR1 exit");
292 exit(2);
293 }
294 #endif
295
296 /* Drop privileges, if requested. */
297
298 if (drop_gid) if (setgid(drop_gid)) { perror("INIT: setgid"); exit(1); }
299 if (drop_uid) if (setuid(drop_uid)) { perror("INIT: setuid"); exit(1); }
300
301 len_so = read_all_fd(fdstdin, buf, sizeof(buf)-1, &got_all);
302 if (got_all <= 0) DIE("Missing data");
303 buf[got_all] = 0;
304
305 D("Decoding %d chars, n_iter(%d)", got_all, n_iter);
306
307 for (;n_iter; --n_iter) {
308 cf = zxid_new_conf("/var/zxid/");
309 r = zx_dec_zx_root(cf->ctx, got_all, buf, "zxbench"); /* n_decode=1000 ?!? */
310 if (!r) DIE("Decode failure");
311
312 //ent = zxid_get_ent_file(cf, "YV7HPtu3bfqW3I4W_DZr-_DKMP4" /* cxp06 */, "bench");
313 //ent = zxid_get_ent_file(cf, "zIDxx57qGA-qwnsymUf4JD0Er2A" /* s-idp */, "bench");
314 //ent = zxid_get_ent_file(cf, "7S4XRMew6HHKey9j8fESiJUV-Cs" /* hp-idp */, "bench");
315 //r->Envelope->Body->ArtifactResolve
316 if (r->Envelope && r->Envelope->Body) {
317 if (r->Envelope->Body->ArtifactResponse) {
318 if (r->Envelope->Body->ArtifactResponse->Signature) {
319 eid = ZX_GET_CONTENT(r->Envelope->Body->ArtifactResponse->Issuer);
320 D("Found sig in Envelope/Body/ArtifactResponse eid(%.*s)", eid->len, eid->s);
321 ent = zxid_get_ent_cache(cf, eid);
322 ZERO(&refs, sizeof(refs));
323 refs.sref = r->Envelope->Body->ArtifactResponse->Signature->SignedInfo->Reference;
324 refs.blob = (struct zx_elem_s*)r->Envelope->Body->ArtifactResponse;
325 res = zxsig_validate(cf->ctx, ent->sign_cert,
326 r->Envelope->Body->ArtifactResponse->Signature,
327 1, &refs);
328 if (res == ZXSIG_OK) {
329 D("sig vfy ok %d", res);
330 } else {
331 ERR("sig vfy failed due to(%d)", res);
332 }
333 }
334 if (r->Envelope->Body->ArtifactResponse->Response) {
335 if (r->Envelope->Body->ArtifactResponse->Response->Assertion) {
336 if (r->Envelope->Body->ArtifactResponse->Response->Assertion->Signature) {
337 eid = ZX_GET_CONTENT(r->Envelope->Body->ArtifactResponse->Response->Assertion->Issuer);
338 D("Found sig in Envelope/Body/ArtifactResponse/Response/Assertion eid(%.*s)", eid->len, eid->s);
339 ent = zxid_get_ent_cache(cf, eid);
340 refs.sref = r->Envelope->Body->ArtifactResponse->Response->Assertion->Signature->SignedInfo->Reference;
341 refs.blob = (struct zx_elem_s*)r->Envelope->Body->ArtifactResponse->Response->Assertion;
342 res = zxsig_validate(cf->ctx, ent->sign_cert,
343 r->Envelope->Body->ArtifactResponse->Response->Assertion->Signature,
344 1, &refs);
345 if (res == ZXSIG_OK) {
346 D("sig vfy ok %d", res);
347 } else {
348 ERR("sig vfy failed due to(%d)", res);
349 }
350 }
351 }
352 }
353 }
354 } else if (r->Assertion) {
355 if (r->Assertion->Signature) {
356 eid = ZX_GET_CONTENT(r->Assertion->Issuer);
357 D("Found sig in (bare) Assertion eid(%.*s)", eid->len, eid->s);
358 ent = zxid_get_ent_cache(cf, eid);
359 refs.sref = r->Assertion->Signature->SignedInfo->Reference;
360 refs.blob = (struct zx_elem_s*)r->Assertion;
361 res = zxsig_validate(cf->ctx, ent->sign_cert,
362 r->Assertion->Signature,
363 1, &refs);
364 if (res == ZXSIG_OK) {
365 D("sig vfy ok %d", res);
366 } else {
367 ERR("sig vfy failed due to(%d)", res);
368 }
369 }
370 } else if (r->Response) {
371
372 if (r->Response->Signature) {
373 eid = ZX_GET_CONTENT(r->Response->Issuer);
374 D("Found sig in Response eid(%.*s)", eid->len, eid->s);
375 ent = zxid_get_ent_cache(cf, eid);
376 refs.sref = r->Response->Signature->SignedInfo->Reference;
377 refs.blob = (struct zx_elem_s*)r->Response;
378 res = zxsig_validate(cf->ctx, ent->sign_cert,
379 r->Response->Signature,
380 1, &refs);
381 if (res == ZXSIG_OK) {
382 D("sig vfy ok %d", res);
383 } else {
384 ERR("sig vfy failed due to(%d)", res);
385 }
386 }
387
388 if (r->Response->Assertion) {
389 if (r->Response->Assertion->Signature) {
390 eid = ZX_GET_CONTENT(r->Response->Assertion->Issuer);
391 D("Found sig in Response/Assertion eid(%.*s)", eid->len, eid->s);
392 ent = zxid_get_ent_cache(cf, eid);
393 refs.sref = r->Response->Assertion->Signature->SignedInfo->Reference;
394 refs.blob = (struct zx_elem_s*)r->Response->Assertion;
395 res = zxsig_validate(cf->ctx, ent->sign_cert,
396 r->Response->Assertion->Signature,
397 1, &refs);
398 if (res == ZXSIG_OK) {
399 D("sig vfy ok %d", res);
400 } else {
401 ERR("sig vfy failed due to(%d)", res);
402 }
403 }
404 }
405 }
406
407 #if 1
408 len_so = zx_LEN_SO_root(cf->ctx, r);
409 D("Enc so len %d chars", len_so);
410
411 p = zx_ENC_SO_root(cf->ctx, r, out);
412 if (!p)
413 DIE("encoding error");
414
415 len_wo = zx_LEN_WO_any_elem(cf->ctx, r);
416 D("Enc wo len %d chars", len_wo);
417
418 wo_p = zx_ENC_WO_any_elem(cf->ctx, r, wo_out);
419 if (!wo_p)
420 DIE("encoding error");
421 #endif
422 zx_FREE_root(cf->ctx, r, 0);
423 }
424 printf("Re-encoded result SO:\n%.*s\n", len_so, out);
425 if (p - out != len_so)
426 D("encode length mismatch %d vs. %d (len)", p - out, len_so);
427
428 printf("Re-encoded result WO:\n%.*s\n", len_wo, wo_out);
429 if (wo_p - wo_out != len_wo)
430 D("encode length mismatch %d vs %d (len)", wo_p - wo_out, len_wo);
431
432 if (memcmp(out, wo_out, MIN(len_so, len_wo)))
433 printf("SO and WO differ.\n");
434
435 return 0;
436 }
437
438 /* EOF -- zxbench.c */
439