Coverage Report

Created: 2026-04-12 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xmlsec/src/relationship.c
Line
Count
Source
1
/**
2
 * XML Security Library (http://www.aleksey.com/xmlsec).
3
 *
4
 * This is free software; see the Copyright file in the source distribution for precise wording.
5
 *
6
 * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
7
 */
8
/**
9
 * @addtogroup xmlsec_core_transforms
10
 * @brief Relationship transform implementation.
11
 */
12
#include "globals.h"
13
14
#include <stdlib.h>
15
#include <string.h>
16
17
#include <libxml/tree.h>
18
#include <libxml/xpointer.h>
19
#include <libxml/c14n.h>
20
21
#include <xmlsec/xmlsec.h>
22
#include <xmlsec/xmltree.h>
23
#include <xmlsec/keys.h>
24
#include <xmlsec/list.h>
25
#include <xmlsec/transforms.h>
26
#include <xmlsec/errors.h>
27
28
#include "cast_helpers.h"
29
30
31
/******************************************************************************
32
 *
33
 * XML Relationshi transform
34
 *
35
 *  * [Relationship transform](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061796_ISO_IEC_29500-2_2012.zip)
36
 *
37
 * The relationships transform takes the XML document from the Relationships part and converts
38
 * it to another XML document.
39
 *
40
 * The package implementer might create relationships XML that contains content from several namespaces,
41
 * along with versioning instructions as defined in Part 3, “Markup Compatibility and Extensibility”. [O6.11]
42
 *
43
 * The relationships transform algorithm is as follows:
44
 *
45
 * Step 1: Process versioning instructions
46
 *   1. The package implementer shall process the versioning instructions, considering that the only
47
 *   known namespace is the Relationships namespace.
48
 *   2. The package implementer shall remove all ignorable content, ignoring preservation attributes.
49
 *   3. The package implementer shall remove all versioning instructions.
50
 *
51
 * Step 2: Sort and filter relationships
52
 *   1. The package implementer shall remove all namespace declarations except the Relationships
53
 *   namespace declaration.
54
 *   2. The package implementer shall remove the Relationships namespace prefix, if it is present.
55
 *   3. The package implementer shall sort relationship elements by Id value in lexicographical
56
 *   order, considering Id values as case-sensitive Unicode strings.
57
 *   4. The package implementer shall remove all Relationship elements that do not have either an Id
58
 *   value that matches any SourceId value or a Type value that matches any SourceType value, among
59
 *   the SourceId and SourceType values specified in the transform definition. Producers and consumers
60
 *   shall compare values as case-sensitive Unicode strings. [M6.27] The resulting XML document holds
61
 *   all Relationship elements that either have an Id value that matches a SourceId value or a Type value
62
 *   that matches a SourceType value specified in the transform definition.
63
 *
64
 * Step 3: Prepare for canonicalization
65
 *   1. The package implementer shall remove all characters between the Relationships start tag and
66
 *   the first Relationship start tag.
67
 *   2. The package implementer shall remove any contents of the Relationship element.
68
 *   3. The package implementer shall remove all characters between the last Relationship end tag and
69
 *   the Relationships end tag.
70
 *   4. If there are no Relationship elements, the package implementer shall remove all characters
71
 *   between the Relationships start tag and the Relationships end tag.
72
 *   5. The package implementer shall remove comments from the Relationships XML content.
73
 *   6. The package implementer shall add a TargetMode attribute with its default value, if this
74
 *   optional attribute is missing from the Relationship element.
75
 *   7. The package implementer can generate Relationship elements as start-tag/end-tag pairs with
76
 *   empty content, or as empty elements. A canonicalization transform, applied immediately after the
77
 *   Relationships Transform, converts all XML elements into start-tag/end-tag pairs.
78
 *
79
 *
80
 *   IMPLEMENTATION NOTES (https://github.com/lsh123/xmlsec/pull/24):
81
 *
82
 *   * We don't simply manipulate the XML tree, but do an XML tree -> output bytes transformation,
83
 *     because we never write characters inside XML elements, we implicitly remove all character
84
 *     contents, as required by step 3, point 1. It also simplifies the task of the situation that
85
 *     realistically the input of the transformation is always a document that conforms to the OOXML
86
 *     relationships XML schema, so in practice it'll never happen that the input document has e.g.
87
 *     characters, as the schema requires that the document has only XML elements and attributes,
88
 *     but no characters.
89
 *
90
 *   * Step 2, point 4 talks about a SourceType value, but given that neither Microsoft Office, nor LibreOffice
91
 *     writes that theoretical attribute, the implementation doesn't handle it. If there is a real-world situation
92
 *     when there will be such an input, then it'll be easy to add support for that. But I didn't want to clutter
93
 *     the current implementation with details that doesn't seem to be used in practice
94
 *
95
 * xmlSecTransform + xmlSecRelationshipCtx
96
 *
97
  *****************************************************************************/
