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