/* Called by: zxid_map_val_ss, zxid_mk_usr_a7n_to_sp, zxid_xacml_az_cd1_do, zxid_xacml_az_do */ struct zx_sa_Subject_s* zxid_mk_subj(zxid_conf* cf, struct zx_elem_s* father, zxid_entity* sp_meta, zxid_nid* nid) { struct zx_sa_Subject_s* subj = zx_NEW_sa_Subject(cf->ctx, father); #if 0 // , struct zx_str* affil, char* fmt nid = zx_NEW_sa_NameID(cf->ctx,0); nid->SPNameQualifier = affil; nid->NameQualifier = zxid_my_ent_id(cf); nid->Format = zx_dup_str(cf->ctx, fmt); /* *** implement persistent */ if (!strcmp(fmt, SAML2_TRANSIENT_NID_FMT)) { zx_add_content(cf->ctx, nid, zxid_mk_id(cf, "T", ZXID_ID_BITS)); } else { /* *** see also zxid_get_user_nameid() */ } #endif if (cf->nameid_enc) { if (sp_meta) subj->EncryptedID = zxid_mk_enc_id(cf, &subj->gg, nid, sp_meta); else { ERR("NameID encryption configred, but no metadata supplied. Defaulting to unencrypted NameID %d", 0); ZX_ADD_KID(subj, NameID, nid); } } else { ZX_ADD_KID(subj, NameID, nid); } /* SAML spec is more lax than the schema: saml-core-2.0-os.pdf ll.653-657 says <SubjectConfirmation> [Zero or More] */ return subj; }
/* Called by: zxid_add_fed_tok2epr, zxid_imreq, zxid_mk_saml_resp */ struct zx_sa_EncryptedAssertion_s* zxid_mk_enc_a7n(zxid_conf* cf, struct zx_elem_s* father, zxid_a7n* a7n, zxid_entity* meta) { struct zx_xenc_EncryptedData_s* ed; struct zx_str* ss; struct zx_sa_EncryptedAssertion_s* enc_a7n; if (!cf || !a7n) { ERR("NULL arguments (programmer error) %p", cf); return 0; } if (!meta || !meta->enc_cert) { ERR("Missing destination metadata or the metadata does not have encryption certificate. %p", meta); return 0; } ss = zx_easy_enc_elem_opt(cf, &a7n->gg); if (!ss) { ERR("Failed to XML serialize assertion %p", a7n); return 0; } enc_a7n = zx_NEW_sa_EncryptedAssertion(cf->ctx, father); if (cf->enckey_opt & 0x20) { /* Nested EncryptedKey approach (Shibboleth early 2010) */ ed = zxenc_pubkey_enc(cf, ss, 0, meta->enc_cert, "40", 0); } else { /* RetrievalMethod approach */ ed = zxenc_pubkey_enc(cf, ss, &enc_a7n->EncryptedKey, meta->enc_cert, "39", meta); } if (!ed) { 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); return 0; } ZX_ADD_KID(enc_a7n, EncryptedData, ed); zx_str_free(cf->ctx, ss); return enc_a7n; }
/* Called by: a7n_test, zxid_sp_mni_redir, zxid_sp_mni_soap */ struct zx_sp_ManageNameIDRequest_s* zxid_mk_mni(zxid_conf* cf, zxid_nid* nid, struct zx_str* new_nym, zxid_entity* idp_meta) { struct zx_str* ss; struct zx_xenc_EncryptedKey_s* ek; struct zx_elem_s* newid; struct zx_sp_ManageNameIDRequest_s* r = zx_NEW_sp_ManageNameIDRequest(cf->ctx,0); r->Issuer = zxid_my_issuer(cf, &r->gg); r->ID = zxid_mk_id_attr(cf, &r->gg, zx_ID_ATTR, "R", ZXID_ID_BITS); r->Version = zx_ref_attr(cf->ctx, &r->gg, zx_Version_ATTR, SAML2_VERSION); r->IssueInstant = zxid_date_time_attr(cf, &r->gg, zx_IssueInstant_ATTR, time(0)); if (cf->nameid_enc && idp_meta) { r->EncryptedID = zxid_mk_enc_id(cf, &r->gg, nid, idp_meta); if (new_nym && new_nym->len) { newid = zx_new_str_elem(cf->ctx, 0, zx_sp_NewID_ELEM, new_nym); ss = zx_easy_enc_elem_opt(cf, newid); r->NewEncryptedID = zx_NEW_sp_NewEncryptedID(cf->ctx, &r->gg); if (cf->enckey_opt & 0x20) { /* Nested EncryptedKey approach (Shibboleth early 2010) */ ZX_ADD_KID(r->NewEncryptedID, EncryptedData, zxenc_pubkey_enc(cf, ss, 0, idp_meta->enc_cert, "43",0)); } else { /* RetrievalMethod approach */ ZX_ADD_KID(r->NewEncryptedID, EncryptedData, zxenc_pubkey_enc(cf, ss, &ek, idp_meta->enc_cert, "39", idp_meta)); ZX_ADD_KID(r->NewEncryptedID, EncryptedKey, ek); zx_reverse_elem_lists(&r->NewEncryptedID->gg); } zx_str_free(cf->ctx, ss); zx_free_elem(cf->ctx, newid, 0); } else r->Terminate = zx_new_str_elem(cf->ctx, &r->gg, zx_sp_Terminate_ELEM, 0); } else { r->NameID = nid; if (new_nym && new_nym->len) r->NewID = zx_new_str_elem(cf->ctx, &r->gg, zx_sp_NewID_ELEM, new_nym); else r->Terminate = zx_new_str_elem(cf->ctx, &r->gg, zx_sp_Terminate_ELEM, 0); } return r; }
/* Called by: zxid_idp_soap_dispatch x2, zxid_sp_soap_dispatch x8 */ int zxid_soap_cgi_resp_body(zxid_conf* cf, zxid_ses* ses, struct zx_e_Body_s* body) { struct zx_e_Envelope_s* env = zx_NEW_e_Envelope(cf->ctx,0); struct zx_str* ss; struct zx_str* logpath; env->Body = body; zx_add_kid(&env->gg, &body->gg); env->Header = zx_NEW_e_Header(cf->ctx, &env->gg); if (ses && ses->curflt) { D("Detected curflt, abandoning previous Body content. %d", 0); /* *** LEAK: Should free previous body content */ env->Body = (struct zx_e_Body_s*)zx_replace_kid(&env->gg, (struct zx_elem_s*)zx_NEW_e_Body(cf->ctx, 0)); ZX_ADD_KID(env->Body, Fault, ses->curflt); } zxid_wsf_decor(cf, ses, env, 1, 0); ss = zx_easy_enc_elem_opt(cf, &env->gg); if (cf->log_issue_msg) { logpath = zxlog_path(cf, ses->issuer, ss, ZXLOG_ISSUE_DIR, ZXLOG_WIR_KIND, 1); if (logpath) { if (zxlog_dup_check(cf, logpath, "cgi_resp")) { ERR("Duplicate wire msg(%.*s) (Simple Sign)", ss->len, ss->s); #if 0 if (cf->dup_msg_fatal) { ERR("FATAL (by configuration): Duplicate wire msg(%.*s) (cgi_resp)", ss->len, ss->s); zxlog_blob(cf, 1, logpath, ss, "cgi_resp dup"); zx_str_free(cf->ctx, logpath); return 0; } #endif } zxlog_blob(cf, 1, logpath, ss, "cgi_resp"); zxlogwsp(cf, ses, "K", "CGIRESP", 0, "logpath(%.*s)", logpath->len, logpath->s); zx_str_free(cf->ctx, logpath); } } if (errmac_debug & ERRMAC_INOUT) INFO("SOAP_RESP(%.*s)", ss->len, ss->s); fprintf(stdout, "CONTENT-TYPE: text/xml" CRLF "CONTENT-LENGTH: %d" CRLF2 "%.*s", ss->len, ss->len, ss->s); fflush(stdout); D("^^^^^^^^^^^^^^ Done (%d chars returned) ^^^^^^^^^^^^^", ss->len); return ZXID_REDIR_OK; }
/* Called by: zxid_call_epr, zxid_wsc_prepare_call, zxid_wsc_valid_resp, zxid_wsp_decorate */ struct zx_e_Envelope_s* zxid_add_env_if_needed(zxid_conf* cf, const char* enve) { struct zx_e_Envelope_s* env; struct zx_root_s* r; struct zx_str* ret; r = zx_dec_zx_root(cf->ctx, strlen(enve), enve, "add_env"); if (!r) { ERR("Malformed XML enve(%s)", enve); return 0; } /* N.B. The lists are in reverse order after the parse. */ env = r->Envelope; if (env) { /* N.B. Maintain the forward order, Header is 1st element of Envelope->kids. */ if (!env->Header) { D("ENV EXISTS, no Header %p %p", env, env->Body); if (!env->Body) env->Body = zx_NEW_e_Body(cf->ctx, &env->gg); env->Header = zx_NEW_e_Header(cf->ctx, &env->gg); } else { D("ENV EXISTS w/Header %p %p", env, env->Body); if (!env->Body) env->Body = zx_NEW_e_Body(cf->ctx, &env->gg); } } else if (r->Body) { D("HERE2 BODY EXISTS %p %p", env, r->Header); env = zx_NEW_e_Envelope(cf->ctx,0); ZX_ADD_KID(env, Body, r->Body); if (r->Header) ZX_ADD_KID(env, Header, r->Header); else env->Header = zx_NEW_e_Header(cf->ctx, &env->gg); /* N.B. Maintain the Forward order: Header is now first element of Envelope->kids. */ } else { /* Resort to stringwise attempt to add envelope. */ ZX_FREE(cf->ctx, r); if (!memcmp(enve, "<?xml ", sizeof("<?xml ")-1)) { /* Ignore common, but unnecessary decl. */ for (enve += sizeof("<?xml "); *enve && !(enve[0] == '?' && enve[1] == '>'); ++enve) ; if (*enve) enve += 2; } /* Must be just payload */ enve = zx_alloc_sprintf(cf->ctx, 0, "%s%s%s", zx_env_body_open, enve, zx_env_body_close); D("HERE3 ADD ENV(%s)", enve); r = zx_dec_zx_root(cf->ctx, strlen(enve), enve, "add_env2"); if (!r) { ERR("Malformed XML enve(%s)", enve); return 0; } env = r->Envelope; #if 0 ret=zx_easy_enc_elem_opt(cf,&env->gg); INFO("ser(%.*s) enve(%s)",ret->len,ret->s,enve); // *** /* The lists are in reverse order after the parse. But since this is a text parse, * wireorder is maintained, thus giving forward order, afterall. */ zx_reverse_elem_lists(&env->gg); #endif } ZX_FREE(cf->ctx, r); if (env->gg.kids != &env->Header->gg) { D("ENV Fixing Header-Body ordering %p", env); env->gg.kids = &env->Header->gg; env->Header->gg.g.n = &env->Body->gg.g; env->Body->gg.g.n = 0; } ret = zx_easy_enc_elem_opt(cf,&env->gg); INFO("ser(%.*s) enve(%s)",ret->len,ret->s,enve); // *** if (!env) ERR("No <e:Envelope> found in input argument. enve(%s)", enve); /* DO NOT: zx_reverse_elem_lists(&env->gg); * ensure forward order for external use */ return env; }
/* Called by: zxid_wsc_call, zxid_wsc_prepare_call */ static int zxid_wsc_prep(zxid_conf* cf, zxid_ses* ses, zxid_epr* epr, struct zx_e_Envelope_s* env) { zxid_tok* tok; struct zx_e_Header_s* hdr; if (!zxid_wsf_decor(cf, ses, env, 0, epr)) return 0; hdr = env->Header; /* 6.rq: ReplyTo (optional) */ if (cf->wsc_replyto_hdr && strcmp(cf->wsc_replyto_hdr, "#inhibit")) { /* Mandatory for a request (says who? - apparenly AXIS2 or WSO2 has a bug of * requiring this and not understanding to default it to anon). * liberty-idwsf-soap-binding-2.0-errata-v1.0.pdf * p.21 ll.591-595 seem to imply that ReplyTo can be omitted if value would be A_ANON. */ hdr->ReplyTo = zx_NEW_a_ReplyTo(cf->ctx, &hdr->gg); /*hdr->ReplyTo->Address = zxid_mk_addr(cf, zx_strf(cf->ctx, "%s?o=P", cf->burl));*/ if (!strcmp(cf->wsc_replyto_hdr, "#anon")) { hdr->ReplyTo->Address = zxid_mk_addr(cf, &hdr->ReplyTo->gg, zx_dup_str(cf->ctx, A_ANON)); } else if (!strcmp(cf->wsc_replyto_hdr, "#anon_2005_03")) { hdr->ReplyTo->Address = zxid_mk_addr(cf, &hdr->ReplyTo->gg, zx_dup_str(cf->ctx, A_ANON_2005_03)); } else { hdr->ReplyTo->Address = zxid_mk_addr(cf, &hdr->ReplyTo->gg, zx_dup_str(cf->ctx, cf->wsc_replyto_hdr)); } hdr->ReplyTo->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->ReplyTo->gg, zx_e_mustUnderstand_ATTR, XML_TRUE); hdr->ReplyTo->actor = zx_ref_attr(cf->ctx, &hdr->ReplyTo->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT); } #if 0 /* Omission means to use same address as ReplyTo */ hdr->FaultTo = zx_NEW_a_FaultTo(cf->ctx, &hdr->gg); hdr->FaultTo->Address = zx_mk_addr(cf->ctx, &hdr->FaultTo->gg, zx_strf(cf->ctx, "%s?o=P", cf->burl)); hdr->FaultTo->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->FaultTo->gg, zx_e_mustUnderstand_ATTR, XML_TRUE); hdr->FaultTo->actor = zx_ref_attr(cf->ctx, &hdr->FaultTo->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT); #endif if (ses->call_tgttok || ses->call_invoktok && epr && epr->Metadata && epr->Metadata->SecurityContext && epr->Metadata->SecurityContext->Token) { /* 9.rq: Target Identity */ if (ses->call_tgttok) { D("TargetIdentity: Explicit specification of ses->call_tgttok %d",0); tok = ses->call_tgttok; } else { D("TargetIdentity: Using token from EPR due to specification of ses->call_invoktok %d",0); tok = epr->Metadata->SecurityContext->Token; } hdr->TargetIdentity = zx_NEW_b_TargetIdentity(cf->ctx, &hdr->gg); hdr->TargetIdentity->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->TargetIdentity->gg, zx_e_mustUnderstand_ATTR, XML_TRUE); hdr->TargetIdentity->actor = zx_ref_attr(cf->ctx, &hdr->TargetIdentity->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT); if (tok->EncryptedAssertion) { ZX_ADD_KID(hdr->TargetIdentity, EncryptedAssertion, tok->EncryptedAssertion); } else if (tok->Assertion) { ZX_ADD_KID(hdr->TargetIdentity, Assertion, tok->Assertion); } else { ERR("No <sa:EncryptedAssertion> or <sa:Assertion> found in <sec:Token> %p", tok); } } /* else this is just implied by the sec mech */ /* 10. UsageDirective */ zxid_attach_sol1_usage_directive(cf, ses, env, TAS3_PLEDGE, cf->wsc_localpdp_obl_pledge); zx_reverse_elem_lists(&hdr->gg); return 1; }