98
typedef struct _xmlSecRelationshipCtx           xmlSecRelationshipCtx,
99
                                                *xmlSecRelationshipCtxPtr;
100
struct _xmlSecRelationshipCtx {
101
    xmlSecPtrListPtr                    sourceIdList;
102
};
103
104
0
XMLSEC_TRANSFORM_DECLARE(Relationship, xmlSecRelationshipCtx)
105
0
#define xmlSecRelationshipSize XMLSEC_TRANSFORM_SIZE(Relationship)
106
0
107
0
static int              xmlSecRelationshipInitialize      (xmlSecTransformPtr transform);
108
0
static void             xmlSecRelationshipFinalize        (xmlSecTransformPtr transform);
109
0
static int              xmlSecTransformRelationshipPopBin (xmlSecTransformPtr transform,
110
0
                                                           xmlSecByte* data,
111
0
                                                           xmlSecSize maxDataSize,
112
0
                                                           xmlSecSize* dataSize,
113
0
                                                           xmlSecTransformCtxPtr transformCtx);
114
0
static int              xmlSecTransformRelationshipPushXml(xmlSecTransformPtr transform,
115
0
                                                           xmlSecNodeSetPtr nodes,
116
0
                                                           xmlSecTransformCtxPtr transformCtx);
117
0
static int              xmlSecRelationshipReadNode        (xmlSecTransformPtr transform,
118
0
                                                           xmlNodePtr node,
119
0
                                                           xmlSecTransformCtxPtr transformCtx);
120
0
121
0
static int              xmlSecTransformRelationshipProcessElementNode(xmlSecTransformPtr transform,
122
0
                                                            xmlOutputBufferPtr buf,
123
0
                                                            xmlNodePtr cur);
124
0
125
0
126
0
static xmlSecTransformKlass xmlSecRelationshipKlass = {
127
0
    /* klass/object sizes */
128
0
    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
129
0
    xmlSecRelationshipSize,                     /* xmlSecSize objSize */
130
0
131
0
    xmlSecNameRelationship,                     /* const xmlChar* name; */
132
0
    xmlSecHrefRelationship,                     /* const xmlChar* href; */
133
0
    xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
134
0
135
0
    xmlSecRelationshipInitialize,               /* xmlSecTransformInitializeMethod initialize; */
136
0
    xmlSecRelationshipFinalize,                 /* xmlSecTransformFinalizeMethod finalize; */
137
0
    xmlSecRelationshipReadNode,                 /* xmlSecTransformNodeReadMethod readNode; */
138
0
    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
139
0
    NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
140
0
    NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
141
0
    NULL,                                       /* xmlSecTransformValidateMethod validate; */
142
0
    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
143
0
    NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
144
0
    xmlSecTransformRelationshipPopBin,          /* xmlSecTransformPopBinMethod popBin; */
145
0
    xmlSecTransformRelationshipPushXml,         /* xmlSecTransformPushXmlMethod pushXml; */
146
0
    NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
147
0
    NULL,                                       /* xmlSecTransformExecuteMethod execute; */
148
0
149
0
    NULL,                                       /* void* reserved0; */
150
0
    NULL,                                       /* void* reserved1; */
151
0
};
152
0
153
0
/**
154
0
 * @brief Gets the Relationship transform klass.
155
0
 *
156
0
 * @return Relationship transform klass.
157
0
 */
