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