Home | History | Annotate | Download | only in asn1
      1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      2  * All rights reserved.
      3  *
      4  * This package is an SSL implementation written
      5  * by Eric Young (eay (at) cryptsoft.com).
      6  * The implementation was written so as to conform with Netscapes SSL.
      7  *
      8  * This library is free for commercial and non-commercial use as long as
      9  * the following conditions are aheared to.  The following conditions
     10  * apply to all code found in this distribution, be it the RC4, RSA,
     11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     12  * included with this distribution is covered by the same copyright terms
     13  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     14  *
     15  * Copyright remains Eric Young's, and as such any Copyright notices in
     16  * the code are not to be removed.
     17  * If this package is used in a product, Eric Young should be given attribution
     18  * as the author of the parts of the library used.
     19  * This can be in the form of a textual message at program startup or
     20  * in documentation (online or textual) provided with the package.
     21  *
     22  * Redistribution and use in source and binary forms, with or without
     23  * modification, are permitted provided that the following conditions
     24  * are met:
     25  * 1. Redistributions of source code must retain the copyright
     26  *    notice, this list of conditions and the following disclaimer.
     27  * 2. Redistributions in binary form must reproduce the above copyright
     28  *    notice, this list of conditions and the following disclaimer in the
     29  *    documentation and/or other materials provided with the distribution.
     30  * 3. All advertising materials mentioning features or use of this software
     31  *    must display the following acknowledgement:
     32  *    "This product includes cryptographic software written by
     33  *     Eric Young (eay (at) cryptsoft.com)"
     34  *    The word 'cryptographic' can be left out if the rouines from the library
     35  *    being used are not cryptographic related :-).
     36  * 4. If you include any Windows specific code (or a derivative thereof) from
     37  *    the apps directory (application code) you must include an acknowledgement:
     38  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     39  *
     40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     50  * SUCH DAMAGE.
     51  *
     52  * The licence and distribution terms for any publically available version or
     53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     54  * copied and put under another distribution licence
     55  * [including the GNU Public Licence.] */
     56 
     57 #include <openssl/asn1.h>
     58 
     59 #include <openssl/err.h>
     60 #include <openssl/mem.h>
     61 
     62 #include "asn1_locl.h"
     63 
     64 /* UTF8 utilities */
     65 
     66 /*
     67  * This parses a UTF8 string one character at a time. It is passed a pointer
     68  * to the string and the length of the string. It sets 'value' to the value
     69  * of the current character. It returns the number of characters read or a
     70  * negative error code: -1 = string too short -2 = illegal character -3 =
     71  * subsequent characters not of the form 10xxxxxx -4 = character encoded
     72  * incorrectly (not minimal length).
     73  */
     74 
     75 int UTF8_getc(const unsigned char *str, int len, uint32_t *val)
     76 {
     77     const unsigned char *p;
     78     uint32_t value;
     79     int ret;
     80     if (len <= 0)
     81         return 0;
     82     p = str;
     83 
     84     /* Check syntax and work out the encoded value (if correct) */
     85     if ((*p & 0x80) == 0) {
     86         value = *p++ & 0x7f;
     87         ret = 1;
     88     } else if ((*p & 0xe0) == 0xc0) {
     89         if (len < 2)
     90             return -1;
     91         if ((p[1] & 0xc0) != 0x80)
     92             return -3;
     93         value = (*p++ & 0x1f) << 6;
     94         value |= *p++ & 0x3f;
     95         if (value < 0x80)
     96             return -4;
     97         ret = 2;
     98     } else if ((*p & 0xf0) == 0xe0) {
     99         if (len < 3)
    100             return -1;
    101         if (((p[1] & 0xc0) != 0x80)
    102             || ((p[2] & 0xc0) != 0x80))
    103             return -3;
    104         value = (*p++ & 0xf) << 12;
    105         value |= (*p++ & 0x3f) << 6;
    106         value |= *p++ & 0x3f;
    107         if (value < 0x800)
    108             return -4;
    109         ret = 3;
    110     } else if ((*p & 0xf8) == 0xf0) {
    111         if (len < 4)
    112             return -1;
    113         if (((p[1] & 0xc0) != 0x80)
    114             || ((p[2] & 0xc0) != 0x80)
    115             || ((p[3] & 0xc0) != 0x80))
    116             return -3;
    117         value = ((uint32_t)(*p++ & 0x7)) << 18;
    118         value |= (*p++ & 0x3f) << 12;
    119         value |= (*p++ & 0x3f) << 6;
    120         value |= *p++ & 0x3f;
    121         if (value < 0x10000)
    122             return -4;
    123         ret = 4;
    124     } else if ((*p & 0xfc) == 0xf8) {
    125         if (len < 5)
    126             return -1;
    127         if (((p[1] & 0xc0) != 0x80)
    128             || ((p[2] & 0xc0) != 0x80)
    129             || ((p[3] & 0xc0) != 0x80)
    130             || ((p[4] & 0xc0) != 0x80))
    131             return -3;
    132         value = ((uint32_t)(*p++ & 0x3)) << 24;
    133         value |= ((uint32_t)(*p++ & 0x3f)) << 18;
    134         value |= ((uint32_t)(*p++ & 0x3f)) << 12;
    135         value |= (*p++ & 0x3f) << 6;
    136         value |= *p++ & 0x3f;
    137         if (value < 0x200000)
    138             return -4;
    139         ret = 5;
    140     } else if ((*p & 0xfe) == 0xfc) {
    141         if (len < 6)
    142             return -1;
    143         if (((p[1] & 0xc0) != 0x80)
    144             || ((p[2] & 0xc0) != 0x80)
    145             || ((p[3] & 0xc0) != 0x80)
    146             || ((p[4] & 0xc0) != 0x80)
    147             || ((p[5] & 0xc0) != 0x80))
    148             return -3;
    149         value = ((uint32_t)(*p++ & 0x1)) << 30;
    150         value |= ((uint32_t)(*p++ & 0x3f)) << 24;
    151         value |= ((uint32_t)(*p++ & 0x3f)) << 18;
    152         value |= ((uint32_t)(*p++ & 0x3f)) << 12;
    153         value |= (*p++ & 0x3f) << 6;
    154         value |= *p++ & 0x3f;
    155         if (value < 0x4000000)
    156             return -4;
    157         ret = 6;
    158     } else
    159         return -2;
    160     *val = value;
    161     return ret;
    162 }
    163 
    164 /*
    165  * This takes a character 'value' and writes the UTF8 encoded value in 'str'
    166  * where 'str' is a buffer containing 'len' characters. Returns the number of
    167  * characters written or -1 if 'len' is too small. 'str' can be set to NULL
    168  * in which case it just returns the number of characters. It will need at
    169  * most 6 characters.
    170  */
    171 
    172 int UTF8_putc(unsigned char *str, int len, uint32_t value)
    173 {
    174     if (!str)
    175         len = 6;                /* Maximum we will need */
    176     else if (len <= 0)
    177         return -1;
    178     if (value < 0x80) {
    179         if (str)
    180             *str = (unsigned char)value;
    181         return 1;
    182     }
    183     if (value < 0x800) {
    184         if (len < 2)
    185             return -1;
    186         if (str) {
    187             *str++ = (unsigned char)(((value >> 6) & 0x1f) | 0xc0);
    188             *str = (unsigned char)((value & 0x3f) | 0x80);
    189         }
    190         return 2;
    191     }
    192     if (value < 0x10000) {
    193         if (len < 3)
    194             return -1;
    195         if (str) {
    196             *str++ = (unsigned char)(((value >> 12) & 0xf) | 0xe0);
    197             *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
    198             *str = (unsigned char)((value & 0x3f) | 0x80);
    199         }
    200         return 3;
    201     }
    202     if (value < 0x200000) {
    203         if (len < 4)
    204             return -1;
    205         if (str) {
    206             *str++ = (unsigned char)(((value >> 18) & 0x7) | 0xf0);
    207             *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
    208             *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
    209             *str = (unsigned char)((value & 0x3f) | 0x80);
    210         }
    211         return 4;
    212     }
    213     if (value < 0x4000000) {
    214         if (len < 5)
    215             return -1;
    216         if (str) {
    217             *str++ = (unsigned char)(((value >> 24) & 0x3) | 0xf8);
    218             *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
    219             *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
    220             *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
    221             *str = (unsigned char)((value & 0x3f) | 0x80);
    222         }
    223         return 5;
    224     }
    225     if (len < 6)
    226         return -1;
    227     if (str) {
    228         *str++ = (unsigned char)(((value >> 30) & 0x1) | 0xfc);
    229         *str++ = (unsigned char)(((value >> 24) & 0x3f) | 0x80);
    230         *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
    231         *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
    232         *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
    233         *str = (unsigned char)((value & 0x3f) | 0x80);
    234     }
    235     return 6;
    236 }
    237