Skip to content
Merged
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
10 changes: 9 additions & 1 deletion EsrpScan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@ parameters:
default: "$(Pipeline.Workspace)"
- name: "pattern"
default: "*.dll,*.exe"
- name: "scanningService"
default: "pwshEsrpScanning"

steps:
- task: UseDotNet@2
displayName: 'Install .NET Core sdk 2.x for ESRP'
inputs:
version: 2.x

- pwsh: |
Write-Verbose -Verbose "scanPath = '${{ parameters.scanPath }}'"
Write-Verbose -Verbose "pattern = '${{ parameters.pattern }}'"
Write-Verbose -Verbose "scanningService = '${{ parameters.scanningService }}'"
displayName: Log parameters

- task: SFP.build-tasks.custom-build-task-2.EsrpMalwareScanning@1
displayName: 'Malware Scanning'
inputs:
ConnectedServiceName: pwshEsrpScanning
ConnectedServiceName: ${{ parameters.scanningService }}
FolderPath: ${{ parameters.scanPath }}
Pattern: ${{ parameters.pattern }}
UseMinimatch: true
Expand Down
28 changes: 28 additions & 0 deletions EsrpSign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ parameters:
default: "auto"
- name: "alwaysCopy"
default: "False"
- name: "useCustomEsrpJson"
default: "false"
- name: "verifySignature"
default: "false"
- name: "pageHash"
default: "true"

steps:
- task: UseDotNet@2
Expand All @@ -27,6 +33,18 @@ steps:
Write-Verbose -Verbose "signOutputPath = '${{ parameters.signOutputPath }}'"
Write-Verbose -Verbose "certificateId = '${{ parameters.certificateId }}'"
Write-Verbose -Verbose "pattern = '${{ parameters.pattern }}'"
Write-Verbose -Verbose "useMinimatch = '${{ parameters.useMinimatch }}'"
Write-Verbose -Verbose "signingService = '${{ parameters.signingService }}'"
Write-Verbose -Verbose "shouldSign = '${{ parameters.shouldSign }}'"
Write-Verbose -Verbose "alwaysCopy = '${{ parameters.alwaysCopy }}'"
Write-Verbose -Verbose "useCustomEsrpJson = '${{ parameters.useCustomEsrpJson }}'"
Write-Verbose -Verbose "verifySignature = '${{ parameters.verifySignature }}'"
Write-Verbose -Verbose "pageHash = '${{ parameters.pageHash }}'"

if (('${{ parameters.useCustomEsrpJson }}' -ne 'false') -and ('${{ parameters.certificateId }}' -ne ''))
{
throw "Only one of useCustomEsrpJson and certificateId must be set!"
}
displayName: Log parameters

- pwsh: |
Expand All @@ -52,6 +70,8 @@ steps:
signOutputPath: ${{ parameters.signOutputPath }}
pattern: ${{ parameters.pattern }}
certificateId: ${{ parameters.certificateId }}
verifySignature: ${{ parameters.verifySignature }}
pageHash: ${{ parameters.pageHash }}

- ${{ if eq(parameters.certificateId , 'CP-231522') }}:
- template: template-compliance/authenticode-sign.yml
Expand All @@ -60,6 +80,8 @@ steps:
signOutputPath: ${{ parameters.signOutputPath }}
pattern: ${{ parameters.pattern }}
certificateId: ${{ parameters.certificateId }}
verifySignature: ${{ parameters.verifySignature }}
pageHash: ${{ parameters.pageHash }}

- ${{ if eq(parameters.certificateId, 'CP-401405') }}:
- template: template-compliance/nuget-sign.yml
Expand All @@ -68,6 +90,7 @@ steps:
signOutputPath: ${{ parameters.signOutputPath }}
pattern: ${{ parameters.pattern }}
certificateId: ${{ parameters.certificateId }}
verifySignature: ${{ parameters.verifySignature }}

- ${{ if or(eq(parameters.certificateId, 'CP-450779-Pgp'),eq(parameters.certificateId, 'CP-450778-Pgp')) }}:
- template: template-compliance/pgp-sign.yml
Expand All @@ -83,6 +106,11 @@ steps:
pattern: ${{ parameters.pattern }}
certificateId: ${{ parameters.certificateId }}

- ${{ if eq(parameters.useCustomEsrpJson, 'true') }}:
- template: template-compliance/custom-sign.yml
parameters:
signOutputPath: ${{ parameters.signOutputPath }}

