168651Skris/* a_strex.c */
2194206Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
368651Skris * project 2000.
468651Skris */
568651Skris/* ====================================================================
6160814Ssimon * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
768651Skris *
868651Skris * Redistribution and use in source and binary forms, with or without
968651Skris * modification, are permitted provided that the following conditions
1068651Skris * are met:
1168651Skris *
1268651Skris * 1. Redistributions of source code must retain the above copyright
1368651Skris *    notice, this list of conditions and the following disclaimer.
1468651Skris *
1568651Skris * 2. Redistributions in binary form must reproduce the above copyright
1668651Skris *    notice, this list of conditions and the following disclaimer in
1768651Skris *    the documentation and/or other materials provided with the
1868651Skris *    distribution.
1968651Skris *
2068651Skris * 3. All advertising materials mentioning features or use of this
2168651Skris *    software must display the following acknowledgment:
2268651Skris *    "This product includes software developed by the OpenSSL Project
2368651Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2468651Skris *
2568651Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2668651Skris *    endorse or promote products derived from this software without
2768651Skris *    prior written permission. For written permission, please contact
2868651Skris *    licensing@OpenSSL.org.
2968651Skris *
3068651Skris * 5. Products derived from this software may not be called "OpenSSL"
3168651Skris *    nor may "OpenSSL" appear in their names without prior written
3268651Skris *    permission of the OpenSSL Project.
3368651Skris *
3468651Skris * 6. Redistributions of any form whatsoever must retain the following
3568651Skris *    acknowledgment:
3668651Skris *    "This product includes software developed by the OpenSSL Project
3768651Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3868651Skris *
3968651Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4068651Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4168651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4268651Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4368651Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4468651Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4568651Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4668651Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4768651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4868651Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4968651Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5068651Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5168651Skris * ====================================================================
5268651Skris *
5368651Skris * This product includes cryptographic software written by Eric Young
5468651Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5568651Skris * Hudson (tjh@cryptsoft.com).
5668651Skris *
5768651Skris */
5868651Skris
5968651Skris#include <stdio.h>
6068651Skris#include <string.h>
61160814Ssimon#include "cryptlib.h"
6268651Skris#include <openssl/crypto.h>
6368651Skris#include <openssl/x509.h>
6468651Skris#include <openssl/asn1.h>
6568651Skris
6668651Skris#include "charmap.h"
6768651Skris
6868651Skris/* ASN1_STRING_print_ex() and X509_NAME_print_ex().
6968651Skris * Enhanced string and name printing routines handling
7068651Skris * multibyte characters, RFC2253 and a host of other
7168651Skris * options.
7268651Skris */
7368651Skris
7468651Skris
7568651Skris#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 | \
78237657Sjkim		  ASN1_STRFLGS_ESC_QUOTE | \
79237657Sjkim		  ASN1_STRFLGS_ESC_CTRL | \
80237657Sjkim		  ASN1_STRFLGS_ESC_MSB)
8168651Skris
82237657Sjkim
8368651Skris/* Three IO functions for sending data to memory, a BIO and
8468651Skris * and a FILE pointer.
8568651Skris */
86109998Smarkm#if 0				/* never used */
87109998Smarkmstatic int send_mem_chars(void *arg, const void *buf, int len)
8868651Skris{
8968651Skris	unsigned char **out = arg;
9068651Skris	if(!out) return 1;
9168651Skris	memcpy(*out, buf, len);
9268651Skris	*out += len;
9368651Skris	return 1;
9468651Skris}
95109998Smarkm#endif
9668651Skris
97109998Smarkmstatic int send_bio_chars(void *arg, const void *buf, int len)
9868651Skris{
9968651Skris	if(!arg) return 1;
10068651Skris	if(BIO_write(arg, buf, len) != len) return 0;
10168651Skris	return 1;
10268651Skris}
10368651Skris
104109998Smarkmstatic int send_fp_chars(void *arg, const void *buf, int len)
10568651Skris{
10668651Skris	if(!arg) return 1;
10768651Skris	if(fwrite(buf, 1, len, arg) != (unsigned int)len) return 0;
10868651Skris	return 1;
10968651Skris}
11068651Skris
11168651Skristypedef int char_io(void *arg, const void *buf, int len);
11268651Skris
11368651Skris/* This function handles display of
11468651Skris * strings, one character at a time.
11568651Skris * It is passed an unsigned long for each
11668651Skris * character because it could come from 2 or even
11768651Skris * 4 byte forms.
11868651Skris */
11968651Skris
12068651Skrisstatic int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes, char_io *io_ch, void *arg)
12168651Skris{
12268651Skris	unsigned char chflgs, chtmp;
123109998Smarkm	char tmphex[HEX_SIZE(long)+3];
124109998Smarkm
125109998Smarkm	if(c > 0xffffffffL)
126109998Smarkm		return -1;
12768651Skris	if(c > 0xffff) {
128109998Smarkm		BIO_snprintf(tmphex, sizeof tmphex, "\\W%08lX", c);
12968651Skris		if(!io_ch(arg, tmphex, 10)) return -1;
13068651Skris		return 10;
13168651Skris	}
13268651Skris	if(c > 0xff) {
133109998Smarkm		BIO_snprintf(tmphex, sizeof tmphex, "\\U%04lX", c);
13468651Skris		if(!io_ch(arg, tmphex, 6)) return -1;
13568651Skris		return 6;
13668651Skris	}
13768651Skris	chtmp = (unsigned char)c;
13868651Skris	if(chtmp > 0x7f) chflgs = flags & ASN1_STRFLGS_ESC_MSB;
13968651Skris	else chflgs = char_type[chtmp] & flags;
14068651Skris	if(chflgs & CHARTYPE_BS_ESC) {
14168651Skris		/* If we don't escape with quotes, signal we need quotes */
14268651Skris		if(chflgs & ASN1_STRFLGS_ESC_QUOTE) {
14368651Skris			if(do_quotes) *do_quotes = 1;
14468651Skris			if(!io_ch(arg, &chtmp, 1)) return -1;
14568651Skris			return 1;
14668651Skris		}
14768651Skris		if(!io_ch(arg, "\\", 1)) return -1;
14868651Skris		if(!io_ch(arg, &chtmp, 1)) return -1;
14968651Skris		return 2;
15068651Skris	}
15168651Skris	if(chflgs & (ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_ESC_MSB)) {
15268651Skris		BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
15368651Skris		if(!io_ch(arg, tmphex, 3)) return -1;
15468651Skris		return 3;
15568651Skris	}
156237657Sjkim	/* If we get this far and do any escaping at all must escape
157237657Sjkim	 * the escape character itself: backslash.
158237657Sjkim	 */
159237657Sjkim	if (chtmp == '\\' && flags & ESC_FLAGS) {
160237657Sjkim		if(!io_ch(arg, "\\\\", 2)) return -1;
161237657Sjkim		return 2;
162237657Sjkim	}
16368651Skris	if(!io_ch(arg, &chtmp, 1)) return -1;
16468651Skris	return 1;
16568651Skris}
16668651Skris
16768651Skris#define BUF_TYPE_WIDTH_MASK	0x7
16868651Skris#define BUF_TYPE_CONVUTF8	0x8
16968651Skris
17068651Skris/* This function sends each character in a buffer to
17168651Skris * do_esc_char(). It interprets the content formats
17268651Skris * and converts to or from UTF8 as appropriate.
17368651Skris */
17468651Skris
17568651Skrisstatic int do_buf(unsigned char *buf, int buflen,
17668651Skris			int type, unsigned char flags, char *quotes, char_io *io_ch, void *arg)
17768651Skris{
17868651Skris	int i, outlen, len;
17968651Skris	unsigned char orflags, *p, *q;
18068651Skris	unsigned long c;
18168651Skris	p = buf;
18268651Skris	q = buf + buflen;
18368651Skris	outlen = 0;
18468651Skris	while(p != q) {
185167612Ssimon		if(p == buf && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_FIRST_ESC_2253;
18668651Skris		else orflags = 0;
18768651Skris		switch(type & BUF_TYPE_WIDTH_MASK) {
18868651Skris			case 4:
18968651Skris			c = ((unsigned long)*p++) << 24;
19068651Skris			c |= ((unsigned long)*p++) << 16;
19168651Skris			c |= ((unsigned long)*p++) << 8;
19268651Skris			c |= *p++;
19368651Skris			break;
19468651Skris
19568651Skris			case 2:
19668651Skris			c = ((unsigned long)*p++) << 8;
19768651Skris			c |= *p++;
19868651Skris			break;
19968651Skris
20068651Skris			case 1:
20168651Skris			c = *p++;
20268651Skris			break;
20368651Skris
20468651Skris			case 0:
20568651Skris			i = UTF8_getc(p, buflen, &c);
20668651Skris			if(i < 0) return -1;	/* Invalid UTF8String */
20768651Skris			p += i;
20868651Skris			break;
209160814Ssimon			default:
210160814Ssimon			return -1;	/* invalid width */
21168651Skris		}
212167612Ssimon		if (p == q && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_LAST_ESC_2253;
21368651Skris		if(type & BUF_TYPE_CONVUTF8) {
21468651Skris			unsigned char utfbuf[6];
21568651Skris			int utflen;
216109998Smarkm			utflen = UTF8_putc(utfbuf, sizeof utfbuf, c);
21768651Skris			for(i = 0; i < utflen; i++) {
21868651Skris				/* We don't need to worry about setting orflags correctly
21968651Skris				 * because if utflen==1 its value will be correct anyway
22068651Skris				 * otherwise each character will be > 0x7f and so the
22168651Skris				 * character will never be escaped on first and last.
22268651Skris				 */
22368651Skris				len = do_esc_char(utfbuf[i], (unsigned char)(flags | orflags), quotes, io_ch, arg);
22468651Skris				if(len < 0) return -1;
22568651Skris				outlen += len;
22668651Skris			}
22768651Skris		} else {
22868651Skris			len = do_esc_char(c, (unsigned char)(flags | orflags), quotes, io_ch, arg);
22968651Skris			if(len < 0) return -1;
23068651Skris			outlen += len;
23168651Skris		}
23268651Skris	}
23368651Skris	return outlen;
23468651Skris}
23568651Skris
23668651Skris/* This function hex dumps a buffer of characters */
23768651Skris
23868651Skrisstatic int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf, int buflen)
23968651Skris{
240160814Ssimon	static const char hexdig[] = "0123456789ABCDEF";
24168651Skris	unsigned char *p, *q;
24268651Skris	char hextmp[2];
24368651Skris	if(arg) {
24468651Skris		p = buf;
24568651Skris		q = buf + buflen;
24668651Skris		while(p != q) {
24768651Skris			hextmp[0] = hexdig[*p >> 4];
24868651Skris			hextmp[1] = hexdig[*p & 0xf];
24968651Skris			if(!io_ch(arg, hextmp, 2)) return -1;
25068651Skris			p++;
25168651Skris		}
25268651Skris	}
25368651Skris	return buflen << 1;
25468651Skris}
25568651Skris
25668651Skris/* "dump" a string. This is done when the type is unknown,
25768651Skris * or the flags request it. We can either dump the content
25868651Skris * octets or the entire DER encoding. This uses the RFC2253
25968651Skris * #01234 format.
26068651Skris */
26168651Skris
262109998Smarkmstatic int do_dump(unsigned long lflags, char_io *io_ch, void *arg, ASN1_STRING *str)
26368651Skris{
26468651Skris	/* Placing the ASN1_STRING in a temp ASN1_TYPE allows
26568651Skris	 * the DER encoding to readily obtained
26668651Skris	 */
26768651Skris	ASN1_TYPE t;
26868651Skris	unsigned char *der_buf, *p;
26968651Skris	int outlen, der_len;
27068651Skris
27168651Skris	if(!io_ch(arg, "#", 1)) return -1;
27268651Skris	/* If we don't dump DER encoding just dump content octets */
27368651Skris	if(!(lflags & ASN1_STRFLGS_DUMP_DER)) {
27468651Skris		outlen = do_hex_dump(io_ch, arg, str->data, str->length);
27568651Skris		if(outlen < 0) return -1;
27668651Skris		return outlen + 1;
27768651Skris	}
27868651Skris	t.type = str->type;
27968651Skris	t.value.ptr = (char *)str;
28068651Skris	der_len = i2d_ASN1_TYPE(&t, NULL);
28168651Skris	der_buf = OPENSSL_malloc(der_len);
28268651Skris	if(!der_buf) return -1;
28368651Skris	p = der_buf;
28468651Skris	i2d_ASN1_TYPE(&t, &p);
28568651Skris	outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
28668651Skris	OPENSSL_free(der_buf);
28768651Skris	if(outlen < 0) return -1;
28868651Skris	return outlen + 1;
28968651Skris}
29068651Skris
29168651Skris/* Lookup table to convert tags to character widths,
29268651Skris * 0 = UTF8 encoded, -1 is used for non string types
29368651Skris * otherwise it is the number of bytes per character
29468651Skris */
29568651Skris
296160814Ssimonstatic const signed char tag2nbyte[] = {
29768651Skris	-1, -1, -1, -1, -1,	/* 0-4 */
29868651Skris	-1, -1, -1, -1, -1,	/* 5-9 */
29968651Skris	-1, -1, 0, -1,		/* 10-13 */
30068651Skris	-1, -1, -1, -1,		/* 15-17 */
30168651Skris	-1, 1, 1,		/* 18-20 */
302127128Snectar	-1, 1, 1, 1,		/* 21-24 */
30368651Skris	-1, 1, -1,		/* 25-27 */
30468651Skris	4, -1, 2		/* 28-30 */
30568651Skris};
30668651Skris
30768651Skris/* This is the main function, print out an
30868651Skris * ASN1_STRING taking note of various escape
30968651Skris * and display options. Returns number of
31068651Skris * characters written or -1 if an error
31168651Skris * occurred.
31268651Skris */
31368651Skris
31468651Skrisstatic int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags, ASN1_STRING *str)
31568651Skris{
31668651Skris	int outlen, len;
31768651Skris	int type;
31868651Skris	char quotes;
31968651Skris	unsigned char flags;
32068651Skris	quotes = 0;
32168651Skris	/* Keep a copy of escape flags */
32268651Skris	flags = (unsigned char)(lflags & ESC_FLAGS);
32368651Skris
32468651Skris	type = str->type;
32568651Skris
32668651Skris	outlen = 0;
32768651Skris
32868651Skris
32968651Skris	if(lflags & ASN1_STRFLGS_SHOW_TYPE) {
33068651Skris		const char *tagname;
33168651Skris		tagname = ASN1_tag2str(type);
33268651Skris		outlen += strlen(tagname);
33368651Skris		if(!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1)) return -1;
33468651Skris		outlen++;
33568651Skris	}
33668651Skris
33768651Skris	/* Decide what to do with type, either dump content or display it */
33868651Skris
33968651Skris	/* Dump everything */
34068651Skris	if(lflags & ASN1_STRFLGS_DUMP_ALL) type = -1;
34168651Skris	/* Ignore the string type */
34268651Skris	else if(lflags & ASN1_STRFLGS_IGNORE_TYPE) type = 1;
34368651Skris	else {
34468651Skris		/* Else determine width based on type */
34568651Skris		if((type > 0) && (type < 31)) type = tag2nbyte[type];
34668651Skris		else type = -1;
34768651Skris		if((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN)) type = 1;
34868651Skris	}
34968651Skris
35068651Skris	if(type == -1) {
35168651Skris		len = do_dump(lflags, io_ch, arg, str);
35268651Skris		if(len < 0) return -1;
35368651Skris		outlen += len;
35468651Skris		return outlen;
35568651Skris	}
35668651Skris
35768651Skris	if(lflags & ASN1_STRFLGS_UTF8_CONVERT) {
35868651Skris		/* Note: if string is UTF8 and we want
35968651Skris		 * to convert to UTF8 then we just interpret
36068651Skris		 * it as 1 byte per character to avoid converting
36168651Skris		 * twice.
36268651Skris		 */
36368651Skris		if(!type) type = 1;
36468651Skris		else type |= BUF_TYPE_CONVUTF8;
36568651Skris	}
36668651Skris
36768651Skris	len = do_buf(str->data, str->length, type, flags, &quotes, io_ch, NULL);
368160814Ssimon	if(len < 0) return -1;
36968651Skris	outlen += len;
37068651Skris	if(quotes) outlen += 2;
37168651Skris	if(!arg) return outlen;
37268651Skris	if(quotes && !io_ch(arg, "\"", 1)) return -1;
373160814Ssimon	if(do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
374160814Ssimon		return -1;
37568651Skris	if(quotes && !io_ch(arg, "\"", 1)) return -1;
37668651Skris	return outlen;
37768651Skris}
37868651Skris
37968651Skris/* Used for line indenting: print 'indent' spaces */
38068651Skris
38168651Skrisstatic int do_indent(char_io *io_ch, void *arg, int indent)
38268651Skris{
38368651Skris	int i;
38468651Skris	for(i = 0; i < indent; i++)
38568651Skris			if(!io_ch(arg, " ", 1)) return 0;
38668651Skris	return 1;
38768651Skris}
38868651Skris
389109998Smarkm#define FN_WIDTH_LN	25
390109998Smarkm#define FN_WIDTH_SN	10
39168651Skris
39268651Skrisstatic int do_name_ex(char_io *io_ch, void *arg, X509_NAME *n,
39368651Skris				int indent, unsigned long flags)
39468651Skris{
39568651Skris	int i, prev = -1, orflags, cnt;
39668651Skris	int fn_opt, fn_nid;
39768651Skris	ASN1_OBJECT *fn;
39868651Skris	ASN1_STRING *val;
39968651Skris	X509_NAME_ENTRY *ent;
40068651Skris	char objtmp[80];
40168651Skris	const char *objbuf;
40268651Skris	int outlen, len;
40368651Skris	char *sep_dn, *sep_mv, *sep_eq;
40468651Skris	int sep_dn_len, sep_mv_len, sep_eq_len;
40568651Skris	if(indent < 0) indent = 0;
40668651Skris	outlen = indent;
40768651Skris	if(!do_indent(io_ch, arg, indent)) return -1;
40868651Skris	switch (flags & XN_FLAG_SEP_MASK)
40968651Skris	{
41068651Skris		case XN_FLAG_SEP_MULTILINE:
41168651Skris		sep_dn = "\n";
41268651Skris		sep_dn_len = 1;
41368651Skris		sep_mv = " + ";
41468651Skris		sep_mv_len = 3;
41568651Skris		break;
41668651Skris
41768651Skris		case XN_FLAG_SEP_COMMA_PLUS:
41868651Skris		sep_dn = ",";
41968651Skris		sep_dn_len = 1;
42068651Skris		sep_mv = "+";
42168651Skris		sep_mv_len = 1;
42268651Skris		indent = 0;
42368651Skris		break;
42468651Skris
42568651Skris		case XN_FLAG_SEP_CPLUS_SPC:
42668651Skris		sep_dn = ", ";
42768651Skris		sep_dn_len = 2;
42868651Skris		sep_mv = " + ";
42968651Skris		sep_mv_len = 3;
43068651Skris		indent = 0;
43168651Skris		break;
43268651Skris
43368651Skris		case XN_FLAG_SEP_SPLUS_SPC:
43468651Skris		sep_dn = "; ";
43568651Skris		sep_dn_len = 2;
43668651Skris		sep_mv = " + ";
43768651Skris		sep_mv_len = 3;
43868651Skris		indent = 0;
43968651Skris		break;
44068651Skris
44168651Skris		default:
44268651Skris		return -1;
44368651Skris	}
44468651Skris
44568651Skris	if(flags & XN_FLAG_SPC_EQ) {
44668651Skris		sep_eq = " = ";
44768651Skris		sep_eq_len = 3;
44868651Skris	} else {
44968651Skris		sep_eq = "=";
45068651Skris		sep_eq_len = 1;
45168651Skris	}
45268651Skris
45368651Skris	fn_opt = flags & XN_FLAG_FN_MASK;
45468651Skris
45568651Skris	cnt = X509_NAME_entry_count(n);
45668651Skris	for(i = 0; i < cnt; i++) {
45768651Skris		if(flags & XN_FLAG_DN_REV)
45868651Skris				ent = X509_NAME_get_entry(n, cnt - i - 1);
45968651Skris		else ent = X509_NAME_get_entry(n, i);
46068651Skris		if(prev != -1) {
46168651Skris			if(prev == ent->set) {
46268651Skris				if(!io_ch(arg, sep_mv, sep_mv_len)) return -1;
46368651Skris				outlen += sep_mv_len;
46468651Skris			} else {
46568651Skris				if(!io_ch(arg, sep_dn, sep_dn_len)) return -1;
46668651Skris				outlen += sep_dn_len;
46768651Skris				if(!do_indent(io_ch, arg, indent)) return -1;
46868651Skris				outlen += indent;
46968651Skris			}
47068651Skris		}
47168651Skris		prev = ent->set;
47268651Skris		fn = X509_NAME_ENTRY_get_object(ent);
47368651Skris		val = X509_NAME_ENTRY_get_data(ent);
47468651Skris		fn_nid = OBJ_obj2nid(fn);
47568651Skris		if(fn_opt != XN_FLAG_FN_NONE) {
476109998Smarkm			int objlen, fld_len;
47768651Skris			if((fn_opt == XN_FLAG_FN_OID) || (fn_nid==NID_undef) ) {
478109998Smarkm				OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1);
479109998Smarkm				fld_len = 0; /* XXX: what should this be? */
48068651Skris				objbuf = objtmp;
48168651Skris			} else {
482109998Smarkm				if(fn_opt == XN_FLAG_FN_SN) {
483109998Smarkm					fld_len = FN_WIDTH_SN;
48468651Skris					objbuf = OBJ_nid2sn(fn_nid);
485109998Smarkm				} else if(fn_opt == XN_FLAG_FN_LN) {
486109998Smarkm					fld_len = FN_WIDTH_LN;
48768651Skris					objbuf = OBJ_nid2ln(fn_nid);
488109998Smarkm				} else {
489109998Smarkm					fld_len = 0; /* XXX: what should this be? */
490109998Smarkm					objbuf = "";
491109998Smarkm				}
49268651Skris			}
49368651Skris			objlen = strlen(objbuf);
49468651Skris			if(!io_ch(arg, objbuf, objlen)) return -1;
495109998Smarkm			if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
496109998Smarkm				if (!do_indent(io_ch, arg, fld_len - objlen)) return -1;
497109998Smarkm				outlen += fld_len - objlen;
498109998Smarkm			}
49968651Skris			if(!io_ch(arg, sep_eq, sep_eq_len)) return -1;
50068651Skris			outlen += objlen + sep_eq_len;
50168651Skris		}
50268651Skris		/* If the field name is unknown then fix up the DER dump
50368651Skris		 * flag. We might want to limit this further so it will
50468651Skris 		 * DER dump on anything other than a few 'standard' fields.
50568651Skris		 */
50668651Skris		if((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
50768651Skris					orflags = ASN1_STRFLGS_DUMP_ALL;
50868651Skris		else orflags = 0;
50968651Skris
51068651Skris		len = do_print_ex(io_ch, arg, flags | orflags, val);
51168651Skris		if(len < 0) return -1;
51268651Skris		outlen += len;
51368651Skris	}
51468651Skris	return outlen;
51568651Skris}
51668651Skris
51768651Skris/* Wrappers round the main functions */
51868651Skris
51968651Skrisint X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags)
52068651Skris{
521109998Smarkm	if(flags == XN_FLAG_COMPAT)
522109998Smarkm		return X509_NAME_print(out, nm, indent);
52368651Skris	return do_name_ex(send_bio_chars, out, nm, indent, flags);
52468651Skris}
52568651Skris
526160814Ssimon#ifndef OPENSSL_NO_FP_API
52768651Skrisint X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags)
52868651Skris{
529109998Smarkm	if(flags == XN_FLAG_COMPAT)
530109998Smarkm		{
531109998Smarkm		BIO *btmp;
532109998Smarkm		int ret;
533109998Smarkm		btmp = BIO_new_fp(fp, BIO_NOCLOSE);
534109998Smarkm		if(!btmp) return -1;
535109998Smarkm		ret = X509_NAME_print(btmp, nm, indent);
536109998Smarkm		BIO_free(btmp);
537109998Smarkm		return ret;
538109998Smarkm		}
53968651Skris	return do_name_ex(send_fp_chars, fp, nm, indent, flags);
54068651Skris}
541160814Ssimon#endif
54268651Skris
54368651Skrisint ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags)
54468651Skris{
54568651Skris	return do_print_ex(send_bio_chars, out, flags, str);
54668651Skris}
54768651Skris
548160814Ssimon#ifndef OPENSSL_NO_FP_API
54968651Skrisint ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags)
55068651Skris{
55168651Skris	return do_print_ex(send_fp_chars, fp, flags, str);
55268651Skris}
553160814Ssimon#endif
55468651Skris
55568651Skris/* Utility function: convert any string type to UTF8, returns number of bytes
55668651Skris * in output string or a negative error code
55768651Skris */
55868651Skris
55968651Skrisint ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
56068651Skris{
56168651Skris	ASN1_STRING stmp, *str = &stmp;
56268651Skris	int mbflag, type, ret;
563109998Smarkm	if(!in) return -1;
56468651Skris	type = in->type;
56568651Skris	if((type < 0) || (type > 30)) return -1;
56668651Skris	mbflag = tag2nbyte[type];
56768651Skris	if(mbflag == -1) return -1;
568160814Ssimon	mbflag |= MBSTRING_FLAG;
56968651Skris	stmp.data = NULL;
570246772Sjkim	stmp.length = 0;
571279264Sdelphij	stmp.flags = 0;
57268651Skris	ret = ASN1_mbstring_copy(&str, in->data, in->length, mbflag, B_ASN1_UTF8STRING);
57368651Skris	if(ret < 0) return ret;
574109998Smarkm	*out = stmp.data;
57568651Skris	return stmp.length;
57668651Skris}
577