a_strex.c revision 331638
168651Skris/* a_strex.c */
2280297Sjkim/*
3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4280297Sjkim * 2000.
568651Skris */
668651Skris/* ====================================================================
7160814Ssimon * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
868651Skris *
968651Skris * Redistribution and use in source and binary forms, with or without
1068651Skris * modification, are permitted provided that the following conditions
1168651Skris * are met:
1268651Skris *
1368651Skris * 1. Redistributions of source code must retain the above copyright
14280297Sjkim *    notice, this list of conditions and the following disclaimer.
1568651Skris *
1668651Skris * 2. Redistributions in binary form must reproduce the above copyright
1768651Skris *    notice, this list of conditions and the following disclaimer in
1868651Skris *    the documentation and/or other materials provided with the
1968651Skris *    distribution.
2068651Skris *
2168651Skris * 3. All advertising materials mentioning features or use of this
2268651Skris *    software must display the following acknowledgment:
2368651Skris *    "This product includes software developed by the OpenSSL Project
2468651Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2568651Skris *
2668651Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2768651Skris *    endorse or promote products derived from this software without
2868651Skris *    prior written permission. For written permission, please contact
2968651Skris *    licensing@OpenSSL.org.
3068651Skris *
3168651Skris * 5. Products derived from this software may not be called "OpenSSL"
3268651Skris *    nor may "OpenSSL" appear in their names without prior written
3368651Skris *    permission of the OpenSSL Project.
3468651Skris *
3568651Skris * 6. Redistributions of any form whatsoever must retain the following
3668651Skris *    acknowledgment:
3768651Skris *    "This product includes software developed by the OpenSSL Project
3868651Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3968651Skris *
4068651Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4168651Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4268651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4368651Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4468651Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4568651Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4668651Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4768651Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4868651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4968651Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5068651Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5168651Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5268651Skris * ====================================================================
5368651Skris *
5468651Skris * This product includes cryptographic software written by Eric Young
5568651Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5668651Skris * Hudson (tjh@cryptsoft.com).
5768651Skris *
5868651Skris */
5968651Skris
6068651Skris#include <stdio.h>
6168651Skris#include <string.h>
62160814Ssimon#include "cryptlib.h"
6368651Skris#include <openssl/crypto.h>
6468651Skris#include <openssl/x509.h>
6568651Skris#include <openssl/asn1.h>
6668651Skris
6768651Skris#include "charmap.h"
6868651Skris
69280297Sjkim/*
70280297Sjkim * ASN1_STRING_print_ex() and X509_NAME_print_ex(). Enhanced string and name
71280297Sjkim * printing routines handling multibyte characters, RFC2253 and a host of
72280297Sjkim * other options.
7368651Skris */
7468651Skris
75280297Sjkim#define CHARTYPE_BS_ESC         (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
7668651Skris
77237657Sjkim#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \
78280297Sjkim                  ASN1_STRFLGS_ESC_QUOTE | \
79280297Sjkim                  ASN1_STRFLGS_ESC_CTRL | \
80280297Sjkim                  ASN1_STRFLGS_ESC_MSB)
8168651Skris
82280297Sjkim/*
83280297Sjkim * Three IO functions for sending data to memory, a BIO and and a FILE
84280297Sjkim * pointer.
8568651Skris */
86280297Sjkim#if 0                           /* never used */
87109998Smarkmstatic int send_mem_chars(void *arg, const void *buf, int len)
8868651Skris{
89280297Sjkim    unsigned char **out = arg;
90280297Sjkim    if (!out)
91280297Sjkim        return 1;
92280297Sjkim    memcpy(*out, buf, len);
93280297Sjkim    *out += len;
94280297Sjkim    return 1;
9568651Skris}
96109998Smarkm#endif
9768651Skris
98109998Smarkmstatic int send_bio_chars(void *arg, const void *buf, int len)
9968651Skris{
100280297Sjkim    if (!arg)
101280297Sjkim        return 1;
102280297Sjkim    if (BIO_write(arg, buf, len) != len)
103280297Sjkim        return 0;
104280297Sjkim    return 1;
10568651Skris}
10668651Skris
107109998Smarkmstatic int send_fp_chars(void *arg, const void *buf, int len)
10868651Skris{
109280297Sjkim    if (!arg)
110280297Sjkim        return 1;
111280297Sjkim    if (fwrite(buf, 1, len, arg) != (unsigned int)len)
112280297Sjkim        return 0;
113280297Sjkim    return 1;
11468651Skris}
11568651Skris
116280297Sjkimtypedef int char_io (void *arg, const void *buf, int len);
11768651Skris
118280297Sjkim/*
119280297Sjkim * This function handles display of strings, one character at a time. It is
120280297Sjkim * passed an unsigned long for each character because it could come from 2 or
121280297Sjkim * even 4 byte forms.
12268651Skris */
12368651Skris
124280297Sjkimstatic int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes,
125280297Sjkim                       char_io *io_ch, void *arg)
12668651Skris{
127280297Sjkim    unsigned char chflgs, chtmp;
128280297Sjkim    char tmphex[HEX_SIZE(long) + 3];
129109998Smarkm
130280297Sjkim    if (c > 0xffffffffL)
131280297Sjkim        return -1;
132280297Sjkim    if (c > 0xffff) {
133331638Sjkim        BIO_snprintf(tmphex, sizeof(tmphex), "\\W%08lX", c);
134280297Sjkim        if (!io_ch(arg, tmphex, 10))
135280297Sjkim            return -1;
136280297Sjkim        return 10;
137280297Sjkim    }
138280297Sjkim    if (c > 0xff) {
139331638Sjkim        BIO_snprintf(tmphex, sizeof(tmphex), "\\U%04lX", c);
140280297Sjkim        if (!io_ch(arg, tmphex, 6))
141280297Sjkim            return -1;
142280297Sjkim        return 6;
143280297Sjkim    }
144280297Sjkim    chtmp = (unsigned char)c;
145280297Sjkim    if (chtmp > 0x7f)
146280297Sjkim        chflgs = flags & ASN1_STRFLGS_ESC_MSB;
147280297Sjkim    else
148280297Sjkim        chflgs = char_type[chtmp] & flags;
149280297Sjkim    if (chflgs & CHARTYPE_BS_ESC) {
150280297Sjkim        /* If we don't escape with quotes, signal we need quotes */
151280297Sjkim        if (chflgs & ASN1_STRFLGS_ESC_QUOTE) {
152280297Sjkim            if (do_quotes)
153280297Sjkim                *do_quotes = 1;
154280297Sjkim            if (!io_ch(arg, &chtmp, 1))
155280297Sjkim                return -1;
156280297Sjkim            return 1;
157280297Sjkim        }
158280297Sjkim        if (!io_ch(arg, "\\", 1))
159280297Sjkim            return -1;
160280297Sjkim        if (!io_ch(arg, &chtmp, 1))
161280297Sjkim            return -1;
162280297Sjkim        return 2;
163280297Sjkim    }
164280297Sjkim    if (chflgs & (ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB)) {
165280297Sjkim        BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
166280297Sjkim        if (!io_ch(arg, tmphex, 3))
167280297Sjkim            return -1;
168280297Sjkim        return 3;
169280297Sjkim    }
170280297Sjkim    /*
171280297Sjkim     * If we get this far and do any escaping at all must escape the escape
172280297Sjkim     * character itself: backslash.
173280297Sjkim     */
174280297Sjkim    if (chtmp == '\\' && flags & ESC_FLAGS) {
175280297Sjkim        if (!io_ch(arg, "\\\\", 2))
176280297Sjkim            return -1;
177280297Sjkim        return 2;
178280297Sjkim    }
179280297Sjkim    if (!io_ch(arg, &chtmp, 1))
180280297Sjkim        return -1;
181280297Sjkim    return 1;
18268651Skris}
18368651Skris
184280297Sjkim#define BUF_TYPE_WIDTH_MASK     0x7
185280297Sjkim#define BUF_TYPE_CONVUTF8       0x8
18668651Skris
187280297Sjkim/*
188280297Sjkim * This function sends each character in a buffer to do_esc_char(). It
189280297Sjkim * interprets the content formats and converts to or from UTF8 as
190280297Sjkim * appropriate.
19168651Skris */
19268651Skris
19368651Skrisstatic int do_buf(unsigned char *buf, int buflen,
194280297Sjkim                  int type, unsigned char flags, char *quotes, char_io *io_ch,
195280297Sjkim                  void *arg)
19668651Skris{
197280297Sjkim    int i, outlen, len;
198280297Sjkim    unsigned char orflags, *p, *q;
199280297Sjkim    unsigned long c;
200280297Sjkim    p = buf;
201280297Sjkim    q = buf + buflen;
202280297Sjkim    outlen = 0;
203280297Sjkim    while (p != q) {
204280297Sjkim        if (p == buf && flags & ASN1_STRFLGS_ESC_2253)
205280297Sjkim            orflags = CHARTYPE_FIRST_ESC_2253;
206280297Sjkim        else
207280297Sjkim            orflags = 0;
208280297Sjkim        switch (type & BUF_TYPE_WIDTH_MASK) {
209280297Sjkim        case 4:
210280297Sjkim            c = ((unsigned long)*p++) << 24;
211280297Sjkim            c |= ((unsigned long)*p++) << 16;
212280297Sjkim            c |= ((unsigned long)*p++) << 8;
213280297Sjkim            c |= *p++;
214280297Sjkim            break;
21568651Skris
216280297Sjkim        case 2:
217280297Sjkim            c = ((unsigned long)*p++) << 8;
218280297Sjkim            c |= *p++;
219280297Sjkim            break;
22068651Skris
221280297Sjkim        case 1:
222280297Sjkim            c = *p++;
223280297Sjkim            break;
224280297Sjkim
225280297Sjkim        case 0:
226280297Sjkim            i = UTF8_getc(p, buflen, &c);
227280297Sjkim            if (i < 0)
228280297Sjkim                return -1;      /* Invalid UTF8String */
229280297Sjkim            p += i;
230280297Sjkim            break;
231280297Sjkim        default:
232280297Sjkim            return -1;          /* invalid width */
233280297Sjkim        }
234280297Sjkim        if (p == q && flags & ASN1_STRFLGS_ESC_2253)
235280297Sjkim            orflags = CHARTYPE_LAST_ESC_2253;
236280297Sjkim        if (type & BUF_TYPE_CONVUTF8) {
237280297Sjkim            unsigned char utfbuf[6];
238280297Sjkim            int utflen;
239331638Sjkim            utflen = UTF8_putc(utfbuf, sizeof(utfbuf), c);
240280297Sjkim            for (i = 0; i < utflen; i++) {
241280297Sjkim                /*
242280297Sjkim                 * We don't need to worry about setting orflags correctly
243280297Sjkim                 * because if utflen==1 its value will be correct anyway
244280297Sjkim                 * otherwise each character will be > 0x7f and so the
245280297Sjkim                 * character will never be escaped on first and last.
246280297Sjkim                 */
247280297Sjkim                len =
248280297Sjkim                    do_esc_char(utfbuf[i], (unsigned char)(flags | orflags),
249280297Sjkim                                quotes, io_ch, arg);
250280297Sjkim                if (len < 0)
251280297Sjkim                    return -1;
252280297Sjkim                outlen += len;
253280297Sjkim            }
254280297Sjkim        } else {
255280297Sjkim            len =
256280297Sjkim                do_esc_char(c, (unsigned char)(flags | orflags), quotes,
257280297Sjkim                            io_ch, arg);
258280297Sjkim            if (len < 0)
259280297Sjkim                return -1;
260280297Sjkim            outlen += len;
261280297Sjkim        }
262280297Sjkim    }
263280297Sjkim    return outlen;
26468651Skris}
26568651Skris
26668651Skris/* This function hex dumps a buffer of characters */
26768651Skris
268280297Sjkimstatic int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
269280297Sjkim                       int buflen)
27068651Skris{
271280297Sjkim    static const char hexdig[] = "0123456789ABCDEF";
272280297Sjkim    unsigned char *p, *q;
273280297Sjkim    char hextmp[2];
274280297Sjkim    if (arg) {
275280297Sjkim        p = buf;
276280297Sjkim        q = buf + buflen;
277280297Sjkim        while (p != q) {
278280297Sjkim            hextmp[0] = hexdig[*p >> 4];
279280297Sjkim            hextmp[1] = hexdig[*p & 0xf];
280280297Sjkim            if (!io_ch(arg, hextmp, 2))
281280297Sjkim                return -1;
282280297Sjkim            p++;
283280297Sjkim        }
284280297Sjkim    }
285280297Sjkim    return buflen << 1;
28668651Skris}
28768651Skris
288280297Sjkim/*
289280297Sjkim * "dump" a string. This is done when the type is unknown, or the flags
290280297Sjkim * request it. We can either dump the content octets or the entire DER
291280297Sjkim * encoding. This uses the RFC2253 #01234 format.
29268651Skris */
29368651Skris
294280297Sjkimstatic int do_dump(unsigned long lflags, char_io *io_ch, void *arg,
295280297Sjkim                   ASN1_STRING *str)
29668651Skris{
297280297Sjkim    /*
298280297Sjkim     * Placing the ASN1_STRING in a temp ASN1_TYPE allows the DER encoding to
299280297Sjkim     * readily obtained
300280297Sjkim     */
301280297Sjkim    ASN1_TYPE t;
302280297Sjkim    unsigned char *der_buf, *p;
303280297Sjkim    int outlen, der_len;
30468651Skris
305280297Sjkim    if (!io_ch(arg, "#", 1))
306280297Sjkim        return -1;
307280297Sjkim    /* If we don't dump DER encoding just dump content octets */
308280297Sjkim    if (!(lflags & ASN1_STRFLGS_DUMP_DER)) {
309280297Sjkim        outlen = do_hex_dump(io_ch, arg, str->data, str->length);
310280297Sjkim        if (outlen < 0)
311280297Sjkim            return -1;
312280297Sjkim        return outlen + 1;
313280297Sjkim    }
314280297Sjkim    t.type = str->type;
315280297Sjkim    t.value.ptr = (char *)str;
316280297Sjkim    der_len = i2d_ASN1_TYPE(&t, NULL);
317280297Sjkim    der_buf = OPENSSL_malloc(der_len);
318280297Sjkim    if (!der_buf)
319280297Sjkim        return -1;
320280297Sjkim    p = der_buf;
321280297Sjkim    i2d_ASN1_TYPE(&t, &p);
322280297Sjkim    outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
323280297Sjkim    OPENSSL_free(der_buf);
324280297Sjkim    if (outlen < 0)
325280297Sjkim        return -1;
326280297Sjkim    return outlen + 1;
32768651Skris}
32868651Skris
329280297Sjkim/*
330280297Sjkim * Lookup table to convert tags to character widths, 0 = UTF8 encoded, -1 is
331280297Sjkim * used for non string types otherwise it is the number of bytes per
332280297Sjkim * character
33368651Skris */
33468651Skris
335160814Ssimonstatic const signed char tag2nbyte[] = {
336280297Sjkim    -1, -1, -1, -1, -1,         /* 0-4 */
337280297Sjkim    -1, -1, -1, -1, -1,         /* 5-9 */
338280297Sjkim    -1, -1, 0, -1,              /* 10-13 */
339280297Sjkim    -1, -1, -1, -1,             /* 15-17 */
340306195Sjkim    1, 1, 1,                    /* 18-20 */
341280297Sjkim    -1, 1, 1, 1,                /* 21-24 */
342280297Sjkim    -1, 1, -1,                  /* 25-27 */
343280297Sjkim    4, -1, 2                    /* 28-30 */
34468651Skris};
34568651Skris
346280297Sjkim/*
347280297Sjkim * This is the main function, print out an ASN1_STRING taking note of various
348280297Sjkim * escape and display options. Returns number of characters written or -1 if
349280297Sjkim * an error occurred.
35068651Skris */
35168651Skris
352280297Sjkimstatic int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
353280297Sjkim                       ASN1_STRING *str)
35468651Skris{
355280297Sjkim    int outlen, len;
356280297Sjkim    int type;
357280297Sjkim    char quotes;
358280297Sjkim    unsigned char flags;
359280297Sjkim    quotes = 0;
360280297Sjkim    /* Keep a copy of escape flags */
361280297Sjkim    flags = (unsigned char)(lflags & ESC_FLAGS);
36268651Skris
363280297Sjkim    type = str->type;
36468651Skris
365280297Sjkim    outlen = 0;
36668651Skris
367280297Sjkim    if (lflags & ASN1_STRFLGS_SHOW_TYPE) {
368280297Sjkim        const char *tagname;
369280297Sjkim        tagname = ASN1_tag2str(type);
370280297Sjkim        outlen += strlen(tagname);
371280297Sjkim        if (!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1))
372280297Sjkim            return -1;
373280297Sjkim        outlen++;
374280297Sjkim    }
37568651Skris
376280297Sjkim    /* Decide what to do with type, either dump content or display it */
37768651Skris
378280297Sjkim    /* Dump everything */
379280297Sjkim    if (lflags & ASN1_STRFLGS_DUMP_ALL)
380280297Sjkim        type = -1;
381280297Sjkim    /* Ignore the string type */
382280297Sjkim    else if (lflags & ASN1_STRFLGS_IGNORE_TYPE)
383280297Sjkim        type = 1;
384280297Sjkim    else {
385280297Sjkim        /* Else determine width based on type */
386280297Sjkim        if ((type > 0) && (type < 31))
387280297Sjkim            type = tag2nbyte[type];
388280297Sjkim        else
389280297Sjkim            type = -1;
390280297Sjkim        if ((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN))
391280297Sjkim            type = 1;
392280297Sjkim    }
39368651Skris
394280297Sjkim    if (type == -1) {
395280297Sjkim        len = do_dump(lflags, io_ch, arg, str);
396280297Sjkim        if (len < 0)
397280297Sjkim            return -1;
398280297Sjkim        outlen += len;
399280297Sjkim        return outlen;
400280297Sjkim    }
40168651Skris
402280297Sjkim    if (lflags & ASN1_STRFLGS_UTF8_CONVERT) {
403280297Sjkim        /*
404280297Sjkim         * Note: if string is UTF8 and we want to convert to UTF8 then we
405280297Sjkim         * just interpret it as 1 byte per character to avoid converting
406280297Sjkim         * twice.
407280297Sjkim         */
408280297Sjkim        if (!type)
409280297Sjkim            type = 1;
410280297Sjkim        else
411280297Sjkim            type |= BUF_TYPE_CONVUTF8;
412280297Sjkim    }
41368651Skris
414280297Sjkim    len = do_buf(str->data, str->length, type, flags, &quotes, io_ch, NULL);
415280297Sjkim    if (len < 0)
416280297Sjkim        return -1;
417280297Sjkim    outlen += len;
418280297Sjkim    if (quotes)
419280297Sjkim        outlen += 2;
420280297Sjkim    if (!arg)
421280297Sjkim        return outlen;
422280297Sjkim    if (quotes && !io_ch(arg, "\"", 1))
423280297Sjkim        return -1;
424280297Sjkim    if (do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
425280297Sjkim        return -1;
426280297Sjkim    if (quotes && !io_ch(arg, "\"", 1))
427280297Sjkim        return -1;
428280297Sjkim    return outlen;
42968651Skris}
43068651Skris
43168651Skris/* Used for line indenting: print 'indent' spaces */
43268651Skris
43368651Skrisstatic int do_indent(char_io *io_ch, void *arg, int indent)
43468651Skris{
435280297Sjkim    int i;
436280297Sjkim    for (i = 0; i < indent; i++)
437280297Sjkim        if (!io_ch(arg, " ", 1))
438280297Sjkim            return 0;
439280297Sjkim    return 1;
44068651Skris}
44168651Skris
442280297Sjkim#define FN_WIDTH_LN     25
443280297Sjkim#define FN_WIDTH_SN     10
44468651Skris
44568651Skrisstatic int do_name_ex(char_io *io_ch, void *arg, X509_NAME *n,
446280297Sjkim                      int indent, unsigned long flags)
44768651Skris{
448280297Sjkim    int i, prev = -1, orflags, cnt;
449280297Sjkim    int fn_opt, fn_nid;
450280297Sjkim    ASN1_OBJECT *fn;
451280297Sjkim    ASN1_STRING *val;
452280297Sjkim    X509_NAME_ENTRY *ent;
453280297Sjkim    char objtmp[80];
454280297Sjkim    const char *objbuf;
455280297Sjkim    int outlen, len;
456280297Sjkim    char *sep_dn, *sep_mv, *sep_eq;
457280297Sjkim    int sep_dn_len, sep_mv_len, sep_eq_len;
458280297Sjkim    if (indent < 0)
459280297Sjkim        indent = 0;
460280297Sjkim    outlen = indent;
461280297Sjkim    if (!do_indent(io_ch, arg, indent))
462280297Sjkim        return -1;
463280297Sjkim    switch (flags & XN_FLAG_SEP_MASK) {
464280297Sjkim    case XN_FLAG_SEP_MULTILINE:
465280297Sjkim        sep_dn = "\n";
466280297Sjkim        sep_dn_len = 1;
467280297Sjkim        sep_mv = " + ";
468280297Sjkim        sep_mv_len = 3;
469280297Sjkim        break;
47068651Skris
471280297Sjkim    case XN_FLAG_SEP_COMMA_PLUS:
472280297Sjkim        sep_dn = ",";
473280297Sjkim        sep_dn_len = 1;
474280297Sjkim        sep_mv = "+";
475280297Sjkim        sep_mv_len = 1;
476280297Sjkim        indent = 0;
477280297Sjkim        break;
47868651Skris
479280297Sjkim    case XN_FLAG_SEP_CPLUS_SPC:
480280297Sjkim        sep_dn = ", ";
481280297Sjkim        sep_dn_len = 2;
482280297Sjkim        sep_mv = " + ";
483280297Sjkim        sep_mv_len = 3;
484280297Sjkim        indent = 0;
485280297Sjkim        break;
48668651Skris
487280297Sjkim    case XN_FLAG_SEP_SPLUS_SPC:
488280297Sjkim        sep_dn = "; ";
489280297Sjkim        sep_dn_len = 2;
490280297Sjkim        sep_mv = " + ";
491280297Sjkim        sep_mv_len = 3;
492280297Sjkim        indent = 0;
493280297Sjkim        break;
49468651Skris
495280297Sjkim    default:
496280297Sjkim        return -1;
497280297Sjkim    }
49868651Skris
499280297Sjkim    if (flags & XN_FLAG_SPC_EQ) {
500280297Sjkim        sep_eq = " = ";
501280297Sjkim        sep_eq_len = 3;
502280297Sjkim    } else {
503280297Sjkim        sep_eq = "=";
504280297Sjkim        sep_eq_len = 1;
505280297Sjkim    }
50668651Skris
507280297Sjkim    fn_opt = flags & XN_FLAG_FN_MASK;
50868651Skris
509280297Sjkim    cnt = X509_NAME_entry_count(n);
510280297Sjkim    for (i = 0; i < cnt; i++) {
511280297Sjkim        if (flags & XN_FLAG_DN_REV)
512280297Sjkim            ent = X509_NAME_get_entry(n, cnt - i - 1);
513280297Sjkim        else
514280297Sjkim            ent = X509_NAME_get_entry(n, i);
515280297Sjkim        if (prev != -1) {
516280297Sjkim            if (prev == ent->set) {
517280297Sjkim                if (!io_ch(arg, sep_mv, sep_mv_len))
518280297Sjkim                    return -1;
519280297Sjkim                outlen += sep_mv_len;
520280297Sjkim            } else {
521280297Sjkim                if (!io_ch(arg, sep_dn, sep_dn_len))
522280297Sjkim                    return -1;
523280297Sjkim                outlen += sep_dn_len;
524280297Sjkim                if (!do_indent(io_ch, arg, indent))
525280297Sjkim                    return -1;
526280297Sjkim                outlen += indent;
527280297Sjkim            }
528280297Sjkim        }
529280297Sjkim        prev = ent->set;
530280297Sjkim        fn = X509_NAME_ENTRY_get_object(ent);
531280297Sjkim        val = X509_NAME_ENTRY_get_data(ent);
532280297Sjkim        fn_nid = OBJ_obj2nid(fn);
533280297Sjkim        if (fn_opt != XN_FLAG_FN_NONE) {
534280297Sjkim            int objlen, fld_len;
535280297Sjkim            if ((fn_opt == XN_FLAG_FN_OID) || (fn_nid == NID_undef)) {
536331638Sjkim                OBJ_obj2txt(objtmp, sizeof(objtmp), fn, 1);
537280297Sjkim                fld_len = 0;    /* XXX: what should this be? */
538280297Sjkim                objbuf = objtmp;
539280297Sjkim            } else {
540280297Sjkim                if (fn_opt == XN_FLAG_FN_SN) {
541280297Sjkim                    fld_len = FN_WIDTH_SN;
542280297Sjkim                    objbuf = OBJ_nid2sn(fn_nid);
543280297Sjkim                } else if (fn_opt == XN_FLAG_FN_LN) {
544280297Sjkim                    fld_len = FN_WIDTH_LN;
545280297Sjkim                    objbuf = OBJ_nid2ln(fn_nid);
546280297Sjkim                } else {
547280297Sjkim                    fld_len = 0; /* XXX: what should this be? */
548280297Sjkim                    objbuf = "";
549280297Sjkim                }
550280297Sjkim            }
551280297Sjkim            objlen = strlen(objbuf);
552280297Sjkim            if (!io_ch(arg, objbuf, objlen))
553280297Sjkim                return -1;
554280297Sjkim            if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
555280297Sjkim                if (!do_indent(io_ch, arg, fld_len - objlen))
556280297Sjkim                    return -1;
557280297Sjkim                outlen += fld_len - objlen;
558280297Sjkim            }
559280297Sjkim            if (!io_ch(arg, sep_eq, sep_eq_len))
560280297Sjkim                return -1;
561280297Sjkim            outlen += objlen + sep_eq_len;
562280297Sjkim        }
563280297Sjkim        /*
564280297Sjkim         * If the field name is unknown then fix up the DER dump flag. We
565280297Sjkim         * might want to limit this further so it will DER dump on anything
566280297Sjkim         * other than a few 'standard' fields.
567280297Sjkim         */
568280297Sjkim        if ((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
569280297Sjkim            orflags = ASN1_STRFLGS_DUMP_ALL;
570280297Sjkim        else
571280297Sjkim            orflags = 0;
572280297Sjkim
573280297Sjkim        len = do_print_ex(io_ch, arg, flags | orflags, val);
574280297Sjkim        if (len < 0)
575280297Sjkim            return -1;
576280297Sjkim        outlen += len;
577280297Sjkim    }
578280297Sjkim    return outlen;
57968651Skris}
58068651Skris
58168651Skris/* Wrappers round the main functions */
58268651Skris
583280297Sjkimint X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent,
584280297Sjkim                       unsigned long flags)
58568651Skris{
586280297Sjkim    if (flags == XN_FLAG_COMPAT)
587280297Sjkim        return X509_NAME_print(out, nm, indent);
588280297Sjkim    return do_name_ex(send_bio_chars, out, nm, indent, flags);
58968651Skris}
59068651Skris
591160814Ssimon#ifndef OPENSSL_NO_FP_API
592280297Sjkimint X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent,
593280297Sjkim                          unsigned long flags)
59468651Skris{
595280297Sjkim    if (flags == XN_FLAG_COMPAT) {
596280297Sjkim        BIO *btmp;
597280297Sjkim        int ret;
598280297Sjkim        btmp = BIO_new_fp(fp, BIO_NOCLOSE);
599280297Sjkim        if (!btmp)
600280297Sjkim            return -1;
601280297Sjkim        ret = X509_NAME_print(btmp, nm, indent);
602280297Sjkim        BIO_free(btmp);
603280297Sjkim        return ret;
604280297Sjkim    }
605280297Sjkim    return do_name_ex(send_fp_chars, fp, nm, indent, flags);
60668651Skris}
607160814Ssimon#endif
60868651Skris
60968651Skrisint ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags)
61068651Skris{
611280297Sjkim    return do_print_ex(send_bio_chars, out, flags, str);
61268651Skris}
61368651Skris
614160814Ssimon#ifndef OPENSSL_NO_FP_API
61568651Skrisint ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags)
61668651Skris{
617280297Sjkim    return do_print_ex(send_fp_chars, fp, flags, str);
61868651Skris}
619160814Ssimon#endif
62068651Skris
621280297Sjkim/*
622280297Sjkim * Utility function: convert any string type to UTF8, returns number of bytes
62368651Skris * in output string or a negative error code
62468651Skris */
62568651Skris
62668651Skrisint ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
62768651Skris{
628280297Sjkim    ASN1_STRING stmp, *str = &stmp;
629280297Sjkim    int mbflag, type, ret;
630280297Sjkim    if (!in)
631280297Sjkim        return -1;
632280297Sjkim    type = in->type;
633280297Sjkim    if ((type < 0) || (type > 30))
634280297Sjkim        return -1;
635280297Sjkim    mbflag = tag2nbyte[type];
636280297Sjkim    if (mbflag == -1)
637280297Sjkim        return -1;
638280297Sjkim    mbflag |= MBSTRING_FLAG;
639280297Sjkim    stmp.data = NULL;
640280297Sjkim    stmp.length = 0;
641280297Sjkim    stmp.flags = 0;
642280297Sjkim    ret =
643280297Sjkim        ASN1_mbstring_copy(&str, in->data, in->length, mbflag,
644280297Sjkim                           B_ASN1_UTF8STRING);
645280297Sjkim    if (ret < 0)
646280297Sjkim        return ret;
647280297Sjkim    *out = stmp.data;
648280297Sjkim    return stmp.length;
64968651Skris}
650