Coverage Report

Created: 2024-11-21 07:03

/src/wolfssl/wolfcrypt/src/coding.c
Line
Count
Source (jump to first uncovered line)
1
/* coding.c
2
 *
3
 * Copyright (C) 2006-2024 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
23
#ifdef HAVE_CONFIG_H
24
    #include <config.h>
25
#endif
26
27
#include <wolfssl/wolfcrypt/settings.h>
28
29
#ifndef NO_CODING
30
31
#include <wolfssl/wolfcrypt/coding.h>
32
#include <wolfssl/wolfcrypt/error-crypt.h>
33
#include <wolfssl/wolfcrypt/logging.h>
34
#ifndef NO_ASN
35
    #include <wolfssl/wolfcrypt/asn.h> /* For PEM_LINE_SZ */
36
#endif
37
#ifdef NO_INLINE
38
    #include <wolfssl/wolfcrypt/misc.h>
39
#else
40
    #define WOLFSSL_MISC_INCLUDED
41
    #include <wolfcrypt/src/misc.c>
42
#endif
43
44
enum {
45
    BAD         = 0xFF,  /* invalid encoding */
46
    PAD         = '=',
47
    BASE64_MIN  = 0x2B,
48
    BASE16_MIN  = 0x30
49
};
50
51
52
#ifndef BASE64_LINE_SZ
53
    #ifdef NO_ASN
54
        #define BASE64_LINE_SZ 64
55
    #else
56
0
        #define BASE64_LINE_SZ PEM_LINE_SZ
57
    #endif
58
#endif
59
60
#ifdef WOLFSSL_BASE64_DECODE
61
62
#ifdef BASE64_NO_TABLE
63
static WC_INLINE byte Base64_Char2Val(byte c)
64
{
65
    word16 v = 0x0000;
66
67
    v |= 0xff3E & ctMask16Eq(c, 0x2b);
68
    v |= 0xff3F & ctMask16Eq(c, 0x2f);
69
    v |= (c + 0xff04) & ctMask16GTE(c, 0x30) & ctMask16LTE(c, 0x39);
70
    v |= (0xff00 + c - 0x41) & ctMask16GTE(c, 0x41) & ctMask16LTE(c, 0x5a);
71
    v |= (0xff00 + c - 0x47) & ctMask16GTE(c, 0x61) & ctMask16LTE(c, 0x7a);
72
    v |= ~(v >> 8);
73
74
    return (byte)v;
75
}
76
#else
77
static
78
ALIGN64 const byte base64Decode[] = {          /* + starts at 0x2B */
79
/* 0x28:       + , - . / */                   62, BAD, BAD, BAD,  63,
80
/* 0x30: 0 1 2 3 4 5 6 7 */    52,  53,  54,  55,  56,  57,  58,  59,
81
/* 0x38: 8 9 : ; < = > ? */    60,  61, BAD, BAD, BAD, BAD, BAD, BAD,
82
/* 0x40: @ A B C D E F G */   BAD,   0,   1,   2,   3,   4,   5,   6,
83
/* 0x48: H I J K L M N O */     7,   8,   9,  10,  11,  12,  13,  14,
84
/* 0x50: P Q R S T U V W */    15,  16,  17,  18,  19,  20,  21,  22,
85
/* 0x58: X Y Z [ \ ] ^ _ */    23,  24,  25, BAD, BAD, BAD, BAD, BAD,
86
/* 0x60: ` a b c d e f g */   BAD,  26,  27,  28,  29,  30,  31,  32,
87
/* 0x68: h i j k l m n o */    33,  34,  35,  36,  37,  38,  39,  40,
88
/* 0x70: p q r s t u v w */    41,  42,  43,  44,  45,  46,  47,  48,
89
/* 0x78: x y z           */    49,  50,  51
90
                            };
