]>
Commit | Line | Data |
---|---|---|
7bf7a6d0 MTL |
1 | /* |
2 | * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. | |
b6f94dbe | 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 | |
3e575651 SL |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
d3819813 | 11 | #include <ctype.h> |
7bf7a6d0 | 12 | #include "internal/cryptlib.h" |
3e575651 SL |
13 | #include <openssl/asn1t.h> |
14 | #include <openssl/x509.h> | |
7bf7a6d0 MTL |
15 | #include "internal/x509_int.h" |
16 | #include "internal/asn1_int.h" | |
17 | #include "x509_lcl.h" | |
3e575651 | 18 | |
62f0afa2 MTL |
19 | /* |
20 | * Maximum length of X509_NAME: much larger than anything we should | |
21 | * ever see in practice. | |
22 | */ | |
23 | ||
24 | #define X509_NAME_MAX (1024 * 1024) | |
25 | ||
d3819813 MTL |
26 | static int x509_name_ex_d2i(ASN1_VALUE **val, |
27 | const unsigned char **in, long len, | |
28 | const ASN1_ITEM *it, | |
29 | int tag, int aclass, char opt, ASN1_TLC *ctx); | |
3e575651 | 30 | |
d3819813 MTL |
31 | static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, |
32 | const ASN1_ITEM *it, int tag, int aclass); | |
3e575651 SL |
33 | static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it); |
34 | static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it); | |
35 | ||
36 | static int x509_name_encode(X509_NAME *a); | |
d3819813 | 37 | static int x509_name_canon(X509_NAME *a); |
7bf7a6d0 | 38 | static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in); |
d3819813 MTL |
39 | static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * intname, |
40 | unsigned char **in); | |
41 | ||
42 | static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, | |
43 | int indent, | |
44 | const char *fname, const ASN1_PCTX *pctx); | |
3e575651 SL |
45 | |
46 | ASN1_SEQUENCE(X509_NAME_ENTRY) = { | |
d3819813 MTL |
47 | ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT), |
48 | ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE) | |
3e575651 SL |
49 | } ASN1_SEQUENCE_END(X509_NAME_ENTRY) |
50 | ||
51 | IMPLEMENT_ASN1_FUNCTIONS(X509_NAME_ENTRY) | |
52 | IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME_ENTRY) | |
53 | ||
d3819813 MTL |
54 | /* |
55 | * For the "Name" type we need a SEQUENCE OF { SET OF X509_NAME_ENTRY } so | |
56 | * declare two template wrappers for this | |
3e575651 SL |
57 | */ |
58 | ||
59 | ASN1_ITEM_TEMPLATE(X509_NAME_ENTRIES) = | |
d3819813 | 60 | ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, RDNS, X509_NAME_ENTRY) |
7bf7a6d0 | 61 | static_ASN1_ITEM_TEMPLATE_END(X509_NAME_ENTRIES) |
3e575651 SL |
62 | |
63 | ASN1_ITEM_TEMPLATE(X509_NAME_INTERNAL) = | |
d3819813 | 64 | ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Name, X509_NAME_ENTRIES) |
7bf7a6d0 | 65 | static_ASN1_ITEM_TEMPLATE_END(X509_NAME_INTERNAL) |
3e575651 | 66 | |
d3819813 MTL |
67 | /* |
68 | * Normally that's where it would end: we'd have two nested STACK structures | |
3e575651 | 69 | * representing the ASN1. Unfortunately X509_NAME uses a completely different |
d3819813 MTL |
70 | * form and caches encodings so we have to process the internal form and |
71 | * convert to the external form. | |
3e575651 SL |
72 | */ |
73 | ||
7bf7a6d0 | 74 | static const ASN1_EXTERN_FUNCS x509_name_ff = { |
d3819813 MTL |
75 | NULL, |
76 | x509_name_ex_new, | |
77 | x509_name_ex_free, | |
78 | 0, /* Default clear behaviour is OK */ | |
79 | x509_name_ex_d2i, | |
80 | x509_name_ex_i2d, | |
81 | x509_name_ex_print | |
3e575651 SL |
82 | }; |
83 | ||
d3819813 | 84 | IMPLEMENT_EXTERN_ASN1(X509_NAME, V_ASN1_SEQUENCE, x509_name_ff) |
3e575651 SL |
85 | |
86 | IMPLEMENT_ASN1_FUNCTIONS(X509_NAME) | |
d3819813 | 87 | |
3e575651 SL |
88 | IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME) |
89 | ||
90 | static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it) | |
91 | { | |
7bf7a6d0 MTL |
92 | X509_NAME *ret = OPENSSL_zalloc(sizeof(*ret)); |
93 | ||
94 | if (ret == NULL) | |
d3819813 MTL |
95 | goto memerr; |
96 | if ((ret->entries = sk_X509_NAME_ENTRY_new_null()) == NULL) | |
97 | goto memerr; | |
98 | if ((ret->bytes = BUF_MEM_new()) == NULL) | |
99 | goto memerr; | |
d3819813 MTL |
100 | ret->modified = 1; |
101 | *val = (ASN1_VALUE *)ret; | |
102 | return 1; | |
3e575651 SL |
103 | |
104 | memerr: | |
d3819813 MTL |
105 | ASN1err(ASN1_F_X509_NAME_EX_NEW, ERR_R_MALLOC_FAILURE); |
106 | if (ret) { | |
7bf7a6d0 | 107 | sk_X509_NAME_ENTRY_free(ret->entries); |
d3819813 MTL |
108 | OPENSSL_free(ret); |
109 | } | |
110 | return 0; | |
3e575651 SL |
111 | } |
112 | ||
113 | static void x509_name_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) | |
114 | { | |
d3819813 | 115 | X509_NAME *a; |
7bf7a6d0 | 116 | |
d3819813 MTL |
117 | if (!pval || !*pval) |
118 | return; | |
119 | a = (X509_NAME *)*pval; | |
120 | ||
121 | BUF_MEM_free(a->bytes); | |
122 | sk_X509_NAME_ENTRY_pop_free(a->entries, X509_NAME_ENTRY_free); | |
7bf7a6d0 | 123 | OPENSSL_free(a->canon_enc); |
d3819813 MTL |
124 | OPENSSL_free(a); |
125 | *pval = NULL; | |
3e575651 SL |
126 | } |
127 | ||
7bf7a6d0 MTL |
128 | static void local_sk_X509_NAME_ENTRY_free(STACK_OF(X509_NAME_ENTRY) *ne) |
129 | { | |
130 | sk_X509_NAME_ENTRY_free(ne); | |
131 | } | |
132 | ||
133 | static void local_sk_X509_NAME_ENTRY_pop_free(STACK_OF(X509_NAME_ENTRY) *ne) | |
134 | { | |
135 | sk_X509_NAME_ENTRY_pop_free(ne, X509_NAME_ENTRY_free); | |
136 | } | |
137 | ||
d3819813 MTL |
138 | static int x509_name_ex_d2i(ASN1_VALUE **val, |
139 | const unsigned char **in, long len, | |
140 | const ASN1_ITEM *it, int tag, int aclass, | |
141 | char opt, ASN1_TLC *ctx) | |
142 | { | |
143 | const unsigned char *p = *in, *q; | |
144 | union { | |
145 | STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; | |
146 | ASN1_VALUE *a; | |
147 | } intname = { | |
148 | NULL | |
149 | }; | |
150 | union { | |
151 | X509_NAME *x; | |
152 | ASN1_VALUE *a; | |
153 | } nm = { | |
154 | NULL | |
155 | }; | |
156 | int i, j, ret; | |
157 | STACK_OF(X509_NAME_ENTRY) *entries; | |
158 | X509_NAME_ENTRY *entry; | |
f4173af1 MTL |
159 | if (len > X509_NAME_MAX) |
160 | len = X509_NAME_MAX; | |
d3819813 MTL |
161 | q = p; |
162 | ||
163 | /* Get internal representation of Name */ | |
164 | ret = ASN1_item_ex_d2i(&intname.a, | |
165 | &p, len, ASN1_ITEM_rptr(X509_NAME_INTERNAL), | |
166 | tag, aclass, opt, ctx); | |
167 | ||
168 | if (ret <= 0) | |
169 | return ret; | |
170 | ||
171 | if (*val) | |
172 | x509_name_ex_free(val, NULL); | |
173 | if (!x509_name_ex_new(&nm.a, NULL)) | |
174 | goto err; | |
175 | /* We've decoded it: now cache encoding */ | |
176 | if (!BUF_MEM_grow(nm.x->bytes, p - q)) | |
177 | goto err; | |
178 | memcpy(nm.x->bytes->data, q, p - q); | |
179 | ||
180 | /* Convert internal representation to X509_NAME structure */ | |
181 | for (i = 0; i < sk_STACK_OF_X509_NAME_ENTRY_num(intname.s); i++) { | |
182 | entries = sk_STACK_OF_X509_NAME_ENTRY_value(intname.s, i); | |
183 | for (j = 0; j < sk_X509_NAME_ENTRY_num(entries); j++) { | |
184 | entry = sk_X509_NAME_ENTRY_value(entries, j); | |
185 | entry->set = i; | |
186 | if (!sk_X509_NAME_ENTRY_push(nm.x->entries, entry)) | |
187 | goto err; | |
7bf7a6d0 | 188 | sk_X509_NAME_ENTRY_set(entries, j, NULL); |
d3819813 | 189 | } |
d3819813 | 190 | } |
d3819813 MTL |
191 | ret = x509_name_canon(nm.x); |
192 | if (!ret) | |
193 | goto err; | |
7bf7a6d0 MTL |
194 | sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, |
195 | local_sk_X509_NAME_ENTRY_free); | |
d3819813 MTL |
196 | nm.x->modified = 0; |
197 | *val = nm.a; | |
198 | *in = p; | |
199 | return ret; | |
7bf7a6d0 | 200 | |
d3819813 MTL |
201 | err: |
202 | if (nm.x != NULL) | |
203 | X509_NAME_free(nm.x); | |
7bf7a6d0 MTL |
204 | sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, |
205 | local_sk_X509_NAME_ENTRY_pop_free); | |
d3819813 MTL |
206 | ASN1err(ASN1_F_X509_NAME_EX_D2I, ERR_R_NESTED_ASN1_ERROR); |
207 | return 0; | |
208 | } | |
3e575651 | 209 | |
d3819813 MTL |
210 | static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, |
211 | const ASN1_ITEM *it, int tag, int aclass) | |
3e575651 | 212 | { |
d3819813 MTL |
213 | int ret; |
214 | X509_NAME *a = (X509_NAME *)*val; | |
215 | if (a->modified) { | |
216 | ret = x509_name_encode(a); | |
217 | if (ret < 0) | |
218 | return ret; | |
219 | ret = x509_name_canon(a); | |
220 | if (ret < 0) | |
221 | return ret; | |
222 | } | |
223 | ret = a->bytes->length; | |
224 | if (out != NULL) { | |
225 | memcpy(*out, a->bytes->data, ret); | |
226 | *out += ret; | |
227 | } | |
228 | return ret; | |
3e575651 SL |
229 | } |
230 | ||
3e575651 SL |
231 | static int x509_name_encode(X509_NAME *a) |
232 | { | |
d3819813 MTL |
233 | union { |
234 | STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; | |
235 | ASN1_VALUE *a; | |
236 | } intname = { | |
237 | NULL | |
238 | }; | |
239 | int len; | |
240 | unsigned char *p; | |
241 | STACK_OF(X509_NAME_ENTRY) *entries = NULL; | |
242 | X509_NAME_ENTRY *entry; | |
243 | int i, set = -1; | |
244 | intname.s = sk_STACK_OF_X509_NAME_ENTRY_new_null(); | |
245 | if (!intname.s) | |
246 | goto memerr; | |
247 | for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { | |
248 | entry = sk_X509_NAME_ENTRY_value(a->entries, i); | |
249 | if (entry->set != set) { | |
250 | entries = sk_X509_NAME_ENTRY_new_null(); | |
251 | if (!entries) | |
252 | goto memerr; | |
7bf7a6d0 MTL |
253 | if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname.s, entries)) { |
254 | sk_X509_NAME_ENTRY_free(entries); | |
d3819813 | 255 | goto memerr; |
7bf7a6d0 | 256 | } |
d3819813 MTL |
257 | set = entry->set; |
258 | } | |
259 | if (!sk_X509_NAME_ENTRY_push(entries, entry)) | |
260 | goto memerr; | |
261 | } | |
262 | len = ASN1_item_ex_i2d(&intname.a, NULL, | |
263 | ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); | |
264 | if (!BUF_MEM_grow(a->bytes, len)) | |
265 | goto memerr; | |
266 | p = (unsigned char *)a->bytes->data; | |
267 | ASN1_item_ex_i2d(&intname.a, | |
268 | &p, ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); | |
269 | sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, | |
270 | local_sk_X509_NAME_ENTRY_free); | |
271 | a->modified = 0; | |
272 | return len; | |
273 | memerr: | |
274 | sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, | |
275 | local_sk_X509_NAME_ENTRY_free); | |
276 | ASN1err(ASN1_F_X509_NAME_ENCODE, ERR_R_MALLOC_FAILURE); | |
277 | return -1; | |
278 | } | |
279 | ||
280 | static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, | |
281 | int indent, | |
282 | const char *fname, const ASN1_PCTX *pctx) | |
283 | { | |
7bf7a6d0 | 284 | if (X509_NAME_print_ex(out, (const X509_NAME *)*pval, |
d3819813 MTL |
285 | indent, pctx->nm_flags) <= 0) |
286 | return 0; | |
287 | return 2; | |
288 | } | |
289 | ||
290 | /* | |
291 | * This function generates the canonical encoding of the Name structure. In | |
292 | * it all strings are converted to UTF8, leading, trailing and multiple | |
293 | * spaces collapsed, converted to lower case and the leading SEQUENCE header | |
294 | * removed. In future we could also normalize the UTF8 too. By doing this | |
7bf7a6d0 | 295 | * comparison of Name structures can be rapidly performed by just using |
d3819813 MTL |
296 | * memcmp() of the canonical encoding. By omitting the leading SEQUENCE name |
297 | * constraints of type dirName can also be checked with a simple memcmp(). | |
298 | */ | |
299 | ||
300 | static int x509_name_canon(X509_NAME *a) | |
301 | { | |
302 | unsigned char *p; | |
303 | STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL; | |
304 | STACK_OF(X509_NAME_ENTRY) *entries = NULL; | |
305 | X509_NAME_ENTRY *entry, *tmpentry = NULL; | |
7bf7a6d0 | 306 | int i, set = -1, ret = 0, len; |
d3819813 | 307 | |
7bf7a6d0 MTL |
308 | OPENSSL_free(a->canon_enc); |
309 | a->canon_enc = NULL; | |
d3819813 MTL |
310 | /* Special case: empty X509_NAME => null encoding */ |
311 | if (sk_X509_NAME_ENTRY_num(a->entries) == 0) { | |
312 | a->canon_enclen = 0; | |
313 | return 1; | |
314 | } | |
315 | intname = sk_STACK_OF_X509_NAME_ENTRY_new_null(); | |
316 | if (!intname) | |
317 | goto err; | |
318 | for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { | |
319 | entry = sk_X509_NAME_ENTRY_value(a->entries, i); | |
320 | if (entry->set != set) { | |
321 | entries = sk_X509_NAME_ENTRY_new_null(); | |
322 | if (!entries) | |
323 | goto err; | |
7bf7a6d0 MTL |
324 | if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname, entries)) { |
325 | sk_X509_NAME_ENTRY_free(entries); | |
d3819813 | 326 | goto err; |
7bf7a6d0 | 327 | } |
d3819813 MTL |
328 | set = entry->set; |
329 | } | |
330 | tmpentry = X509_NAME_ENTRY_new(); | |
7bf7a6d0 | 331 | if (tmpentry == NULL) |
d3819813 MTL |
332 | goto err; |
333 | tmpentry->object = OBJ_dup(entry->object); | |
7bf7a6d0 MTL |
334 | if (tmpentry->object == NULL) |
335 | goto err; | |
d3819813 MTL |
336 | if (!asn1_string_canon(tmpentry->value, entry->value)) |
337 | goto err; | |
338 | if (!sk_X509_NAME_ENTRY_push(entries, tmpentry)) | |
339 | goto err; | |
340 | tmpentry = NULL; | |
341 | } | |
342 | ||
343 | /* Finally generate encoding */ | |
344 | ||
7bf7a6d0 MTL |
345 | len = i2d_name_canon(intname, NULL); |
346 | if (len < 0) | |
347 | goto err; | |
348 | a->canon_enclen = len; | |
d3819813 MTL |
349 | |
350 | p = OPENSSL_malloc(a->canon_enclen); | |
351 | ||
7bf7a6d0 | 352 | if (p == NULL) |
d3819813 MTL |
353 | goto err; |
354 | ||
355 | a->canon_enc = p; | |
356 | ||
357 | i2d_name_canon(intname, &p); | |
358 | ||
359 | ret = 1; | |
360 | ||
361 | err: | |
362 | ||
7bf7a6d0 MTL |
363 | X509_NAME_ENTRY_free(tmpentry); |
364 | sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname, | |
365 | local_sk_X509_NAME_ENTRY_pop_free); | |
d3819813 MTL |
366 | return ret; |
367 | } | |
368 | ||
369 | /* Bitmap of all the types of string that will be canonicalized. */ | |
370 | ||
371 | #define ASN1_MASK_CANON \ | |
372 | (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \ | |
373 | | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \ | |
374 | | B_ASN1_VISIBLESTRING) | |
375 | ||
7bf7a6d0 | 376 | static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in) |
d3819813 MTL |
377 | { |
378 | unsigned char *to, *from; | |
379 | int len, i; | |
380 | ||
381 | /* If type not in bitmask just copy string across */ | |
382 | if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON)) { | |
383 | if (!ASN1_STRING_copy(out, in)) | |
384 | return 0; | |
385 | return 1; | |
386 | } | |
387 | ||
388 | out->type = V_ASN1_UTF8STRING; | |
389 | out->length = ASN1_STRING_to_UTF8(&out->data, in); | |
390 | if (out->length == -1) | |
391 | return 0; | |
392 | ||
393 | to = out->data; | |
394 | from = to; | |
395 | ||
396 | len = out->length; | |
397 | ||
398 | /* | |
399 | * Convert string in place to canonical form. Ultimately we may need to | |
400 | * handle a wider range of characters but for now ignore anything with | |
401 | * MSB set and rely on the isspace() and tolower() functions. | |
402 | */ | |
403 | ||
404 | /* Ignore leading spaces */ | |
405 | while ((len > 0) && !(*from & 0x80) && isspace(*from)) { | |
406 | from++; | |
407 | len--; | |
408 | } | |
409 | ||
7bf7a6d0 | 410 | to = from + len; |
d3819813 MTL |
411 | |
412 | /* Ignore trailing spaces */ | |
7bf7a6d0 | 413 | while ((len > 0) && !(to[-1] & 0x80) && isspace(to[-1])) { |
d3819813 MTL |
414 | to--; |
415 | len--; | |
416 | } | |
417 | ||
418 | to = out->data; | |
419 | ||
420 | i = 0; | |
421 | while (i < len) { | |
422 | /* If MSB set just copy across */ | |
423 | if (*from & 0x80) { | |
424 | *to++ = *from++; | |
425 | i++; | |
426 | } | |
427 | /* Collapse multiple spaces */ | |
428 | else if (isspace(*from)) { | |
429 | /* Copy one space across */ | |
430 | *to++ = ' '; | |
431 | /* | |
432 | * Ignore subsequent spaces. Note: don't need to check len here | |
433 | * because we know the last character is a non-space so we can't | |
434 | * overflow. | |
435 | */ | |
436 | do { | |
437 | from++; | |
438 | i++; | |
439 | } | |
440 | while (!(*from & 0x80) && isspace(*from)); | |
441 | } else { | |
442 | *to++ = tolower(*from); | |
443 | from++; | |
444 | i++; | |
445 | } | |
446 | } | |
447 | ||
448 | out->length = to - out->data; | |
449 | ||
450 | return 1; | |
451 | ||
3e575651 SL |
452 | } |
453 | ||
d3819813 MTL |
454 | static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * _intname, |
455 | unsigned char **in) | |
456 | { | |
457 | int i, len, ltmp; | |
458 | ASN1_VALUE *v; | |
459 | STACK_OF(ASN1_VALUE) *intname = (STACK_OF(ASN1_VALUE) *)_intname; | |
460 | ||
461 | len = 0; | |
462 | for (i = 0; i < sk_ASN1_VALUE_num(intname); i++) { | |
463 | v = sk_ASN1_VALUE_value(intname, i); | |
464 | ltmp = ASN1_item_ex_i2d(&v, in, | |
465 | ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1); | |
466 | if (ltmp < 0) | |
467 | return ltmp; | |
468 | len += ltmp; | |
469 | } | |
470 | return len; | |
471 | } | |
3e575651 SL |
472 | |
473 | int X509_NAME_set(X509_NAME **xn, X509_NAME *name) | |
d3819813 MTL |
474 | { |
475 | X509_NAME *in; | |
476 | ||
477 | if (!xn || !name) | |
478 | return (0); | |
479 | ||
480 | if (*xn != name) { | |
481 | in = X509_NAME_dup(name); | |
482 | if (in != NULL) { | |
483 | X509_NAME_free(*xn); | |
484 | *xn = in; | |
485 | } | |
486 | } | |
487 | return (*xn != NULL); | |
488 | } | |
489 | ||
7bf7a6d0 MTL |
490 | int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase) |
491 | { | |
492 | char *s, *c, *b; | |
493 | int l, i; | |
494 | ||
495 | l = 80 - 2 - obase; | |
f4173af1 | 496 | |
7bf7a6d0 MTL |
497 | b = X509_NAME_oneline(name, NULL, 0); |
498 | if (!b) | |
499 | return 0; | |
500 | if (!*b) { | |
501 | OPENSSL_free(b); | |
502 | return 1; | |
503 | } | |
504 | s = b + 1; /* skip the first slash */ | |
505 | ||
506 | c = s; | |
507 | for (;;) { | |
508 | #ifndef CHARSET_EBCDIC | |
509 | if (((*s == '/') && | |
510 | ((s[1] >= 'A') && (s[1] <= 'Z') && ((s[2] == '=') || | |
511 | ((s[2] >= 'A') | |
512 | && (s[2] <= 'Z') | |
513 | && (s[3] == '=')) | |
514 | ))) || (*s == '\0')) | |
515 | #else | |
516 | if (((*s == '/') && | |
517 | (isupper(s[1]) && ((s[2] == '=') || | |
518 | (isupper(s[2]) && (s[3] == '=')) | |
519 | ))) || (*s == '\0')) | |
520 | #endif | |
521 | { | |
522 | i = s - c; | |
523 | if (BIO_write(bp, c, i) != i) | |
524 | goto err; | |
525 | c = s + 1; /* skip following slash */ | |
526 | if (*s != '\0') { | |
527 | if (BIO_write(bp, ", ", 2) != 2) | |
528 | goto err; | |
529 | } | |
530 | l--; | |
531 | } | |
532 | if (*s == '\0') | |
533 | break; | |
534 | s++; | |
535 | l--; | |
536 | } | |
537 | ||
538 | OPENSSL_free(b); | |
539 | return 1; | |
540 | err: | |
541 | X509err(X509_F_X509_NAME_PRINT, ERR_R_BUF_LIB); | |
542 | OPENSSL_free(b); | |
543 | return 0; | |
544 | } | |
545 | ||
546 | int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, | |
547 | size_t *pderlen) | |
548 | { | |
549 | /* Make sure encoding is valid */ | |
550 | if (i2d_X509_NAME(nm, NULL) <= 0) | |
551 | return 0; | |
552 | if (pder != NULL) | |
553 | *pder = (unsigned char *)nm->bytes->data; | |
554 | if (pderlen != NULL) | |
555 | *pderlen = nm->bytes->length; | |
556 | return 1; | |
557 | } |