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