158
0
xmlSecTransformId
159
0
xmlSecTransformRelationshipGetKlass(void) {
160
0
    return(&xmlSecRelationshipKlass);
161
0
}
162
163
static int
164
0
xmlSecRelationshipInitialize(xmlSecTransformPtr transform) {
165
0
    xmlSecRelationshipCtxPtr ctx;
166
167
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformRelationshipId), -1);
168
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecRelationshipSize), -1);
169
170
0
    ctx = xmlSecRelationshipGetCtx(transform);
171
0
    xmlSecAssert2(ctx != NULL, -1);
172
173
    /* initialize context */
174
0
    memset(ctx, 0, sizeof(xmlSecRelationshipCtx));
175
176
0
    ctx->sourceIdList = xmlSecPtrListCreate(xmlSecStringListId);
177
0
    if(ctx->sourceIdList == NULL) {
178
0
        xmlSecInternalError("xmlSecPtrListCreate",
179
0
                            xmlSecTransformGetName(transform));
180
0
        return(-1);
181
0
    }
182
0
    return(0);
183
0
}
184
185
static void
186
0
xmlSecRelationshipFinalize(xmlSecTransformPtr transform) {
187
0
    xmlSecRelationshipCtxPtr ctx;
188
189
0
    xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformRelationshipId));
190
0
    xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecRelationshipSize));
191
192
0
    ctx = xmlSecRelationshipGetCtx(transform);
193
0
    xmlSecAssert(ctx != NULL);
194
195
0
    if(ctx->sourceIdList != NULL) {
196
0
       xmlSecPtrListDestroy(ctx->sourceIdList);
197
0
    }
198
199
0
    memset(ctx, 0, sizeof(xmlSecRelationshipCtx));
200
0
}
201
202
static int
203
0
xmlSecRelationshipReadNode(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
204
0
    xmlSecRelationshipCtxPtr ctx;
205
0
    xmlNodePtr cur;
206
0
    int ret;
207
208
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformRelationshipId), -1);
209
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecRelationshipSize), -1);
210
0
    xmlSecAssert2(node != NULL, -1);
211
0
    xmlSecAssert2(transformCtx != NULL, -1);
212
0
    ctx = xmlSecRelationshipGetCtx(transform);
213
0
    xmlSecAssert2(ctx != NULL, -1);
214
215
0
    cur = node->children;
216
0
    while(cur != NULL) {
217
0
        if(xmlSecCheckNodeName(cur, xmlSecNodeRelationshipReference, xmlSecRelationshipReferenceNs)) {
218
0
            xmlChar* sourceId;
219
220
0
            sourceId = xmlGetProp(cur, xmlSecRelationshipAttrSourceId);
221
0
            if(sourceId == NULL) {
222
0
                xmlSecInvalidNodeAttributeError(cur, xmlSecRelationshipAttrSourceId,
223
0
                                                NULL, "empty");
224
0
                return(-1);
225
0
            }
226
227
0
            ret = xmlSecPtrListAdd(ctx->sourceIdList, sourceId);
228
0
            if(ret < 0) {
229
0
                xmlSecInternalError("xmlSecPtrListAdd",
230
0
                                    xmlSecTransformGetName(transform));
231
0
                xmlFree(sourceId);
232
0
                return(-1);
233
0
            }
234
0
        }
235
236
0
        cur = cur->next;
237
0
    }
238
239
0
    return(0);
