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