diff --git a/CODE_SIGNING.md b/CODE_SIGNING.md new file mode 100644 index 0000000..18f437c --- /dev/null +++ b/CODE_SIGNING.md @@ -0,0 +1,100 @@ +# Code Signing Configuration + +## Overview + +AsyncAwaitBestPractices supports Windows Authenticode code signing to ensure compatibility with Windows 11 Smart App Control. This feature helps prevent the security warnings that occur when Smart App Control is enabled. + +## How It Works + +### Build Process +- Code signing is automatically enabled during Release builds when running on Windows +- Signing occurs after the build completes for each target framework +- The signing process is conditional and won't break builds when certificates are not available + +### Requirements +- Valid Windows code signing certificate (`.pfx` file) +- `signtool.exe` available in PATH (included with Windows SDK) +- Windows build environment (signing is skipped on other platforms) + +## Configuration + +### Environment Variables +Set these environment variables to enable code signing: + +```bash +WINDOWS_CODESIGN_CERTIFICATE=path/to/your/certificate.pfx +WINDOWS_CODESIGN_PASSWORD=your-certificate-password +``` + +### MSBuild Properties +Alternatively, you can set these MSBuild properties: + +```xml + + path/to/your/certificate.pfx + your-certificate-password + http://timestamp.digicert.com + +``` + +## Azure DevOps Pipeline + +The Azure DevOps pipeline is configured to automatically sign assemblies when: +1. A secure file named by `WINDOWS_CODESIGN_CERTIFICATE_NAME` variable is available +2. The `WINDOWS_CODESIGN_PASSWORD` variable is set +3. The build is running on Windows + +### Pipeline Setup +1. Upload your code signing certificate as a secure file in Azure DevOps +2. Set the `WINDOWS_CODESIGN_CERTIFICATE_NAME` variable to the name of your secure file +3. Set the `WINDOWS_CODESIGN_PASSWORD` variable as a secret variable + +## Certificate Requirements + +### For Windows 11 Smart App Control +- Certificate must be issued by a trusted Certificate Authority +- Certificate must be valid for code signing +- Certificate should have timestamping enabled for long-term validity + +### Recommended Certificate Authorities +- DigiCert +- Sectigo (formerly Comodo) +- GlobalSign +- Entrust + +## Troubleshooting + +### Common Issues +- **Certificate not found**: Ensure the certificate path is correct and the file exists +- **Invalid password**: Verify the certificate password is correct +- **Timestamp server unavailable**: The build will retry timestamping, or you can change the timestamp server URL +- **signtool not found**: Install Windows SDK or ensure signtool.exe is in your PATH + +### Local Development +Code signing is disabled by default for local development. To test signing locally: +1. Obtain a code signing certificate +2. Set the required environment variables +3. Build in Release configuration on Windows + +## Security Considerations + +- **Never commit certificates to source control** +- **Use secure storage for certificates and passwords** +- **Regularly update certificates before expiration** +- **Use separate certificates for different environments if needed** + +## Verification + +### Checking if an Assembly is Signed +You can verify if an assembly is signed using: + +```powershell +# PowerShell +Get-AuthenticodeSignature "AsyncAwaitBestPractices.dll" + +# Command Prompt +signtool verify /pa "AsyncAwaitBestPractices.dll" +``` + +### Properties Dialog +Right-click the DLL file and select "Properties" → "Digital Signatures" tab to view signature information. \ No newline at end of file diff --git a/README.md b/README.md index ee86990..c160198 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,17 @@ Available on NuGet: https://www.nuget.org/packages/AsyncAwaitBestPractices/ - `AsyncValueCommand : IAsyncValueCommand` - [Usage instructions](#asyncawaitbestpracticesmvvm-2) +## Security & Code Signing + +AsyncAwaitBestPractices supports **Windows Authenticode code signing** for compatibility with Windows 11 Smart App Control. This ensures that applications using the library won't be blocked by enhanced security features. + +- **Automatic signing** in CI/CD pipeline when certificates are available +- **Conditional signing** - doesn't break local development +- **Platform detection** - only signs on Windows +- **Secure certificate storage** using Azure DevOps secure files + +For detailed setup instructions, see [CODE_SIGNING.md](CODE_SIGNING.md). + ## Setup ### AsyncAwaitBestPractices diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3cea036..dc374c9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -172,15 +172,29 @@ jobs: summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml' failIfCoverageEmpty: true + # Download code signing certificate + - task: DownloadSecureFile@1 + displayName: 'Download Windows Code Signing Certificate' + condition: and(eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['WINDOWS_CODESIGN_CERTIFICATE_NAME'], ''), ne(variables['WINDOWS_CODESIGN_PASSWORD'], '')) # Only run this step on Windows and when certificate and password are available + inputs: + secureFile: $(WINDOWS_CODESIGN_CERTIFICATE_NAME) + name: codesigncert + - task: CmdLine@2 displayName: 'Pack AsyncAwaitBestPractices NuGet' inputs: script: 'dotnet pack $(PathToAsyncAwaitBestPracticesCsproj) -c Release -p:PackageVersion=$(NugetPackageVersion)' + env: + WINDOWS_CODESIGN_CERTIFICATE: $(codesigncert.secureFilePath) + WINDOWS_CODESIGN_PASSWORD: $(WINDOWS_CODESIGN_PASSWORD) - task: CmdLine@2 displayName: 'Pack AsyncAwaitBestPractices.MVVM NuGet' inputs: script: 'dotnet pack $(PathToAsyncAwaitBestPracticesMVVMCsproj) -c Release -p:PackageVersion=$(NugetPackageVersion)' + env: + WINDOWS_CODESIGN_CERTIFICATE: $(codesigncert.secureFilePath) + WINDOWS_CODESIGN_PASSWORD: $(WINDOWS_CODESIGN_PASSWORD) # check vulnerabilities - powershell: | diff --git a/src/AsyncAwaitBestPractices.MVVM/AsyncAwaitBestPractices.MVVM.csproj b/src/AsyncAwaitBestPractices.MVVM/AsyncAwaitBestPractices.MVVM.csproj index fbf411f..b83bb94 100644 --- a/src/AsyncAwaitBestPractices.MVVM/AsyncAwaitBestPractices.MVVM.csproj +++ b/src/AsyncAwaitBestPractices.MVVM/AsyncAwaitBestPractices.MVVM.csproj @@ -52,6 +52,11 @@ Debug;Release false true + + + $(WINDOWS_CODESIGN_CERTIFICATE) + $(WINDOWS_CODESIGN_PASSWORD) + http://timestamp.digicert.com @@ -71,4 +76,12 @@ + + + + + + \ No newline at end of file diff --git a/src/AsyncAwaitBestPractices/AsyncAwaitBestPractices.csproj b/src/AsyncAwaitBestPractices/AsyncAwaitBestPractices.csproj index 9d97bf7..f17bbdd 100644 --- a/src/AsyncAwaitBestPractices/AsyncAwaitBestPractices.csproj +++ b/src/AsyncAwaitBestPractices/AsyncAwaitBestPractices.csproj @@ -53,6 +53,11 @@ Debug;Release false true + + + $(WINDOWS_CODESIGN_CERTIFICATE) + $(WINDOWS_CODESIGN_PASSWORD) + http://timestamp.digicert.com @@ -82,4 +87,12 @@ + + + + + + \ No newline at end of file