240
0
}
241
242
/* Sorts Relationship elements by Id value in lexicographical order. */
243
static int
244
0
xmlSecTransformRelationshipCompare(xmlNodePtr node1, xmlNodePtr node2) {
245
0
    xmlChar* id1 = NULL;
246
0
    xmlChar* id2 = NULL;
247
0
    int ret;
248
249
0
    if(node1 == node2) {
250
0
        return(0);
251
0
    }
252
0
    if(node1 == NULL) {
253
0
        return(-1);
254
0
    }
255
0
    if(node2 == NULL) {
256
0
        return(1);
257
0
    }
258
259
0
    id1 = xmlGetProp(node1, xmlSecRelationshipAttrId);
260
0
    id2 = xmlGetProp(node2, xmlSecRelationshipAttrId);
261
0
    if(id1 == NULL) {
262
0
        ret = -1;
263
0
        goto done;
264
0
    }
265
0
    if(id2 == NULL) {
266
0
        ret = 1;
267
0
        goto done;
268
0
    }
269
270
0
    ret = xmlStrcmp(id1, id2);
271
272
0
done:
273
0
    if (id1 != NULL) {
274
0
        xmlFree(id1);
275
0
    }
276
0
    if (id2 != NULL) {
277
0
        xmlFree(id2);
278
0
    }
279
280
0
    return ret;
281
0
}
282
283
/*
284
 * This is step 2, point 4: if the input sourceId list doesn't contain the Id attribute of the current node,
285
 * then exclude it from the output, instead of processing it.
286
 */
287
static int
288
0
xmlSecTransformRelationshipProcessNode(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlNodePtr cur) {
289
0
    int found = -1;
290
0
    xmlSecRelationshipCtxPtr ctx;
291
0
    xmlSecSize ii;
292
0
    int ret;
293
294
0
    xmlSecAssert2(transform != NULL, -1);
295
0
    xmlSecAssert2(buf != NULL, -1);
296
0
    xmlSecAssert2(cur != NULL, -1);
297
298
0
    if(xmlSecCheckNodeName(cur, xmlSecNodeRelationship, xmlSecRelationshipsNs)) {
299
0
        xmlChar* id = xmlGetProp(cur, xmlSecRelationshipAttrId);
300
0
        if(id == NULL) {
301
0
            xmlSecXmlError2("xmlGetProp(xmlSecRelationshipAttrId)",
302
0
                            xmlSecTransformGetName(transform),
303
0
                            "name=%s", xmlSecRelationshipAttrId);
304
0
            return(-1);
305
0
        }
306
307
0
        ctx = xmlSecRelationshipGetCtx(transform);
308
0
        for(ii = 0; ii < xmlSecPtrListGetSize(ctx->sourceIdList); ++ii) {
309
0
            if(xmlStrcmp((xmlChar *)xmlSecPtrListGetItem(ctx->sourceIdList, ii), id) == 0) {
310
0
                found = 1;
311
0
                break;
312
0
            }
313
0
        }
314
315
0
        xmlFree(id);
316
317
0
        if(found < 0) {
318
0
            return(0);
319
0
        }
320
0
    }
321
322
0
    ret = xmlSecTransformRelationshipProcessElementNode(transform, buf, cur);
323
0
    if(ret < 0) {
324
0
        xmlSecInternalError("xmlSecTransformRelationshipProcessElementNode",
325
0
                            xmlSecTransformGetName(transform));
326
0
        return(-1);
327
0
    }
328
329
0
    return(0);
330
0
}
331
332
/*
333
 * This is step 2, point 3: sort elements by Id: we process other elements as-is, but for elements we collect them in a list,
334
 * then sort, and finally process them (process the head of the list, then pop the head, till the list becomes empty).
335
 */
