Skip to content

Instantly share code, notes, and snippets.

@dotMorten
Created August 24, 2019 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dotMorten/293c74dcb956d8b44edfc7317d5f1954 to your computer and use it in GitHub Desktop.
Save dotMorten/293c74dcb956d8b44edfc7317d5f1954 to your computer and use it in GitHub Desktop.
// Requires the following nuget packages:
// NuGet.Packaging
// OpenVsixSignTool.Core
// And built on .NET Framework 4.7.2+
using NuGet.Packaging;
using NuGet.Packaging.Signing;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
namespace VerifySignatures
{
class Program
{
static int Main(string[] args)
{
bool quietMode = false;
int returncode = 0;
string path = args[0];
if (args.Contains("-q"))
quietMode = true;
var opc = OpenVsixSignTool.Core.OpcPackage.Open(path);
var signatures = opc.GetSignatures().ToList();
if(signatures.Count == 0)
{
WriteLine("ERROR: VSIX not signed: " + path, true);
returncode++;
}
else
{
if (!quietMode) WriteLine("VSIX is signed: " + path);
foreach (var signature in signatures)
{
//TODO: Verify signature is actually valid
}
}
var trustProviders = new ISignatureVerificationProvider[]
{
new IntegrityVerificationProvider(),
new SignatureTrustAndValidityVerificationProvider(),
new AllowListVerificationProvider(
new VerificationAllowListEntry[] { },
requireNonEmptyAllowList: false,
noMatchErrorMessage: "Strings.Error_NoMatchingCertificate")
};
PackageSignatureVerifier verifier = new PackageSignatureVerifier(trustProviders);
var verifierSettings = SignedPackageVerifierSettings.GetVerifyCommandDefaultPolicy();
foreach (var item in opc.GetParts())
{
var uri = item.Uri;
if(uri.OriginalString.EndsWith(".nupkg"))
{
// Verify nuget
using (var nuget = new StreamedFile(item)) // item.Open())
{
using (var package = new PackageArchiveReader(nuget.Filename))
{
bool parentWritten = false;
VerifySignaturesResult result;
try
{
result = verifier.VerifySignaturesAsync(package, verifierSettings, CancellationToken.None).Result;
}
catch(InvalidDataException)
{
returncode++;
WriteLine($"{uri} - ERROR: NuGet package invalid", true);
parentWritten = true;
continue;
}
if(!result.IsSigned)
{
returncode++;
WriteLine($"{uri} - ERROR: NuGet not signed", true);
parentWritten = true;
}
else if(!result.IsValid)
{
returncode++;
WriteLine($"{uri} - ERROR: NuGet Signature not valid", true);
parentWritten = true;
}
else
{
if (!quietMode)
{
WriteLine($"{uri} - OK");
parentWritten = true;
}
}
foreach(var file in package.GetFiles())
{
if (!file.ToLower().EndsWith(".dll"))
continue;
using (var s = package.GetStream(file))
{
using (var f = new StreamedFile(s))
{
try
{
using (var cert = X509Certificate.CreateFromSignedFile(f.Filename))
{
if (!quietMode) Console.WriteLine($"\t{file} - OK");
}
}
catch (System.Security.Cryptography.CryptographicException)
{
returncode++;
if (!parentWritten)
{
Console.WriteLine(uri);
parentWritten = true;
}
WriteLine($"\t{file} - ERROR: Assembly not signed", true);
}
}
}
}
}
}
}
else if (uri.OriginalString.EndsWith(".dll"))
{
// Verify dll
using (var f = new StreamedFile(item))
{
try
{
using (var cert = X509Certificate.CreateFromSignedFile(f.Filename))
{
if (!quietMode) WriteLine($"{uri} - OK");
}
}
catch (System.Security.Cryptography.CryptographicException)
{
returncode++;
WriteLine($"{uri} - ERROR: Assembly not signed", true);
}
}
}
}
return returncode;
}
private static void WriteLine(string message, bool isError = false)
{
var fc = Console.ForegroundColor;
if (isError)
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
if (isError)
Console.ForegroundColor = fc;
}
private class StreamedFile : IDisposable
{
string tmp;
public StreamedFile(OpenVsixSignTool.Core.OpcPart item)
{
using (var s = item.Open())
{
CopyToTempFile(s);
}
}
public StreamedFile(Stream s)
{
CopyToTempFile(s);
}
private void CopyToTempFile(Stream str)
{
tmp = Path.GetTempFileName();
using (var file = File.OpenWrite(tmp))
str.CopyTo(file);
}
public void Dispose()
{
File.Delete(tmp);
}
public string Filename => tmp;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment