[metadata] Encode public key length correctly for keys longer than 128 bytes
authorAleksey Kliger <aleksey@xamarin.com>
Thu, 13 Jul 2017 19:54:12 +0000 (15:54 -0400)
committerAleksey Kliger (λgeek) <akliger@gmail.com>
Fri, 14 Jul 2017 18:43:18 +0000 (14:43 -0400)
Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=57691

For keys longer than 1024 bits, we encoded the length incorrectly as
   0x80 (length & 0xff)
instead of the correct algorithm:
  if (length < 0x80)
    length
  else if (length < 0x4000)
    0x80|(length>>8) (length & 0xff)
  else
    0xc0|(length>>24) (length>>16)&0xff (length>>8)&0xff length&0xff

which is provided by mono_metadata_encode_value.

See ECMA-335 II.24.2.4 #US and #Blob heaps

N.B.: we now always allocate the memory for the key as (keylen + 4) which
over-allocates by a couple of bytes in the cases where the key is shorter.

mono/metadata/assembly.c

index e5b1cb0c57ad730db7c323e1ff9741ec7e3e17ac..35896715ac6ead8cd6b48aa2b7cbff950f2f7832 100644 (file)
@@ -2370,7 +2370,7 @@ static gboolean
 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
 {
        const gchar *pkey;
-       gchar header [16], val, *arr;
+       gchar header [16], val, *arr, *endp;
        gint i, j, offset, bitlen, keylen, pkeylen;
        
        keylen = strlen (key) >> 1;
@@ -2432,16 +2432,10 @@ parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
        if (!pubkey)
                return TRUE;
                
+       arr = (gchar *)g_malloc (keylen + 4);
        /* Encode the size of the blob */
-       offset = 0;
-       if (keylen <= 127) {
-               arr = (gchar *)g_malloc (keylen + 1);
-               arr [offset++] = keylen;
-       } else {
-               arr = (gchar *)g_malloc (keylen + 2);
-               arr [offset++] = 0x80; /* 10bs */
-               arr [offset++] = keylen;
-       }
+       mono_metadata_encode_value (keylen, &arr[0], &endp);
+       offset = (gint)(endp-arr);
                
        for (i = offset, j = 0; i < keylen + offset; i++) {
                arr [i] = g_ascii_xdigit_value (key [j++]) << 4;