Home | History | Annotate | Download | only in x509
      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/x509.h>
     58 
     59 #include <string.h>
     60 
     61 #include <openssl/asn1.h>
     62 #include <openssl/mem.h>
     63 #include <openssl/obj.h>
     64 
     65 #include "charmap.h"
     66 
     67 /*
     68  * ASN1_STRING_print_ex() and X509_NAME_print_ex(). Enhanced string and name
     69  * printing routines handling multibyte characters, RFC2253 and a host of
     70  * other options.
     71  */
     72 
     73 #define CHARTYPE_BS_ESC         (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
     74 
     75 #define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \
     76                   ASN1_STRFLGS_ESC_QUOTE | \
     77                   ASN1_STRFLGS_ESC_CTRL | \
     78                   ASN1_STRFLGS_ESC_MSB)
     79 
     80 static int send_bio_chars(void *arg, const void *buf, int len)
     81 {
     82     if (!arg)
     83         return 1;
     84     if (BIO_write(arg, buf, len) != len)
     85         return 0;
     86     return 1;
     87 }
     88 
     89 static int send_fp_chars(void *arg, const void *buf, int len)
     90 {
     91     if (!arg)
     92         return 1;
     93     if (fwrite(buf, 1, len, arg) != (unsigned int)len)
     94         return 0;
     95     return 1;
     96 }
     97 
     98 typedef int char_io (void *arg, const void *buf, int len);
     99 
    100 /*
    101  * This function handles display of strings, one character at a time. It is
    102  * passed an unsigned long for each character because it could come from 2 or
    103  * even 4 byte forms.
    104  */
    105 
    106 #define HEX_SIZE(type) (sizeof(type)*2)
    107 
    108 static int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes,
    109                        char_io *io_ch, void *arg)
    110 {
    111     unsigned char chflgs, chtmp;
    112     char tmphex[HEX_SIZE(long) + 3];
    113 
    114     if (c > 0xffffffffL)
    115         return -1;
    116     if (c > 0xffff) {
    117         BIO_snprintf(tmphex, sizeof tmphex, "\\W%08lX", c);
    118         if (!io_ch(arg, tmphex, 10))
    119             return -1;
    120         return 10;
    121     }
    122     if (c > 0xff) {
    123         BIO_snprintf(tmphex, sizeof tmphex, "\\U%04lX", c);
    124         if (!io_ch(arg, tmphex, 6))
    125             return -1;
    126         return 6;
    127     }
    128     chtmp = (unsigned char)c;
    129     if (chtmp > 0x7f)
    130         chflgs = flags & ASN1_STRFLGS_ESC_MSB;
    131     else
    132         chflgs = char_type[chtmp] & flags;
    133     if (chflgs & CHARTYPE_BS_ESC) {
    134         /* If we don't escape with quotes, signal we need quotes */
    135         if (chflgs & ASN1_STRFLGS_ESC_QUOTE) {
    136             if (do_quotes)
    137                 *do_quotes = 1;
    138             if (!io_ch(arg, &chtmp, 1))
    139                 return -1;
    140             return 1;
    141         }
    142         if (!io_ch(arg, "\\", 1))
    143             return -1;
    144         if (!io_ch(arg, &chtmp, 1))
    145             return -1;
    146         return 2;
    147     }
    148     if (chflgs & (ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB)) {
    149         BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
    150         if (!io_ch(arg, tmphex, 3))
    151             return -1;
    152         return 3;
    153     }
    154     /*
    155      * If we get this far and do any escaping at all must escape the escape
    156      * character itself: backslash.
    157      */
    158     if (chtmp == '\\' && flags & ESC_FLAGS) {
    159         if (!io_ch(arg, "\\\\", 2))
    160             return -1;
    161         return 2;
    162     }
    163     if (!io_ch(arg, &chtmp, 1))
    164         return -1;
    165     return 1;
    166 }
    167 
    168 #define BUF_TYPE_WIDTH_MASK     0x7
    169 #define BUF_TYPE_CONVUTF8       0x8
    170 
    171 /*
    172  * This function sends each character in a buffer to do_esc_char(). It
    173  * interprets the content formats and converts to or from UTF8 as
    174  * appropriate.
    175  */
    176 
    177 static int do_buf(unsigned char *buf, int buflen,
    178                   int type, unsigned char flags, char *quotes, char_io *io_ch,
    179                   void *arg)
    180 {
    181     int i, outlen, len;
    182     unsigned char orflags, *p, *q;
    183     unsigned long c;
    184     p = buf;
    185     q = buf + buflen;
    186     outlen = 0;
    187     while (p != q) {
    188         if (p == buf && flags & ASN1_STRFLGS_ESC_2253)
    189             orflags = CHARTYPE_FIRST_ESC_2253;
    190         else
    191             orflags = 0;
    192         switch (type & BUF_TYPE_WIDTH_MASK) {
    193         case 4:
    194             c = ((unsigned long)*p++) << 24;
    195             c |= ((unsigned long)*p++) << 16;
    196             c |= ((unsigned long)*p++) << 8;
    197             c |= *p++;
    198             break;
    199 
    200         case 2:
    201             c = ((unsigned long)*p++) << 8;
    202             c |= *p++;
    203             break;
    204 
    205         case 1:
    206             c = *p++;
    207             break;
    208 
    209         case 0:
    210             i = UTF8_getc(p, buflen, &c);
    211             if (i < 0)
    212                 return -1;      /* Invalid UTF8String */
    213             p += i;
    214             break;
    215         default:
    216             return -1;          /* invalid width */
    217         }
    218         if (p == q && flags & ASN1_STRFLGS_ESC_2253)
    219             orflags = CHARTYPE_LAST_ESC_2253;
    220         if (type & BUF_TYPE_CONVUTF8) {
    221             unsigned char utfbuf[6];
    222             int utflen;
    223             utflen = UTF8_putc(utfbuf, sizeof utfbuf, c);
    224             for (i = 0; i < utflen; i++) {
    225                 /*
    226                  * We don't need to worry about setting orflags correctly
    227                  * because if utflen==1 its value will be correct anyway
    228                  * otherwise each character will be > 0x7f and so the
    229                  * character will never be escaped on first and last.
    230                  */
    231                 len =
    232                     do_esc_char(utfbuf[i], (unsigned char)(flags | orflags),
    233                                 quotes, io_ch, arg);
    234                 if (len < 0)
    235                     return -1;
    236                 outlen += len;
    237             }
    238         } else {
    239             len =
    240                 do_esc_char(c, (unsigned char)(flags | orflags), quotes,
    241                             io_ch, arg);
    242             if (len < 0)
    243                 return -1;
    244             outlen += len;
    245         }
    246     }
    247     return outlen;
    248 }
    249 
    250 /* This function hex dumps a buffer of characters */
    251 
    252 static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
    253                        int buflen)
    254 {
    255     static const char hexdig[] = "0123456789ABCDEF";
    256     unsigned char *p, *q;
    257     char hextmp[2];
    258     if (arg) {
    259         p = buf;
    260         q = buf + buflen;
    261         while (p != q) {
    262             hextmp[0] = hexdig[*p >> 4];
    263             hextmp[1] = hexdig[*p & 0xf];
    264             if (!io_ch(arg, hextmp, 2))
    265                 return -1;
    266             p++;
    267         }
    268     }
    269     return buflen << 1;
    270 }
    271 
    272 /*
    273  * "dump" a string. This is done when the type is unknown, or the flags
    274  * request it. We can either dump the content octets or the entire DER
    275  * encoding. This uses the RFC2253 #01234 format.
    276  */
    277 
    278 static int do_dump(unsigned long lflags, char_io *io_ch, void *arg,
    279                    ASN1_STRING *str)
    280 {
    281     /*
    282      * Placing the ASN1_STRING in a temp ASN1_TYPE allows the DER encoding to
    283      * readily obtained
    284      */
    285     ASN1_TYPE t;
    286     unsigned char *der_buf, *p;
    287     int outlen, der_len;
    288 
    289     if (!io_ch(arg, "#", 1))
    290         return -1;
    291     /* If we don't dump DER encoding just dump content octets */
    292     if (!(lflags & ASN1_STRFLGS_DUMP_DER)) {
    293         outlen = do_hex_dump(io_ch, arg, str->data, str->length);
    294         if (outlen < 0)
    295             return -1;
    296         return outlen + 1;
    297     }
    298     t.type = str->type;
    299     t.value.ptr = (char *)str;
    300     der_len = i2d_ASN1_TYPE(&t, NULL);
    301     der_buf = OPENSSL_malloc(der_len);
    302     if (!der_buf)
    303         return -1;
    304     p = der_buf;
    305     i2d_ASN1_TYPE(&t, &p);
    306     outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
    307     OPENSSL_free(der_buf);
    308     if (outlen < 0)
    309         return -1;
    310     return outlen + 1;
    311 }
    312 
    313 /*
    314  * Lookup table to convert tags to character widths, 0 = UTF8 encoded, -1 is
    315  * used for non string types otherwise it is the number of bytes per
    316  * character
    317  */
    318 
    319 static const signed char tag2nbyte[] = {
    320     -1, -1, -1, -1, -1,         /* 0-4 */
    321     -1, -1, -1, -1, -1,         /* 5-9 */
    322     -1, -1, 0, -1,              /* 10-13 */
    323     -1, -1, -1, -1,             /* 15-17 */
    324     1, 1, 1,                    /* 18-20 */
    325     -1, 1, 1, 1,                /* 21-24 */
    326     -1, 1, -1,                  /* 25-27 */
    327     4, -1, 2                    /* 28-30 */
    328 };
    329 
    330 /*
    331  * This is the main function, print out an ASN1_STRING taking note of various
    332  * escape and display options. Returns number of characters written or -1 if
    333  * an error occurred.
    334  */
    335 
    336 static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
    337                        ASN1_STRING *str)
    338 {
    339     int outlen, len;
    340     int type;
    341     char quotes;
    342     unsigned char flags;
    343     quotes = 0;
    344     /* Keep a copy of escape flags */
    345     flags = (unsigned char)(lflags & ESC_FLAGS);
    346 
    347     type = str->type;
    348 
    349     outlen = 0;
    350 
    351     if (lflags & ASN1_STRFLGS_SHOW_TYPE) {
    352         const char *tagname;
    353         tagname = ASN1_tag2str(type);
    354         outlen += strlen(tagname);
    355         if (!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1))
    356             return -1;
    357         outlen++;
    358     }
    359 
    360     /* Decide what to do with type, either dump content or display it */
    361 
    362     /* Dump everything */
    363     if (lflags & ASN1_STRFLGS_DUMP_ALL)
    364         type = -1;
    365     /* Ignore the string type */
    366     else if (lflags & ASN1_STRFLGS_IGNORE_TYPE)
    367         type = 1;
    368     else {
    369         /* Else determine width based on type */
    370         if ((type > 0) && (type < 31))
    371             type = tag2nbyte[type];
    372         else
    373             type = -1;
    374         if ((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN))
    375             type = 1;
    376     }
    377 
    378     if (type == -1) {
    379         len = do_dump(lflags, io_ch, arg, str);
    380         if (len < 0)
    381             return -1;
    382         outlen += len;
    383         return outlen;
    384     }
    385 
    386     if (lflags & ASN1_STRFLGS_UTF8_CONVERT) {
    387         /*
    388          * Note: if string is UTF8 and we want to convert to UTF8 then we
    389          * just interpret it as 1 byte per character to avoid converting
    390          * twice.
    391          */
    392         if (!type)
    393             type = 1;
    394         else
    395             type |= BUF_TYPE_CONVUTF8;
    396     }
    397 
    398     len = do_buf(str->data, str->length, type, flags, &quotes, io_ch, NULL);
    399     if (len < 0)
    400         return -1;
    401     outlen += len;
    402     if (quotes)
    403         outlen += 2;
    404     if (!arg)
    405         return outlen;
    406     if (quotes && !io_ch(arg, "\"", 1))
    407         return -1;
    408     if (do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
    409         return -1;
    410     if (quotes && !io_ch(arg, "\"", 1))
    411         return -1;
    412     return outlen;
    413 }
    414 
    415 /* Used for line indenting: print 'indent' spaces */
    416 
    417 static int do_indent(char_io *io_ch, void *arg, int indent)
    418 {
    419     int i;
    420     for (i = 0; i < indent; i++)
    421         if (!io_ch(arg, " ", 1))
    422             return 0;
    423     return 1;
    424 }
    425 
    426 #define FN_WIDTH_LN     25
    427 #define FN_WIDTH_SN     10
    428 
    429 static int do_name_ex(char_io *io_ch, void *arg, X509_NAME *n,
    430                       int indent, unsigned long flags)
    431 {
    432     int i, prev = -1, orflags, cnt;
    433     int fn_opt, fn_nid;
    434     ASN1_OBJECT *fn;
    435     ASN1_STRING *val;
    436     X509_NAME_ENTRY *ent;
    437     char objtmp[80];
    438     const char *objbuf;
    439     int outlen, len;
    440     const char *sep_dn, *sep_mv, *sep_eq;
    441     int sep_dn_len, sep_mv_len, sep_eq_len;
    442     if (indent < 0)
    443         indent = 0;
    444     outlen = indent;
    445     if (!do_indent(io_ch, arg, indent))
    446         return -1;
    447     switch (flags & XN_FLAG_SEP_MASK) {
    448     case XN_FLAG_SEP_MULTILINE:
    449         sep_dn = "\n";
    450         sep_dn_len = 1;
    451         sep_mv = " + ";
    452         sep_mv_len = 3;
    453         break;
    454 
    455     case XN_FLAG_SEP_COMMA_PLUS:
    456         sep_dn = ",";
    457         sep_dn_len = 1;
    458         sep_mv = "+";
    459         sep_mv_len = 1;
    460         indent = 0;
    461         break;
    462 
    463     case XN_FLAG_SEP_CPLUS_SPC:
    464         sep_dn = ", ";
    465         sep_dn_len = 2;
    466         sep_mv = " + ";
    467         sep_mv_len = 3;
    468         indent = 0;
    469         break;
    470 
    471     case XN_FLAG_SEP_SPLUS_SPC:
    472         sep_dn = "; ";
    473         sep_dn_len = 2;
    474         sep_mv = " + ";
    475         sep_mv_len = 3;
    476         indent = 0;
    477         break;
    478 
    479     default:
    480         return -1;
    481     }
    482 
    483     if (flags & XN_FLAG_SPC_EQ) {
    484         sep_eq = " = ";
    485         sep_eq_len = 3;
    486     } else {
    487         sep_eq = "=";
    488         sep_eq_len = 1;
    489     }
    490 
    491     fn_opt = flags & XN_FLAG_FN_MASK;
    492 
    493     cnt = X509_NAME_entry_count(n);
    494     for (i = 0; i < cnt; i++) {
    495         if (flags & XN_FLAG_DN_REV)
    496             ent = X509_NAME_get_entry(n, cnt - i - 1);
    497         else
    498             ent = X509_NAME_get_entry(n, i);
    499         if (prev != -1) {
    500             if (prev == ent->set) {
    501                 if (!io_ch(arg, sep_mv, sep_mv_len))
    502                     return -1;
    503                 outlen += sep_mv_len;
    504             } else {
    505                 if (!io_ch(arg, sep_dn, sep_dn_len))
    506                     return -1;
    507                 outlen += sep_dn_len;
    508                 if (!do_indent(io_ch, arg, indent))
    509                     return -1;
    510                 outlen += indent;
    511             }
    512         }
    513         prev = ent->set;
    514         fn = X509_NAME_ENTRY_get_object(ent);
    515         val = X509_NAME_ENTRY_get_data(ent);
    516         fn_nid = OBJ_obj2nid(fn);
    517         if (fn_opt != XN_FLAG_FN_NONE) {
    518             int objlen, fld_len;
    519             if ((fn_opt == XN_FLAG_FN_OID) || (fn_nid == NID_undef)) {
    520                 OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1);
    521                 fld_len = 0;    /* XXX: what should this be? */
    522                 objbuf = objtmp;
    523             } else {
    524                 if (fn_opt == XN_FLAG_FN_SN) {
    525                     fld_len = FN_WIDTH_SN;
    526                     objbuf = OBJ_nid2sn(fn_nid);
    527                 } else if (fn_opt == XN_FLAG_FN_LN) {
    528                     fld_len = FN_WIDTH_LN;
    529                     objbuf = OBJ_nid2ln(fn_nid);
    530                 } else {
    531                     fld_len = 0; /* XXX: what should this be? */
    532                     objbuf = "";
    533                 }
    534             }
    535             objlen = strlen(objbuf);
    536             if (!io_ch(arg, objbuf, objlen))
    537                 return -1;
    538             if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
    539                 if (!do_indent(io_ch, arg, fld_len - objlen))
    540                     return -1;
    541                 outlen += fld_len - objlen;
    542             }
    543             if (!io_ch(arg, sep_eq, sep_eq_len))
    544                 return -1;
    545             outlen += objlen + sep_eq_len;
    546         }
    547         /*
    548          * If the field name is unknown then fix up the DER dump flag. We
    549          * might want to limit this further so it will DER dump on anything
    550          * other than a few 'standard' fields.
    551          */
    552         if ((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
    553             orflags = ASN1_STRFLGS_DUMP_ALL;
    554         else
    555             orflags = 0;
    556 
    557         len = do_print_ex(io_ch, arg, flags | orflags, val);
    558         if (len < 0)
    559             return -1;
    560         outlen += len;
    561     }
    562     return outlen;
    563 }
    564 
    565 /* Wrappers round the main functions */
    566 
    567 int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent,
    568                        unsigned long flags)
    569 {
    570     if (flags == XN_FLAG_COMPAT)
    571         return X509_NAME_print(out, nm, indent);
    572     return do_name_ex(send_bio_chars, out, nm, indent, flags);
    573 }
    574 
    575 #ifndef OPENSSL_NO_FP_API
    576 int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent,
    577                           unsigned long flags)
    578 {
    579     if (flags == XN_FLAG_COMPAT) {
    580         BIO *btmp;
    581         int ret;
    582         btmp = BIO_new_fp(fp, BIO_NOCLOSE);
    583         if (!btmp)
    584             return -1;
    585         ret = X509_NAME_print(btmp, nm, indent);
    586         BIO_free(btmp);
    587         return ret;
    588     }
    589     return do_name_ex(send_fp_chars, fp, nm, indent, flags);
    590 }
    591 #endif
    592 
    593 int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags)
    594 {
    595     return do_print_ex(send_bio_chars, out, flags, str);
    596 }
    597 
    598 #ifndef OPENSSL_NO_FP_API
    599 int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags)
    600 {
    601     return do_print_ex(send_fp_chars, fp, flags, str);
    602 }
    603 #endif
    604 
    605 /*
    606  * Utility function: convert any string type to UTF8, returns number of bytes
    607  * in output string or a negative error code
    608  */
    609 
    610 int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
    611 {
    612     ASN1_STRING stmp, *str = &stmp;
    613     int mbflag, type, ret;
    614     if (!in)
    615         return -1;
    616     type = in->type;
    617     if ((type < 0) || (type > 30))
    618         return -1;
    619     mbflag = tag2nbyte[type];
    620     if (mbflag == -1)
    621         return -1;
    622     mbflag |= MBSTRING_FLAG;
    623     stmp.data = NULL;
    624     stmp.length = 0;
    625     stmp.flags = 0;
    626     ret =
    627         ASN1_mbstring_copy(&str, in->data, in->length, mbflag,
    628                            B_ASN1_UTF8STRING);
    629     if (ret < 0)
    630         return ret;
    631     *out = stmp.data;
    632     return stmp.length;
    633 }
    634