336
static int
337
0
xmlSecTransformRelationshipProcessNodeList(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlNodePtr cur) {
338
0
    xmlListPtr list;
339
0
    int ret;
340
341
0
    xmlSecAssert2(transform != NULL, -1);
342
0
    xmlSecAssert2(buf != NULL, -1);
343
0
    xmlSecAssert2(cur != NULL, -1);
344
345
0
    list = xmlListCreate(NULL, (xmlListDataCompare)xmlSecTransformRelationshipCompare);
346
0
    if(list == NULL) {
347
0
        xmlSecXmlError("xmlListCreate", xmlSecTransformGetName(transform));
348
0
        return(-1);
349
0
    }
350
351
0
    for(; cur; cur = cur->next) {
352
0
        if(xmlStrcmp(cur->name, xmlSecNodeRelationship) == 0) {
353
0
            if(xmlListInsert(list, cur) != 0) {
354
0
                xmlSecXmlError("xmlListInsert", xmlSecTransformGetName(transform));
355
0
                return(-1);
356
0
            }
357
0
        } else {
358
0
            ret = xmlSecTransformRelationshipProcessNode(transform, buf, cur);
359
0
            if(ret < 0) {
360
0
                xmlSecInternalError("xmlSecTransformRelationshipProcessNode",
361
0
                                    xmlSecTransformGetName(transform));
362
0
                xmlListDelete(list);
363
0
                return(-1);
364
0
            }
365
0
        }
366
0
    }
367
368
0
    xmlListSort(list);
369
370
0
    while(!xmlListEmpty(list)) {
371
0
        xmlLinkPtr link = xmlListFront(list);
372
0
        xmlNodePtr node = (xmlNodePtr)xmlLinkGetData(link);
373
374
0
        ret = xmlSecTransformRelationshipProcessNode(transform, buf, node);
375
0
        if(ret < 0) {
376
0
            xmlSecInternalError("xmlSecTransformRelationshipProcessNode",
377
0
                                xmlSecTransformGetName(transform));
378
0
            xmlListDelete(list);
379
0
            return(-1);
380
0
        }
381
382
0
        xmlListPopFront(list);
383
0
    }
384
385
    /* done */
386
0
    xmlListDelete(list);
387
0
    return(0);
388
0
}
389
390
static int
391
0
xmlSecTransformRelationshipWriteProp(xmlOutputBufferPtr buf, const xmlChar * name, const xmlChar * value) {
392
0
    int ret;
393
394
0
    xmlSecAssert2(buf != NULL, -1);
395
0
    xmlSecAssert2(name != NULL, -1);
396
397
0
    ret = xmlOutputBufferWriteString(buf, " ");
398
0
    if(ret < 0) {
399
0
        xmlSecXmlError("xmlOutputBufferWriteString", NULL);
400
0
        return(-1);
401
0
    }
402
403
0
    ret = xmlOutputBufferWriteString(buf, (const char*) name);
404
0
    if(ret < 0) {
405
0
        xmlSecXmlError("xmlOutputBufferWriteString", NULL);
406
0
        return(-1);
407
0
    }
408
409
0
    if(value != NULL) {
410
0
        ret = xmlOutputBufferWriteString(buf, "=\"");
411
0
        if(ret < 0) {
412
0
            xmlSecXmlError("xmlOutputBufferWriteString", NULL);
413
0
            return(-1);
414
0
        }
415
0
        ret = xmlOutputBufferWriteString(buf, (const char*) value);
416
0
        if(ret < 0) {
417
0
            xmlSecXmlError("xmlOutputBufferWriteString", NULL);
418
0
            return(-1);
419
0
        }
420
0
        ret = xmlOutputBufferWriteString(buf, "\"");
421
0
        if(ret < 0) {
422
0
            xmlSecXmlError("xmlOutputBufferWriteString", NULL);
423
0
            return(-1);
424
0
        }
425
0
    }
426
427
0
    return (0);
428
0
}
429
430
static int
431
0
xmlSecTransformRelationshipWriteNs(xmlOutputBufferPtr buf, const xmlChar * href) {
432
0
    xmlSecAssert2(buf != NULL, -1);
433
434
0
    return(xmlSecTransformRelationshipWriteProp(buf, BAD_CAST "xmlns", (href != NULL) ? href : BAD_CAST ""));
435
0
}
436
437
438
static int
439
0
xmlSecTransformRelationshipProcessElementNode(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlNodePtr cur) {
440
0
    xmlAttrPtr attr;
441
0
    int foundTargetMode = 0;
442
0
    int ret;
443
444
0
    xmlSecAssert2(transform != NULL, -1);
445
0
    xmlSecAssert2(buf != NULL, -1);
446
0
    xmlSecAssert2(cur != NULL, -1);
447
0
    xmlSecAssert2(cur->name != NULL, -1);
448
449
    /* write open node */
450
0
    ret = xmlOutputBufferWriteString(buf, "<");
451
0
    if(ret < 0) {
452
0
        xmlSecXmlError("xmlOutputBufferWriteString",
453
0
                            xmlSecTransformGetName(transform));
454
0
        return(-1);
455
0
    }
456
0
    ret = xmlOutputBufferWriteString(buf, (const char *)cur->name);
457
0
    if(ret < 0) {
458
0
        xmlSecXmlError("xmlOutputBufferWriteString",
459
0
                            xmlSecTransformGetName(transform));
460
0
        return(-1);
461
0
    }
462
463
    /* write namespaces */
464
0
    if(cur->nsDef != NULL) {
465
0
        ret = xmlSecTransformRelationshipWriteNs(buf, cur->nsDef->href);
466
0
        if(ret < 0) {
467
0
            xmlSecInternalError("xmlSecTransformRelationshipWriteNs",
468
0
                                xmlSecTransformGetName(transform));
469
0
            return(-1);
470
0
        }
471
0
    }
472
473
    /*
474
     *  write attributes:
475
     *
476
     *  This is step 3, point 6: add default value of TargetMode if there is no such attribute.
477
     */
478
0
    for(attr = cur->properties; attr != NULL; attr = attr->next) {
479
0
        xmlChar * value = xmlGetProp(cur, attr->name);
480
481
0
        if(xmlStrcmp(attr->name, xmlSecRelationshipAttrTargetMode) == 0) {
482
0
            foundTargetMode = 1;
483
0
        }
484
485
0
        ret = xmlSecTransformRelationshipWriteProp(buf, attr->name, value);
486
0
        if(ret < 0) {
487
0
            xmlSecInternalError("xmlSecTransformRelationshipWriteProp",
488
0
                                xmlSecTransformGetName(transform));
489
0
            xmlFree(value);
490
0
            return(-1);
491
0
        }
492
493
0
        xmlFree(value);
494
0
    }
495
496
    /* write TargetMode */
497
0
    if(xmlStrcmp(cur->name, xmlSecNodeRelationship) == 0 && !foundTargetMode) {
498
0
        ret = xmlSecTransformRelationshipWriteProp(buf, xmlSecRelationshipAttrTargetMode, BAD_CAST "Internal");
499
0
        if(ret < 0) {
500
0
            xmlSecInternalError("xmlSecTransformRelationshipWriteProp(TargetMode=Internal)",
501
0
                                xmlSecTransformGetName(transform));
502
0
            return(-1);
503
0
        }
504
0
    }
505
506
    /* finish writing open node */
507
0
    ret = xmlOutputBufferWriteString(buf, ">");
508
0
    if(ret < 0) {
509
0
        xmlSecXmlError("xmlOutputBufferWriteString",
510
0
                            xmlSecTransformGetName(transform));
511
0
        return(-1);
512
0
    }
513
514
    /* write children */
515
0
    if(cur->children != NULL) {
516
0
        ret = xmlSecTransformRelationshipProcessNodeList(transform, buf, cur->children);
517
0
        if(ret < 0) {
518
0
            xmlSecInternalError("xmlSecTransformRelationshipProcessNodeList",
519
0
                                xmlSecTransformGetName(transform));
520
0
            return(-1);
521
0
        }
522
0
    }
523
524
    /* write closing node */
525
0
    ret = xmlOutputBufferWriteString(buf, "</");
526
0
    if(ret < 0) {
527
0
        xmlSecXmlError("xmlOutputBufferWriteString",
528
0
                            xmlSecTransformGetName(transform));
529
0
        return(-1);
530
0
    }
531
0
    ret = xmlOutputBufferWriteString(buf, (const char *)cur->name);
532
0
    if(ret < 0) {
533
0
        xmlSecXmlError("xmlOutputBufferWriteString",
534
0
                            xmlSecTransformGetName(transform));
535
0
        return(-1);
536
0
    }
537
0
    if(xmlOutputBufferWriteString(buf, ">") < 0) {
538
0
        xmlSecXmlError("xmlOutputBufferWriteString",
539
0
                            xmlSecTransformGetName(transform));
540
0
        return(-1);
541
0
    }
542
543
    /* done */
544
0
    return(0);
545
0
}
546
547
static int
548
0
xmlSecTransformRelationshipExecute(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlDocPtr doc) {
549
0
    int ret;
550
551
0
    xmlSecAssert2(transform != NULL, -1);
552
0
    xmlSecAssert2(buf != NULL, -1);
553
0
    xmlSecAssert2(doc != NULL, -1);
554
555
0
    if(doc->children != NULL) {
556
0
        ret = xmlSecTransformRelationshipProcessNodeList(transform, buf, doc->children);
557
0
        if(ret < 0) {
558
0
            xmlSecInternalError("xmlSecTransformRelationshipProcessNodeList",
559
0
                                xmlSecTransformGetName(transform));
560
0
            return(-1);
561
0
        }
562
0
    }
563
564
0
    return(0);
565
0
}
566
567
static int
568
xmlSecTransformRelationshipPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes, xmlSecTransformCtxPtr transformCtx)
569
0
{
570
0
    xmlOutputBufferPtr buf;
571
0
    xmlSecRelationshipCtxPtr ctx;
572
0
    int ret;
573
574
0
    xmlSecAssert2(nodes != NULL, -1);
575
0
    xmlSecAssert2(nodes->doc != NULL, -1);
576
0
    xmlSecAssert2(transformCtx != NULL, -1);
577
578
0
    ctx = xmlSecRelationshipGetCtx(transform);
579
0
    xmlSecAssert2(ctx != NULL, -1);
580
581
    /* check/update current transform status */
582
0
    switch(transform->status) {
583
0
    case xmlSecTransformStatusNone:
584
0
       transform->status = xmlSecTransformStatusWorking;
585
0
       break;
586
0
    case xmlSecTransformStatusWorking:
587
0
    case xmlSecTransformStatusFinished:
588
0
       return(0);
589
0
    default:
590
0
       xmlSecInvalidTransfromStatusError(transform);
591
0
       return(-1);
592
0
    }
593
0
    xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1);
