* test-9.il: New test, test instaniating a class
[mono.git] / mono / metadata / monosn.c
1 /*
2  * monosn.c: Mono String Name Utility
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  *
9  */
10 #include <mono/metadata/class.h>
11 #include <mono/metadata/debug-helpers.h>
12 #include <mono/metadata/tokentype.h>
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/assembly.h>
15 #include "mono/utils/mono-digest.h"
16 /* trim headers */
17
18 #include <string.h>
19 #include <ctype.h>
20
21 #define RSA1_MAGIC     0x32415351
22 #define RSA2_MAGIC     0x32415352
23 #define PRIVKEY_MAGIC  0x00000207
24 #define PUBKEY_MAGIC   0x00008004
25
26 typedef struct {
27         guchar type, version;
28         guint16 reserved1;
29         guint32 algid;
30 } MonoKeyHeader;
31
32 typedef struct {
33         MonoKeyHeader header;
34         guint32 bitlen;
35         guint32 exponent;
36         guchar  modulus [MONO_ZERO_LEN_ARRAY];
37 } MonoRSAPubHeader;
38
39 static void
40 print_data (const char *data, int len)
41 {
42         int i;
43         for (i = 0; i < len; ++i) {
44                 if (i && !(i % 32))
45                         printf ("\n");
46                 printf ("%02x", data [i] & 0xff);
47         }
48         printf ("\n");
49 }
50
51 static int
52 show_token (const char *file, int is_assembly, int show_pubkey) {
53         char token [20];
54         if (!is_assembly) {
55                 char *pubkey;
56                 gsize len;
57                 if (!g_file_get_contents (file, &pubkey, &len, NULL)) {
58                         printf ("Cannot load file: %s\n", file);
59                         return 2;
60                 }
61                 mono_digest_get_public_token (token, pubkey, len);
62                 if (show_pubkey) {
63                         printf ("Public key is\n");
64                         print_data (pubkey, len);
65                 }
66                 g_free (pubkey);
67         } else {
68                 MonoImage *image;
69                 const char *pubkey;
70                 guint32 len;
71                 image = mono_image_open (file, NULL);
72                 if (!image) {
73                         printf ("Cannot open image file: %s\n", file);
74                         return 2;
75                 }
76                 pubkey = mono_image_get_public_key (image, &len);
77                 if (!pubkey) {
78                         printf ("%s does not represent a strongly named assembly\n", image->name);
79                         mono_image_close (image);
80                         return 2;
81                 }
82                 if (show_pubkey) {
83                         printf ("Public key is\n");
84                         print_data (pubkey, len);
85                 }
86                 mono_digest_get_public_token (token, pubkey, len);
87                 mono_image_close (image);
88         }
89         printf ("Public key token is ");
90         print_data (token, 8);
91         return 0;
92 }
93
94 static int
95 extract_data_to_file (int pubk, const char *assembly, const char *outfile) {
96         MonoImage *image;
97         FILE *file;
98         const char *pubkey;
99         guint32 len;
100         
101         image = mono_image_open (assembly, NULL);
102         if (!image) {
103                 printf ("Cannot open image file: %s\n", assembly);
104                 return 2;
105         }
106         if (pubk)
107                 pubkey = mono_image_get_public_key (image, &len);
108         else
109                 pubkey = mono_image_get_strong_name (image, &len);
110         if (!pubkey) {
111                 printf ("%s does not represent a strongly named assembly\n", image->name);
112                 mono_image_close (image);
113                 return 2;
114         }
115         if (!(file = fopen (outfile, "wb"))) {
116                 printf ("Cannot open output file: %s\n", outfile);
117                 return 2;
118         }
119         fwrite (pubkey, len, 1, file);
120         fclose (file);
121         mono_image_close (image);
122         return 0;
123 }
124
125 const static guint8 asciitable [128] = {
126         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
127         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
128         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
129         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
131         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
133         0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
134         0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
135         0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
136         0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
137         0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
138         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
139         0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
140         0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
141         0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
142         0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
143         0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
144         0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
145         0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
146         0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
147         0xff, 0xff
148 };
149
150 /* data is changed in place */
151 static char*
152 pem_decode (guchar *data, int len, int *rlen) {
153         guchar *p, *s;
154         int b64len, i, rem = 0, full;
155         int b0, b1, b2, b3, offset, dlen;
156
157         p = strstr (data, "-----BEGIN");
158         s = strstr (data, "\n-----END");
159         if (!p || !s)
160                 return NULL;
161         while (*p != '\n') p++;
162         *s = 0;
163         s = data = p;
164         while (*p) {
165                 if (isalnum (*p) || *p == '+' || *p == '=' || *p == '/') {
166                         *s++ = *p++;
167                 } else {
168                         p++;
169                 }
170         }
171         *s = 0;
172         b64len = s - data;
173
174         full = b64len >> 2;
175         if (data [b64len - 1] == '=') {
176                 full--;
177                 rem++;
178         }
179         if (data [b64len - 2] == '=')
180                 rem++;
181         offset = 0;
182         p = data;
183         for (i = 0; i < full; ++i) {
184                 b0 = asciitable [data [offset++]];
185                 b1 = asciitable [data [offset++]];
186                 b2 = asciitable [data [offset++]];
187                 b3 = asciitable [data [offset++]];
188
189                 *p++ = (b0 << 2) | (b1 >> 4);
190                 *p++ = (b1 << 4) | (b2 >> 2);
191                 *p++ = (b2 << 6) | b3;
192         }
193         dlen = full * 3;
194         switch (rem) {
195         case 1:
196                 b0 = asciitable [data [offset++]];
197                 b1 = asciitable [data [offset++]];
198                 b2 = asciitable [data [offset++]];
199
200                 *p++ = (b0 << 2) | (b1 >> 4);
201                 *p++ = (b1 << 4) | (b2 >> 2);
202                 dlen += 2;
203                 break;
204         case 2:
205                 b0 = asciitable [data [offset++]];
206                 b1 = asciitable [data [offset++]];
207
208                 *p++ = (b0 << 2) | (b1 >> 4);
209                 dlen++;
210                 break;
211         }
212         *rlen = dlen;
213         return data;
214 }
215
216 enum {
217         DER_INTEGER = 2,
218         DER_BITSTRING = 3,
219         DER_NULL = 5,
220         DER_OBJID = 6,
221         DER_SEQUENCE = 16,
222         DER_INVALID = -1,
223         DER_END = -2
224 };
225
226 static int
227 der_get_next (guchar *data, int dlen, int offset, int *len, guchar **rdata)
228 {
229         int i, l, type, val;
230
231         if (offset + 1 >= dlen)
232                 return DER_END;
233
234         type = data [offset++] & 0x1f;
235         if (data [offset] == 0x80) /* not supported */
236                 return DER_INVALID;
237         l = 0;
238         if (data [offset] & 0x80) {
239                 val = data [offset++] & 0x7f;
240                 for (i = 0; i < val; ++i) {
241                         l = (l << 8) | data [offset++];
242                 }
243         } else {
244                 l = data [offset++];
245         }
246         *len = l;
247         *rdata = data + offset;
248         return type;
249 }
250
251 static void
252 dump_asn1 (guchar *key, int len) {
253         int type, offset, elen;
254         guchar *edata;
255
256         offset = 0;
257         while ((type = der_get_next (key, len, offset, &elen, &edata)) >= 0) {
258                 switch (type) {
259                 case DER_SEQUENCE:
260                         g_print ("seq (%d) at %d\n", elen, offset);
261                         dump_asn1 (edata, elen);
262                         offset = elen + edata - key;
263                         break;
264                 case DER_BITSTRING:
265                         g_print ("bits (%d) at %p + %d\n", elen, edata, offset);
266                         dump_asn1 (edata + 1, elen);
267                         offset = 1 + elen + edata - key;
268                         break;
269                 case DER_INTEGER:
270                         g_print ("int (%d) at %d\n", elen, offset);
271                         offset = elen + edata - key;
272                         break;
273                 case DER_NULL:
274                         g_print ("null (%d) at %d\n", elen, offset);
275                         offset = elen + edata - key;
276                         break;
277                 case DER_OBJID:
278                         g_print ("objid (%d) at %d\n", elen, offset);
279                         offset = elen + edata - key;
280                         break;
281                 default:
282                         return;
283                 }
284         }
285 }
286
287 static guint32
288 get_der_int (guchar *data, int len)
289 {
290         guint32 val = 0;
291         int i;
292         for (i = 0; i < len; ++i)
293                 val = (val << 8) | data [i];
294         return val;
295 }
296
297 static void
298 mem_reverse (guchar *p, int len) {
299         int i, t;
300
301         for (i = 0; i < len/2; ++i) {
302                 t = p [i];
303                 p [i] = p [len - i - 1];
304                 p [len - i - 1] = t;
305         }
306 }
307
308 static int
309 convert_der_key (guchar *key, int len, guchar **ret, int *retlen)
310 {
311         int type, offset, val, elen;
312         guchar *r, *edata;
313
314         offset = 0;
315         type = der_get_next (key, len, offset, &elen, &edata);
316         if (type != DER_SEQUENCE)
317                 return 1;
318         key = edata;
319         len = elen;
320         type = der_get_next (key, len, offset, &elen, &edata);
321         if (type == DER_INTEGER) {
322                 int i;
323                 guchar *ints [6];
324                 int lengths [6];
325                 guchar *p;
326                 /* a private RSA key */
327                 val = get_der_int (edata, elen);
328                 if (val != 0)
329                         return 2;
330                 offset = elen + edata - key;
331                 /* the modulus */
332                 type = der_get_next (key, len, offset, &elen, &edata);
333                 if (type != DER_INTEGER)
334                         return 2;
335                 offset = elen + edata - key;
336                 if ((elen & 1) && *edata == 0) {
337                         edata ++;
338                         elen--;
339                 }
340                 r = g_new0 (guchar, elen*4 + elen/2 + 20);
341                 r [0] = 0x7; r [1] = 0x2; r [5] = 0x24;
342                 r [8] = 0x52; r [9] = 0x53; r [10] = 0x41; r [11] = 0x32;
343                 *(guint32*)(r + 12) = elen * 8;
344                 memcpy (r + 20, edata, elen);
345                 mem_reverse (r + 20, elen);
346                 p = r + 20 + elen;
347                 /* the exponent */
348                 type = der_get_next (key, len, offset, &elen, &edata);
349                 if (type != DER_INTEGER)
350                         return 2;
351                 offset = elen + edata - key;
352                 val = get_der_int (edata, elen);
353                 *(guint32*)(r + 16) = val;
354                 for (i = 0; i < 6; i++) {
355                         type = der_get_next (key, len, offset, &elen, &edata);
356                         if (type != DER_INTEGER)
357                                 return 2;
358                         offset = elen + edata - key;
359                         if ((elen & 1) && *edata == 0) {
360                                 edata++;
361                                 elen--;
362                         }
363                         ints [i] = edata;
364                         lengths [i] = elen;
365                         g_print ("len: %d\n", elen);
366                 }
367                 /* prime1 */
368                 g_print ("prime1 at %d (%d)\n", p-r, lengths [1]);
369                 memcpy (p, ints [1], lengths [1]);
370                 mem_reverse (p, lengths [1]);
371                 p += lengths [1];
372                 /* prime2 */
373                 g_print ("prime2 at %d (%d)\n", p-r, lengths [2]);
374                 memcpy (p, ints [2], lengths [2]);
375                 mem_reverse (p, lengths [2]);
376                 p += lengths [2];
377                 /* exponent1 */
378                 g_print ("exp1 at %d (%d)\n", p-r, lengths [3]);
379                 memcpy (p, ints [3], lengths [3]);
380                 mem_reverse (p, lengths [3]);
381                 p += lengths [3];
382                 /* exponent2 */
383                 g_print ("exp2 at %d (%d)\n", p-r, lengths [4]);
384                 memcpy (p, ints [4], lengths [4]);
385                 mem_reverse (p, lengths [4]);
386                 p += lengths [4];
387                 /* coeff */
388                 g_print ("coeff at %d (%d)\n", p-r, lengths [5]);
389                 memcpy (p, ints [5], lengths [5]);
390                 mem_reverse (p, lengths [5]);
391                 p += lengths [5];
392                 /* private exponent */
393                 g_print ("prive at %d (%d)\n", p-r, lengths [0]);
394                 memcpy (p, ints [0], lengths [0]);
395                 mem_reverse (p, lengths [0]);
396                 p += lengths [0];
397                 *ret = r;
398                 *retlen = p-r;
399                 return 0;
400         }
401         return 1;
402 }
403
404 static int
405 convert_format (const char *from, const char *outfile) {
406         guchar *key, *bindata, *keyout;
407         gsize len;
408         int binlen, ret, lenout;
409         FILE *file;
410         
411         if (!g_file_get_contents (from, (gchar**) &key, &len, NULL)) {
412                 printf ("Cannot load file: %s\n", from);
413                 return 2;
414         }
415
416         if (*key == 0 || *key == 0x24) {
417                 g_free (key);
418                 printf ("Cannot convert to pem format yet\n");
419                 return 2;
420         }
421         bindata = pem_decode (key, len, &binlen);
422         if (!(file = fopen (outfile, "wb"))) {
423                 g_free (key);
424                 printf ("Cannot open output file: %s\n", outfile);
425                 return 2;
426         }
427         dump_asn1 (bindata, binlen);
428         ret = convert_der_key (bindata, binlen, &keyout, &lenout);
429         if (!ret) {
430                 fwrite (keyout, lenout, 1, file);
431                 g_free (keyout);
432         } else {
433                 printf ("Cannot convert key\n");
434         }
435         fclose (file);
436         g_free (key);
437         return ret;
438 }
439
440 static int
441 get_digest (const char *from, const char *outfile)
442 {
443         guchar *ass;
444         guchar digest [20];
445         gsize len;
446         guint32 snpos, snsize;
447         FILE *file;
448         MonoImage *image;
449         MonoSHA1Context sha1;
450         
451         image = mono_image_open (from, NULL);
452         if (!image) {
453                 printf ("Cannot open image file: %s\n", from);
454                 return 2;
455         }
456         snpos = mono_image_strong_name_position (image, &snsize);
457         if (!snpos) {
458                 /*printf ("%s does not represent a strongly named assembly\n", from);
459                 mono_image_close (image);
460                 return 2;*/
461                 snsize = 0;
462         }
463         
464         if (!g_file_get_contents (from, (gchar**) &ass, &len, NULL)) {
465                 printf ("Cannot load file: %s\n", from);
466                 mono_image_close (image);
467                 return 2;
468         }
469         /* 
470          * FIXME: we may need to set the STRONGNAMESIGNED flag in the cli header 
471          * before taking the sha1 digest of the image.
472          */
473         mono_sha1_init (&sha1);
474         mono_sha1_update (&sha1, ass, snpos);
475         mono_sha1_update (&sha1, ass + snpos + snsize, len - snsize - snpos);
476         mono_sha1_final (&sha1, digest);
477
478         mono_image_close (image);
479         g_free (ass);
480         if (!(file = fopen (outfile, "wb"))) {
481                 printf ("Cannot open output file: %s\n", outfile);
482                 return 2;
483         }
484         fwrite (digest, 20, 1, file);
485         fclose (file);
486         return 0;
487 }
488
489 static void 
490 help (int err) {
491         printf ("monosn: Mono Strong Name Utility\nUsage: monosn option [arguments]\n");
492         printf ("Available options:\n");
493         printf ("\t-C keyin keyout   Convert key file format from PEM to cryptoAPI (or the reverse).\n");
494         printf ("\t-e assembly file  Extract the public key from assembly to file.\n");
495         printf ("\t-E assembly file  Extract the strong name from assembly to file.\n");
496         printf ("\t-r assembly file  Extract the sha1 digest from assembly to file.\n");
497         printf ("\t-t[p] file        Display the public key token from file.\n");
498         printf ("\t-T[p] assembly    Display the public key token from assembly.\n");
499         exit (err);
500 }
501
502 int 
503 main (int argc, char *argv[]) {
504         int opt;
505         
506         if (argc < 2 || argv [1] [0] != '-')
507                 help (1);
508
509         opt = argv [1] [1];
510         switch (opt) {
511         case 'C':
512                 if (argc != 4)
513                         help (1);
514                 return convert_format (argv [2], argv [3]);
515         case 'e':
516                 if (argc != 4)
517                         help (1);
518                 return extract_data_to_file (1, argv [2], argv [3]);
519         case 'E':
520                 if (argc != 4)
521                         help (1);
522                 return extract_data_to_file (0, argv [2], argv [3]);
523         case 'h':
524         case '?':
525                 help (0);
526                 return 0;
527         case 'r':
528                 if (argc != 4)
529                         help (1);
530                 return get_digest (argv [2], argv [3]);
531         case 't':
532                 if (argc != 3)
533                         help (1);
534                 return show_token (argv [2], 0, argv [1] [2] == 'p');
535         case 'T':
536                 if (argc != 3)
537                         help (1);
538                 return show_token (argv [2], 1, argv [1] [2] == 'p');
539         default:
540                 help (1);
541         }
542         return 0;
543 }
544