1281348Scy/* a_strex.c */
2281348Scy/*
3281348Scy * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4281348Scy * 2000.
5281348Scy */
6281348Scy/* ====================================================================
7281348Scy * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
8281348Scy *
9281348Scy * Redistribution and use in source and binary forms, with or without
10281348Scy * modification, are permitted provided that the following conditions
11281348Scy * are met:
12281348Scy *
13281348Scy * 1. Redistributions of source code must retain the above copyright
14281348Scy *    notice, this list of conditions and the following disclaimer.
15281348Scy *
16281348Scy * 2. Redistributions in binary form must reproduce the above copyright
17281348Scy *    notice, this list of conditions and the following disclaimer in
18289764Sglebius *    the documentation and/or other materials provided with the
19289764Sglebius *    distribution.
20289764Sglebius *
21281348Scy * 3. All advertising materials mentioning features or use of this
22281348Scy *    software must display the following acknowledgment:
23281348Scy *    "This product includes software developed by the OpenSSL Project
24281348Scy *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25281348Scy *
26281348Scy * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27281348Scy *    endorse or promote products derived from this software without
28281348Scy *    prior written permission. For written permission, please contact
29281348Scy *    licensing@OpenSSL.org.
30281348Scy *
31281348Scy * 5. Products derived from this software may not be called "OpenSSL"
32281348Scy *    nor may "OpenSSL" appear in their names without prior written
33281348Scy *    permission of the OpenSSL Project.
34281348Scy *
35281348Scy * 6. Redistributions of any form whatsoever must retain the following
36281348Scy *    acknowledgment:
37281348Scy *    "This product includes software developed by the OpenSSL Project
38281348Scy *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39281348Scy *
40281348Scy * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41281348Scy * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42281348Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43281348Scy * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44281348Scy * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45281348Scy * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46281348Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47281348Scy * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48281348Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49281348Scy * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50281348Scy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51281348Scy * OF THE POSSIBILITY OF SUCH DAMAGE.
52281348Scy * ====================================================================
53281348Scy *
54281348Scy * This product includes cryptographic software written by Eric Young
55281348Scy * (eay@cryptsoft.com).  This product includes software written by Tim
56281348Scy * Hudson (tjh@cryptsoft.com).
57281348Scy *
58281348Scy */
59281348Scy
60281348Scy#include <stdio.h>
61281348Scy#include <string.h>
62281348Scy#include "cryptlib.h"
63281348Scy#include <openssl/crypto.h>
64281348Scy#include <openssl/x509.h>
65281348Scy#include <openssl/asn1.h>
66281348Scy
67281348Scy#include "charmap.h"
68281348Scy
69281348Scy/*
70281348Scy * ASN1_STRING_print_ex() and X509_NAME_print_ex(). Enhanced string and name
71281348Scy * printing routines handling multibyte characters, RFC2253 and a host of
72281348Scy * other options.
73281348Scy */
74281348Scy
75281348Scy#define CHARTYPE_BS_ESC         (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
76281348Scy
77281348Scy#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \
78281348Scy                  ASN1_STRFLGS_ESC_QUOTE | \
79281348Scy                  ASN1_STRFLGS_ESC_CTRL | \
80281348Scy                  ASN1_STRFLGS_ESC_MSB)
81281348Scy
82281348Scy/*
83281348Scy * Three IO functions for sending data to memory, a BIO and and a FILE
84281348Scy * pointer.
85281348Scy */
86281348Scy#if 0                           /* never used */
87281348Scystatic int send_mem_chars(void *arg, const void *buf, int len)
88281348Scy{
89281348Scy    unsigned char **out = arg;
90281348Scy    if (!out)
91281348Scy        return 1;
92281348Scy    memcpy(*out, buf, len);
93281348Scy    *out += len;
94281348Scy    return 1;
95281348Scy}
96281348Scy#endif
97281348Scy
98281348Scystatic int send_bio_chars(void *arg, const void *buf, int len)
99281348Scy{
100281348Scy    if (!arg)
101281348Scy        return 1;
102281348Scy    if (BIO_write(arg, buf, len) != len)
103281348Scy        return 0;
104281348Scy    return 1;
105281348Scy}
106281348Scy
107281348Scystatic int send_fp_chars(void *arg, const void *buf, int len)
108281348Scy{
109281348Scy    if (!arg)
110281348Scy        return 1;
111281348Scy    if (fwrite(buf, 1, len, arg) != (unsigned int)len)
112281348Scy        return 0;
113281348Scy    return 1;
114281348Scy}
115281348Scy
116281348Scytypedef int char_io (void *arg, const void *buf, int len);
117281348Scy
118281348Scy/*
119281348Scy * This function handles display of strings, one character at a time. It is
120281348Scy * passed an unsigned long for each character because it could come from 2 or
121281348Scy * even 4 byte forms.
122281348Scy */
123281348Scy
124281348Scystatic int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes,
125281348Scy                       char_io *io_ch, void *arg)
126281348Scy{
127281348Scy    unsigned char chflgs, chtmp;
128281348Scy    char tmphex[HEX_SIZE(long) + 3];
129281348Scy
130281348Scy    if (c > 0xffffffffL)
131281348Scy        return -1;
132281348Scy    if (c > 0xffff) {
133281348Scy        BIO_snprintf(tmphex, sizeof tmphex, "\\W%08lX", c);
134281348Scy        if (!io_ch(arg, tmphex, 10))
135281348Scy            return -1;
136281348Scy        return 10;
137281348Scy    }
138281348Scy    if (c > 0xff) {
139281348Scy        BIO_snprintf(tmphex, sizeof tmphex, "\\U%04lX", c);
140281348Scy        if (!io_ch(arg, tmphex, 6))
141281348Scy            return -1;
142281348Scy        return 6;
143281348Scy    }
144281348Scy    chtmp = (unsigned char)c;
145281348Scy    if (chtmp > 0x7f)
146281348Scy        chflgs = flags & ASN1_STRFLGS_ESC_MSB;
147281348Scy    else
148281348Scy        chflgs = char_type[chtmp] & flags;
149281348Scy    if (chflgs & CHARTYPE_BS_ESC) {
150281348Scy        /* If we don't escape with quotes, signal we need quotes */
151281348Scy        if (chflgs & ASN1_STRFLGS_ESC_QUOTE) {
152281348Scy            if (do_quotes)
153281348Scy                *do_quotes = 1;
154281348Scy            if (!io_ch(arg, &chtmp, 1))
155281348Scy                return -1;
156281348Scy            return 1;
157281348Scy        }
158281348Scy        if (!io_ch(arg, "\\", 1))
159281348Scy            return -1;
160281348Scy        if (!io_ch(arg, &chtmp, 1))
161281348Scy            return -1;
162281348Scy        return 2;
163281348Scy    }
164281348Scy    if (chflgs & (ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB)) {
165281348Scy        BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
166281348Scy        if (!io_ch(arg, tmphex, 3))
167281348Scy            return -1;
168281348Scy        return 3;
169281348Scy    }
170281348Scy    /*
171281348Scy     * If we get this far and do any escaping at all must escape the escape
172281348Scy     * character itself: backslash.
173281348Scy     */
174281348Scy    if (chtmp == '\\' && flags & ESC_FLAGS) {
175281348Scy        if (!io_ch(arg, "\\\\", 2))
176281348Scy            return -1;
177281348Scy        return 2;
178281348Scy    }
179281348Scy    if (!io_ch(arg, &chtmp, 1))
180281348Scy        return -1;
181281348Scy    return 1;
182281348Scy}
183281348Scy
184281348Scy#define BUF_TYPE_WIDTH_MASK     0x7
185281348Scy#define BUF_TYPE_CONVUTF8       0x8
186281348Scy
187281348Scy/*
188281348Scy * This function sends each character in a buffer to do_esc_char(). It
189281348Scy * interprets the content formats and converts to or from UTF8 as
190281348Scy * appropriate.
191281348Scy */
192281348Scy
193281348Scystatic int do_buf(unsigned char *buf, int buflen,
194281348Scy                  int type, unsigned char flags, char *quotes, char_io *io_ch,
195281348Scy                  void *arg)
196281348Scy{
197281348Scy    int i, outlen, len;
198281348Scy    unsigned char orflags, *p, *q;
199281348Scy    unsigned long c;
200281348Scy    p = buf;
201281348Scy    q = buf + buflen;
202281348Scy    outlen = 0;
203281348Scy    while (p != q) {
204281348Scy        if (p == buf && flags & ASN1_STRFLGS_ESC_2253)
205281348Scy            orflags = CHARTYPE_FIRST_ESC_2253;
206281348Scy        else
207281348Scy            orflags = 0;
208289764Sglebius        switch (type & BUF_TYPE_WIDTH_MASK) {
209289764Sglebius        case 4:
210281348Scy            c = ((unsigned long)*p++) << 24;
211281348Scy            c |= ((unsigned long)*p++) << 16;
212281348Scy            c |= ((unsigned long)*p++) << 8;
213281348Scy            c |= *p++;
214281348Scy            break;
215281348Scy
216281348Scy        case 2:
217281348Scy            c = ((unsigned long)*p++) << 8;
218281348Scy            c |= *p++;
219281348Scy            break;
220281348Scy
221281348Scy        case 1:
222281348Scy            c = *p++;
223281348Scy            break;
224281348Scy
225281348Scy        case 0:
226281348Scy            i = UTF8_getc(p, buflen, &c);
227281348Scy            if (i < 0)
228281348Scy                return -1;      /* Invalid UTF8String */
229281348Scy            p += i;
230281348Scy            break;
231281348Scy        default:
232281348Scy            return -1;          /* invalid width */
233281348Scy        }
234281348Scy        if (p == q && flags & ASN1_STRFLGS_ESC_2253)
235281348Scy            orflags = CHARTYPE_LAST_ESC_2253;
236281348Scy        if (type & BUF_TYPE_CONVUTF8) {
237281348Scy            unsigned char utfbuf[6];
238281348Scy            int utflen;
239281348Scy            utflen = UTF8_putc(utfbuf, sizeof utfbuf, c);
240281348Scy            for (i = 0; i < utflen; i++) {
241281348Scy                /*
242281348Scy                 * We don't need to worry about setting orflags correctly
243281348Scy                 * because if utflen==1 its value will be correct anyway
244281348Scy                 * otherwise each character will be > 0x7f and so the
245281348Scy                 * character will never be escaped on first and last.
246281348Scy                 */
247281348Scy                len =
248281348Scy                    do_esc_char(utfbuf[i], (unsigned char)(flags | orflags),
249281348Scy                                quotes, io_ch, arg);
250281348Scy                if (len < 0)
251281348Scy                    return -1;
252281348Scy                outlen += len;
253281348Scy            }
254281348Scy        } else {
255281348Scy            len =
256281348Scy                do_esc_char(c, (unsigned char)(flags | orflags), quotes,
257281348Scy                            io_ch, arg);
258281348Scy            if (len < 0)
259281348Scy                return -1;
260281348Scy            outlen += len;
261281348Scy        }
262281348Scy    }
263281348Scy    return outlen;
264281348Scy}
265281348Scy
266281348Scy/* This function hex dumps a buffer of characters */
267281348Scy
268281348Scystatic int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
269281348Scy                       int buflen)
270281348Scy{
271281348Scy    static const char hexdig[] = "0123456789ABCDEF";
272281348Scy    unsigned char *p, *q;
273281348Scy    char hextmp[2];
274281348Scy    if (arg) {
275281348Scy        p = buf;
276281348Scy        q = buf + buflen;
277281348Scy        while (p != q) {
278281348Scy            hextmp[0] = hexdig[*p >> 4];
279281348Scy            hextmp[1] = hexdig[*p & 0xf];
280281348Scy            if (!io_ch(arg, hextmp, 2))
281281348Scy                return -1;
282281348Scy            p++;
283281348Scy        }
284281348Scy    }
285281348Scy    return buflen << 1;
286281348Scy}
287281348Scy
288281348Scy/*
289281348Scy * "dump" a string. This is done when the type is unknown, or the flags
290281348Scy * request it. We can either dump the content octets or the entire DER
291281348Scy * encoding. This uses the RFC2253 #01234 format.
292281348Scy */
293281348Scy
294281348Scystatic int do_dump(unsigned long lflags, char_io *io_ch, void *arg,
295281348Scy                   ASN1_STRING *str)
296281348Scy{
297281348Scy    /*
298281348Scy     * Placing the ASN1_STRING in a temp ASN1_TYPE allows the DER encoding to
299281348Scy     * readily obtained
300281348Scy     */
301281348Scy    ASN1_TYPE t;
302281348Scy    unsigned char *der_buf, *p;
303281348Scy    int outlen, der_len;
304281348Scy
305281348Scy    if (!io_ch(arg, "#", 1))
306281348Scy        return -1;
307281348Scy    /* If we don't dump DER encoding just dump content octets */
308281348Scy    if (!(lflags & ASN1_STRFLGS_DUMP_DER)) {
309281348Scy        outlen = do_hex_dump(io_ch, arg, str->data, str->length);
310281348Scy        if (outlen < 0)
311281348Scy            return -1;
312281348Scy        return outlen + 1;
313281348Scy    }
314281348Scy    t.type = str->type;
315281348Scy    t.value.ptr = (char *)str;
316281348Scy    der_len = i2d_ASN1_TYPE(&t, NULL);
317281348Scy    der_buf = OPENSSL_malloc(der_len);
318281348Scy    if (!der_buf)
319281348Scy        return -1;
320281348Scy    p = der_buf;
321281348Scy    i2d_ASN1_TYPE(&t, &p);
322281348Scy    outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
323281348Scy    OPENSSL_free(der_buf);
324281348Scy    if (outlen < 0)
325281348Scy        return -1;
326281348Scy    return outlen + 1;
327281348Scy}
328281348Scy
329281348Scy/*
330281348Scy * Lookup table to convert tags to character widths, 0 = UTF8 encoded, -1 is
331281348Scy * used for non string types otherwise it is the number of bytes per
332281348Scy * character
333281348Scy */
334281348Scy
335281348Scystatic const signed char tag2nbyte[] = {
336281348Scy    -1, -1, -1, -1, -1,         /* 0-4 */
337281348Scy    -1, -1, -1, -1, -1,         /* 5-9 */
338281348Scy    -1, -1, 0, -1,              /* 10-13 */
339281348Scy    -1, -1, -1, -1,             /* 15-17 */
340281348Scy    -1, 1, 1,                   /* 18-20 */
341281348Scy    -1, 1, 1, 1,                /* 21-24 */
342281348Scy    -1, 1, -1,                  /* 25-27 */
343281348Scy    4, -1, 2                    /* 28-30 */
344281348Scy};
345281348Scy
346281348Scy/*
347281348Scy * This is the main function, print out an ASN1_STRING taking note of various
348281348Scy * escape and display options. Returns number of characters written or -1 if
349281348Scy * an error occurred.
350281348Scy */
351281348Scy
352281348Scystatic int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
353281348Scy                       ASN1_STRING *str)
354281348Scy{
355281348Scy    int outlen, len;
356281348Scy    int type;
357281348Scy    char quotes;
358281348Scy    unsigned char flags;
359281348Scy    quotes = 0;
360281348Scy    /* Keep a copy of escape flags */
361281348Scy    flags = (unsigned char)(lflags & ESC_FLAGS);
362281348Scy
363281348Scy    type = str->type;
364281348Scy
365281348Scy    outlen = 0;
366281348Scy
367281348Scy    if (lflags & ASN1_STRFLGS_SHOW_TYPE) {
368281348Scy        const char *tagname;
369281348Scy        tagname = ASN1_tag2str(type);
370281348Scy        outlen += strlen(tagname);
371281348Scy        if (!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1))
372281348Scy            return -1;
373281348Scy        outlen++;
374281348Scy    }
375281348Scy
376281348Scy    /* Decide what to do with type, either dump content or display it */
377281348Scy
378281348Scy    /* Dump everything */
379281348Scy    if (lflags & ASN1_STRFLGS_DUMP_ALL)
380281348Scy        type = -1;
381281348Scy    /* Ignore the string type */
382281348Scy    else if (lflags & ASN1_STRFLGS_IGNORE_TYPE)
383281348Scy        type = 1;
384281348Scy    else {
385281348Scy        /* Else determine width based on type */
386281348Scy        if ((type > 0) && (type < 31))
387281348Scy            type = tag2nbyte[type];
388281348Scy        else
389281348Scy            type = -1;
390281348Scy        if ((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN))
391281348Scy            type = 1;
392281348Scy    }
393281348Scy
394281348Scy    if (type == -1) {
395281348Scy        len = do_dump(lflags, io_ch, arg, str);
396281348Scy        if (len < 0)
397281348Scy            return -1;
398281348Scy        outlen += len;
399281348Scy        return outlen;
400281348Scy    }
401281348Scy
402281348Scy    if (lflags & ASN1_STRFLGS_UTF8_CONVERT) {
403281348Scy        /*
404281348Scy         * Note: if string is UTF8 and we want to convert to UTF8 then we
405281348Scy         * just interpret it as 1 byte per character to avoid converting
406281348Scy         * twice.
407281348Scy         */
408281348Scy        if (!type)
409281348Scy            type = 1;
410281348Scy        else
411281348Scy            type |= BUF_TYPE_CONVUTF8;
412281348Scy    }
413281348Scy
414281348Scy    len = do_buf(str->data, str->length, type, flags, &quotes, io_ch, NULL);
415281348Scy    if (len < 0)
416281348Scy        return -1;
417281348Scy    outlen += len;
418281348Scy    if (quotes)
419281348Scy        outlen += 2;
420281348Scy    if (!arg)
421281348Scy        return outlen;
422281348Scy    if (quotes && !io_ch(arg, "\"", 1))
423281348Scy        return -1;
424281348Scy    if (do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
425281348Scy        return -1;
426281348Scy    if (quotes && !io_ch(arg, "\"", 1))
427281348Scy        return -1;
428281348Scy    return outlen;
429281348Scy}
430281348Scy
431281348Scy/* Used for line indenting: print 'indent' spaces */
432281348Scy
433281348Scystatic int do_indent(char_io *io_ch, void *arg, int indent)
434281348Scy{
435281348Scy    int i;
436281348Scy    for (i = 0; i < indent; i++)
437281348Scy        if (!io_ch(arg, " ", 1))
438281348Scy            return 0;
439281348Scy    return 1;
440281348Scy}
441281348Scy
442281348Scy#define FN_WIDTH_LN     25
443281348Scy#define FN_WIDTH_SN     10
444281348Scy
445281348Scystatic int do_name_ex(char_io *io_ch, void *arg, X509_NAME *n,
446281348Scy                      int indent, unsigned long flags)
447281348Scy{
448281348Scy    int i, prev = -1, orflags, cnt;
449281348Scy    int fn_opt, fn_nid;
450281348Scy    ASN1_OBJECT *fn;
451281348Scy    ASN1_STRING *val;
452281348Scy    X509_NAME_ENTRY *ent;
453281348Scy    char objtmp[80];
454281348Scy    const char *objbuf;
455281348Scy    int outlen, len;
456281348Scy    char *sep_dn, *sep_mv, *sep_eq;
457281348Scy    int sep_dn_len, sep_mv_len, sep_eq_len;
458281348Scy    if (indent < 0)
459281348Scy        indent = 0;
460281348Scy    outlen = indent;
461281348Scy    if (!do_indent(io_ch, arg, indent))
462281348Scy        return -1;
463281348Scy    switch (flags & XN_FLAG_SEP_MASK) {
464281348Scy    case XN_FLAG_SEP_MULTILINE:
465281348Scy        sep_dn = "\n";
466281348Scy        sep_dn_len = 1;
467281348Scy        sep_mv = " + ";
468281348Scy        sep_mv_len = 3;
469281348Scy        break;
470281348Scy
471281348Scy    case XN_FLAG_SEP_COMMA_PLUS:
472281348Scy        sep_dn = ",";
473281348Scy        sep_dn_len = 1;
474281348Scy        sep_mv = "+";
475281348Scy        sep_mv_len = 1;
476281348Scy        indent = 0;
477281348Scy        break;
478281348Scy
479281348Scy    case XN_FLAG_SEP_CPLUS_SPC:
480281348Scy        sep_dn = ", ";
481281348Scy        sep_dn_len = 2;
482281348Scy        sep_mv = " + ";
483281348Scy        sep_mv_len = 3;
484281348Scy        indent = 0;
485281348Scy        break;
486281348Scy
487281348Scy    case XN_FLAG_SEP_SPLUS_SPC:
488281348Scy        sep_dn = "; ";
489281348Scy        sep_dn_len = 2;
490281348Scy        sep_mv = " + ";
491281348Scy        sep_mv_len = 3;
492281348Scy        indent = 0;
493281348Scy        break;
494281348Scy
495281348Scy    default:
496281348Scy        return -1;
497281348Scy    }
498281348Scy
499281348Scy    if (flags & XN_FLAG_SPC_EQ) {
500281348Scy        sep_eq = " = ";
501281348Scy        sep_eq_len = 3;
502281348Scy    } else {
503281348Scy        sep_eq = "=";
504281348Scy        sep_eq_len = 1;
505281348Scy    }
506281348Scy
507281348Scy    fn_opt = flags & XN_FLAG_FN_MASK;
508281348Scy
509281348Scy    cnt = X509_NAME_entry_count(n);
510281348Scy    for (i = 0; i < cnt; i++) {
511281348Scy        if (flags & XN_FLAG_DN_REV)
512281348Scy            ent = X509_NAME_get_entry(n, cnt - i - 1);
513281348Scy        else
514281348Scy            ent = X509_NAME_get_entry(n, i);
515281348Scy        if (prev != -1) {
516281348Scy            if (prev == ent->set) {
517281348Scy                if (!io_ch(arg, sep_mv, sep_mv_len))
518281348Scy                    return -1;
519281348Scy                outlen += sep_mv_len;
520281348Scy            } else {
521281348Scy                if (!io_ch(arg, sep_dn, sep_dn_len))
522281348Scy                    return -1;
523281348Scy                outlen += sep_dn_len;
524281348Scy                if (!do_indent(io_ch, arg, indent))
525281348Scy                    return -1;
526281348Scy                outlen += indent;
527281348Scy            }
528281348Scy        }
529281348Scy        prev = ent->set;
530281348Scy        fn = X509_NAME_ENTRY_get_object(ent);
531281348Scy        val = X509_NAME_ENTRY_get_data(ent);
532281348Scy        fn_nid = OBJ_obj2nid(fn);
533281348Scy        if (fn_opt != XN_FLAG_FN_NONE) {
534281348Scy            int objlen, fld_len;
535281348Scy            if ((fn_opt == XN_FLAG_FN_OID) || (fn_nid == NID_undef)) {
536281348Scy                OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1);
537281348Scy                fld_len = 0;    /* XXX: what should this be? */
538281348Scy                objbuf = objtmp;
539281348Scy            } else {
540281348Scy                if (fn_opt == XN_FLAG_FN_SN) {
541281348Scy                    fld_len = FN_WIDTH_SN;
542281348Scy                    objbuf = OBJ_nid2sn(fn_nid);
543281348Scy                } else if (fn_opt == XN_FLAG_FN_LN) {
544281348Scy                    fld_len = FN_WIDTH_LN;
545281348Scy                    objbuf = OBJ_nid2ln(fn_nid);
546281348Scy                } else {
547281348Scy                    fld_len = 0; /* XXX: what should this be? */
548281348Scy                    objbuf = "";
549281348Scy                }
550281348Scy            }
551281348Scy            objlen = strlen(objbuf);
552281348Scy            if (!io_ch(arg, objbuf, objlen))
553281348Scy                return -1;
554281348Scy            if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
555281348Scy                if (!do_indent(io_ch, arg, fld_len - objlen))
556281348Scy                    return -1;
557281348Scy                outlen += fld_len - objlen;
558281348Scy            }
559281348Scy            if (!io_ch(arg, sep_eq, sep_eq_len))
560281348Scy                return -1;
561281348Scy            outlen += objlen + sep_eq_len;
562281348Scy        }
563281348Scy        /*
564281348Scy         * If the field name is unknown then fix up the DER dump flag. We
565281348Scy         * might want to limit this further so it will DER dump on anything
566281348Scy         * other than a few 'standard' fields.
567281348Scy         */
568281348Scy        if ((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
569281348Scy            orflags = ASN1_STRFLGS_DUMP_ALL;
570281348Scy        else
571281348Scy            orflags = 0;
572281348Scy
573281348Scy        len = do_print_ex(io_ch, arg, flags | orflags, val);
574281348Scy        if (len < 0)
575281348Scy            return -1;
576281348Scy        outlen += len;
577281348Scy    }
578281348Scy    return outlen;
579281348Scy}
580281348Scy
581281348Scy/* Wrappers round the main functions */
582281348Scy
583281348Scyint X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent,
584281348Scy                       unsigned long flags)
585281348Scy{
586281348Scy    if (flags == XN_FLAG_COMPAT)
587281348Scy        return X509_NAME_print(out, nm, indent);
588281348Scy    return do_name_ex(send_bio_chars, out, nm, indent, flags);
589281348Scy}
590281348Scy
591281348Scy#ifndef OPENSSL_NO_FP_API
592281348Scyint X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent,
593281348Scy                          unsigned long flags)
594281348Scy{
595281348Scy    if (flags == XN_FLAG_COMPAT) {
596281348Scy        BIO *btmp;
597281348Scy        int ret;
598281348Scy        btmp = BIO_new_fp(fp, BIO_NOCLOSE);
599281348Scy        if (!btmp)
600281348Scy            return -1;
601281348Scy        ret = X509_NAME_print(btmp, nm, indent);
602281348Scy        BIO_free(btmp);
603281348Scy        return ret;
604281348Scy    }
605281348Scy    return do_name_ex(send_fp_chars, fp, nm, indent, flags);
606281348Scy}
607281348Scy#endif
608281348Scy
609281348Scyint ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags)
610281348Scy{
611281348Scy    return do_print_ex(send_bio_chars, out, flags, str);
612281348Scy}
613281348Scy
614281348Scy#ifndef OPENSSL_NO_FP_API
615281348Scyint ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags)
616281348Scy{
617281348Scy    return do_print_ex(send_fp_chars, fp, flags, str);
618281348Scy}
619281348Scy#endif
620281348Scy
621281348Scy/*
622281348Scy * Utility function: convert any string type to UTF8, returns number of bytes
623281348Scy * in output string or a negative error code
624281348Scy */
625281348Scy
626281348Scyint ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
627281348Scy{
628281348Scy    ASN1_STRING stmp, *str = &stmp;
629281348Scy    int mbflag, type, ret;
630281348Scy    if (!in)
631281348Scy        return -1;
632281348Scy    type = in->type;
633281348Scy    if ((type < 0) || (type > 30))
634281348Scy        return -1;
635281348Scy    mbflag = tag2nbyte[type];
636281348Scy    if (mbflag == -1)
637281348Scy        return -1;
638281348Scy    mbflag |= MBSTRING_FLAG;
639281348Scy    stmp.data = NULL;
640281348Scy    stmp.length = 0;
641281348Scy    stmp.flags = 0;
642281348Scy    ret =
643281348Scy        ASN1_mbstring_copy(&str, in->data, in->length, mbflag,
644281348Scy                           B_ASN1_UTF8STRING);
645281348Scy    if (ret < 0)
646281348Scy        return ret;
647281348Scy    *out = stmp.data;
648281348Scy    return stmp.length;
649281348Scy}
650281348Scy