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