Skip to content
Open
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
2 changes: 2 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/10.0.200.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@
* Removed `#light` and `#indent` directives (they are now a no-op; combined with `off` they give an error). ([PR #19143](https://github.com/dotnet/fsharp/pull/19143))
* Removed `--light`, `--indentation-syntax`, `--no-indendation-syntax`, `--ml-keywords` and `--mlcompatibility` compiler/fsi flags. ([PR #19143](https://github.com/dotnet/fsharp/pull/19143))
* Removed parsing support for long-deprecated ML (non-light) constructs. ([PR #19143](https://github.com/dotnet/fsharp/pull/19143))

Fix strong name signature size to align with Roslyn for public signing (#11887)
89 changes: 61 additions & 28 deletions src/Compiler/AbstractIL/ilsign.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

module internal FSharp.Compiler.AbstractIL.StrongNameSign

Expand Down Expand Up @@ -127,6 +127,10 @@ type BlobReader =
val mutable _offset: int
new(blob: byte array) = { _blob = blob; _offset = 0 }

member x.Offset
with get () = x._offset
and set (v) = x._offset <- v

member x.ReadInt32() : int =
let offset = x._offset
x._offset <- offset + 4
Expand All @@ -145,13 +149,13 @@ type BlobReader =
let RSAParametersFromBlob blob keyType =
let mutable reader = BlobReader blob

if reader.ReadInt32() <> 0x00000207 && keyType = KeyType.KeyPair then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignPrivateKeyExpected ())))
reader.ReadInt32() |> ignore
reader.ReadInt32() |> ignore

reader.ReadInt32() |> ignore // ALG_ID
let magic = reader.ReadInt32()

if reader.ReadInt32() <> RSA_PRIV_MAGIC then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignRsaKeyExpected ()))) // 'RSA2'
if magic <> RSA_PUB_MAGIC && magic <> RSA_PRIV_MAGIC then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignRsaKeyExpected ())))

let byteLen, halfLen =
let bitLen = reader.ReadInt32()
Expand All @@ -160,15 +164,20 @@ let RSAParametersFromBlob blob keyType =
| 0 -> (bitLen / 8, bitLen / 16)
| _ -> raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidBitLen ())))

ignore keyType

let mutable key = RSAParameters()
key.Exponent <- reader.ReadBigInteger 4
key.Modulus <- reader.ReadBigInteger byteLen
key.P <- reader.ReadBigInteger halfLen
key.Q <- reader.ReadBigInteger halfLen
key.DP <- reader.ReadBigInteger halfLen
key.DQ <- reader.ReadBigInteger halfLen
key.InverseQ <- reader.ReadBigInteger halfLen
key.D <- reader.ReadBigInteger byteLen

if magic = RSA_PRIV_MAGIC then
key.P <- reader.ReadBigInteger halfLen
key.Q <- reader.ReadBigInteger halfLen
key.DP <- reader.ReadBigInteger halfLen
key.DQ <- reader.ReadBigInteger halfLen
key.InverseQ <- reader.ReadBigInteger halfLen
key.D <- reader.ReadBigInteger byteLen

key

let validateRSAField (field: byte array MaybeNull) expected (name: string) =
Expand Down Expand Up @@ -300,20 +309,49 @@ let signStream stream keyBlob =
let signature = createSignature hash keyBlob KeyType.KeyPair
patchSignature stream peReader signature

/// Calculates the required signature space for an RSA key blob.
/// Adheres strictly to MS-AZRP and PE/COFF standards with zero environment-specific logic.
let signatureSize (pk: byte array) =
if pk.Length < 25 then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidPKBlob ())))
// Total overhead for StrongName and RSA Headers (12 + 8 + 12 = 32 bytes).
// - StrongName Header (CLI Metadata): 12 bytes
// - PUBLICKEYSTRUC (8 bytes) & RSAPUBKEY (12 bytes)
// Source: https://learn.microsoft.com/en-us/windows/win32/seccrypto/base-provider-key-blobs#public-key-blobs
let legacyHeaderOverhead = 32

if pk.Length < legacyHeaderOverhead then
pk.Length
else
// Manual bit-shifting to avoid heap allocation from BlobReader.
// Offset 20: RSAPUBKEY.magic (RSA1=0x31415352, RSA2=0x32415352)
let magic =
int pk.[20]
||| (int pk.[21] <<< 8)
||| (int pk.[22] <<< 16)
||| (int pk.[23] <<< 24)

if magic <> RSA_PUB_MAGIC && magic <> RSA_PRIV_MAGIC then
pk.Length
else
// Offset 24: RSAPUBKEY.bitlen (Source: MS-AZRP)
let bitLen =
int pk.[24]
||| (int pk.[25] <<< 8)
||| (int pk.[26] <<< 16)
||| (int pk.[27] <<< 24)

// Per MS-AZRP: "The number of bytes can be determined by dividing the
// value of the RSAPUBKEY bitlen field by eight."
let modulusSize = bitLen / 8

let mutable reader = BlobReader pk
reader.ReadBigInteger 12 |> ignore // Skip CLRHeader
reader.ReadBigInteger 8 |> ignore // Skip BlobHeader
let magic = reader.ReadInt32() // Read magic
// Raw Size: Modulus + 32 bytes of fixed metadata headers.
let rawSize = modulusSize + legacyHeaderOverhead

if not (magic = RSA_PRIV_MAGIC || magic = RSA_PUB_MAGIC) then // RSAPubKey.magic
raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidPKBlob ())))
// PE/COFF Spec: IMAGE_DIRECTORY_ENTRY_SECURITY must be 8-byte aligned.
// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-attribute-certificate-table-image_directory_entry_security
let alignment = 8
let alignedSize = ((rawSize + (alignment - 1)) / alignment) * alignment

let x = reader.ReadInt32() / 8
x
alignedSize

// Returns a CLR Format Blob public key
let getPublicKeyForKeyPair keyBlob =
Expand Down Expand Up @@ -371,12 +409,7 @@ type ILStrongNameSigner =
| KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()

member s.SignatureSize =
let pkSignatureSize pk =
try
signerSignatureSize pk
with exn ->
failwith ("A call to StrongNameSignatureSize failed (" + exn.Message + ")")
0x80
let pkSignatureSize pk = signerSignatureSize pk

match s with
| PublicKeySigner pk -> pkSignatureSize pk
Expand Down
Loading