1 /* zxidmk.c - Handwritten nitty-gritty functions for constructing various elems
2 * Copyright (c) 2006-2011 Symlabs (symlabs@symlabs.com), All Rights Reserved.
3 * Author: Sampo Kellomaki (sampo@iki.fi)
4 * This is confidential unpublished proprietary source code of the author.
5 * NO WARRANTY, not even implied warranties. Contains trade secrets.
6 * Distribution prohibited unless authorized in writing.
7 * Licensed under Apache License 2.0, see file COPYING.
8 * $Id: zxidmk.c,v 1.27 2009-11-24 23:53:40 sampo Exp $
9 *
10 * 12.8.2006, created --Sampo
11 * 8.10.2007, added signing ArtifactResolve --Sampo
12 * 7.10.2008, added documentation --Sampo
13 * 24.8.2009, added XACML stuff --Sampo
14 */
15
16 #include "platform.h"
17 #include "errmac.h"
18 #include "zxid.h"
19 #include "zxidpriv.h"
20 #include "zxidutil.h"
21 #include "zxidconf.h"
22 #include "saml2.h"
23 #include "c/zx-const.h"
24 #include "c/zx-ns.h"
25 #include "c/zx-data.h"
26
27 /*() Interpret ZXID standard form fields to construct a XML structure for AuthnRequest */
28
29 /* Called by: a7n_test, x509_test, zxid_lecp_check, zxid_start_sso_url */
zxid_mk_authn_req(zxid_conf * cf,zxid_cgi * cgi)30 struct zx_sp_AuthnRequest_s* zxid_mk_authn_req(zxid_conf* cf, zxid_cgi* cgi)
31 {
32 char index[2] = "1";
33 struct zx_sp_AuthnRequest_s* ar = zx_NEW_sp_AuthnRequest(cf->ctx,0);
34 ar->ID = zxid_mk_id_attr(cf, &ar->gg, zx_ID_ATTR, "N", ZXID_ID_BITS);
35 ar->Version = zx_ref_attr(cf->ctx, &ar->gg, zx_Version_ATTR, SAML2_VERSION);
36 ar->IssueInstant = zxid_date_time_attr(cf, &ar->gg, zx_IssueInstant_ATTR, time(0));
37
38 if (cf->nice_name && cf->nice_name[0])
39 ar->ProviderName = zx_ref_attr(cf->ctx, &ar->gg, zx_ProviderName_ATTR, cf->nice_name);
40
41 if (BOOL_STR_TEST(cgi->force_authn))
42 ar->ForceAuthn = zx_ref_attr(cf->ctx, &ar->gg, zx_ForceAuthn_ATTR, XML_TRUE);
43
44 if (BOOL_STR_TEST(cgi->ispassive))
45 ar->IsPassive = zx_ref_attr(cf->ctx, &ar->gg, zx_IsPassive_ATTR, XML_TRUE);
46
47 if (cgi->consent && cgi->consent[0])
48 ar->Consent = zx_ref_attr(cf->ctx, &ar->gg, zx_Consent_ATTR, cgi->consent);
49
50 ar->Issuer = zxid_my_issuer(cf, &ar->gg);
51
52 D("nid_fmt(%s) allow_create=%c ispassive=%c", cgi->nid_fmt, cgi->allow_create, cgi->ispassive);
53 if (cgi->nid_fmt && cgi->nid_fmt[0] || cgi->affil && cgi->affil[0]
54 || BOOL_STR_TEST(cgi->allow_create)) {
55 ar->NameIDPolicy = zx_NEW_sp_NameIDPolicy(cf->ctx, &ar->gg);
56
57 if (cgi->nid_fmt && cgi->nid_fmt[0])
58 ar->NameIDPolicy->Format = zx_ref_attr(cf->ctx, &ar->NameIDPolicy->gg, zx_Format_ATTR, zxid_saml2_map_nid_fmt(cgi->nid_fmt));
59
60 if (cgi->affil && cgi->affil[0])
61 ar->NameIDPolicy->SPNameQualifier = zx_ref_attr(cf->ctx, &ar->NameIDPolicy->gg, zx_SPNameQualifier_ATTR, cgi->affil);
62
63 if (BOOL_STR_TEST(cgi->allow_create))
64 ar->NameIDPolicy->AllowCreate = zx_ref_attr(cf->ctx, &ar->NameIDPolicy->gg, zx_AllowCreate_ATTR, XML_TRUE); /* default false */
65 }
66
67 if (cgi->authn_ctx && cgi->authn_ctx[0]) {
68 ar->RequestedAuthnContext = zx_NEW_sp_RequestedAuthnContext(cf->ctx, &ar->gg);
69 ar->RequestedAuthnContext->AuthnContextClassRef
70 = zx_ref_elem(cf->ctx, &ar->RequestedAuthnContext->gg, zx_sa_AuthnContextClassRef_ELEM, zxid_saml2_map_authn_ctx(cgi->authn_ctx));
71 if (cgi->matching_rule && cgi->matching_rule[0])
72 ar->RequestedAuthnContext->Comparison = zx_ref_attr(cf->ctx, &ar->RequestedAuthnContext->gg, zx_Comparison_ATTR, cgi->matching_rule);
73 }
74 if (cgi->pr_ix) {
75 index[0] = cgi->pr_ix+'0';
76 ar->AssertionConsumerServiceIndex = zx_dup_attr(cf->ctx, &ar->gg, zx_AssertionConsumerServiceIndex_ATTR, index);
77 }
78 if (cgi->get_complete && cgi->get_complete[0]
79 || cgi->pxy_count && cgi->pxy_count[0]
80 || cgi->idppxylist && cgi->idppxylist[0]) {
81 ar->Scoping = zx_NEW_sp_Scoping(cf->ctx, &ar->gg);
82 if (cgi->pxy_count && cgi->pxy_count[0])
83 ar->Scoping->ProxyCount = zx_ref_attr(cf->ctx, &ar->gg, zx_ProxyCount_ATTR, cgi->pxy_count);
84 #if 0
85 if (cgi->get_complete && cgi->get_complete[0] || cgi->idppxylist) {
86 ar->Scoping->IDPList = zx_NEW_sp_IDPList(cf->ctx, &ar->Scoping->gg);
87 /* *** Add IDPEntry and GetComplete */
88 }
89 #endif
90 }
91 zx_reverse_elem_lists(&ar->gg); /* Ensure Issuer comes first. */
92 return ar;
93 }
94
95 /*() Make the body for the ArtifactResolve SOAP message, signing it if needed. */
96
97 /* Called by: covimp_test, zxid_sp_deref_art */
zxid_mk_art_deref(zxid_conf * cf,struct zx_elem_s * father,zxid_entity * idp_meta,const char * artifact)98 struct zx_sp_ArtifactResolve_s* zxid_mk_art_deref(zxid_conf* cf, struct zx_elem_s* father, zxid_entity* idp_meta, const char* artifact)
99 {
100 X509* sign_cert;
101 EVP_PKEY* sign_pkey;
102 struct zxsig_ref refs;
103 struct zx_sp_ArtifactResolve_s* ar = zx_NEW_sp_ArtifactResolve(cf->ctx, father);
104 ar->Version = zx_ref_attr(cf->ctx, &ar->gg, zx_Version_ATTR, SAML2_VERSION);
105 ar->IssueInstant = zxid_date_time_attr(cf, &ar->gg, zx_IssueInstant_ATTR, time(0));
106 ar->ID = zxid_mk_id_attr(cf, &ar->gg, zx_ID_ATTR, "R", ZXID_ID_BITS);
107 ar->Artifact = zx_ref_elem(cf->ctx, &ar->gg, zx_sp_Artifact_ELEM, artifact);
108 ar->Issuer = zxid_my_issuer(cf, &ar->gg);
109 if (cf->sso_soap_sign) {
110 ZERO(&refs, sizeof(refs));
111 refs.id = &ar->ID->g;
112 refs.canon = zx_easy_enc_elem_sig(cf, &ar->gg);
113 if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert art deref")) {
114 ar->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
115 zx_add_kid_after_sa_Issuer(&ar->gg, &ar->Signature->gg);
116 }
117 zx_str_free(cf->ctx, refs.canon);
118 }
119 return ar;
120 }
121
122 /*() Create SAML protocol <Status> element, given various levels of error input. */
123
124 /* Called by: so_enc_dec, zxid_OK, zxid_nidmap_do x2, zxid_ssos_anreq x4 */
zxid_mk_Status(zxid_conf * cf,struct zx_elem_s * father,const char * sc1,const char * sc2,const char * msg)125 struct zx_sp_Status_s* zxid_mk_Status(zxid_conf* cf, struct zx_elem_s* father, const char* sc1, const char* sc2, const char* msg)
126 {
127 struct zx_sp_Status_s* st = zx_NEW_sp_Status(cf->ctx, father);
128 if (msg)
129 st->StatusMessage = zx_ref_elem(cf->ctx, &st->gg, zx_sp_StatusMessage_ELEM, msg);
130 st->StatusCode = zx_NEW_sp_StatusCode(cf->ctx, &st->gg);
131 st->StatusCode->Value = zx_ref_attr(cf->ctx, &st->StatusCode->gg, zx_Value_ATTR, sc1);
132 if (sc2) {
133 st->StatusCode->StatusCode = zx_NEW_sp_StatusCode(cf->ctx, &st->StatusCode->gg);
134 st->StatusCode->StatusCode->Value = zx_ref_attr(cf->ctx, &st->StatusCode->StatusCode->gg, zx_Value_ATTR, sc2);
135 }
136 return st;
137 }
138
139 /*() Create SAML <Status> element indicating success. */
140
141 /* Called by: zxid_idp_soap_dispatch, zxid_mk_saml_resp, zxid_mni_do, zxid_mni_do_ss, zxid_nidmap_do, zxid_slo_resp_redir, zxid_sp_soap_dispatch */
zxid_OK(zxid_conf * cf,struct zx_elem_s * father)142 struct zx_sp_Status_s* zxid_OK(zxid_conf* cf, struct zx_elem_s* father)
143 {
144 return zxid_mk_Status(cf, father, SAML2_SC_SUCCESS, 0, 0);
145 }
146
147 /*() Create EncryptedID given normal NameID and metadata of destination. Encryption
148 * will be done using encryption certificate of the receiver identified by the metadata. */
149
150 /* Called by: zxid_mk_logout, zxid_mk_mni, zxid_mk_subj */
zxid_mk_enc_id(zxid_conf * cf,struct zx_elem_s * father,zxid_nid * nid,zxid_entity * meta)151 struct zx_sa_EncryptedID_s* zxid_mk_enc_id(zxid_conf* cf, struct zx_elem_s* father, zxid_nid* nid, zxid_entity* meta)
152 {
153 struct zx_xenc_EncryptedData_s* ed;
154 struct zx_sa_EncryptedID_s* encid;
155 struct zx_str* ss;
156 if (!cf || !nid) {
157 ERR("NULL arguments (programmer error) %p", cf);
158 return 0;
159 }
160 if (!meta || !meta->enc_cert) {
161 ERR("Missing destination metadata or the metadata does not have encryption certificate. %p", meta);
162 return 0;
163 }
164 ss = zx_easy_enc_elem_opt(cf, &nid->gg);
165 if (!ss) {
166 ERR("Failed to XML serialize nameid %p", nid);
167 return 0;
168 }
169 encid = zx_NEW_sa_EncryptedID(cf->ctx, father);
170 if (cf->enckey_opt & 0x20) {
171 /* Nested EncryptedKey approach (Shibboleth early 2010) */
172 ed = zxenc_pubkey_enc(cf, ss, 0, meta->enc_cert, "41", 0);
173 } else {
174 /* RetrievalMethod approach */
175 ed = zxenc_pubkey_enc(cf, ss, &encid->EncryptedKey, meta->enc_cert, "38", meta);
176 }
177 if (!ed) {
178 ERR("Failed to encrypt a nameid (this could be due to problems with encryption certificate of the destination or destination's metadata; you may be able to work around this problem by manipulating NAMEID_ENC config option, but consider the security implication) cert=%p", meta->enc_cert);
179 return 0;
180 }
181 ZX_ADD_KID(encid, EncryptedData, ed);
182 zx_str_free(cf->ctx, ss);
183 return encid;
184 }
185
186 /*() Create EncryptedAssertion given normal A7N and metadata of destination. Encryption
187 * will be done using encryption certificate of the receiver identified by the metadata. */
188
189 /* Called by: zxid_add_fed_tok2epr, zxid_imreq, zxid_mk_saml_resp */
zxid_mk_enc_a7n(zxid_conf * cf,struct zx_elem_s * father,zxid_a7n * a7n,zxid_entity * meta)190 struct zx_sa_EncryptedAssertion_s* zxid_mk_enc_a7n(zxid_conf* cf, struct zx_elem_s* father, zxid_a7n* a7n, zxid_entity* meta)
191 {
192 struct zx_xenc_EncryptedData_s* ed;
193 struct zx_str* ss;
194 struct zx_sa_EncryptedAssertion_s* enc_a7n;
195 if (!cf || !a7n) {
196 ERR("NULL arguments (programmer error) %p", cf);
197 return 0;
198 }
199 if (!meta || !meta->enc_cert) {
200 ERR("Missing destination metadata or the metadata does not have encryption certificate. %p", meta);
201 return 0;
202 }
203 ss = zx_easy_enc_elem_opt(cf, &a7n->gg);
204 if (!ss) {
205 ERR("Failed to XML serialize assertion %p", a7n);
206 return 0;
207 }
208 enc_a7n = zx_NEW_sa_EncryptedAssertion(cf->ctx, father);
209 if (cf->enckey_opt & 0x20) {
210 /* Nested EncryptedKey approach (Shibboleth early 2010) */
211 ed = zxenc_pubkey_enc(cf, ss, 0, meta->enc_cert, "40", 0);
212 } else {
213 /* RetrievalMethod approach */
214 ed = zxenc_pubkey_enc(cf, ss, &enc_a7n->EncryptedKey, meta->enc_cert, "39", meta);
215 }
216 if (!ed) {
217 ERR("Failed to encrypt assertion %p (this could be due to problems with encryption certificate of the destination or destination's metadata; you may be able to work around this problem by manipulating POST_A7N_ENC or DI_A7N_ENC config option, but consider the security implication)", a7n);
218 return 0;
219 }
220 ZX_ADD_KID(enc_a7n, EncryptedData, ed);
221 zx_str_free(cf->ctx, ss);
222 return enc_a7n;
223 }
224
225 /*() Create XML data structure for <LogoutRequest> element. Low level API. */
226
227 /* Called by: test_ibm_cert_problem_enc_dec, zxid_sp_slo_redir, zxid_sp_slo_soap */
zxid_mk_logout(zxid_conf * cf,zxid_nid * nid,struct zx_str * ses_ix,zxid_entity * idp_meta)228 struct zx_sp_LogoutRequest_s* zxid_mk_logout(zxid_conf* cf, zxid_nid* nid, struct zx_str* ses_ix, zxid_entity* idp_meta)
229 {
230 struct zx_sp_LogoutRequest_s* r = zx_NEW_sp_LogoutRequest(cf->ctx,0);
231 r->Issuer = zxid_my_issuer(cf, &r->gg);
232 r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "L", ZXID_ID_BITS);
233 r->Version = zx_ref_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION);
234 r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0));
235
236 D("nameid_enc(%d) idp_meta(%p) enc_cert(%p)", cf->nameid_enc, idp_meta, idp_meta->enc_cert);
237 if (cf->nameid_enc && idp_meta)
238 r->EncryptedID = zxid_mk_enc_id(cf, &r->gg, nid, idp_meta);
239 else
240 r->NameID = nid;
241 if (ses_ix)
242 r->SessionIndex = zx_new_str_elem(cf->ctx, &r->gg, zx_sp_SessionIndex_ELEM, ses_ix);
243 return r;
244 }
245
246 /*() Create XML data structure for <LogoutResponse> element. Low level API. */
247
248 /* Called by: zxid_idp_soap_dispatch, zxid_slo_resp_redir, zxid_sp_soap_dispatch */
zxid_mk_logout_resp(zxid_conf * cf,struct zx_sp_Status_s * st,struct zx_str * req_id)249 struct zx_sp_LogoutResponse_s* zxid_mk_logout_resp(zxid_conf* cf, struct zx_sp_Status_s* st, struct zx_str* req_id)
250 {
251 struct zx_sp_LogoutResponse_s* r = zx_NEW_sp_LogoutResponse(cf->ctx,0);
252 r->Issuer = zxid_my_issuer(cf, &r->gg);
253 r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "r", ZXID_ID_BITS);
254 r->Version = zx_ref_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION);
255 r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0));
256 if (req_id)
257 r->InResponseTo = zx_ref_len_attr(cf->ctx, &r->gg, zx_InResponseTo_ATTR, req_id->len, req_id->s);
258 zx_add_kid(&r->gg, &st->gg);
259 r->Status = st;
260 return r;
261 }
262
263 /*() Change SPNameID (newnym supplied), or Terminate federation (newnym not supplied).
264 * Create XML data structure for <ManageNameIDRequest> element. Low level API. */
265
266 /* Called by: a7n_test, zxid_sp_mni_redir, zxid_sp_mni_soap */
zxid_mk_mni(zxid_conf * cf,zxid_nid * nid,struct zx_str * new_nym,zxid_entity * idp_meta)267 struct zx_sp_ManageNameIDRequest_s* zxid_mk_mni(zxid_conf* cf, zxid_nid* nid, struct zx_str* new_nym, zxid_entity* idp_meta)
268 {
269 struct zx_str* ss;
270 struct zx_xenc_EncryptedKey_s* ek;
271 struct zx_elem_s* newid;
272 struct zx_sp_ManageNameIDRequest_s* r = zx_NEW_sp_ManageNameIDRequest(cf->ctx,0);
273 r->Issuer = zxid_my_issuer(cf, &r->gg);
274 r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "R", ZXID_ID_BITS);
275 r->Version = zx_ref_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION);
276 r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0));
277 if (cf->nameid_enc && idp_meta) {
278 r->EncryptedID = zxid_mk_enc_id(cf, &r->gg, nid, idp_meta);
279 if (new_nym && new_nym->len) {
280 newid = zx_new_str_elem(cf->ctx, 0, zx_sp_NewID_ELEM, new_nym);
281 ss = zx_easy_enc_elem_opt(cf, newid);
282 r->NewEncryptedID = zx_NEW_sp_NewEncryptedID(cf->ctx, &r->gg);
283 if (cf->enckey_opt & 0x20) {
284 /* Nested EncryptedKey approach (Shibboleth early 2010) */
285 ZX_ADD_KID(r->NewEncryptedID, EncryptedData, zxenc_pubkey_enc(cf, ss, 0, idp_meta->enc_cert, "43",0));
286 } else {
287 /* RetrievalMethod approach */
288 ZX_ADD_KID(r->NewEncryptedID, EncryptedData, zxenc_pubkey_enc(cf, ss, &ek, idp_meta->enc_cert, "39", idp_meta));
289 ZX_ADD_KID(r->NewEncryptedID, EncryptedKey, ek);
290 zx_reverse_elem_lists(&r->NewEncryptedID->gg);
291 }
292 zx_str_free(cf->ctx, ss);
293 zx_free_elem(cf->ctx, newid, 0);
294 } else
295 r->Terminate = zx_new_str_elem(cf->ctx, &r->gg, zx_sp_Terminate_ELEM, 0);
296 } else {
297 r->NameID = nid;
298 if (new_nym && new_nym->len)
299 r->NewID = zx_new_str_elem(cf->ctx, &r->gg, zx_sp_NewID_ELEM, new_nym);
300 else
301 r->Terminate = zx_new_str_elem(cf->ctx, &r->gg, zx_sp_Terminate_ELEM, 0);
302 }
303 return r;
304 }
305
306 /*() Create XML data structure for <ManageNameIDResponse> element. Low level API.*/
307
308 /* Called by: zxid_mni_do, zxid_mni_do_ss */
zxid_mk_mni_resp(zxid_conf * cf,struct zx_sp_Status_s * st,struct zx_str * req_id)309 struct zx_sp_ManageNameIDResponse_s* zxid_mk_mni_resp(zxid_conf* cf, struct zx_sp_Status_s* st, struct zx_str* req_id)
310 {
311 struct zx_sp_ManageNameIDResponse_s* r = zx_NEW_sp_ManageNameIDResponse(cf->ctx,0);
312 r->Issuer = zxid_my_issuer(cf, &r->gg);
313 r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "r", ZXID_ID_BITS);
314 r->Version = zx_ref_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION);
315 r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0));
316 if (req_id)
317 r->InResponseTo = zx_ref_len_attr(cf->ctx, &r->gg,zx_InResponseTo_ATTR, req_id->len,req_id->s);
318 zx_add_kid(&r->gg, &st->gg);
319 r->Status = st;
320 return r;
321 }
322
323 /* ======== IdP SSO Related ======== */
324
325 /*() Constructor for Assertion */
326
327 /* Called by: zxid_map_val_ss, zxid_mk_usr_a7n_to_sp, zxid_xacml_az_cd1_do x2, zxid_xacml_az_do x2 */
zxid_mk_a7n(zxid_conf * cf,struct zx_str * audience,struct zx_sa_Subject_s * subj,struct zx_sa_AuthnStatement_s * an_stmt,struct zx_sa_AttributeStatement_s * at_stmt)328 zxid_a7n* zxid_mk_a7n(zxid_conf* cf, struct zx_str* audience, struct zx_sa_Subject_s* subj, struct zx_sa_AuthnStatement_s* an_stmt, struct zx_sa_AttributeStatement_s* at_stmt)
329 {
330 zxid_a7n* a7n = zx_NEW_sa_Assertion(cf->ctx,0);
331 a7n->Version = zx_dup_attr(cf->ctx, &a7n->gg, zx_Version_ATTR, SAML2_VERSION);
332 a7n->ID = zxid_mk_id_attr(cf, &a7n->gg, zx_ID_ATTR, "A", ZXID_ID_BITS);
333 a7n->IssueInstant = zxid_date_time_attr(cf, &a7n->gg, zx_IssueInstant_ATTR, time(0));
334 a7n->Issuer = zxid_my_issuer(cf, &a7n->gg);
335 a7n->Subject = subj;
336 if (subj)
337 zx_add_kid(&a7n->gg, &subj->gg);
338 a7n->Conditions = zx_NEW_sa_Conditions(cf->ctx, &a7n->gg);
339 a7n->Conditions->NotOnOrAfter = zxid_date_time_attr(cf, &a7n->Conditions->gg, zx_NotOnOrAfter_ATTR, time(0) + cf->a7nttl);
340 a7n->Conditions->NotBefore = zxid_date_time_attr(cf, &a7n->Conditions->gg, zx_NotBefore_ATTR, time(0));
341 if (audience) {
342 a7n->Conditions->AudienceRestriction = zx_NEW_sa_AudienceRestriction(cf->ctx, &a7n->Conditions->gg);
343 a7n->Conditions->AudienceRestriction->Audience = zx_new_str_elem(cf->ctx, &a7n->Conditions->AudienceRestriction->gg, zx_sa_Audience_ELEM, audience);
344 }
345 a7n->AuthnStatement = an_stmt;
346 if (an_stmt)
347 zx_add_kid(&a7n->gg, &an_stmt->gg);
348 a7n->AttributeStatement = at_stmt;
349 if (at_stmt)
350 zx_add_kid(&a7n->gg, &at_stmt->gg);
351 zx_reverse_elem_lists(&a7n->gg);
352 return a7n;
353 }
354
355 /*() Construct Subject, possibly with EncryptedID */
356
357 /* Called by: zxid_map_val_ss, zxid_mk_usr_a7n_to_sp, zxid_xacml_az_cd1_do, zxid_xacml_az_do */
zxid_mk_subj(zxid_conf * cf,struct zx_elem_s * father,zxid_entity * sp_meta,zxid_nid * nid)358 struct zx_sa_Subject_s* zxid_mk_subj(zxid_conf* cf, struct zx_elem_s* father, zxid_entity* sp_meta, zxid_nid* nid)
359 {
360 struct zx_sa_Subject_s* subj = zx_NEW_sa_Subject(cf->ctx, father);
361
362 #if 0
363 // , struct zx_str* affil, char* fmt
364 nid = zx_NEW_sa_NameID(cf->ctx,0);
365 nid->SPNameQualifier = affil;
366 nid->NameQualifier = zxid_my_ent_id(cf);
367 nid->Format = zx_dup_str(cf->ctx, fmt); /* *** implement persistent */
368 if (!strcmp(fmt, SAML2_TRANSIENT_NID_FMT)) {
369 zx_add_content(cf->ctx, nid, zxid_mk_id(cf, "T", ZXID_ID_BITS));
370 } else {
371 /* *** see also zxid_get_user_nameid() */
372 }
373 #endif
374
375 if (cf->nameid_enc) {
376 if (sp_meta)
377 subj->EncryptedID = zxid_mk_enc_id(cf, &subj->gg, nid, sp_meta);
378 else {
379 ERR("NameID encryption configred, but no metadata supplied. Defaulting to unencrypted NameID %d", 0);
380 ZX_ADD_KID(subj, NameID, nid);
381 }
382 } else {
383 ZX_ADD_KID(subj, NameID, nid);
384 }
385 /* SAML spec is more lax than the schema: saml-core-2.0-os.pdf ll.653-657 says <SubjectConfirmation> [Zero or More] */
386 return subj;
387 }
388
389 /*() Construct AuthnStatement */
390
391 /* Called by: zxid_mk_usr_a7n_to_sp */
zxid_mk_an_stmt(zxid_conf * cf,zxid_ses * ses,struct zx_elem_s * father,const char * eid)392 struct zx_sa_AuthnStatement_s* zxid_mk_an_stmt(zxid_conf* cf, zxid_ses* ses, struct zx_elem_s* father, const char* eid)
393 {
394 struct zx_str sesix;
395 struct zx_str eid_ss;
396 struct zx_str* ss;
397 struct zx_sa_AuthnStatement_s* an_stmt = zx_NEW_sa_AuthnStatement(cf->ctx, father);
398 if (ses->sesix) {
399 #if 0
400 an_stmt->SessionIndex = zx_dup_str(cf->ctx, ses->sesix);
401 #else
402 /* Need noncorrelatable session index */
403 eid_ss.len = strlen(eid);
404 eid_ss.s = (char*)eid;
405 sesix.len = strlen(ses->sesix);
406 sesix.s = ses->sesix;
407 ss = zxid_psobj_enc(cf, &eid_ss, "ZS", &sesix);
408 an_stmt->SessionIndex = zx_ref_len_attr(cf->ctx, &an_stmt->gg, zx_SessionIndex_ATTR, ss->len, ss->s);
409 #endif
410 }
411 an_stmt->AuthnInstant = zxid_date_time_attr(cf, &an_stmt->gg, zx_AuthnInstant_ATTR, ses->an_instant);
412 an_stmt->AuthnContext = zx_NEW_sa_AuthnContext(cf->ctx, &an_stmt->gg);
413 if (ses->an_ctx)
414 an_stmt->AuthnContext->AuthnContextClassRef
415 = zx_dup_elem(cf->ctx, &an_stmt->AuthnContext->gg, zx_sa_AuthnContextClassRef_ELEM, ses->an_ctx);
416 else {
417 ERR("Session(%s) lacks AuthentContextClassRef. Output AuthnStatement will not satisfy all processing rules. See configuration option ISSUE_AUTHNCTX_PW.", ses->sesix);
418 }
419 return an_stmt;
420 }
421
422 /*() Construct SAML SAML Attribute from string */
423
424 /* Called by: zxid_add_mapped_attr, zxid_map_val_ss, zxid_mk_sa_attribute */
zxid_mk_sa_attribute_ss(zxid_conf * cf,struct zx_elem_s * father,const char * name,const char * namfmt,struct zx_str * val)425 struct zx_sa_Attribute_s* zxid_mk_sa_attribute_ss(zxid_conf* cf, struct zx_elem_s* father, const char* name, const char* namfmt, struct zx_str* val)
426 {
427 struct zx_root_s* r;
428 struct zx_sa_Attribute_s* at = zx_NEW_sa_Attribute(cf->ctx, father);
429 if (namfmt)
430 at->NameFormat = zx_ref_attr(cf->ctx, &at->gg, zx_NameFormat_ATTR, namfmt);
431 at->Name = zx_dup_attr(cf->ctx, &at->gg, zx_Name_ATTR, name);
432 at->AttributeValue = zx_NEW_sa_AttributeValue(cf->ctx, &at->gg);
433 if (!val)
434 return at;
435
436 if (val->s[0] == '<') {
437 /* Looks like the value may be XML data. We need to pass it as XML data structure for
438 * canonicalization to work right (e.g. value is an A7N that is rendered one
439 * way when canonicalized independently, but in different way when canonicalized
440 * as part of a bigger structure - for example sa namespace may be omitted as it
441 * is already supplied by the parent element). */
442 r = zx_dec_zx_root(cf->ctx, val->len, val->s, "sa at parse");
443 if (r && r->gg.kids) {
444 at->AttributeValue->gg.kids = r->gg.kids;
445 switch (r->gg.kids->g.tok) {
446 case zx_sa_Assertion_ELEM: at->AttributeValue->Assertion = (void*)r->gg.kids; break;
447 case zx_sa_EncryptedAssertion_ELEM: at->AttributeValue->EncryptedAssertion = (void*)r->gg.kids; break;
448 case zx_di12_ResourceOffering_ELEM: at->AttributeValue->ResourceOffering = (void*)r->gg.kids; break;
449 case zx_a_EndpointReference_ELEM: at->AttributeValue->EndpointReference = (void*)r->gg.kids; break;
450 }
451 ZX_FREE(cf->ctx, r);
452 } else {
453 /* XML did not parse, may be its just string data, after all. */
454 zx_add_content(cf->ctx, &at->AttributeValue->gg, val);
455 }
456 } else {
457 zx_add_content(cf->ctx, &at->AttributeValue->gg, val);
458 }
459 return at;
460 }
461
462 /*() Construct SAML SAML Attribute */
463
464 /* Called by: zxid_gen_boots, zxid_mk_usr_a7n_to_sp x2 */
zxid_mk_sa_attribute(zxid_conf * cf,struct zx_elem_s * father,const char * name,const char * namfmt,const char * val)465 struct zx_sa_Attribute_s* zxid_mk_sa_attribute(zxid_conf* cf, struct zx_elem_s* father, const char* name, const char* namfmt, const char* val)
466 {
467 return zxid_mk_sa_attribute_ss(cf, father, name, namfmt, val?zx_dup_str(cf->ctx, val):0);
468 }
469
470 /*() Construct SAML protocol Response (such as may be used to carry assertion in SSO) */
471
472 /* Called by: zxid_idp_sso x4, zxid_ssos_anreq, zxid_xacml_az_cd1_do x2, zxid_xacml_az_do x2 */
zxid_mk_saml_resp(zxid_conf * cf,zxid_a7n * a7n,zxid_entity * enc_meta)473 struct zx_sp_Response_s* zxid_mk_saml_resp(zxid_conf* cf, zxid_a7n* a7n, zxid_entity* enc_meta)
474 {
475 struct zx_sp_Response_s* r = zx_NEW_sp_Response(cf->ctx,0);
476 r->Version = zx_dup_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION);
477 r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "R", ZXID_ID_BITS);
478 r->Issuer = zxid_my_issuer(cf, &r->gg);
479 r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0));
480 r->Status = zxid_OK(cf, &r->gg);
481 if (a7n) {
482 if (enc_meta) {
483 /* See saml-bindings-2.0-os.pdf, sec 3.5.5.2 Security Considerations, p.24, ll.847-851
484 * After publication it was understood that the SHOULD NOT could be eliminated
485 * if EncryptedAssertion is used. */
486
487 r->EncryptedAssertion = zxid_mk_enc_a7n(cf, &r->gg, a7n, enc_meta);
488 } else {
489 r->Assertion = a7n;
490 zx_add_kid(&r->gg, &a7n->gg);
491 }
492 }
493 zx_reverse_elem_lists(&r->gg);
494 return r;
495 }
496
497 /*() Construct XACML Response */
498
499 /* Called by: zxid_ins_xacml_az_cd1_stmt x2, zxid_ins_xacml_az_stmt x2 */
zxid_mk_xacml_resp(zxid_conf * cf,char * decision)500 struct zx_xac_Response_s* zxid_mk_xacml_resp(zxid_conf* cf, char* decision)
501 {
502 struct zx_xac_Response_s* resp = zx_NEW_xac_Response(cf->ctx,0);
503 resp->Result = zx_NEW_xac_Result(cf->ctx, &resp->gg);
504 resp->Result->Decision = zx_ref_elem(cf->ctx, &resp->Result->gg, zx_xac_Decision_ELEM, decision);
505 resp->Result->Status = zx_NEW_xac_Status(cf->ctx, &resp->Result->gg);
506 resp->Result->Status->StatusCode = zx_NEW_xac_StatusCode(cf->ctx, &resp->Result->Status->gg);
507 resp->Result->Status->StatusCode->Value
508 = zx_ref_attr(cf->ctx, &resp->Result->Status->StatusCode->gg, zx_Value_ATTR, "urn:oasis:names:tc:xacml:1.0:status:ok");
509 zx_reverse_elem_lists(&resp->Result->gg);
510 return resp;
511 }
512
513 /*() Low level constructor for simple XACML attribute (see the
514 * source to understand how "simple" they are). */
515
516 /* Called by: zxid_call_trustpdp x6, zxid_pepmap_extract x3 */
zxid_mk_xacml_simple_at(zxid_conf * cf,struct zx_elem_s * father,struct zx_str * atid,struct zx_str * attype,struct zx_str * atissuer,struct zx_str * atvalue)517 struct zx_xac_Attribute_s* zxid_mk_xacml_simple_at(zxid_conf* cf, struct zx_elem_s* father, struct zx_str* atid, struct zx_str* attype, struct zx_str* atissuer, struct zx_str* atvalue)
518 {
519 struct zx_root_s* r;
520 struct zx_xac_Attribute_s* at = zx_NEW_xac_Attribute(cf->ctx, father);
521 at->AttributeId = zx_ref_len_attr(cf->ctx, &at->gg, zx_AttributeId_ATTR, atid->len, atid->s);
522 at->DataType = zx_ref_len_attr(cf->ctx, &at->gg, zx_DataType_ATTR, attype->len, attype->s);
523 if (atissuer)
524 at->Issuer = zx_ref_len_attr(cf->ctx, &at->gg, zx_Issuer_ATTR, atissuer->len, atissuer->s);
525 if (atvalue->s[0] == '<') {
526 /* Looks like the value may be XML data. We need to pass it as XML data structure for
527 * canonicalization to work right (e.g. value is an A7N that is rendered one
528 * way when canonicalized independently, but in different way when canonicalized
529 * as part of a bigger structure - for example sa namespace may be omitted as it
530 * is already supplied by the parent element). */
531 r = zx_dec_zx_root(cf->ctx, atvalue->len, atvalue->s, "xac at parse");
532 if (r && r->gg.kids) {
533 at->AttributeValue = zx_new_elem(cf->ctx, &at->gg, zx_xac_AttributeValue_ELEM);
534 at->AttributeValue->kids = r->gg.kids;
535 ZX_FREE(cf->ctx, r);
536 } else {
537 /* XML did not parse, may be its just string data, after all. */
538 at->AttributeValue = zx_new_str_elem(cf->ctx, &at->gg, zx_xac_AttributeValue_ELEM, atvalue);
539 }
540 } else {
541 at->AttributeValue = zx_new_str_elem(cf->ctx, &at->gg, zx_xac_AttributeValue_ELEM, atvalue);
542 }
543 zx_reverse_elem_lists(&at->gg);
544 return at;
545 }
546
547 /*() Construct xac_Request */
548
549 /* Called by: zxid_az_soap, zxid_mk_az, zxid_mk_az_cd1 */
zxid_mk_xac_az(zxid_conf * cf,struct zx_elem_s * father,struct zx_xac_Attribute_s * subj,struct zx_xac_Attribute_s * rsrc,struct zx_xac_Attribute_s * act,struct zx_xac_Attribute_s * env)550 struct zx_xac_Request_s* zxid_mk_xac_az(zxid_conf* cf, struct zx_elem_s* father, struct zx_xac_Attribute_s* subj, struct zx_xac_Attribute_s* rsrc, struct zx_xac_Attribute_s* act, struct zx_xac_Attribute_s* env)
551 {
552 struct zx_xac_Request_s* r = zx_NEW_xac_Request(cf->ctx, father);
553 /* N.B. The lists are already linked and only need to be attached to kids lists. */
554 r->Subject = zx_NEW_xac_Subject(cf->ctx, &r->gg);
555 r->Subject->gg.kids = (struct zx_elem_s*)(r->Subject->Attribute = subj);
556
557 r->Resource = zx_NEW_xac_Resource(cf->ctx, &r->gg);
558 r->Resource->gg.kids = (struct zx_elem_s*)(r->Resource->Attribute = rsrc);
559
560 r->Action = zx_NEW_xac_Action(cf->ctx, &r->gg);
561 r->Action->gg.kids = (struct zx_elem_s*)(r->Action->Attribute = act);
562
563 r->Environment = zx_NEW_xac_Environment(cf->ctx, &r->gg);
564 r->Environment->gg.kids = (struct zx_elem_s*)(r->Environment->Attribute = env);
565
566 zx_reverse_elem_lists(&r->gg);
567 return r;
568 }
569
570 /*() Construct XACMLAuthzDecisionQuery */
571
572 /* Called by: attribute_sort_test, zxid_az_soap */
zxid_mk_az(zxid_conf * cf,struct zx_xac_Attribute_s * subj,struct zx_xac_Attribute_s * rsrc,struct zx_xac_Attribute_s * act,struct zx_xac_Attribute_s * env)573 struct zx_xasp_XACMLAuthzDecisionQuery_s* zxid_mk_az(zxid_conf* cf, struct zx_xac_Attribute_s* subj, struct zx_xac_Attribute_s* rsrc, struct zx_xac_Attribute_s* act, struct zx_xac_Attribute_s* env)
574 {
575 struct zx_xasp_XACMLAuthzDecisionQuery_s* r = zx_NEW_xasp_XACMLAuthzDecisionQuery(cf->ctx,0);
576 r->Issuer = zxid_my_issuer(cf, &r->gg);
577 r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "R", ZXID_ID_BITS);
578 r->Version = zx_ref_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION);
579 r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0));
580 r->Request = zxid_mk_xac_az(cf, &r->gg, subj, rsrc, act, env);
581 zx_reverse_elem_lists(&r->gg);
582 return r;
583 }
584
585 /*() Construct XACMLAuthzDecisionQuery according to Commitee Draft 1 */
586
587 /* Called by: attribute_sort_test, zxid_az_soap */
zxid_mk_az_cd1(zxid_conf * cf,struct zx_xac_Attribute_s * subj,struct zx_xac_Attribute_s * rsrc,struct zx_xac_Attribute_s * act,struct zx_xac_Attribute_s * env)588 struct zx_xaspcd1_XACMLAuthzDecisionQuery_s* zxid_mk_az_cd1(zxid_conf* cf, struct zx_xac_Attribute_s* subj, struct zx_xac_Attribute_s* rsrc, struct zx_xac_Attribute_s* act, struct zx_xac_Attribute_s* env)
589 {
590 struct zx_xaspcd1_XACMLAuthzDecisionQuery_s* r = zx_NEW_xaspcd1_XACMLAuthzDecisionQuery(cf->ctx,0);
591 r->Issuer = zxid_my_issuer(cf, &r->gg);
592 r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "R", ZXID_ID_BITS);
593 r->Version = zx_ref_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION);
594 r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0));
595 r->Request = zxid_mk_xac_az(cf, &r->gg, subj, rsrc, act, env);
596 zx_reverse_elem_lists(&r->gg);
597 return r;
598 }
599
600 /* EOF -- zxidmk.c */
601