594
595
    /* prepare output buffer: next transform or ourselves */
596
0
    if(transform->next != NULL) {
597
0
       buf = xmlSecTransformCreateOutputBuffer(transform->next, transformCtx);
598
0
       if(buf == NULL) {
599
0
           xmlSecInternalError("xmlSecTransformCreateOutputBuffer",
600
0
                               xmlSecTransformGetName(transform));
601
0
           return(-1);
602
0
       }
603
0
    } else {
604
0
       buf = xmlSecBufferCreateOutputBuffer(&(transform->outBuf));
605
0
       if(buf == NULL) {
606
0
           xmlSecInternalError("xmlSecBufferCreateOutputBuffer",
607
0
                               xmlSecTransformGetName(transform));
608
0
           return(-1);
609
0
       }
610
0
    }
611
612
0
    ret = xmlSecTransformRelationshipExecute(transform, buf, nodes->doc);
613
0
    if(ret < 0) {
614
0
       xmlSecInternalError("xmlSecTransformRelationshipExecute",
615
0
                           xmlSecTransformGetName(transform));
616
0
       (void)xmlOutputBufferClose(buf);
617
0
       return(-1);
618
0
    }
619
620
0
    ret = xmlOutputBufferClose(buf);
621
0
    if(ret < 0) {
622
0
       xmlSecXmlError("xmlOutputBufferClose", xmlSecTransformGetName(transform));
623
0
       return(-1);
624
0
    }
