Line | Count | Source |
1 | | /** |
2 | | * XML Security Library (http://www.aleksey.com/xmlsec). |
3 | | * |
4 | | * This is free software; see the Copyright file in the source distribution for precise wording. |
5 | | * |
6 | | * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. |
7 | | */ |
8 | | /** |
9 | | * @addtogroup xmlsec_core_transforms |
10 | | * @brief XPath transform implementation. |
11 | | */ |
12 | | #include "globals.h" |
13 | | |
14 | | #include <stdlib.h> |
15 | | #include <string.h> |
16 | | |
17 | | #include <libxml/tree.h> |
18 | | #include <libxml/xpath.h> |
19 | | #include <libxml/xpathInternals.h> |
20 | | #include <libxml/xpointer.h> |
21 | | |
22 | | #include <xmlsec/xmlsec.h> |
23 | | #include <xmlsec/xmltree.h> |
24 | | #include <xmlsec/keys.h> |
25 | | #include <xmlsec/list.h> |
26 | | #include <xmlsec/transforms.h> |
27 | | #include <xmlsec/errors.h> |
28 | | |
29 | | #include "cast_helpers.h" |
30 | | |
31 | | /** |
32 | | * @brief Implements the XPath here() function. |
33 | | * @details The implementation of XPath "here()" function. |
34 | | * See xmlXPtrHereFunction() in xpointer.c. the only change is that |
35 | | * we return NodeSet instead of NodeInterval. |
36 | | * @param ctxt the pointer to XPath context. |
37 | | * @param nargs the arguments number. |
38 | | */ |
39 | | static void |
40 | 0 | xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
41 | 0 | xmlXPathObjectPtr obj; |
42 | |
|
43 | 0 | CHECK_ARITY(0); |
44 | |
|
45 | 0 | if((ctxt == NULL) || (ctxt->context == NULL) || (ctxt->context->here == NULL)) { |
46 | 0 | XP_ERROR(XPTR_SYNTAX_ERROR); |
47 | 0 | } |
48 | 0 | obj = xmlXPathNewNodeSet(ctxt->context->here); |
49 | 0 | if(obj == NULL) { |
50 | 0 | XP_ERROR(XPATH_MEMORY_ERROR); |
51 | 0 | } |
52 | 0 | valuePush(ctxt, obj); |
53 | 0 | } |
54 | | |
55 | | /****************************************************************************** |
56 | | * |
57 | | * XPath/XPointer data |
58 | | * |
59 | | *****************************************************************************/ |
60 | | typedef struct _xmlSecXPathData xmlSecXPathData, |
61 | | *xmlSecXPathDataPtr; |
62 | | typedef enum { |
63 | | xmlSecXPathDataTypeXPath, |
64 | | xmlSecXPathDataTypeXPath2, |
65 | | xmlSecXPathDataTypeXPointer |
66 | | } xmlSecXPathDataType; |
67 | | |
68 | | struct _xmlSecXPathData { |
69 | | xmlSecXPathDataType type; |
70 | | xmlXPathContextPtr ctx; |
71 | | xmlChar* expr; |
72 | | xmlSecNodeSetOp nodeSetOp; |
73 | | xmlSecNodeSetType nodeSetType; |
74 | | }; |
75 | | |
76 | | static xmlSecXPathDataPtr xmlSecXPathDataCreate (xmlSecXPathDataType type); |
77 | | static void xmlSecXPathDataDestroy (xmlSecXPathDataPtr data); |
78 | | static int xmlSecXPathDataSetExpr (xmlSecXPathDataPtr data, |
79 | | const xmlChar* expr); |
80 | | static int xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, |
81 | | xmlNodePtr node); |
82 | | static int xmlSecXPathDataNodeRead (xmlSecXPathDataPtr data, |
83 | | xmlNodePtr node); |
84 | | static xmlSecNodeSetPtr xmlSecXPathDataExecute (xmlSecXPathDataPtr data, |
85 | | xmlDocPtr doc, |
86 | | xmlNodePtr hereNode); |
87 | | |
88 | | static xmlSecXPathDataPtr |
89 | 6.48k | xmlSecXPathDataCreate(xmlSecXPathDataType type) { |
90 | 6.48k | xmlSecXPathDataPtr data; |
91 | | |
92 | 6.48k | data = (xmlSecXPathDataPtr) xmlMalloc(sizeof(xmlSecXPathData)); |
93 | 6.48k | if(data == NULL) { |
94 | 0 | xmlSecMallocError(sizeof(xmlSecXPathData), NULL); |
95 | 0 | return(NULL); |
96 | 0 | } |
97 | 6.48k | memset(data, 0, sizeof(xmlSecXPathData)); |
98 | | |
99 | 6.48k | data->type = type; |
100 | 6.48k | data->nodeSetType = xmlSecNodeSetTree; |
101 | | |
102 | | /* create xpath or xpointer context */ |
103 | 6.48k | switch(data->type) { |
104 | 0 | case xmlSecXPathDataTypeXPath: |
105 | 0 | case xmlSecXPathDataTypeXPath2: |
106 | 0 | data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */ |
107 | 0 | if(data->ctx == NULL) { |
108 | 0 | xmlSecXmlError("xmlXPathNewContext", NULL); |
109 | 0 | xmlSecXPathDataDestroy(data); |
110 | 0 | return(NULL); |
111 | 0 | } |
112 | 0 | break; |
113 | 6.48k | case xmlSecXPathDataTypeXPointer: |
114 | 6.48k | data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */ |
115 | 6.48k | if(data->ctx == NULL) { |
116 | 0 | xmlSecXmlError("xmlXPathNewContext", NULL); |
117 | 0 | xmlSecXPathDataDestroy(data); |
118 | 0 | return(NULL); |
119 | 0 | } |
120 | 6.48k | break; |
121 | 6.48k | } |
122 | | |
123 | 6.48k | return(data); |
124 | 6.48k | } |
125 | | |
126 | | static void |
127 | 6.48k | xmlSecXPathDataDestroy(xmlSecXPathDataPtr data) { |
128 | 6.48k | xmlSecAssert(data != NULL); |
129 | | |
130 | 6.48k | if(data->expr != NULL) { |
131 | 6.48k | xmlFree(data->expr); |
132 | 6.48k | } |
133 | 6.48k | if(data->ctx != NULL) { |
134 | 6.48k | xmlXPathFreeContext(data->ctx); |
135 | 6.48k | } |
136 | 6.48k | memset(data, 0, sizeof(xmlSecXPathData)); |
137 | 6.48k | xmlFree(data); |
138 | 6.48k | } |
139 | | |
140 | | static int |
141 | 6.48k | xmlSecXPathDataSetExpr(xmlSecXPathDataPtr data, const xmlChar* expr) { |
142 | 6.48k | xmlSecAssert2(data != NULL, -1); |
143 | 6.48k | xmlSecAssert2(data->expr == NULL, -1); |
144 | 6.48k | xmlSecAssert2(data->ctx != NULL, -1); |
145 | 6.48k | xmlSecAssert2(expr != NULL, -1); |
146 | | |
147 | 6.48k | data->expr = xmlStrdup(expr); |
148 | 6.48k | if(data->expr == NULL) { |
149 | 0 | xmlSecStrdupError(expr, NULL); |
150 | 0 | return(-1); |
151 | 0 | } |
152 | 6.48k | return(0); |
153 | 6.48k | } |
154 | | |
155 | | |
156 | | static int |
157 | 6.48k | xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, xmlNodePtr node) { |
158 | 6.48k | xmlNodePtr cur; |
159 | 6.48k | xmlNsPtr ns; |
160 | 6.48k | int ret; |
161 | | |
162 | 6.48k | xmlSecAssert2(data != NULL, -1); |
163 | 6.48k | xmlSecAssert2(data->ctx != NULL, -1); |
164 | 6.48k | xmlSecAssert2(node != NULL, -1); |
165 | | |
166 | | /* register namespaces */ |
167 | 34.3k | for(cur = node; cur != NULL; cur = cur->parent) { |
168 | 40.8k | for(ns = cur->nsDef; ns != NULL; ns = ns->next) { |
169 | | /* check that we have no other namespace with same prefix already */ |
170 | 12.9k | if((ns->prefix != NULL) && (xmlXPathNsLookup(data->ctx, ns->prefix) == NULL)){ |
171 | 165 | ret = xmlXPathRegisterNs(data->ctx, ns->prefix, ns->href); |
172 | 165 | if(ret != 0) { |
173 | 0 | xmlSecXmlError2("xmlXPathRegisterNs", NULL, |
174 | 0 | "prefix=%s", xmlSecErrorsSafeString(ns->prefix)); |
175 | 0 | return(-1); |
176 | 0 | } |
177 | 165 | } |
178 | 12.9k | } |
179 | 27.8k | } |
180 | | |
181 | 6.48k | return(0); |
182 | 6.48k | } |
183 | | |
184 | | static int |
185 | 0 | xmlSecXPathDataNodeRead(xmlSecXPathDataPtr data, xmlNodePtr node) { |
186 | 0 | int ret; |
187 | |
|
188 | 0 | xmlSecAssert2(data != NULL, -1); |
189 | 0 | xmlSecAssert2(data->expr == NULL, -1); |
190 | 0 | xmlSecAssert2(data->ctx != NULL, -1); |
191 | 0 | xmlSecAssert2(node != NULL, -1); |
192 | |
|
193 | 0 | ret = xmlSecXPathDataRegisterNamespaces (data, node); |
194 | 0 | if(ret < 0) { |
195 | 0 | xmlSecInternalError("xmlSecXPathDataRegisterNamespaces", NULL); |
196 | 0 | return(-1); |
197 | 0 | } |
198 | | |
199 | | /* read node content and set expr */ |
200 | 0 | data->expr = xmlNodeGetContent(node); |
201 | 0 | if(data->expr == NULL) { |
202 | 0 | xmlSecInvalidNodeContentError(node, NULL, "empty"); |
203 | 0 | return(-1); |
204 | 0 | } |
205 | | |
206 | 0 | return(0); |
207 | 0 | } |
208 | | |
209 | | static xmlSecNodeSetPtr |
210 | 6.48k | xmlSecXPathDataExecute(xmlSecXPathDataPtr data, xmlDocPtr doc, xmlNodePtr hereNode) { |
211 | 6.48k | xmlXPathObjectPtr xpathObj = NULL; |
212 | 6.48k | xmlSecNodeSetPtr nodes; |
213 | | |
214 | 6.48k | xmlSecAssert2(data != NULL, NULL); |
215 | 6.48k | xmlSecAssert2(data->expr != NULL, NULL); |
216 | 6.48k | xmlSecAssert2(data->ctx != NULL, NULL); |
217 | 6.48k | xmlSecAssert2(doc != NULL, NULL); |
218 | 6.48k | xmlSecAssert2(hereNode != NULL, NULL); |
219 | | |
220 | | /* do not forget to set the doc */ |
221 | 6.48k | data->ctx->doc = doc; |
222 | | |
223 | | /* here function works only on the same document */ |
224 | 6.48k | if(hereNode->doc == doc) { |
225 | 6.48k | data->ctx->here = hereNode; |
226 | 6.48k | data->ctx->xptr = 1; |
227 | 6.48k | xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", xmlSecXPathHereFunction); |
228 | 6.48k | } else { |
229 | | /* clear any stale "here" node/function left over from a previous |
230 | | * execution against another document */ |
231 | 0 | data->ctx->here = NULL; |
232 | 0 | xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", NULL); |
233 | 0 | } |
234 | | |
235 | | /* execute xpath or xpointer expression */ |
236 | 6.48k | switch(data->type) { |
237 | 0 | case xmlSecXPathDataTypeXPath: |
238 | 0 | case xmlSecXPathDataTypeXPath2: |
239 | 0 | xpathObj = xmlXPathEvalExpression(data->expr, data->ctx); |
240 | 0 | if(xpathObj == NULL) { |
241 | 0 | xmlSecXmlError2("xmlXPathEvalExpression", NULL, |
242 | 0 | "expr=%s", xmlSecErrorsSafeString(data->expr)); |
243 | 0 | return(NULL); |
244 | 0 | } |
245 | 0 | break; |
246 | 6.48k | case xmlSecXPathDataTypeXPointer: |
247 | 6.48k | xpathObj = xmlXPtrEval(data->expr, data->ctx); |
248 | 6.48k | if(xpathObj == NULL) { |
249 | 4.38k | xmlSecXmlError2("xmlXPtrEval", NULL, |
250 | 4.38k | "expr=%s", xmlSecErrorsSafeString(data->expr)); |
251 | 4.38k | return(NULL); |
252 | 4.38k | } |
253 | 2.09k | break; |
254 | 2.09k | default: |
255 | 0 | xmlSecInternalError("Invalid XPath transform type", NULL); |
256 | 0 | return(NULL); |
257 | 6.48k | } |
258 | | |
259 | | /* sometimes LibXML2 returns an empty nodeset or just NULL, we want |
260 | | to reserve NULL for our own purposes so we simply create an empty |
261 | | node set here */ |
262 | 2.09k | if(xpathObj->nodesetval == NULL) { |
263 | 0 | xpathObj->nodesetval = xmlXPathNodeSetCreate(NULL); |
264 | 0 | if(xpathObj->nodesetval == NULL) { |
265 | 0 | xmlXPathFreeObject(xpathObj); |
266 | 0 | xmlSecXmlError2("xmlXPathNodeSetCreate", NULL, |
267 | 0 | "expr=%s", xmlSecErrorsSafeString(data->expr)); |
268 | 0 | return(NULL); |
269 | 0 | } |
270 | 0 | } |
271 | | |
272 | 2.09k | nodes = xmlSecNodeSetCreate(doc, xpathObj->nodesetval, data->nodeSetType); |
273 | 2.09k | if(nodes == NULL) { |
274 | 0 | xmlSecInternalError2("xmlSecNodeSetCreate", NULL, |
275 | 0 | "type=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(data->nodeSetType)); |
276 | 0 | xmlXPathFreeObject(xpathObj); |
277 | 0 | return(NULL); |
278 | 0 | } |
279 | 2.09k | xpathObj->nodesetval = NULL; |
280 | 2.09k | xmlXPathFreeObject(xpathObj); |
281 | | |
282 | 2.09k | return(nodes); |
283 | 2.09k | } |
284 | | |
285 | | |
286 | | /****************************************************************************** |
287 | | * |
288 | | * XPath data list |
289 | | * |
290 | | *****************************************************************************/ |
291 | | #define xmlSecXPathDataListId \ |
292 | 6.48k | xmlSecXPathDataListGetKlass() |
293 | | static xmlSecPtrListId xmlSecXPathDataListGetKlass (void); |
294 | | static xmlSecNodeSetPtr xmlSecXPathDataListExecute (xmlSecPtrListPtr dataList, |
295 | | xmlDocPtr doc, |
296 | | xmlNodePtr hereNode, |
297 | | xmlSecNodeSetPtr nodes); |
298 | | |
299 | | static xmlSecPtrListKlass xmlSecXPathDataListKlass = { |
300 | | BAD_CAST "xpath-data-list", |
301 | | NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ |
302 | | (xmlSecPtrDestroyItemMethod)xmlSecXPathDataDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ |
303 | | NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ |
304 | | NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ |
305 | | }; |
306 | | |
307 | | static xmlSecPtrListId |
308 | 32.4k | xmlSecXPathDataListGetKlass(void) { |
309 | 32.4k | return(&xmlSecXPathDataListKlass); |
310 | 32.4k | } |
311 | | |
312 | | static xmlSecNodeSetPtr |
313 | | xmlSecXPathDataListExecute(xmlSecPtrListPtr dataList, xmlDocPtr doc, |
314 | 6.48k | xmlNodePtr hereNode, xmlSecNodeSetPtr nodes) { |
315 | 6.48k | xmlSecXPathDataPtr data; |
316 | 6.48k | xmlSecNodeSetPtr res, tmp, tmp2; |
317 | 6.48k | xmlSecSize pos; |
318 | | |
319 | 6.48k | xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), NULL); |
320 | 6.48k | xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, NULL); |
321 | 6.48k | xmlSecAssert2(doc != NULL, NULL); |
322 | 6.48k | xmlSecAssert2(hereNode != NULL, NULL); |
323 | | |
324 | 6.48k | res = nodes; |
325 | 8.58k | for(pos = 0; pos < xmlSecPtrListGetSize(dataList); ++pos) { |
326 | 6.48k | data = (xmlSecXPathDataPtr)xmlSecPtrListGetItem(dataList, pos); |
327 | 6.48k | if(data == NULL) { |
328 | 0 | xmlSecInternalError2("xmlSecPtrListGetItem", NULL, "pos=" XMLSEC_SIZE_FMT, pos); |
329 | 0 | if((res != NULL) && (res != nodes)) { |
330 | 0 | xmlSecNodeSetDestroy(res); |
331 | 0 | } |
332 | 0 | return(NULL); |
333 | 0 | } |
334 | | |
335 | 6.48k | tmp = xmlSecXPathDataExecute(data, doc, hereNode); |
336 | 6.48k | if(tmp == NULL) { |
337 | 4.38k | xmlSecInternalError("xmlSecXPathDataExecute", NULL); |
338 | 4.38k | if((res != NULL) && (res != nodes)) { |
339 | 0 | xmlSecNodeSetDestroy(res); |
340 | 0 | } |
341 | 4.38k | return(NULL); |
342 | 4.38k | } |
343 | | |
344 | 2.09k | tmp2 = xmlSecNodeSetAdd(res, tmp, data->nodeSetOp); |
345 | 2.09k | if(tmp2 == NULL) { |
346 | 0 | xmlSecInternalError2("xmlSecNodeSetAdd", NULL, |
347 | 0 | "nodeSetOp=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(data->nodeSetOp)); |
348 | 0 | if((res != NULL) && (res != nodes)) { |
349 | 0 | xmlSecNodeSetDestroy(res); |
350 | 0 | } |
351 | 0 | xmlSecNodeSetDestroy(tmp); |
352 | 0 | return(NULL); |
353 | 0 | } |
354 | 2.09k | res = tmp2; |
355 | 2.09k | } |
356 | | |
357 | 2.09k | return(res); |
358 | 6.48k | } |
359 | | |
360 | | /****************************************************************************** |
361 | | * |
362 | | * XPath/XPointer transforms |
363 | | * |
364 | | * xmlSecTransform + xmlSecXPathDataList |
365 | | * |
366 | | *****************************************************************************/ |
367 | 77.8k | XMLSEC_TRANSFORM_DECLARE(XPath, xmlSecPtrList) |
368 | 77.8k | #define xmlSecXPathSize XMLSEC_TRANSFORM_SIZE(XPath) |
369 | 77.8k | |
370 | 77.8k | #define xmlSecTransformXPathCheckId(transform) \ |
371 | 77.8k | (xmlSecTransformCheckId((transform), xmlSecTransformXPathId) || \ |
372 | 77.8k | xmlSecTransformCheckId((transform), xmlSecTransformXPath2Id) || \ |
373 | 77.8k | xmlSecTransformCheckId((transform), xmlSecTransformXPointerId)) |
374 | 77.8k | |
375 | 77.8k | static int xmlSecTransformXPathInitialize (xmlSecTransformPtr transform); |
376 | 77.8k | static void xmlSecTransformXPathFinalize (xmlSecTransformPtr transform); |
377 | 77.8k | static int xmlSecTransformXPathExecute (xmlSecTransformPtr transform, |
378 | 77.8k | int last, |
379 | 77.8k | xmlSecTransformCtxPtr transformCtx); |
380 | 77.8k | |
381 | 77.8k | static int |
382 | 77.8k | xmlSecTransformXPathInitialize(xmlSecTransformPtr transform) { |
383 | 6.48k | xmlSecPtrListPtr dataList; |
384 | 6.48k | int ret; |
385 | | |
386 | 6.48k | xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1); |
387 | | |
388 | 6.48k | dataList = xmlSecXPathGetCtx(transform); |
389 | 6.48k | xmlSecAssert2(dataList != NULL, -1); |
390 | | |
391 | 6.48k | ret = xmlSecPtrListInitialize(dataList, xmlSecXPathDataListId); |
392 | 6.48k | if(ret < 0) { |
393 | 0 | xmlSecInternalError("xmlSecPtrListInitialize", |
394 | 0 | xmlSecTransformGetName(transform)); |
395 | 0 | return(-1); |
396 | 0 | } |
397 | 6.48k | return(0); |
398 | 6.48k | } |
399 | | |
400 | | static void |
401 | 6.48k | xmlSecTransformXPathFinalize(xmlSecTransformPtr transform) { |
402 | 6.48k | xmlSecPtrListPtr dataList; |
403 | | |
404 | 6.48k | xmlSecAssert(xmlSecTransformXPathCheckId(transform)); |
405 | | |
406 | 6.48k | dataList = xmlSecXPathGetCtx(transform); |
407 | 6.48k | xmlSecAssert(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId)); |
408 | | |
409 | 6.48k | xmlSecPtrListFinalize(dataList); |
410 | 6.48k | } |
411 | | |
412 | | static int |
413 | | xmlSecTransformXPathExecute(xmlSecTransformPtr transform, int last, |
414 | 6.48k | xmlSecTransformCtxPtr transformCtx) { |
415 | 6.48k | xmlSecPtrListPtr dataList; |
416 | 6.48k | xmlDocPtr doc; |
417 | | |
418 | 6.48k | xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1); |
419 | 6.48k | xmlSecAssert2(transform->hereNode != NULL, -1); |
420 | 6.48k | xmlSecAssert2(transform->outNodes == NULL, -1); |
421 | 6.48k | xmlSecAssert2(last != 0, -1); |
422 | 6.48k | xmlSecAssert2(transformCtx != NULL, -1); |
423 | | |
424 | 6.48k | dataList = xmlSecXPathGetCtx(transform); |
425 | 6.48k | xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); |
426 | 6.48k | xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, -1); |
427 | | |
428 | 6.48k | doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc; |
429 | 6.48k | xmlSecAssert2(doc != NULL, -1); |
430 | | |
431 | 6.48k | transform->outNodes = xmlSecXPathDataListExecute(dataList, doc, |
432 | 6.48k | transform->hereNode, transform->inNodes); |
433 | 6.48k | if(transform->outNodes == NULL) { |
434 | 4.38k | xmlSecInternalError("xmlSecXPathDataListExecute", |
435 | 4.38k | xmlSecTransformGetName(transform)); |
436 | 4.38k | return(-1); |
437 | 4.38k | } |
438 | 2.09k | return(0); |
439 | 6.48k | } |
440 | | |
441 | | /****************************************************************************** |
442 | | * |
443 | | * XPath transform |
444 | | * |
445 | | *****************************************************************************/ |
446 | | static int xmlSecTransformXPathNodeRead (xmlSecTransformPtr transform, |
447 | | xmlNodePtr node, |
448 | | xmlSecTransformCtxPtr transformCtx); |
449 | | |
450 | | static xmlSecTransformKlass xmlSecTransformXPathKlass = { |
451 | | /* klass/object sizes */ |
452 | | sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ |
453 | | xmlSecXPathSize, /* xmlSecSize objSize */ |
454 | | |
455 | | xmlSecNameXPath, /* const xmlChar* name; */ |
456 | | xmlSecXPathNs, /* const xmlChar* href; */ |
457 | | xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ |
458 | | |
459 | | xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */ |
460 | | xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */ |
461 | | xmlSecTransformXPathNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ |
462 | | NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ |
463 | | NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ |
464 | | NULL, /* xmlSecTransformSetKeyMethod setKey; */ |
465 | | NULL, /* xmlSecTransformValidateMethod validate; */ |
466 | | xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ |
467 | | NULL, /* xmlSecTransformPushBinMethod pushBin; */ |
468 | | NULL, /* xmlSecTransformPopBinMethod popBin; */ |
469 | | xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ |
470 | | xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ |
471 | | xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */ |
472 | | |
473 | | NULL, /* void* reserved0; */ |
474 | | NULL, /* void* reserved1; */ |
475 | | }; |
476 | | |
477 | | /** |
478 | | * @brief Gets the XPath transform klass. |
479 | | * @details The XPath transform evaluates given XPath expression and |
480 | | * intersects the result with the previous nodes set. See |
481 | | * http://www.w3.org/TR/xmldsig-core/#sec-XPath for more details. |
482 | | * @return XPath transform id. |
483 | | */ |
484 | | xmlSecTransformId |
485 | 19.4k | xmlSecTransformXPathGetKlass(void) { |
486 | 19.4k | return(&xmlSecTransformXPathKlass); |
487 | 19.4k | } |
488 | | |
489 | 0 | #define XMLSEC_TRANSFORM_XPATH_TMPL "(//. | //@* | //namespace::*)[boolean(%s)]" |
490 | | |
491 | | static int |
492 | 0 | xmlSecTransformXPathNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { |
493 | 0 | xmlSecPtrListPtr dataList; |
494 | 0 | xmlSecXPathDataPtr data; |
495 | 0 | xmlNodePtr cur; |
496 | 0 | xmlChar* tmp; |
497 | 0 | xmlSecSize tmpSize; |
498 | 0 | int tmpLen; |
499 | 0 | int ret; |
500 | |
|
501 | 0 | xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPathId), -1); |
502 | 0 | xmlSecAssert2(node != NULL, -1); |
503 | 0 | xmlSecAssert2(transformCtx != NULL, -1); |
504 | |
|
505 | 0 | dataList = xmlSecXPathGetCtx(transform); |
506 | 0 | xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); |
507 | 0 | xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); |
508 | | |
509 | | /* there is only one required node */ |
510 | 0 | cur = xmlSecGetNextElementNode(node->children); |
511 | 0 | if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPath, xmlSecDSigNs))) { |
512 | 0 | xmlSecInvalidNodeError(cur, xmlSecNodeXPath, |
513 | 0 | xmlSecTransformGetName(transform)); |
514 | 0 | return(-1); |
515 | 0 | } |
516 | | |
517 | | /* read information from the node */ |
518 | 0 | data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath); |
519 | 0 | if(data == NULL) { |
520 | 0 | xmlSecInternalError("xmlSecXPathDataCreate", |
521 | 0 | xmlSecTransformGetName(transform)); |
522 | 0 | return(-1); |
523 | 0 | } |
524 | | |
525 | 0 | ret = xmlSecXPathDataNodeRead(data, cur); |
526 | 0 | if(ret < 0) { |
527 | 0 | xmlSecInternalError("xmlSecXPathDataNodeRead", |
528 | 0 | xmlSecTransformGetName(transform)); |
529 | 0 | xmlSecXPathDataDestroy(data); |
530 | 0 | return(-1); |
531 | 0 | } |
532 | | |
533 | | /* append it to the list */ |
534 | 0 | ret = xmlSecPtrListAdd(dataList, data); |
535 | 0 | if(ret < 0) { |
536 | 0 | xmlSecInternalError("xmlSecPtrListAdd", |
537 | 0 | xmlSecTransformGetName(transform)); |
538 | 0 | xmlSecXPathDataDestroy(data); |
539 | 0 | return(-1); |
540 | 0 | } |
541 | | |
542 | | /* create full XPath expression */ |
543 | 0 | xmlSecAssert2(data->expr != NULL, -1); |
544 | 0 | tmpLen = xmlStrlen(data->expr) + xmlStrlen(BAD_CAST XMLSEC_TRANSFORM_XPATH_TMPL) + 1; |
545 | 0 | XMLSEC_SAFE_CAST_INT_TO_SIZE(tmpLen, tmpSize, return(-1), NULL); |
546 | |
|
547 | 0 | tmp = (xmlChar*) xmlMalloc(sizeof(xmlChar) * tmpSize); |
548 | 0 | if(tmp == NULL) { |
549 | 0 | xmlSecMallocError(sizeof(xmlChar) * tmpSize, |
550 | 0 | xmlSecTransformGetName(transform)); |
551 | 0 | return(-1); |
552 | 0 | } |
553 | 0 | ret = xmlStrPrintf(tmp, tmpLen, XMLSEC_TRANSFORM_XPATH_TMPL, (char*)data->expr); |
554 | 0 | if(ret < 0) { |
555 | 0 | xmlSecXmlError("xmlStrPrintf", xmlSecTransformGetName(transform)); |
556 | 0 | xmlFree(tmp); |
557 | 0 | return(-1); |
558 | 0 | } |
559 | 0 | xmlFree(data->expr); |
560 | 0 | data->expr = tmp; |
561 | | |
562 | | /* set correct node set type and operation */ |
563 | 0 | data->nodeSetOp = xmlSecNodeSetIntersection; |
564 | 0 | data->nodeSetType = xmlSecNodeSetNormal; |
565 | | |
566 | | /* check that we have nothing else */ |
567 | 0 | cur = xmlSecGetNextElementNode(cur->next); |
568 | 0 | if(cur != NULL) { |
569 | 0 | xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform)); |
570 | 0 | return(-1); |
571 | 0 | } |
572 | 0 | return(0); |
573 | 0 | } |
574 | | |
575 | | /****************************************************************************** |
576 | | * |
577 | | * XPath2 transform |
578 | | * |
579 | | *****************************************************************************/ |
580 | | static int xmlSecTransformXPath2NodeRead (xmlSecTransformPtr transform, |
581 | | xmlNodePtr node, |
582 | | xmlSecTransformCtxPtr transformCtx); |
583 | | static xmlSecTransformKlass xmlSecTransformXPath2Klass = { |
584 | | /* klass/object sizes */ |
585 | | sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ |
586 | | xmlSecXPathSize, /* xmlSecSize objSize */ |
587 | | |
588 | | xmlSecNameXPath2, /* const xmlChar* name; */ |
589 | | xmlSecXPath2Ns, /* const xmlChar* href; */ |
590 | | xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ |
591 | | |
592 | | xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */ |
593 | | xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */ |
594 | | xmlSecTransformXPath2NodeRead, /* xmlSecTransformNodeReadMethod readNode; */ |
595 | | NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ |
596 | | NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ |
597 | | NULL, /* xmlSecTransformSetKeyMethod setKey; */ |
598 | | NULL, /* xmlSecTransformValidateMethod validate; */ |
599 | | xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ |
600 | | NULL, /* xmlSecTransformPushBinMethod pushBin; */ |
601 | | NULL, /* xmlSecTransformPopBinMethod popBin; */ |
602 | | xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ |
603 | | xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ |
604 | | xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */ |
605 | | |
606 | | NULL, /* void* reserved0; */ |
607 | | NULL, /* void* reserved1; */ |
608 | | }; |
609 | | |
610 | | /** |
611 | | * @brief Gets the XPath2 transform klass. |
612 | | * @details The XPath2 transform (http://www.w3.org/TR/xmldsig-filter2/). |
613 | | * @return XPath2 transform klass. |
614 | | */ |
615 | | xmlSecTransformId |
616 | 19.4k | xmlSecTransformXPath2GetKlass(void) { |
617 | 19.4k | return(&xmlSecTransformXPath2Klass); |
618 | 19.4k | } |
619 | | |
620 | | static int |
621 | 0 | xmlSecTransformXPath2NodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { |
622 | 0 | xmlSecPtrListPtr dataList; |
623 | 0 | xmlSecXPathDataPtr data; |
624 | 0 | xmlNodePtr cur; |
625 | 0 | xmlChar* op; |
626 | 0 | int ret; |
627 | |
|
628 | 0 | xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPath2Id), -1); |
629 | 0 | xmlSecAssert2(node != NULL, -1); |
630 | 0 | xmlSecAssert2(transformCtx != NULL, -1); |
631 | |
|
632 | 0 | dataList = xmlSecXPathGetCtx(transform); |
633 | 0 | xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); |
634 | 0 | xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); |
635 | | |
636 | | /* There are only xpath nodes */ |
637 | 0 | cur = xmlSecGetNextElementNode(node->children); |
638 | 0 | while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeXPath2, xmlSecXPath2Ns)) { |
639 | | /* read information from the node */ |
640 | 0 | data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath2); |
641 | 0 | if(data == NULL) { |
642 | 0 | xmlSecInternalError("xmlSecXPathDataCreate", |
643 | 0 | xmlSecTransformGetName(transform)); |
644 | 0 | return(-1); |
645 | 0 | } |
646 | | |
647 | 0 | ret = xmlSecXPathDataNodeRead(data, cur); |
648 | 0 | if(ret < 0) { |
649 | 0 | xmlSecInternalError("xmlSecXPathDataNodeRead", |
650 | 0 | xmlSecTransformGetName(transform)); |
651 | 0 | xmlSecXPathDataDestroy(data); |
652 | 0 | return(-1); |
653 | 0 | } |
654 | | |
655 | | /* append it to the list */ |
656 | 0 | ret = xmlSecPtrListAdd(dataList, data); |
657 | 0 | if(ret < 0) { |
658 | 0 | xmlSecInternalError("xmlSecPtrListAdd", |
659 | 0 | xmlSecTransformGetName(transform)); |
660 | 0 | xmlSecXPathDataDestroy(data); |
661 | 0 | return(-1); |
662 | 0 | } |
663 | | |
664 | | /* set correct node set type and operation */ |
665 | 0 | data->nodeSetType = xmlSecNodeSetTree; |
666 | 0 | op = xmlGetProp(cur, xmlSecAttrFilter); |
667 | 0 | if(op == NULL) { |
668 | 0 | xmlSecInvalidNodeAttributeError(cur, xmlSecAttrFilter, |
669 | 0 | xmlSecTransformGetName(transform), |
670 | 0 | "empty"); |
671 | 0 | return(-1); |
672 | 0 | } |
673 | 0 | if(xmlStrEqual(op, xmlSecXPath2FilterIntersect)) { |
674 | 0 | data->nodeSetOp = xmlSecNodeSetIntersection; |
675 | 0 | } else if(xmlStrEqual(op, xmlSecXPath2FilterSubtract)) { |
676 | 0 | data->nodeSetOp = xmlSecNodeSetSubtraction; |
677 | 0 | } else if(xmlStrEqual(op, xmlSecXPath2FilterUnion)) { |
678 | 0 | data->nodeSetOp = xmlSecNodeSetUnion; |
679 | 0 | } else { |
680 | 0 | xmlSecInvalidNodeAttributeError(cur, xmlSecAttrFilter, |
681 | 0 | xmlSecTransformGetName(transform), |
682 | 0 | "unknown"); |
683 | 0 | xmlFree(op); |
684 | 0 | return(-1); |
685 | 0 | } |
686 | 0 | xmlFree(op); |
687 | |
|
688 | 0 | cur = xmlSecGetNextElementNode(cur->next); |
689 | 0 | } |
690 | | |
691 | | /* check that we have at least one XPath node */ |
692 | 0 | if(xmlSecPtrListGetSize(dataList) == 0) { |
693 | 0 | xmlSecInvalidNodeContentError(node, xmlSecTransformGetName(transform), "empty"); |
694 | 0 | return(-1); |
695 | 0 | } |
696 | | |
697 | | /* check that we have nothing else */ |
698 | 0 | if(cur != NULL) { |
699 | 0 | xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform)); |
700 | 0 | return(-1); |
701 | 0 | } |
702 | 0 | return(0); |
703 | 0 | } |
704 | | |
705 | | /****************************************************************************** |
706 | | * |
707 | | * XPointer transform |
708 | | * |
709 | | *****************************************************************************/ |
710 | | static int xmlSecTransformXPointerNodeRead (xmlSecTransformPtr transform, |
711 | | xmlNodePtr node, |
712 | | xmlSecTransformCtxPtr transformCtx); |
713 | | static xmlSecTransformKlass xmlSecTransformXPointerKlass = { |
714 | | /* klass/object sizes */ |
715 | | sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ |
716 | | xmlSecXPathSize, /* xmlSecSize objSize */ |
717 | | |
718 | | xmlSecNameXPointer, /* const xmlChar* name; */ |
719 | | xmlSecXPointerNs, /* const xmlChar* href; */ |
720 | | xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ |
721 | | |
722 | | xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */ |
723 | | xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */ |
724 | | xmlSecTransformXPointerNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ |
725 | | NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ |
726 | | NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ |
727 | | NULL, /* xmlSecTransformSetKeyMethod setKey; */ |
728 | | NULL, /* xmlSecTransformValidateMethod validate; */ |
729 | | xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ |
730 | | NULL, /* xmlSecTransformPushBinMethod pushBin; */ |
731 | | NULL, /* xmlSecTransformPopBinMethod popBin; */ |
732 | | xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ |
733 | | xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ |
734 | | xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */ |
735 | | |
736 | | NULL, /* void* reserved0; */ |
737 | | NULL, /* void* reserved1; */ |
738 | | }; |
739 | | |
740 | | /** |
741 | | * @brief Gets the XPointer transform klass. |
742 | | * @details The XPointer transform klass |
743 | | * (https://www.rfc-editor.org/rfc/rfc9231.html). |
744 | | * @return XPointer transform klass. |
745 | | */ |
746 | | xmlSecTransformId |
747 | 32.4k | xmlSecTransformXPointerGetKlass(void) { |
748 | 32.4k | return(&xmlSecTransformXPointerKlass); |
749 | 32.4k | } |
750 | | |
751 | | /** |
752 | | * @brief Sets the XPointer expression for a transform. |
753 | | * @details Sets the XPointer expression for an XPointer @p transform. |
754 | | * @param transform the pointer to XPointer transform. |
755 | | * @param expr the XPointer expression. |
756 | | * @param nodeSetType the type of evaluated XPointer expression. |
757 | | * @param hereNode the pointer to "here" node. |
758 | | * @return 0 on success or a negative value if an error occurs. |
759 | | */ |
760 | | int |
761 | | xmlSecTransformXPointerSetExpr(xmlSecTransformPtr transform, const xmlChar* expr, |
762 | 6.48k | xmlSecNodeSetType nodeSetType, xmlNodePtr hereNode) { |
763 | 6.48k | xmlSecPtrListPtr dataList; |
764 | 6.48k | xmlSecXPathDataPtr data; |
765 | 6.48k | int ret; |
766 | | |
767 | 6.48k | xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1); |
768 | 6.48k | xmlSecAssert2(transform->hereNode == NULL, -1); |
769 | 6.48k | xmlSecAssert2(expr != NULL, -1); |
770 | 6.48k | xmlSecAssert2(hereNode != NULL, -1); |
771 | | |
772 | 6.48k | dataList = xmlSecXPathGetCtx(transform); |
773 | 6.48k | xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); |
774 | 6.48k | xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); |
775 | | |
776 | 6.48k | data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer); |
777 | 6.48k | if(data == NULL) { |
778 | 0 | xmlSecInternalError("xmlSecXPathDataCreate", |
779 | 0 | xmlSecTransformGetName(transform)); |
780 | 0 | return(-1); |
781 | 0 | } |
782 | | |
783 | 6.48k | ret = xmlSecXPathDataRegisterNamespaces(data, hereNode); |
784 | 6.48k | if(ret < 0) { |
785 | 0 | xmlSecInternalError("xmlSecXPathDataRegisterNamespaces", |
786 | 0 | xmlSecTransformGetName(transform)); |
787 | 0 | xmlSecXPathDataDestroy(data); |
788 | 0 | return(-1); |
789 | 0 | } |
790 | | |
791 | 6.48k | ret = xmlSecXPathDataSetExpr(data, expr); |
792 | 6.48k | if(ret < 0) { |
793 | 0 | xmlSecInternalError("xmlSecXPathDataSetExpr", |
794 | 0 | xmlSecTransformGetName(transform)); |
795 | 0 | xmlSecXPathDataDestroy(data); |
796 | 0 | return(-1); |
797 | 0 | } |
798 | | |
799 | | /* append it to the list */ |
800 | 6.48k | ret = xmlSecPtrListAdd(dataList, data); |
801 | 6.48k | if(ret < 0) { |
802 | 0 | xmlSecInternalError("xmlSecPtrListAdd", |
803 | 0 | xmlSecTransformGetName(transform)); |
804 | 0 | xmlSecXPathDataDestroy(data); |
805 | 0 | return(-1); |
806 | 0 | } |
807 | | |
808 | | /* set correct node set type and operation */ |
809 | 6.48k | data->nodeSetOp = xmlSecNodeSetIntersection; |
810 | 6.48k | data->nodeSetType = nodeSetType; |
811 | | |
812 | | /* set the "here" node only after all fallible operations succeeded, |
813 | | * so a failed call leaves the transform unmodified */ |
814 | 6.48k | transform->hereNode = hereNode; |
815 | | |
816 | 6.48k | return(0); |
817 | 6.48k | } |
818 | | |
819 | | static int |
820 | 0 | xmlSecTransformXPointerNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { |
821 | 0 | xmlSecPtrListPtr dataList; |
822 | 0 | xmlSecXPathDataPtr data; |
823 | 0 | xmlNodePtr cur; |
824 | 0 | int ret; |
825 | |
|
826 | 0 | xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1); |
827 | 0 | xmlSecAssert2(node != NULL, -1); |
828 | 0 | xmlSecAssert2(transformCtx != NULL, -1); |
829 | |
|
830 | 0 | dataList = xmlSecXPathGetCtx(transform); |
831 | 0 | xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); |
832 | 0 | xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); |
833 | | |
834 | | /* there is only one required node */ |
835 | 0 | cur = xmlSecGetNextElementNode(node->children); |
836 | 0 | if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPointer, xmlSecXPointerNs))) { |
837 | 0 | xmlSecInvalidNodeError(cur, xmlSecNodeXPointer, |
838 | 0 | xmlSecTransformGetName(transform)); |
839 | 0 | return(-1); |
840 | 0 | } |
841 | | |
842 | | /* read information from the node */ |
843 | 0 | data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer); |
844 | 0 | if(data == NULL) { |
845 | 0 | xmlSecInternalError("xmlSecXPathDataCreate", |
846 | 0 | xmlSecTransformGetName(transform)); |
847 | 0 | return(-1); |
848 | 0 | } |
849 | | |
850 | 0 | ret = xmlSecXPathDataNodeRead(data, cur); |
851 | 0 | if(ret < 0) { |
852 | 0 | xmlSecInternalError("xmlSecXPathDataNodeRead", |
853 | 0 | xmlSecTransformGetName(transform)); |
854 | 0 | xmlSecXPathDataDestroy(data); |
855 | 0 | return(-1); |
856 | 0 | } |
857 | | |
858 | | /* append it to the list */ |
859 | 0 | ret = xmlSecPtrListAdd(dataList, data); |
860 | 0 | if(ret < 0) { |
861 | 0 | xmlSecInternalError("xmlSecPtrListAdd", |
862 | 0 | xmlSecTransformGetName(transform)); |
863 | 0 | xmlSecXPathDataDestroy(data); |
864 | 0 | return(-1); |
865 | 0 | } |
866 | | |
867 | | /* set correct node set type and operation */ |
868 | 0 | data->nodeSetOp = xmlSecNodeSetIntersection; |
869 | 0 | data->nodeSetType = xmlSecNodeSetTree; |
870 | | |
871 | | /* check that we have nothing else */ |
872 | 0 | cur = xmlSecGetNextElementNode(cur->next); |
873 | 0 | if(cur != NULL) { |
874 | 0 | xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform)); |
875 | 0 | return(-1); |
876 | 0 | } |
877 | 0 | return(0); |
878 | 0 | } |
879 | | |
880 | | |
881 | | /****************************************************************************** |
882 | | * |
883 | | * Visa3DHack transform |
884 | | * |
885 | | * xmlSecTransform + xmlChar* (pointer to ID) |
886 | | * |
887 | | *****************************************************************************/ |
888 | 0 | XMLSEC_TRANSFORM_DECLARE(Visa3DHack, xmlChar*) |
889 | 0 | #define xmlSecVisa3DHackSize XMLSEC_TRANSFORM_SIZE(Visa3DHack) |
890 | 0 |
|
891 | 0 | #define xmlSecTransformVisa3DHackCheckId(transform) \ |
892 | 0 | (xmlSecTransformCheckId((transform), xmlSecTransformVisa3DHackId)) |
893 | 0 |
|
894 | 0 | static int xmlSecTransformVisa3DHackInitialize (xmlSecTransformPtr transform); |
895 | 0 | static void xmlSecTransformVisa3DHackFinalize (xmlSecTransformPtr transform); |
896 | 0 | static int xmlSecTransformVisa3DHackExecute (xmlSecTransformPtr transform, |
897 | 0 | int last, |
898 | 0 | xmlSecTransformCtxPtr transformCtx); |
899 | 0 |
|
900 | 0 | static xmlSecTransformKlass xmlSecTransformVisa3DHackKlass = { |
901 | 0 | /* klass/object sizes */ |
902 | 0 | sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ |
903 | 0 | xmlSecVisa3DHackSize, /* xmlSecSize objSize */ |
904 | 0 |
|
905 | 0 | BAD_CAST "Visa3DHackTransform", /* const xmlChar* name; */ |
906 | 0 | NULL, /* const xmlChar* href; */ |
907 | 0 | xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ |
908 | 0 |
|
909 | 0 | xmlSecTransformVisa3DHackInitialize, /* xmlSecTransformInitializeMethod initialize; */ |
910 | 0 | xmlSecTransformVisa3DHackFinalize, /* xmlSecTransformFinalizeMethod finalize; */ |
911 | 0 | NULL, /* xmlSecTransformNodeReadMethod readNode; */ |
912 | 0 | NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ |
913 | 0 | NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ |
914 | 0 | NULL, /* xmlSecTransformSetKeyMethod setKey; */ |
915 | 0 | NULL, /* xmlSecTransformValidateMethod validate; */ |
916 | 0 | xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ |
917 | 0 | NULL, /* xmlSecTransformPushBinMethod pushBin; */ |
918 | 0 | NULL, /* xmlSecTransformPopBinMethod popBin; */ |
919 | 0 | xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ |
920 | 0 | xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ |
921 | 0 | xmlSecTransformVisa3DHackExecute, /* xmlSecTransformExecuteMethod execute; */ |
922 | 0 |
|
923 | 0 | NULL, /* void* reserved0; */ |
924 | 0 | NULL, /* void* reserved1; */ |
925 | 0 | }; |
926 | 0 |
|
927 | 0 | /** |
928 | 0 | * @brief Gets the Visa3DHack transform klass. |
929 | 0 | * @details The Visa3DHack transform klass. The only reason why we need this |
930 | 0 | * is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows |
931 | 0 | * invalid XPointer expressions in the URI attribute. Since we couldn't evaluate |
932 | 0 | * such expressions thru XPath/XPointer engine, we need to have this hack here. |
933 | 0 | * @return Visa3DHack transform klass. |
934 | 0 | */ |
935 | 0 | xmlSecTransformId |
936 | 0 | xmlSecTransformVisa3DHackGetKlass(void) { |
937 | 0 | return(&xmlSecTransformVisa3DHackKlass); |
938 | 0 | } |
939 | | |
940 | | /** |
941 | | * @brief Sets the ID value for an Visa3DHack @p transform. |
942 | | * @param transform the pointer to Visa3DHack transform. |
943 | | * @param id the ID value. |
944 | | * @return 0 on success or a negative value if an error occurs. |
945 | | */ |
946 | | int |
947 | 0 | xmlSecTransformVisa3DHackSetID(xmlSecTransformPtr transform, const xmlChar* id) { |
948 | 0 | xmlChar** idPtr; |
949 | |
|
950 | 0 | xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformVisa3DHackId), -1); |
951 | 0 | xmlSecAssert2(id != NULL, -1); |
952 | |
|
953 | 0 | idPtr = xmlSecVisa3DHackGetCtx(transform); |
954 | 0 | xmlSecAssert2(idPtr != NULL, -1); |
955 | 0 | xmlSecAssert2((*idPtr) == NULL, -1); |
956 | |
|
957 | 0 | (*idPtr) = xmlStrdup(id); |
958 | 0 | if((*idPtr) == NULL) { |
959 | 0 | xmlSecStrdupError(id, xmlSecTransformGetName(transform)); |
960 | 0 | return(-1); |
961 | 0 | } |
962 | | |
963 | 0 | return(0); |
964 | 0 | } |
965 | | |
966 | | static int |
967 | 0 | xmlSecTransformVisa3DHackInitialize(xmlSecTransformPtr transform) { |
968 | 0 | xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1); |
969 | |
|
970 | 0 | return(0); |
971 | 0 | } |
972 | | |
973 | | static void |
974 | 0 | xmlSecTransformVisa3DHackFinalize(xmlSecTransformPtr transform) { |
975 | 0 | xmlChar** idPtr; |
976 | |
|
977 | 0 | xmlSecAssert(xmlSecTransformVisa3DHackCheckId(transform)); |
978 | |
|
979 | 0 | idPtr = xmlSecVisa3DHackGetCtx(transform); |
980 | 0 | xmlSecAssert(idPtr != NULL); |
981 | |
|
982 | 0 | if((*idPtr) != NULL) { |
983 | 0 | xmlFree((*idPtr)); |
984 | 0 | } |
985 | 0 | (*idPtr) = NULL; |
986 | 0 | } |
987 | | |
988 | | static int |
989 | | xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform, int last, |
990 | 0 | xmlSecTransformCtxPtr transformCtx) { |
991 | 0 | xmlChar** idPtr; |
992 | 0 | xmlDocPtr doc; |
993 | 0 | xmlAttrPtr attr; |
994 | 0 | xmlNodeSetPtr nodeSet; |
995 | |
|
996 | 0 | xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1); |
997 | 0 | xmlSecAssert2(transform->outNodes == NULL, -1); |
998 | 0 | xmlSecAssert2(last != 0, -1); |
999 | 0 | xmlSecAssert2(transformCtx != NULL, -1); |
1000 | |
|
1001 | 0 | idPtr = xmlSecVisa3DHackGetCtx(transform); |
1002 | 0 | xmlSecAssert2(idPtr != NULL, -1); |
1003 | 0 | xmlSecAssert2((*idPtr) != NULL, -1); |
1004 | | |
1005 | | /* if there are no input nodes we must have a "here" node to get the |
1006 | | * document from (in the normal flow inNodes is always set) */ |
1007 | 0 | if(transform->inNodes == NULL) { |
1008 | 0 | xmlSecAssert2(transform->hereNode != NULL, -1); |
1009 | 0 | } |
1010 | | |
1011 | 0 | doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc; |
1012 | 0 | xmlSecAssert2(doc != NULL, -1); |
1013 | |
|
1014 | 0 | attr = xmlGetID(doc, (*idPtr)); |
1015 | 0 | if((attr == NULL) || (attr->parent == NULL)) { |
1016 | 0 | xmlSecXmlError2("xmlGetID", xmlSecTransformGetName(transform), |
1017 | 0 | "id=\"%s\"", xmlSecErrorsSafeString(*idPtr)); |
1018 | 0 | return(-1); |
1019 | 0 | } |
1020 | | |
1021 | 0 | nodeSet = xmlXPathNodeSetCreate(attr->parent); |
1022 | 0 | if(nodeSet == NULL) { |
1023 | 0 | xmlSecXmlError2("xmlXPathNodeSetCreate", xmlSecTransformGetName(transform), |
1024 | 0 | "id=\"%s\"", xmlSecErrorsSafeString(*idPtr)); |
1025 | 0 | return(-1); |
1026 | 0 | } |
1027 | | |
1028 | 0 | transform->outNodes = xmlSecNodeSetCreate(doc, nodeSet, xmlSecNodeSetTreeWithoutComments); |
1029 | 0 | if(transform->outNodes == NULL) { |
1030 | 0 | xmlSecInternalError("xmlSecNodeSetCreate", |
1031 | 0 | xmlSecTransformGetName(transform)); |
1032 | 0 | xmlXPathFreeNodeSet(nodeSet); |
1033 | 0 | return(-1); |
1034 | 0 | } |
1035 | 0 | return(0); |
1036 | 0 | } |