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