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