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