source: azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/wolfcrypt/src/coding.c@ 457

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

ファイルを追加

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