- pwsh: |
Write-Verbose -Verbose "EsrpJson = '${env:EsrpJson}'"
displayName: Log Json
Expand Down
115 changes: 114 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ Details can be found in the PowerShell Maintainers teams channel's Wiki tab.
parameters:
# the folder which contains the binaries to sign
buildOutputPath: $(signSrcPath)
# the location to put the signed output
# the location to put the signed output.
# Note, All files in "buildOutputPath" are copied to "signOutputPath" not just ones matching the "pattern".
signOutputPath: $(signOutPath)
# the certificate ID to use
certificateId: "CP-230012"
Expand All @@ -86,6 +87,29 @@ Details can be found in the PowerShell Maintainers teams channel's Wiki tab.
# decides if the task should use minimatch for the pattern matching.
# https://github.com/isaacs/minimatch#features
useMinimatch: false
# If "true", use a custom JSON string for ESRP signing. Defaults to "false".
useCustomEsrpJson: false
# If "true", ESRP will automatically verify your files are signed properly (eg signtool /verify).
# Only supported for authenticode & nuget signing.
# Defaults to "false".
verifySignature: false
# If "true", ESRP will page hash sign your files.
# Only supported for authenticode signing.
# Defaults to "true".
pageHash: true
# If "true", ESRP will be called to sign your files.
# If "false", ESRP is not called, files will not be signed.
# If "auto", ESRP is called if and only certain build conditions are met.
# Defaults to "auto".
shouldSign: 'auto'
# If "true", your files are always copied to signOutputPath even if ESRP is not called to sign the files.
# Useful to set to true if you want your build pipeline to behave as close to 'normal' as possible when testing and not signing.
# Defaults to "false".
alwaysCopy: false
# The name of the Azure DevOps Service connection you configured for ESRP Signing.
# Defaults to "pwshSigning".
signingService: 'pwshSigning'

```

### ESRP Authenticode minimatch example
Expand Down Expand Up @@ -158,6 +182,76 @@ This example signs `pkg` files recursively, using minimatch.
**\*.pkg
useMinimatch: true
```

### ESRP custom signing JSON example
1. Set the build variable ESRP_TEMPLATE_CUSTOM_JSON to your desired ESRP JSON string.
2. Call EsrpSign.yml@ComplianceRepo with certificateId: "" and useCustomEsrpJson: true.

```yaml
- pwsh: |
[string] $SigningServer = '$(SigningServer)'
Write-Verbose "SigningServer - $SigningServer" -Verbose

$esrpParameters = @{
OpusName = "Microsoft"
OpusInfo = "http://www.microsoft.com"
FileDigest = "/fd sha256"
TimeStamp = "/tr ""$SigningServer"" /td sha256"
}

$esrp = @(
@{
KeyCode = "Dynamic"
CertTemplateName = "WINMSAPP1ST"
CertSubjectName = "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
operationCode = "SigntoolSign"
Parameters = $esrpParameters
ToolName = "sign"
ToolVersion = "1.0"},
@{
KeyCode = "Dynamic"
CertTemplateName = "WINMSAPP1ST"
CertSubjectName = "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
OperationCode = "SigntoolVerify"
ToolName = "sign"
ToolVersion = "1.0"
}
)

$vstsCommandString = "vso[task.setvariable variable=ESRP_TEMPLATE_CUSTOM_JSON][$($esrp | ConvertTo-Json -Compress)]"
Write-Verbose -Message ("sending " + $vstsCommandString) -Verbose
Write-Host "##$vstsCommandString"
displayName: Generate app signing JSON

- template: EsrpSign.yml@ComplianceRepo
parameters:
buildOutputPath: $(signSrcPath)
signOutputPath: $(signOutPath)
# Explicitly set to "" for custom string
certificateId: ""
pattern: '*.msix'
useMinimatch: false
# Use ESRP_TEMPLATE_CUSTOM_JSON as custom string
useCustomEsrpJson: true
```

### ESRP Custom Signing Service Connection Example

This example uses a custom signing (Azure DevOps) service connection name.

```yaml
- template: EsrpSign.yml@ComplianceRepo
parameters:
buildOutputPath: $(signSrcPath)
signOutputPath: $(signOutPath)
certificateId: "CP-230012"
pattern: '*.dll'
# The name of the Azure DevOps Service connection you configured for ESRP Signing.
# Defaults to "pwshSigning".
signingService: 'FactoryOrchestratorSigning'

```

## ESRP Malware Scanning Template Overview

** Requires on-boarding, see the wiki in the internal PowerShell Maintainers teams channel **
Expand Down Expand Up @@ -186,4 +280,23 @@ scanning on each upload will allow us to detect when any malware was introduced.
**\*.rpm
**\*.deb
**\*.tar.gz
# The name of the Azure DevOps Service connection you configured for ESRP Malware Scanning.
# Defaults to "pwshEsrpScanning".
scanningService: 'pwshEsrpScanning'
```

### ESRP Scanning Custom Service Example

This example uses a custom ESRP malware scanning (Azure DevOps) service name.

```yaml
- template: EsrpSign.yml@ComplianceRepo
parameters:
buildOutputPath: $(signSrcPath)
signOutputPath: $(signOutPath)
certificateId: "CP-230012"
pattern: |
**\*.dll
scanningService: 'FactoryOrchestratorScanning'

