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