1 /* zxidmeta.c  -  Handwritten functions for metadata parsing and generation as well as CoT handling
2  * Copyright (c) 2012 Synergetics SA (sampo@synergetics.be), All Rights Reserved.
3  * Copyright (c) 2010-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
4  * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
5  * Author: Sampo Kellomaki (sampo@iki.fi)
6  * This is confidential unpublished proprietary source code of the author.
7  * NO WARRANTY, not even implied warranties. Contains trade secrets.
8  * Distribution prohibited unless authorized in writing.
9  * Licensed under Apache License 2.0, see file COPYING.
10  * $Id: zxidmeta.c,v 1.59 2009-11-24 23:53:40 sampo Exp $
11  *
12  * The CoT cache exists both on disk as directory /var/zxid/cot and in
13  * memory as the field cf->cot. The latter is protected by cf->mx lock.
14  * The entities in cache are essentially read only, i.e. once the head
15  * of the list cf->cot has been dereferenced in a thread safe way,
16  * the entity pointers themselves can be passed around threads with
17  * impunity. No locking needed for them.
18  *
19  * 12.8.2006,  created --Sampo
20  * 12.10.2007, mild refactoring to process keys for xenc as well. --Sampo
21  * 13.12.2007, fixed missing KeyDescriptor/@use as seen in CA IdP metadata --Sampo
22  * 14.4.2008,  added SimpleSign --Sampo
23  * 7.10.2008,  added documentation --Sampo
24  * 1.2.2010,   removed arbitrary size limit --Sampo
25  * 12.2.2010,  added pthread locking --Sampo
26  * 17.2.2011,  fixed processing of whitespace in metadata --Sampo
27  * 10.12.2011, added OAuth2, OpenID Connect, and UMA support --Sampo
28  * 11.12.2011, added OrganizationURL support per symlabs-saml-displayname-2008.pdf submitted to OASIS SSTC --Sampo
29  * 6.2.2012,   corrected the OrganizationURL to be absolute --Sampo
30  */
31 
32 #include "platform.h"  /* for dirent.h */
33 
34 #include <fcntl.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 
42 #ifdef USE_OPENSSL
43 #include <openssl/sha.h>
44 #include <openssl/x509.h>
45 #include <openssl/rsa.h>
46 #endif
47 
48 #include "errmac.h"
49 #include "saml2.h"
50 #include "zxid.h"
51 #include "zxidutil.h"
52 #include "zxidconf.h"
53 #include "c/zx-const.h"
54 #include "c/zx-ns.h"
55 #include "c/zx-data.h"
56 
57 /* ============== CoT and Metadata of Others ============== */
58 
59 /*() Process certificates (public keys) from a metadata for entity.
60  * Since one entity can be both IdP and SP, this function may
61  * be called twice per entity, with different kd argument. */
62 
63 /* Called by:  zxid_mk_ent x2 */
zxid_process_keys(zxid_conf * cf,zxid_entity * ent,struct zx_md_KeyDescriptor_s * kd,const char * logkey)64 static void zxid_process_keys(zxid_conf* cf, zxid_entity* ent, struct zx_md_KeyDescriptor_s* kd, const char* logkey)
65 {
66   int len;
67   char* pp;
68   char* p;
69   char* e;
70   X509* x;
71 
72   for (; kd; kd = (struct zx_md_KeyDescriptor_s*)kd->gg.g.n) {
73     if (kd->gg.g.tok != zx_md_KeyDescriptor_ELEM)
74       continue;
75     if (!kd->KeyInfo || !kd->KeyInfo->X509Data || !ZX_GET_CONTENT(kd->KeyInfo->X509Data->X509Certificate)) {
76       ERR("KeyDescriptor for %s missing essential subelements KeyInfo=%p", logkey, kd->KeyInfo);
77       return;
78     }
79     p = ZX_GET_CONTENT_S(kd->KeyInfo->X509Data->X509Certificate);
80     len = ZX_GET_CONTENT_LEN(kd->KeyInfo->X509Data->X509Certificate);
81     e = p + len;
82     pp = ZX_ALLOC(cf->ctx, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(e-p));
83     e = unbase64_raw(p, e, pp, zx_std_index_64);
84     x = 0;  /* Forces d2i_X509() to alloc the memory. */
85     if (!d2i_X509(&x, (const unsigned char**)&pp /* *** compile warning */, e-pp) || !x) {
86       ERR("DER decoding of X509 certificate for %s failed. use(%.*s)", logkey, kd->use->g.len, kd->use->g.s);
87       D("Extracted %s base64 form of cert(%.*s)", logkey, len, p);
88       return;
89     }
90     if (!kd->use) {
91       ent->sign_cert = x;
92       ent->enc_cert = x;
93       D("KeyDescriptor is missing use attribute. Assume this certificate can be used for both signing and encryption. %d", 0);
94       return;
95     }
96     if (!memcmp("signing", kd->use->g.s, kd->use->g.len)) {
97       ent->sign_cert = x;
98       DD("Extracted %s sign cert(%.*s)", logkey, len, p);
99     } else if (!memcmp("encryption", kd->use->g.s, kd->use->g.len)) {
100       ent->enc_cert = x;
101       DD("Extracted %s enc cert(%.*s)", logkey, len, p);
102     } else {
103       ERR("Unknown key use(%.*s) Assume certificate can be used for both signing and encryption.", kd->use->g.len, kd->use->g.s);
104       D("Extracted %s cert(%.*s)", logkey, len, p);
105       ent->sign_cert = x;
106       ent->enc_cert = x;
107     }
108   }
109 }
110 
111 /*() Helper to create EntityDescriptor */
112 
113 /* Called by:  zxid_parse_meta x2 */
zxid_mk_ent(zxid_conf * cf,struct zx_md_EntityDescriptor_s * ed)114 static zxid_entity* zxid_mk_ent(zxid_conf* cf, struct zx_md_EntityDescriptor_s* ed)
115 {
116   struct zx_str* val;
117   zxid_entity* ent = ZX_ZALLOC(cf->ctx, zxid_entity);
118   ent->ed = ed;
119   if (!ed->entityID)
120     goto bad_md;
121   ent->eid = zx_str_to_c(cf->ctx, &ed->entityID->g);
122   sha1_safe_base64(ent->sha1_name, ed->entityID->g.len, ent->eid);
123   ent->sha1_name[27] = 0;
124 
125   if (ed->Organization) {  /* see symlabs-saml-displayname-2008.pdf submitted to OASIS SSTC */
126     if (val = ZX_GET_CONTENT(ed->Organization->OrganizationDisplayName))
127       ent->dpy_name = zx_str_to_c(cf->ctx, val);
128     if (val = ZX_GET_CONTENT(ed->Organization->OrganizationURL)) {
129       if (     zx_memmem(val->s, val->len, "saml2_icon", sizeof("saml2_icon")-1)) {
130 	if (   !zx_memmem(val->s, val->len, "saml2_icon_468x60", sizeof("saml2_icon_468x60")-1)
131 	    && !zx_memmem(val->s, val->len, "saml2_icon_150x60", sizeof("saml2_icon_150x60")-1)
132 	    && !zx_memmem(val->s, val->len, "saml2_icon_16x16",  sizeof("saml2_icon_16x16")-1))
133 	  ERR("OrganizationURL has to specify button image and the image filename MUST contain substring \"saml2_icon\" in it (see symlabs-saml-displayname-2008.pdf submitted to OASIS SSTC). Furthermore, this substring must specify the size, which must be one of 468x60, 150x60, or 16x16. Acceptable substrings are are \"saml2_icon_468x60\", \"saml2_icon_150x60\", \"saml2_icon_16x16\", e.g. \"https://example.com/example-brand-saml2_icon_150x60.png\". Current value(%.*s) may be used despite this error. The preferred size is \"%s\". Only last acceptable specification of OrganizationURL will be used.", val->len, val->s, cf->pref_button_size);
134 	if (!ent->button_url      /* Pref overrides previous. */
135 	    || !zx_memmem(val->s, val->len, cf->pref_button_size, strlen(cf->pref_button_size)))
136 	  ent->button_url = zx_str_to_c(cf->ctx, val);
137       } else
138 	ERR("OrganizationURL SHOULD specify user interface button image and the image filename MUST contain substring \"saml2_icon\" in it. Current value(%.*s) is not usable and will be ignored. See symlabs-saml-displayname-2008.pdf, submitted to OASIS SSTC.", val->len, val->s);
139     }
140   }
141 
142   if (ed->IDPSSODescriptor)
143     zxid_process_keys(cf, ent, ed->IDPSSODescriptor->KeyDescriptor, "IDP SSO");
144   if (ed->SPSSODescriptor)
145     zxid_process_keys(cf, ent, ed->SPSSODescriptor->KeyDescriptor, "SP SSO");
146 
147   if (!ent->sign_cert && !ent->enc_cert) {
148     ERR("Metadata did not have any certificates! Incomplete metadata? %d",0);
149   } else if (!ent->sign_cert) {
150     INFO("Metadata only had encryption certificate. Using it for signing as well. %d", 0);
151     ent->sign_cert = ent->enc_cert;
152   } else if (!ent->enc_cert) {
153     INFO("Metadata only had signing certificate. Using it for encryption as well. %d", 0);
154     ent->enc_cert = ent->sign_cert;
155   }
156 
157   return ent;
158  bad_md:
159   ERR("Bad metadata. EntityDescriptor was corrupt. %d", 0);
160   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "BADMD", 0, "");
161   return 0;
162 }
163 
164 /*() Parse Metadata, see [SAML2meta]. This function is quite low level
165  * and assumes it is processing a buffer (which may contain multiple
166  * instances of various metadata).
167  *
168  * cf:: ZXID configuration object, used here mainly for memory allocation
169  * md:: Value-result parameter. Pointer to char pointer pointing to the
170  *     beginning of the metadata. As metadata is scanned and parsed, this
171  *     pointer will be advanced
172  * lim:: End of the metadata buffer
173  * return:: Entity data structure composed from the metadata. If more than
174  *     one EntityDescriptor is found, then a linked list is returned. */
175 
176 /* Called by:  zxid_addmd, zxid_get_ent_file, zxid_get_meta, zxid_lscot_line */
zxid_parse_meta(zxid_conf * cf,char ** md,char * lim)177 zxid_entity* zxid_parse_meta(zxid_conf* cf, char** md, char* lim)
178 {
179   zxid_entity* ee;
180   zxid_entity* ent;
181   struct zx_md_EntityDescriptor_s* ed;
182   struct zx_root_s* r;
183 
184   r = zx_dec_zx_root(cf->ctx, lim-*md, *md, "parse meta");  /* *** n_decode=5 */
185   *md = (char*)cf->ctx->p;
186   if (!r)
187     return 0;
188   if (r->EntityDescriptor) {
189     ed = r->EntityDescriptor;
190     ZX_FREE(cf->ctx, r);  /* N.B Shallow free only, do not free the descriptor. */
191     return zxid_mk_ent(cf, ed);
192   } else if (r->EntitiesDescriptor) {
193     if (!r->EntitiesDescriptor->EntityDescriptor)
194       goto bad_md;
195     ee = 0;
196     for (ed = r->EntitiesDescriptor->EntityDescriptor;
197 	 ed;
198 	 ed = (struct zx_md_EntityDescriptor_s*)ZX_NEXT(ed)) {
199       if (ed->gg.g.tok != zx_md_EntityDescriptor_ELEM)
200 	continue;
201       ent = zxid_mk_ent(cf, ed);
202       ent->n = ee;
203       ee = ent;
204     }
205     ZX_FREE(cf->ctx, r->EntitiesDescriptor);
206     ZX_FREE(cf->ctx, r);  /* N.B Shallow free only, do not free the descriptors. */
207     return ee;
208   }
209  bad_md:
210   ERR("Bad metadata. EntityDescriptor could not be found or was corrupt. MD(%.*s) %d chars parsed.", ((int)(lim-cf->ctx->bas)), cf->ctx->bas, ((int)(*md - cf->ctx->bas)));
211   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "BADMD", 0, "chars_parsed(%d)", ((int)(*md - cf->ctx->bas)));
212   zx_free_elem(cf->ctx, &r->gg, 0);
213   return 0;
214 }
215 
216 /*() Write metadata of an entity to the Circle of Trust (CoT) cache of
217  * the entity identified by cf. Mainly used by Auto-CoT. */
218 
219 /* Called by:  opt x3, zxid_get_ent_ss */
zxid_write_ent_to_cache(zxid_conf * cf,zxid_entity * ent)220 int zxid_write_ent_to_cache(zxid_conf* cf, zxid_entity* ent)
221 {
222   struct zx_str* ss;
223   fdtype fd = open_fd_from_path(O_CREAT | O_WRONLY | O_TRUNC, 0666, "write_ent_to_cache", 1, "%s" ZXID_COT_DIR "%s", cf->cpath, ent->sha1_name);
224   if (fd == BADFD) {
225     perror("open metadata for writing metadata to cache");
226     ERR("Failed to open file for writing: sha1_name(%s) to metadata cache", ent->sha1_name);
227     return 0;
228   }
229 
230   ss = zx_easy_enc_elem_opt(cf, &ent->ed->gg);
231   if (!ss)
232     return 0;
233   write_all_fd(fd, ss->s, ss->len);
234   zx_str_free(cf->ctx, ss);
235   close_file(fd, (const char*)__FUNCTION__);
236   return 1;
237 }
238 
239 /*() Read metadata from a file.
240  *
241  * Usually the file will be named according to "sha1 name", which
242  * is safe base64 encoded SHA1 digest hash over the EntityID. This
243  * is used to ensure unique file name for each entity. However,
244  * this function will in fact read from any file name supplied.
245  * If the file contains multiple EntityDescriptor elements, they
246  * are all added to the cot. Also EntitiesDesciptor is handled.
247  *
248  * See also zxid_get_ent_cache() which will compute the sha1_name
249  * and then read the metadata. */
250 
251 /* Called by:  covimp_test, main x3, test_ibm_cert_problem_enc_dec, zxid_get_ent_by_sha1_name, zxid_get_ent_cache, zxid_load_cot_cache_from_file */
zxid_get_ent_file(zxid_conf * cf,const char * sha1_name,const char * logkey)252 zxid_entity* zxid_get_ent_file(zxid_conf* cf, const char* sha1_name, const char* logkey)
253 {
254   int n, got, siz;
255   fdtype fd;
256   char* md_buf;
257   char* p;
258   zxid_entity* first = 0;
259   zxid_entity* ent;
260   zxid_entity* ee;
261 
262   DD("sha1_name(%s)", sha1_name);
263   fd = open_fd_from_path(O_RDONLY, 0, logkey, 1, "%s" ZXID_COT_DIR "%s", cf->cpath, sha1_name);
264   if (fd == BADFD) {
265     perror("open metadata to read");
266     D("No metadata file found for sha1_name(%s)", sha1_name);
267     return 0;
268   }
269   siz = get_file_size(fd);
270   md_buf = ZX_ALLOC(cf->ctx, siz+1);
271   n = read_all_fd(fd, md_buf, siz, &got);
272   DD("==========sha1_name(%s)", sha1_name);
273   if (n == -1)
274     goto readerr;
275   close_file(fd, (const char*)__FUNCTION__);
276 
277   if (got <= 20) {
278     ERR("%s: Metadata found is too short, only %d bytes. sha1_name(%s) md_buf(%.*s)", logkey, got, sha1_name, got, md_buf);
279     return 0;
280   }
281   DD("md_buf(%.*s) got=%d siz=%d sha1_name(%s)", got, md_buf, got, siz, sha1_name);
282 
283   p = md_buf;
284   while (p < md_buf+got) {   /* Loop over concatenated descriptors. */
285     ent = zxid_parse_meta(cf, &p, md_buf+got);
286     if (!first)
287       first = ent;
288     DD("++++++++++++sha1_name(%s)", sha1_name);
289     if (!ent) {
290       ZX_FREE(cf->ctx, md_buf);
291       ERR("%s: ***** Parsing metadata failed for sha1_name(%s)", logkey, sha1_name);
292       return first;
293     }
294     LOCK(cf->mx, "add ent to cot");
295     while (ent) {
296       ee = ent->n;
297       ent->n = cf->cot;
298       cf->cot = ent;
299       ent = ee;
300     }
301     UNLOCK(cf->mx, "add ent to cot");
302     D("GOT META sha1_name(%s) eid(%s)", sha1_name, ent?ent->eid:"?");
303   }
304   return first;
305 
306 readerr:
307   perror("read metadata");
308   D("%s: Failed to read metadata for sha1_name(%s)", logkey, sha1_name);
309   close_file(fd, (const char*)__FUNCTION__);
310   return 0;
311 }
312 
313 /*LOCK_STATIC(zxid_ent_cache_mx);*/
314 extern struct zx_lock zxid_ent_cache_mx;
315 
316 /* Called by:  zxid_get_ent_cache, zxid_load_cot_cache */
zxid_load_cot_cache_from_file(zxid_conf * cf)317 static void zxid_load_cot_cache_from_file(zxid_conf* cf)
318 {
319   zxid_entity* ee;
320   if (!cf->load_cot_cache)
321     return;
322   LOCK(zxid_ent_cache_mx, "get ent from cache");
323   LOCK(cf->mx, "check cot");
324   ee = cf->cot;
325   UNLOCK(cf->mx, "check cot");
326   if (!ee) {
327     D("Loading cot cache from(%s)", cf->load_cot_cache);
328     zxid_get_ent_file(cf, cf->load_cot_cache, "load_cot_cache_from_file");
329     D("CoT cache loaded from(%s)", cf->load_cot_cache);
330   }
331   UNLOCK(zxid_ent_cache_mx, "get ent from cache");
332 }
333 
334 /*() Search cot datastructure by entity id. Failing to find,
335  * compute sha1_name for an entity and then read the metadata from
336  * the CoT metadata cache directory, e.g. /var/zxid/cot */
337 
338 /* Called by:  main x5, zxid_get_ent_ss x3 */
zxid_get_ent_cache(zxid_conf * cf,struct zx_str * eid)339 zxid_entity* zxid_get_ent_cache(zxid_conf* cf, struct zx_str* eid)
340 {
341   zxid_entity* ent;
342   char sha1_name[28];
343   char logkey[256];
344 
345   zxid_load_cot_cache_from_file(cf);
346   for (ent = cf->cot; ent; ent = ent->n)  /* Check in memory cache. */
347     if (eid->len == strlen(ent->eid) && !memcmp(eid->s, ent->eid, eid->len)) {
348       D("GOT FROM MEM eid(%s)", ent->eid);
349       return ent;
350     }
351   sha1_safe_base64(sha1_name, eid->len, eid->s);
352   sha1_name[27] = 0;
353 
354   snprintf(logkey, sizeof(logkey)-1, "get_ent_cache EntityID(%.*s)", eid->len, eid->s);
355   logkey[sizeof(logkey)-1] = 0;
356   return zxid_get_ent_file(cf, sha1_name, logkey);
357 }
358 
359 /*(i) Get metadata for entity, either from cache or network (using WKL), depending
360  * on configuration options. Main work horse for getting entity metadata.
361  *
362  * cf:: ZXID configuration object
363  * eid:: Entity ID whose metadata is desired
364  * return:: Entity data structure, including the metadata */
365 
366 /* Called by: */
zxid_get_ent_ss(zxid_conf * cf,struct zx_str * eid)367 zxid_entity* zxid_get_ent_ss(zxid_conf* cf, struct zx_str* eid)
368 {
369   zxid_entity* old_cot;
370   zxid_entity* ent;
371   zxid_entity* ee;
372   zxid_entity* match = 0;
373 
374   D("eid(%.*s) path(%.*s) cf->magic=%x, md_cache_first(%d), cot(%p)", eid->len, eid->s, cf->cpath_len, cf->cpath, cf->magic, cf->md_cache_first, cf->cot);
375   if (cf->md_cache_first) {
376     ent = zxid_get_ent_cache(cf, eid);
377     if (ent)
378       return ent;
379   }
380 
381   if (cf->md_fetch) {
382     ent = zxid_get_meta_ss(cf, eid);
383     if (ent) {
384       LOCK(cf->mx, "read cot");
385       old_cot = cf->cot;
386       UNLOCK(cf->mx, "read cot");
387       while (ent) {
388 	if (eid->len == strlen(ent->eid) && !memcmp(eid->s, ent->eid, eid->len)) {
389 	  match = ent;
390 	}
391 	/* Check whether entity is already in the cache. */
392 	if (zxid_get_ent_cache(cf, &ent->ed->entityID->g)) {
393 	  INFO("While fetching metadata for eid(%.*s) got metadata for eid(%s), but the metadata was already in the cache. NEW METADATA IGNORED.", eid->len, eid->s, ent->eid);
394 	  ent = ent->n;
395 	} else {
396 	  INFO("While fetching metadata for eid(%.*s) got metadata for eid(%s). New metadata cached.", eid->len, eid->s, ent->eid);
397 	  ee = ent->n;
398 	  LOCK(cf->mx, "add fetched ent to cot");
399 	  ent->n = cf->cot;
400 	  cf->cot = ent;
401 	  UNLOCK(cf->mx, "add fetched ent to cot");
402 	  ent = ee;
403 	}
404       }
405 
406       if (cf->md_populate_cache) {
407 	LOCK(cf->mx, "read cot");
408 	ent = cf->cot;
409 	UNLOCK(cf->mx, "read cot");
410 	for (; ent != old_cot; ent = ent->n)
411 	  zxid_write_ent_to_cache(cf, ent);
412       }
413       if (match)
414 	return match;
415     }
416   }
417 
418   if (cf->md_cache_last) {
419     ent = zxid_get_ent_cache(cf, eid);
420     if (ent)
421       return ent;
422   }
423   D("eid(%.*s) NOT FOUND", eid->len, eid->s);
424   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "NOMD", 0, "eid(%.*s)", eid->len, eid->s);
425   return 0;
426 }
427 
428 /*() Wrapper for zxid_get_ent_ss(), which see. */
429 
430 /* Called by:  hi_vfy_peer_ssl_cred, zxbus_verify_receipt, zxcall_main, zxid_cdc_check x2, zxid_oauth2_az_server_sso, zxid_simple_idp_show_an, zxid_start_sso_url */
zxid_get_ent(zxid_conf * cf,const char * eid)431 zxid_entity* zxid_get_ent(zxid_conf* cf, const char* eid)
432 {
433   struct zx_str ss;
434   if (!eid)
435     return 0;
436   ss.s = (char*)eid;
437   ss.len = strlen(eid);
438   DD("eid: (%s)", eid);
439   return zxid_get_ent_ss(cf, &ss);
440 }
441 
442 /*() Given sha1_name, check in memory cache and if not, the disk cache. Do not try net (WKL). */
443 
444 /* Called by:  zxid_get_ent_by_succinct_id, zxid_load_cot_cache */
zxid_get_ent_by_sha1_name(zxid_conf * cf,char * sha1_name)445 zxid_entity* zxid_get_ent_by_sha1_name(zxid_conf* cf, char* sha1_name)
446 {
447   zxid_entity* ent;
448   LOCK(cf->mx, "scan cache by sha1_name");
449   for (ent = cf->cot; ent; ent = ent->n)  /* Check in-memory cache. */
450     if (!strcmp(sha1_name, ent->sha1_name)) {
451       UNLOCK(cf->mx, "scan cache by sha1_name");
452       return ent;
453     }
454   UNLOCK(cf->mx, "scan cache by sha1_name");
455   ent = zxid_get_ent_file(cf, sha1_name, "get_ent_by_sha1_name");
456   if (!ent)
457     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "B", "NOMD", 0, "sha1_name(%s)", sha1_name);
458   return ent;
459 }
460 
461 /*() In artifact profile concept of "succinct id" appears. If you have one of those,
462  * you canuse this function to fetch the entity metadata. Only in-memory
463  * and disk caches will be tried. No network connection (WKL) will be initiated. */
464 
465 /* Called by:  zxid_sp_deref_art */
zxid_get_ent_by_succinct_id(zxid_conf * cf,char * raw_succinct_id)466 zxid_entity* zxid_get_ent_by_succinct_id(zxid_conf* cf, char* raw_succinct_id) {
467   char sha1_name[28];
468   base64_fancy_raw(raw_succinct_id, 20, sha1_name, safe_basis_64, 1<<31, 0, 0, '.');
469   sha1_name[27] = 0;
470   return zxid_get_ent_by_sha1_name(cf, sha1_name);
471 }
472 
473 /*() Usually you will want to use the get_ent() methods if you need
474  * only specific entities. Loading the entire cache is expensive and
475  * only useful if you really need to enumerate through all
476  * available entities. This may be the case when rendering login
477  * buttons for all IdPs in a user interface.
478  *
479  * cf:: ZXID configuration object
480  * return:: Linked list of Entity objects (metadata) for CoT partners */
481 
482 /* Called by:  main x2, zxid_idp_list_cf_cgi, zxid_mk_idp_list */
zxid_load_cot_cache(zxid_conf * cf)483 zxid_entity* zxid_load_cot_cache(zxid_conf* cf)
484 {
485   zxid_entity* ent;
486   struct dirent* de;
487   DIR* dir;
488   char buf[4096];
489   if (cf->cpath_len + sizeof(ZXID_COT_DIR) > sizeof(buf)) {
490    ERR("Too long path(%.*s) for config dir. Has %d chars. Max allowed %d. (config problem)",
491 	cf->cpath_len, cf->cpath, cf->cpath_len, ((int)(sizeof(buf) - sizeof(ZXID_COT_DIR))));
492     return 0;
493   }
494   memcpy(buf, cf->cpath, cf->cpath_len);
495   memcpy(buf + cf->cpath_len, ZXID_COT_DIR, sizeof(ZXID_COT_DIR));
496 
497   zxid_load_cot_cache_from_file(cf);
498 
499   dir = opendir(buf);
500   if (!dir) {
501     perror("opendir for /var/zxid/cot (or other if configured) for loading cot cache");
502     ERR("opendir failed path(%s) uid=%d gid=%d", buf, geteuid(), getegid());
503     return 0;
504   }
505 
506   while (de = readdir(dir))
507     if (de->d_name[0] != '.' && de->d_name[strlen(de->d_name)-1] != '~')
508       zxid_get_ent_by_sha1_name(cf, de->d_name);
509 
510   DD("HERE %p", cf);
511   closedir(dir);
512 
513   LOCK(cf->mx, "return cot");
514   ent = cf->cot;
515   UNLOCK(cf->mx, "return cot");
516   return ent;
517 }
518 
519 /* ============== Our Metadata ============== */
520 
521 /*() Generate XML-DSIG key info given X509 certificate. */
522 
523 /* Called by:  zxenc_pubkey_enc, zxid_key_desc */
zxid_key_info(zxid_conf * cf,struct zx_elem_s * father,X509 * x)524 struct zx_ds_KeyInfo_s* zxid_key_info(zxid_conf* cf, struct zx_elem_s* father, X509* x)
525 {
526   int len;
527   char* dd;
528   char* d;
529   char* pp;
530   char* p;
531   struct zx_ds_KeyInfo_s* ki = zx_NEW_ds_KeyInfo(cf->ctx, father);
532   ki->X509Data = zx_NEW_ds_X509Data(cf->ctx, &ki->gg);
533 
534 #ifdef USE_OPENSSL
535   /* Build PEM encoding (which is base64 of the DER encoding + header and footer) */
536 
537   len = i2d_X509(x, 0);  /* Length of the DER encoding */
538   if (len <= 0) {
539     ERR("DER encoding certificate failed: %d %p", len, x);
540   } else {
541     dd = d = ZX_ALLOC(cf->ctx, len);
542     i2d_X509(x, (unsigned char**)&d);  /* DER encoding of the cert */
543     pp = p = ZX_ALLOC(cf->ctx, (len+4) * 4 / 3 + (len/64) + 6);
544     p = base64_fancy_raw(dd, len, p, std_basis_64, 64, 1, "\n", '=');
545     *p = 0;
546     ki->X509Data->X509Certificate = zx_ref_len_elem(cf->ctx, &ki->X509Data->gg, zx_ds_X509Certificate_ELEM, p-pp, pp);
547   }
548 #else
549   ERR("This copy of zxid was compiled to NOT use OpenSSL. Generating KeyInfo is not supported. Add -DUSE_OPENSSL and recompile. %d", 0);
550 #endif
551   zx_reverse_elem_lists(&ki->gg);
552   return ki;
553 }
554 
555 /*() Generate key descriptor metadata fragment given X509 certificate [SAML2meta]. */
556 
557 /* Called by:  zxid_idp_sso_desc x2, zxid_sp_sso_desc x2 */
zxid_key_desc(zxid_conf * cf,struct zx_elem_s * father,char * use,X509 * x)558 struct zx_md_KeyDescriptor_s* zxid_key_desc(zxid_conf* cf, struct zx_elem_s* father, char* use, X509* x) {
559   struct zx_md_KeyDescriptor_s* kd = zx_NEW_md_KeyDescriptor(cf->ctx, father);
560   kd->use = zx_ref_attr(cf->ctx, &kd->gg, zx_use_ATTR, use);
561   kd->KeyInfo = zxid_key_info(cf, &kd->gg, x);
562   zx_reverse_elem_lists(&kd->gg);
563   return kd;
564 }
565 
566 /*() Generate Artifact Resolution (AR) Descriptor idp metadata fragment [SAML2meta]. */
567 
568 /* Called by:  zxid_idp_sso_desc */
zxid_ar_desc(zxid_conf * cf,struct zx_elem_s * father,char * binding,char * loc,char * resp_loc)569 struct zx_md_ArtifactResolutionService_s* zxid_ar_desc(zxid_conf* cf, struct zx_elem_s* father, char* binding, char* loc, char* resp_loc) {
570   struct zx_md_ArtifactResolutionService_s* d = zx_NEW_md_ArtifactResolutionService(cf->ctx,father);
571   d->Binding = zx_ref_attr(cf->ctx, &d->gg, zx_Binding_ATTR, binding);
572   d->Location = zx_attrf(cf->ctx, &d->gg, zx_Location_ATTR, "%s%s", cf->burl, loc);
573   if (resp_loc)
574     d->ResponseLocation = zx_attrf(cf->ctx, &d->gg, zx_ResponseLocation_ATTR, "%s%s", cf->burl, resp_loc);
575   zx_reverse_elem_lists(&d->gg);
576   return d;
577 }
578 
579 /*() Constructor for Single Sign-On (SSO) Descriptor idp metadata fragment [SAML2meta]. */
580 
581 /* Called by:  zxid_idp_sso_desc x2 */
zxid_sso_desc(zxid_conf * cf,struct zx_elem_s * father,char * binding,char * loc,char * resp_loc)582 struct zx_md_SingleSignOnService_s* zxid_sso_desc(zxid_conf* cf, struct zx_elem_s* father, char* binding, char* loc, char* resp_loc) {
583   struct zx_md_SingleSignOnService_s* d = zx_NEW_md_SingleSignOnService(cf->ctx,father);
584   d->Binding = zx_ref_attr(cf->ctx, &d->gg, zx_Binding_ATTR, binding);
585   d->Location = zx_attrf(cf->ctx, &d->gg, zx_Location_ATTR, "%s%s", cf->burl, loc);
586   if (resp_loc)
587     d->ResponseLocation = zx_attrf(cf->ctx, &d->gg, zx_ResponseLocation_ATTR, "%s%s", cf->burl, resp_loc);
588   zx_reverse_elem_lists(&d->gg);
589   return d;
590 }
591 
592 /*() Generate Single Logout (SLO) Descriptor metadata fragment [SAML2meta]. */
593 
594 /* Called by:  zxid_idp_sso_desc x2, zxid_sp_sso_desc x2 */
zxid_slo_desc(zxid_conf * cf,struct zx_elem_s * father,char * binding,char * loc,char * resp_loc)595 struct zx_md_SingleLogoutService_s* zxid_slo_desc(zxid_conf* cf, struct zx_elem_s* father, char* binding, char* loc, char* resp_loc) {
596   struct zx_md_SingleLogoutService_s* d = zx_NEW_md_SingleLogoutService(cf->ctx,father);
597   d->Binding = zx_ref_attr(cf->ctx, &d->gg, zx_Binding_ATTR, binding);
598   d->Location = zx_attrf(cf->ctx, &d->gg, zx_Location_ATTR, "%s%s", cf->burl, loc);
599   if (resp_loc)
600     d->ResponseLocation = zx_attrf(cf->ctx, &d->gg, zx_ResponseLocation_ATTR, "%s%s", cf->burl, resp_loc);
601   zx_reverse_elem_lists(&d->gg);
602   return d;
603 }
604 
605 /*() Generate Manage Name Id (MNI) Descriptor metadata fragment [SAML2meta]. */
606 
607 /* Called by:  zxid_idp_sso_desc x2, zxid_sp_sso_desc x2 */
zxid_mni_desc(zxid_conf * cf,struct zx_elem_s * father,char * binding,char * loc,char * resp_loc)608 struct zx_md_ManageNameIDService_s* zxid_mni_desc(zxid_conf* cf, struct zx_elem_s* father, char* binding, char* loc, char* resp_loc) {
609   struct zx_md_ManageNameIDService_s* d = zx_NEW_md_ManageNameIDService(cf->ctx,father);
610   d->Binding = zx_ref_attr(cf->ctx, &d->gg, zx_Binding_ATTR, binding);
611   d->Location = zx_attrf(cf->ctx, &d->gg, zx_Location_ATTR, "%s%s", cf->burl, loc);
612   if (resp_loc)
613     d->ResponseLocation = zx_attrf(cf->ctx, &d->gg, zx_ResponseLocation_ATTR, "%s%s", cf->burl, resp_loc);
614   zx_reverse_elem_lists(&d->gg);
615   return d;
616 }
617 
618 /*() Generate Name ID Mapping Service metadata fragment [SAML2meta]. */
619 
620 /* Called by:  zxid_idp_sso_desc */
zxid_nimap_desc(zxid_conf * cf,struct zx_elem_s * father,char * binding,char * loc,char * resp_loc)621 struct zx_md_NameIDMappingService_s* zxid_nimap_desc(zxid_conf* cf, struct zx_elem_s* father, char* binding, char* loc, char* resp_loc) {
622   struct zx_md_NameIDMappingService_s* d = zx_NEW_md_NameIDMappingService(cf->ctx,father);
623   d->Binding = zx_ref_attr(cf->ctx, &d->gg, zx_Binding_ATTR, binding);
624   d->Location = zx_attrf(cf->ctx, &d->gg, zx_Location_ATTR, "%s%s", cf->burl, loc);
625   if (resp_loc)
626     d->ResponseLocation = zx_attrf(cf->ctx, &d->gg, zx_ResponseLocation_ATTR, "%s%s", cf->burl, resp_loc);
627   zx_reverse_elem_lists(&d->gg);
628   return d;
629 }
630 
631 /*() Generate Assertion Consumer Service (SSO) Descriptor metadata fragment [SAML2meta]. */
632 
633 /* Called by:  zxid_sp_sso_desc x6 */
zxid_ac_desc(zxid_conf * cf,struct zx_elem_s * father,char * binding,char * loc,char * ix)634 struct zx_md_AssertionConsumerService_s* zxid_ac_desc(zxid_conf* cf, struct zx_elem_s* father, char* binding, char* loc, char* ix) {
635   struct zx_md_AssertionConsumerService_s* d = zx_NEW_md_AssertionConsumerService(cf->ctx,father);
636   d->Binding = zx_ref_attr(cf->ctx, &d->gg, zx_Binding_ATTR, binding);
637   d->Location = zx_attrf(cf->ctx, &d->gg, zx_Location_ATTR, "%s%s", cf->burl, loc);
638   d->index = zx_ref_attr(cf->ctx, &d->gg, zx_index_ATTR, ix);
639   zx_reverse_elem_lists(&d->gg);
640   return d;
641 }
642 
643 /*() Generate SP SSO Descriptor metadata fragment [SAML2meta]. */
644 
645 /* Called by:  zxid_sp_meta */
zxid_sp_sso_desc(zxid_conf * cf,struct zx_elem_s * father)646 struct zx_md_SPSSODescriptor_s* zxid_sp_sso_desc(zxid_conf* cf, struct zx_elem_s* father)
647 {
648   struct zx_md_SPSSODescriptor_s* sp_ssod = zx_NEW_md_SPSSODescriptor(cf->ctx,father);
649   sp_ssod->AuthnRequestsSigned        = zx_ref_attr(cf->ctx, &sp_ssod->gg, zx_AuthnRequestsSigned_ATTR, cf->authn_req_sign?"1":"0");
650   sp_ssod->WantAssertionsSigned       = zx_ref_attr(cf->ctx, &sp_ssod->gg, zx_WantAssertionsSigned_ATTR, cf->want_sso_a7n_signed?"1":"0");
651   sp_ssod->errorURL                   = zx_attrf(cf->ctx, &sp_ssod->gg, zx_errorURL_ATTR, "%s?o=E", cf->burl);
652   sp_ssod->protocolSupportEnumeration = zx_ref_attr(cf->ctx, &sp_ssod->gg, zx_protocolSupportEnumeration_ATTR, SAML2_PROTO);
653 
654   LOCK(cf->mx, "read certs for our md");
655   if (!cf->enc_cert)
656     cf->enc_cert = zxid_read_cert(cf, "enc-nopw-cert.pem");
657 
658   if (!cf->sign_cert)
659     cf->sign_cert = zxid_read_cert(cf, "sign-nopw-cert.pem");
660 
661   if (!cf->enc_cert || !cf->sign_cert) {
662     UNLOCK(cf->mx, "read certs for our md");
663     ERR("Signing or encryption certificate not found (or both are corrupt). %p", cf->enc_cert);
664   } else {
665     sp_ssod->KeyDescriptor = zxid_key_desc(cf, &sp_ssod->gg, "encryption", cf->enc_cert);
666     sp_ssod->KeyDescriptor = zxid_key_desc(cf, &sp_ssod->gg, "signing", cf->sign_cert);
667     UNLOCK(cf->mx, "read certs for our md");
668   }
669 
670   sp_ssod->SingleLogoutService = zxid_slo_desc(cf, &sp_ssod->gg, SAML2_REDIR, "?o=Q", "?o=Q");
671   sp_ssod->SingleLogoutService = zxid_slo_desc(cf, &sp_ssod->gg, SAML2_SOAP,  "?o=S", 0);
672 
673   sp_ssod->ManageNameIDService = zxid_mni_desc(cf, &sp_ssod->gg, SAML2_REDIR, "?o=Q", "?o=Q");
674   sp_ssod->ManageNameIDService = zxid_mni_desc(cf, &sp_ssod->gg, SAML2_SOAP,  "?o=S", 0);
675 
676   sp_ssod->NameIDFormat = zx_ref_elem(cf->ctx, &sp_ssod->gg, zx_md_NameIDFormat_ELEM, SAML2_PERSISTENT_NID_FMT);
677   sp_ssod->NameIDFormat = zx_ref_elem(cf->ctx, &sp_ssod->gg, zx_md_NameIDFormat_ELEM, SAML2_TRANSIENT_NID_FMT);
678 
679   /* N.B. The index values should not be changed. They are used in
680    * AuthnReq to choose profile using AssertionConsumerServiceIndex */
681 
682   sp_ssod->AssertionConsumerService = zxid_ac_desc(cf, &sp_ssod->gg, SAML2_ART, "", "1");
683   sp_ssod->AssertionConsumerService = zxid_ac_desc(cf, &sp_ssod->gg, SAML2_POST, "?o=P", "2");
684   sp_ssod->AssertionConsumerService = zxid_ac_desc(cf, &sp_ssod->gg, SAML2_SOAP, "?o=S", "3");
685   sp_ssod->AssertionConsumerService = zxid_ac_desc(cf, &sp_ssod->gg, SAML2_PAOS, "?o=P", "4");
686   sp_ssod->AssertionConsumerService = zxid_ac_desc(cf, &sp_ssod->gg, SAML2_POST_SIMPLE_SIGN, "?o=P", "5");
687   sp_ssod->AssertionConsumerService = zxid_ac_desc(cf, &sp_ssod->gg, OAUTH2_REDIR, "?o=O", "8");
688   zx_reverse_elem_lists(&sp_ssod->gg);
689   return sp_ssod;
690 }
691 
692 /*() Generate IdP SSO Descriptor metadata fragment [SAML2meta]. */
693 
694 /* Called by:  zxid_sp_meta */
zxid_idp_sso_desc(zxid_conf * cf,struct zx_elem_s * father)695 struct zx_md_IDPSSODescriptor_s* zxid_idp_sso_desc(zxid_conf* cf, struct zx_elem_s* father)
696 {
697   struct zx_md_IDPSSODescriptor_s* idp_ssod = zx_NEW_md_IDPSSODescriptor(cf->ctx,father);
698   idp_ssod->WantAuthnRequestsSigned
699     = zx_ref_attr(cf->ctx, &idp_ssod->gg, zx_WantAuthnRequestsSigned_ATTR,
700 		  cf->want_authn_req_signed?"1":"0");
701   idp_ssod->errorURL
702     = zx_attrf(cf->ctx, &idp_ssod->gg, zx_errorURL_ATTR, "%s?o=E", cf->burl);
703   idp_ssod->protocolSupportEnumeration
704     = zx_ref_attr(cf->ctx, &idp_ssod->gg, zx_protocolSupportEnumeration_ATTR, SAML2_PROTO);
705 
706   LOCK(cf->mx, "read certs for our md idp");
707   if (!cf->enc_cert)
708     cf->enc_cert = zxid_read_cert(cf, "enc-nopw-cert.pem");
709 
710   if (!cf->sign_cert)
711     cf->sign_cert = zxid_read_cert(cf, "sign-nopw-cert.pem");
712 
713   if (!cf->enc_cert || !cf->sign_cert) {
714     UNLOCK(cf->mx, "read certs for our md idp");
715     ERR("Neither signing nor encryption certificate found (or both are corrupt). %p", cf->enc_cert);
716   } else {
717     idp_ssod->KeyDescriptor = zxid_key_desc(cf, &idp_ssod->gg, "encryption", cf->enc_cert);
718     idp_ssod->KeyDescriptor = zxid_key_desc(cf, &idp_ssod->gg, "signing", cf->sign_cert);
719     UNLOCK(cf->mx, "read certs for our md idp");
720   }
721 
722 #if 0
723   /* *** NI */
724   idp_ssod->ArtifactResolutionService = zxid_ar_desc(cf, &idp_ssod->gg, SAML2_SOAP, "?o=S", 0);
725 #endif
726 
727   idp_ssod->SingleLogoutService = zxid_slo_desc(cf, &idp_ssod->gg, SAML2_REDIR, "?o=Q", "?o=Q");
728   idp_ssod->SingleLogoutService = zxid_slo_desc(cf, &idp_ssod->gg, SAML2_SOAP, "?o=S", 0);
729 
730 #if 0
731   /* *** NI */
732   idp_ssod->ManageNameIDService = zxid_mni_desc(cf, &idp_ssod->gg, SAML2_REDIR, "?o=Q", "?o=Q");
733   idp_ssod->ManageNameIDService = zxid_mni_desc(cf, &idp_ssod->gg, SAML2_SOAP, "?o=S", 0);
734 #endif
735 
736   idp_ssod->NameIDFormat = zx_ref_elem(cf->ctx, &idp_ssod->gg, zx_md_NameIDFormat_ELEM, SAML2_PERSISTENT_NID_FMT);
737   idp_ssod->NameIDFormat = zx_ref_elem(cf->ctx, &idp_ssod->gg, zx_md_NameIDFormat_ELEM, SAML2_TRANSIENT_NID_FMT);
738 
739   idp_ssod->SingleSignOnService = zxid_sso_desc(cf, &idp_ssod->gg, SAML2_REDIR, "?o=F", 0);
740   idp_ssod->SingleSignOnService = zxid_sso_desc(cf, &idp_ssod->gg, OAUTH2_REDIR, "?o=F", 0); /* Same endpoint as for SAML - the detection is from presence of CGI field response_type */
741 
742   if (cf->imps_ena)
743     idp_ssod->NameIDMappingService = zxid_nimap_desc(cf, &idp_ssod->gg, SAML2_SOAP, "?o=S", 0);
744 
745   zx_reverse_elem_lists(&idp_ssod->gg);
746   return idp_ssod;
747 }
748 
749 /*() Generate Organization metadata fragment [SAML2meta]. */
750 
751 /* Called by:  zxid_sp_meta */
zxid_org_desc(zxid_conf * cf,struct zx_elem_s * father)752 struct zx_md_Organization_s* zxid_org_desc(zxid_conf* cf, struct zx_elem_s* father)
753 {
754   struct zx_md_Organization_s* org = zx_NEW_md_Organization(cf->ctx,father);
755   org->OrganizationName = zx_NEW_md_OrganizationName(cf->ctx, &org->gg);
756   org->OrganizationName->lang = zx_ref_attr(cf->ctx, &org->OrganizationName->gg, zx_xml_lang_ATTR, "en");  /* *** config */
757   if (cf->org_name && cf->org_name[0])
758     zx_add_content(cf->ctx, &org->OrganizationName->gg, zx_ref_str(cf->ctx, cf->org_name));
759   else
760     zx_add_content(cf->ctx, &org->OrganizationName->gg, zx_ref_str(cf->ctx, STRNULLCHKQ(cf->nice_name)));
761 
762   org->OrganizationDisplayName = zx_NEW_md_OrganizationDisplayName(cf->ctx, &org->gg);
763   org->OrganizationDisplayName->lang = zx_ref_attr(cf->ctx, &org->OrganizationDisplayName->gg, zx_xml_lang_ATTR, "en");  /* *** config */
764   zx_add_content(cf->ctx, &org->OrganizationDisplayName->gg, zx_ref_str(cf->ctx, STRNULLCHKQ(cf->nice_name)));
765 
766   if (cf->button_url && cf->button_url[0]) {
767     /* see symlabs-saml-displayname-2008.pdf submitted to OASIS SSTC) */
768     /* *** add support for multiple $ separated button_url's */
769     org->OrganizationURL = zx_NEW_md_OrganizationURL(cf->ctx, &org->gg);
770     org->OrganizationURL->lang = zx_ref_attr(cf->ctx, &org->OrganizationURL->gg, zx_xml_lang_ATTR, "en");  /* *** config */
771     zx_add_content(cf->ctx, &org->OrganizationURL->gg, zx_ref_str(cf->ctx, cf->button_url));
772   }
773   zx_reverse_elem_lists(&org->gg);
774   return org;
775 }
776 
777 /*() Generate Contact Person metadata fragment [SAML2meta]. */
778 
779 /* Called by:  zxid_sp_meta */
zxid_contact_desc(zxid_conf * cf,struct zx_elem_s * father)780 struct zx_md_ContactPerson_s* zxid_contact_desc(zxid_conf* cf, struct zx_elem_s* father)
781 {
782   struct zx_md_ContactPerson_s* contact = zx_NEW_md_ContactPerson(cf->ctx,father);
783 
784   contact->contactType = zx_ref_attr(cf->ctx, &contact->gg, zx_contactType_ATTR, "administrative");  /* *** config */
785 
786   if (cf->contact_org) {
787     if (cf->contact_org[0])
788       contact->Company = zx_ref_elem(cf->ctx, &contact->gg, zx_md_Company_ELEM, cf->contact_org);
789   } else
790     if (cf->org_name && cf->org_name[0])
791       contact->Company
792 	= zx_ref_elem(cf->ctx, &contact->gg, zx_md_Company_ELEM, cf->org_name);
793     else
794       contact->Company
795 	= zx_ref_elem(cf->ctx, &contact->gg, zx_md_Company_ELEM, STRNULLCHKQ(cf->nice_name));
796 
797   if (cf->contact_name && cf->contact_name[0])
798     contact->SurName = zx_ref_elem(cf->ctx, &contact->gg, zx_md_SurName_ELEM, cf->contact_name);
799   if (cf->contact_email && cf->contact_email[0])
800     contact->EmailAddress = zx_ref_elem(cf->ctx, &contact->gg, zx_md_EmailAddress_ELEM, cf->contact_email);
801   if (cf->contact_tel && cf->contact_tel[0])
802     contact->TelephoneNumber = zx_ref_elem(cf->ctx, &contact->gg, zx_md_TelephoneNumber_ELEM, cf->contact_tel);
803 
804   zx_reverse_elem_lists(&contact->gg);
805   return contact;
806 }
807 
808 /*(i) Primary interface to our own Entity ID. While this would usually be
809  * automatically generated from URL configuration option so as to conform
810  * to the Well Known Location (WKL) metadata exchange convention [SAML2meta].
811  * On some sites the entity ID may be different and thus everybody who
812  * does not know better should use this interface to obtain it.
813  *
814  * cf:: ZXID configuration object, used to compute EntityID and also for memory allocation
815  * return:: Entity ID as zx_str (caller must free with zx_str_free()) */
816 
817 /* Called by:  zxid_idp_map_nid2uid, zxid_mk_oauth_az_req, zxid_mk_subj, zxid_my_issuer, zxid_nidmap_do, zxid_ses_to_pool, zxid_sp_sso_finalize, zxid_wsf_validate_a7n */
zxid_my_ent_id(zxid_conf * cf)818 struct zx_str* zxid_my_ent_id(zxid_conf* cf)
819 {
820   if (cf->non_standard_entityid) {
821     D("my_entity_id nonstd(%s)", cf->non_standard_entityid);
822     return zx_strf(cf->ctx, "%s", cf->non_standard_entityid);
823   } else if (cf->bare_url_entityid) {
824     D("my_entity_id bare url(%s)", cf->burl);
825     return zx_strf(cf->ctx, "%s", cf->burl);
826   } else {
827     D("my_entity_id(%s?o=B)", cf->burl);
828     return zx_strf(cf->ctx, "%s?o=B", cf->burl);
829   }
830 }
831 
832 /*() Return our EntityID as c-string. Caller must free with ZX_FREE(cf->ctx, eid) */
833 
834 /* Called by:  main x2, stomp_got_ack, test_receipt, zxbus_send_cmdf, zxid_idp_select_zxstr_cf_cgi, zxid_map_bangbang, zxid_show_conf, zxid_sso_issue_jwt */
zxid_my_ent_id_cstr(zxid_conf * cf)835 char* zxid_my_ent_id_cstr(zxid_conf* cf)
836 {
837   int len;
838   char* eid;
839   if (cf->non_standard_entityid) {
840     D("my_entity_id nonstd(%s)", cf->non_standard_entityid);
841     return zx_dup_cstr(cf->ctx, cf->non_standard_entityid);
842   } else if (cf->bare_url_entityid) {
843     D("my_entity_id bare url(%s)", cf->burl);
844     return zx_dup_cstr(cf->ctx, cf->burl);
845   } else {
846     D("my_entity_id(%s?o=B)", cf->burl);
847     len = strlen(cf->burl);
848     eid = ZX_ALLOC(cf->ctx, len+sizeof("?o=B"));
849     strcpy(eid, cf->burl);
850     strcpy(eid+len, "?o=B");
851     return eid;
852   }
853 }
854 
855 /*() Return our EntityID as an attribute. Caller must free. */
856 
857 /* Called by:  zxid_check_fed, zxid_mk_ecp_Request_hdr, zxid_sp_meta, zxid_wsf_decor */
zxid_my_ent_id_attr(zxid_conf * cf,struct zx_elem_s * father,int tok)858 struct zx_attr_s* zxid_my_ent_id_attr(zxid_conf* cf, struct zx_elem_s* father, int tok)
859 {
860   if (cf->non_standard_entityid) {
861     D("my_nonstd_entity_id(%s)", cf->non_standard_entityid);
862     return zx_attrf(cf->ctx, father, tok, "%s", cf->non_standard_entityid);
863   } else if (cf->bare_url_entityid) {
864     D("my_entity_id bare url(%s)", cf->burl);
865     return zx_attrf(cf->ctx, father, tok, "%s", cf->burl);
866   } else {
867     D("my_entity_id(%s?o=B)", cf->burl);
868     return zx_attrf(cf->ctx, father, tok, "%s?o=B", cf->burl);
869   }
870 }
871 
872 /*() Dynamically determine our Common Domain Cookie (IdP discovery) URL. */
873 
874 /* Called by: */
zxid_my_cdc_url(zxid_conf * cf)875 struct zx_str* zxid_my_cdc_url(zxid_conf* cf)
876 {
877   return zx_strf(cf->ctx, "%s?o=C", cf->cdc_url);
878 }
879 
880 /*() Generate Issuer value. Issuer is often same as Entity ID, but sometimes
881  * it will be affiliation ID. This function is a low level interface. Usually
882  * you would want to use zxid_my_issuer(). */
883 
884 /* Called by:  zxid_my_issuer */
zxid_issuer(zxid_conf * cf,struct zx_elem_s * father,struct zx_str * nameid,char * affiliation)885 struct zx_sa_Issuer_s* zxid_issuer(zxid_conf* cf, struct zx_elem_s* father, struct zx_str* nameid, char* affiliation)
886 {
887   struct zx_sa_Issuer_s* is = zx_NEW_sa_Issuer(cf->ctx, father);
888   zx_add_content(cf->ctx, &is->gg, nameid);
889   if (affiliation && affiliation[0])
890     is->NameQualifier = zx_ref_attr(cf->ctx, &is->gg, zx_NameQualifier_ATTR, affiliation);
891   /*is->Format = zx_ref_str(cf->ctx, );*/
892   return is;
893 }
894 
895 /*() Generate Issuer value for our entity. Issuer is often same as Entity ID, but sometimes
896  * it will be affiliation ID. */
897 
898 /* Called by:  zxid_mk_a7n, zxid_mk_art_deref, zxid_mk_authn_req, zxid_mk_az, zxid_mk_az_cd1, zxid_mk_ecp_Request_hdr, zxid_mk_logout, zxid_mk_logout_resp, zxid_mk_mni, zxid_mk_mni_resp, zxid_mk_saml_resp */
zxid_my_issuer(zxid_conf * cf,struct zx_elem_s * father)899 struct zx_sa_Issuer_s* zxid_my_issuer(zxid_conf* cf, struct zx_elem_s* father) {
900   return zxid_issuer(cf, father, zxid_my_ent_id(cf), cf->affiliation);
901 }
902 
903 /*() Generate the (IdP) metadata field indicating presence of a metadata authority. */
904 
zxid_md_authority_loc(zxid_conf * cf,struct zx_md_EntityDescriptor_s * ed)905 static struct zx_md_AdditionalMetadataLocation_s* zxid_md_authority_loc(zxid_conf* cf, struct zx_md_EntityDescriptor_s* ed) {
906   struct zx_md_AdditionalMetadataLocation_s* mda;
907   mda = zx_NEW_md_AdditionalMetadataLocation(cf->ctx, &ed->gg);
908   mda->namespace_is_cxx_keyword = zx_dup_attr(cf->ctx,&mda->gg,zx_namespace_ATTR,"#md-authority");
909   zx_add_content(cf->ctx, &mda->gg, zx_strf(cf->ctx, "%s?o=b", cf->burl));
910   return mda;
911 }
912 
913 /*() Generate our SP metadata and return it as a string. cgi may be specified as null. */
914 
915 /* Called by:  zxid_genmd, zxid_send_sp_meta, zxid_simple_show_meta */
zxid_sp_meta(zxid_conf * cf,zxid_cgi * cgi)916 struct zx_str* zxid_sp_meta(zxid_conf* cf, zxid_cgi* cgi)
917 {
918   struct zx_md_EntityDescriptor_s* ed;
919 
920   ed = zx_NEW_md_EntityDescriptor(cf->ctx,0);
921   ed->entityID = zxid_my_ent_id_attr(cf, &ed->gg, zx_entityID_ATTR);
922   if (cf->idp_ena)
923     ed->IDPSSODescriptor = zxid_idp_sso_desc(cf, &ed->gg);
924   ed->SPSSODescriptor = zxid_sp_sso_desc(cf, &ed->gg);
925   ed->Organization = zxid_org_desc(cf, &ed->gg);
926   ed->ContactPerson = zxid_contact_desc(cf, &ed->gg);
927   if (cf->md_authority_ena)
928     ed->AdditionalMetadataLocation = zxid_md_authority_loc(cf, ed);
929   zx_reverse_elem_lists(&ed->gg);
930 
931   if (cf->log_level>0)
932     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "W", "MYMD", 0, 0);
933   return zx_easy_enc_elem_opt(cf, &ed->gg);
934 }
935 
936 /*() Generate our SP metadata and send it to remote partner.
937  *
938  * Limitation:: This function only works with CGI as it will print the
939  *     serialized metadata straight to stdout. There are other
940  *     methods for getting metadata without this limitation, e.g. zxid_sp_meta() */
941 
942 /* Called by:  main x2, opt x2 */
zxid_send_sp_meta(zxid_conf * cf,zxid_cgi * cgi)943 int zxid_send_sp_meta(zxid_conf* cf, zxid_cgi* cgi) {
944   struct zx_str* ss = zxid_sp_meta(cf, cgi);
945   if (!ss)
946     return 0;
947   //write_all_fd(1, ss->s, ss->len);
948   write_all_fd(fdstdout, ss->s, ss->len);
949   zx_str_free(cf->ctx, ss);
950   return 0;
951 }
952 
953 /* ------- CARML ------- */
954 
955 /*() Generate our SP CARML and return it as a string. */
956 
957 /* Called by:  zxid_simple_show_carml */
zxid_sp_carml(zxid_conf * cf)958 struct zx_str* zxid_sp_carml(zxid_conf* cf)
959 {
960   if (cf->log_level>0)
961     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "W", "MYCARML", 0, 0);
962 
963   /* *** Much work needed to study CARML spec and to convert need and want to comply */
964 
965   return zx_strf(cf->ctx,
966 "<carml:ClientAttrReq"
967 " AppName=\"ZXID SP\""
968 " Description=\"ZXID SP Attribute Needs and Wants\""
969 " xmlns:carml=\"urn:igf:client:0.9:carml\">"
970 "<carml:DataDefs>"
971 
972 "  <carml:Attributes>"
973 "  </carml:Attributes>"
974 
975 "  <carml:Predicates>"
976 "  </carml:Predicates>"
977 
978 "  <carml:Roles>"
979 "  </carml:Roles>"
980 
981 "  <carml:Policies>"
982 "  </carml:Policies>"
983 
984 "</carml:DataDefs>"
985 
986 "<carml:ReadInteraction/>"
987 "<carml:FindInteraction/>"
988 "<carml:SearchInteraction/>"
989 "<carml:CompareInteraction/>"
990 "<carml:ModifyInteraction/>"
991 "<carml:AddInteraction/>"
992 
993 "</carml:ClientAttrReq>"
994 		 );
995 }
996 
997 /* EOF  --  zxidmeta.c */
998