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