1 /*
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  *
5  * This is free software; see Copyright file in the source
6  * distribution for preciese wording.
7  *
8  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
9  */
10 /**
11  * SECTION:base64
12  * @Short_description: Base64 encoding/decoding functions and base64 transform implementation.
13  * @Stability: Stable
14  *
15  */
16 
17 #include "globals.h"
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #include <libxml/tree.h>
24 
25 #include <xmlsec/xmlsec.h>
26 #include <xmlsec/keys.h>
27 #include <xmlsec/transforms.h>
28 #include <xmlsec/base64.h>
29 #include <xmlsec/errors.h>
30 
31 /*
32  * the table to map numbers to base64
33  */
34 static const xmlSecByte base64[] =
35 {
36 /*   0    1    2    3    4    5    6    7   */
37     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */
38     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */
39     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */
40     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */
41     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */
42     'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */
43     'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */
44     '4', '5', '6', '7', '8', '9', '+', '/'  /* 7 */
45 };
46 
47 
48 /* few macros to simplify the code */
49 #define xmlSecBase64Encode1(a)          (((a) >> 2) & 0x3F)
50 #define xmlSecBase64Encode2(a, b)       ((((a) << 4) & 0x30) + (((b) >> 4) & 0x0F))
51 #define xmlSecBase64Encode3(b, c)       ((((b) << 2) & 0x3c) + (((c) >> 6) & 0x03))
52 #define xmlSecBase64Encode4(c)          ((c) & 0x3F)
53 
54 #define xmlSecBase64Decode1(a, b)       (((a) << 2) | (((b) & 0x3F) >> 4))
55 #define xmlSecBase64Decode2(b, c)       (((b) << 4) | (((c) & 0x3F) >> 2))
56 #define xmlSecBase64Decode3(c, d)       (((c) << 6) | ((d) & 0x3F))
57 
58 #define xmlSecIsBase64Char(ch)          ((((ch) >= 'A') && ((ch) <= 'Z')) || \
59                                          (((ch) >= 'a') && ((ch) <= 'z')) || \
60                                          (((ch) >= '0') && ((ch) <= '9')) || \
61                                          ((ch) == '+') || ((ch) == '/'))
62 #define xmlSecIsBase64Space(ch)         (((ch) == ' ') || ((ch) == '\t') || \
63                                          ((ch) == '\x0d') || ((ch) == '\x0a'))
64 
65 
66 
67 /***********************************************************************
68  *
69  * Base64 Context
70  *
71  ***********************************************************************/
72 typedef enum {
73     xmlSecBase64StatusConsumeAndNext  = 0,
74     xmlSecBase64StatusConsumeAndRepeat,
75     xmlSecBase64StatusNext,
76     xmlSecBase64StatusDone,
77     xmlSecBase64StatusFailed
78 } xmlSecBase64Status;
79 
80 struct _xmlSecBase64Ctx {
81     int                 encode;
82     int                 inByte;
83     int                 inPos;
84     xmlSecSize          linePos;
85     xmlSecSize          columns;
86     int                 finished;
87 };
88 
89 static xmlSecBase64Status       xmlSecBase64CtxEncodeByte       (xmlSecBase64CtxPtr ctx,
90                                                                  xmlSecByte  inByte,
91                                                                  xmlSecByte* outByte);
92 static xmlSecBase64Status       xmlSecBase64CtxEncodeByteFinal  (xmlSecBase64CtxPtr ctx,
93                                                                  xmlSecByte* outByte);
94 static xmlSecBase64Status       xmlSecBase64CtxDecodeByte       (xmlSecBase64CtxPtr ctx,
95                                                                  xmlSecByte inByte,
96                                                                  xmlSecByte* outByte);
97 static int                      xmlSecBase64CtxEncode           (xmlSecBase64CtxPtr ctx,
98                                                                  const xmlSecByte* inBuf,
99                                                                  xmlSecSize inBufSize,
100                                                                  xmlSecSize* inBufResSize,
101                                                                  xmlSecByte* outBuf,
102                                                                  xmlSecSize outBufSize,
103                                                                  xmlSecSize* outBufResSize);
104 static int                      xmlSecBase64CtxEncodeFinal      (xmlSecBase64CtxPtr ctx,
105                                                                  xmlSecByte* outBuf,
106                                                                  xmlSecSize outBufSize,
107                                                                  xmlSecSize* outBufResSize);
108 static int                      xmlSecBase64CtxDecode           (xmlSecBase64CtxPtr ctx,
109                                                                  const xmlSecByte* inBuf,
110                                                                  xmlSecSize inBufSize,
111                                                                  xmlSecSize* inBufResSize,
112                                                                  xmlSecByte* outBuf,
113                                                                  xmlSecSize outBufSize,
114                                                                  xmlSecSize* outBufResSize);
115 static int                      xmlSecBase64CtxDecodeIsFinished (xmlSecBase64CtxPtr ctx);
116 
117 
118 static int g_xmlsec_base64_default_line_size = XMLSEC_BASE64_LINESIZE;
119 
120 /**
121  * xmlSecBase64GetDefaultLineSize:
122  *
123  * Gets the current default line size.
124  *
125  * Returns: the current default line size.
126  */
127 int
xmlSecBase64GetDefaultLineSize(void)128 xmlSecBase64GetDefaultLineSize(void)
129 {
130     return g_xmlsec_base64_default_line_size;
131 }
132 
133 /**
134  * xmlSecBase64SetDefaultLineSize:
135  * @columns: number of columns
136  *
137  * Sets the current default line size.
138  */
139 void
xmlSecBase64SetDefaultLineSize(int columns)140 xmlSecBase64SetDefaultLineSize(int columns)
141 {
142     g_xmlsec_base64_default_line_size = columns;
143 }
144 
145 /**
146  * xmlSecBase64CtxCreate:
147  * @encode:             the encode/decode flag (1 - encode, 0 - decode)
148  * @columns:            the max line length.
149  *
150  * Allocates and initializes new base64 context.
151  *
152  * Returns: a pointer to newly created #xmlSecBase64Ctx structure
153  * or NULL if an error occurs.
154  */
155 xmlSecBase64CtxPtr
xmlSecBase64CtxCreate(int encode,int columns)156 xmlSecBase64CtxCreate(int encode, int columns) {
157     xmlSecBase64CtxPtr ctx;
158     int ret;
159 
160     /*
161      * Allocate a new xmlSecBase64CtxPtr and fill the fields.
162      */
163     ctx = (xmlSecBase64CtxPtr) xmlMalloc(sizeof(xmlSecBase64Ctx));
164     if (ctx == NULL) {
165         xmlSecMallocError(sizeof(xmlSecBase64Ctx), NULL);
166         return(NULL);
167     }
168 
169     ret = xmlSecBase64CtxInitialize(ctx, encode, columns);
170     if(ret < 0) {
171         xmlSecInternalError("xmlSecBase64CtxInitialize", NULL);
172         xmlSecBase64CtxDestroy(ctx);
173         return(NULL);
174     }
175     return(ctx);
176 }
177 
178 /**
179  * xmlSecBase64CtxDestroy:
180  * @ctx:                the pointer to #xmlSecBase64Ctx structure.
181  *
182  * Destroys base64 context.
183  */
184 void
xmlSecBase64CtxDestroy(xmlSecBase64CtxPtr ctx)185 xmlSecBase64CtxDestroy(xmlSecBase64CtxPtr ctx) {
186     xmlSecAssert(ctx != NULL);
187 
188     xmlSecBase64CtxFinalize(ctx);
189     xmlFree(ctx);
190 }
191 
192 /**
193  * xmlSecBase64CtxInitialize:
194  * @ctx:                the pointer to #xmlSecBase64Ctx structure,
195  * @encode:             the encode/decode flag (1 - encode, 0 - decode)
196  * @columns:            the max line length.
197  *
198  * Initializes new base64 context.
199  *
200  * Returns: 0 on success and a negative value otherwise.
201  */
202 int
xmlSecBase64CtxInitialize(xmlSecBase64CtxPtr ctx,int encode,int columns)203 xmlSecBase64CtxInitialize(xmlSecBase64CtxPtr ctx, int encode, int columns) {
204     xmlSecAssert2(ctx != NULL, -1);
205 
206     memset(ctx, 0, sizeof(xmlSecBase64Ctx));
207 
208     ctx->encode     = encode;
209     ctx->columns    = columns;
210     return(0);
211 }
212 
213 /**
214  * xmlSecBase64CtxFinalize:
215  * @ctx:                the pointer to #xmlSecBase64Ctx structure,
216  *
217  * Frees all the resources allocated by @ctx.
218  */
219 void
xmlSecBase64CtxFinalize(xmlSecBase64CtxPtr ctx)220 xmlSecBase64CtxFinalize(xmlSecBase64CtxPtr ctx) {
221     xmlSecAssert(ctx != NULL);
222 
223     memset(ctx, 0, sizeof(xmlSecBase64Ctx));
224 }
225 
226 /**
227  * xmlSecBase64CtxUpdate:
228  * @ctx:                the pointer to #xmlSecBase64Ctx structure
229  * @in:                 the input buffer
230  * @inSize:             the input buffer size
231  * @out:                the output buffer
232  * @outSize:            the output buffer size
233  *
234  * Encodes or decodes the next piece of data from input buffer.
235  *
236  * Returns: the number of bytes written to output buffer or
237  * -1 if an error occurs.
238  */
239 int
xmlSecBase64CtxUpdate(xmlSecBase64CtxPtr ctx,const xmlSecByte * in,xmlSecSize inSize,xmlSecByte * out,xmlSecSize outSize)240 xmlSecBase64CtxUpdate(xmlSecBase64CtxPtr ctx,
241                      const xmlSecByte *in, xmlSecSize inSize,
242                      xmlSecByte *out, xmlSecSize outSize) {
243     xmlSecSize inResSize = 0, outResSize = 0;
244     int ret;
245 
246     xmlSecAssert2(ctx != NULL, -1);
247     xmlSecAssert2(in != NULL, -1);
248     xmlSecAssert2(out != NULL, -1);
249 
250     if(ctx->encode != 0) {
251         ret = xmlSecBase64CtxEncode(ctx, in, inSize, &inResSize,
252                                     out, outSize, &outResSize);
253         if((ret < 0) || (inResSize != inSize)) {
254             xmlSecInternalError("xmlSecBase64CtxEncode", NULL);
255             return(-1);
256         }
257     } else {
258         ret = xmlSecBase64CtxDecode(ctx, in, inSize, &inResSize,
259                                     out, outSize, &outResSize);
260         if((ret < 0) || (inResSize != inSize)) {
261             xmlSecInternalError("xmlSecBase64CtxDecode", NULL);
262             return(-1);
263         }
264     }
265 
266     return(outResSize);
267 }
268 
269 /**
270  * xmlSecBase64CtxFinal:
271  * @ctx:                the pointer to #xmlSecBase64Ctx structure
272  * @out:                the output buffer
273  * @outSize:            the output buffer size
274  *
275  * Encodes or decodes the last piece of data stored in the context
276  * and finalizes the result.
277  *
278  * Returns: the number of bytes written to output buffer or
279  * -1 if an error occurs.
280  */
281 int
xmlSecBase64CtxFinal(xmlSecBase64CtxPtr ctx,xmlSecByte * out,xmlSecSize outSize)282 xmlSecBase64CtxFinal(xmlSecBase64CtxPtr ctx,
283                     xmlSecByte *out, xmlSecSize outSize) {
284     xmlSecSize outResSize = 0;
285     int ret;
286 
287     xmlSecAssert2(ctx != NULL, -1);
288     xmlSecAssert2(out != NULL, -1);
289     xmlSecAssert2(outSize > 0, -1);
290 
291     if(ctx->encode != 0) {
292         ret = xmlSecBase64CtxEncodeFinal(ctx, out, outSize, &outResSize);
293         if(ret < 0) {
294             xmlSecInternalError2("xmlSecBase64CtxEncodeFinal", NULL, "outSize=%d", outSize);
295             return(-1);
296         }
297     } else {
298         if(!xmlSecBase64CtxDecodeIsFinished(ctx)) {
299             xmlSecInternalError("xmlSecBase64CtxDecodeIsFinished", NULL);
300             return(-1);
301         }
302     }
303 
304     /* add \0 */
305     if((outResSize + 1) < outSize) {
306         out[outResSize] = '\0';
307     }
308     return(outResSize);
309 }
310 
311 static xmlSecBase64Status
xmlSecBase64CtxEncodeByte(xmlSecBase64CtxPtr ctx,xmlSecByte inByte,xmlSecByte * outByte)312 xmlSecBase64CtxEncodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) {
313     xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed);
314     xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed);
315 
316     if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) {
317         (*outByte) = '\n';
318         ctx->linePos = 0;
319         return(xmlSecBase64StatusConsumeAndRepeat);
320     } else if(ctx->inPos == 0) {
321         /* we just started new block */
322         (*outByte) = base64[xmlSecBase64Encode1(inByte)];
323         ctx->inByte = inByte;
324         ++ctx->linePos;
325         ++ctx->inPos;
326         return(xmlSecBase64StatusConsumeAndNext);
327     } else if(ctx->inPos == 1) {
328         (*outByte) = base64[xmlSecBase64Encode2(ctx->inByte, inByte)];
329         ctx->inByte = inByte;
330         ++ctx->linePos;
331         ++ctx->inPos;
332         return(xmlSecBase64StatusConsumeAndNext);
333     } else if(ctx->inPos == 2) {
334         (*outByte) = base64[xmlSecBase64Encode3(ctx->inByte, inByte)];
335         ctx->inByte = inByte;
336         ++ctx->linePos;
337         ++ctx->inPos;
338         return(xmlSecBase64StatusConsumeAndRepeat);
339     } else if(ctx->inPos == 3) {
340         (*outByte) = base64[xmlSecBase64Encode4(ctx->inByte)];
341         ++ctx->linePos;
342         ctx->inByte = 0;
343         ctx->inPos  = 0;
344         return(xmlSecBase64StatusConsumeAndNext);
345     }
346 
347     xmlSecInvalidIntegerDataError("ctx->inPos", ctx->inPos, "0,1,2,3", NULL);
348     return(xmlSecBase64StatusFailed);
349 }
350 
351 static xmlSecBase64Status
xmlSecBase64CtxEncodeByteFinal(xmlSecBase64CtxPtr ctx,xmlSecByte * outByte)352 xmlSecBase64CtxEncodeByteFinal(xmlSecBase64CtxPtr ctx, xmlSecByte* outByte) {
353     xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed);
354     xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed);
355 
356     if(ctx->inPos == 0) {
357         return(xmlSecBase64StatusDone);
358     } else if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) {
359         (*outByte) = '\n';
360         ctx->linePos = 0;
361         return(xmlSecBase64StatusConsumeAndRepeat);
362     } else if(ctx->finished == 0) {
363         ctx->finished = 1;
364         return(xmlSecBase64CtxEncodeByte(ctx, 0, outByte));
365     } else if(ctx->inPos < 3) {
366         (*outByte) = '=';
367         ++ctx->inPos;
368         ++ctx->linePos;
369         return(xmlSecBase64StatusConsumeAndRepeat);
370     } else if(ctx->inPos == 3) {
371         (*outByte) = '=';
372         ++ctx->linePos;
373         ctx->inPos = 0;
374         return(xmlSecBase64StatusConsumeAndRepeat);
375     }
376 
377     xmlSecInvalidIntegerDataError("ctx->inPos", ctx->inPos, "0,1,2,3", NULL);
378     return(xmlSecBase64StatusFailed);
379 }
380 
381 static xmlSecBase64Status
xmlSecBase64CtxDecodeByte(xmlSecBase64CtxPtr ctx,xmlSecByte inByte,xmlSecByte * outByte)382 xmlSecBase64CtxDecodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) {
383     xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed);
384     xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed);
385 
386     if((ctx->finished != 0) && (ctx->inPos == 0)) {
387         return(xmlSecBase64StatusDone);
388     } if(inByte == '=') {
389         ctx->finished = 1;
390         if(ctx->inPos == 2) {
391             ++ctx->inPos;
392             return(xmlSecBase64StatusNext);
393         } else if(ctx->inPos == 3) {
394             ctx->inPos = 0;
395             return(xmlSecBase64StatusNext);
396         } else {
397             xmlSecInvalidIntegerDataError("ctx->inPos", ctx->inPos, "2,3", NULL);
398             return(xmlSecBase64StatusFailed);
399         }
400     } else if(xmlSecIsBase64Space(inByte)) {
401         return(xmlSecBase64StatusNext);
402     } else if(!xmlSecIsBase64Char(inByte) || (ctx->finished != 0)) {
403         xmlSecInvalidIntegerDataError("inByte", inByte, "base64 character", NULL);
404         return(xmlSecBase64StatusFailed);
405     }
406 
407     /* convert from character to position in base64 array */
408     if((inByte >= 'A') && (inByte <= 'Z')) {
409         inByte = (inByte - 'A');
410     } else if((inByte >= 'a') && (inByte <= 'z')) {
411         inByte = 26 + (inByte - 'a');
412     } else if((inByte >= '0') && (inByte <= '9')) {
413         inByte = 52 + (inByte - '0');
414     } else if(inByte == '+') {
415         inByte = 62;
416     } else if(inByte == '/') {
417         inByte = 63;
418     }
419 
420     if(ctx->inPos == 0) {
421         ctx->inByte = inByte;
422         ++ctx->inPos;
423         return(xmlSecBase64StatusNext);
424     } else if(ctx->inPos == 1) {
425         (*outByte) = (xmlSecByte)xmlSecBase64Decode1(ctx->inByte, inByte);
426         ctx->inByte = inByte;
427         ++ctx->inPos;
428         return(xmlSecBase64StatusConsumeAndNext);
429     } else if(ctx->inPos == 2) {
430         (*outByte) = (xmlSecByte)xmlSecBase64Decode2(ctx->inByte, inByte);
431         ctx->inByte = inByte;
432         ++ctx->inPos;
433         return(xmlSecBase64StatusConsumeAndNext);
434     } else if(ctx->inPos == 3) {
435         (*outByte) = (xmlSecByte)xmlSecBase64Decode3(ctx->inByte, inByte);
436         ctx->inByte = 0;
437         ctx->inPos = 0;
438         return(xmlSecBase64StatusConsumeAndNext);
439     }
440 
441     xmlSecInvalidIntegerDataError("ctx->inPos", ctx->inPos, "0,1,2,3", NULL);
442     return(xmlSecBase64StatusFailed);
443 }
444 
445 
446 static int
xmlSecBase64CtxEncode(xmlSecBase64CtxPtr ctx,const xmlSecByte * inBuf,xmlSecSize inBufSize,xmlSecSize * inBufResSize,xmlSecByte * outBuf,xmlSecSize outBufSize,xmlSecSize * outBufResSize)447 xmlSecBase64CtxEncode(xmlSecBase64CtxPtr ctx,
448                      const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize,
449                      xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) {
450     xmlSecBase64Status status = xmlSecBase64StatusNext;
451     xmlSecSize inPos, outPos;
452 
453     xmlSecAssert2(ctx != NULL, -1);
454     xmlSecAssert2(inBuf != NULL, -1);
455     xmlSecAssert2(inBufResSize != NULL, -1);
456     xmlSecAssert2(outBuf != NULL, -1);
457     xmlSecAssert2(outBufResSize != NULL, -1);
458 
459     /* encode */
460     for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize); ) {
461         status = xmlSecBase64CtxEncodeByte(ctx, inBuf[inPos], &(outBuf[outPos]));
462         switch(status) {
463             case xmlSecBase64StatusConsumeAndNext:
464                 ++inPos;
465                 ++outPos;
466                 break;
467             case xmlSecBase64StatusConsumeAndRepeat:
468                 ++outPos;
469                 break;
470             case xmlSecBase64StatusNext:
471             case xmlSecBase64StatusDone:
472             case xmlSecBase64StatusFailed:
473                 xmlSecInternalError2("xmlSecBase64CtxEncodeByte", NULL, "status=%d", status);
474                 return(-1);
475         }
476     }
477 
478     (*inBufResSize)  = inPos;
479     (*outBufResSize) = outPos;
480 
481     return(0);
482 }
483 
484 static int
xmlSecBase64CtxEncodeFinal(xmlSecBase64CtxPtr ctx,xmlSecByte * outBuf,xmlSecSize outBufSize,xmlSecSize * outBufResSize)485 xmlSecBase64CtxEncodeFinal(xmlSecBase64CtxPtr ctx,
486                      xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) {
487     xmlSecBase64Status status = xmlSecBase64StatusNext;
488     xmlSecSize outPos;
489 
490     xmlSecAssert2(ctx != NULL, -1);
491     xmlSecAssert2(outBuf != NULL, -1);
492     xmlSecAssert2(outBufResSize != NULL, -1);
493 
494     /* encode final bytes */
495     for(outPos = 0; (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) {
496         status = xmlSecBase64CtxEncodeByteFinal(ctx, &(outBuf[outPos]));
497         switch(status) {
498             case xmlSecBase64StatusConsumeAndNext:
499             case xmlSecBase64StatusConsumeAndRepeat:
500                 ++outPos;
501                 break;
502             case xmlSecBase64StatusDone:
503                 break;
504             case xmlSecBase64StatusNext:
505             case xmlSecBase64StatusFailed:
506                 xmlSecInternalError2("xmlSecBase64CtxEncodeByteFinal", NULL, "status=%d", status);
507                 return(-1);
508         }
509     }
510 
511     if(status != xmlSecBase64StatusDone) {
512         xmlSecInvalidSizeOtherError("invalid base64 buffer size", NULL);
513         return(-1);
514     }
515     if(outPos < outBufSize) {
516         outBuf[outPos] = '\0'; /* just in case */
517     }
518 
519     (*outBufResSize) = outPos;
520     return(0);
521 }
522 
523 
524 static int
xmlSecBase64CtxDecode(xmlSecBase64CtxPtr ctx,const xmlSecByte * inBuf,xmlSecSize inBufSize,xmlSecSize * inBufResSize,xmlSecByte * outBuf,xmlSecSize outBufSize,xmlSecSize * outBufResSize)525 xmlSecBase64CtxDecode(xmlSecBase64CtxPtr ctx,
526                      const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize,
527                      xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) {
528     xmlSecBase64Status status = xmlSecBase64StatusNext;
529     xmlSecSize inPos, outPos;
530 
531     xmlSecAssert2(ctx != NULL, -1);
532     xmlSecAssert2(inBuf != NULL, -1);
533     xmlSecAssert2(inBufResSize != NULL, -1);
534     xmlSecAssert2(outBuf != NULL, -1);
535     xmlSecAssert2(outBufResSize != NULL, -1);
536 
537     /* decode */
538     for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) {
539         status = xmlSecBase64CtxDecodeByte(ctx, inBuf[inPos], &(outBuf[outPos]));
540         switch(status) {
541             case xmlSecBase64StatusConsumeAndNext:
542                 ++inPos;
543                 ++outPos;
544                 break;
545             case xmlSecBase64StatusConsumeAndRepeat:
546                 ++outPos;
547                 break;
548             case xmlSecBase64StatusNext:
549                 ++inPos;
550                 break;
551             case xmlSecBase64StatusDone:
552                 break;
553             case xmlSecBase64StatusFailed:
554                 xmlSecInternalError2("xmlSecBase64CtxDecodeByte", NULL, "status=%d", status);
555                 return(-1);
556         }
557     }
558 
559     /* skip spaces at the end */
560     while((inPos < inBufSize) && xmlSecIsBase64Space(inBuf[inPos])) {
561         ++inPos;
562     }
563 
564     (*inBufResSize)  = inPos;
565     (*outBufResSize) = outPos;
566 
567     return(0);
568 }
569 
570 static int
xmlSecBase64CtxDecodeIsFinished(xmlSecBase64CtxPtr ctx)571 xmlSecBase64CtxDecodeIsFinished(xmlSecBase64CtxPtr ctx) {
572     xmlSecAssert2(ctx != NULL, -1);
573 
574     return((ctx->inPos == 0) ? 1 : 0);
575 }
576 
577 /**
578  * xmlSecBase64Encode:
579  * @buf:                the input buffer.
580  * @len:                the input buffer size.
581  * @columns:            the output max line length (if 0 then no line breaks
582  *                      would be inserted)
583  *
584  * Encodes the data from input buffer and allocates the string for the result.
585  * The caller is responsible for freeing returned buffer using
586  * xmlFree() function.
587  *
588  * Returns: newly allocated string with base64 encoded data
589  * or NULL if an error occurs.
590  */
591 xmlChar*
xmlSecBase64Encode(const xmlSecByte * buf,xmlSecSize len,int columns)592 xmlSecBase64Encode(const xmlSecByte *buf, xmlSecSize len, int columns) {
593     xmlSecBase64Ctx ctx;
594     xmlChar *ptr;
595     xmlSecSize size;
596     int size_update, size_final;
597     int ret;
598 
599     xmlSecAssert2(buf != NULL, NULL);
600 
601     ret = xmlSecBase64CtxInitialize(&ctx, 1, columns);
602     if(ret < 0) {
603         xmlSecInternalError("xmlSecBase64CtxInitialize", NULL);
604         return(NULL);
605     }
606 
607     /* create result buffer */
608     size = (4 * len) / 3 + 4;
609     if(columns > 0) {
610         size += (size / columns) + 4;
611     }
612     ptr = (xmlChar*) xmlMalloc(size);
613     if(ptr == NULL) {
614         xmlSecMallocError(size, NULL);
615         xmlSecBase64CtxFinalize(&ctx);
616         return(NULL);
617     }
618 
619     ret = xmlSecBase64CtxUpdate(&ctx, buf, len, (xmlSecByte*)ptr, size);
620     if(ret < 0) {
621         xmlSecInternalError3("xmlSecBase64CtxUpdate", NULL,
622                              "len=%lu;size=%lu",
623                              (unsigned long)len, (unsigned long)size);
624         xmlFree(ptr);
625         xmlSecBase64CtxFinalize(&ctx);
626         return(NULL);
627     }
628     size_update = ret;
629 
630     ret = xmlSecBase64CtxFinal(&ctx, ((xmlSecByte*)ptr) + size_update, size - size_update);
631     if(ret < 0) {
632         xmlSecInternalError("xmlSecBase64CtxFinal", NULL);
633         xmlFree(ptr);
634         xmlSecBase64CtxFinalize(&ctx);
635         return(NULL);
636     }
637     size_final = ret;
638     ptr[size_update + size_final] = '\0';
639 
640     xmlSecBase64CtxFinalize(&ctx);
641     return(ptr);
642 }
643 
644 /**
645  * xmlSecBase64Decode:
646  * @str:                the input buffer with base64 encoded string
647  * @buf:                the output buffer
648  * @len:                the output buffer size
649  *
650  * Decodes input base64 encoded string and puts result into
651  * the output buffer.
652  *
653  * Returns: the number of bytes written to the output buffer or
654  * a negative value if an error occurs
655  */
656 int
xmlSecBase64Decode(const xmlChar * str,xmlSecByte * buf,xmlSecSize len)657 xmlSecBase64Decode(const xmlChar* str, xmlSecByte *buf, xmlSecSize len) {
658     xmlSecBase64Ctx ctx;
659     int size_update;
660     int size_final;
661     int ret;
662 
663     xmlSecAssert2(str != NULL, -1);
664     xmlSecAssert2(buf != NULL, -1);
665 
666     ret = xmlSecBase64CtxInitialize(&ctx, 0, 0);
667     if(ret < 0) {
668         xmlSecInternalError("xmlSecBase64CtxInitialize", NULL);
669         return(-1);
670     }
671 
672     ret = xmlSecBase64CtxUpdate(&ctx, (const xmlSecByte*)str, xmlStrlen(str), buf, len);
673     if(ret < 0) {
674         xmlSecInternalError("xmlSecBase64CtxUpdate", NULL);
675         xmlSecBase64CtxFinalize(&ctx);
676         return(-1);
677     }
678 
679     size_update = ret;
680     ret = xmlSecBase64CtxFinal(&ctx, buf + size_update, len - size_update);
681     if(ret < 0) {
682         xmlSecInternalError("xmlSecBase64CtxFinal", NULL);
683         xmlSecBase64CtxFinalize(&ctx);
684         return(-1);
685     }
686     size_final = ret;
687 
688     xmlSecBase64CtxFinalize(&ctx);
689     return(size_update + size_final);
690 }
691 
692 /**************************************************************
693  *
694  * Base64 Transform
695  *
696  * xmlSecBase64Ctx is located after xmlSecTransform
697  *
698  **************************************************************/
699 #define xmlSecBase64Size \
700         (sizeof(xmlSecTransform) + sizeof(xmlSecBase64Ctx))
701 #define xmlSecBase64GetCtx(transform) \
702     ((xmlSecTransformCheckSize((transform), xmlSecBase64Size)) ? \
703         (xmlSecBase64CtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
704         (xmlSecBase64CtxPtr)NULL)
705 
706 static int              xmlSecBase64Initialize          (xmlSecTransformPtr transform);
707 static void             xmlSecBase64Finalize            (xmlSecTransformPtr transform);
708 static int              xmlSecBase64Execute             (xmlSecTransformPtr transform,
709                                                          int last,
710                                                          xmlSecTransformCtxPtr transformCtx);
711 
712 static xmlSecTransformKlass xmlSecBase64Klass = {
713     /* klass/object sizes */
714     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
715     xmlSecBase64Size,                           /* xmlSecSize objSize */
716 
717     xmlSecNameBase64,                           /* const xmlChar* name; */
718     xmlSecHrefBase64,                           /* const xmlChar* href; */
719     xmlSecTransformUsageDSigTransform,          /* xmlSecAlgorithmUsage usage; */
720 
721     xmlSecBase64Initialize,                     /* xmlSecTransformInitializeMethod initialize; */
722     xmlSecBase64Finalize,                       /* xmlSecTransformFinalizeMethod finalize; */
723     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
724     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
725     NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
726     NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
727     NULL,                                       /* xmlSecTransformValidateMethod validate; */
728     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
729     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
730     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
731     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
732     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
733     xmlSecBase64Execute,                        /* xmlSecTransformExecuteMethod execute; */
734 
735     NULL,                                       /* void* reserved0; */
736     NULL,                                       /* void* reserved1; */
737 };
738 
739 /**
740  * xmlSecTransformBase64GetKlass:
741  *
742  * The Base64 transform klass (http://www.w3.org/TR/xmldsig-core/#sec-Base-64).
743  * The normative specification for base64 decoding transforms is RFC 2045
744  * (http://www.ietf.org/rfc/rfc2045.txt). The base64 Transform element has
745  * no content. The input is decoded by the algorithms. This transform is
746  * useful if an application needs to sign the raw data associated with
747  * the encoded content of an element.
748  *
749  * Returns: base64 transform id.
750  */
751 xmlSecTransformId
xmlSecTransformBase64GetKlass(void)752 xmlSecTransformBase64GetKlass(void) {
753     return(&xmlSecBase64Klass);
754 }
755 
756 /**
757  * xmlSecTransformBase64SetLineSize:
758  * @transform:          the pointer to BASE64 encode transform.
759  * @lineSize:           the new max line size.
760  *
761  * Sets the max line size to @lineSize.
762  */
763 void
xmlSecTransformBase64SetLineSize(xmlSecTransformPtr transform,xmlSecSize lineSize)764 xmlSecTransformBase64SetLineSize(xmlSecTransformPtr transform, xmlSecSize lineSize) {
765     xmlSecBase64CtxPtr ctx;
766 
767     xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id));
768 
769     ctx = xmlSecBase64GetCtx(transform);
770     xmlSecAssert(ctx != NULL);
771 
772     ctx->columns = lineSize;
773 }
774 
775 static int
xmlSecBase64Initialize(xmlSecTransformPtr transform)776 xmlSecBase64Initialize(xmlSecTransformPtr transform) {
777     xmlSecBase64CtxPtr ctx;
778     int ret;
779 
780     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1);
781 
782     ctx = xmlSecBase64GetCtx(transform);
783     xmlSecAssert2(ctx != NULL, -1);
784 
785     transform->operation = xmlSecTransformOperationDecode;
786     ret = xmlSecBase64CtxInitialize(ctx, 0, xmlSecBase64GetDefaultLineSize());
787     if(ret < 0) {
788         xmlSecInternalError("xmlSecBase64CtxInitialize",
789                             xmlSecTransformGetName(transform));
790         return(-1);
791     }
792 
793     return(0);
794 }
795 
796 static void
xmlSecBase64Finalize(xmlSecTransformPtr transform)797 xmlSecBase64Finalize(xmlSecTransformPtr transform) {
798     xmlSecBase64CtxPtr ctx;
799 
800     xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id));
801 
802     ctx = xmlSecBase64GetCtx(transform);
803     xmlSecAssert(ctx != NULL);
804 
805     xmlSecBase64CtxFinalize(ctx);
806 }
807 
808 static int
xmlSecBase64Execute(xmlSecTransformPtr transform,int last,xmlSecTransformCtxPtr transformCtx)809 xmlSecBase64Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
810     xmlSecBase64CtxPtr ctx;
811     xmlSecBufferPtr in, out;
812     xmlSecSize inSize, outSize, outLen;
813     int ret;
814 
815     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1);
816     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncode) || (transform->operation == xmlSecTransformOperationDecode), -1);
817     xmlSecAssert2(transformCtx != NULL, -1);
818 
819     ctx = xmlSecBase64GetCtx(transform);
820     xmlSecAssert2(ctx != NULL, -1);
821 
822     in = &(transform->inBuf);
823     out = &(transform->outBuf);
824 
825     if(transform->status == xmlSecTransformStatusNone) {
826         ctx->encode = (transform->operation == xmlSecTransformOperationEncode) ? 1 : 0;
827         transform->status = xmlSecTransformStatusWorking;
828     }
829 
830     switch(transform->status) {
831         case xmlSecTransformStatusWorking:
832             inSize = xmlSecBufferGetSize(in);
833             outSize = xmlSecBufferGetSize(out);
834             if(inSize > 0) {
835                 if(ctx->encode != 0) {
836                     outLen = 4 * inSize / 3 + 8;
837                     if(ctx->columns > 0) {
838                         outLen += inSize / ctx->columns + 4;
839                     }
840                 } else {
841                     outLen = 3 * inSize / 4 + 8;
842                 }
843                 ret = xmlSecBufferSetMaxSize(out, outSize + outLen);
844                 if(ret < 0) {
845                     xmlSecInternalError2("xmlSecBufferSetMaxSize",
846                                          xmlSecTransformGetName(transform),
847                                          "size=%d", outSize + outLen);
848                     return(-1);
849                 }
850 
851                 /* encode/decode the next chunk */
852                 ret = xmlSecBase64CtxUpdate(ctx, xmlSecBufferGetData(in), inSize,
853                                             xmlSecBufferGetData(out) + outSize,
854                                             outLen);
855                 if(ret < 0) {
856                     xmlSecInternalError("xmlSecBase64CtxUpdate",
857                                         xmlSecTransformGetName(transform));
858                     return(-1);
859                 }
860                 outLen = ret;
861 
862                 /* set correct size */
863                 ret = xmlSecBufferSetSize(out, outSize + outLen);
864                 if(ret < 0) {
865                     xmlSecInternalError2("xmlSecBufferSetSize",
866                                          xmlSecTransformGetName(transform),
867                                          "size=%d", outSize + outLen);
868                     return(-1);
869                 }
870 
871                 /* remove chunk from input */
872                 ret = xmlSecBufferRemoveHead(in, inSize);
873                 if(ret < 0) {
874                     xmlSecInternalError2("xmlSecBufferRemoveHead",
875                                          xmlSecTransformGetName(transform),
876                                          "size=%d", inSize);
877                     return(-1);
878                 }
879             }
880 
881             if(last) {
882                 outSize = xmlSecBufferGetSize(out);
883 
884                 ret = xmlSecBufferSetMaxSize(out, outSize + 16);
885                 if(ret < 0) {
886                     xmlSecInternalError2("xmlSecBufferSetMaxSize",
887                                          xmlSecTransformGetName(transform),
888                                          "size=%d", outSize + 16);
889                     return(-1);
890                 }
891 
892                 /* add from ctx buffer */
893                 ret = xmlSecBase64CtxFinal(ctx, xmlSecBufferGetData(out) + outSize, 16);
894                 if(ret < 0) {
895                     xmlSecInternalError("xmlSecBase64CtxFinal",
896                                         xmlSecTransformGetName(transform));
897                     return(-1);
898                 }
899                 outLen = ret;
900 
901                 /* set correct size */
902                 ret = xmlSecBufferSetSize(out, outSize + outLen);
903                 if(ret < 0) {
904                     xmlSecInternalError2("xmlSecBufferSetSize",
905                                          xmlSecTransformGetName(transform),
906                                          "size=%d", outSize + outLen);
907                     return(-1);
908                 }
909                 transform->status = xmlSecTransformStatusFinished;
910             }
911             break;
912         case xmlSecTransformStatusFinished:
913             /* the only way we can get here is if there is no input */
914             xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1);
915             break;
916         default:
917             xmlSecInvalidTransfromStatusError(transform);
918             return(-1);
919     }
920     return(0);
921 }
922 
923 
924