625
0
    transform->status = xmlSecTransformStatusFinished;
626
0
    return(0);
627
0
}
628
629
static int
630
0
xmlSecTransformRelationshipPopBin(xmlSecTransformPtr transform, xmlSecByte* data, xmlSecSize maxDataSize, xmlSecSize* dataSize, xmlSecTransformCtxPtr transformCtx) {
631
0
    xmlSecBufferPtr out;
632
0
    int ret;
633
634
0
    xmlSecAssert2(data != NULL, -1);
635
0
    xmlSecAssert2(dataSize != NULL, -1);
636
0
    xmlSecAssert2(transformCtx != NULL, -1);
637
638
0
    out = &(transform->outBuf);
639
0
    if(transform->status == xmlSecTransformStatusNone) {
640
0
       xmlOutputBufferPtr buf;
641
642
0
       xmlSecAssert2(transform->inNodes == NULL, -1);
643
644
0
       if(transform->prev == NULL) {
645
0
           (*dataSize) = 0;
646
0
           transform->status = xmlSecTransformStatusFinished;
647
0
           return(0);
648
0
       }
649
650
       /* get xml data from previous transform */
651
0
       ret = xmlSecTransformPopXml(transform->prev, &(transform->inNodes), transformCtx);
652
0
       if(ret < 0) {
653
0
           xmlSecInternalError("xmlSecTransformPopXml",
654
0
                               xmlSecTransformGetName(transform));
655
0
           return(-1);
656
0
       }
657
658
       /* dump everything to internal buffer */
659
0
       buf = xmlSecBufferCreateOutputBuffer(out);
660
0
       if(buf == NULL) {
661
0
           xmlSecInternalError("xmlSecBufferCreateOutputBuffer",
662
0
                               xmlSecTransformGetName(transform));
663
0
           return(-1);
664
0
       }
665
666
0
       ret = xmlC14NExecute(transform->inNodes->doc, (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, transform->inNodes, XML_C14N_1_0, NULL, 0, buf);
667
0
       if(ret < 0) {
668
0
            xmlSecInternalError("xmlC14NExecute",
669
0
                                xmlSecTransformGetName(transform));
670
0
           (void)xmlOutputBufferClose(buf);
671
0
           return(-1);
672
0
       }
673
674
0
       ret = xmlOutputBufferClose(buf);
675
0
       if(ret < 0) {
676
0
           xmlSecXmlError("xmlOutputBufferClose", xmlSecTransformGetName(transform));
677
0
           return(-1);
678
0
       }
679
0
       transform->status = xmlSecTransformStatusWorking;
680
0
    }
681
682
0
    if(transform->status == xmlSecTransformStatusWorking) {
683
0
       xmlSecSize outSize;
684
685
       /* return chunk after chunk */
686
0
       outSize = xmlSecBufferGetSize(out);
687
0
       if(outSize > maxDataSize) {
688
0
           outSize = maxDataSize;
689
0
       }
690
0
       if(outSize > transformCtx->binaryChunkSize) {
691
0
           outSize = transformCtx->binaryChunkSize;
692
0
       }
693
0
       if(outSize > 0) {
694
0
           xmlSecAssert2(xmlSecBufferGetData(out), -1);
695
696
0
           memcpy(data, xmlSecBufferGetData(out), outSize);
697
0
           ret = xmlSecBufferRemoveHead(out, outSize);
698
0
           if(ret < 0) {
699
0
               xmlSecInternalError2("xmlSecBufferRemoveHead",
700
0
                                    xmlSecTransformGetName(transform),
701
0
                                    "size=" XMLSEC_SIZE_FMT, outSize);
702
0
               return(-1);
703
0
           }
704
0
       } else if(xmlSecBufferGetSize(out) == 0) {
705
0
           transform->status = xmlSecTransformStatusFinished;
706
0
       }
707
0
       (*dataSize) = outSize;
708
0
    } else if(transform->status == xmlSecTransformStatusFinished) {
709
       /* the only way we can get here is if there is no output */
710
0
       xmlSecAssert2(xmlSecBufferGetSize(out) == 0, -1);
711
0
       (*dataSize) = 0;
712
0
    } else {
713
0
       xmlSecInvalidTransfromStatusError(transform);
714
0
       return(-1);
715
0
    }
716
717
0
    return(0);
718
0
}