source: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/wolfcrypt/src/coding.c@ 464

Last change on this file since 464 was 464, checked in by coas-nagasima, 3 years ago

WolfSSLとAzure IoT SDKを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 15.8 KB
Line 
1/* coding.c
2 *
3 * Copyright (C) 2006-2020 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
44enum {
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 #define BASE64_LINE_SZ PEM_LINE_SZ
57 #endif
58#endif
59
60#ifdef WOLFSSL_BASE64_DECODE
61
62#ifdef BASE64_NO_TABLE
63static 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
77static
78ALIGN64 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#define BASE64DECODE_SZ (byte)(sizeof(base64Decode))
92
93static WC_INLINE byte Base64_Char2Val(byte c)
94{
95#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 byte v;
100 byte mask;
101
102 c -= BASE64_MIN;
103 mask = (((byte)(0x3f - c)) >> 7) - 1;
104 /* Load a value from the first cache line and use when mask set. */
105 v = base64Decode[ c & 0x3f ] & mask ;
106 /* Load a value from the second cache line and use when mask not set. */
107 v |= base64Decode[(c & 0x0f) | 0x40] & (~mask);
108
109 return v;
110#else
111 return base64Decode[c - BASE64_MIN];
112#endif
113}
114#endif
115
116static WC_INLINE int Base64_SkipNewline(const byte* in, word32 *inLen, word32 *outJ)
117{
118 word32 len = *inLen;
119 word32 j = *outJ;
120 if (len && (in[j] == ' ' || in[j] == '\r' || in[j] == '\n')) {
121 byte endLine = in[j++];
122 len--;
123 while (len && endLine == ' ') { /* allow trailing whitespace */
124 endLine = in[j++];
125 len--;
126 }
127 if (endLine == '\r') {
128 if (len) {
129 endLine = in[j++];
130 len--;
131 }
132 }
133 if (endLine != '\n') {
134 WOLFSSL_MSG("Bad end of line in Base64 Decode");
135 return ASN_INPUT_E;
136 }
137 }
138 if (!len) {
139 return BUFFER_E;
140 }
141 *inLen = len;
142 *outJ = j;
143 return 0;
144}
145
146int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
147{
148 word32 i = 0;
149 word32 j = 0;
150 word32 plainSz = inLen - ((inLen + (BASE64_LINE_SZ - 1)) / BASE64_LINE_SZ );
151 int ret;
152#ifndef BASE64_NO_TABLE
153 const byte maxIdx = BASE64DECODE_SZ + BASE64_MIN - 1;
154#endif
155
156 plainSz = (plainSz * 3 + 3) / 4;
157 if (plainSz > *outLen) return BAD_FUNC_ARG;
158
159 while (inLen > 3) {
160 int pad3 = 0;
161 int pad4 = 0;
162 byte b1, b2, b3;
163 byte e1, e2, e3, e4;
164
165 if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
166 if (ret == BUFFER_E) {
167 /* Running out of buffer here is not an error */
168 break;
169 }
170 return ret;
171 }
172 e1 = in[j++];
173 if (e1 == '\0') {
174 break;
175 }
176 inLen--;
177 if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
178 return ret;
179 }
180 e2 = in[j++];
181 inLen--;
182 if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
183 return ret;
184 }
185 e3 = in[j++];
186 inLen--;
187 if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
188 return ret;
189 }
190 e4 = in[j++];
191 inLen--;
192
193 if (e3 == PAD)
194 pad3 = 1;
195 if (e4 == PAD)
196 pad4 = 1;
197
198 if (pad3 && !pad4)
199 return ASN_INPUT_E;
200
201#ifndef BASE64_NO_TABLE
202 if (e1 < BASE64_MIN || e2 < BASE64_MIN || e3 < BASE64_MIN ||
203 e4 < BASE64_MIN) {
204 WOLFSSL_MSG("Bad Base64 Decode data, too small");
205 return ASN_INPUT_E;
206 }
207
208 if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
209 WOLFSSL_MSG("Bad Base64 Decode data, too big");
210 return ASN_INPUT_E;
211 }
212#endif
213
214 if (i + 1 + !pad3 + !pad4 > *outLen) {
215 WOLFSSL_MSG("Bad Base64 Decode out buffer, too small");
216 return BAD_FUNC_ARG;
217 }
218
219 e1 = Base64_Char2Val(e1);
220 e2 = Base64_Char2Val(e2);
221 e3 = (e3 == PAD) ? 0 : Base64_Char2Val(e3);
222 e4 = (e4 == PAD) ? 0 : Base64_Char2Val(e4);
223
224 if (e1 == BAD || e2 == BAD || e3 == BAD || e4 == BAD) {
225 WOLFSSL_MSG("Bad Base64 Decode bad character");
226 return ASN_INPUT_E;
227 }
228
229 b1 = (byte)((e1 << 2) | (e2 >> 4));
230 b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
231 b3 = (byte)(((e3 & 0x3) << 6) | e4);
232
233 out[i++] = b1;
234 if (!pad3)
235 out[i++] = b2;
236 if (!pad4)
237 out[i++] = b3;
238 else
239 break;
240 }
241/* If the output buffer has a room for an extra byte, add a null terminator */
242 if (out && *outLen > i)
243 out[i]= '\0';
244
245 *outLen = i;
246
247 return 0;
248}
249
250#endif /* WOLFSSL_BASE64_DECODE */
251
252#if defined(WOLFSSL_BASE64_ENCODE)
253
254static
255const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
256 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
257 'U', 'V', 'W', 'X', 'Y', 'Z',
258 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
259 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
260 'u', 'v', 'w', 'x', 'y', 'z',
261 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
262 '+', '/'
263 };
264
265
266/* make sure *i (idx) won't exceed max, store and possibly escape to out,
267 * raw means use e w/o decode, 0 on success */
268static int CEscape(int escaped, byte e, byte* out, word32* i, word32 maxSz,
269 int raw, int getSzOnly)
270{
271 int doEscape = 0;
272 word32 needed = 1;
273 word32 idx = *i;
274
275 byte basic;
276 byte plus = 0;
277 byte equals = 0;
278 byte newline = 0;
279
280 if (raw)
281 basic = e;
282 else
283 basic = base64Encode[e];
284
285 /* check whether to escape. Only escape for EncodeEsc */
286 if (escaped == WC_ESC_NL_ENC) {
287 switch ((char)basic) {
288 case '+' :
289 plus = 1;
290 doEscape = 1;
291 needed += 2;
292 break;
293 case '=' :
294 equals = 1;
295 doEscape = 1;
296 needed += 2;
297 break;
298 case '\n' :
299 newline = 1;
300 doEscape = 1;
301 needed += 2;
302 break;
303 default:
304 /* do nothing */
305 break;
306 }
307 }
308
309 /* check size */
310 if ( (idx+needed) > maxSz && !getSzOnly) {
311 WOLFSSL_MSG("Escape buffer max too small");
312 return BUFFER_E;
313 }
314
315 /* store it */
316 if (doEscape == 0) {
317 if(getSzOnly)
318 idx++;
319 else
320 out[idx++] = basic;
321 }
322 else {
323 if(getSzOnly)
324 idx+=3;
325 else {
326 out[idx++] = '%'; /* start escape */
327
328 if (plus) {
329 out[idx++] = '2';
330 out[idx++] = 'B';
331 }
332 else if (equals) {
333 out[idx++] = '3';
334 out[idx++] = 'D';
335 }
336 else if (newline) {
337 out[idx++] = '0';
338 out[idx++] = 'A';
339 }
340 }
341 }
342 *i = idx;
343
344 return 0;
345}
346
347
348/* internal worker, handles both escaped and normal line endings.
349 If out buffer is NULL, will return sz needed in outLen */
350static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
351 word32* outLen, int escaped)
352{
353 int ret = 0;
354 word32 i = 0,
355 j = 0,
356 n = 0; /* new line counter */
357
358 int getSzOnly = (out == NULL);
359
360 word32 outSz = (inLen + 3 - 1) / 3 * 4;
361 word32 addSz = (outSz + BASE64_LINE_SZ - 1) / BASE64_LINE_SZ; /* new lines */
362
363 if (escaped == WC_ESC_NL_ENC)
364 addSz *= 3; /* instead of just \n, we're doing %0A triplet */
365 else if (escaped == WC_NO_NL_ENC)
366 addSz = 0; /* encode without \n */
367
368 outSz += addSz;
369
370 /* if escaped we can't predetermine size for one pass encoding, but
371 * make sure we have enough if no escapes are in input
372 * Also need to ensure outLen valid before dereference */
373 if (!outLen || (outSz > *outLen && !getSzOnly)) return BAD_FUNC_ARG;
374
375 while (inLen > 2) {
376 byte b1 = in[j++];
377 byte b2 = in[j++];
378 byte b3 = in[j++];
379
380 /* encoded idx */
381 byte e1 = b1 >> 2;
382 byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
383 byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
384 byte e4 = b3 & 0x3F;
385
386 /* store */
387 ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
388 if (ret != 0) break;
389 ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
390 if (ret != 0) break;
391 ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
392 if (ret != 0) break;
393 ret = CEscape(escaped, e4, out, &i, *outLen, 0, getSzOnly);
394 if (ret != 0) break;
395
396 inLen -= 3;
397
398 /* Insert newline after BASE64_LINE_SZ, unless no \n requested */
399 if (escaped != WC_NO_NL_ENC && (++n % (BASE64_LINE_SZ/4)) == 0 && inLen) {
400 ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
401 if (ret != 0) break;
402 }
403 }
404
405 /* last integral */
406 if (inLen && ret == 0) {
407 int twoBytes = (inLen == 2);
408
409 byte b1 = in[j++];
410 byte b2 = (twoBytes) ? in[j++] : 0;
411
412 byte e1 = b1 >> 2;
413 byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
414 byte e3 = (byte)((b2 & 0xF) << 2);
415
416 ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
417 if (ret == 0)
418 ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
419 if (ret == 0) {
420 /* third */
421 if (twoBytes)
422 ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
423 else
424 ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
425 }
426 /* fourth always pad */
427 if (ret == 0)
428 ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
429 }
430
431 if (ret == 0 && escaped != WC_NO_NL_ENC)
432 ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
433
434 if (i != outSz && escaped != 1 && ret == 0)
435 return ASN_INPUT_E;
436/* If the output buffer has a room for an extra byte, add a null terminator */
437 if (out && *outLen > i)
438 out[i]= '\0';
439
440 *outLen = i;
441
442 if (ret == 0)
443 return getSzOnly ? LENGTH_ONLY_E : 0;
444
445 return ret;
446}
447
448
449/* Base64 Encode, PEM style, with \n line endings */
450int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
451{
452 return DoBase64_Encode(in, inLen, out, outLen, WC_STD_ENC);
453}
454
455
456/* Base64 Encode, with %0A escaped line endings instead of \n */
457int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
458{
459 return DoBase64_Encode(in, inLen, out, outLen, WC_ESC_NL_ENC);
460}
461
462int Base64_Encode_NoNl(const byte* in, word32 inLen, byte* out, word32* outLen)
463{
464 return DoBase64_Encode(in, inLen, out, outLen, WC_NO_NL_ENC);
465}
466
467#endif /* WOLFSSL_BASE64_ENCODE */
468
469
470#ifdef WOLFSSL_BASE16
471
472static
473const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
474 BAD, BAD, BAD, BAD, BAD, BAD, BAD,
475 10, 11, 12, 13, 14, 15, /* upper case A-F */
476 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
477 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
478 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
479 BAD, BAD, /* G - ` */
480 10, 11, 12, 13, 14, 15 /* lower case a-f */
481 }; /* A starts at 0x41 not 0x3A */
482
483int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
484{
485 word32 inIdx = 0;
486 word32 outIdx = 0;
487
488 if (in == NULL || out == NULL || outLen == NULL)
489 return BAD_FUNC_ARG;
490
491 if (inLen == 1 && *outLen && in) {
492 byte b = in[inIdx++] - BASE16_MIN; /* 0 starts at 0x30 */
493
494 /* sanity check */
495 if (b >= sizeof(hexDecode)/sizeof(hexDecode[0]))
496 return ASN_INPUT_E;
497
498 b = hexDecode[b];
499
500 if (b == BAD)
501 return ASN_INPUT_E;
502
503 out[outIdx++] = b;
504
505 *outLen = outIdx;
506 return 0;
507 }
508
509 if (inLen % 2)
510 return BAD_FUNC_ARG;
511
512 if (*outLen < (inLen / 2))
513 return BAD_FUNC_ARG;
514
515 while (inLen) {
516 byte b = in[inIdx++] - BASE16_MIN; /* 0 starts at 0x30 */
517 byte b2 = in[inIdx++] - BASE16_MIN;
518
519 /* sanity checks */
520 if (b >= sizeof(hexDecode)/sizeof(hexDecode[0]))
521 return ASN_INPUT_E;
522 if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
523 return ASN_INPUT_E;
524
525 b = hexDecode[b];
526 b2 = hexDecode[b2];
527
528 if (b == BAD || b2 == BAD)
529 return ASN_INPUT_E;
530
531 out[outIdx++] = (byte)((b << 4) | b2);
532 inLen -= 2;
533 }
534
535 *outLen = outIdx;
536 return 0;
537}
538
539int Base16_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
540{
541 word32 outIdx = 0;
542 word32 i;
543 byte hb, lb;
544
545 if (in == NULL || out == NULL || outLen == NULL)
546 return BAD_FUNC_ARG;
547
548 if (*outLen < (2 * inLen + 1))
549 return BAD_FUNC_ARG;
550
551 for (i = 0; i < inLen; i++) {
552 hb = in[i] >> 4;
553 lb = in[i] & 0x0f;
554
555 /* ASCII value */
556 hb += '0';
557 if (hb > '9')
558 hb += 7;
559
560 /* ASCII value */
561 lb += '0';
562 if (lb>'9')
563 lb += 7;
564
565 out[outIdx++] = hb;
566 out[outIdx++] = lb;
567 }
568
569 /* force 0 at this end */
570 out[outIdx++] = 0;
571
572 *outLen = outIdx;
573 return 0;
574}
575
576#endif /* WOLFSSL_BASE16 */
577
578#endif /* !NO_CODING */
Note: See TracBrowser for help on using the repository browser.