Skip to content

Commit

Permalink
Don't rely on StrongNameKeyPair (#548)
Browse files Browse the repository at this point in the history
  • Loading branch information
atykhyy authored and jbevain committed Aug 5, 2019
1 parent b2d248c commit 12da1bf
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 11 deletions.
8 changes: 4 additions & 4 deletions Mono.Cecil/AssemblyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ static void Write (ModuleDefinition module, Disposable<Stream> stream, WriterPar
if (symbol_writer_provider == null && parameters.WriteSymbols)
symbol_writer_provider = new DefaultSymbolWriterProvider ();

if (parameters.StrongNameKeyPair != null && name != null) {
name.PublicKey = parameters.StrongNameKeyPair.PublicKey;
if (parameters.HasStrongNameKey && name != null) {
name.PublicKey = CryptoService.GetPublicKey (parameters);
module.Attributes |= ModuleAttributes.StrongNameSigned;
}

Expand All @@ -125,8 +125,8 @@ static void Write (ModuleDefinition module, Disposable<Stream> stream, WriterPar
stream.value.SetLength (0);
writer.WriteImage ();

if (parameters.StrongNameKeyPair != null)
CryptoService.StrongName (stream.value, writer, parameters.StrongNameKeyPair);
if (parameters.HasStrongNameKey)
CryptoService.StrongName (stream.value, writer, parameters);
}
} finally {
module.metadata_builder = null;
Expand Down
16 changes: 16 additions & 0 deletions Mono.Cecil/ModuleDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ public sealed class WriterParameters {
Stream symbol_stream;
ISymbolWriterProvider symbol_writer_provider;
bool write_symbols;
byte [] key_blob;
string key_container;
SR.StrongNameKeyPair key_pair;

public uint? Timestamp {
Expand All @@ -205,6 +207,20 @@ public bool WriteSymbols {
set { write_symbols = value; }
}

public bool HasStrongNameKey {
get { return key_pair != null || key_blob != null || key_container != null; }
}

public byte [] StrongNameKeyBlob {
get { return key_blob; }
set { key_blob = value; }
}

public string StrongNameKeyContainer {
get { return key_container; }
set { key_container = value; }
}

public SR.StrongNameKeyPair StrongNameKeyPair {
get { return key_pair; }
set { key_pair = value; }
Expand Down
46 changes: 46 additions & 0 deletions Mono.Security.Cryptography/CryptoConvert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ static private uint ToUInt32LE (byte [] bytes, int offset)
return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
}

static private byte [] GetBytesLE (int val)
{
return new byte [] {
(byte) (val & 0xff),
(byte) ((val >> 8) & 0xff),
(byte) ((val >> 16) & 0xff),
(byte) ((val >> 24) & 0xff)
};
}

static private byte[] Trim (byte[] array)
{
for (int i=0; i < array.Length; i++) {
Expand Down Expand Up @@ -240,5 +250,41 @@ static public RSA FromCapiKeyBlob (byte[] blob, int offset)
}
throw new CryptographicException ("Unknown blob format.");
}

static public byte[] ToCapiPublicKeyBlob (RSA rsa)
{
RSAParameters p = rsa.ExportParameters (false);
int keyLength = p.Modulus.Length; // in bytes
byte[] blob = new byte [20 + keyLength];

blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
// [2], [3] // RESERVED - Always 0
blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
blob [8] = 0x52; // Magic - RSA1 (ASCII in hex)
blob [9] = 0x53;
blob [10] = 0x41;
blob [11] = 0x31;

byte[] bitlen = GetBytesLE (keyLength << 3);
blob [12] = bitlen [0]; // bitlen
blob [13] = bitlen [1];
blob [14] = bitlen [2];
blob [15] = bitlen [3];

// public exponent (DWORD)
int pos = 16;
int n = p.Exponent.Length;
while (n > 0)
blob [pos++] = p.Exponent [--n];
// modulus
pos = 20;
byte[] part = p.Modulus;
int len = part.Length;
Array.Reverse (part, 0, len);
Buffer.BlockCopy (part, 0, blob, pos, len);
pos += len;
return blob;
}
}
}
40 changes: 33 additions & 7 deletions Mono.Security.Cryptography/CryptoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,33 @@ namespace Mono.Cecil {

static class CryptoService {

public static void StrongName (Stream stream, ImageWriter writer, StrongNameKeyPair key_pair)
public static byte [] GetPublicKey (WriterParameters parameters)
{
using (var rsa = parameters.CreateRSA ()) {
var cspBlob = CryptoConvert.ToCapiPublicKeyBlob (rsa);
var publicKey = new byte [12 + cspBlob.Length];
Buffer.BlockCopy (cspBlob, 0, publicKey, 12, cspBlob.Length);
// The first 12 bytes are documented at:
// http://msdn.microsoft.com/library/en-us/cprefadd/html/grfungethashfromfile.asp
// ALG_ID - Signature
publicKey [1] = 36;
// ALG_ID - Hash
publicKey [4] = 4;
publicKey [5] = 128;
// Length of Public Key (in bytes)
publicKey [8] = (byte) (cspBlob.Length >> 0);
publicKey [9] = (byte) (cspBlob.Length >> 8);
publicKey [10] = (byte) (cspBlob.Length >> 16);
publicKey [11] = (byte) (cspBlob.Length >> 24);
return publicKey;
}
}

public static void StrongName (Stream stream, ImageWriter writer, WriterParameters parameters)
{
int strong_name_pointer;

var strong_name = CreateStrongName (key_pair, HashStream (stream, writer, out strong_name_pointer));
var strong_name = CreateStrongName (parameters, HashStream (stream, writer, out strong_name_pointer));
PatchStrongName (stream, strong_name_pointer, strong_name);
}

Expand All @@ -40,11 +62,11 @@ static void PatchStrongName (Stream stream, int strong_name_pointer, byte [] str
stream.Write (strong_name, 0, strong_name.Length);
}

static byte [] CreateStrongName (StrongNameKeyPair key_pair, byte [] hash)
static byte [] CreateStrongName (WriterParameters parameters, byte [] hash)
{
const string hash_algo = "SHA1";

using (var rsa = key_pair.CreateRSA ()) {
using (var rsa = parameters.CreateRSA ()) {
var formatter = new RSAPKCS1SignatureFormatter (rsa);
formatter.SetHashAlgorithm (hash_algo);

Expand Down Expand Up @@ -74,7 +96,6 @@ static byte [] HashStream (Stream stream, ImageWriter writer, out int strong_nam
var sha1 = new SHA1Managed ();
var buffer = new byte [buffer_size];
using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) {

stream.Seek (0, SeekOrigin.Begin);
CopyStreamChunk (stream, crypto_stream, buffer, header_size);

Expand Down Expand Up @@ -148,12 +169,17 @@ public static Guid ComputeGuid (byte [] hash)

static partial class Mixin {

public static RSA CreateRSA (this StrongNameKeyPair key_pair)
public static RSA CreateRSA (this WriterParameters writer_parameters)
{
byte [] key;
string key_container;

if (!TryGetKeyContainer (key_pair, out key, out key_container))
if (writer_parameters.StrongNameKeyBlob != null)
return CryptoConvert.FromCapiKeyBlob (writer_parameters.StrongNameKeyBlob);

if (writer_parameters.StrongNameKeyContainer != null)
key_container = writer_parameters.StrongNameKeyContainer;
else if (!TryGetKeyContainer (writer_parameters.StrongNameKeyPair, out key, out key_container))
return CryptoConvert.FromCapiKeyBlob (key);

var parameters = new CspParameters {
Expand Down

0 comments on commit 12da1bf

Please sign in to comment.