91
0
#define BASE64DECODE_SZ    (byte)(sizeof(base64Decode))
92
93
static WC_INLINE byte Base64_Char2Val(byte c)
94
0
{
95
0
#ifndef WC_NO_CACHE_RESISTANT
96
    /* 80 characters in table.
97
     * 64 bytes in a cache line - first line has 64, second has 16
98
     */
99
0
    byte v;
100
0
    byte mask;
101
102
0
    c -= BASE64_MIN;
103
0
    mask = (byte)((((byte)(0x3f - c)) >> 7) - 1);
104
    /* Load a value from the first cache line and use when mask set. */
105
0
    v  = (byte)(base64Decode[ c & 0x3f        ] &   mask);
106
    /* Load a value from the second cache line and use when mask not set. */
107
0
    v |= (byte)(base64Decode[(c & 0x0f) | 0x40] & (~mask));
108
109
0
    return v;
110
#else
111
    return base64Decode[c - BASE64_MIN];
112
#endif
113
0
}
114
#endif
115
116
int Base64_SkipNewline(const byte* in, word32 *inLen,
117
  word32 *outJ)
118
0
{
119
0
    word32 len = *inLen;
120
0
    word32 j = *outJ;
121
0
    byte curChar;
122
123
0
    if (len == 0) {
124
0
        return BUFFER_E;
125
0
    }
126
0
    curChar = in[j];
127
128
0
    while (len > 1 && curChar == ' ') {
129
        /* skip whitespace in the middle or end of line */
130
0
        curChar = in[++j];
131
0
        len--;
132
0
    }
133
0
    if (len && (curChar == '\r' || curChar == '\n')) {
134
0
        j++;
135
0
        len--;
136
0
        if (curChar == '\r') {
137
0
            if (len) {
138
0
                curChar = in[j++];
139
0
                len--;
140
0
            }
141
0
        }
142
0
        if (curChar != '\n') {
143
0
            WOLFSSL_MSG("Bad end of line in Base64 Decode");
144
0
            return ASN_INPUT_E;
145
0
        }
146
147
0
        if (len) {
148
0
            curChar = in[j];
149
0
        }
150
0
    }
151
0
    while (len && curChar == ' ') {
152
0
        if (--len > 0) {
153
0
            curChar = in[++j];
154
0
        }
155
0
    }
156
0
    if (!len) {
157
0
        return BUFFER_E;
158
0
    }
159
0
    *inLen = len;
160
0
    *outJ = j;
161
0
    return 0;
162
0
}
163
164
int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
165
0
{
166
0
    word32 i = 0;
167
0
    word32 j = 0;
168
0
    word32 plainSz = inLen - ((inLen + (BASE64_LINE_SZ - 1)) / BASE64_LINE_SZ );
169
0
    int ret;
170
0
#ifndef BASE64_NO_TABLE
171
0
    const byte maxIdx = BASE64DECODE_SZ + BASE64_MIN - 1;
172
0
#endif
173
174
0
    plainSz = (plainSz * 3 + 3) / 4;
175
0
    if (plainSz > *outLen) return BAD_FUNC_ARG;
176
177
0
    while (inLen > 3) {
178
0
        int pad3 = 0;
179
0
        int pad4 = 0;
180
0
        byte b1, b2, b3;
181
0
        byte e1, e2, e3, e4;
182
183
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
184
0
            if (ret == WC_NO_ERR_TRACE(BUFFER_E)) {
185
                /* Running out of buffer here is not an error */
186
0
                break;
187
0
            }
188
0
            return ret;
189
0
        }
190
0
        e1 = in[j++];
191
0
        if (e1 == '\0') {
192
0
            break;
193
0
        }
194
0
        inLen--;
195
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
196
0
            return ret;
197
0
        }
198
0
        e2 = in[j++];
199
0
        inLen--;
200
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
201
0
            return ret;
202
0
        }
203
0
        e3 = in[j++];
204
0
        inLen--;
205
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
206
0
            return ret;
207
0
        }
208
0
        e4 = in[j++];
209
0
        inLen--;
210
211
0
        if (e3 == PAD)
212
0
            pad3 = 1;
213
0
        if (e4 == PAD)
214
0
            pad4 = 1;
215
216
0
        if (pad3 && !pad4)
217
0
            return ASN_INPUT_E;
218
219
0
#ifndef BASE64_NO_TABLE
220
0
        if (e1 < BASE64_MIN || e2 < BASE64_MIN || e3 < BASE64_MIN ||
221
0
                                                              e4 < BASE64_MIN) {
222
0
            WOLFSSL_MSG("Bad Base64 Decode data, too small");
223
0
            return ASN_INPUT_E;
224
0
        }
