1 /*
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  *
5  * This is free software; see Copyright file in the source
6  * distribution for preciese wording.
7  *
8  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
9  */
10 /**
11  * SECTION:transforms
12  * @Short_description: Transform object functions.
13  * @Stability: Stable
14  *
15  * The [Transforms Element](http://www.w3.org/TR/xmldsig-core/#sec-Transforms)
16  * contains an ordered list of Transform elements; these describe how the signer
17  * obtained the data object that was digested.
18  *
19  * Schema Definition:
20  *
21  * |[<!-- language="XML" -->
22  *  <element name="Transforms" type="ds:TransformsType"/>
23  *  <complexType name="TransformsType">
24  *    <sequence>
25  *      <element ref="ds:Transform" maxOccurs="unbounded"/>
26  *    </sequence>
27  *   </complexType>
28  *
29  *  <element name="Transform" type="ds:TransformType"/>
30  *  <complexType name="TransformType" mixed="true">
31  *    <choice minOccurs="0" maxOccurs="unbounded">
32  *      <any namespace="##other" processContents="lax"/>
33  *      <!-- (1,1) elements from (0,unbounded) namespaces -->
34  *      <element name="XPath" type="string"/>
35  *    </choice>
36  *    <attribute name="Algorithm" type="anyURI" use="required"/>
37  *  </complexType>
38  * ]|
39  *
40  * DTD:
41  *
42  * |[<!-- language="XML" -->
43  *  <!ELEMENT Transforms (Transform+)>
44  *  <!ELEMENT Transform (#PCDATA|XPath %Transform.ANY;)* >
45  *  <!ATTLIST Transform Algorithm    CDATA    #REQUIRED >
46  *  <!ELEMENT XPath (#PCDATA) >
47  * ]|
48  */
49 
50 #include "globals.h"
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 
55 #include <libxml/tree.h>
56 #include <libxml/xpath.h>
57 #include <libxml/xpointer.h>
58 
59 #include <xmlsec/xmlsec.h>
60 #include <xmlsec/buffer.h>
61 #include <xmlsec/xmltree.h>
62 #include <xmlsec/keysdata.h>
63 #include <xmlsec/keys.h>
64 #include <xmlsec/keyinfo.h>
65 #include <xmlsec/transforms.h>
66 #include <xmlsec/base64.h>
67 #include <xmlsec/io.h>
68 #include <xmlsec/membuf.h>
69 #include <xmlsec/parser.h>
70 #include <xmlsec/errors.h>
71 
72 #include "xslt.h"
73 
74 /**************************************************************************
75  *
76  * Global xmlSecTransformIds list functions
77  *
78  *************************************************************************/
79 static xmlSecPtrList xmlSecAllTransformIds;
80 
81 
82 /**
83  * xmlSecTransformIdsGet:
84  *
85  * Gets global registered transform klasses list.
86  *
87  * Returns: the pointer to list of all registered transform klasses.
88  */
89 xmlSecPtrListPtr
xmlSecTransformIdsGet(void)90 xmlSecTransformIdsGet(void) {
91     return(&xmlSecAllTransformIds);
92 }
93 
94 /**
95  * xmlSecTransformIdsInit:
96  *
97  * Initializes the transform klasses. This function is called from the
98  * #xmlSecInit function and the application should not call it directly.
99  *
100  * Returns: 0 on success or a negative value if an error occurs.
101  */
102 int
xmlSecTransformIdsInit(void)103 xmlSecTransformIdsInit(void) {
104     int ret;
105 
106     ret = xmlSecPtrListInitialize(xmlSecTransformIdsGet(), xmlSecTransformIdListId);
107     if(ret < 0) {
108         xmlSecInternalError("xmlSecPtrListInitialize(xmlSecTransformIdListId)", NULL);
109         return(-1);
110     }
111 
112     ret = xmlSecTransformIdsRegisterDefault();
113     if(ret < 0) {
114         xmlSecInternalError("xmlSecTransformIdsRegisterDefault", NULL);
115         return(-1);
116     }
117 
118 #ifndef XMLSEC_NO_XSLT
119     xmlSecTransformXsltInitialize();
120 #endif /* XMLSEC_NO_XSLT */
121 
122     return(0);
123 }
124 
125 /**
126  * xmlSecTransformIdsShutdown:
127  *
128  * Shuts down the keys data klasses. This function is called from the
129  * #xmlSecShutdown function and the application should not call it directly.
130  */
131 void
xmlSecTransformIdsShutdown(void)132 xmlSecTransformIdsShutdown(void) {
133 #ifndef XMLSEC_NO_XSLT
134     xmlSecTransformXsltShutdown();
135 #endif /* XMLSEC_NO_XSLT */
136 
137     xmlSecPtrListFinalize(xmlSecTransformIdsGet());
138 }
139 
140 /**
141  * xmlSecTransformIdsRegister:
142  * @id:                 the transform klass.
143  *
144  * Registers @id in the global list of transform klasses.
145  *
146  * Returns: 0 on success or a negative value if an error occurs.
147  */
148 int
xmlSecTransformIdsRegister(xmlSecTransformId id)149 xmlSecTransformIdsRegister(xmlSecTransformId id) {
150     int ret;
151 
152     xmlSecAssert2(id != xmlSecTransformIdUnknown, -1);
153 
154     ret = xmlSecPtrListAdd(xmlSecTransformIdsGet(), (xmlSecPtr)id);
155     if(ret < 0) {
156         xmlSecInternalError("xmlSecPtrListAdd",
157                             xmlSecTransformKlassGetName(id));
158         return(-1);
159     }
160 
161     return(0);
162 }
163 
164 /**
165  * xmlSecTransformIdsRegisterDefault:
166  *
167  * Registers default (implemented by XML Security Library)
168  * transform klasses: XPath transform, Base64 transform, ...
169  *
170  * Returns: 0 on success or a negative value if an error occurs.
171  */
172 int
xmlSecTransformIdsRegisterDefault(void)173 xmlSecTransformIdsRegisterDefault(void) {
174     if(xmlSecTransformIdsRegister(xmlSecTransformBase64Id) < 0) {
175         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformBase64Id)", NULL);
176         return(-1);
177     }
178 
179     if(xmlSecTransformIdsRegister(xmlSecTransformEnvelopedId) < 0) {
180         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformEnvelopedId)", NULL);
181         return(-1);
182     }
183 
184     /* c14n methods */
185     if(xmlSecTransformIdsRegister(xmlSecTransformInclC14NId) < 0) {
186         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformInclC14NId)", NULL);
187         return(-1);
188     }
189     if(xmlSecTransformIdsRegister(xmlSecTransformInclC14NWithCommentsId) < 0) {
190         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformInclC14NWithCommentsId)", NULL);
191         return(-1);
192     }
193     if(xmlSecTransformIdsRegister(xmlSecTransformInclC14N11Id) < 0) {
194         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformInclC14N11Id)", NULL);
195         return(-1);
196     }
197     if(xmlSecTransformIdsRegister(xmlSecTransformInclC14N11WithCommentsId) < 0) {
198         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformInclC14N11WithCommentsId)", NULL);
199         return(-1);
200     }
201     if(xmlSecTransformIdsRegister(xmlSecTransformExclC14NId) < 0) {
202         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformExclC14NId)", NULL);
203         return(-1);
204     }
205     if(xmlSecTransformIdsRegister(xmlSecTransformExclC14NWithCommentsId) < 0) {
206         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformExclC14NWithCommentsId)", NULL);
207         return(-1);
208     }
209 
210     if(xmlSecTransformIdsRegister(xmlSecTransformXPathId) < 0) {
211         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformXPathId)", NULL);
212         return(-1);
213     }
214 
215     if(xmlSecTransformIdsRegister(xmlSecTransformXPath2Id) < 0) {
216         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformXPath2Id)", NULL);
217         return(-1);
218     }
219 
220     if(xmlSecTransformIdsRegister(xmlSecTransformXPointerId) < 0) {
221         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformXPointerId)", NULL);
222         return(-1);
223     }
224 
225     if(xmlSecTransformIdsRegister(xmlSecTransformRelationshipId) < 0) {
226         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformRelationshipId)", NULL);
227         return(-1);
228     }
229 
230 #ifndef XMLSEC_NO_XSLT
231     if(xmlSecTransformIdsRegister(xmlSecTransformXsltId) < 0) {
232         xmlSecInternalError("xmlSecTransformIdsRegister(xmlSecTransformXsltId)", NULL);
233         return(-1);
234     }
235 #endif /* XMLSEC_NO_XSLT */
236 
237     return(0);
238 }
239 
240 /**************************************************************************
241  *
242  * utils
243  *
244  *************************************************************************/
245 /**
246  * xmlSecTransformUriTypeCheck:
247  * @type:               the expected URI type.
248  * @uri:                the uri for checking.
249  *
250  * Checks if @uri matches expected type @type.
251  *
252  * Returns: 1 if @uri matches @type, 0 if not or a negative value
253  * if an error occurs.
254  */
255 int
xmlSecTransformUriTypeCheck(xmlSecTransformUriType type,const xmlChar * uri)256 xmlSecTransformUriTypeCheck(xmlSecTransformUriType type, const xmlChar* uri) {
257     xmlSecTransformUriType uriType = 0;
258 
259     if((uri == NULL) || (xmlStrlen(uri) == 0)) {
260         uriType = xmlSecTransformUriTypeEmpty;
261     } else if(uri[0] == '#') {
262         uriType = xmlSecTransformUriTypeSameDocument;
263     } else if(xmlStrncmp(uri, BAD_CAST "file://", 7) == 0) {
264         uriType = xmlSecTransformUriTypeLocal;
265     } else {
266         uriType = xmlSecTransformUriTypeRemote;
267     }
268     return(((uriType & type) != 0) ? 1 : 0);
269 }
270 
271 /**************************************************************************
272  *
273  * xmlSecTransformCtx
274  *
275  *************************************************************************/
276 
277 /**
278  * xmlSecTransformCtxCreate:
279  *
280  * Creates transforms chain processing context.
281  * The caller is responsible for destroying returned object by calling
282  * #xmlSecTransformCtxDestroy function.
283  *
284  * Returns: pointer to newly allocated context object or NULL if an error
285  * occurs.
286  */
287 xmlSecTransformCtxPtr
xmlSecTransformCtxCreate(void)288 xmlSecTransformCtxCreate(void) {
289     xmlSecTransformCtxPtr ctx;
290     int ret;
291 
292     /* Allocate a new xmlSecTransform and fill the fields. */
293     ctx = (xmlSecTransformCtxPtr)xmlMalloc(sizeof(xmlSecTransformCtx));
294     if(ctx == NULL) {
295         xmlSecMallocError(sizeof(xmlSecTransformCtx), NULL);
296         return(NULL);
297     }
298 
299     ret = xmlSecTransformCtxInitialize(ctx);
300     if(ret < 0) {
301         xmlSecInternalError("xmlSecTransformCtxInitialize", NULL);
302         xmlSecTransformCtxDestroy(ctx);
303         return(NULL);
304     }
305 
306     return(ctx);
307 }
308 
309 /**
310  * xmlSecTransformCtxDestroy:
311  * @ctx:                the pointer to transforms chain processing context.
312  *
313  * Destroy context object created with #xmlSecTransformCtxCreate function.
314  */
315 void
xmlSecTransformCtxDestroy(xmlSecTransformCtxPtr ctx)316 xmlSecTransformCtxDestroy(xmlSecTransformCtxPtr ctx) {
317     xmlSecAssert(ctx != NULL);
318 
319     xmlSecTransformCtxFinalize(ctx);
320     xmlFree(ctx);
321 }
322 
323 /**
324  * xmlSecTransformCtxInitialize:
325  * @ctx:                the pointer to transforms chain processing context.
326  *
327  * Initializes transforms chain processing context.
328  * The caller is responsible for cleaning up returned object by calling
329  * #xmlSecTransformCtxFinalize function.
330  *
331  * Returns: 0 on success or a negative value if an error occurs.
332  */
333 int
xmlSecTransformCtxInitialize(xmlSecTransformCtxPtr ctx)334 xmlSecTransformCtxInitialize(xmlSecTransformCtxPtr ctx) {
335     int ret;
336 
337     xmlSecAssert2(ctx != NULL, -1);
338 
339     memset(ctx, 0, sizeof(xmlSecTransformCtx));
340 
341     ret = xmlSecPtrListInitialize(&(ctx->enabledTransforms), xmlSecTransformIdListId);
342     if(ret < 0) {
343         xmlSecInternalError("xmlSecPtrListInitialize(xmlSecTransformIdListId)", NULL);
344         return(-1);
345     }
346 
347     ctx->enabledUris = xmlSecTransformUriTypeAny;
348     return(0);
349 }
350 
351 /**
352  * xmlSecTransformCtxFinalize:
353  * @ctx:                the pointer to transforms chain processing context.
354  *
355  * Cleans up @ctx object initialized with #xmlSecTransformCtxInitialize function.
356  */
357 void
xmlSecTransformCtxFinalize(xmlSecTransformCtxPtr ctx)358 xmlSecTransformCtxFinalize(xmlSecTransformCtxPtr ctx) {
359     xmlSecAssert(ctx != NULL);
360 
361     xmlSecTransformCtxReset(ctx);
362     xmlSecPtrListFinalize(&(ctx->enabledTransforms));
363     memset(ctx, 0, sizeof(xmlSecTransformCtx));
364 }
365 
366 /**
367  * xmlSecTransformCtxReset:
368  * @ctx:                the pointer to transforms chain processing context.
369  *
370  * Resets transforms context for new processing.
371  */
372 void
xmlSecTransformCtxReset(xmlSecTransformCtxPtr ctx)373 xmlSecTransformCtxReset(xmlSecTransformCtxPtr ctx) {
374     xmlSecTransformPtr transform, tmp;
375 
376     xmlSecAssert(ctx != NULL);
377 
378     ctx->result = NULL;
379     ctx->status = xmlSecTransformStatusNone;
380 
381     /* destroy uri */
382     if(ctx->uri != NULL) {
383         xmlFree(ctx->uri);
384         ctx->uri = NULL;
385     }
386     if(ctx->xptrExpr != NULL) {
387         xmlFree(ctx->xptrExpr);
388         ctx->xptrExpr = NULL;
389     }
390 
391     /* destroy transforms chain */
392     for(transform = ctx->first; transform != NULL; transform = tmp) {
393         tmp = transform->next;
394         xmlSecTransformDestroy(transform);
395     }
396     ctx->first = ctx->last = NULL;
397 }
398 
399 /**
400  * xmlSecTransformCtxCopyUserPref:
401  * @dst:                the pointer to destination transforms chain processing context.
402  * @src:                the pointer to source transforms chain processing context.
403  *
404  * Copies user settings from @src context to @dst.
405  *
406  * Returns: 0 on success or a negative value otherwise.
407  */
408 int
xmlSecTransformCtxCopyUserPref(xmlSecTransformCtxPtr dst,xmlSecTransformCtxPtr src)409 xmlSecTransformCtxCopyUserPref(xmlSecTransformCtxPtr dst, xmlSecTransformCtxPtr src) {
410     int ret;
411 
412     xmlSecAssert2(dst != NULL, -1);
413     xmlSecAssert2(src != NULL, -1);
414 
415     dst->userData        = src->userData;
416     dst->flags           = src->flags;
417     dst->flags2          = src->flags2;
418     dst->enabledUris     = src->enabledUris;
419     dst->preExecCallback = src->preExecCallback;
420 
421     ret = xmlSecPtrListCopy(&(dst->enabledTransforms), &(src->enabledTransforms));
422     if(ret < 0) {
423         xmlSecInternalError("xmlSecPtrListCopy(enabledTransforms)", NULL);
424         return(-1);
425     }
426 
427     return(0);
428 }
429 
430 /**
431  * xmlSecTransformCtxAppend:
432  * @ctx:                the pointer to transforms chain processing context.
433  * @transform:          the pointer to new transform.
434  *
435  * Connects the @transform to the end of the chain of transforms in the @ctx
436  * (see #xmlSecTransformConnect function for details).
437  *
438  * Returns: 0 on success or a negative value otherwise.
439  */
440 int
xmlSecTransformCtxAppend(xmlSecTransformCtxPtr ctx,xmlSecTransformPtr transform)441 xmlSecTransformCtxAppend(xmlSecTransformCtxPtr ctx, xmlSecTransformPtr transform) {
442     int ret;
443 
444     xmlSecAssert2(ctx != NULL, -1);
445     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
446     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
447 
448     if(ctx->last != NULL) {
449         ret = xmlSecTransformConnect(ctx->last, transform, ctx);
450         if(ret < 0) {
451             xmlSecInternalError("xmlSecTransformConnect",
452                                 xmlSecTransformGetName(transform));
453             return(-1);
454         }
455     } else {
456         xmlSecAssert2(ctx->first == NULL, -1);
457         ctx->first = transform;
458     }
459     ctx->last = transform;
460 
461     return(0);
462 }
463 
464 /**
465  * xmlSecTransformCtxPrepend:
466  * @ctx:                the pointer to transforms chain processing context.
467  * @transform:          the pointer to new transform.
468  *
469  * Connects the @transform to the beggining of the chain of transforms in the @ctx
470  * (see #xmlSecTransformConnect function for details).
471  *
472  * Returns: 0 on success or a negative value otherwise.
473  */
474 int
xmlSecTransformCtxPrepend(xmlSecTransformCtxPtr ctx,xmlSecTransformPtr transform)475 xmlSecTransformCtxPrepend(xmlSecTransformCtxPtr ctx, xmlSecTransformPtr transform) {
476     int ret;
477 
478     xmlSecAssert2(ctx != NULL, -1);
479     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
480     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
481 
482     if(ctx->first != NULL) {
483         ret = xmlSecTransformConnect(transform, ctx->first, ctx);
484         if(ret < 0) {
485             xmlSecInternalError("xmlSecTransformConnect",
486                                 xmlSecTransformGetName(transform));
487             return(-1);
488         }
489     } else {
490         xmlSecAssert2(ctx->last == NULL, -1);
491         ctx->last = transform;
492     }
493     ctx->first = transform;
494 
495     return(0);
496 }
497 
498 /**
499  * xmlSecTransformCtxCreateAndAppend:
500  * @ctx:                the pointer to transforms chain processing context.
501  * @id:                 the new transform klass.
502  *
503  * Creates new transform and connects it to the end of the chain of
504  * transforms in the @ctx (see #xmlSecTransformConnect function for details).
505  *
506  * Returns: pointer to newly created transform or NULL if an error occurs.
507  */
508 xmlSecTransformPtr
xmlSecTransformCtxCreateAndAppend(xmlSecTransformCtxPtr ctx,xmlSecTransformId id)509 xmlSecTransformCtxCreateAndAppend(xmlSecTransformCtxPtr ctx, xmlSecTransformId id) {
510     xmlSecTransformPtr transform;
511     int ret;
512 
513     xmlSecAssert2(ctx != NULL, NULL);
514     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL);
515     xmlSecAssert2(id != xmlSecTransformIdUnknown, NULL);
516 
517     transform = xmlSecTransformCreate(id);
518     if(!xmlSecTransformIsValid(transform)) {
519         xmlSecInternalError("xmlSecTransformCreate",
520                             xmlSecTransformKlassGetName(id));
521         return(NULL);
522     }
523 
524     ret = xmlSecTransformCtxAppend(ctx, transform);
525     if(ret < 0) {
526         xmlSecInternalError("xmlSecTransformCtxAppend",
527                             xmlSecTransformKlassGetName(id));
528         xmlSecTransformDestroy(transform);
529         return(NULL);
530     }
531 
532     return(transform);
533 }
534 
535 /**
536  * xmlSecTransformCtxCreateAndPrepend:
537  * @ctx:                the pointer to transforms chain processing context.
538  * @id:                 the new transform klass.
539  *
540  * Creates new transform and connects it to the end of the chain of
541  * transforms in the @ctx (see #xmlSecTransformConnect function for details).
542  *
543  * Returns: pointer to newly created transform or NULL if an error occurs.
544  */
545 xmlSecTransformPtr
xmlSecTransformCtxCreateAndPrepend(xmlSecTransformCtxPtr ctx,xmlSecTransformId id)546 xmlSecTransformCtxCreateAndPrepend(xmlSecTransformCtxPtr ctx, xmlSecTransformId id) {
547     xmlSecTransformPtr transform;
548     int ret;
549 
550     xmlSecAssert2(ctx != NULL, NULL);
551     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL);
552     xmlSecAssert2(id != xmlSecTransformIdUnknown, NULL);
553 
554     transform = xmlSecTransformCreate(id);
555     if(!xmlSecTransformIsValid(transform)) {
556         xmlSecInternalError("xmlSecTransformCreate",
557                             xmlSecTransformKlassGetName(id));
558         return(NULL);
559     }
560 
561     ret = xmlSecTransformCtxPrepend(ctx, transform);
562     if(ret < 0) {
563         xmlSecInternalError("xmlSecTransformCtxPrepend",
564                             xmlSecTransformGetName(transform));
565         xmlSecTransformDestroy(transform);
566         return(NULL);
567     }
568 
569     return(transform);
570 }
571 
572 /**
573  * xmlSecTransformCtxNodeRead:
574  * @ctx:                the pointer to transforms chain processing context.
575  * @node:               the pointer to transform's node.
576  * @usage:              the transform's usage (signature, encryption, etc.).
577  *
578  * Reads the transform from the @node and appends it to the current chain
579  * of transforms in @ctx.
580  *
581  * Returns: pointer to newly created transform or NULL if an error occurs.
582  */
583 xmlSecTransformPtr
xmlSecTransformCtxNodeRead(xmlSecTransformCtxPtr ctx,xmlNodePtr node,xmlSecTransformUsage usage)584 xmlSecTransformCtxNodeRead(xmlSecTransformCtxPtr ctx, xmlNodePtr node,
585                            xmlSecTransformUsage usage) {
586     xmlSecTransformPtr transform;
587     int ret;
588 
589     xmlSecAssert2(ctx != NULL, NULL);
590     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL);
591     xmlSecAssert2(node != NULL, NULL);
592 
593     transform = xmlSecTransformNodeRead(node, usage, ctx);
594     if(transform == NULL) {
595         xmlSecInternalError("xmlSecTransformNodeRead",
596                             xmlSecNodeGetName(node));
597         return(NULL);
598     }
599 
600     ret = xmlSecTransformCtxAppend(ctx, transform);
601     if(ret < 0) {
602         xmlSecInternalError("xmlSecTransformCtxAppend",
603                             xmlSecTransformGetName(transform));
604         xmlSecTransformDestroy(transform);
605         return(NULL);
606     }
607 
608     return(transform);
609 }
610 
611 /**
612  * xmlSecTransformCtxNodesListRead:
613  * @ctx:                the pointer to transforms chain processing context.
614  * @node:               the pointer to <dsig:Transform/> nodes parent node.
615  * @usage:              the transform's usage (signature, encryption, etc.).
616  *
617  * Reads transforms from the <dsig:Transform/> children of the @node and
618  * appends them to the current transforms chain in @ctx object.
619  *
620  * Returns: 0 on success or a negative value otherwise.
621  */
622 int
xmlSecTransformCtxNodesListRead(xmlSecTransformCtxPtr ctx,xmlNodePtr node,xmlSecTransformUsage usage)623 xmlSecTransformCtxNodesListRead(xmlSecTransformCtxPtr ctx, xmlNodePtr node, xmlSecTransformUsage usage) {
624     xmlSecTransformPtr transform;
625     xmlNodePtr cur;
626     int ret;
627 
628     xmlSecAssert2(ctx != NULL, -1);
629     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
630     xmlSecAssert2(node != NULL, -1);
631 
632     cur = xmlSecGetNextElementNode(node->children);
633     while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeTransform, xmlSecDSigNs)) {
634         transform = xmlSecTransformNodeRead(cur, usage, ctx);
635         if(transform == NULL) {
636             xmlSecInternalError("xmlSecTransformNodeRead",
637                                 xmlSecNodeGetName(cur));
638             return(-1);
639         }
640 
641         ret = xmlSecTransformCtxAppend(ctx, transform);
642         if(ret < 0) {
643             xmlSecInternalError("xmlSecTransformCtxAppend",
644                                 xmlSecTransformGetName(transform));
645             xmlSecTransformDestroy(transform);
646             return(-1);
647         }
648         cur = xmlSecGetNextElementNode(cur->next);
649     }
650 
651     if(cur != NULL) {
652         xmlSecUnexpectedNodeError(cur, NULL);
653         return(-1);
654     }
655     return(0);
656 }
657 
658 /**
659  * xmlSecTransformCtxSetUri:
660  * @ctx:                the pointer to transforms chain processing context.
661  * @uri:                the URI.
662  * @hereNode:           the pointer to "here" node required by some
663  *                      XML transforms (may be NULL).
664  *
665  * Parses uri and adds xpointer transforms if required.
666  *
667  * The following examples demonstrate what the URI attribute identifies and
668  * how it is dereferenced
669  * (http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel):
670  *
671  * - URI="http://example.com/bar.xml"
672  * identifies the octets that represent the external resource
673  * 'http://example.com/bar.xml', that is probably an XML document given
674  * its file extension.
675  *
676  * - URI="http://example.com/bar.xml#chapter1"
677  * identifies the element with ID attribute value 'chapter1' of the
678  * external XML resource 'http://example.com/bar.xml', provided as an
679  * octet stream. Again, for the sake of interoperability, the element
680  * identified as 'chapter1' should be obtained using an XPath transform
681  * rather than a URI fragment (barename XPointer resolution in external
682  * resources is not REQUIRED in this specification).
683  *
684  * - URI=""
685  * identifies the node-set (minus any comment nodes) of the XML resource
686  * containing the signature
687  *
688  * - URI="#chapter1"
689  * identifies a node-set containing the element with ID attribute value
690  * 'chapter1' of the XML resource containing the signature. XML Signature
691  * (and its applications) modify this node-set to include the element plus
692  * all descendants including namespaces and attributes -- but not comments.
693  *
694  * Returns: 0 on success or a negative value otherwise.
695  */
696 int
xmlSecTransformCtxSetUri(xmlSecTransformCtxPtr ctx,const xmlChar * uri,xmlNodePtr hereNode)697 xmlSecTransformCtxSetUri(xmlSecTransformCtxPtr ctx, const xmlChar* uri, xmlNodePtr hereNode) {
698     xmlSecNodeSetType nodeSetType = xmlSecNodeSetTree;
699     const xmlChar* xptr;
700     xmlChar* buf = NULL;
701     int useVisa3DHack = 0;
702     int ret;
703 
704     xmlSecAssert2(ctx != NULL, -1);
705     xmlSecAssert2(ctx->uri == NULL, -1);
706     xmlSecAssert2(ctx->xptrExpr == NULL, -1);
707     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
708     xmlSecAssert2(hereNode != NULL, -1);
709 
710     /* check uri */
711     if(xmlSecTransformUriTypeCheck(ctx->enabledUris, uri) != 1) {
712         xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_URI_TYPE, NULL,
713                           "uri=%s", xmlSecErrorsSafeString(uri));
714         return(-1);
715     }
716 
717     /* is it an empty uri? */
718     if((uri == NULL) || (xmlStrlen(uri) == 0)) {
719         return(0);
720     }
721 
722     /* do we have barename or full xpointer? */
723     xptr = xmlStrchr(uri, '#');
724     if(xptr == NULL){
725         ctx->uri = xmlStrdup(uri);
726         if(ctx->uri == NULL) {
727             xmlSecStrdupError(uri, NULL);
728             return(-1);
729         }
730         /* we are done */
731         return(0);
732     } else if(xmlStrcmp(uri, BAD_CAST "#xpointer(/)") == 0) {
733         ctx->xptrExpr = xmlStrdup(uri);
734         if(ctx->xptrExpr == NULL) {
735             xmlSecStrdupError(uri, NULL);
736             return(-1);
737         }
738         /* we are done */
739         return(0);
740     }
741 
742     ctx->uri = xmlStrndup(uri, (int)(xptr - uri));
743     if(ctx->uri == NULL) {
744         xmlSecStrdupError(uri, NULL);
745         return(-1);
746     }
747 
748     ctx->xptrExpr = xmlStrdup(xptr);
749     if(ctx->xptrExpr == NULL) {
750         xmlSecStrdupError(xptr, NULL);
751         return(-1);
752     }
753 
754     /* do we have barename or full xpointer? */
755     xmlSecAssert2(xptr != NULL, -1);
756     if((xmlStrncmp(xptr, BAD_CAST "#xpointer(", 10) == 0) || (xmlStrncmp(xptr, BAD_CAST "#xmlns(", 7) == 0)) {
757         ++xptr;
758         nodeSetType = xmlSecNodeSetTree;
759     } else if((ctx->flags & XMLSEC_TRANSFORMCTX_FLAGS_USE_VISA3D_HACK) != 0) {
760         ++xptr;
761         nodeSetType = xmlSecNodeSetTreeWithoutComments;
762         useVisa3DHack = 1;
763     } else {
764         static const char tmpl[] = "xpointer(id(\'%s\'))";
765         xmlSecSize size;
766 
767         /* we need to add "xpointer(id('..')) because otherwise we have
768          * problems with numeric ("111" and so on) and other "strange" ids */
769         size = xmlStrlen(BAD_CAST tmpl) + xmlStrlen(xptr) + 2;
770         buf = (xmlChar*)xmlMalloc(size * sizeof(xmlChar));
771         if(buf == NULL) {
772             xmlSecMallocError(size * sizeof(xmlChar), NULL);
773             return(-1);
774         }
775         ret = xmlStrPrintf(buf, size, tmpl, xptr + 1);
776         if(ret < 0) {
777             xmlSecXmlError("xmlStrPrintf", NULL);
778              xmlFree(buf);
779              return(-1);
780         }
781         xptr = buf;
782         nodeSetType = xmlSecNodeSetTreeWithoutComments;
783     }
784 
785     if(useVisa3DHack == 0) {
786         xmlSecTransformPtr transform;
787 
788         /* we need to create XPonter transform to execute expr */
789         transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformXPointerId);
790         if(!xmlSecTransformIsValid(transform)) {
791             xmlSecInternalError("xmlSecTransformCtxCreateAndPrepend(xmlSecTransformXPointerId)", NULL);
792             if(buf != NULL) {
793                 xmlFree(buf);
794             }
795             return(-1);
796         }
797 
798         ret = xmlSecTransformXPointerSetExpr(transform, xptr, nodeSetType, hereNode);
799         if(ret < 0) {
800             xmlSecInternalError("xmlSecTransformXPointerSetExpr",
801                                 xmlSecTransformGetName(transform));
802             if(buf != NULL) {
803                 xmlFree(buf);
804             }
805             return(-1);
806         }
807     } else {
808         /* Visa3D protocol doesn't follow XML/XPointer/XMLDSig specs
809          * and allows invalid XPointer expressions (e.g. "#12345") in
810          * the URI attribute.
811          * Since we couldn't evaluate such expressions thru XPath/XPointer
812          * engine, we need to have this hack here
813          */
814         xmlSecTransformPtr transform;
815 
816         transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformVisa3DHackId);
817         if(!xmlSecTransformIsValid(transform)) {
818             xmlSecInternalError("xmlSecTransformCtxCreateAndPrepend(xmlSecTransformVisa3DHackId)", NULL);
819             if(buf != NULL) {
820                 xmlFree(buf);
821             }
822             return(-1);
823         }
824 
825         ret = xmlSecTransformVisa3DHackSetID(transform, xptr);
826         if(ret < 0) {
827             xmlSecInternalError("xmlSecTransformVisa3DHackSetID",
828                                 xmlSecTransformGetName(transform));
829             if(buf != NULL) {
830                 xmlFree(buf);
831             }
832             return(-1);
833         }
834     }
835     if(buf != NULL) {
836         xmlFree(buf);
837     }
838 
839     return(0);
840 }
841 
842 /**
843  * xmlSecTransformCtxPrepare:
844  * @ctx:                the pointer to transforms chain processing context.
845  * @inputDataType:      the expected input type.
846  *
847  * Prepares the transform context for processing data of @inputDataType.
848  *
849  * Returns: 0 on success or a negative value otherwise.
850  */
851 int
xmlSecTransformCtxPrepare(xmlSecTransformCtxPtr ctx,xmlSecTransformDataType inputDataType)852 xmlSecTransformCtxPrepare(xmlSecTransformCtxPtr ctx, xmlSecTransformDataType inputDataType) {
853     xmlSecTransformDataType firstType;
854     xmlSecTransformPtr transform;
855     int ret;
856 
857     xmlSecAssert2(ctx != NULL, -1);
858     xmlSecAssert2(ctx->result == NULL, -1);
859     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
860 
861     /* add binary buffer to store result */
862     transform = xmlSecTransformCtxCreateAndAppend(ctx, xmlSecTransformMemBufId);
863     if(!xmlSecTransformIsValid(transform)) {
864         xmlSecInternalError("xmlSecTransformCtxCreateAndAppend(xmlSecTransformMemBufId)", NULL);
865         return(-1);
866     }
867     ctx->result = xmlSecTransformMemBufGetBuffer(transform);
868     if(ctx->result == NULL) {
869         xmlSecInternalError("xmlSecTransformMemBufGetBuffer(xmlSecTransformMemBufId)",
870                             xmlSecTransformGetName(transform));
871         return(-1);
872     }
873 
874     firstType = xmlSecTransformGetDataType(ctx->first, xmlSecTransformModePush, ctx);
875     if(((firstType & xmlSecTransformDataTypeBin) == 0) &&
876        ((inputDataType & xmlSecTransformDataTypeBin) != 0)) {
877 
878         /* need to add parser transform */
879         transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformXmlParserId);
880         if(transform == NULL) {
881             xmlSecInternalError("xmlSecTransformCtxCreateAndPrepend(xmlSecTransformXmlParserId)", NULL);
882             return(-1);
883         }
884     } else if(((firstType & xmlSecTransformDataTypeXml) == 0) &&
885        ((inputDataType & xmlSecTransformDataTypeXml) != 0)) {
886 
887         /* need to add c14n transform */
888         transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformInclC14NId);
889         if(transform == NULL) {
890             xmlSecInternalError("xmlSecTransformCtxCreateAndPrepend(xmlSecTransformInclC14NId)", NULL);
891             return(-1);
892         }
893     }
894 
895     /* finally let application a chance to verify that it's ok to execte
896      * this transforms chain */
897     if(ctx->preExecCallback != NULL) {
898         ret = (ctx->preExecCallback)(ctx);
899         if(ret < 0) {
900             xmlSecInternalError("ctx->preExecCallback", NULL);
901             return(-1);
902         }
903     }
904 
905     ctx->status = xmlSecTransformStatusWorking;
906     return(0);
907 }
908 
909 /**
910  * xmlSecTransformCtxBinaryExecute:
911  * @ctx:                the pointer to transforms chain processing context.
912  * @data:               the input binary data buffer.
913  * @dataSize:           the input data size.
914  *
915  * Processes binary data using transforms chain in the @ctx.
916  *
917  * Returns: 0 on success or a negative value otherwise.
918  */
919 int
xmlSecTransformCtxBinaryExecute(xmlSecTransformCtxPtr ctx,const xmlSecByte * data,xmlSecSize dataSize)920 xmlSecTransformCtxBinaryExecute(xmlSecTransformCtxPtr ctx,
921                                 const xmlSecByte* data, xmlSecSize dataSize) {
922     int ret;
923 
924     xmlSecAssert2(ctx != NULL, -1);
925     xmlSecAssert2(ctx->result == NULL, -1);
926     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
927     xmlSecAssert2(data != NULL, -1);
928     xmlSecAssert2(dataSize > 0, -1);
929 
930     /* we should not have uri stored in ctx */
931     xmlSecAssert2(ctx->uri == NULL, -1);
932 
933     ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeBin);
934     if(ret < 0) {
935         xmlSecInternalError("xmlSecTransformCtxPrepare(TypeBin)", NULL);
936         return(-1);
937     }
938 
939     ret = xmlSecTransformPushBin(ctx->first, data, dataSize, 1, ctx);
940     if(ret < 0) {
941         xmlSecInternalError2("xmlSecTransformPushBin", NULL,
942                              "dataSize=%d", dataSize);
943         return(-1);
944     }
945 
946     ctx->status = xmlSecTransformStatusFinished;
947     return(0);
948 }
949 
950 /**
951  * xmlSecTransformCtxUriExecute:
952  * @ctx:                the pointer to transforms chain processing context.
953  * @uri:                the URI.
954  *
955  * Process binary data from the URI using transforms chain in @ctx.
956  *
957  * Returns: 0 on success or a negative value otherwise.
958  */
959 int
xmlSecTransformCtxUriExecute(xmlSecTransformCtxPtr ctx,const xmlChar * uri)960 xmlSecTransformCtxUriExecute(xmlSecTransformCtxPtr ctx, const xmlChar* uri) {
961     xmlSecTransformPtr uriTransform;
962     int ret;
963 
964     xmlSecAssert2(ctx != NULL, -1);
965     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
966     xmlSecAssert2(uri != NULL, -1);
967 
968     /* we should not execute transform for a different uri */
969     xmlSecAssert2((ctx->uri == NULL) || (uri == ctx->uri) || xmlStrEqual(uri, ctx->uri), -1);
970 
971     uriTransform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformInputURIId);
972     if(uriTransform == NULL) {
973         xmlSecInternalError("xmlSecTransformCtxCreateAndPrepend(xmlSecTransformInputURIId)", NULL);
974         return(-1);
975     }
976 
977     ret = xmlSecTransformInputURIOpen(uriTransform, uri);
978     if(ret < 0) {
979         xmlSecInternalError2("xmlSecTransformInputURIOpen", NULL,
980                             "uri=%s", xmlSecErrorsSafeString(uri));
981         return(-1);
982     }
983 
984     /* we do not need to do something special for this transform */
985     ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeUnknown);
986     if(ret < 0) {
987         xmlSecInternalError("xmlSecTransformCtxPrepare(TypeUnknown)", NULL);
988         return(-1);
989     }
990 
991     /* Now we have a choice: we either can push from first transform or pop
992      * from last. Our C14N transforms prefers push, so push data!
993      */
994     ret = xmlSecTransformPump(uriTransform, uriTransform->next, ctx);
995     if(ret < 0) {
996         xmlSecInternalError("xmlSecTransformPump",
997                             xmlSecTransformGetName(uriTransform));
998         return(-1);
999     }
1000 
1001     /* Close to free up file handle */
1002     ret = xmlSecTransformInputURIClose(uriTransform);
1003     if(ret < 0) {
1004         xmlSecInternalError("xmlSecTransformInputURIClose",
1005                             xmlSecTransformGetName(uriTransform));
1006         return(-1);
1007     }
1008 
1009     /* Done */
1010     ctx->status = xmlSecTransformStatusFinished;
1011     return(0);
1012 }
1013 
1014 /**
1015  * xmlSecTransformCtxXmlExecute:
1016  * @ctx:                the pointer to transforms chain processing context.
1017  * @nodes:              the input node set.
1018  *
1019  * Process @nodes using transforms in the transforms chain in @ctx.
1020  *
1021  * Returns: 0 on success or a negative value otherwise.
1022  */
1023 int
xmlSecTransformCtxXmlExecute(xmlSecTransformCtxPtr ctx,xmlSecNodeSetPtr nodes)1024 xmlSecTransformCtxXmlExecute(xmlSecTransformCtxPtr ctx, xmlSecNodeSetPtr nodes) {
1025     int ret;
1026 
1027     xmlSecAssert2(ctx != NULL, -1);
1028     xmlSecAssert2(ctx->result == NULL, -1);
1029     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
1030     xmlSecAssert2(nodes != NULL, -1);
1031 
1032     xmlSecAssert2((ctx->uri == NULL) || (xmlStrlen(ctx->uri) == 0), -1);
1033 
1034     ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeXml);
1035     if(ret < 0) {
1036         xmlSecInternalError("xmlSecTransformCtxPrepare(TypeXml)", NULL);
1037         return(-1);
1038     }
1039 
1040     /* it's better to do push than pop because all XML transform
1041      * just don't care and c14n likes push more than pop */
1042     ret = xmlSecTransformPushXml(ctx->first, nodes, ctx);
1043     if(ret < 0) {
1044         xmlSecInternalError("xmlSecTransformPushXml",
1045                             xmlSecTransformGetName(ctx->first));
1046         return(-1);
1047     }
1048 
1049     ctx->status = xmlSecTransformStatusFinished;
1050     return(0);
1051 }
1052 
1053 /**
1054  * xmlSecTransformCtxExecute:
1055  * @ctx:                the pointer to transforms chain processing context.
1056  * @doc:                the pointer to input document.
1057  *
1058  * Executes transforms chain in @ctx.
1059  *
1060  * Returns: 0 on success or a negative value otherwise.
1061  */
1062 int
xmlSecTransformCtxExecute(xmlSecTransformCtxPtr ctx,xmlDocPtr doc)1063 xmlSecTransformCtxExecute(xmlSecTransformCtxPtr ctx, xmlDocPtr doc) {
1064     int ret;
1065 
1066     xmlSecAssert2(ctx != NULL, -1);
1067     xmlSecAssert2(ctx->result == NULL, -1);
1068     xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
1069     xmlSecAssert2(doc != NULL, -1);
1070 
1071     if((ctx->uri == NULL) || (xmlStrlen(ctx->uri) == 0)) {
1072         xmlSecNodeSetPtr nodes;
1073 
1074         if((ctx->xptrExpr != NULL) && (xmlStrlen(ctx->xptrExpr) > 0)){
1075             /* our xpointer transform takes care of providing correct nodes set */
1076             nodes = xmlSecNodeSetCreate(doc, NULL, xmlSecNodeSetNormal);
1077             if(nodes == NULL) {
1078                 xmlSecInternalError("xmlSecNodeSetCreate", NULL);
1079                 return(-1);
1080             }
1081 
1082         } else {
1083             /* we do not want to have comments for empty URI */
1084             nodes = xmlSecNodeSetGetChildren(doc, NULL, 0, 0);
1085             if(nodes == NULL) {
1086                 xmlSecInternalError("xmlSecNodeSetGetChildren", NULL);
1087                 return(-1);
1088             }
1089         }
1090         ret = xmlSecTransformCtxXmlExecute(ctx, nodes);
1091         if(ret < 0) {
1092             xmlSecInternalError("xmlSecTransformCtxXmlExecute", NULL);
1093             xmlSecNodeSetDestroy(nodes);
1094             return(-1);
1095         }
1096         /* TODO: don't destroy nodes here */
1097         xmlSecNodeSetDestroy(nodes);
1098     } else {
1099         ret = xmlSecTransformCtxUriExecute(ctx, ctx->uri);
1100         if(ret < 0) {
1101             xmlSecInternalError("xmlSecTransformCtxUriExecute", NULL);
1102             return(-1);
1103         }
1104     }
1105 
1106     return(0);
1107 }
1108 
1109 /**
1110  * xmlSecTransformCtxDebugDump:
1111  * @ctx:                the pointer to transforms chain processing context.
1112  * @output:             the pointer to output FILE.
1113  *
1114  * Prints transforms context debug information to @output.
1115  */
1116 void
xmlSecTransformCtxDebugDump(xmlSecTransformCtxPtr ctx,FILE * output)1117 xmlSecTransformCtxDebugDump(xmlSecTransformCtxPtr ctx, FILE* output) {
1118     xmlSecTransformPtr transform;
1119 
1120     xmlSecAssert(ctx != NULL);
1121     xmlSecAssert(output != NULL);
1122 
1123     fprintf(output, "== TRANSFORMS CTX (status=%d)\n", ctx->status);
1124 
1125     fprintf(output, "== flags: 0x%08x\n", ctx->flags);
1126     fprintf(output, "== flags2: 0x%08x\n", ctx->flags2);
1127     if(xmlSecPtrListGetSize(&(ctx->enabledTransforms)) > 0) {
1128         fprintf(output, "== enabled transforms: ");
1129         xmlSecTransformIdListDebugDump(&(ctx->enabledTransforms), output);
1130     } else {
1131         fprintf(output, "== enabled transforms: all\n");
1132     }
1133 
1134     fprintf(output, "=== uri: %s\n",
1135             (ctx->uri != NULL) ? ctx->uri : BAD_CAST "NULL");
1136     fprintf(output, "=== uri xpointer expr: %s\n",
1137             (ctx->xptrExpr != NULL) ? ctx->xptrExpr : BAD_CAST "NULL");
1138     for(transform = ctx->first; transform != NULL; transform = transform->next) {
1139         xmlSecTransformDebugDump(transform, output);
1140     }
1141 }
1142 
1143 /**
1144  * xmlSecTransformCtxDebugXmlDump:
1145  * @ctx:                the pointer to transforms chain processing context.
1146  * @output:             the pointer to output FILE.
1147  *
1148  * Prints transforms context debug information to @output in XML format.
1149  */
1150 void
xmlSecTransformCtxDebugXmlDump(xmlSecTransformCtxPtr ctx,FILE * output)1151 xmlSecTransformCtxDebugXmlDump(xmlSecTransformCtxPtr ctx, FILE* output) {
1152     xmlSecTransformPtr transform;
1153 
1154     xmlSecAssert(ctx != NULL);
1155     xmlSecAssert(output != NULL);
1156 
1157     fprintf(output, "<TransformCtx status=\"%d\">\n", ctx->status);
1158 
1159     fprintf(output, "<Flags>%08x</Flags>\n", ctx->flags);
1160     fprintf(output, "<Flags2>%08x</Flags2>\n", ctx->flags2);
1161     if(xmlSecPtrListGetSize(&(ctx->enabledTransforms)) > 0) {
1162         fprintf(output, "<EnabledTransforms>\n");
1163         xmlSecTransformIdListDebugXmlDump(&(ctx->enabledTransforms), output);
1164         fprintf(output, "</EnabledTransforms>\n");
1165     } else {
1166         fprintf(output, "<EnabledTransforms>all</EnabledTransforms>\n");
1167     }
1168 
1169 
1170     fprintf(output, "<Uri>");
1171     xmlSecPrintXmlString(output, ctx->uri);
1172     fprintf(output, "</Uri>\n");
1173 
1174     fprintf(output, "<UriXPointer>");
1175     xmlSecPrintXmlString(output, ctx->xptrExpr);
1176     fprintf(output, "</UriXPointer>\n");
1177 
1178     for(transform = ctx->first; transform != NULL; transform = transform->next) {
1179         xmlSecTransformDebugXmlDump(transform, output);
1180     }
1181     fprintf(output, "</TransformCtx>\n");
1182 }
1183 
1184 /**************************************************************************
1185  *
1186  * xmlSecTransform
1187  *
1188  *************************************************************************/
1189 /**
1190  * xmlSecTransformCreate:
1191  * @id:                 the transform id to create.
1192  *
1193  * Creates new transform of the @id klass. The caller is responsible for
1194  * destroying returned transform using #xmlSecTransformDestroy function.
1195  *
1196  * Returns: pointer to newly created transform or NULL if an error occurs.
1197  */
1198 xmlSecTransformPtr
xmlSecTransformCreate(xmlSecTransformId id)1199 xmlSecTransformCreate(xmlSecTransformId id) {
1200     xmlSecTransformPtr transform;
1201     int ret;
1202 
1203     xmlSecAssert2(id != NULL, NULL);
1204     xmlSecAssert2(id->klassSize >= sizeof(xmlSecTransformKlass), NULL);
1205     xmlSecAssert2(id->objSize >= sizeof(xmlSecTransform), NULL);
1206     xmlSecAssert2(id->name != NULL, NULL);
1207 
1208     /* Allocate a new xmlSecTransform and fill the fields. */
1209     transform = (xmlSecTransformPtr)xmlMalloc(id->objSize);
1210     if(transform == NULL) {
1211         xmlSecMallocError(id->objSize, NULL);
1212         return(NULL);
1213     }
1214     memset(transform, 0, id->objSize);
1215     transform->id = id;
1216 
1217     if(id->initialize != NULL) {
1218         ret = (id->initialize)(transform);
1219         if(ret < 0) {
1220             xmlSecInternalError("id->initialize",
1221                                 xmlSecTransformGetName(transform));
1222             xmlSecTransformDestroy(transform);
1223             return(NULL);
1224         }
1225     }
1226 
1227     ret = xmlSecBufferInitialize(&(transform->inBuf), 0);
1228     if(ret < 0) {
1229         xmlSecInternalError("xmlSecBufferInitialize",
1230                             xmlSecTransformGetName(transform));
1231         xmlSecTransformDestroy(transform);
1232         return(NULL);
1233     }
1234 
1235     ret = xmlSecBufferInitialize(&(transform->outBuf), 0);
1236     if(ret < 0) {
1237         xmlSecInternalError("xmlSecBufferInitialize",
1238                             xmlSecTransformGetName(transform));
1239         xmlSecTransformDestroy(transform);
1240         return(NULL);
1241     }
1242 
1243     return(transform);
1244 }
1245 
1246 /**
1247  * xmlSecTransformDestroy:
1248  * @transform:          the pointer to transform.
1249  *
1250  * Destroys transform created with #xmlSecTransformCreate function.
1251  */
1252 void
xmlSecTransformDestroy(xmlSecTransformPtr transform)1253 xmlSecTransformDestroy(xmlSecTransformPtr transform) {
1254     xmlSecAssert(xmlSecTransformIsValid(transform));
1255     xmlSecAssert(transform->id->objSize > 0);
1256 
1257     /* first need to remove ourselves from chain */
1258     xmlSecTransformRemove(transform);
1259 
1260     xmlSecBufferFinalize(&(transform->inBuf));
1261     xmlSecBufferFinalize(&(transform->outBuf));
1262 
1263     /* we never destroy input nodes, output nodes
1264      * are destroyed if and only if they are different
1265      * from input nodes
1266      */
1267     if((transform->outNodes != NULL) && (transform->outNodes != transform->inNodes)) {
1268         xmlSecNodeSetDestroy(transform->outNodes);
1269     }
1270     if(transform->id->finalize != NULL) {
1271         (transform->id->finalize)(transform);
1272     }
1273     memset(transform, 0, transform->id->objSize);
1274     xmlFree(transform);
1275 }
1276 
1277 /**
1278  * xmlSecTransformNodeRead:
1279  * @node:               the pointer to the transform's node.
1280  * @usage:              the transform usage (signature, encryption, ...).
1281  * @transformCtx:       the transform's chain processing context.
1282  *
1283  * Reads transform from the @node as follows:
1284  *
1285  *    1) reads "Algorithm" attribute;
1286  *
1287  *    2) checks the lists of known and allowed transforms;
1288  *
1289  *    3) calls transform's create method;
1290  *
1291  *    4) calls transform's read transform node method.
1292  *
1293  * Returns: pointer to newly created transform or NULL if an error occurs.
1294  */
1295 xmlSecTransformPtr
xmlSecTransformNodeRead(xmlNodePtr node,xmlSecTransformUsage usage,xmlSecTransformCtxPtr transformCtx)1296 xmlSecTransformNodeRead(xmlNodePtr node, xmlSecTransformUsage usage, xmlSecTransformCtxPtr transformCtx) {
1297     xmlSecTransformPtr transform;
1298     xmlSecTransformId id;
1299     xmlChar *href;
1300     int ret;
1301 
1302     xmlSecAssert2(node != NULL, NULL);
1303     xmlSecAssert2(transformCtx != NULL, NULL);
1304 
1305     href = xmlGetProp(node, xmlSecAttrAlgorithm);
1306     if(href == NULL) {
1307         xmlSecInvalidNodeAttributeError(node, xmlSecAttrAlgorithm,
1308                                         NULL, "empty");
1309         return(NULL);
1310     }
1311 
1312     id = xmlSecTransformIdListFindByHref(xmlSecTransformIdsGet(), href, usage);
1313     if(id == xmlSecTransformIdUnknown) {
1314         xmlSecInternalError2("xmlSecTransformIdListFindByHref", NULL,
1315                              "href=%s", xmlSecErrorsSafeString(href));
1316         xmlFree(href);
1317         return(NULL);
1318     }
1319 
1320     /* check with enabled transforms list */
1321     if((xmlSecPtrListGetSize(&(transformCtx->enabledTransforms)) > 0) &&
1322        (xmlSecTransformIdListFind(&(transformCtx->enabledTransforms), id) != 1)) {
1323         xmlSecOtherError2(XMLSEC_ERRORS_R_TRANSFORM_DISABLED,
1324                           xmlSecTransformKlassGetName(id),
1325                           "href=%s", xmlSecErrorsSafeString(href));
1326         xmlFree(href);
1327         return(NULL);
1328     }
1329 
1330     transform = xmlSecTransformCreate(id);
1331     if(!xmlSecTransformIsValid(transform)) {
1332         xmlSecInternalError("xmlSecTransformCreate(id)",
1333                             xmlSecTransformKlassGetName(id));
1334         xmlFree(href);
1335         return(NULL);
1336     }
1337 
1338     if(transform->id->readNode != NULL) {
1339         ret = transform->id->readNode(transform, node, transformCtx);
1340         if(ret < 0) {
1341             xmlSecInternalError("readNode",
1342                                 xmlSecTransformGetName(transform));
1343             xmlSecTransformDestroy(transform);
1344             xmlFree(href);
1345             return(NULL);
1346         }
1347     }
1348 
1349     /* finally remember the transform node */
1350     transform->hereNode = node;
1351     xmlFree(href);
1352     return(transform);
1353 }
1354 
1355 /**
1356  * xmlSecTransformPump:
1357  * @left:               the source pumping transform.
1358  * @right:              the destination pumping transform.
1359  * @transformCtx:       the transform's chain processing context.
1360  *
1361  * Pops data from @left transform and pushes to @right transform until
1362  * no more data is available.
1363  *
1364  * Returns: 0 on success or a negative value if an error occurs.
1365  */
1366 int
xmlSecTransformPump(xmlSecTransformPtr left,xmlSecTransformPtr right,xmlSecTransformCtxPtr transformCtx)1367 xmlSecTransformPump(xmlSecTransformPtr left, xmlSecTransformPtr right, xmlSecTransformCtxPtr transformCtx) {
1368     xmlSecTransformDataType leftType;
1369     xmlSecTransformDataType rightType;
1370     int ret;
1371 
1372     xmlSecAssert2(xmlSecTransformIsValid(left), -1);
1373     xmlSecAssert2(xmlSecTransformIsValid(right), -1);
1374     xmlSecAssert2(transformCtx != NULL, -1);
1375 
1376     leftType = xmlSecTransformGetDataType(left, xmlSecTransformModePop, transformCtx);
1377     rightType = xmlSecTransformGetDataType(right, xmlSecTransformModePush, transformCtx);
1378 
1379     if(((leftType & xmlSecTransformDataTypeXml) != 0) &&
1380        ((rightType & xmlSecTransformDataTypeXml) != 0)) {
1381 
1382        xmlSecNodeSetPtr nodes = NULL;
1383 
1384        ret = xmlSecTransformPopXml(left, &nodes, transformCtx);
1385        if(ret < 0) {
1386             xmlSecInternalError("xmlSecTransformPopXml",
1387                                 xmlSecTransformGetName(left));
1388             return(-1);
1389        }
1390 
1391        ret = xmlSecTransformPushXml(right, nodes, transformCtx);
1392        if(ret < 0) {
1393             xmlSecInternalError("xmlSecTransformPushXml",
1394                                 xmlSecTransformGetName(right));
1395             return(-1);
1396        }
1397     }  else if(((leftType & xmlSecTransformDataTypeBin) != 0) &&
1398                ((rightType & xmlSecTransformDataTypeBin) != 0)) {
1399         xmlSecByte buf[XMLSEC_TRANSFORM_BINARY_CHUNK];
1400         xmlSecSize bufSize;
1401         int final;
1402 
1403         do {
1404             ret = xmlSecTransformPopBin(left, buf, sizeof(buf), &bufSize, transformCtx);
1405             if(ret < 0) {
1406                 xmlSecInternalError("xmlSecTransformPopBin",
1407                                     xmlSecTransformGetName(left));
1408                 return(-1);
1409             }
1410             final = (bufSize == 0) ? 1 : 0;
1411             ret = xmlSecTransformPushBin(right, buf, bufSize, final, transformCtx);
1412             if(ret < 0) {
1413                 xmlSecInternalError("xmlSecTransformPushBin",
1414                                     xmlSecTransformGetName(right));
1415                 return(-1);
1416             }
1417         } while(final == 0);
1418     } else {
1419         xmlSecInvalidTransfromError2(left,
1420                     "transforms input/output data formats do not match, right transform=\"%s\"",
1421                     xmlSecErrorsSafeString(xmlSecTransformGetName(right)));
1422     }
1423     return(0);
1424 }
1425 
1426 
1427 /**
1428  * xmlSecTransformSetKey:
1429  * @transform:          the pointer to transform.
1430  * @key:                the pointer to key.
1431  *
1432  * Sets the transform's key.
1433  *
1434  * Returns: 0 on success or a negative value otherwise.
1435  */
1436 int
xmlSecTransformSetKey(xmlSecTransformPtr transform,xmlSecKeyPtr key)1437 xmlSecTransformSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
1438     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1439     xmlSecAssert2(key != NULL, -1);
1440 
1441     if(transform->id->setKey != NULL) {
1442         return((transform->id->setKey)(transform, key));
1443     }
1444     return(0);
1445 }
1446 
1447 /**
1448  * xmlSecTransformSetKeyReq:
1449  * @transform:          the pointer to transform.
1450  * @keyReq:             the pointer to keys requirements object.
1451  *
1452  * Sets the key requirements for @transform in the @keyReq.
1453  *
1454  * Returns: 0 on success or a negative value otherwise.
1455  */
1456 int
xmlSecTransformSetKeyReq(xmlSecTransformPtr transform,xmlSecKeyReqPtr keyReq)1457 xmlSecTransformSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) {
1458     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1459     xmlSecAssert2(keyReq != NULL, -1);
1460 
1461     keyReq->keyId       = xmlSecKeyDataIdUnknown;
1462     keyReq->keyType     = xmlSecKeyDataTypeUnknown;
1463     keyReq->keyUsage    = xmlSecKeyUsageAny;
1464     keyReq->keyBitsSize = 0;
1465 
1466     if(transform->id->setKeyReq != NULL) {
1467         return((transform->id->setKeyReq)(transform, keyReq));
1468     }
1469     return(0);
1470 }
1471 
1472 /**
1473  * xmlSecTransformVerify:
1474  * @transform:          the pointer to transform.
1475  * @data:               the binary data for verification.
1476  * @dataSize:           the data size.
1477  * @transformCtx:       the transform's chain processing context.
1478  *
1479  * Verifies the data with transform's processing results
1480  * (for digest, HMAC and signature transforms). The verification
1481  * result is stored in the #status member of #xmlSecTransform object.
1482  *
1483  * Returns: 0 on success or a negative value if an error occurs.
1484  */
1485 int
xmlSecTransformVerify(xmlSecTransformPtr transform,const xmlSecByte * data,xmlSecSize dataSize,xmlSecTransformCtxPtr transformCtx)1486 xmlSecTransformVerify(xmlSecTransformPtr transform, const xmlSecByte* data,
1487                     xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx) {
1488     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1489     xmlSecAssert2(transform->id->verify != NULL, -1);
1490     xmlSecAssert2(transformCtx != NULL, -1);
1491 
1492     return((transform->id->verify)(transform, data, dataSize, transformCtx));
1493 }
1494 
1495 /**
1496  * xmlSecTransformVerifyNodeContent:
1497  * @transform:          the pointer to transform.
1498  * @node:               the pointer to node.
1499  * @transformCtx:       the transform's chain processing context.
1500  *
1501  * Gets the @node content, base64 decodes it and calls #xmlSecTransformVerify
1502  * function to verify binary results.
1503  *
1504  * Returns: 0 on success or a negative value if an error occurs.
1505  */
1506 int
xmlSecTransformVerifyNodeContent(xmlSecTransformPtr transform,xmlNodePtr node,xmlSecTransformCtxPtr transformCtx)1507 xmlSecTransformVerifyNodeContent(xmlSecTransformPtr transform, xmlNodePtr node,
1508                                  xmlSecTransformCtxPtr transformCtx) {
1509     xmlSecBuffer buffer;
1510     int ret;
1511 
1512     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1513     xmlSecAssert2(node != NULL, -1);
1514     xmlSecAssert2(transformCtx != NULL, -1);
1515 
1516     ret = xmlSecBufferInitialize(&buffer, 0);
1517     if(ret < 0) {
1518         xmlSecInternalError("xmlSecBufferInitialize",
1519                             xmlSecTransformGetName(transform));
1520         return(-1);
1521     }
1522 
1523     ret = xmlSecBufferBase64NodeContentRead(&buffer, node);
1524     if((ret < 0) || (xmlSecBufferGetData(&buffer) == NULL)) {
1525         xmlSecInternalError("xmlSecBufferBase64NodeContentRead",
1526                             xmlSecTransformGetName(transform));
1527         xmlSecBufferFinalize(&buffer);
1528         return(-1);
1529     }
1530 
1531     ret = xmlSecTransformVerify(transform, xmlSecBufferGetData(&buffer),
1532                                 xmlSecBufferGetSize(&buffer), transformCtx);
1533     if(ret < 0) {
1534         xmlSecInternalError("xmlSecTransformVerify",
1535                             xmlSecTransformGetName(transform));
1536         xmlSecBufferFinalize(&buffer);
1537         return(-1);
1538     }
1539 
1540     xmlSecBufferFinalize(&buffer);
1541     return(0);
1542 }
1543 
1544 /**
1545  * xmlSecTransformGetDataType:
1546  * @transform:          the pointer to transform.
1547  * @mode:               the data mode (push or pop).
1548  * @transformCtx:       the transform's chain processing context.
1549  *
1550  * Gets transform input (@mode is "push") or output (@mode is "pop") data
1551  * type (binary or XML).
1552  *
1553  * Returns: the transform's data type for the @mode operation.
1554  */
1555 xmlSecTransformDataType
xmlSecTransformGetDataType(xmlSecTransformPtr transform,xmlSecTransformMode mode,xmlSecTransformCtxPtr transformCtx)1556 xmlSecTransformGetDataType(xmlSecTransformPtr transform, xmlSecTransformMode mode,
1557                     xmlSecTransformCtxPtr transformCtx) {
1558     xmlSecAssert2(xmlSecTransformIsValid(transform), xmlSecTransformDataTypeUnknown);
1559     xmlSecAssert2(transform->id->getDataType != NULL, xmlSecTransformDataTypeUnknown);
1560 
1561     return((transform->id->getDataType)(transform, mode, transformCtx));
1562 }
1563 
1564 /**
1565  * xmlSecTransformPushBin:
1566  * @transform:          the pointer to transform object.
1567  * @data:               the input binary data,
1568  * @dataSize:           the input data size.
1569  * @final:              the flag: if set to 1 then it's the last
1570  *                      data chunk.
1571  * @transformCtx:       the pointer to transform context object.
1572  *
1573  * Process binary @data and pushes results to next transform.
1574  *
1575  * Returns: 0 on success or a negative value if an error occurs.
1576  */
1577 int
xmlSecTransformPushBin(xmlSecTransformPtr transform,const xmlSecByte * data,xmlSecSize dataSize,int final,xmlSecTransformCtxPtr transformCtx)1578 xmlSecTransformPushBin(xmlSecTransformPtr transform, const xmlSecByte* data,
1579                     xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) {
1580     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1581     xmlSecAssert2(transform->id->pushBin != NULL, -1);
1582     xmlSecAssert2(transformCtx != NULL, -1);
1583 
1584     return((transform->id->pushBin)(transform, data, dataSize, final, transformCtx));
1585 }
1586 
1587 /**
1588  * xmlSecTransformPopBin:
1589  * @transform:          the pointer to transform object.
1590  * @data:               the buffer to store result data.
1591  * @maxDataSize:        the size of the buffer #data.
1592  * @dataSize:           the pointer to returned data size.
1593  * @transformCtx:       the pointer to transform context object.
1594  *
1595  * Pops data from previous transform in the chain, processes data and
1596  * returns result in the @data buffer. The size of returned data is
1597  * placed in the @dataSize.
1598  *
1599  * Returns: 0 on success or a negative value if an error occurs.
1600  */
1601 int
xmlSecTransformPopBin(xmlSecTransformPtr transform,xmlSecByte * data,xmlSecSize maxDataSize,xmlSecSize * dataSize,xmlSecTransformCtxPtr transformCtx)1602 xmlSecTransformPopBin(xmlSecTransformPtr transform, xmlSecByte* data,
1603                     xmlSecSize maxDataSize, xmlSecSize* dataSize, xmlSecTransformCtxPtr transformCtx) {
1604     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1605     xmlSecAssert2(transform->id->popBin != NULL, -1);
1606     xmlSecAssert2(data != NULL, -1);
1607     xmlSecAssert2(dataSize != NULL, -1);
1608     xmlSecAssert2(transformCtx != NULL, -1);
1609 
1610     return((transform->id->popBin)(transform, data, maxDataSize, dataSize, transformCtx));
1611 }
1612 
1613 /**
1614  * xmlSecTransformPushXml:
1615  * @transform:          the pointer to transform object.
1616  * @nodes:              the input nodes.
1617  * @transformCtx:       the pointer to transform context object.
1618  *
1619  * Processes @nodes and pushes result to the next transform in the chain.
1620  *
1621  * Returns: 0 on success or a negative value if an error occurs.
1622  */
1623 int
xmlSecTransformPushXml(xmlSecTransformPtr transform,xmlSecNodeSetPtr nodes,xmlSecTransformCtxPtr transformCtx)1624 xmlSecTransformPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes,
1625                     xmlSecTransformCtxPtr transformCtx) {
1626     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1627     xmlSecAssert2(transform->id->pushXml != NULL, -1);
1628     xmlSecAssert2(transformCtx != NULL, -1);
1629 
1630     return((transform->id->pushXml)(transform, nodes, transformCtx));
1631 }
1632 
1633 /**
1634  * xmlSecTransformPopXml:
1635  * @transform:          the pointer to transform object.
1636  * @nodes:              the pointer to store popinter to result nodes.
1637  * @transformCtx:       the pointer to transform context object.
1638  *
1639  * Pops data from previous transform in the chain, processes the data and
1640  * returns result in @nodes.
1641  *
1642  * Returns: 0 on success or a negative value if an error occurs.
1643  */
1644 int
xmlSecTransformPopXml(xmlSecTransformPtr transform,xmlSecNodeSetPtr * nodes,xmlSecTransformCtxPtr transformCtx)1645 xmlSecTransformPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes,
1646                     xmlSecTransformCtxPtr transformCtx) {
1647     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1648     xmlSecAssert2(transform->id->popXml != NULL, -1);
1649     xmlSecAssert2(transformCtx != NULL, -1);
1650 
1651     return((transform->id->popXml)(transform, nodes, transformCtx));
1652 }
1653 
1654 /**
1655  * xmlSecTransformExecute:
1656  * @transform:          the pointer to transform.
1657  * @last:               the flag: if set to 1 then it's the last data chunk.
1658  * @transformCtx:       the transform's chain processing context.
1659  *
1660  * Executes transform (used by default popBin/pushBin/popXml/pushXml methods).
1661  *
1662  * Returns: 0 on success or a negative value if an error occurs.
1663  */
1664 int
xmlSecTransformExecute(xmlSecTransformPtr transform,int last,xmlSecTransformCtxPtr transformCtx)1665 xmlSecTransformExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
1666     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1667     xmlSecAssert2(transform->id->execute != NULL, -1);
1668     xmlSecAssert2(transformCtx != NULL, -1);
1669 
1670     return((transform->id->execute)(transform, last, transformCtx));
1671 }
1672 
1673 /**
1674  * xmlSecTransformDebugDump:
1675  * @transform:          the pointer to transform.
1676  * @output:             the pointer to output FILE.
1677  *
1678  * Prints transform's debug information to @output.
1679  */
1680 void
xmlSecTransformDebugDump(xmlSecTransformPtr transform,FILE * output)1681 xmlSecTransformDebugDump(xmlSecTransformPtr transform, FILE* output) {
1682     xmlSecAssert(xmlSecTransformIsValid(transform));
1683     xmlSecAssert(output != NULL);
1684 
1685     fprintf(output, "=== Transform: %s (href=%s)\n",
1686                 xmlSecErrorsSafeString(transform->id->name),
1687                 xmlSecErrorsSafeString(transform->id->href));
1688 }
1689 
1690 /**
1691  * xmlSecTransformDebugXmlDump:
1692  * @transform:          the pointer to transform.
1693  * @output:             the pointer to output FILE.
1694  *
1695  * Prints transform's debug information to @output in XML format.
1696  */
1697 void
xmlSecTransformDebugXmlDump(xmlSecTransformPtr transform,FILE * output)1698 xmlSecTransformDebugXmlDump(xmlSecTransformPtr transform, FILE* output) {
1699     xmlSecAssert(xmlSecTransformIsValid(transform));
1700     xmlSecAssert(output != NULL);
1701 
1702     fprintf(output, "<Transform name=\"");
1703     xmlSecPrintXmlString(output,transform->id->name);
1704     fprintf(output, "\" href=\"");
1705     xmlSecPrintXmlString(output, transform->id->href);
1706     fprintf(output, "\" />\n");
1707 }
1708 
1709 /************************************************************************
1710  *
1711  * Operations on transforms chain
1712  *
1713  ************************************************************************/
1714 /**
1715  * xmlSecTransformConnect:
1716  * @left:               the pointer to left (prev) transform.
1717  * @right:              the pointer to right (next) transform.
1718  * @transformCtx:       the transform's chain processing context.
1719  *
1720  * If the data object is a node-set and the next transform requires octets,
1721  * the signature application MUST attempt to convert the node-set to an octet
1722  * stream using Canonical XML [XML-C14N].
1723  *
1724  * The story is different if the right transform is base64 decode
1725  * (http://www.w3.org/TR/xmldsig-core/#sec-Base-64):
1726  *
1727  * This transform requires an octet stream for input. If an XPath node-set
1728  * (or sufficiently functional alternative) is given as input, then it is
1729  * converted to an octet stream by performing operations logically equivalent
1730  * to 1) applying an XPath transform with expression self::text(), then 2)
1731  * taking the string-value of the node-set. Thus, if an XML element is
1732  * identified by a barename XPointer in the Reference URI, and its content
1733  * consists solely of base64 encoded character data, then this transform
1734  * automatically strips away the start and end tags of the identified element
1735  * and any of its descendant elements as well as any descendant comments and
1736  * processing instructions. The output of this transform is an octet stream.
1737  *
1738  * Returns: 0 on success or a negative value if an error occurs.
1739  */
1740 int
xmlSecTransformConnect(xmlSecTransformPtr left,xmlSecTransformPtr right,xmlSecTransformCtxPtr transformCtx)1741 xmlSecTransformConnect(xmlSecTransformPtr left, xmlSecTransformPtr right,
1742                        xmlSecTransformCtxPtr transformCtx) {
1743     xmlSecTransformDataType leftType;
1744     xmlSecTransformDataType rightType;
1745     xmlSecTransformId middleId;
1746     xmlSecTransformPtr middle;
1747 
1748     xmlSecAssert2(xmlSecTransformIsValid(left), -1);
1749     xmlSecAssert2(xmlSecTransformIsValid(right), -1);
1750     xmlSecAssert2(transformCtx != NULL, -1);
1751 
1752     leftType = xmlSecTransformGetDataType(left, xmlSecTransformModePop, transformCtx);
1753     rightType = xmlSecTransformGetDataType(right, xmlSecTransformModePush, transformCtx);
1754 
1755     /* happy case first: nothing need to be done */
1756     if((((leftType & xmlSecTransformDataTypeBin) != 0) &&
1757         ((rightType & xmlSecTransformDataTypeBin) != 0)) ||
1758        (((leftType & xmlSecTransformDataTypeXml) != 0) &&
1759         ((rightType & xmlSecTransformDataTypeXml) != 0))) {
1760 
1761         left->next = right;
1762         right->prev = left;
1763         return(0);
1764     }
1765 
1766     if(((leftType & xmlSecTransformDataTypeBin) != 0) &&
1767         ((rightType & xmlSecTransformDataTypeXml) != 0)) {
1768 
1769         /* need to insert parser */
1770         middleId = xmlSecTransformXmlParserId;
1771     } else if(((leftType & xmlSecTransformDataTypeXml) != 0) &&
1772         ((rightType & xmlSecTransformDataTypeBin) != 0)) {
1773 
1774         /* need to insert c14n or special pre-base64 transform */
1775         if(xmlSecTransformCheckId(right, xmlSecTransformBase64Id)) {
1776             middleId = xmlSecTransformRemoveXmlTagsC14NId;
1777         } else {
1778             middleId = xmlSecTransformInclC14NId;
1779         }
1780     } else {
1781         xmlSecInvalidTransfromError2(left,
1782                     "transforms types do not match, right transform=\"%s\"",
1783                     xmlSecErrorsSafeString(xmlSecTransformGetName(right)));
1784         return(-1);
1785     }
1786 
1787     /* insert transform */
1788     middle = xmlSecTransformCreate(middleId);
1789     if(middle == NULL) {
1790         xmlSecInternalError("xmlSecTransformCreate",
1791                             xmlSecTransformKlassGetName(middleId));
1792         return(-1);
1793     }
1794     left->next = middle;
1795     middle->prev = left;
1796     middle->next = right;
1797     right->prev = middle;
1798     return(0);
1799 }
1800 
1801 /**
1802  * xmlSecTransformRemove:
1803  * @transform: the pointer to #xmlSecTransform structure.
1804  *
1805  * Removes @transform from the chain.
1806  */
1807 void
xmlSecTransformRemove(xmlSecTransformPtr transform)1808 xmlSecTransformRemove(xmlSecTransformPtr transform) {
1809     xmlSecAssert(xmlSecTransformIsValid(transform));
1810 
1811     if(transform->next != NULL) {
1812         transform->next->prev = transform->prev;
1813     }
1814     if(transform->prev != NULL) {
1815         transform->prev->next = transform->next;
1816     }
1817     transform->next = transform->prev = NULL;
1818 }
1819 
1820 
1821 /************************************************************************
1822  *
1823  * Default callbacks, most of the transforms can use them
1824  *
1825  ************************************************************************/
1826 /**
1827  * xmlSecTransformDefaultGetDataType:
1828  * @transform:          the pointer to transform.
1829  * @mode:               the data mode (push or pop).
1830  * @transformCtx:       the transform's chain processing context.
1831  *
1832  * Gets transform input (@mode is "push") or output (@mode is "pop") data
1833  * type (binary or XML) by analyzing available pushBin/popBin/pushXml/popXml
1834  * methods.
1835  *
1836  * Returns: the transform's data type for the @mode operation.
1837  */
1838 xmlSecTransformDataType
xmlSecTransformDefaultGetDataType(xmlSecTransformPtr transform,xmlSecTransformMode mode,xmlSecTransformCtxPtr transformCtx)1839 xmlSecTransformDefaultGetDataType(xmlSecTransformPtr transform, xmlSecTransformMode mode,
1840                                   xmlSecTransformCtxPtr transformCtx) {
1841     xmlSecTransformDataType type = xmlSecTransformDataTypeUnknown;
1842 
1843     xmlSecAssert2(xmlSecTransformIsValid(transform), xmlSecTransformDataTypeUnknown);
1844     xmlSecAssert2(transformCtx != NULL, xmlSecTransformDataTypeUnknown);
1845 
1846     /* we'll try to guess the data type based on the handlers we have */
1847     switch(mode) {
1848         case xmlSecTransformModePush:
1849             if(transform->id->pushBin != NULL) {
1850                 type |= xmlSecTransformDataTypeBin;
1851             }
1852             if(transform->id->pushXml != NULL) {
1853                 type |= xmlSecTransformDataTypeXml;
1854             }
1855             break;
1856         case xmlSecTransformModePop:
1857             if(transform->id->popBin != NULL) {
1858                 type |= xmlSecTransformDataTypeBin;
1859             }
1860             if(transform->id->popXml != NULL) {
1861                 type |= xmlSecTransformDataTypeXml;
1862             }
1863             break;
1864         default:
1865             xmlSecInvalidIntegerDataError("mode", mode,
1866                     "xmlSecTransformModePush,xmlSecTransformModePop",
1867                     xmlSecTransformGetName(transform));
1868             return(xmlSecTransformDataTypeUnknown);
1869     }
1870 
1871     return(type);
1872 }
1873 
1874 /**
1875  * xmlSecTransformDefaultPushBin:
1876  * @transform:          the pointer to transform object.
1877  * @data:               the input binary data,
1878  * @dataSize:           the input data size.
1879  * @final:              the flag: if set to 1 then it's the last
1880  *                      data chunk.
1881  * @transformCtx:       the pointer to transform context object.
1882  *
1883  * Process binary @data by calling transform's execute method and pushes
1884  * results to next transform.
1885  *
1886  * Returns: 0 on success or a negative value if an error occurs.
1887  */
1888 int
xmlSecTransformDefaultPushBin(xmlSecTransformPtr transform,const xmlSecByte * data,xmlSecSize dataSize,int final,xmlSecTransformCtxPtr transformCtx)1889 xmlSecTransformDefaultPushBin(xmlSecTransformPtr transform, const xmlSecByte* data,
1890                         xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) {
1891     xmlSecSize inSize = 0;
1892     xmlSecSize outSize = 0;
1893     int finalData = 0;
1894     int ret;
1895 
1896     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1897     xmlSecAssert2(transformCtx != NULL, -1);
1898 
1899     do {
1900         /* append data to input buffer */
1901         if(dataSize > 0) {
1902             xmlSecSize chunkSize;
1903 
1904             xmlSecAssert2(data != NULL, -1);
1905 
1906             chunkSize = dataSize;
1907             if(chunkSize > XMLSEC_TRANSFORM_BINARY_CHUNK) {
1908                 chunkSize = XMLSEC_TRANSFORM_BINARY_CHUNK;
1909             }
1910 
1911             ret = xmlSecBufferAppend(&(transform->inBuf), data, chunkSize);
1912             if(ret < 0) {
1913                 xmlSecInternalError2("xmlSecBufferAppend",
1914                                      xmlSecTransformGetName(transform),
1915                                      "size=%d", chunkSize);
1916                 return(-1);
1917             }
1918 
1919             dataSize -= chunkSize;
1920             data += chunkSize;
1921         }
1922 
1923         /* process data */
1924         finalData = (((dataSize == 0) && (final != 0)) ? 1 : 0);
1925         ret = xmlSecTransformExecute(transform, finalData, transformCtx);
1926         if(ret < 0) {
1927             xmlSecInternalError2("xmlSecTransformExecute",
1928                                  xmlSecTransformGetName(transform),
1929                                  "final=%d", final);
1930             return(-1);
1931         }
1932 
1933         /* push data to the next transform */
1934         inSize = xmlSecBufferGetSize(&(transform->inBuf));
1935         outSize = xmlSecBufferGetSize(&(transform->outBuf));
1936         if(inSize > 0) {
1937             finalData = 0;
1938         }
1939 
1940         /* we don't want to push too much */
1941         if(outSize > XMLSEC_TRANSFORM_BINARY_CHUNK) {
1942             outSize = XMLSEC_TRANSFORM_BINARY_CHUNK;
1943             finalData = 0;
1944         }
1945         if((transform->next != NULL) && ((outSize > 0) || (finalData != 0))) {
1946             ret = xmlSecTransformPushBin(transform->next,
1947                             xmlSecBufferGetData(&(transform->outBuf)),
1948                             outSize,
1949                             finalData,
1950                             transformCtx);
1951             if(ret < 0) {
1952                 xmlSecInternalError3("xmlSecTransformPushBin",
1953                                      xmlSecTransformGetName(transform->next),
1954                                      "final=%d;outSize=%d", final, outSize);
1955                 return(-1);
1956             }
1957         }
1958 
1959         /* remove data anyway */
1960         if(outSize > 0) {
1961             ret = xmlSecBufferRemoveHead(&(transform->outBuf), outSize);
1962             if(ret < 0) {
1963                 xmlSecInternalError2("xmlSecBufferRemoveHead",
1964                                      xmlSecTransformGetName(transform),
1965                                      "size=%d", outSize);
1966                 return(-1);
1967             }
1968         }
1969     } while((dataSize > 0) || (outSize > 0));
1970 
1971     return(0);
1972 }
1973 
1974 /**
1975  * xmlSecTransformDefaultPopBin:
1976  * @transform:          the pointer to transform object.
1977  * @data:               the buffer to store result data.
1978  * @maxDataSize:        the size of the buffer #data.
1979  * @dataSize:           the pointer to returned data size.
1980  * @transformCtx:       the pointer to transform context object.
1981  *
1982  * Pops data from previous transform in the chain, processes data by calling
1983  * transform's execute method and returns result in the @data buffer. The
1984  * size of returned data is placed in the @dataSize.
1985  *
1986  * Returns: 0 on success or a negative value if an error occurs.
1987  */
1988 int
xmlSecTransformDefaultPopBin(xmlSecTransformPtr transform,xmlSecByte * data,xmlSecSize maxDataSize,xmlSecSize * dataSize,xmlSecTransformCtxPtr transformCtx)1989 xmlSecTransformDefaultPopBin(xmlSecTransformPtr transform, xmlSecByte* data,
1990                              xmlSecSize maxDataSize, xmlSecSize* dataSize,
1991                              xmlSecTransformCtxPtr transformCtx) {
1992     xmlSecSize outSize;
1993     int final = 0;
1994     int ret;
1995 
1996     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
1997     xmlSecAssert2(data != NULL, -1);
1998     xmlSecAssert2(dataSize != NULL, -1);
1999     xmlSecAssert2(transformCtx != NULL, -1);
2000 
2001     while((xmlSecBufferGetSize(&(transform->outBuf)) == 0) && (final == 0)) {
2002         /* read data from previous transform if exist */
2003         if(transform->prev != NULL) {
2004             xmlSecSize inSize, chunkSize;
2005 
2006             inSize = xmlSecBufferGetSize(&(transform->inBuf));
2007             chunkSize = XMLSEC_TRANSFORM_BINARY_CHUNK;
2008 
2009             /* ensure that we have space for at least one data chunk */
2010             ret = xmlSecBufferSetMaxSize(&(transform->inBuf), inSize + chunkSize);
2011             if(ret < 0) {
2012                 xmlSecInternalError2("xmlSecBufferSetMaxSize",
2013                                      xmlSecTransformGetName(transform),
2014                                      "size=%d", inSize + chunkSize);
2015                 return(-1);
2016             }
2017 
2018             /* get data from previous transform */
2019             ret = xmlSecTransformPopBin(transform->prev,
2020                             xmlSecBufferGetData(&(transform->inBuf)) + inSize,
2021                             chunkSize, &chunkSize, transformCtx);
2022             if(ret < 0) {
2023                 xmlSecInternalError("xmlSecTransformPopBin",
2024                                     xmlSecTransformGetName(transform->prev));
2025                 return(-1);
2026             }
2027 
2028             /* adjust our size if needed */
2029             if(chunkSize > 0) {
2030                 ret = xmlSecBufferSetSize(&(transform->inBuf), inSize + chunkSize);
2031                 if(ret < 0) {
2032                     xmlSecInternalError2("xmlSecBufferSetSize",
2033                                          xmlSecTransformGetName(transform),
2034                                          "size=%d", inSize + chunkSize);
2035                     return(-1);
2036                 }
2037                 final = 0; /* the previous transform returned some data..*/
2038             } else {
2039                 final = 1; /* no data returned from previous transform, we are done */
2040             }
2041         } else {
2042             final = 1; /* no previous transform, we are "permanently final" */
2043         }
2044 
2045         /* execute our transform */
2046         ret = xmlSecTransformExecute(transform, final, transformCtx);
2047         if(ret < 0) {
2048             xmlSecInternalError("xmlSecTransformExecute",
2049                                 xmlSecTransformGetName(transform));
2050             return(-1);
2051         }
2052     }
2053 
2054     /* copy result (if any) */
2055     outSize = xmlSecBufferGetSize(&(transform->outBuf));
2056     if(outSize > maxDataSize) {
2057         outSize = maxDataSize;
2058     }
2059 
2060     /* we don't want to put too much */
2061     if(outSize > XMLSEC_TRANSFORM_BINARY_CHUNK) {
2062         outSize = XMLSEC_TRANSFORM_BINARY_CHUNK;
2063     }
2064     if(outSize > 0) {
2065         xmlSecAssert2(xmlSecBufferGetData(&(transform->outBuf)), -1);
2066 
2067         memcpy(data, xmlSecBufferGetData(&(transform->outBuf)), outSize);
2068 
2069         ret = xmlSecBufferRemoveHead(&(transform->outBuf), outSize);
2070         if(ret < 0) {
2071             xmlSecInternalError2("xmlSecBufferRemoveHead",
2072                                  xmlSecTransformGetName(transform),
2073                                  "size=%d", outSize);
2074             return(-1);
2075         }
2076     }
2077 
2078     /* set the result size */
2079     (*dataSize) = outSize;
2080     return(0);
2081 }
2082 
2083 /**
2084  * xmlSecTransformDefaultPushXml:
2085  * @transform:          the pointer to transform object.
2086  * @nodes:              the input nodes.
2087  * @transformCtx:       the pointer to transform context object.
2088  *
2089  * Processes @nodes by calling transform's execute method and pushes
2090  * result to the next transform in the chain.
2091  *
2092  * Returns: 0 on success or a negative value if an error occurs.
2093  */
2094 int
xmlSecTransformDefaultPushXml(xmlSecTransformPtr transform,xmlSecNodeSetPtr nodes,xmlSecTransformCtxPtr transformCtx)2095 xmlSecTransformDefaultPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes,
2096                             xmlSecTransformCtxPtr transformCtx) {
2097     int ret;
2098 
2099     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
2100     xmlSecAssert2(transform->inNodes == NULL, -1);
2101     xmlSecAssert2(transform->outNodes == NULL, -1);
2102     xmlSecAssert2(transformCtx != NULL, -1);
2103 
2104     /* execute our transform */
2105     transform->inNodes = nodes;
2106     ret = xmlSecTransformExecute(transform, 1, transformCtx);
2107     if(ret < 0) {
2108         xmlSecInternalError("xmlSecTransformExecute",
2109                             xmlSecTransformGetName(transform));
2110         return(-1);
2111     }
2112 
2113     /* push result to the next transform (if exist) */
2114     if(transform->next != NULL) {
2115         ret = xmlSecTransformPushXml(transform->next, transform->outNodes, transformCtx);
2116         if(ret < 0) {
2117             xmlSecInternalError("xmlSecTransformPushXml",
2118                                 xmlSecTransformGetName(transform));
2119             return(-1);
2120         }
2121     }
2122     return(0);
2123 }
2124 
2125 /**
2126  * xmlSecTransformDefaultPopXml:
2127  * @transform:          the pointer to transform object.
2128  * @nodes:              the pointer to store popinter to result nodes.
2129  * @transformCtx:       the pointer to transform context object.
2130  *
2131  * Pops data from previous transform in the chain, processes the data
2132  * by calling transform's execute method and returns result in @nodes.
2133  *
2134  * Returns: 0 on success or a negative value if an error occurs.
2135  */
2136 int
xmlSecTransformDefaultPopXml(xmlSecTransformPtr transform,xmlSecNodeSetPtr * nodes,xmlSecTransformCtxPtr transformCtx)2137 xmlSecTransformDefaultPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes,
2138                             xmlSecTransformCtxPtr transformCtx) {
2139     int ret;
2140 
2141     xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
2142     xmlSecAssert2(transform->inNodes == NULL, -1);
2143     xmlSecAssert2(transform->outNodes == NULL, -1);
2144     xmlSecAssert2(transformCtx != NULL, -1);
2145 
2146     /* pop result from the prev transform (if exist) */
2147     if(transform->prev != NULL) {
2148         ret = xmlSecTransformPopXml(transform->prev, &(transform->inNodes), transformCtx);
2149         if(ret < 0) {
2150             xmlSecInternalError("xmlSecTransformPopXml",
2151                                 xmlSecTransformGetName(transform));
2152             return(-1);
2153         }
2154     }
2155 
2156     /* execute our transform */
2157     ret = xmlSecTransformExecute(transform, 1, transformCtx);
2158     if(ret < 0) {
2159         xmlSecInternalError("xmlSecTransformExecute",
2160                             xmlSecTransformGetName(transform));
2161         return(-1);
2162     }
2163 
2164     /* return result if requested */
2165     if(nodes != NULL) {
2166         (*nodes) = transform->outNodes;
2167     }
2168 
2169     return(0);
2170 }
2171 
2172 /***********************************************************************
2173  *
2174  * Transform Ids list
2175  *
2176  **********************************************************************/
2177 static xmlSecPtrListKlass xmlSecTransformIdListKlass = {
2178     BAD_CAST "transform-ids-list",
2179     NULL,                                                       /* xmlSecPtrDuplicateItemMethod duplicateItem; */
2180     NULL,                                                       /* xmlSecPtrDestroyItemMethod destroyItem; */
2181     NULL,                                                       /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
2182     NULL,                                                       /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
2183 };
2184 
2185 /**
2186  * xmlSecTransformIdListGetKlass:
2187  *
2188  * The transform id list klass.
2189  *
2190  * Returns: pointer to the transform id list klass.
2191  */
2192 xmlSecPtrListId
xmlSecTransformIdListGetKlass(void)2193 xmlSecTransformIdListGetKlass(void) {
2194     return(&xmlSecTransformIdListKlass);
2195 }
2196 
2197 /**
2198  * xmlSecTransformIdListFind:
2199  * @list:               the pointer to transform ids list.
2200  * @transformId:        the transform klass.
2201  *
2202  * Lookups @dataId in @list.
2203  *
2204  * Returns: 1 if @dataId is found in the @list, 0 if not and a negative
2205  * value if an error occurs.
2206  */
2207 int
xmlSecTransformIdListFind(xmlSecPtrListPtr list,xmlSecTransformId transformId)2208 xmlSecTransformIdListFind(xmlSecPtrListPtr list, xmlSecTransformId transformId) {
2209     xmlSecSize i, size;
2210 
2211     xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), -1);
2212     xmlSecAssert2(transformId != NULL, -1);
2213 
2214     size = xmlSecPtrListGetSize(list);
2215     for(i = 0; i < size; ++i) {
2216         if((xmlSecTransformId)xmlSecPtrListGetItem(list, i) == transformId) {
2217             return(1);
2218         }
2219     }
2220     return(0);
2221 }
2222 
2223 /**
2224  * xmlSecTransformIdListFindByHref:
2225  * @list:               the pointer to transform ids list.
2226  * @href:               the desired transform klass href.
2227  * @usage:              the desired transform usage.
2228  *
2229  * Lookups data klass in the list with given @href and @usage in @list.
2230  *
2231  * Returns: transform klass is found and NULL otherwise.
2232  */
2233 xmlSecTransformId
xmlSecTransformIdListFindByHref(xmlSecPtrListPtr list,const xmlChar * href,xmlSecTransformUsage usage)2234 xmlSecTransformIdListFindByHref(xmlSecPtrListPtr list, const xmlChar* href,
2235                             xmlSecTransformUsage usage) {
2236     xmlSecTransformId transformId;
2237     xmlSecSize i, size;
2238 
2239     xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), xmlSecTransformIdUnknown);
2240     xmlSecAssert2(href != NULL, xmlSecTransformIdUnknown);
2241 
2242     size = xmlSecPtrListGetSize(list);
2243     for(i = 0; i < size; ++i) {
2244         transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
2245         xmlSecAssert2(transformId != xmlSecTransformIdUnknown, xmlSecTransformIdUnknown);
2246 
2247         if(((usage & transformId->usage) != 0) && (transformId->href != NULL) &&
2248            xmlStrEqual(href, transformId->href)) {
2249            return(transformId);
2250         }
2251     }
2252     return(xmlSecTransformIdUnknown);
2253 }
2254 
2255 /**
2256  * xmlSecTransformIdListFindByName:
2257  * @list:               the pointer to transform ids list.
2258  * @name:               the desired transform klass name.
2259  * @usage:              the desired transform usage.
2260  *
2261  * Lookups data klass in the list with given @name and @usage in @list.
2262  *
2263  * Returns: transform klass is found and NULL otherwise.
2264  */
2265 xmlSecTransformId
xmlSecTransformIdListFindByName(xmlSecPtrListPtr list,const xmlChar * name,xmlSecTransformUsage usage)2266 xmlSecTransformIdListFindByName(xmlSecPtrListPtr list, const xmlChar* name,
2267                             xmlSecTransformUsage usage) {
2268     xmlSecTransformId transformId;
2269     xmlSecSize i, size;
2270 
2271     xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), xmlSecTransformIdUnknown);
2272     xmlSecAssert2(name != NULL, xmlSecTransformIdUnknown);
2273 
2274     size = xmlSecPtrListGetSize(list);
2275     for(i = 0; i < size; ++i) {
2276         transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
2277         xmlSecAssert2(transformId != xmlSecTransformIdUnknown, xmlSecTransformIdUnknown);
2278 
2279         if(((usage & transformId->usage) != 0) && (transformId->name != NULL) &&
2280            xmlStrEqual(name, BAD_CAST transformId->name)) {
2281 
2282            return(transformId);
2283         }
2284     }
2285     return(xmlSecTransformIdUnknown);
2286 }
2287 
2288 /**
2289  * xmlSecTransformIdListDebugDump:
2290  * @list:               the pointer to transform ids list.
2291  * @output:             the pointer to output FILE.
2292  *
2293  * Prints binary transform debug information to @output.
2294  */
2295 void
xmlSecTransformIdListDebugDump(xmlSecPtrListPtr list,FILE * output)2296 xmlSecTransformIdListDebugDump(xmlSecPtrListPtr list, FILE* output) {
2297     xmlSecTransformId transformId;
2298     xmlSecSize i, size;
2299 
2300     xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecTransformIdListId));
2301     xmlSecAssert(output != NULL);
2302 
2303     size = xmlSecPtrListGetSize(list);
2304     for(i = 0; i < size; ++i) {
2305         transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
2306         xmlSecAssert(transformId != NULL);
2307         xmlSecAssert(transformId->name != NULL);
2308 
2309         if(i > 0) {
2310             fprintf(output, ",\"%s\"", transformId->name);
2311         } else {
2312             fprintf(output, "\"%s\"", transformId->name);
2313         }
2314     }
2315     fprintf(output, "\n");
2316 }
2317 
2318 /**
2319  * xmlSecTransformIdListDebugXmlDump:
2320  * @list:               the pointer to transform ids list.
2321  * @output:             the pointer to output FILE.
2322  *
2323  * Prints binary transform debug information to @output in XML format.
2324  */
2325 void
xmlSecTransformIdListDebugXmlDump(xmlSecPtrListPtr list,FILE * output)2326 xmlSecTransformIdListDebugXmlDump(xmlSecPtrListPtr list, FILE* output) {
2327     xmlSecTransformId transformId;
2328     xmlSecSize i, size;
2329 
2330     xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecTransformIdListId));
2331     xmlSecAssert(output != NULL);
2332 
2333     fprintf(output, "<TransformIdsList>\n");
2334     size = xmlSecPtrListGetSize(list);
2335     for(i = 0; i < size; ++i) {
2336         transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
2337         xmlSecAssert(transformId != NULL);
2338         xmlSecAssert(transformId->name != NULL);
2339 
2340         fprintf(output, "<TransformId name=\"");
2341         xmlSecPrintXmlString(output, transformId->name);
2342         fprintf(output, "\" />");
2343     }
2344     fprintf(output, "</TransformIdsList>\n");
2345 }
2346 
2347 /************************************************************************
2348  *
2349  * IO buffers for transforms
2350  *
2351  ************************************************************************/
2352 typedef struct _xmlSecTransformIOBuffer                 xmlSecTransformIOBuffer,
2353                                                         *xmlSecTransformIOBufferPtr;
2354 typedef enum {
2355     xmlSecTransformIOBufferModeRead,
2356     xmlSecTransformIOBufferModeWrite
2357 } xmlSecTransformIOBufferMode;
2358 
2359 struct _xmlSecTransformIOBuffer {
2360     xmlSecTransformIOBufferMode         mode;
2361     xmlSecTransformPtr                  transform;
2362     xmlSecTransformCtxPtr               transformCtx;
2363 };
2364 
2365 static xmlSecTransformIOBufferPtr xmlSecTransformIOBufferCreate (xmlSecTransformIOBufferMode mode,
2366                                                                  xmlSecTransformPtr transform,
2367                                                                  xmlSecTransformCtxPtr transformCtx);
2368 static void     xmlSecTransformIOBufferDestroy                  (xmlSecTransformIOBufferPtr buffer);
2369 static int      xmlSecTransformIOBufferRead                     (xmlSecTransformIOBufferPtr buffer,
2370                                                                  xmlSecByte *buf,
2371                                                                  xmlSecSize size);
2372 static int      xmlSecTransformIOBufferWrite                    (xmlSecTransformIOBufferPtr buffer,
2373                                                                  const xmlSecByte *buf,
2374                                                                  xmlSecSize size);
2375 static int      xmlSecTransformIOBufferClose                    (xmlSecTransformIOBufferPtr buffer);
2376 
2377 
2378 /**
2379  * xmlSecTransformCreateOutputBuffer:
2380  * @transform:          the pointer to transform.
2381  * @transformCtx:       the pointer to transform context object.
2382  *
2383  * Creates output buffer to write data to @transform.
2384  *
2385  * Returns: pointer to new output buffer or NULL if an error occurs.
2386  */
2387 xmlOutputBufferPtr
xmlSecTransformCreateOutputBuffer(xmlSecTransformPtr transform,xmlSecTransformCtxPtr transformCtx)2388 xmlSecTransformCreateOutputBuffer(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) {
2389     xmlSecTransformIOBufferPtr buffer;
2390     xmlSecTransformDataType type;
2391     xmlOutputBufferPtr output;
2392 
2393     xmlSecAssert2(xmlSecTransformIsValid(transform), NULL);
2394     xmlSecAssert2(transformCtx != NULL, NULL);
2395 
2396     /* check that we have binary push method for this transform */
2397     type = xmlSecTransformDefaultGetDataType(transform, xmlSecTransformModePush, transformCtx);
2398     if((type & xmlSecTransformDataTypeBin) == 0) {
2399         xmlSecInvalidTransfromError2(transform,
2400                             "push binary data not supported, type=\"%d\"",
2401                             (int)type);
2402         return(NULL);
2403     }
2404 
2405     buffer = xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferModeWrite, transform, transformCtx);
2406     if(buffer == NULL) {
2407         xmlSecInternalError("xmlSecTransformIOBufferCreate",
2408                             xmlSecTransformGetName(transform));
2409         return(NULL);
2410     }
2411 
2412     output = xmlOutputBufferCreateIO((xmlOutputWriteCallback)xmlSecTransformIOBufferWrite,
2413                                      (xmlOutputCloseCallback)xmlSecTransformIOBufferClose,
2414                                      buffer,
2415                                      NULL);
2416     if(output == NULL) {
2417         xmlSecXmlError("xmlOutputBufferCreateIO", xmlSecTransformGetName(transform));
2418         xmlSecTransformIOBufferDestroy(buffer);
2419         return(NULL);
2420     }
2421 
2422     return(output);
2423 }
2424 
2425 /**
2426  * xmlSecTransformCreateInputBuffer:
2427  * @transform:          the pointer to transform.
2428  * @transformCtx:       the pointer to transform context object.
2429  *
2430  * Creates input buffer to read data from @transform.
2431  *
2432  * Returns: pointer to new input buffer or NULL if an error occurs.
2433  */
2434 xmlParserInputBufferPtr
xmlSecTransformCreateInputBuffer(xmlSecTransformPtr transform,xmlSecTransformCtxPtr transformCtx)2435 xmlSecTransformCreateInputBuffer(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) {
2436     xmlSecTransformIOBufferPtr buffer;
2437     xmlSecTransformDataType type;
2438     xmlParserInputBufferPtr input;
2439 
2440     xmlSecAssert2(xmlSecTransformIsValid(transform), NULL);
2441     xmlSecAssert2(transformCtx != NULL, NULL);
2442 
2443     /* check that we have binary pop method for this transform */
2444     type = xmlSecTransformDefaultGetDataType(transform, xmlSecTransformModePop, transformCtx);
2445     if((type & xmlSecTransformDataTypeBin) == 0) {
2446         xmlSecInvalidTransfromError2(transform,
2447                             "pop binary data not supported, type=\"%d\"",
2448                             (int)type);
2449         return(NULL);
2450     }
2451 
2452     buffer = xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferModeRead, transform, transformCtx);
2453     if(buffer == NULL) {
2454         xmlSecInternalError("xmlSecTransformIOBufferCreate",
2455                             xmlSecTransformGetName(transform));
2456         return(NULL);
2457     }
2458 
2459     input = xmlParserInputBufferCreateIO((xmlInputReadCallback)xmlSecTransformIOBufferRead,
2460                                      (xmlInputCloseCallback)xmlSecTransformIOBufferClose,
2461                                      buffer,
2462                                      XML_CHAR_ENCODING_NONE);
2463     if(input == NULL) {
2464         xmlSecXmlError("xmlParserInputBufferCreateIO", xmlSecTransformGetName(transform));
2465         xmlSecTransformIOBufferDestroy(buffer);
2466         return(NULL);
2467     }
2468 
2469     return(input);
2470 }
2471 
2472 static xmlSecTransformIOBufferPtr
xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferMode mode,xmlSecTransformPtr transform,xmlSecTransformCtxPtr transformCtx)2473 xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferMode mode, xmlSecTransformPtr transform,
2474                               xmlSecTransformCtxPtr transformCtx) {
2475     xmlSecTransformIOBufferPtr buffer;
2476 
2477     xmlSecAssert2(xmlSecTransformIsValid(transform), NULL);
2478     xmlSecAssert2(transformCtx != NULL, NULL);
2479 
2480     buffer = (xmlSecTransformIOBufferPtr)xmlMalloc(sizeof(xmlSecTransformIOBuffer));
2481     if(buffer == NULL) {
2482         xmlSecMallocError(sizeof(xmlSecTransformIOBuffer), NULL);
2483         return(NULL);
2484     }
2485     memset(buffer, 0, sizeof(xmlSecTransformIOBuffer));
2486 
2487     buffer->mode = mode;
2488     buffer->transform = transform;
2489     buffer->transformCtx = transformCtx;
2490 
2491     return(buffer);
2492 }
2493 
2494 static void
xmlSecTransformIOBufferDestroy(xmlSecTransformIOBufferPtr buffer)2495 xmlSecTransformIOBufferDestroy(xmlSecTransformIOBufferPtr buffer) {
2496     xmlSecAssert(buffer != NULL);
2497 
2498     memset(buffer, 0, sizeof(xmlSecTransformIOBuffer));
2499     xmlFree(buffer);
2500 }
2501 
2502 static int
xmlSecTransformIOBufferRead(xmlSecTransformIOBufferPtr buffer,xmlSecByte * buf,xmlSecSize size)2503 xmlSecTransformIOBufferRead(xmlSecTransformIOBufferPtr buffer,
2504                             xmlSecByte *buf, xmlSecSize size) {
2505     int ret;
2506 
2507     xmlSecAssert2(buffer != NULL, -1);
2508     xmlSecAssert2(buffer->mode == xmlSecTransformIOBufferModeRead, -1);
2509     xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1);
2510     xmlSecAssert2(buffer->transformCtx != NULL, -1);
2511     xmlSecAssert2(buf != NULL, -1);
2512 
2513     ret = xmlSecTransformPopBin(buffer->transform, buf, size, &size, buffer->transformCtx);
2514     if(ret < 0) {
2515         xmlSecInternalError("xmlSecTransformPopBin",
2516                             xmlSecTransformGetName(buffer->transform));
2517         return(-1);
2518     }
2519     return(size);
2520 }
2521 
2522 static int
xmlSecTransformIOBufferWrite(xmlSecTransformIOBufferPtr buffer,const xmlSecByte * buf,xmlSecSize size)2523 xmlSecTransformIOBufferWrite(xmlSecTransformIOBufferPtr buffer,
2524                             const xmlSecByte *buf, xmlSecSize size) {
2525     int ret;
2526 
2527     xmlSecAssert2(buffer != NULL, -1);
2528     xmlSecAssert2(buffer->mode == xmlSecTransformIOBufferModeWrite, -1);
2529     xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1);
2530     xmlSecAssert2(buffer->transformCtx != NULL, -1);
2531     xmlSecAssert2(buf != NULL, -1);
2532 
2533     ret = xmlSecTransformPushBin(buffer->transform, buf, size, 0, buffer->transformCtx);
2534     if(ret < 0) {
2535         xmlSecInternalError("xmlSecTransformPushBin",
2536                             xmlSecTransformGetName(buffer->transform));
2537         return(-1);
2538     }
2539     return(size);
2540 }
2541 
2542 static int
xmlSecTransformIOBufferClose(xmlSecTransformIOBufferPtr buffer)2543 xmlSecTransformIOBufferClose(xmlSecTransformIOBufferPtr buffer) {
2544     int ret;
2545 
2546     xmlSecAssert2(buffer != NULL, -1);
2547     xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1);
2548     xmlSecAssert2(buffer->transformCtx != NULL, -1);
2549 
2550     /* need to flush write buffer before destroying */
2551     if(buffer->mode == xmlSecTransformIOBufferModeWrite) {
2552         ret = xmlSecTransformPushBin(buffer->transform, NULL, 0, 1, buffer->transformCtx);
2553         if(ret < 0) {
2554             xmlSecInternalError("xmlSecTransformPushBin",
2555                                 xmlSecTransformGetName(buffer->transform));
2556             return(-1);
2557         }
2558     }
2559 
2560     xmlSecTransformIOBufferDestroy(buffer);
2561     return(0);
2562 }
2563