#include "mono/utils/mono-digest.h"
/* trim headers */
+#include <string.h>
+#include <ctype.h>
+
#define RSA1_MAGIC 0x32415351
#define RSA2_MAGIC 0x32415352
#define PRIVKEY_MAGIC 0x00000207
MonoImage *image;
const char *pubkey;
guint32 len;
+
+ mono_metadata_init ();
+ mono_raw_buffer_init ();
+ mono_images_init ();
+ mono_assemblies_init ();
+ mono_loader_init ();
+
image = mono_image_open (file, NULL);
if (!image) {
printf ("Cannot open image file: %s\n", file);
}
pubkey = mono_image_get_public_key (image, &len);
if (!pubkey) {
- printf ("%s does not represent a strongly named assembly\n", image->name);
+ printf ("%s does not represent a strongly named assembly\n", mono_image_get_name(image));
mono_image_close (image);
return 2;
}
else
pubkey = mono_image_get_strong_name (image, &len);
if (!pubkey) {
- printf ("%s does not represent a strongly named assembly\n", image->name);
+ printf ("%s does not represent a strongly named assembly\n", mono_image_get_name(image));
mono_image_close (image);
return 2;
}
return 0;
}
+const static guint8 asciitable [128] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+ 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+ 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
+ 0xff, 0xff
+};
+
+/* data is changed in place */
+static char*
+pem_decode (guchar *data, int len, int *rlen) {
+ guchar *p, *s;
+ int b64len, i, rem = 0, full;
+ int b0, b1, b2, b3, offset, dlen;
+
+ p = strstr (data, "-----BEGIN");
+ s = strstr (data, "\n-----END");
+ if (!p || !s)
+ return NULL;
+ while (*p != '\n') p++;
+ *s = 0;
+ s = data = p;
+ while (*p) {
+ if (isalnum (*p) || *p == '+' || *p == '=' || *p == '/') {
+ *s++ = *p++;
+ } else {
+ p++;
+ }
+ }
+ *s = 0;
+ b64len = s - data;
+
+ full = b64len >> 2;
+ if (data [b64len - 1] == '=') {
+ full--;
+ rem++;
+ }
+ if (data [b64len - 2] == '=')
+ rem++;
+ offset = 0;
+ p = data;
+ for (i = 0; i < full; ++i) {
+ b0 = asciitable [data [offset++]];
+ b1 = asciitable [data [offset++]];
+ b2 = asciitable [data [offset++]];
+ b3 = asciitable [data [offset++]];
+
+ *p++ = (b0 << 2) | (b1 >> 4);
+ *p++ = (b1 << 4) | (b2 >> 2);
+ *p++ = (b2 << 6) | b3;
+ }
+ dlen = full * 3;
+ switch (rem) {
+ case 1:
+ b0 = asciitable [data [offset++]];
+ b1 = asciitable [data [offset++]];
+ b2 = asciitable [data [offset++]];
+
+ *p++ = (b0 << 2) | (b1 >> 4);
+ *p++ = (b1 << 4) | (b2 >> 2);
+ dlen += 2;
+ break;
+ case 2:
+ b0 = asciitable [data [offset++]];
+ b1 = asciitable [data [offset++]];
+
+ *p++ = (b0 << 2) | (b1 >> 4);
+ dlen++;
+ break;
+ }
+ *rlen = dlen;
+ return data;
+}
+
+enum {
+ DER_INTEGER = 2,
+ DER_BITSTRING = 3,
+ DER_NULL = 5,
+ DER_OBJID = 6,
+ DER_SEQUENCE = 16,
+ DER_INVALID = -1,
+ DER_END = -2
+};
+
+static int
+der_get_next (guchar *data, int dlen, int offset, int *len, guchar **rdata)
+{
+ int i, l, type, val;
+
+ if (offset + 1 >= dlen)
+ return DER_END;
+
+ type = data [offset++] & 0x1f;
+ if (data [offset] == 0x80) /* not supported */
+ return DER_INVALID;
+ l = 0;
+ if (data [offset] & 0x80) {
+ val = data [offset++] & 0x7f;
+ for (i = 0; i < val; ++i) {
+ l = (l << 8) | data [offset++];
+ }
+ } else {
+ l = data [offset++];
+ }
+ *len = l;
+ *rdata = data + offset;
+ return type;
+}
+
+static void
+dump_asn1 (guchar *key, int len) {
+ int type, offset, elen;
+ guchar *edata;
+
+ offset = 0;
+ while ((type = der_get_next (key, len, offset, &elen, &edata)) >= 0) {
+ switch (type) {
+ case DER_SEQUENCE:
+ g_print ("seq (%d) at %d\n", elen, offset);
+ dump_asn1 (edata, elen);
+ offset = elen + edata - key;
+ break;
+ case DER_BITSTRING:
+ g_print ("bits (%d) at %p + %d\n", elen, edata, offset);
+ dump_asn1 (edata + 1, elen);
+ offset = 1 + elen + edata - key;
+ break;
+ case DER_INTEGER:
+ g_print ("int (%d) at %d\n", elen, offset);
+ offset = elen + edata - key;
+ break;
+ case DER_NULL:
+ g_print ("null (%d) at %d\n", elen, offset);
+ offset = elen + edata - key;
+ break;
+ case DER_OBJID:
+ g_print ("objid (%d) at %d\n", elen, offset);
+ offset = elen + edata - key;
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+static guint32
+get_der_int (guchar *data, int len)
+{
+ guint32 val = 0;
+ int i;
+ for (i = 0; i < len; ++i)
+ val = (val << 8) | data [i];
+ return val;
+}
+
+static void
+mem_reverse (guchar *p, int len) {
+ int i, t;
+
+ for (i = 0; i < len/2; ++i) {
+ t = p [i];
+ p [i] = p [len - i - 1];
+ p [len - i - 1] = t;
+ }
+}
+
+static int
+convert_der_key (guchar *key, int len, guchar **ret, int *retlen)
+{
+ int type, offset, val, elen;
+ guchar *r, *edata;
+
+ offset = 0;
+ type = der_get_next (key, len, offset, &elen, &edata);
+ if (type != DER_SEQUENCE)
+ return 1;
+ key = edata;
+ len = elen;
+ type = der_get_next (key, len, offset, &elen, &edata);
+ if (type == DER_INTEGER) {
+ int i;
+ guchar *ints [6];
+ int lengths [6];
+ guchar *p;
+ /* a private RSA key */
+ val = get_der_int (edata, elen);
+ if (val != 0)
+ return 2;
+ offset = elen + edata - key;
+ /* the modulus */
+ type = der_get_next (key, len, offset, &elen, &edata);
+ if (type != DER_INTEGER)
+ return 2;
+ offset = elen + edata - key;
+ if ((elen & 1) && *edata == 0) {
+ edata ++;
+ elen--;
+ }
+ r = g_new0 (guchar, elen*4 + elen/2 + 20);
+ r [0] = 0x7; r [1] = 0x2; r [5] = 0x24;
+ r [8] = 0x52; r [9] = 0x53; r [10] = 0x41; r [11] = 0x32;
+ *(guint32*)(r + 12) = elen * 8;
+ memcpy (r + 20, edata, elen);
+ mem_reverse (r + 20, elen);
+ p = r + 20 + elen;
+ /* the exponent */
+ type = der_get_next (key, len, offset, &elen, &edata);
+ if (type != DER_INTEGER)
+ return 2;
+ offset = elen + edata - key;
+ val = get_der_int (edata, elen);
+ *(guint32*)(r + 16) = val;
+ for (i = 0; i < 6; i++) {
+ type = der_get_next (key, len, offset, &elen, &edata);
+ if (type != DER_INTEGER)
+ return 2;
+ offset = elen + edata - key;
+ if ((elen & 1) && *edata == 0) {
+ edata++;
+ elen--;
+ }
+ ints [i] = edata;
+ lengths [i] = elen;
+ g_print ("len: %d\n", elen);
+ }
+ /* prime1 */
+ g_print ("prime1 at %d (%d)\n", p-r, lengths [1]);
+ memcpy (p, ints [1], lengths [1]);
+ mem_reverse (p, lengths [1]);
+ p += lengths [1];
+ /* prime2 */
+ g_print ("prime2 at %d (%d)\n", p-r, lengths [2]);
+ memcpy (p, ints [2], lengths [2]);
+ mem_reverse (p, lengths [2]);
+ p += lengths [2];
+ /* exponent1 */
+ g_print ("exp1 at %d (%d)\n", p-r, lengths [3]);
+ memcpy (p, ints [3], lengths [3]);
+ mem_reverse (p, lengths [3]);
+ p += lengths [3];
+ /* exponent2 */
+ g_print ("exp2 at %d (%d)\n", p-r, lengths [4]);
+ memcpy (p, ints [4], lengths [4]);
+ mem_reverse (p, lengths [4]);
+ p += lengths [4];
+ /* coeff */
+ g_print ("coeff at %d (%d)\n", p-r, lengths [5]);
+ memcpy (p, ints [5], lengths [5]);
+ mem_reverse (p, lengths [5]);
+ p += lengths [5];
+ /* private exponent */
+ g_print ("prive at %d (%d)\n", p-r, lengths [0]);
+ memcpy (p, ints [0], lengths [0]);
+ mem_reverse (p, lengths [0]);
+ p += lengths [0];
+ *ret = r;
+ *retlen = p-r;
+ return 0;
+ }
+ return 1;
+}
+
+static int
+convert_format (const char *from, const char *outfile) {
+ guchar *key, *bindata, *keyout;
+ gsize len;
+ int binlen, ret, lenout;
+ FILE *file;
+
+ if (!g_file_get_contents (from, (gchar**) &key, &len, NULL)) {
+ printf ("Cannot load file: %s\n", from);
+ return 2;
+ }
+
+ if (*key == 0 || *key == 0x24) {
+ g_free (key);
+ printf ("Cannot convert to pem format yet\n");
+ return 2;
+ }
+ bindata = pem_decode (key, len, &binlen);
+ if (!(file = fopen (outfile, "wb"))) {
+ g_free (key);
+ printf ("Cannot open output file: %s\n", outfile);
+ return 2;
+ }
+ dump_asn1 (bindata, binlen);
+ ret = convert_der_key (bindata, binlen, &keyout, &lenout);
+ if (!ret) {
+ fwrite (keyout, lenout, 1, file);
+ g_free (keyout);
+ } else {
+ printf ("Cannot convert key\n");
+ }
+ fclose (file);
+ g_free (key);
+ return ret;
+}
+
+static int
+get_digest (const char *from, const char *outfile)
+{
+ guchar *ass;
+ guchar digest [20];
+ gsize len;
+ guint32 snpos, snsize;
+ FILE *file;
+ MonoImage *image;
+ MonoSHA1Context sha1;
+
+ image = mono_image_open (from, NULL);
+ if (!image) {
+ printf ("Cannot open image file: %s\n", from);
+ return 2;
+ }
+ snpos = mono_image_strong_name_position (image, &snsize);
+ if (!snpos) {
+ /*printf ("%s does not represent a strongly named assembly\n", from);
+ mono_image_close (image);
+ return 2;*/
+ snsize = 0;
+ }
+
+ if (!g_file_get_contents (from, (gchar**) &ass, &len, NULL)) {
+ printf ("Cannot load file: %s\n", from);
+ mono_image_close (image);
+ return 2;
+ }
+ /*
+ * FIXME: we may need to set the STRONGNAMESIGNED flag in the cli header
+ * before taking the sha1 digest of the image.
+ */
+ mono_sha1_init (&sha1);
+ mono_sha1_update (&sha1, ass, snpos);
+ mono_sha1_update (&sha1, ass + snpos + snsize, len - snsize - snpos);
+ mono_sha1_final (&sha1, digest);
+
+ mono_image_close (image);
+ g_free (ass);
+ if (!(file = fopen (outfile, "wb"))) {
+ printf ("Cannot open output file: %s\n", outfile);
+ return 2;
+ }
+ fwrite (digest, 20, 1, file);
+ fclose (file);
+ return 0;
+}
+
static void
help (int err) {
printf ("monosn: Mono Strong Name Utility\nUsage: monosn option [arguments]\n");
printf ("Available options:\n");
- printf ("\t-e assembly file Extract the public key from assembly to file.");
- printf ("\t-E assembly file Extract the strong name from assembly to file.");
- printf ("\t-t[p] file Display the public key token from file.");
- printf ("\t-T[p] assembly Display the public key token from assembly.");
+ printf ("\t-C keyin keyout Convert key file format from PEM to cryptoAPI (or the reverse).\n");
+ printf ("\t-e assembly file Extract the public key from assembly to file.\n");
+ printf ("\t-E assembly file Extract the strong name from assembly to file.\n");
+ printf ("\t-r assembly file Extract the sha1 digest from assembly to file.\n");
+ printf ("\t-t[p] file Display the public key token from file.\n");
+ printf ("\t-T[p] assembly Display the public key token from assembly.\n");
exit (err);
}
opt = argv [1] [1];
switch (opt) {
+ case 'C':
+ if (argc != 4)
+ help (1);
+ return convert_format (argv [2], argv [3]);
case 'e':
if (argc != 4)
help (1);
case '?':
help (0);
return 0;
+ case 'r':
+ if (argc != 4)
+ help (1);
+ return get_digest (argv [2], argv [3]);
case 't':
if (argc != 3)
help (1);