225
226
0
        if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
227
0
            WOLFSSL_MSG("Bad Base64 Decode data, too big");
228
0
            return ASN_INPUT_E;
229
0
        }
230
0
#endif
231
232
0
        if (i + 1 + !pad3 + !pad4 > *outLen) {
233
0
            WOLFSSL_MSG("Bad Base64 Decode out buffer, too small");
234
0
            return BAD_FUNC_ARG;
235
0
        }
236
237
0
        e1 = Base64_Char2Val(e1);
238
0
        e2 = Base64_Char2Val(e2);
239
0
        e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val(e3));
240
0
        e4 = (byte)((e4 == PAD) ? 0 : Base64_Char2Val(e4));
241
242
0
        if (e1 == BAD || e2 == BAD || e3 == BAD || e4 == BAD) {
243
0
            WOLFSSL_MSG("Bad Base64 Decode bad character");
244
0
            return ASN_INPUT_E;
245
0
        }
246
247
0
        b1 = (byte)((e1 << 2) | (e2 >> 4));
248
0
        b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
249
0
        b3 = (byte)(((e3 & 0x3) << 6) | e4);
250
251
0
        out[i++] = b1;
252
0
        if (!pad3)
253
0
            out[i++] = b2;
254
0
        if (!pad4)
255
0
            out[i++] = b3;
256
0
        else
257
0
            break;
258
0
    }
259
/* If the output buffer has a room for an extra byte, add a null terminator */
260
0
    if (out && *outLen > i)
261
0
        out[i]= '\0';
262
263
0
    *outLen = i;
264
265
0
    return 0;
266
0
}
267
268
#endif /* WOLFSSL_BASE64_DECODE */
269
270
#if defined(WOLFSSL_BASE64_ENCODE)
271
272
static
273
const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
274
                              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
275
                              'U', 'V', 'W', 'X', 'Y', 'Z',
276
                              'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
277
                              'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
278
                              'u', 'v', 'w', 'x', 'y', 'z',
279
                              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
280
                              '+', '/'
281
                            };
282
283
284
/* make sure *i (idx) won't exceed max, store and possibly escape to out,
285
 * raw means use e w/o decode,  0 on success */
286
static int CEscape(int escaped, byte e, byte* out, word32* i, word32 maxSz,
287
                  int raw, int getSzOnly)
288
0
{
289
0
    int    doEscape = 0;
290
0
    word32 needed = 1;
291
0
    word32 idx = *i;
292
293
0
    byte basic;
294
0
    byte plus    = 0;
295
0
    byte equals  = 0;
296
0
    byte newline = 0;
297
298
0
    if (raw)
299
0
        basic = e;
300
0
    else
301
0
        basic = base64Encode[e];
302
303
    /* check whether to escape. Only escape for EncodeEsc */
304
0
    if (escaped == WC_ESC_NL_ENC) {
305
0
        switch ((char)basic) {
306
0
            case '+' :
307
0
                plus     = 1;
308
0
                doEscape = 1;
309
0
                needed  += 2;
310
0
                break;
311
0
            case '=' :
312
0
                equals   = 1;
313
0
                doEscape = 1;
314
0
                needed  += 2;
315
0
                break;
316
0
            case '\n' :
317
0
                newline  = 1;
318
0
                doEscape = 1;
319
0
                needed  += 2;
320
0
                break;
321
0
            default:
322
                /* do nothing */
323
0
                break;
324
0
        }
325
0
    }
326
327
    /* check size */
328
0
    if ( (idx+needed) > maxSz && !getSzOnly) {
329
0
        WOLFSSL_MSG("Escape buffer max too small");
330
0
        return BUFFER_E;
331
0
    }
332
333
    /* store it */
334
0
    if (doEscape == 0) {
335
0
        if(getSzOnly)
336
0
            idx++;
337
0
        else
338
0
            out[idx++] = basic;
339
0
    }
340
0
    else {
341
0
        if(getSzOnly)
342
0
            idx+=3;
343
0
        else {
344
0
            out[idx++] = '%';  /* start escape */
345
346
0
            if (plus) {
347
0
                out[idx++] = '2';
348
0
                out[idx++] = 'B';
349
0
            }
350
0
            else if (equals) {
351
0
                out[idx++] = '3';
352
0
                out[idx++] = 'D';
353
0
            }
354
0
            else if (newline) {
355
0
                out[idx++] = '0';
356
0
                out[idx++] = 'A';
357
0
            }
358
0
        }
359
0
    }
360
0
    *i = idx;
361
362
0
    return 0;
363
0
}
364
365
366
/* internal worker, handles both escaped and normal line endings.
367
   If out buffer is NULL, will return sz needed in outLen */
