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, "es, 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