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