368
static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
369
                           word32* outLen, int escaped)
370
0
{
371
0
    int    ret = 0;
372
0
    word32 i = 0,
373
0
           j = 0,
374
0
           n = 0;   /* new line counter */
375
376
0
    int    getSzOnly = (out == NULL);
377
378
0
    word32 outSz = (inLen + 3 - 1) / 3 * 4;
379
0
    word32 addSz = (outSz + BASE64_LINE_SZ - 1) / BASE64_LINE_SZ;  /* new lines */
380
381
0
    if (escaped == WC_ESC_NL_ENC)
382
0
        addSz *= 3;   /* instead of just \n, we're doing %0A triplet */
383
0
    else if (escaped == WC_NO_NL_ENC)
384
0
        addSz = 0;    /* encode without \n */
385
386
0
    outSz += addSz;
387
388
    /* if escaped we can't predetermine size for one pass encoding, but
389
     * make sure we have enough if no escapes are in input
390
     * Also need to ensure outLen valid before dereference */
391
0
    if (!outLen || (outSz > *outLen && !getSzOnly)) return BAD_FUNC_ARG;
392
393
0
    while (inLen > 2) {
394
0
        byte b1 = in[j++];
395
0
        byte b2 = in[j++];
396
0
        byte b3 = in[j++];
397
398
        /* encoded idx */
399
0
        byte e1 = b1 >> 2;
400
0
        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
401
0
        byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
402
0
        byte e4 = b3 & 0x3F;
403
404
        /* store */
405
0
        ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
406
0
        if (ret != 0) break;
407
0
        ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
408
0
        if (ret != 0) break;
409
0
        ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
410
0
        if (ret != 0) break;
411
0
        ret = CEscape(escaped, e4, out, &i, *outLen, 0, getSzOnly);
412
0
        if (ret != 0) break;
413
414
0
        inLen -= 3;
415
416
        /* Insert newline after BASE64_LINE_SZ, unless no \n requested */
417
0
        if (escaped != WC_NO_NL_ENC && (++n % (BASE64_LINE_SZ/4)) == 0 && inLen) {
418
0
            ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
419
0
            if (ret != 0) break;
420
0
        }
421
0
    }
422
423
    /* last integral */
424
0
    if (inLen && ret == 0) {
425
0
        int twoBytes = (inLen == 2);
426
427
0
        byte b1 = in[j++];
428
0
        byte b2 = (twoBytes) ? in[j++] : 0;
429
430
0
        byte e1 = b1 >> 2;
431
0
        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
432
0
        byte e3 = (byte)((b2 & 0xF) << 2);
433
434
0
        ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
435
0
        if (ret == 0)
436
0
            ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
437
0
        if (ret == 0) {
438
            /* third */
439
0
            if (twoBytes)
440
0
                ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
441
0
            else
442
0
                ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
443
0
        }
444
        /* fourth always pad */
445
0
        if (ret == 0)
446
0
            ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
447
0
    }
448
449
0
    if (ret == 0 && escaped != WC_NO_NL_ENC)
450
0
        ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
451
452
0
    if (i != outSz && escaped != 1 && ret == 0)
453
0
        return ASN_INPUT_E;
454
/* If the output buffer has a room for an extra byte, add a null terminator */
455
0
    if (out && *outLen > i)
456
0
        out[i]= '\0';
457
458
0
    *outLen = i;
459
460
0
    if (ret == 0)
461
0
        return getSzOnly ? WC_NO_ERR_TRACE(LENGTH_ONLY_E) : 0;
462
463
0
    return ret;
464
0
}
465
466
467
/* Base64 Encode, PEM style, with \n line endings */
468
int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
469
0
{
470
0
    return DoBase64_Encode(in, inLen, out, outLen, WC_STD_ENC);
471
0
}
472
473
474
/* Base64 Encode, with %0A escaped line endings instead of \n */
475
int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
476
0
{
477
0
    return DoBase64_Encode(in, inLen, out, outLen, WC_ESC_NL_ENC);
478
0
}
479
480
int Base64_Encode_NoNl(const byte* in, word32 inLen, byte* out, word32* outLen)
481
0
{
482
0
    return DoBase64_Encode(in, inLen, out, outLen, WC_NO_NL_ENC);
483
0
}
484
485
#endif /* WOLFSSL_BASE64_ENCODE */
486
487
488
#ifdef WOLFSSL_BASE16
489
490
static
491
const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
492
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD,
493
                           10, 11, 12, 13, 14, 15,  /* upper case A-F */
