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