1- // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
1+ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
22
33module internal FSharp.Compiler.AbstractIL.StrongNameSign
44
@@ -126,9 +126,11 @@ type BlobReader =
126126 val mutable _blob : byte array
127127 val mutable _offset : int
128128 new ( blob: byte array) = { _ blob = blob; _ offset = 0 }
129-
130- member x.Offset with get() = x._ offset and set ( v ) = x._ offset <- v
131-
129+
130+ member x.Offset
131+ with get () = x._ offset
132+ and set ( v ) = x._ offset <- v
133+
132134 member x.ReadInt32 () : int =
133135 let offset = x._ offset
134136 x._ offset <- offset + 4
@@ -144,34 +146,40 @@ type BlobReader =
144146 x._ offset <- x._ offset + length
145147 arr |> Array.rev
146148
147- let RSAParametersFromBlob blob keyType =
149+ /// Decodes an RSA functional blob into RSAParameters.
150+ /// Ref: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-publickeystruc
151+ let RSAParametersFromBlob blob =
148152 let mutable reader = BlobReader blob
149153
150- let header = reader.ReadInt32()
151- if header <> 0x00000206 && header <> 0x00000207 && keyType = KeyType.KeyPair then
152- raise ( CryptographicException( getResourceString ( FSComp.SR.ilSignPrivateKeyExpected ())))
153-
154- reader.ReadInt32() |> ignore // ALG_ID
154+ // Skip PUBLICKEYSTRUC (8 bytes): bType(1), bVersion(1), reserved(2), aiKeyAlg(4)
155+ reader.ReadInt32() |> ignore
156+ reader.ReadInt32() |> ignore
155157
156- if reader.ReadInt32() <> RSA_ PRIV_ MAGIC then
157- raise ( CryptographicException( getResourceString ( FSComp.SR.ilSignRsaKeyExpected ()))) // 'RSA2'
158+ // Read RSAPUBKEY header (starts with magic)
159+ // Ref: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-rsapubkey
160+ let magic = reader.ReadInt32()
158161
159- let byteLen , halfLen =
160- let bitLen = reader.ReadInt32 ( )
162+ if magic <> RSA _ PUB _ MAGIC && magic <> RSA _ PRIV _ MAGIC then
163+ raise ( CryptographicException ( getResourceString ( FSComp.SR.ilSignRsaKeyExpected ())) )
161164
162- match bitLen % 16 with
163- | 0 -> ( bitLen / 8 , bitLen / 16 )
164- | _ -> raise ( CryptographicException( getResourceString ( FSComp.SR.ilSignInvalidBitLen ())))
165+ let bitLen = reader.ReadInt32()
166+ let byteLen , halfLen = ( bitLen / 8 , bitLen / 16 )
165167
166168 let mutable key = RSAParameters()
167- key.Exponent <- reader.ReadBigInteger 4
169+ key.Exponent <- reader.ReadBigInteger 4 // pubexp (4 bytes)
168170 key.Modulus <- reader.ReadBigInteger byteLen
169- key.P <- reader.ReadBigInteger halfLen
170- key.Q <- reader.ReadBigInteger halfLen
171- key.DP <- reader.ReadBigInteger halfLen
172- key.DQ <- reader.ReadBigInteger halfLen
173- key.InverseQ <- reader.ReadBigInteger halfLen
174- key.D <- reader.ReadBigInteger byteLen
171+
172+ // IMPORTANT: Conditional reading based on Magic.
173+ // Private fields (P, Q, DP, DQ, InverseQ, D) follow the modulus ONLY in PrivateKeyBlobs (RSA2).
174+ // Ref: https://learn.microsoft.com/en-us/windows/win32/seccrypto/base-provider-key-blobs
175+ if magic = RSA_ PRIV_ MAGIC then
176+ key.P <- reader.ReadBigInteger halfLen
177+ key.Q <- reader.ReadBigInteger halfLen
178+ key.DP <- reader.ReadBigInteger halfLen
179+ key.DQ <- reader.ReadBigInteger halfLen
180+ key.InverseQ <- reader.ReadBigInteger halfLen
181+ key.D <- reader.ReadBigInteger byteLen
182+
175183 key
176184
177185let validateRSAField ( field : byte array MaybeNull ) expected ( name : string ) =
@@ -262,13 +270,19 @@ let toCLRKeyBlob (rsaParameters: RSAParameters) (algId: int) : byte array =
262270
263271 key
264272
265- let createSignature ( hash : byte array ) keyBlob keyType =
273+ let createSignature ( hash : byte array ) keyBlob _keyType =
266274 use rsa = RSA.Create()
267- rsa.ImportParameters( RSAParametersFromBlob keyBlob keyType )
275+ rsa.ImportParameters( RSAParametersFromBlob keyBlob)
268276
269- let signature =
270- rsa.SignHash( hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)
277+ let hashAlgName =
278+ match hash.Length with
279+ | 20 -> HashAlgorithmName.SHA1
280+ | 32 -> HashAlgorithmName.SHA256
281+ | 48 -> HashAlgorithmName.SHA384
282+ | 64 -> HashAlgorithmName.SHA512
283+ | _ -> HashAlgorithmName.SHA1
271284
285+ let signature = rsa.SignHash( hash, hashAlgName, RSASignaturePadding.Pkcs1)
272286 signature |> Array.rev
273287
274288let patchSignature ( stream : Stream ) ( peReader : PEReader ) ( signature : byte array ) =
@@ -304,29 +318,37 @@ let signStream stream keyBlob =
304318 patchSignature stream peReader signature
305319
306320let signatureSize ( pk : byte array ) =
307- if pk.Length < 20 then 0
321+ if ( box pk |> isNull) || pk.Length < 8 + 12 then
322+ 0
308323 else
309- let reader = BlobReader pk
310- reader.Offset <- 12
311- let bitLen = reader.ReadInt32()
312- let modulusLength = bitLen / 8
313-
314- if modulusLength < 160 then 128 else modulusLength - 32
315- // Key signing
316- type keyContainerName = string
317- type keyPair = byte array
318- type pubkey = byte array
319- type pubkeyOptions = byte array * bool
324+ let mutable reader = BlobReader pk
325+ reader.Offset <- 8
326+
327+ let magic = reader.ReadInt32()
328+
329+ if magic = RSA_ PUB_ MAGIC || magic = RSA_ PRIV_ MAGIC then
330+ let bitLen = reader.ReadInt32()
331+ let size = bitLen / 8
332+ ( size + 7 ) &&& ~~~ 7
333+ else
334+ 0
335+
336+ let signatureSizeFromKeyPair ( keyBlob : byte array ) = signatureSize keyBlob
320337
338+ // Returns a CLR Format Blob public key
321339let getPublicKeyForKeyPair keyBlob =
322340 use rsa = RSA.Create()
323- rsa.ImportParameters( RSAParametersFromBlob keyBlob KeyType.KeyPair )
341+ rsa.ImportParameters( RSAParametersFromBlob keyBlob)
324342 let rsaParameters = rsa.ExportParameters false
325343 toCLRKeyBlob rsaParameters CALG_ RSA_ KEYX
326344
327- let signerGetPublicKeyForKeyPair ( kp : keyPair ) : pubkey = getPublicKeyForKeyPair kp
345+ // Key signing
346+ type keyContainerName = string
347+ type keyPair = byte array
348+ type pubkey = byte array
349+ type pubkeyOptions = byte array * bool
328350
329- let signerSignatureSize ( pk : pubkey ) : int = signatureSize pk
351+ let signerGetPublicKeyForKeyPair ( kp : keyPair ) : pubkey = getPublicKeyForKeyPair kp
330352
331353let signerSignStreamWithKeyPair stream keyBlob = signStream stream keyBlob
332354
@@ -345,37 +367,30 @@ type ILStrongNameSigner =
345367 static member OpenPublicKeyOptions kp p = PublicKeyOptionsSigner( kp, p)
346368
347369 static member OpenPublicKey bytes = PublicKeySigner bytes
348- static member OpenKeyPairFile bytes = KeyPair( bytes)
370+
371+ static member OpenKeyPairFile bytes = KeyPair bytes
372+
349373 static member OpenKeyContainer s = KeyContainer s
350374
351375 member s.IsFullySigned =
352376 match s with
353377 | PublicKeySigner _ -> false
354- | PublicKeyOptionsSigner pko ->
355- let _ , usePublicSign = pko
356- usePublicSign
378+ | PublicKeyOptionsSigner(_, usePublicSign) -> usePublicSign
357379 | KeyPair _ -> true
358380 | KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()
359381
360382 member s.PublicKey =
361383 match s with
362384 | PublicKeySigner pk -> pk
363- | PublicKeyOptionsSigner pko ->
364- let pk , _ = pko
365- pk
385+ | PublicKeyOptionsSigner( pk, _) -> pk
366386 | KeyPair kp -> signerGetPublicKeyForKeyPair kp
367387 | KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()
368388
369389 member s.SignatureSize =
370- let pkSignatureSize pk =
371- signerSignatureSize pk
372-
373390 match s with
374- | PublicKeySigner pk -> pkSignatureSize pk
375- | PublicKeyOptionsSigner pko ->
376- let pk , _ = pko
377- pkSignatureSize pk
378- | KeyPair kp -> pkSignatureSize ( signerGetPublicKeyForKeyPair kp)
391+ | PublicKeySigner pk
392+ | PublicKeyOptionsSigner( pk, _) -> signatureSize pk
393+ | KeyPair kp -> signatureSize kp
379394 | KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()
380395
381396 member s.SignStream stream =
0 commit comments