Renesas / SecureDweet
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coding.c Source File

coding.c

00001 /* coding.c
00002  *
00003  * Copyright (C) 2006-2016 wolfSSL Inc.
00004  *
00005  * This file is part of wolfSSL.
00006  *
00007  * wolfSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * wolfSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
00020  */
00021 
00022 
00023 #ifdef HAVE_CONFIG_H
00024     #include <config.h>
00025 #endif
00026 
00027 #include <wolfssl/wolfcrypt/settings.h>
00028 
00029 #ifndef NO_CODING
00030 
00031 #include <wolfssl/wolfcrypt/coding.h>
00032 #include <wolfssl/wolfcrypt/error-crypt.h>
00033 #include <wolfssl/wolfcrypt/logging.h>
00034 
00035 
00036 enum {
00037     BAD         = 0xFF,  /* invalid encoding */
00038     PAD         = '=',
00039     PEM_LINE_SZ = 64
00040 };
00041 
00042 
00043 static
00044 const byte base64Decode[] = { 62, BAD, BAD, BAD, 63,   /* + starts at 0x2B */
00045                               52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
00046                               BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00047                               0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
00048                               10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
00049                               20, 21, 22, 23, 24, 25,
00050                               BAD, BAD, BAD, BAD, BAD, BAD,
00051                               26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
00052                               36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
00053                               46, 47, 48, 49, 50, 51
00054                             };
00055 
00056 
00057 int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
00058 {
00059     word32 i = 0;
00060     word32 j = 0;
00061     word32 plainSz = inLen - ((inLen + (PEM_LINE_SZ - 1)) / PEM_LINE_SZ );
00062     const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1;
00063 
00064     plainSz = (plainSz * 3 + 3) / 4;
00065     if (plainSz > *outLen) return BAD_FUNC_ARG;
00066 
00067     while (inLen > 3) {
00068         byte b1, b2, b3;
00069         byte e1 = in[j++];
00070         byte e2 = in[j++];
00071         byte e3 = in[j++];
00072         byte e4 = in[j++];
00073 
00074         int pad3 = 0;
00075         int pad4 = 0;
00076 
00077         if (e1 == 0)            /* end file 0's */
00078             break;
00079         if (e3 == PAD)
00080             pad3 = 1;
00081         if (e4 == PAD)
00082             pad4 = 1;
00083 
00084         if (e1 < 0x2B || e2 < 0x2B || e3 < 0x2B || e4 < 0x2B) {
00085             WOLFSSL_MSG("Bad Base64 Decode data, too small");
00086             return ASN_INPUT_E;
00087         }
00088 
00089         if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
00090             WOLFSSL_MSG("Bad Base64 Decode data, too big");
00091             return ASN_INPUT_E;
00092         }
00093 
00094         e1 = base64Decode[e1 - 0x2B];
00095         e2 = base64Decode[e2 - 0x2B];
00096         e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B];
00097         e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B];
00098 
00099         b1 = (byte)((e1 << 2) | (e2 >> 4));
00100         b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
00101         b3 = (byte)(((e3 & 0x3) << 6) | e4);
00102 
00103         out[i++] = b1;
00104         if (!pad3)
00105             out[i++] = b2;
00106         if (!pad4)
00107             out[i++] = b3;
00108         else
00109             break;
00110 
00111         inLen -= 4;
00112         if (inLen && (in[j] == ' ' || in[j] == '\r' || in[j] == '\n')) {
00113             byte endLine = in[j++];
00114             inLen--;
00115             while (inLen && endLine == ' ') {   /* allow trailing whitespace */
00116                 endLine = in[j++];
00117                 inLen--;
00118             }
00119             if (endLine == '\r') {
00120                 if (inLen) {
00121                     endLine = in[j++];
00122                     inLen--;
00123                 }
00124             }
00125             if (endLine != '\n') {
00126                 WOLFSSL_MSG("Bad end of line in Base64 Decode");
00127                 return ASN_INPUT_E;
00128             }
00129         }
00130     }
00131     *outLen = i;
00132 
00133     return 0;
00134 }
00135 
00136 
00137 #if defined(WOLFSSL_BASE64_ENCODE)
00138 
00139 static
00140 const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
00141                               'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
00142                               'U', 'V', 'W', 'X', 'Y', 'Z',
00143                               'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
00144                               'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
00145                               'u', 'v', 'w', 'x', 'y', 'z',
00146                               '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00147                               '+', '/'
00148                             };
00149 
00150 
00151 /* make sure *i (idx) won't exceed max, store and possibly escape to out,
00152  * raw means use e w/o decode,  0 on success */
00153 static int CEscape(int escaped, byte e, byte* out, word32* i, word32 max,
00154                   int raw, int getSzOnly)
00155 {
00156     int    doEscape = 0;
00157     word32 needed = 1;
00158     word32 idx = *i;
00159 
00160     byte basic;
00161     byte plus    = 0;
00162     byte equals  = 0;
00163     byte newline = 0;
00164 
00165     if (raw)
00166         basic = e;
00167     else
00168         basic = base64Encode[e];
00169 
00170     /* check whether to escape. Only escape for EncodeEsc */
00171     if (escaped == WC_ESC_NL_ENC) {
00172         switch ((char)basic) {
00173             case '+' :
00174                 plus     = 1;
00175                 doEscape = 1;
00176                 needed  += 2;
00177                 break;
00178             case '=' :
00179                 equals   = 1;
00180                 doEscape = 1;
00181                 needed  += 2;
00182                 break;
00183             case '\n' :
00184                 newline  = 1;
00185                 doEscape = 1;
00186                 needed  += 2;
00187                 break;
00188             default:
00189                 /* do nothing */
00190                 break;
00191         }
00192     }
00193 
00194     /* check size */
00195     if ( (idx+needed) > max && !getSzOnly) {
00196         WOLFSSL_MSG("Escape buffer max too small");
00197         return BUFFER_E;
00198     }
00199 
00200     /* store it */
00201     if (doEscape == 0) {
00202         if(getSzOnly)
00203             idx++;
00204         else
00205             out[idx++] = basic;
00206     }
00207     else {
00208         if(getSzOnly)
00209             idx+=3;
00210         else {
00211             out[idx++] = '%';  /* start escape */
00212 
00213             if (plus) {
00214                 out[idx++] = '2';
00215                 out[idx++] = 'B';
00216             }
00217             else if (equals) {
00218                 out[idx++] = '3';
00219                 out[idx++] = 'D';
00220             }
00221             else if (newline) {
00222                 out[idx++] = '0';
00223                 out[idx++] = 'A';
00224             }
00225         }
00226     }
00227     *i = idx;
00228 
00229     return 0;
00230 }
00231 
00232 
00233 /* internal worker, handles both escaped and normal line endings.
00234    If out buffer is NULL, will return sz needed in outLen */
00235 static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
00236                            word32* outLen, int escaped)
00237 {
00238     int    ret = 0;
00239     word32 i = 0,
00240            j = 0,
00241            n = 0;   /* new line counter */
00242 
00243     int    getSzOnly = (out == NULL);
00244 
00245     word32 outSz = (inLen + 3 - 1) / 3 * 4;
00246     word32 addSz = (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ;  /* new lines */
00247 
00248     if (escaped == WC_ESC_NL_ENC)
00249         addSz *= 3;   /* instead of just \n, we're doing %0A triplet */
00250     else if (escaped == WC_NO_NL_ENC)
00251         addSz = 0;    /* encode without \n */
00252 
00253     outSz += addSz;
00254 
00255     /* if escaped we can't predetermine size for one pass encoding, but
00256      * make sure we have enough if no escapes are in input
00257      * Also need to ensure outLen valid before dereference */
00258     if (!outLen || (outSz > *outLen && !getSzOnly)) return BAD_FUNC_ARG;
00259 
00260     while (inLen > 2) {
00261         byte b1 = in[j++];
00262         byte b2 = in[j++];
00263         byte b3 = in[j++];
00264 
00265         /* encoded idx */
00266         byte e1 = b1 >> 2;
00267         byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
00268         byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
00269         byte e4 = b3 & 0x3F;
00270 
00271         /* store */
00272         ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
00273         if (ret != 0) break;
00274         ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
00275         if (ret != 0) break;
00276         ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
00277         if (ret != 0) break;
00278         ret = CEscape(escaped, e4, out, &i, *outLen, 0, getSzOnly);
00279         if (ret != 0) break;
00280 
00281         inLen -= 3;
00282 
00283         /* Insert newline after PEM_LINE_SZ, unless no \n requested */
00284         if (escaped != WC_NO_NL_ENC && (++n % (PEM_LINE_SZ/4)) == 0 && inLen){
00285             ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
00286             if (ret != 0) break;
00287         }
00288     }
00289 
00290     /* last integral */
00291     if (inLen && ret == 0) {
00292         int twoBytes = (inLen == 2);
00293 
00294         byte b1 = in[j++];
00295         byte b2 = (twoBytes) ? in[j++] : 0;
00296 
00297         byte e1 = b1 >> 2;
00298         byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
00299         byte e3 = (byte)((b2 & 0xF) << 2);
00300 
00301         ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
00302         if (ret == 0)
00303             ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
00304         if (ret == 0) {
00305             /* third */
00306             if (twoBytes)
00307                 ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
00308             else
00309                 ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
00310         }
00311         /* fourth always pad */
00312         if (ret == 0)
00313             ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
00314     }
00315 
00316     if (ret == 0 && escaped != WC_NO_NL_ENC)
00317         ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
00318 
00319     if (i != outSz && escaped != 1 && ret == 0)
00320         return ASN_INPUT_E;
00321 
00322     *outLen = i;
00323     if(ret == 0)
00324         return getSzOnly ? LENGTH_ONLY_E : 0;
00325     return ret;
00326 }
00327 
00328 
00329 /* Base64 Encode, PEM style, with \n line endings */
00330 int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
00331 {
00332     return DoBase64_Encode(in, inLen, out, outLen, WC_STD_ENC);
00333 }
00334 
00335 
00336 /* Base64 Encode, with %0A escaped line endings instead of \n */
00337 int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
00338 {
00339     return DoBase64_Encode(in, inLen, out, outLen, WC_ESC_NL_ENC);
00340 }
00341 
00342 int Base64_Encode_NoNl(const byte* in, word32 inLen, byte* out, word32* outLen)
00343 {
00344     return DoBase64_Encode(in, inLen, out, outLen, WC_NO_NL_ENC);
00345 }
00346 
00347 #endif  /* defined(WOLFSSL_BASE64_ENCODE) */
00348 
00349 
00350 #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS)
00351 
00352 static
00353 const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
00354                            BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00355                            10, 11, 12, 13, 14, 15,  /* upper case A-F */
00356                            BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00357                            BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00358                            BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00359                            BAD, BAD,  /* G - ` */
00360                            10, 11, 12, 13, 14, 15   /* lower case a-f */
00361                          };  /* A starts at 0x41 not 0x3A */
00362 
00363 int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
00364 {
00365     word32 inIdx  = 0;
00366     word32 outIdx = 0;
00367 
00368     if (inLen == 1 && *outLen && in) {
00369         byte b = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
00370 
00371         /* sanity check */
00372         if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
00373             return ASN_INPUT_E;
00374 
00375         b  = hexDecode[b];
00376 
00377         if (b == BAD)
00378             return ASN_INPUT_E;
00379         
00380         out[outIdx++] = b;
00381 
00382         *outLen = outIdx;
00383         return 0;
00384     }
00385 
00386     if (inLen % 2)
00387         return BAD_FUNC_ARG;
00388 
00389     if (*outLen < (inLen / 2))
00390         return BAD_FUNC_ARG;
00391 
00392     while (inLen) {
00393         byte b  = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
00394         byte b2 = in[inIdx++] - 0x30;
00395 
00396         /* sanity checks */
00397         if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
00398             return ASN_INPUT_E;
00399         if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
00400             return ASN_INPUT_E;
00401 
00402         b  = hexDecode[b];
00403         b2 = hexDecode[b2];
00404 
00405         if (b == BAD || b2 == BAD)
00406             return ASN_INPUT_E;
00407         
00408         out[outIdx++] = (byte)((b << 4) | b2);
00409         inLen -= 2;
00410     }
00411 
00412     *outLen = outIdx;
00413     return 0;
00414 }
00415 
00416 int Base16_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
00417 {
00418     word32 outIdx = 0;
00419     word32 i;
00420     byte   hb, lb;
00421 
00422     if (*outLen < (2 * inLen + 1))
00423         return BAD_FUNC_ARG;
00424 
00425     for (i = 0; i < inLen; i++) {
00426         hb = in[i] >> 4;
00427         lb = in[i] & 0x0f;
00428 
00429         /* ASCII value */
00430         hb += '0';
00431         if (hb > '9')
00432             hb += 7;
00433 
00434         /* ASCII value */
00435         lb += '0';
00436         if (lb>'9')
00437             lb += 7;
00438 
00439         out[outIdx++] = hb;
00440         out[outIdx++] = lb;
00441     }
00442 
00443     /* force 0 at this end */
00444     out[outIdx++] = 0;
00445 
00446     *outLen = outIdx;
00447     return 0;
00448 }
00449 
00450 #endif /* (OPENSSL_EXTRA) || (HAVE_WEBSERVER) || (HAVE_FIPS) */
00451 
00452 #endif /* NO_CODING */
00453