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 @@ -52,3 +52,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)
123 changes: 64 additions & 59 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 @@ -142,33 +146,40 @@ type BlobReader =
x._offset <- x._offset + length
arr |> Array.rev

let RSAParametersFromBlob blob keyType =
/// Decodes an RSA functional blob into RSAParameters.
/// Ref: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-publickeystruc
let RSAParametersFromBlob blob =
let mutable reader = BlobReader blob

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

reader.ReadInt32() |> ignore // ALG_ID
// Skip PUBLICKEYSTRUC (8 bytes): bType(1), bVersion(1), reserved(2), aiKeyAlg(4)
reader.ReadInt32() |> ignore
reader.ReadInt32() |> ignore

if reader.ReadInt32() <> RSA_PRIV_MAGIC then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignRsaKeyExpected ()))) // 'RSA2'
// Read RSAPUBKEY header (starts with magic)
// Ref: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-rsapubkey
let magic = reader.ReadInt32()

let byteLen, halfLen =
let bitLen = reader.ReadInt32()
if magic <> RSA_PUB_MAGIC && magic <> RSA_PRIV_MAGIC then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignRsaKeyExpected ())))

match bitLen % 16 with
| 0 -> (bitLen / 8, bitLen / 16)
| _ -> raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidBitLen ())))
let bitLen = reader.ReadInt32()
let byteLen, halfLen = (bitLen / 8, bitLen / 16)

let mutable key = RSAParameters()
key.Exponent <- reader.ReadBigInteger 4
key.Exponent <- reader.ReadBigInteger 4 // pubexp (4 bytes)
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

// IMPORTANT: Conditional reading based on Magic.
// Private fields (P, Q, DP, DQ, InverseQ, D) follow the modulus ONLY in PrivateKeyBlobs (RSA2).
// Ref: https://learn.microsoft.com/en-us/windows/win32/seccrypto/base-provider-key-blobs
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 | null) expected (name: string) =
Expand Down Expand Up @@ -259,13 +270,19 @@ let toCLRKeyBlob (rsaParameters: RSAParameters) (algId: int) : byte array =

key

let createSignature (hash: byte array) keyBlob keyType =
let createSignature (hash: byte array) keyBlob _keyType =
use rsa = RSA.Create()
rsa.ImportParameters(RSAParametersFromBlob keyBlob keyType)
rsa.ImportParameters(RSAParametersFromBlob keyBlob)

let signature =
rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)
let hashAlgName =
match hash.Length with
| 20 -> HashAlgorithmName.SHA1
| 32 -> HashAlgorithmName.SHA256
| 48 -> HashAlgorithmName.SHA384
| 64 -> HashAlgorithmName.SHA512
| _ -> HashAlgorithmName.SHA1

let signature = rsa.SignHash(hash, hashAlgName, RSASignaturePadding.Pkcs1)
signature |> Array.rev

let patchSignature (stream: Stream) (peReader: PEReader) (signature: byte array) =
Expand Down Expand Up @@ -301,24 +318,25 @@ let signStream stream keyBlob =
patchSignature stream peReader signature

let signatureSize (pk: byte array) =
if pk.Length < 25 then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidPKBlob ())))

let mutable reader = BlobReader pk
reader.ReadBigInteger 12 |> ignore // Skip CLRHeader
reader.ReadBigInteger 8 |> ignore // Skip BlobHeader
let magic = reader.ReadInt32() // Read magic

if not (magic = RSA_PRIV_MAGIC || magic = RSA_PUB_MAGIC) then // RSAPubKey.magic
raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidPKBlob ())))

let x = reader.ReadInt32() / 8
x
if (box pk |> isNull) || pk.Length < 8 + 12 then
0
else
let mutable reader = BlobReader pk
reader.Offset <- 8

let magic = reader.ReadInt32()

if magic = RSA_PUB_MAGIC || magic = RSA_PRIV_MAGIC then
let bitLen = reader.ReadInt32()
let size = bitLen / 8
(size + 7) &&& ~~~7
else
0

// Returns a CLR Format Blob public key
let getPublicKeyForKeyPair keyBlob =
use rsa = RSA.Create()
rsa.ImportParameters(RSAParametersFromBlob keyBlob KeyType.KeyPair)
rsa.ImportParameters(RSAParametersFromBlob keyBlob)
let rsaParameters = rsa.ExportParameters false
toCLRKeyBlob rsaParameters CALG_RSA_KEYX

Expand All @@ -330,8 +348,6 @@ type pubkeyOptions = byte array * bool

let signerGetPublicKeyForKeyPair (kp: keyPair) : pubkey = getPublicKeyForKeyPair kp

let signerSignatureSize (pk: pubkey) : int = signatureSize pk

let signerSignStreamWithKeyPair stream keyBlob = signStream stream keyBlob

let failWithContainerSigningUnsupportedOnThisPlatform () =
Expand All @@ -349,41 +365,30 @@ type ILStrongNameSigner =
static member OpenPublicKeyOptions kp p = PublicKeyOptionsSigner(kp, p)

static member OpenPublicKey bytes = PublicKeySigner bytes
static member OpenKeyPairFile bytes = KeyPair(bytes)

static member OpenKeyPairFile bytes = KeyPair bytes

static member OpenKeyContainer s = KeyContainer s

member s.IsFullySigned =
match s with
| PublicKeySigner _ -> false
| PublicKeyOptionsSigner pko ->
let _, usePublicSign = pko
usePublicSign
| PublicKeyOptionsSigner(_, usePublicSign) -> usePublicSign
| KeyPair _ -> true
| KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()

member s.PublicKey =
match s with
| PublicKeySigner pk -> pk
| PublicKeyOptionsSigner pko ->
let pk, _ = pko
pk
| PublicKeyOptionsSigner(pk, _) -> pk
| KeyPair kp -> signerGetPublicKeyForKeyPair kp
| KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()

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

match s with
| PublicKeySigner pk -> pkSignatureSize pk
| PublicKeyOptionsSigner pko ->
let pk, _ = pko
pkSignatureSize pk
| KeyPair kp -> pkSignatureSize (signerGetPublicKeyForKeyPair kp)
| PublicKeySigner pk
| PublicKeyOptionsSigner(pk, _) -> signatureSize pk
| KeyPair kp -> signatureSize kp
| KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()

member s.SignStream stream =
Expand Down
Loading