wolf SSL / CyaSSL

Dependents:   HTTPClient-SSL HTTPClient HTTPClient-SSL http_access ... more

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-2014 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL 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  * CyaSSL 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-1301, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 #include <cyassl/ctaocrypt/settings.h>
00027 
00028 #ifndef NO_CODING
00029 
00030 #include <cyassl/ctaocrypt/coding.h>
00031 #include <cyassl/ctaocrypt/error-crypt.h>
00032 #include <cyassl/ctaocrypt/logging.h>
00033 
00034 
00035 enum {
00036     BAD         = 0xFF,  /* invalid encoding */
00037     PAD         = '=',
00038     PEM_LINE_SZ = 64
00039 };
00040 
00041 
00042 static
00043 const byte base64Decode[] = { 62, BAD, BAD, BAD, 63,   /* + starts at 0x2B */
00044                               52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
00045                               BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00046                               0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
00047                               10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
00048                               20, 21, 22, 23, 24, 25,
00049                               BAD, BAD, BAD, BAD, BAD, BAD,
00050                               26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
00051                               36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
00052                               46, 47, 48, 49, 50, 51
00053                             };
00054 
00055 
00056 int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
00057 {
00058     word32 i = 0;
00059     word32 j = 0;
00060     word32 plainSz = inLen - ((inLen + (PEM_LINE_SZ - 1)) / PEM_LINE_SZ );
00061     const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1;
00062 
00063     plainSz = (plainSz * 3 + 3) / 4;
00064     if (plainSz > *outLen) return BAD_FUNC_ARG;
00065 
00066     while (inLen > 3) {
00067         byte b1, b2, b3;
00068         byte e1 = in[j++];
00069         byte e2 = in[j++];
00070         byte e3 = in[j++];
00071         byte e4 = in[j++];
00072 
00073         int pad3 = 0;
00074         int pad4 = 0;
00075 
00076         if (e1 == 0)            /* end file 0's */
00077             break;
00078         if (e3 == PAD)
00079             pad3 = 1;
00080         if (e4 == PAD)
00081             pad4 = 1;
00082 
00083         if (e1 < 0x2B || e2 < 0x2B || e3 < 0x2B || e4 < 0x2B) {
00084             CYASSL_MSG("Bad Base64 Decode data, too small");
00085             return ASN_INPUT_E;
00086         }
00087 
00088         if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
00089             CYASSL_MSG("Bad Base64 Decode data, too big");
00090             return ASN_INPUT_E;
00091         }
00092 
00093         e1 = base64Decode[e1 - 0x2B];
00094         e2 = base64Decode[e2 - 0x2B];
00095         e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B];
00096         e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B];
00097 
00098         b1 = (byte)((e1 << 2) | (e2 >> 4));
00099         b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
00100         b3 = (byte)(((e3 & 0x3) << 6) | e4);
00101 
00102         out[i++] = b1;
00103         if (!pad3)
00104             out[i++] = b2;
00105         if (!pad4)
00106             out[i++] = b3;
00107         else
00108             break;
00109         
00110         inLen -= 4;
00111         if (inLen && (in[j] == ' ' || in[j] == '\r' || in[j] == '\n')) {
00112             byte endLine = in[j++];
00113             inLen--;
00114             while (inLen && endLine == ' ') {   /* allow trailing whitespace */
00115                 endLine = in[j++];
00116                 inLen--;
00117             }
00118             if (endLine == '\r') {
00119                 if (inLen) {
00120                     endLine = in[j++];
00121                     inLen--;
00122                 }
00123             }
00124             if (endLine != '\n') {
00125                 CYASSL_MSG("Bad end of line in Base64 Decode");
00126                 return ASN_INPUT_E;
00127             }
00128         }
00129     }
00130     *outLen = i;
00131 
00132     return 0;
00133 }
00134 
00135 
00136 #if defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER)
00137 
00138 static
00139 const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
00140                               'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
00141                               'U', 'V', 'W', 'X', 'Y', 'Z',
00142                               'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
00143                               'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
00144                               'u', 'v', 'w', 'x', 'y', 'z',
00145                               '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
00146                               '+', '/'
00147                             };
00148 
00149 
00150 /* make sure *i (idx) won't exceed max, store and possibly escape to out,
00151  * raw means use e w/o decode,  0 on success */
00152 static int CEscape(int escaped, byte e, byte* out, word32* i, word32 max,
00153                   int raw)
00154 {
00155     int    doEscape = 0;
00156     word32 needed = 1;
00157     word32 idx = *i;
00158 
00159     byte basic;
00160     byte plus    = 0;
00161     byte equals  = 0;
00162     byte newline = 0;
00163 
00164     if (raw)
00165         basic = e;
00166     else
00167         basic = base64Encode[e];
00168 
00169     /* check whether to escape */
00170     if (escaped) {
00171         switch ((char)basic) {
00172             case '+' :
00173                 plus     = 1;
00174                 doEscape = 1;
00175                 needed  += 2;
00176                 break;
00177             case '=' :
00178                 equals   = 1;
00179                 doEscape = 1;
00180                 needed  += 2;
00181                 break;
00182             case '\n' :
00183                 newline  = 1;
00184                 doEscape = 1;
00185                 needed  += 2;
00186                 break;
00187             default:
00188                 /* do nothing */
00189                 break;
00190         }
00191     }
00192 
00193     /* check size */
00194     if ( (idx+needed) > max) {
00195         CYASSL_MSG("Escape buffer max too small");
00196         return BUFFER_E;
00197     }
00198 
00199     /* store it */
00200     if (doEscape == 0) {
00201         out[idx++] = basic;
00202     }
00203     else {
00204         out[idx++] = '%';  /* start escape */
00205 
00206         if (plus) {
00207             out[idx++] = '2';
00208             out[idx++] = 'B';
00209         }
00210         else if (equals) {
00211             out[idx++] = '3';
00212             out[idx++] = 'D';
00213         }
00214         else if (newline) {
00215             out[idx++] = '0';
00216             out[idx++] = 'A';
00217         }
00218 
00219     }
00220     *i = idx;
00221 
00222     return 0;
00223 }
00224 
00225 
00226 /* internal worker, handles both escaped and normal line endings */
00227 static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
00228                            word32* outLen, int escaped)
00229 {
00230     int    ret = 0;
00231     word32 i = 0,
00232            j = 0,
00233            n = 0;   /* new line counter */
00234 
00235     word32 outSz = (inLen + 3 - 1) / 3 * 4;
00236     word32 addSz = (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ;  /* new lines */
00237 
00238     if (escaped)
00239         addSz *= 3;   /* instead of just \n, we're doing %0A triplet */
00240 
00241     outSz += addSz;
00242 
00243     /* if escaped we can't predetermine size for one pass encoding, but
00244      * make sure we have enough if no escapes are in input */
00245     if (outSz > *outLen) return BAD_FUNC_ARG;
00246     
00247     while (inLen > 2) {
00248         byte b1 = in[j++];
00249         byte b2 = in[j++];
00250         byte b3 = in[j++];
00251 
00252         /* encoded idx */
00253         byte e1 = b1 >> 2;
00254         byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
00255         byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
00256         byte e4 = b3 & 0x3F;
00257 
00258         /* store */
00259         ret = CEscape(escaped, e1, out, &i, *outLen, 0);
00260         if (ret != 0) break;
00261         ret = CEscape(escaped, e2, out, &i, *outLen, 0);
00262         if (ret != 0) break;
00263         ret = CEscape(escaped, e3, out, &i, *outLen, 0);
00264         if (ret != 0) break;
00265         ret = CEscape(escaped, e4, out, &i, *outLen, 0);
00266         if (ret != 0) break;
00267 
00268         inLen -= 3;
00269 
00270         if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen) {
00271             ret = CEscape(escaped, '\n', out, &i, *outLen, 1);
00272             if (ret != 0) break;
00273         }
00274     }
00275 
00276     /* last integral */
00277     if (inLen && ret == 0) {
00278         int twoBytes = (inLen == 2);
00279 
00280         byte b1 = in[j++];
00281         byte b2 = (twoBytes) ? in[j++] : 0;
00282 
00283         byte e1 = b1 >> 2;
00284         byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
00285         byte e3 = (byte)((b2 & 0xF) << 2);
00286 
00287         ret = CEscape(escaped, e1, out, &i, *outLen, 0);
00288         if (ret == 0) 
00289             ret = CEscape(escaped, e2, out, &i, *outLen, 0);
00290         if (ret == 0) {
00291             /* third */
00292             if (twoBytes)
00293                 ret = CEscape(escaped, e3, out, &i, *outLen, 0);
00294             else 
00295                 ret = CEscape(escaped, '=', out, &i, *outLen, 1);
00296         }
00297         /* fourth always pad */
00298         if (ret == 0)
00299             ret = CEscape(escaped, '=', out, &i, *outLen, 1);
00300     } 
00301 
00302     if (ret == 0) 
00303         ret = CEscape(escaped, '\n', out, &i, *outLen, 1);
00304 
00305     if (i != outSz && escaped == 0 && ret == 0)
00306         return ASN_INPUT_E; 
00307 
00308     *outLen = i;
00309     return ret; 
00310 }
00311 
00312 
00313 /* Base64 Encode, PEM style, with \n line endings */
00314 int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
00315 {
00316     return DoBase64_Encode(in, inLen, out, outLen, 0);
00317 }
00318 
00319 
00320 /* Base64 Encode, with %0A esacped line endings instead of \n */
00321 int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
00322 {
00323     return DoBase64_Encode(in, inLen, out, outLen, 1);
00324 }
00325 
00326 
00327 #endif  /* defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) || defined(HAVE_WEBSERVER) */
00328 
00329 
00330 #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_FIPS)
00331 
00332 static
00333 const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
00334                            BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00335                            10, 11, 12, 13, 14, 15,  /* upper case A-F */
00336                            BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00337                            BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00338                            BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
00339                            BAD, BAD,  /* G - ` */
00340                            10, 11, 12, 13, 14, 15   /* lower case a-f */
00341                          };  /* A starts at 0x41 not 0x3A */
00342 
00343 int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
00344 {
00345     word32 inIdx  = 0;
00346     word32 outIdx = 0;
00347 
00348     if (inLen == 1 && *outLen && in) {
00349         byte b = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
00350 
00351         /* sanity check */
00352         if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
00353             return ASN_INPUT_E;
00354 
00355         b  = hexDecode[b];
00356 
00357         if (b == BAD)
00358             return ASN_INPUT_E;
00359         
00360         out[outIdx++] = b;
00361 
00362         *outLen = outIdx;
00363         return 0;
00364     }
00365 
00366     if (inLen % 2)
00367         return BAD_FUNC_ARG;
00368 
00369     if (*outLen < (inLen / 2))
00370         return BAD_FUNC_ARG;
00371 
00372     while (inLen) {
00373         byte b  = in[inIdx++] - 0x30;  /* 0 starts at 0x30 */
00374         byte b2 = in[inIdx++] - 0x30;
00375 
00376         /* sanity checks */
00377         if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
00378             return ASN_INPUT_E;
00379         if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
00380             return ASN_INPUT_E;
00381 
00382         b  = hexDecode[b];
00383         b2 = hexDecode[b2];
00384 
00385         if (b == BAD || b2 == BAD)
00386             return ASN_INPUT_E;
00387         
00388         out[outIdx++] = (byte)((b << 4) | b2);
00389         inLen -= 2;
00390     }
00391 
00392     *outLen = outIdx;
00393     return 0;
00394 }
00395 
00396 
00397 #endif /* (OPENSSL_EXTRA) || (HAVE_WEBSERVER) || (HAVE_FIPS) */
00398 
00399 #endif /* NO_CODING */
00400