|
| 1 | +// Copyright (c) Microsoft Corporation. All Rights Reserved. |
| 2 | + |
| 3 | + |
| 4 | +namespace CompilerOptions.Fsc |
| 5 | + |
| 6 | +open System |
| 7 | +open System.IO |
| 8 | +open Xunit |
| 9 | +open FSharp.Test |
| 10 | +open FSharp.Test.Compiler |
| 11 | + |
| 12 | +module publicsign = |
| 13 | + |
| 14 | + /// <summary> |
| 15 | + /// Tests that --publicsign with a raw key blob (sha1full.snk) produces a non-empty PublicKeyToken. |
| 16 | + /// This test specifically exercises the Offset 8 code path in the compiler's public signing logic, |
| 17 | + /// avoiding the KeyPair/Offset 20 path, by using --publicsign --keyfile with a raw SNK file. |
| 18 | + /// </summary> |
| 19 | + [<Fact>] |
| 20 | + let ``--publicsign with raw key blob (sha1full.snk) produces a non-empty PublicKeyToken`` () = |
| 21 | + let source = |
| 22 | + """ |
| 23 | +module TestModule |
| 24 | +let x = 42 |
| 25 | +""" |
| 26 | + |
| 27 | + // Resolve the path to sha1full.snk relative to this source file's directory |
| 28 | + // Path: tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc -> tests/fsharp/core/signedtests/sha1full.snk |
| 29 | + let snkPath: string = |
| 30 | + Path.Combine(__SOURCE_DIRECTORY__, "..", "..", "..", "..", "fsharp", "core", "signedtests", "sha1full.snk") |
| 31 | + |
| 32 | + // Compile with --publicsign+ and --keyfile to exercise the Offset 8 code path |
| 33 | + let result = |
| 34 | + source |
| 35 | + |> FSharp |
| 36 | + |> asLibrary |
| 37 | + |> withFileName "PublicSignTest.fs" |
| 38 | + |> withOptions ["--publicsign+"; sprintf "--keyfile:%s" snkPath] |
| 39 | + |> compile |
| 40 | + |
| 41 | + result |> shouldSucceed |> ignore |
| 42 | + |
| 43 | + // Safely extract the output DLL path using pattern matching |
| 44 | + let outputDll: string = |
| 45 | + match result.OutputPath with |
| 46 | + | Some path -> path |
| 47 | + | None -> failwith "Compilation did not produce an output DLL" |
| 48 | + |
| 49 | + // Read the compiled DLL bytes for verification |
| 50 | + let dllBytes: byte[] = File.ReadAllBytes(outputDll) |
| 51 | + |
| 52 | + // RSA magic number patterns: RSA1 = 0x52 0x53 0x41 0x31, RSA2 = 0x52 0x53 0x41 0x32 |
| 53 | + // These indicate that RSA key material was embedded in the assembly |
| 54 | + let rsa1Magic: byte[] = [| 0x52uy; 0x53uy; 0x41uy; 0x31uy |] |
| 55 | + let rsa2Magic: byte[] = [| 0x52uy; 0x53uy; 0x41uy; 0x32uy |] |
| 56 | + |
| 57 | + /// <summary> |
| 58 | + /// Searches for RSA magic bytes in the byte array. |
| 59 | + /// Returns true if the magic pattern is found, indicating RSA key material is present. |
| 60 | + /// </summary> |
| 61 | + let containsRSAMagic (data: byte[]) (magic: byte[]): bool = |
| 62 | + if data.Length < magic.Length then |
| 63 | + false |
| 64 | + else |
| 65 | + let mutable found = false |
| 66 | + for i in 0 .. (data.Length - magic.Length) do |
| 67 | + if not found && |
| 68 | + data.[i] = magic.[0] && |
| 69 | + data.[i + 1] = magic.[1] && |
| 70 | + data.[i + 2] = magic.[2] && |
| 71 | + data.[i + 3] = magic.[3] then |
| 72 | + found <- true |
| 73 | + found |
| 74 | + |
| 75 | + // Verify that the compiled DLL contains RSA magic bytes, confirming the public key blob was embedded |
| 76 | + let hasRSAMagic: bool = |
| 77 | + containsRSAMagic dllBytes rsa1Magic || containsRSAMagic dllBytes rsa2Magic |
| 78 | + |
| 79 | + Assert.True( |
| 80 | + hasRSAMagic, |
| 81 | + "Compiled DLL should contain RSA magic bytes (RSA1 or RSA2) indicating public key blob was embedded by compiler with --publicsign" |
| 82 | + ) |
0 commit comments