Tizen 2.0 Release
[external/libgnutls26.git] / lib / x509 / dn.c
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software
3  * Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 #include <gnutls_int.h>
27 #include <libtasn1.h>
28 #include <gnutls_datum.h>
29 #include <gnutls_global.h>
30 #include <gnutls_errors.h>
31 #include <gnutls_str.h>
32 #include <common.h>
33 #include <gnutls_num.h>
34
35 /* This file includes all the required to parse an X.509 Distriguished
36  * Name (you need a parser just to read a name in the X.509 protoocols!!!)
37  */
38
39 /* Converts the given OID to an ldap acceptable string or
40  * a dotted OID.
41  */
42 static const char *
43 oid2ldap_string (const char *oid)
44 {
45   const char *ret;
46
47   ret = _gnutls_x509_oid2ldap_string (oid);
48   if (ret)
49     return ret;
50
51   /* else return the OID in dotted format */
52   return oid;
53 }
54
55 /* Escapes a string following the rules from RFC2253.
56  */
57 static char *
58 str_escape (char *str, char *buffer, unsigned int buffer_size)
59 {
60   int str_length, j, i;
61
62   if (str == NULL || buffer == NULL)
63     return NULL;
64
65   str_length = MIN (strlen (str), buffer_size - 1);
66
67   for (i = j = 0; i < str_length; i++)
68     {
69       if (str[i] == ',' || str[i] == '+' || str[i] == '"'
70           || str[i] == '\\' || str[i] == '<' || str[i] == '>'
71           || str[i] == ';')
72         buffer[j++] = '\\';
73
74       buffer[j++] = str[i];
75     }
76
77   /* null terminate the string */
78   buffer[j] = 0;
79
80   return buffer;
81 }
82
83 /* Parses an X509 DN in the asn1_struct, and puts the output into
84  * the string buf. The output is an LDAP encoded DN.
85  *
86  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
87  * That is to point in the rndSequence.
88  */
89 int
90 _gnutls_x509_parse_dn (ASN1_TYPE asn1_struct,
91                        const char *asn1_rdn_name, char *buf,
92                        size_t * sizeof_buf)
93 {
94   gnutls_buffer_st out_str;
95   int k2, k1, result;
96   char tmpbuffer1[ASN1_MAX_NAME_SIZE];
97   char tmpbuffer2[ASN1_MAX_NAME_SIZE];
98   char tmpbuffer3[ASN1_MAX_NAME_SIZE];
99   opaque value[MAX_STRING_LEN], *value2 = NULL;
100   char *escaped = NULL;
101   const char *ldap_desc;
102   char oid[MAX_OID_SIZE];
103   int len, printable;
104   char *string = NULL;
105   size_t sizeof_string, sizeof_escaped;
106
107   if (sizeof_buf == NULL)
108     {
109       gnutls_assert ();
110       return GNUTLS_E_INVALID_REQUEST;
111     }
112
113   if (*sizeof_buf > 0 && buf)
114     buf[0] = 0;
115   else
116     *sizeof_buf = 0;
117
118   _gnutls_buffer_init (&out_str);
119
120   k1 = 0;
121   do
122     {
123
124       k1++;
125       /* create a string like "tbsCertList.issuer.rdnSequence.?1"
126        */
127       if (asn1_rdn_name[0] != 0)
128         snprintf (tmpbuffer1, sizeof (tmpbuffer1), "%s.?%u", asn1_rdn_name,
129                   k1);
130       else
131         snprintf (tmpbuffer1, sizeof (tmpbuffer1), "?%u", k1);
132
133       len = sizeof (value) - 1;
134       result = asn1_read_value (asn1_struct, tmpbuffer1, value, &len);
135
136       if (result == ASN1_ELEMENT_NOT_FOUND)
137         {
138           break;
139         }
140
141       if (result != ASN1_VALUE_NOT_FOUND)
142         {
143           gnutls_assert ();
144           result = _gnutls_asn2err (result);
145           goto cleanup;
146         }
147
148       k2 = 0;
149
150       do
151         {                       /* Move to the attibute type and values
152                                  */
153           k2++;
154
155           if (tmpbuffer1[0] != 0)
156             snprintf (tmpbuffer2, sizeof (tmpbuffer2), "%s.?%u", tmpbuffer1,
157                       k2);
158           else
159             snprintf (tmpbuffer2, sizeof (tmpbuffer2), "?%u", k2);
160
161           /* Try to read the RelativeDistinguishedName attributes.
162            */
163
164           len = sizeof (value) - 1;
165           result = asn1_read_value (asn1_struct, tmpbuffer2, value, &len);
166
167           if (result == ASN1_ELEMENT_NOT_FOUND)
168             break;
169           if (result != ASN1_VALUE_NOT_FOUND)
170             {
171               gnutls_assert ();
172               result = _gnutls_asn2err (result);
173               goto cleanup;
174             }
175
176           /* Read the OID 
177            */
178           _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2);
179           _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".type");
180
181           len = sizeof (oid) - 1;
182           result = asn1_read_value (asn1_struct, tmpbuffer3, oid, &len);
183
184           if (result == ASN1_ELEMENT_NOT_FOUND)
185             break;
186           else if (result != ASN1_SUCCESS)
187             {
188               gnutls_assert ();
189               result = _gnutls_asn2err (result);
190               goto cleanup;
191             }
192
193           /* Read the Value 
194            */
195           _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2);
196           _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".value");
197
198           len = 0;
199           result = asn1_read_value (asn1_struct, tmpbuffer3, NULL, &len);
200
201           value2 = gnutls_malloc (len);
202           if (value2 == NULL)
203             {
204               gnutls_assert ();
205               result = GNUTLS_E_MEMORY_ERROR;
206               goto cleanup;
207             }
208
209           result = asn1_read_value (asn1_struct, tmpbuffer3, value2, &len);
210
211           if (result != ASN1_SUCCESS)
212             {
213               gnutls_assert ();
214               result = _gnutls_asn2err (result);
215               goto cleanup;
216             }
217 #define STR_APPEND(y) if ((result=_gnutls_buffer_append_str( &out_str, y)) < 0) { \
218         gnutls_assert(); \
219         goto cleanup; \
220 }
221           /*   The encodings of adjoining RelativeDistinguishedNames are separated
222            *   by a comma character (',' ASCII 44).
223            */
224
225           /*   Where there is a multi-valued RDN, the outputs from adjoining
226            *   AttributeTypeAndValues are separated by a plus ('+' ASCII 43)
227            *   character.
228            */
229           if (k1 != 1)
230             {                   /* the first time do not append a comma */
231               if (k2 != 1)
232                 {               /* adjoining multi-value RDN */
233                   STR_APPEND ("+");
234                 }
235               else
236                 {
237                   STR_APPEND (",");
238                 }
239             }
240
241           ldap_desc = oid2ldap_string (oid);
242           printable = _gnutls_x509_oid_data_printable (oid);
243
244           /* leading #, hex encoded value and terminating NULL */
245           sizeof_escaped = 2 * len + 2;
246
247           escaped = gnutls_malloc (sizeof_escaped);
248           if (escaped == NULL)
249             {
250               gnutls_assert ();
251               result = GNUTLS_E_MEMORY_ERROR;
252               goto cleanup;
253             }
254
255           sizeof_string = 2 * len + 2;  /* in case it is not printable */
256
257           string = gnutls_malloc (sizeof_string);
258           if (string == NULL)
259             {
260               gnutls_assert ();
261               result = GNUTLS_E_MEMORY_ERROR;
262               goto cleanup;
263             }
264
265           STR_APPEND (ldap_desc);
266           STR_APPEND ("=");
267           result = 0;
268
269           if (printable)
270             result =
271               _gnutls_x509_oid_data2string (oid,
272                                             value2, len,
273                                             string, &sizeof_string);
274
275           if (!printable || result < 0)
276             result =
277               _gnutls_x509_data2hex (value2, len, string, &sizeof_string);
278
279           if (result < 0)
280             {
281               gnutls_assert ();
282               _gnutls_x509_log
283                 ("Found OID: '%s' with value '%s'\n",
284                  oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped,
285                                        NULL));
286               goto cleanup;
287             }
288           STR_APPEND (str_escape (string, escaped, sizeof_escaped));
289           gnutls_free (string);
290           string = NULL;
291
292           gnutls_free (escaped);
293           escaped = NULL;
294           gnutls_free (value2);
295           value2 = NULL;
296
297         }
298       while (1);
299
300     }
301   while (1);
302
303   if (out_str.length >= (unsigned int) *sizeof_buf)
304     {
305       gnutls_assert ();
306       *sizeof_buf = out_str.length + 1;
307       result = GNUTLS_E_SHORT_MEMORY_BUFFER;
308       goto cleanup;
309     }
310
311   if (buf)
312     {
313       _gnutls_buffer_pop_data (&out_str, buf, sizeof_buf);
314       buf[*sizeof_buf] = 0;
315     }
316   else
317     *sizeof_buf = out_str.length;
318
319   result = 0;
320
321 cleanup:
322   gnutls_free (value2);
323   gnutls_free (string);
324   gnutls_free (escaped);
325   _gnutls_buffer_clear (&out_str);
326   return result;
327 }
328
329 /* Parses an X509 DN in the asn1_struct, and searches for the
330  * given OID in the DN.
331  *
332  * If raw_flag == 0, the output will be encoded in the LDAP way. (#hex for non printable)
333  * Otherwise the raw DER data are returned.
334  *
335  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
336  * That is to point in the rndSequence.
337  *
338  * indx specifies which OID to return. Ie 0 means return the first specified
339  * OID found, 1 the second etc.
340  */
341 int
342 _gnutls_x509_parse_dn_oid (ASN1_TYPE asn1_struct,
343                            const char *asn1_rdn_name,
344                            const char *given_oid, int indx,
345                            unsigned int raw_flag,
346                            void *buf, size_t * sizeof_buf)
347 {
348   int k2, k1, result;
349   char tmpbuffer1[ASN1_MAX_NAME_SIZE];
350   char tmpbuffer2[ASN1_MAX_NAME_SIZE];
351   char tmpbuffer3[ASN1_MAX_NAME_SIZE];
352   opaque value[256];
353   char oid[MAX_OID_SIZE];
354   int len, printable;
355   int i = 0;
356   char *cbuf = buf;
357
358   if (cbuf == NULL)
359     *sizeof_buf = 0;
360   else
361     cbuf[0] = 0;
362
363   k1 = 0;
364   do
365     {
366
367       k1++;
368       /* create a string like "tbsCertList.issuer.rdnSequence.?1"
369        */
370       if (asn1_rdn_name[0] != 0)
371         snprintf (tmpbuffer1, sizeof (tmpbuffer1), "%s.?%u", asn1_rdn_name,
372                   k1);
373       else
374         snprintf (tmpbuffer1, sizeof (tmpbuffer1), "?%u", k1);
375
376       len = sizeof (value) - 1;
377       result = asn1_read_value (asn1_struct, tmpbuffer1, value, &len);
378
379       if (result == ASN1_ELEMENT_NOT_FOUND)
380         {
381           gnutls_assert ();
382           break;
383         }
384
385       if (result != ASN1_VALUE_NOT_FOUND)
386         {
387           gnutls_assert ();
388           result = _gnutls_asn2err (result);
389           goto cleanup;
390         }
391
392       k2 = 0;
393
394       do
395         {                       /* Move to the attibute type and values
396                                  */
397           k2++;
398
399           if (tmpbuffer1[0] != 0)
400             snprintf (tmpbuffer2, sizeof (tmpbuffer2), "%s.?%u", tmpbuffer1,
401                       k2);
402           else
403             snprintf (tmpbuffer2, sizeof (tmpbuffer2), "?%u", k2);
404
405           /* Try to read the RelativeDistinguishedName attributes.
406            */
407
408           len = sizeof (value) - 1;
409           result = asn1_read_value (asn1_struct, tmpbuffer2, value, &len);
410
411           if (result == ASN1_ELEMENT_NOT_FOUND)
412             {
413               break;
414             }
415           if (result != ASN1_VALUE_NOT_FOUND)
416             {
417               gnutls_assert ();
418               result = _gnutls_asn2err (result);
419               goto cleanup;
420             }
421
422           /* Read the OID 
423            */
424           _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2);
425           _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".type");
426
427           len = sizeof (oid) - 1;
428           result = asn1_read_value (asn1_struct, tmpbuffer3, oid, &len);
429
430           if (result == ASN1_ELEMENT_NOT_FOUND)
431             break;
432           else if (result != ASN1_SUCCESS)
433             {
434               gnutls_assert ();
435               result = _gnutls_asn2err (result);
436               goto cleanup;
437             }
438
439           if (strcmp (oid, given_oid) == 0 && indx == i++)
440             {                   /* Found the OID */
441
442               /* Read the Value 
443                */
444               _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2);
445               _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".value");
446
447               len = *sizeof_buf;
448               result = asn1_read_value (asn1_struct, tmpbuffer3, buf, &len);
449
450               if (result != ASN1_SUCCESS)
451                 {
452                   gnutls_assert ();
453                   if (result == ASN1_MEM_ERROR)
454                     *sizeof_buf = len;
455                   result = _gnutls_asn2err (result);
456                   goto cleanup;
457                 }
458
459               if (raw_flag != 0)
460                 {
461                   if ((unsigned) len > *sizeof_buf)
462                     {
463                       *sizeof_buf = len;
464                       result = GNUTLS_E_SHORT_MEMORY_BUFFER;
465                       goto cleanup;
466                     }
467                   *sizeof_buf = len;
468
469                   return 0;
470
471                 }
472               else
473                 {               /* parse data. raw_flag == 0 */
474                   printable = _gnutls_x509_oid_data_printable (oid);
475
476                   if (printable == 1)
477                     result =
478                       _gnutls_x509_oid_data2string (oid, buf, len,
479                                                     cbuf, sizeof_buf);
480                   else
481                     result =
482                       _gnutls_x509_data2hex (buf, len, cbuf, sizeof_buf);
483
484                   if (result < 0)
485                     {
486                       gnutls_assert ();
487                       goto cleanup;
488                     }
489
490                   return 0;
491
492                 }               /* raw_flag == 0 */
493             }
494         }
495       while (1);
496
497     }
498   while (1);
499
500   gnutls_assert ();
501
502   result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
503
504 cleanup:
505   return result;
506 }
507
508
509 /* Parses an X509 DN in the asn1_struct, and returns the requested
510  * DN OID.
511  *
512  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
513  * That is to point in the rndSequence.
514  *
515  * indx specifies which OID to return. Ie 0 means return the first specified
516  * OID found, 1 the second etc.
517  */
518 int
519 _gnutls_x509_get_dn_oid (ASN1_TYPE asn1_struct,
520                          const char *asn1_rdn_name,
521                          int indx, void *_oid, size_t * sizeof_oid)
522 {
523   int k2, k1, result;
524   char tmpbuffer1[ASN1_MAX_NAME_SIZE];
525   char tmpbuffer2[ASN1_MAX_NAME_SIZE];
526   char tmpbuffer3[ASN1_MAX_NAME_SIZE];
527   char value[256];
528   char oid[MAX_OID_SIZE];
529   int len;
530   int i = 0;
531
532   k1 = 0;
533   do
534     {
535
536       k1++;
537       /* create a string like "tbsCertList.issuer.rdnSequence.?1"
538        */
539       if (asn1_rdn_name[0] != 0)
540         snprintf (tmpbuffer1, sizeof (tmpbuffer1), "%s.?%u", asn1_rdn_name,
541                   k1);
542       else
543         snprintf (tmpbuffer1, sizeof (tmpbuffer1), "?%u", k1);
544
545       len = sizeof (value) - 1;
546       result = asn1_read_value (asn1_struct, tmpbuffer1, value, &len);
547
548       if (result == ASN1_ELEMENT_NOT_FOUND)
549         {
550           gnutls_assert ();
551           break;
552         }
553
554       if (result != ASN1_VALUE_NOT_FOUND)
555         {
556           gnutls_assert ();
557           result = _gnutls_asn2err (result);
558           goto cleanup;
559         }
560
561       k2 = 0;
562
563       do
564         {                       /* Move to the attibute type and values
565                                  */
566           k2++;
567
568           if (tmpbuffer1[0] != 0)
569             snprintf (tmpbuffer2, sizeof (tmpbuffer2), "%s.?%u", tmpbuffer1,
570                       k2);
571           else
572             snprintf (tmpbuffer2, sizeof (tmpbuffer2), "?%u", k2);
573
574           /* Try to read the RelativeDistinguishedName attributes.
575            */
576
577           len = sizeof (value) - 1;
578           result = asn1_read_value (asn1_struct, tmpbuffer2, value, &len);
579
580           if (result == ASN1_ELEMENT_NOT_FOUND)
581             {
582               break;
583             }
584           if (result != ASN1_VALUE_NOT_FOUND)
585             {
586               gnutls_assert ();
587               result = _gnutls_asn2err (result);
588               goto cleanup;
589             }
590
591           /* Read the OID 
592            */
593           _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2);
594           _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".type");
595
596           len = sizeof (oid) - 1;
597           result = asn1_read_value (asn1_struct, tmpbuffer3, oid, &len);
598
599           if (result == ASN1_ELEMENT_NOT_FOUND)
600             break;
601           else if (result != ASN1_SUCCESS)
602             {
603               gnutls_assert ();
604               result = _gnutls_asn2err (result);
605               goto cleanup;
606             }
607
608           if (indx == i++)
609             {                   /* Found the OID */
610
611               len = strlen (oid) + 1;
612
613               if (*sizeof_oid < (unsigned) len)
614                 {
615                   *sizeof_oid = len;
616                   gnutls_assert ();
617                   return GNUTLS_E_SHORT_MEMORY_BUFFER;
618                 }
619
620               memcpy (_oid, oid, len);
621               *sizeof_oid = len - 1;
622
623               return 0;
624             }
625         }
626       while (1);
627
628     }
629   while (1);
630
631   gnutls_assert ();
632
633   result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
634
635 cleanup:
636   return result;
637 }
638
639 /* This will encode and write the AttributeTypeAndValue field.
640  * 'multi' must be zero if writing an AttributeTypeAndValue, and 1 if Attribute.
641  * In all cases only one value is written.
642  */
643 int
644 _gnutls_x509_encode_and_write_attribute (const char *given_oid,
645                                          ASN1_TYPE asn1_struct,
646                                          const char *where,
647                                          const void *_data,
648                                          int sizeof_data, int multi)
649 {
650   const char *val_name;
651   const opaque *data = _data;
652   char tmp[128];
653   ASN1_TYPE c2;
654   int result;
655
656
657   /* Find how to encode the data.
658    */
659   val_name = _gnutls_x509_oid2asn_string (given_oid);
660   if (val_name == NULL)
661     {
662       gnutls_assert ();
663       _gnutls_x509_log ("Cannot find OID: %s\n", given_oid);
664       return GNUTLS_E_X509_UNSUPPORTED_OID;
665     }
666
667   result = asn1_create_element (_gnutls_get_pkix (), val_name, &c2);
668   if (result != ASN1_SUCCESS)
669     {
670       gnutls_assert ();
671       return _gnutls_asn2err (result);
672     }
673
674   tmp[0] = 0;
675
676   if ((result = _gnutls_x509_oid_data_choice (given_oid)) > 0)
677     {
678       const char *string_type;
679       int i;
680
681       string_type = "printableString";
682
683       /* Check if the data is plain ascii, and use
684        * the UTF8 string type if not.
685        */
686       for (i = 0; i < sizeof_data; i++)
687         {
688           if (!isascii (data[i]))
689             {
690               string_type = "utf8String";
691               break;
692             }
693         }
694
695       /* if the type is a CHOICE then write the
696        * type we'll use.
697        */
698       result = asn1_write_value (c2, "", string_type, 1);
699       if (result != ASN1_SUCCESS)
700         {
701           gnutls_assert ();
702           result = _gnutls_asn2err (result);
703           goto error;
704         }
705
706       _gnutls_str_cpy (tmp, sizeof (tmp), string_type);
707     }
708
709   result = asn1_write_value (c2, tmp, data, sizeof_data);
710   if (result != ASN1_SUCCESS)
711     {
712       gnutls_assert ();
713       result = _gnutls_asn2err (result);
714       goto error;
715     }
716
717
718   /* write the data (value)
719    */
720
721   _gnutls_str_cpy (tmp, sizeof (tmp), where);
722   _gnutls_str_cat (tmp, sizeof (tmp), ".value");
723
724   if (multi != 0)
725     {                           /* if not writing an AttributeTypeAndValue, but an Attribute */
726       _gnutls_str_cat (tmp, sizeof (tmp), "s"); /* values */
727
728       result = asn1_write_value (asn1_struct, tmp, "NEW", 1);
729       if (result != ASN1_SUCCESS)
730         {
731           gnutls_assert ();
732           result = _gnutls_asn2err (result);
733           goto error;
734         }
735
736       _gnutls_str_cat (tmp, sizeof (tmp), ".?LAST");
737
738     }
739
740   result = _gnutls_x509_der_encode_and_copy (c2, "", asn1_struct, tmp, 0);
741   if (result < 0)
742     {
743       gnutls_assert ();
744       result = _gnutls_asn2err (result);
745       goto error;
746     }
747
748   /* write the type
749    */
750   _gnutls_str_cpy (tmp, sizeof (tmp), where);
751   _gnutls_str_cat (tmp, sizeof (tmp), ".type");
752
753   result = asn1_write_value (asn1_struct, tmp, given_oid, 1);
754   if (result != ASN1_SUCCESS)
755     {
756       gnutls_assert ();
757       result = _gnutls_asn2err (result);
758       goto error;
759     }
760
761   result = 0;
762
763 error:
764   asn1_delete_structure (&c2);
765   return result;
766 }
767
768 /* This will write the AttributeTypeAndValue field. The data must be already DER encoded.
769  * 'multi' must be zero if writing an AttributeTypeAndValue, and 1 if Attribute.
770  * In all cases only one value is written.
771  */
772 static int
773 _gnutls_x509_write_attribute (const char *given_oid,
774                               ASN1_TYPE asn1_struct, const char *where,
775                               const void *_data, int sizeof_data)
776 {
777   char tmp[128];
778   int result;
779
780   /* write the data (value)
781    */
782
783   _gnutls_str_cpy (tmp, sizeof (tmp), where);
784   _gnutls_str_cat (tmp, sizeof (tmp), ".value");
785
786   result = asn1_write_value (asn1_struct, tmp, _data, sizeof_data);
787   if (result < 0)
788     {
789       gnutls_assert ();
790       return _gnutls_asn2err (result);
791     }
792
793   /* write the type
794    */
795   _gnutls_str_cpy (tmp, sizeof (tmp), where);
796   _gnutls_str_cat (tmp, sizeof (tmp), ".type");
797
798   result = asn1_write_value (asn1_struct, tmp, given_oid, 1);
799   if (result != ASN1_SUCCESS)
800     {
801       gnutls_assert ();
802       return _gnutls_asn2err (result);
803     }
804
805   return 0;
806 }
807
808
809 /* Decodes an X.509 Attribute (if multi==1) or an AttributeTypeAndValue
810  * otherwise.
811  *
812  * octet_string should be non zero if we are to decode octet strings after
813  * decoding.
814  *
815  * The output is allocated and stored in value.
816  */
817 int
818 _gnutls_x509_decode_and_read_attribute (ASN1_TYPE asn1_struct,
819                                         const char *where, char *oid,
820                                         int oid_size, gnutls_datum_t * value,
821                                         int multi, int octet_string)
822 {
823   char tmpbuffer[128];
824   int len, result;
825
826   /* Read the OID 
827    */
828   _gnutls_str_cpy (tmpbuffer, sizeof (tmpbuffer), where);
829   _gnutls_str_cat (tmpbuffer, sizeof (tmpbuffer), ".type");
830
831   len = oid_size - 1;
832   result = asn1_read_value (asn1_struct, tmpbuffer, oid, &len);
833
834   if (result != ASN1_SUCCESS)
835     {
836       gnutls_assert ();
837       result = _gnutls_asn2err (result);
838       return result;
839     }
840
841   /* Read the Value 
842    */
843
844   _gnutls_str_cpy (tmpbuffer, sizeof (tmpbuffer), where);
845   _gnutls_str_cat (tmpbuffer, sizeof (tmpbuffer), ".value");
846
847   if (multi)
848     _gnutls_str_cat (tmpbuffer, sizeof (tmpbuffer), "s.?1");    /* .values.?1 */
849
850   result =
851     _gnutls_x509_read_value (asn1_struct, tmpbuffer, value, octet_string);
852   if (result < 0)
853     {
854       gnutls_assert ();
855       return result;
856     }
857
858   return 0;
859
860 }
861
862 /* Sets an X509 DN in the asn1_struct, and puts the given OID in the DN.
863  * The input is assumed to be raw data.
864  *
865  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer".
866  * That is to point before the rndSequence.
867  *
868  */
869 int
870 _gnutls_x509_set_dn_oid (ASN1_TYPE asn1_struct,
871                          const char *asn1_name, const char *given_oid,
872                          int raw_flag, const char *name, int sizeof_name)
873 {
874   int result;
875   char tmp[ASN1_MAX_NAME_SIZE], asn1_rdn_name[ASN1_MAX_NAME_SIZE];
876
877   if (sizeof_name == 0 || name == NULL)
878     {
879       gnutls_assert ();
880       return GNUTLS_E_INVALID_REQUEST;
881     }
882
883   /* create the rdnSequence
884    */
885   result = asn1_write_value (asn1_struct, asn1_name, "rdnSequence", 1);
886   if (result != ASN1_SUCCESS)
887     {
888       gnutls_assert ();
889       return _gnutls_asn2err (result);
890     }
891
892   _gnutls_str_cpy (asn1_rdn_name, sizeof (asn1_rdn_name), asn1_name);
893   _gnutls_str_cat (asn1_rdn_name, sizeof (asn1_rdn_name), ".rdnSequence");
894
895   /* create a new element 
896    */
897   result = asn1_write_value (asn1_struct, asn1_rdn_name, "NEW", 1);
898   if (result != ASN1_SUCCESS)
899     {
900       gnutls_assert ();
901       return _gnutls_asn2err (result);
902     }
903
904   _gnutls_str_cpy (tmp, sizeof (tmp), asn1_rdn_name);
905   _gnutls_str_cat (tmp, sizeof (tmp), ".?LAST");
906
907   /* create the set with only one element
908    */
909   result = asn1_write_value (asn1_struct, tmp, "NEW", 1);
910   if (result != ASN1_SUCCESS)
911     {
912       gnutls_assert ();
913       return _gnutls_asn2err (result);
914     }
915
916
917   /* Encode and write the data
918    */
919   _gnutls_str_cpy (tmp, sizeof (tmp), asn1_rdn_name);
920   _gnutls_str_cat (tmp, sizeof (tmp), ".?LAST.?LAST");
921
922   if (!raw_flag)
923     {
924       result =
925         _gnutls_x509_encode_and_write_attribute (given_oid,
926                                                  asn1_struct,
927                                                  tmp, name, sizeof_name, 0);
928     }
929   else
930     {
931       result =
932         _gnutls_x509_write_attribute (given_oid, asn1_struct,
933                                       tmp, name, sizeof_name);
934     }
935
936   if (result < 0)
937     {
938       gnutls_assert ();
939       return result;
940     }
941
942   return 0;
943 }
944
945 /**
946  * gnutls_x509_dn_init:
947  * @dn: the object to be initialized
948  *
949  * This function initializes a #gnutls_x509_dn_t structure.
950  *
951  * The object returned must be deallocated using
952  * gnutls_x509_dn_deinit().
953  *
954  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
955  *   negative error value.
956  *
957  * Since: 2.4.0
958  **/
959 int
960 gnutls_x509_dn_init (gnutls_x509_dn_t * dn)
961 {
962   int result;
963   ASN1_TYPE tmpdn = ASN1_TYPE_EMPTY;
964
965   if ((result =
966        asn1_create_element (_gnutls_get_pkix (),
967                             "PKIX1.Name", &tmpdn)) != ASN1_SUCCESS)
968     {
969       gnutls_assert ();
970       return _gnutls_asn2err (result);
971     }
972
973   *dn = tmpdn;
974
975   return 0;
976 }
977
978 /**
979  * gnutls_x509_dn_import:
980  * @dn: the structure that will hold the imported DN
981  * @data: should contain a DER encoded RDN sequence
982  *
983  * This function parses an RDN sequence and stores the result to a
984  * #gnutls_x509_dn_t structure. The structure must have been initialized
985  * with gnutls_x509_dn_init(). You may use gnutls_x509_dn_get_rdn_ava() to
986  * decode the DN.
987  *
988  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
989  *   negative error value.
990  *
991  * Since: 2.4.0
992  **/
993 int
994 gnutls_x509_dn_import (gnutls_x509_dn_t dn, const gnutls_datum_t * data)
995 {
996   int result;
997   char err[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
998
999   result = asn1_der_decoding ((ASN1_TYPE *) & dn,
1000                               data->data, data->size, err);
1001   if (result != ASN1_SUCCESS)
1002     {
1003       /* couldn't decode DER */
1004       _gnutls_x509_log ("ASN.1 Decoding error: %s\n", err);
1005       gnutls_assert ();
1006       return _gnutls_asn2err (result);
1007     }
1008
1009   return 0;
1010 }
1011
1012 /**
1013  * gnutls_x509_dn_deinit:
1014  * @dn: a DN opaque object pointer.
1015  *
1016  * This function deallocates the DN object as returned by
1017  * gnutls_x509_dn_import().
1018  *
1019  * Since: 2.4.0
1020  **/
1021 void
1022 gnutls_x509_dn_deinit (gnutls_x509_dn_t dn)
1023 {
1024   asn1_delete_structure ((ASN1_TYPE *) & dn);
1025 }
1026
1027 /**
1028  * gnutls_x509_rdn_get:
1029  * @idn: should contain a DER encoded RDN sequence
1030  * @buf: a pointer to a structure to hold the peer's name
1031  * @sizeof_buf: holds the size of @buf
1032  *
1033  * This function will return the name of the given RDN sequence.  The
1034  * name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in
1035  * RFC2253.
1036  *
1037  * Returns: On success, %GNUTLS_E_SUCCESS is returned, or
1038  * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@sizeof_buf is
1039  * updated if the provided buffer is not long enough, otherwise a
1040  * negative error value.
1041  **/
1042 int
1043 gnutls_x509_rdn_get (const gnutls_datum_t * idn,
1044                      char *buf, size_t * sizeof_buf)
1045 {
1046   int result;
1047   ASN1_TYPE dn = ASN1_TYPE_EMPTY;
1048
1049   if (sizeof_buf == 0)
1050     {
1051       gnutls_assert ();
1052       return GNUTLS_E_INVALID_REQUEST;
1053     }
1054
1055   if (buf)
1056     buf[0] = 0;
1057
1058
1059   if ((result =
1060        asn1_create_element (_gnutls_get_pkix (),
1061                             "PKIX1.Name", &dn)) != ASN1_SUCCESS)
1062     {
1063       gnutls_assert ();
1064       return _gnutls_asn2err (result);
1065     }
1066
1067   result = asn1_der_decoding (&dn, idn->data, idn->size, NULL);
1068   if (result != ASN1_SUCCESS)
1069     {
1070       /* couldn't decode DER */
1071       gnutls_assert ();
1072       asn1_delete_structure (&dn);
1073       return _gnutls_asn2err (result);
1074     }
1075
1076   result = _gnutls_x509_parse_dn (dn, "rdnSequence", buf, sizeof_buf);
1077
1078   asn1_delete_structure (&dn);
1079   return result;
1080
1081 }
1082
1083 /**
1084  * gnutls_x509_rdn_get_by_oid:
1085  * @idn: should contain a DER encoded RDN sequence
1086  * @oid: an Object Identifier
1087  * @indx: In case multiple same OIDs exist in the RDN indicates which
1088  *   to send. Use 0 for the first one.
1089  * @raw_flag: If non zero then the raw DER data are returned.
1090  * @buf: a pointer to a structure to hold the peer's name
1091  * @sizeof_buf: holds the size of @buf
1092  *
1093  * This function will return the name of the given Object identifier,
1094  * of the RDN sequence.  The name will be encoded using the rules
1095  * from RFC2253.
1096  *
1097  * Returns: On success, %GNUTLS_E_SUCCESS is returned, or
1098  * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@sizeof_buf is
1099  * updated if the provided buffer is not long enough, otherwise a
1100  * negative error value.
1101  **/
1102 int
1103 gnutls_x509_rdn_get_by_oid (const gnutls_datum_t * idn, const char *oid,
1104                             int indx, unsigned int raw_flag,
1105                             void *buf, size_t * sizeof_buf)
1106 {
1107   int result;
1108   ASN1_TYPE dn = ASN1_TYPE_EMPTY;
1109
1110   if (sizeof_buf == 0)
1111     {
1112       return GNUTLS_E_INVALID_REQUEST;
1113     }
1114
1115   if ((result =
1116        asn1_create_element (_gnutls_get_pkix (),
1117                             "PKIX1.Name", &dn)) != ASN1_SUCCESS)
1118     {
1119       gnutls_assert ();
1120       return _gnutls_asn2err (result);
1121     }
1122
1123   result = asn1_der_decoding (&dn, idn->data, idn->size, NULL);
1124   if (result != ASN1_SUCCESS)
1125     {
1126       /* couldn't decode DER */
1127       gnutls_assert ();
1128       asn1_delete_structure (&dn);
1129       return _gnutls_asn2err (result);
1130     }
1131
1132   result =
1133     _gnutls_x509_parse_dn_oid (dn, "rdnSequence", oid, indx,
1134                                raw_flag, buf, sizeof_buf);
1135
1136   asn1_delete_structure (&dn);
1137   return result;
1138
1139 }
1140
1141 /**
1142  * gnutls_x509_rdn_get_oid:
1143  * @idn: should contain a DER encoded RDN sequence
1144  * @indx: Indicates which OID to return. Use 0 for the first one.
1145  * @buf: a pointer to a structure to hold the peer's name OID
1146  * @sizeof_buf: holds the size of @buf
1147  *
1148  * This function will return the specified Object identifier, of the
1149  * RDN sequence.
1150  *
1151  * Returns: On success, %GNUTLS_E_SUCCESS is returned, or
1152  * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@sizeof_buf is
1153  * updated if the provided buffer is not long enough, otherwise a
1154  * negative error value.
1155  *
1156  * Since: 2.4.0
1157  **/
1158 int
1159 gnutls_x509_rdn_get_oid (const gnutls_datum_t * idn,
1160                          int indx, void *buf, size_t * sizeof_buf)
1161 {
1162   int result;
1163   ASN1_TYPE dn = ASN1_TYPE_EMPTY;
1164
1165   if (sizeof_buf == 0)
1166     {
1167       return GNUTLS_E_INVALID_REQUEST;
1168     }
1169
1170   if ((result =
1171        asn1_create_element (_gnutls_get_pkix (),
1172                             "PKIX1.Name", &dn)) != ASN1_SUCCESS)
1173     {
1174       gnutls_assert ();
1175       return _gnutls_asn2err (result);
1176     }
1177
1178   result = asn1_der_decoding (&dn, idn->data, idn->size, NULL);
1179   if (result != ASN1_SUCCESS)
1180     {
1181       /* couldn't decode DER */
1182       gnutls_assert ();
1183       asn1_delete_structure (&dn);
1184       return _gnutls_asn2err (result);
1185     }
1186
1187   result = _gnutls_x509_get_dn_oid (dn, "rdnSequence", indx, buf, sizeof_buf);
1188
1189   asn1_delete_structure (&dn);
1190   return result;
1191
1192 }
1193
1194 /*
1195  * Compares the DER encoded part of a DN.
1196  *
1197  * FIXME: use a real DN comparison algorithm.
1198  *
1199  * Returns 1 if the DN's match and zero if they don't match. Otherwise
1200  * a negative value is returned to indicate error.
1201  */
1202 int
1203 _gnutls_x509_compare_raw_dn (const gnutls_datum_t * dn1,
1204                              const gnutls_datum_t * dn2)
1205 {
1206
1207   if (dn1->size != dn2->size)
1208     {
1209       gnutls_assert ();
1210       return 0;
1211     }
1212   if (memcmp (dn1->data, dn2->data, dn2->size) != 0)
1213     {
1214       gnutls_assert ();
1215       return 0;
1216     }
1217   return 1;                     /* they match */
1218 }
1219
1220 /**
1221  * gnutls_x509_dn_export:
1222  * @dn: Holds the opaque DN object
1223  * @format: the format of output params. One of PEM or DER.
1224  * @output_data: will contain a DN PEM or DER encoded
1225  * @output_data_size: holds the size of output_data (and will be
1226  *   replaced by the actual size of parameters)
1227  *
1228  * This function will export the DN to DER or PEM format.
1229  *
1230  * If the buffer provided is not long enough to hold the output, then
1231  * *@output_data_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER
1232  * will be returned.
1233  *
1234  * If the structure is PEM encoded, it will have a header
1235  * of "BEGIN NAME".
1236  *
1237  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
1238  *   negative error value.
1239  **/
1240 int
1241 gnutls_x509_dn_export (gnutls_x509_dn_t dn,
1242                        gnutls_x509_crt_fmt_t format, void *output_data,
1243                        size_t * output_data_size)
1244 {
1245   ASN1_TYPE asn1 = dn;
1246
1247   if (asn1 == NULL)
1248     {
1249       gnutls_assert ();
1250       return GNUTLS_E_INVALID_REQUEST;
1251     }
1252
1253   return _gnutls_x509_export_int_named (asn1, "rdnSequence",
1254                                         format, "NAME",
1255                                         output_data, output_data_size);
1256 }