```
61 changes: 35 additions & 26 deletions template-compliance/authenticode-sign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ parameters:
default: "*.dll,*.exe"
- name: "certificateId"
default: "CP-230012"
- name: "verifySignature"
default: "false"
- name: "pageHash"
default: "true"

steps:
- pwsh: |
Expand All @@ -18,38 +22,43 @@ steps:
[string] $SigningServer = '$(SigningServer)'
Write-Verbose "SigningServer - $SigningServer" -Verbose

$esrpParameters = @(
@{
ParameterName = "OpusName"
ParameterValue = "Microsoft"
$esrpParameters = @{
OpusName = "Microsoft"
OpusInfo = "http://www.microsoft.com"
FileDigest = "/fd sha256"
TimeStamp = "/tr ""$SigningServer"" /td sha256"
}
@{
ParameterName = "OpusInfo"
ParameterValue = "http://www.microsoft.com"
}
@{
ParameterName = "PageHash"
ParameterValue = "/NPH"
}
@{
ParameterName = "FileDigest"
ParameterValue = "/fd sha256"
}
@{
ParameterName = "TimeStamp"
ParameterValue = "/tr ""$SigningServer"" /td sha256"

if ("${{ parameters.pageHash }}" -eq "true")
{
$esrpParameters.Add("PageHash", "/NPH")
}
)

$esrp = @(@{
keyCode = $CertificateId
operationSetCode = "SigntoolSign"
parameters = $esrpParameters
toolName = "signtool.exe"
toolVersion = "6.2.9304.0"
keyCode = $CertificateId
operationCode = "SigntoolSign"
parameters = $esrpParameters
toolName = "signtool.exe"
toolVersion = "6.2.9304.0"
})

$vstsCommandString = "vso[task.setvariable variable=$VariableName][$($esrp | ConvertTo-Json -Compress)]"
if ("${{ parameters.verifySignature }}" -eq "true")
{
$esrp += @{
keyCode = $CertificateId
operationCode = "SigntoolVerify"
toolName = "signtool.exe"
toolVersion = "6.2.9304.0"
}
}

$jsonString = $($esrp | ConvertTo-Json -Depth 99 -Compress)
if ($esrp.Count -eq 1)
{
$jsonString = "[$jsonString]"
}

$vstsCommandString = "vso[task.setvariable variable=$VariableName]$jsonString"
Write-Verbose -Message ("sending " + $vstsCommandString) -Verbose
Write-Host "##$vstsCommandString"

Expand Down
21 changes: 21 additions & 0 deletions template-compliance/custom-sign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
parameters:
- name: "signOutputPath"
default: "$(Build.ArtifactStagingDirectory)\\signed"

steps:
- pwsh: |
if ($null -eq $env:ESRP_TEMPLATE_CUSTOM_JSON)
{
Write-Error "ESRP_TEMPLATE_CUSTOM_JSON variable must be set!"
}
[string] $VariableName = "EsrpJson"
$vstsCommandString = "vso[task.setvariable variable=$VariableName]$env:ESRP_TEMPLATE_CUSTOM_JSON"
Write-Verbose -Message ("sending " + $vstsCommandString) -Verbose
Write-Host "##$vstsCommandString"
$vstsCommandString = "vso[task.setvariable variable=GDN_CODESIGN_TARGETDIRECTORY]${{ parameters.signOutputPath }}"
Write-Verbose -Message ("sending " + $vstsCommandString) -Verbose
Write-Host "##$vstsCommandString"
displayName: Generate custom signing JSON
condition: and(succeeded(), eq(variables['ESRP_TEMPLATE_SHOULD_SIGN'], 'True'))
34 changes: 25 additions & 9 deletions template-compliance/nuget-sign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ parameters:
default: "*.nupkg"
- name: "certificateId"
default: "CP-401405"
- name: "verifySignature"
default: "false"

steps:
- pwsh: |
Expand All @@ -15,16 +17,30 @@ steps:

[string] $VariableName = "EsrpJson"

$esrp = @(
@{
keyCode = $CertificateId
operationSetCode = "NuGetSign"
toolName = "sign"
toolVersion = "1.0"
}
)
$esrp = @(@{
keyCode = $CertificateId
operationSetCode = "NuGetSign"
toolName = "sign"
toolVersion = "1.0"
})

$vstsCommandString = "vso[task.setvariable variable=$VariableName][$($esrp | ConvertTo-Json -Compress)]"
if ("${{ parameters.verifySignature }}" -eq "true")
{
$esrp += @{
keyCode = $CertificateId
operationSetCode = "NuGetVerify"
toolName = "sign"
toolVersion = "1.0"
}
}

$jsonString = $($esrp | ConvertTo-Json -Depth 99 -Compress)
if ($esrp.Count -eq 1)
{
$jsonString = "[$jsonString]"
}

$vstsCommandString = "vso[task.setvariable variable=$VariableName]$jsonString"
Write-Verbose -Message ("sending " + $vstsCommandString) -Verbose
Write-Host "##$vstsCommandString"

Expand Down