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