3
3
4
4
#nullable disable
5
5
6
- using System . Buffers . Binary ;
7
6
using System . Diagnostics ;
8
7
using System . Reflection . PortableExecutable ;
9
8
using System . Text . RegularExpressions ;
@@ -80,40 +79,6 @@ public void It_builds_a_runnable_apphost_by_default(string targetFramework)
80
79
. HaveStdOutContaining ( "Hello World!" ) ;
81
80
}
82
81
83
- [ PlatformSpecificTheory ( TestPlatforms . OSX ) ]
84
- [ InlineData ( "netcoreapp3.1" ) ]
85
- [ InlineData ( "net5.0" ) ]
86
- [ InlineData ( ToolsetInfo . CurrentTargetFramework ) ]
87
- public void It_can_disable_codesign_if_opt_out ( string targetFramework )
88
- {
89
- var testAsset = _testAssetsManager
90
- . CopyTestAsset ( "HelloWorld" , identifier : targetFramework )
91
- . WithSource ( )
92
- . WithTargetFramework ( targetFramework ) ;
93
-
94
- var buildCommand = new BuildCommand ( testAsset ) ;
95
- buildCommand
96
- . Execute ( new string [ ] {
97
- "/p:_EnableMacOSCodeSign=false;ProduceReferenceAssembly=false" ,
98
- } )
99
- . Should ( )
100
- . Pass ( ) ;
101
-
102
- var outputDirectory = buildCommand . GetOutputDirectory ( targetFramework ) ;
103
- var appHostFullPath = Path . Combine ( outputDirectory . FullName , "HelloWorld" ) ;
104
-
105
- // Check that the apphost was not signed
106
- var codesignPath = @"/usr/bin/codesign" ;
107
- new RunExeCommand ( Log , codesignPath , new string [ ] { "-d" , appHostFullPath } )
108
- . Execute ( )
109
- . Should ( )
110
- . Fail ( )
111
- . And
112
- . HaveStdErrContaining ( $ "{ appHostFullPath } : code object is not signed at all") ;
113
-
114
- outputDirectory . Should ( ) . OnlyHaveFiles ( GetExpectedFilesFromBuild ( testAsset , targetFramework ) ) ;
115
- }
116
-
117
82
[ PlatformSpecificTheory ( TestPlatforms . OSX ) ]
118
83
[ InlineData ( "netcoreapp3.1" , "win-x64" ) ]
119
84
[ InlineData ( "net5.0" , "win-x64" ) ]
@@ -154,20 +119,35 @@ public void It_does_not_try_to_codesign_non_osx_app_hosts(string targetFramework
154
119
}
155
120
156
121
[ Theory ]
157
- [ InlineData ( "net6.0" , "osx-x64" ) ]
158
- [ InlineData ( "net6.0" , "osx-arm64" ) ]
159
- [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-x64" ) ]
160
- [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-arm64" ) ]
161
- public void It_codesigns_an_app_targeting_osx ( string targetFramework , string rid )
122
+ [ InlineData ( "net8.0" , "osx-x64" , true ) ]
123
+ [ InlineData ( "net8.0" , "osx-arm64" , true ) ]
124
+ [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-x64" , true ) ]
125
+ [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-arm64" , true ) ]
126
+ [ InlineData ( "net8.0" , "osx-x64" , false ) ]
127
+ [ InlineData ( "net8.0" , "osx-arm64" , false ) ]
128
+ [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-x64" , false ) ]
129
+ [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-arm64" , false ) ]
130
+ [ InlineData ( "net8.0" , "osx-x64" , null ) ]
131
+ [ InlineData ( "net8.0" , "osx-arm64" , null ) ]
132
+ [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-x64" , null ) ]
133
+ [ InlineData ( ToolsetInfo . CurrentTargetFramework , "osx-arm64" , null ) ]
134
+ public void It_codesigns_an_app_targeting_osx ( string targetFramework , string rid , bool ? enableMacOSCodesign )
162
135
{
136
+ const bool CodesignsByDefault = true ;
163
137
const string testAssetName = "HelloWorld" ;
164
138
var testAsset = _testAssetsManager
165
139
. CopyTestAsset ( testAssetName , identifier : targetFramework )
166
140
. WithSource ( )
167
141
. WithTargetFramework ( targetFramework ) ;
168
142
169
143
var buildCommand = new BuildCommand ( testAsset ) ;
144
+
170
145
var buildArgs = new List < string > ( ) { $ "/p:RuntimeIdentifier={ rid } " } ;
146
+ if ( enableMacOSCodesign . HasValue )
147
+ {
148
+ buildArgs . Add ( $ "/p:_EnableMacOSCodeSign={ enableMacOSCodesign . Value } ") ;
149
+ }
150
+
171
151
buildCommand
172
152
. Execute ( buildArgs . ToArray ( ) )
173
153
. Should ( )
@@ -176,22 +156,14 @@ public void It_codesigns_an_app_targeting_osx(string targetFramework, string rid
176
156
var outputDirectory = buildCommand . GetOutputDirectory ( targetFramework : targetFramework , runtimeIdentifier : rid ) ;
177
157
var appHostFullPath = Path . Combine ( outputDirectory . FullName , testAssetName ) ;
178
158
179
- // Check that the apphost is signed
180
- HasMachOSignatureLoadCommand ( new FileInfo ( appHostFullPath ) ) . Should ( ) . BeTrue ( ) ;
181
- // When on a Mac, use the codesign tool to verify the signature as well
159
+ // Check that the apphost is signed if expected
160
+ var shouldBeSigned = enableMacOSCodesign ?? CodesignsByDefault ;
161
+ MachOSignature . HasMachOSignatureLoadCommand ( new FileInfo ( appHostFullPath ) ) . Should ( ) . Be ( shouldBeSigned , $ "The app host should { ( shouldBeSigned ? "" : "not " ) } have a Mach-O signature load command." ) ;
182
162
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) )
183
163
{
184
- var codesignPath = @"/usr/bin/codesign" ;
185
- new RunExeCommand ( Log , codesignPath , [ "-s" , "-" , appHostFullPath ] )
186
- . Execute ( )
187
- . Should ( )
188
- . Fail ( )
189
- . And
190
- . HaveStdErrContaining ( $ "{ appHostFullPath } : is already signed") ;
191
- new RunExeCommand ( Log , codesignPath , [ "-v" , appHostFullPath ] )
192
- . Execute ( )
164
+ MachOSignature . HasValidMachOSignature ( new FileInfo ( appHostFullPath ) , Log )
193
165
. Should ( )
194
- . Pass ( ) ;
166
+ . Be ( shouldBeSigned , $ "The app host should have a valid Mach-O signature for { rid } ." ) ;
195
167
}
196
168
}
197
169
@@ -487,62 +459,5 @@ private static bool IsPE32(string path)
487
459
return reader . PEHeaders . PEHeader . Magic == PEMagic . PE32 ;
488
460
}
489
461
}
490
-
491
- // Reads the Mach-O load commands and returns true if an LC_CODE_SIGNATURE command is found, otherwise returns false
492
- static bool HasMachOSignatureLoadCommand ( FileInfo file )
493
- {
494
- /* Mach-O files have the following structure:
495
- * 32 byte header beginning with a magic number and info about the file and load commands
496
- * A series of load commands with the following structure:
497
- * - 4-byte command type
498
- * - 4-byte command size
499
- * - variable length command-specific data
500
- */
501
- const uint LC_CODE_SIGNATURE = 0x1D ;
502
- using ( var stream = file . OpenRead ( ) )
503
- {
504
- // Read the MachO magic number to determine endianness
505
- Span < byte > eightByteBuffer = stackalloc byte [ 8 ] ;
506
- stream . ReadExactly ( eightByteBuffer ) ;
507
- // Determine if the magic number is in the same or opposite endianness as the runtime
508
- bool reverseEndinanness = BitConverter . ToUInt32 ( eightByteBuffer . Slice ( 0 , 4 ) ) switch
509
- {
510
- 0xFEEDFACF => false ,
511
- 0xCFFAEDFE => true ,
512
- _ => throw new InvalidOperationException ( "Not a 64-bit Mach-O file" )
513
- } ;
514
- // 4-byte value at offset 16 is the number of load commands
515
- // 4-byte value at offset 20 is the size of the load commands
516
- stream . Position = 16 ;
517
- ReadUInts ( stream , eightByteBuffer , out uint loadCommandsCount , out uint loadCommandsSize ) ;
518
- // Mach-0 64 byte headers are 32 bytes long, and the first load command will be right after
519
- stream . Position = 32 ;
520
- bool hasSignature = false ;
521
- for ( int commandIndex = 0 ; commandIndex < loadCommandsCount ; commandIndex ++ )
522
- {
523
- ReadUInts ( stream , eightByteBuffer , out uint commandType , out uint commandSize ) ;
524
- if ( commandType == LC_CODE_SIGNATURE )
525
- {
526
- hasSignature = true ;
527
- }
528
- stream . Position += commandSize - eightByteBuffer . Length ;
529
- }
530
- Debug . Assert ( stream . Position == loadCommandsSize + 32 ) ;
531
- return hasSignature ;
532
-
533
- void ReadUInts ( Stream stream , Span < byte > buffer , out uint val1 , out uint val2 )
534
- {
535
- stream . ReadExactly ( buffer ) ;
536
- val1 = BitConverter . ToUInt32 ( buffer . Slice ( 0 , 4 ) ) ;
537
- val2 = BitConverter . ToUInt32 ( buffer . Slice ( 4 , 4 ) ) ;
538
- if ( reverseEndinanness )
539
- {
540
- val1 = BinaryPrimitives . ReverseEndianness ( val1 ) ;
541
- val2 = BinaryPrimitives . ReverseEndianness ( val2 ) ;
542
- }
543
- }
544
- }
545
- }
546
-
547
462
}
548
463
}
0 commit comments