Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't rely on StrongNameKeyPair #548

Merged
merged 6 commits into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
jbevain marked this conversation as resolved.
Show resolved Hide resolved
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