322ca8e87b0b5f2416a5ee5cabfc46b83812786d
[libksba.git] / src / keyinfo.c
1 /* keyinfo.c - Parse and build a keyInfo structure
2  *      Copyright (C) 2001 g10 Code GmbH
3  *
4  * This file is part of KSBA.
5  *
6  * KSBA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * KSBA is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 /* Instead of using the ASN parser - which is easily possible - we use
22    a simple handcoded one to speed the oepration up and make it more
23    robust. */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #include "util.h"
32 #include "asn1-func.h"
33
34 #include "shared.h"
35
36 struct algo_table_s {
37   const unsigned char *oid;  /* NULL indicattes end of table */
38   int                  oidlen;
39   int supported;
40   const char *algo_string;
41   const char *elem_string; /* parameter name or '-' */
42   const char *ctrl_string; /* expected tag values (value > 127 are raw data)*/
43   int digest_algo;
44 };
45
46 static struct algo_table_s pk_algo_table[] = {
47   { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.1 */
48     /* 1.2.840.113549.1.1.1  rsaEncryption (RSAES-PKCA1-v1.5) */ 
49     "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01", 9, 
50     1, "rsa", "-ne", "\x30\x02\x02" },
51   { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.7 */
52     /* 1.2.840.113549.1.1.7  RSAES-OAEP */ 
53     "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x07", 9, 
54     0, "rsa", "-ne", "\x30\x02\x02"}, /* (patent problems) */
55   { /* */
56     /* 2.5.8.1.1 rsa (ambiguous due to missing padding rules)*/
57     "\x55\x08\x01\x01", 4, 
58     1, "ambiguous-rsa", "-ne", "\x30\x02\x02" },
59   { /* iso.member-body.us.x9-57.x9cm.1 */
60     /* 1.2.840.10040.4.1  dsa */
61     "\x2a\x86\x48\xce\x38\x04\x01", 7, 
62     1, "dsa"  "y", "\x02" }, 
63   /* FIXME: Need code to extract p,q,g from the parameters */
64
65   {NULL}
66 };
67
68
69 static struct algo_table_s sig_algo_table[] = {
70   {  /* iso.member-body.us.rsadsi.pkcs.pkcs-1.5 */
71     /* 1.2.840.113549.1.1.5  sha1WithRSAEncryption */ 
72     "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05", 9, 
73     1, "rsa", "s", "\x82", GCRY_MD_SHA1 },
74   { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.4 */
75     /* 1.2.840.113549.1.1.4  md5WithRSAEncryption */ 
76     "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04", 9, 
77     1, "rsa", "s", "\x82", GCRY_MD_MD5 },
78   { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.2 */
79     /* 1.2.840.113549.1.1.2  md2WithRSAEncryption */ 
80     "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02", 9, 
81     0, "rsa", "s", "\x82", 0 },
82   { /* iso.member-body.us.x9-57.x9cm.3 */
83     /* 1.2.840.10040.4.3  dsaWithSha1 */
84     "\x2a\x86\x48\xce\x38\x04\x03", 7, 
85     1, "dsa", "-rs", "\x30\x02\x02", GCRY_MD_SHA1 }, 
86
87   {NULL}
88 };
89
90
91 struct stringbuf {
92   size_t len;
93   size_t size;
94   char *buf;
95   int out_of_core;
96 };
97
98
99 #define TLV_LENGTH() do {         \
100   if (!derlen)                    \
101     return KSBA_Invalid_Keyinfo;  \
102   c = *der++; derlen--;           \
103   if (c == 0x80)                  \
104     return KSBA_Not_DER_Encoded;  \
105   if (c == 0xff)                  \
106     return KSBA_BER_Error;        \
107                                   \
108   if ( !(c & 0x80) )              \
109     len = c;                      \
110   else                            \
111     {                             \
112       int count = c & 0x7f;       \
113                                   \
114       for (len=0; count; count--) \
115         {                         \
116           len <<= 8;              \
117           if (!derlen)            \
118             return KSBA_BER_Error;\
119           c = *der++; derlen--;   \
120           len |= c & 0xff;        \
121         }                         \
122     }                             \
123   if (len > derlen)               \
124     return KSBA_Invalid_Keyinfo;  \
125 } while (0)
126
127
128 /* Return the OFF and the LEN of algorithm within DER.  Do some checks
129    and return the number of bytes read in r_nread, adding this to der
130    does point into the BIT STRING
131  */
132 static KsbaError
133 get_algorithm (const unsigned char *der, size_t derlen,
134                size_t *r_nread, size_t *r_pos, size_t *r_len)
135 {
136   int c;
137   const unsigned char *start = der;
138   const unsigned char *startseq;
139   unsigned long seqlen, len;
140
141   /* get the inner sequence */
142   if (!derlen)
143     return KSBA_Invalid_Keyinfo;
144   c = *der++; derlen--;
145   if ( c != 0x30 )
146     return KSBA_Unexpected_Tag; /* not a SEQUENCE */
147   TLV_LENGTH(); 
148   seqlen = len;
149   startseq = der;
150
151   /* get the object identifier */
152   if (!derlen)
153     return KSBA_Invalid_Keyinfo;
154   c = *der++; derlen--; 
155   if ( c != 0x06 )
156     return KSBA_Unexpected_Tag; /* not an OBJECT IDENTIFIER */
157   TLV_LENGTH();
158
159   /* der does now point to an oid of length LEN */
160   *r_pos = der - start;
161   *r_len = len;
162   {
163     char *p = ksba_oid_to_str (der, len);
164     printf ("algorithm: %s\n", p);
165     xfree (p);
166   }
167   der += len;
168   derlen -= len;
169   seqlen -= der - startseq;;
170
171   /* check that the parameter is NULL or not there */
172   if (!seqlen)
173     {
174       printf ("parameter: none\n");
175     }
176   else
177     {
178       const unsigned char *startparm = der;
179
180       if (!derlen)
181         return KSBA_Invalid_Keyinfo;
182       c = *der++; derlen--;
183       if ( c == 0x05 ) 
184         {
185           printf ("parameter: NULL \n"); /* the only correct thing */
186           if (!derlen)
187             return KSBA_Invalid_Keyinfo;
188           c = *der++; derlen--;
189           if (c) 
190             return KSBA_BER_Error;  /* NULL must have a length of 0 */
191           seqlen -= 2;
192         }
193       else
194         {
195           printf ("parameter: with tag %02x - ignored\n", c);
196           TLV_LENGTH();
197           seqlen -= der - startparm;
198           /* skip the value */
199           der += len;
200           derlen -= len;
201           seqlen -= len;
202         }
203     }
204
205   if (seqlen)
206     return KSBA_Invalid_Keyinfo;
207
208   /* move forward to the BIT_STR */
209   if (!derlen)
210     return KSBA_Invalid_Keyinfo;
211   c = *der++; derlen--;
212     
213   if (c != 0x03)
214     return KSBA_Unexpected_Tag; /* not a BIT STRING */
215   TLV_LENGTH();
216
217   /* we are now inside the BIT STRING */
218   printf ("bit string of %lu bytes\n", len);
219
220   *r_nread = der - start;
221
222   return 0;
223 }
224
225
226 static void
227 init_stringbuf (struct stringbuf *sb, int initiallen)
228 {
229   sb->len = 0;
230   sb->size = initiallen;
231   sb->out_of_core = 0;
232   /* allocate one more, so that get_stringbuf can append a nul */
233   sb->buf = xtrymalloc (initiallen+1);
234   if (!sb->buf)
235       sb->out_of_core = 1;
236 }
237
238 static void
239 put_stringbuf (struct stringbuf *sb, const char *text)
240 {
241   size_t n = strlen (text);
242
243   if (sb->out_of_core)
244     return;
245
246   if (sb->len + n >= sb->size)
247     {
248       char *p;
249       
250       sb->size += n + 100;
251       p = xtryrealloc (sb->buf, sb->size);
252       if ( !p)
253         {
254           sb->out_of_core = 1;
255           return;
256         }
257       sb->buf = p;
258     }
259   memcpy (sb->buf+sb->len, text, n);
260   sb->len += n;
261 }
262
263 static char *
264 get_stringbuf (struct stringbuf *sb)
265 {
266   char *p;
267
268   if (sb->out_of_core)
269     {
270       xfree (sb->buf); sb->buf = NULL;
271       return NULL;
272     }
273
274   sb->buf[sb->len] = 0;
275   p = sb->buf;
276   sb->buf = NULL;
277   sb->out_of_core = 1; /* make sure the caller does an init before reuse */
278   return p;
279 }
280
281
282 /* Assume that der is a buffer of length DERLEN with a DER encoded
283  Asn.1 structure like this:
284  
285   keyInfo ::= SEQUENCE {
286                  SEQUENCE { 
287                     algorithm    OBJECT IDENTIFIER,
288                     parameters   ANY DEFINED BY algorithm OPTIONAL }
289                  publicKey  BIT STRING }
290   
291   We only allow parameters == NULL.
292
293   The function parses this structure and create a SEXP suitable to be
294   used as a public key in Libgcrypt.  The S-Exp will be returned in a
295   string which the caller must free.  
296   
297   We don't pass an ASN.1 node here but a plain memory block.  */
298
299 KsbaError
300 _ksba_keyinfo_to_sexp (const unsigned char *der, size_t derlen,
301                        char **r_string)
302 {
303   KsbaError err;
304   int c;
305   size_t nread, off, len;
306   int algoidx;
307   const unsigned char *ctrl;
308   const char *elem;
309   struct stringbuf sb;
310
311   *r_string = NULL;
312
313   /* check the outer sequence */
314   if (!derlen)
315     return KSBA_Invalid_Keyinfo;
316   c = *der++; derlen--;
317   if ( c != 0x30 )
318     return KSBA_Unexpected_Tag; /* not a SEQUENCE */
319   TLV_LENGTH();
320   /* and now the inner part */
321   err = get_algorithm (der, derlen, &nread, &off, &len);
322   if (err)
323     return err;
324   
325   /* look into our table of supported algorithms */
326   for (algoidx=0; pk_algo_table[algoidx].oid; algoidx++)
327     {
328       if ( len == pk_algo_table[algoidx].oidlen
329            && !memcmp (der+off, pk_algo_table[algoidx].oid, len))
330         break;
331     }
332   if (!pk_algo_table[algoidx].oid)
333     return KSBA_Unknown_Algorithm;
334   if (!pk_algo_table[algoidx].supported)
335     return KSBA_Unsupported_Algorithm;
336
337   der += nread;
338   derlen -= nread;
339
340   if (!derlen)
341     return KSBA_Invalid_Keyinfo;
342   c = *der++; derlen--;
343   if (c) 
344     fprintf (stderr, "warning: number of unused bits is not zero\n");
345
346   /* fixme: we should calculate the initial length form the size of the
347      sequence, so that we don't neen a realloc later */
348   init_stringbuf (&sb, 100);
349   put_stringbuf (&sb, "(public-key(");
350   put_stringbuf (&sb, pk_algo_table[algoidx].algo_string);
351
352   /* FIXME: We don't release the stringbuf in case of error
353      better let the macro jump to a label */
354   elem = pk_algo_table[algoidx].elem_string; 
355   ctrl = pk_algo_table[algoidx].ctrl_string; 
356   for (; *elem; ctrl++, elem++)
357     {
358       int is_int;
359
360       if (!derlen)
361         return KSBA_Invalid_Keyinfo;
362       c = *der++; derlen--;
363       if ( c != *ctrl )
364         return KSBA_Unexpected_Tag; /* not the required tag */
365       is_int = c == 0x02;
366       TLV_LENGTH ();
367       if (is_int && *elem != '-')
368         { /* take this integer */
369           char tmp[100];
370           int i, n;
371           
372           strcpy (tmp, "(. #"); 
373           tmp[1] = *elem;
374           put_stringbuf (&sb, tmp);
375           for (i=n=0; n < len; n++)
376             {
377               if (!derlen)
378                 return KSBA_Invalid_Keyinfo;
379               c = *der++; derlen--;
380               sprintf (tmp+2*i, "%02X", c);
381               if ( !(++i%10) )
382                 {
383                   put_stringbuf (&sb, tmp);
384                   i=0;
385                 }
386             }
387           if (i)
388             put_stringbuf (&sb, tmp);
389           put_stringbuf (&sb, "#)");
390         }
391     }
392   put_stringbuf (&sb, "))");
393   
394   *r_string = get_stringbuf (&sb);
395   if (!*r_string)
396     return KSBA_Out_Of_Core;
397
398   return 0;
399 }
400
401
402 /* Assume that der is a buffer of length DERLEN with a DER encoded
403  Asn.1 structure like this:
404  
405      SEQUENCE { 
406         algorithm    OBJECT IDENTIFIER,
407         parameters   ANY DEFINED BY algorithm OPTIONAL }
408      signature  BIT STRING 
409   
410   We only allow parameters == NULL.
411
412   The function parses this structure and creates a S-Exp suitable to be
413   used as signature value in Libgcrypt:
414   
415   (sig-val
416     (<algo>
417       (<param_name1> <mpi>)
418       ...
419       (<param_namen> <mpi>)
420     ))
421
422  The S-Exp will be returned in a string which the caller must free.
423  We don't pass an ASN.1 node here but a plain memory block.  */
424 KsbaError
425 _ksba_sigval_to_sexp (const unsigned char *der, size_t derlen,
426                        char **r_string)
427 {
428   KsbaError err;
429   int c;
430   size_t nread, off, len;
431   int algoidx;
432   const unsigned char *ctrl;
433   const char *elem;
434   struct stringbuf sb;
435
436   /* FIXME: The entire function is very similar to keyinfo_to_sexp */
437
438   *r_string = NULL;
439
440   err = get_algorithm (der, derlen, &nread, &off, &len);
441   if (err)
442     return err;
443   
444   /* look into our table of supported algorithms */
445   for (algoidx=0; sig_algo_table[algoidx].oid; algoidx++)
446     {
447       if ( len == sig_algo_table[algoidx].oidlen
448            && !memcmp (der+off, sig_algo_table[algoidx].oid, len))
449         break;
450     }
451   if (!sig_algo_table[algoidx].oid)
452     return KSBA_Unknown_Algorithm;
453   if (!sig_algo_table[algoidx].supported)
454     return KSBA_Unsupported_Algorithm;
455
456   der += nread;
457   derlen -= nread;
458
459   if (!derlen)
460     return KSBA_Invalid_Keyinfo;
461   c = *der++; derlen--;
462   if (c) 
463     fprintf (stderr, "warning: number of unused bits is not zero\n");
464
465   /* fixme: we should calculate the initial length form the size of the
466      sequence, so that we don't neen a realloc later */
467   init_stringbuf (&sb, 100);
468   put_stringbuf (&sb, "(sig-val(");
469   put_stringbuf (&sb, sig_algo_table[algoidx].algo_string);
470
471   /* FIXME: We don't release the stringbuf in case of error
472      better let the macro jump to a label */
473   elem = sig_algo_table[algoidx].elem_string; 
474   ctrl = sig_algo_table[algoidx].ctrl_string; 
475   for (; *elem; ctrl++, elem++)
476     {
477       int is_int;
478
479       if ( (*ctrl & 0x80) && !elem[1] )
480         {  /* Hack to allow a raw value */
481           is_int = 1;
482           len = derlen;
483         }
484       else
485         {
486           if (!derlen)
487             return KSBA_Invalid_Keyinfo;
488           c = *der++; derlen--;
489           if ( c != *ctrl )
490             return KSBA_Unexpected_Tag; /* not the required tag */
491           is_int = c == 0x02;
492           TLV_LENGTH ();
493         }
494       if (is_int && *elem != '-')
495         { /* take this integer */
496           char tmp[100];
497           int i, n;
498           
499           strcpy (tmp, "(. #"); 
500           tmp[1] = *elem;
501           put_stringbuf (&sb, tmp);
502           for (i=n=0; n < len; n++)
503             {
504               if (!derlen)
505                 return KSBA_Invalid_Keyinfo;
506               c = *der++; derlen--;
507               sprintf (tmp+2*i, "%02X", c);
508               if ( !(++i%10) )
509                 {
510                   put_stringbuf (&sb, tmp);
511                   i=0;
512                 }
513             }
514           if (i)
515             put_stringbuf (&sb, tmp);
516           put_stringbuf (&sb, "#)");
517         }
518     }
519   put_stringbuf (&sb, "))");
520   
521   *r_string = get_stringbuf (&sb);
522   if (!*r_string)
523     return KSBA_Out_Of_Core;
524
525   return 0;
526 }
527
528
529 /* Take the OID at the given node and map it to a libgcrypt digest algo.
530    Return 0 if the algo is unknown, -1 for an invalid OID 
531    
532    Fixme: This function belongs to another file, but as long as we
533    don't have a generic OID registry we put it here.  */
534 int
535 _ksba_map_oid_to_digest_algo (const unsigned char *image, AsnNode node) 
536 {
537   int algoidx;
538   int off, len;
539
540   if (!node || node->type != TYPE_OBJECT_ID || node->off == -1)
541     return -1;
542
543   off = node->off + node->nhdr;
544   len = node->len;
545   for (algoidx=0; sig_algo_table[algoidx].oid; algoidx++)
546     {
547       if ( len == sig_algo_table[algoidx].oidlen
548            && !memcmp (image + off, sig_algo_table[algoidx].oid, len))
549         break;
550     }
551   if (!sig_algo_table[algoidx].oid)
552     return 0;
553
554   return sig_algo_table[algoidx].digest_algo;
555 }
556