494
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
495
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
496
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
497
                           BAD, BAD,  /* G - ` */
498
                           10, 11, 12, 13, 14, 15   /* lower case a-f */
499
                         };  /* A starts at 0x41 not 0x3A */
500
501
int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
502
0
{
503
0
    word32 inIdx  = 0;
504
0
    word32 outIdx = 0;
505
506
0
    if (in == NULL || out == NULL || outLen == NULL)
507
0
        return BAD_FUNC_ARG;
508
509
0
    if (inLen == 1 && *outLen && in) {
510
0
        byte b = in[inIdx++] - BASE16_MIN;  /* 0 starts at 0x30 */
511
512
        /* sanity check */
513
0
        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
514
0
            return ASN_INPUT_E;
515
516
0
        b  = hexDecode[b];
517
518
0
        if (b == BAD)
519
0
            return ASN_INPUT_E;
520
521
0
        out[outIdx++] = b;
522
523
0
        *outLen = outIdx;
524
0
        return 0;
525
0
    }
526
527
0
    if (inLen % 2)
528
0
        return BAD_FUNC_ARG;
529
530
0
    if (*outLen < (inLen / 2))
531
0
        return BAD_FUNC_ARG;
532
533
0
    while (inLen) {
534
0
        byte b  = in[inIdx++] - BASE16_MIN;  /* 0 starts at 0x30 */
535
0
        byte b2 = in[inIdx++] - BASE16_MIN;
536
537
        /* sanity checks */
538
0
        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
539
0
            return ASN_INPUT_E;
540
0
        if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
541
0
            return ASN_INPUT_E;
542
543
0
        b  = hexDecode[b];
544
0
        b2 = hexDecode[b2];
545
546
0
        if (b == BAD || b2 == BAD)
547
0
            return ASN_INPUT_E;
548
549
0
        out[outIdx++] = (byte)((b << 4) | b2);
550
0
        inLen -= 2;
551
0
    }
552
553
0
    *outLen = outIdx;
554
0
    return 0;
555
0
}
556
557
int Base16_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
558
0
{
559
0
    word32 outIdx = 0;
560
0
    word32 i;
561
562
0
    if (in == NULL || out == NULL || outLen == NULL)
563
0
        return BAD_FUNC_ARG;
564
565
0
    if (*outLen < (2 * inLen))
566
0
        return BAD_FUNC_ARG;
567
568
0
    for (i = 0; i < inLen; i++) {
569
0
        byte hb = in[i] >> 4;
570
0
        byte lb = in[i] & 0x0f;
571
572
        /* ASCII value */
573
0
        hb += '0';
574
0
        if (hb > '9')
575
0
            hb += 7;
576
577
        /* ASCII value */
578
0
        lb += '0';
579
0
        if (lb>'9')
580
0
            lb += 7;
581
582
0
        out[outIdx++] = hb;
583
0
        out[outIdx++] = lb;
584
0
    }
585
586
    /* If the output buffer has a room for an extra byte, add a null terminator */
587
0
    if (*outLen > outIdx)
588
0
        out[outIdx++]= '\0';
589
590
0
    *outLen = outIdx;
591
0
    return 0;
592
0
}
593
594
#endif /* WOLFSSL_BASE16 */
595
596
#endif /* !NO_CODING */