Changeset 771 in openpam


Ignore:
Timestamp:
Mar 6, 2014, 5:54:58 PM (7 years ago)
Author:
Dag-Erling Smørgrav
Message:

Replace base{32,64}_decode() with table-driven implementations. The new
code is less strict about padding, thus ensuring compatibility with
implementations which do not understand padding, such as MIME::Base32.

Location:
trunk/lib/liboath
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/liboath/oath_base32.c

    r770 r771  
    3838#include <errno.h>
    3939#include <stdint.h>
     40#include <stdio.h>
    4041
    4142#include <security/oath.h>
    4243
    43 static const char b32[] =
     44static const char b32enc[] =
    4445    "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    4546
     47static const uint8_t b32dec[256] = {
     48        ['A'] =  0, ['B'] =  1, ['C'] =  2, ['D'] =  3,
     49        ['E'] =  4, ['F'] =  5, ['G'] =  6, ['H'] =  7,
     50        ['I'] =  8, ['J'] =  9, ['K'] = 10, ['L'] = 11,
     51        ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
     52        ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
     53        ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
     54        ['Y'] = 24, ['Z'] = 25,
     55
     56        ['a'] =  0, ['b'] =  1, ['c'] =  2, ['d'] =  3,
     57        ['e'] =  4, ['f'] =  5, ['g'] =  6, ['h'] =  7,
     58        ['i'] =  8, ['j'] =  9, ['k'] = 10, ['l'] = 11,
     59        ['m'] = 12, ['n'] = 13, ['o'] = 14, ['p'] = 15,
     60        ['q'] = 16, ['r'] = 17, ['s'] = 18, ['t'] = 19,
     61        ['u'] = 20, ['v'] = 21, ['w'] = 22, ['x'] = 23,
     62        ['y'] = 24, ['z'] = 25,
     63
     64        ['2'] = 26, ['3'] = 27, ['4'] = 28, ['5'] = 29,
     65        ['6'] = 30, ['7'] = 31,
     66};
     67
    4668/*
    47  * Encode data in RFC 3548 base 32 representation.  The target buffer must
     69 * Encode data in RFC 4648 base 32 representation.  The target buffer must
    4870 * have room for base32_enclen(len) characters and a terminating NUL.
    4971 */
     
    5375        uint64_t bits;
    5476
    55         if (*olen <= base32_enclen(ilen))
     77        if (*olen <= base32_enclen(ilen)) {
     78                errno = ENOSPC;
    5679                return (-1);
     80        }
    5781        *olen = 0;
    5882        while (ilen >= 5) {
     
    6589                ilen -= 5;
    6690                in += 5;
    67                 out[0] = b32[bits >> 35 & 0x1f];
    68                 out[1] = b32[bits >> 30 & 0x1f];
    69                 out[2] = b32[bits >> 25 & 0x1f];
    70                 out[3] = b32[bits >> 20 & 0x1f];
    71                 out[4] = b32[bits >> 15 & 0x1f];
    72                 out[5] = b32[bits >> 10 & 0x1f];
    73                 out[6] = b32[bits >> 5 & 0x1f];
    74                 out[7] = b32[bits & 0x1f];
     91                out[0] = b32enc[bits >> 35 & 0x1f];
     92                out[1] = b32enc[bits >> 30 & 0x1f];
     93                out[2] = b32enc[bits >> 25 & 0x1f];
     94                out[3] = b32enc[bits >> 20 & 0x1f];
     95                out[4] = b32enc[bits >> 15 & 0x1f];
     96                out[5] = b32enc[bits >> 10 & 0x1f];
     97                out[6] = b32enc[bits >> 5 & 0x1f];
     98                out[7] = b32enc[bits & 0x1f];
    7599                *olen += 8;
    76100                out += 8;
     
    88112                        bits |= (uint64_t)in[0] << 32;
    89113                }
    90                 out[0] = b32[bits >> 35 & 0x1f];
    91                 out[1] = b32[bits >> 30 & 0x1f];
    92                 out[2] = ilen > 1 ? b32[bits >> 25 & 0x1f] : '=';
    93                 out[3] = ilen > 1 ? b32[bits >> 20 & 0x1f] : '=';
    94                 out[4] = ilen > 2 ? b32[bits >> 15 & 0x1f] : '=';
    95                 out[5] = ilen > 3 ? b32[bits >> 10 & 0x1f] : '=';
    96                 out[6] = ilen > 3 ? b32[bits >> 5 & 0x1f] : '=';
     114                out[0] = b32enc[bits >> 35 & 0x1f];
     115                out[1] = b32enc[bits >> 30 & 0x1f];
     116                out[2] = ilen > 1 ? b32enc[bits >> 25 & 0x1f] : '=';
     117                out[3] = ilen > 1 ? b32enc[bits >> 20 & 0x1f] : '=';
     118                out[4] = ilen > 2 ? b32enc[bits >> 15 & 0x1f] : '=';
     119                out[5] = ilen > 3 ? b32enc[bits >> 10 & 0x1f] : '=';
     120                out[6] = ilen > 3 ? b32enc[bits >> 5 & 0x1f] : '=';
    97121                out[7] = '=';
    98122                *olen += 8;
     
    105129
    106130/*
    107  * Decode data in RFC 2548 base 32 representation, stopping at the
     131 * Decode data in RFC 4648 base 32 representation, stopping at the
    108132 * terminating NUL, the first invalid (non-base32, non-whitespace)
    109133 * character or after len characters, whichever comes first.
     134 *
     135 * Padding is handled sloppily: any padding character following the data
     136 * is silently consumed.  This not only simplifies the code but ensures
     137 * compatibility with implementations which do not emit or understand
     138 * padding.
    110139 *
    111140 * The olen argument is used by the caller to pass the size of the buffer
     
    118147{
    119148        size_t len;
    120         uint64_t bits;
    121         int shift;
     149        int bits, shift, padding;
    122150
    123         for (len = 0, bits = 0, shift = 40; ilen && *in && *in != '='; --ilen, ++in) {
    124                 if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
     151        for (bits = shift = padding = len = 0; ilen && *in; --ilen, ++in) {
     152                if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n' ||
     153                    (padding && *in == '=')) {
     154                        /* consume */
    125155                        continue;
    126                 } else if (*in >= 'A' && *in <= 'Z') {
    127                         shift -= 5;
    128                         bits |= (uint64_t)(*in - 'A') << shift;
    129                 } else if (*in >= 'a' && *in <= 'z') {
    130                         shift -= 5;
    131                         bits |= (uint64_t)(*in - 'a') << shift;
    132                 } else if (*in >= '2' && *in <= '7') { 
    133                         shift -= 5;
    134                         bits |= (uint64_t)(*in - '2' + 26) << shift;
    135                 } else if (*in == '=') {
    136                         /* handled below */
    137                         break;
     156                } else if (!padding && b32dec[(int)*in]) {
     157                        /* shift into accumulator */
     158                        shift += 5;
     159                        bits = bits << 5 | b32dec[(int)*in];
     160                } else if (!padding && shift && *in == '=') {
     161                        /* final byte */
     162                        shift = 0;
     163                        padding = 1;
    138164                } else {
    139                         goto bad;
     165                        /* error */
     166                        *olen = 0;
     167                        errno = EINVAL;
     168                        return (-1);
    140169                }
    141                 if (shift == 0) {
    142                         if ((len += 5) <= *olen) {
    143                                 *out++ = (bits >> 32) & 0xff;
    144                                 *out++ = (bits >> 24) & 0xff;
    145                                 *out++ = (bits >> 16) & 0xff;
    146                                 *out++ = (bits >> 8) & 0xff;
    147                                 *out++ = bits & 0xff;
    148                         }
    149                         bits = 0;
    150                         shift = 40;
     170                if (shift >= 8) {
     171                        /* output accumulated byte */
     172                        shift -= 8;
     173                        if (len++ < *olen)
     174                                *out++ = (bits >> shift) & 0xff;
    151175                }
    152176        }
    153         if (ilen && *in == '=' &&
    154             (shift == 30 || shift == 20 || shift == 15 || shift == 5)) {
    155                 /*
    156                  * Padding:
    157                  *
    158                  * 00            8 AA====== 30
    159                  * 00 00        16 AAAA==== 20
    160                  * 00 00 00     24 AAAAA=== 15
    161                  * 00 00 00 00  32 AAAAAAA= 5
    162                  *
    163                  * XXX We should check that the last few bits before the
    164                  * padding starts are zero.
    165                  */
    166                 switch (shift) {
    167                 case 5:
    168                         if (++len <= *olen)
    169                                 *out++ = (bits >> 32) & 0xff;
    170                         bits <<= 8;
    171                 case 15:
    172                         if (++len <= *olen)
    173                                 *out++ = (bits >> 32) & 0xff;
    174                         bits <<= 8;
    175                 case 20:
    176                         if (++len <= *olen)
    177                                 *out++ = (bits >> 32) & 0xff;
    178                         bits <<= 8;
    179                 case 30:
    180                         if (++len <= *olen)
    181                                 *out++ = (bits >> 32) & 0xff;
    182                         bits <<= 8;
    183                         break;
    184                 default:
    185                         goto bad;
    186                 }
    187                 /* consume remaining padding and whitespace */
    188                 for (; ilen && *in; --ilen, ++in) {
    189                         if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n')
    190                                 continue;
    191                         else if (*in == '=' && shift)
    192                                 shift -= 5;
    193                         else
    194                                 goto bad;
    195                 }
     177        /* report decoded length */
     178        *olen = len;
     179        if (len > *olen) {
     180                /* overflow */
     181                errno = ENOSPC;
     182                return (-1);
    196183        }
    197         if (ilen)
    198                 goto bad;
    199         *olen = len;
    200         if (len > *olen)
    201                 return (-1);
    202184        return (0);
    203 bad:
    204         *olen = 0;
    205         return (-1);
    206185}
  • trunk/lib/liboath/oath_base64.c

    r770 r771  
    4141#include <security/oath.h>
    4242
    43 static const char b64[] =
     43static const char b64enc[] =
    4444    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    4545    "abcdefghijklmnopqrstuvwxyz"
    4646    "0123456789+/";
    4747
     48static const uint8_t b64dec[256] = {
     49        ['A'] =  0, ['B'] =  1, ['C'] =  2, ['D'] =  3,
     50        ['E'] =  4, ['F'] =  5, ['G'] =  6, ['H'] =  7,
     51        ['I'] =  8, ['J'] =  9, ['K'] = 10, ['L'] = 11,
     52        ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
     53        ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
     54        ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
     55        ['Y'] = 24, ['Z'] = 25, ['a'] = 26, ['b'] = 27,
     56        ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31,
     57        ['g'] = 32, ['h'] = 33, ['i'] = 34, ['j'] = 35,
     58        ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
     59        ['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43,
     60        ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47,
     61        ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
     62        ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55,
     63        ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
     64        ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63,
     65};
     66
    4867/*
    49  * Encode data in RFC 3548 base 64 representation.  The target buffer must
     68 * Encode data in RFC 4648 base 64 representation.  The target buffer must
    5069 * have room for base64_enclen(len) characters and a terminating NUL.
    5170 */
     
    6584                ilen -= 3;
    6685                in += 3;
    67                 out[0] = b64[bits >> 18 & 0x3f];
    68                 out[1] = b64[bits >> 12 & 0x3f];
    69                 out[2] = b64[bits >> 6 & 0x3f];
    70                 out[3] = b64[bits & 0x3f];
     86                out[0] = b64enc[bits >> 18 & 0x3f];
     87                out[1] = b64enc[bits >> 12 & 0x3f];
     88                out[2] = b64enc[bits >> 6 & 0x3f];
     89                out[3] = b64enc[bits & 0x3f];
    7190                *olen += 4;
    7291                out += 4;
     
    8099                        bits |= (uint32_t)in[0] << 16;
    81100                }
    82                 out[0] = b64[bits >> 18 & 0x3f];
    83                 out[1] = b64[bits >> 12 & 0x3f];
    84                 out[2] = ilen > 1 ? b64[bits >> 6 & 0x3f] : '=';
     101                out[0] = b64enc[bits >> 18 & 0x3f];
     102                out[1] = b64enc[bits >> 12 & 0x3f];
     103                out[2] = ilen > 1 ? b64enc[bits >> 6 & 0x3f] : '=';
    85104                out[3] = '=';
    86105                *olen += 4;
     
    93112
    94113/*
    95  * Decode data in RFC 2548 base 64 representation, stopping at the
     114 * Decode data in RFC 4648 base 64 representation, stopping at the
    96115 * terminating NUL, the first invalid (non-base64, non-whitespace)
    97116 * character or after len characters, whichever comes first.
     117 *
     118 * Padding is handled sloppily: any padding character following the data
     119 * is silently consumed.  This not only simplifies the code but ensures
     120 * compatibility with implementations which do not emit or understand
     121 * padding.
    98122 *
    99123 * The olen argument is used by the caller to pass the size of the buffer
     
    106130{
    107131        size_t len;
    108         uint32_t bits;
    109         int shift;
     132        int bits, shift, padding;
    110133
    111         for (len = 0, bits = 0, shift = 24; ilen && *in; --ilen, ++in) {
    112                 if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
     134        for (bits = shift = padding = len = 0; ilen && *in; --ilen, ++in) {
     135                if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n' ||
     136                    (padding && *in == '=')) {
     137                        /* consume */
    113138                        continue;
    114                 } else if (*in >= 'A' && *in <= 'Z') {
    115                         shift -= 6;
    116                         bits |= (uint32_t)(*in - 'A') << shift;
    117                 } else if (*in >= 'a' && *in <= 'z') {
    118                         shift -= 6;
    119                         bits |= (uint32_t)(*in - 'a' + 26) << shift;
    120                 } else if (*in >= '0' && *in <= '9') {
    121                         shift -= 6;
    122                         bits |= (uint32_t)(*in - '0' + 52) << shift;
    123                 } else if (*in == '+') {
    124                         shift -= 6;
    125                         bits |= (uint32_t)62 << shift;
    126                 } else if (*in == '/') {
    127                         shift -= 6;
    128                         bits |= (uint32_t)63 << shift;
    129                 } else if (*in == '=') {
    130                         /* handled below */
    131                         break;
     139                } else if (!padding && b64dec[(int)*in]) {
     140                        /* shift into accumulator */
     141                        shift += 6;
     142                        bits = bits << 6 | b64dec[(int)*in];
     143                } else if (!padding && shift && *in == '=') {
     144                        /* final byte */
     145                        shift = 0;
     146                        padding = 1;
    132147                } else {
    133                         goto bad;
     148                        /* error */
     149                        *olen = 0;
     150                        errno = EINVAL;
     151                        return (-1);
    134152                }
    135                 if (shift == 0) {
    136                         if ((len += 3) <= *olen) {
    137                                 *out++ = (bits >> 16) & 0xff;
    138                                 *out++ = (bits >> 8) & 0xff;
    139                                 *out++ = bits & 0xff;
    140                         }
    141                         bits = 0;
    142                         shift = 24;
     153                if (shift >= 8) {
     154                        /* output accumulated byte */
     155                        shift -= 8;
     156                        if (len++ < *olen)
     157                                *out++ = (bits >> shift) & 0xff;
    143158                }
    144159        }
    145         if (ilen && *in == '=' && (shift == 12 || shift == 6)) {
    146                 /*
    147                  * Padding:
    148                  *
    149                  * 00            8 AA== 12
    150                  * 00 00        16 AAA=  6
    151                  *
    152                  * XXX We should check that the last few bits before the
    153                  * padding starts are zero.
    154                  */
    155                 switch (shift) {
    156                 case 6:
    157                         if (++len <= *olen)
    158                                 *out++ = (bits >> 16) & 0xff;
    159                         bits <<= 8;
    160                 case 12:
    161                         if (++len <= *olen)
    162                                 *out++ = (bits >> 16) & 0xff;
    163                         bits <<= 8;
    164                         break;
    165                 default:
    166                         goto bad;
    167                 }
    168                 /* consume remaining padding and whitespace */
    169                 for (; ilen && *in; --ilen, ++in) {
    170                         if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n')
    171                                 continue;
    172                         else if (*in == '=' && shift)
    173                                 shift -= 6;
    174                         else
    175                                 goto bad;
    176                 }
     160        /* report decoded length */
     161        *olen = len;
     162        if (len > *olen) {
     163                /* overflow */
     164                errno = ENOSPC;
     165                return (-1);
    177166        }
    178         if (ilen)
    179                 goto bad;
    180         *olen = len;
    181         if (len > *olen)
    182                 return (-1);
    183167        return (0);
    184 bad:
    185         *olen = 0;
    186         return (-1);
    187168}
Note: See TracChangeset for help on using the changeset viewer.