Is there a way to check a dll file inside a NuGet package when installing it using NuGet API.
Scenario:
I want a c#/.net application to be able to update itself at runtime using NuGet packages. Since this is obviously pretty risky I would like to verify that the package comes from the source I expect it to come from.
Problem:
NuGet does not support package signing. There is a paper addressing the issue here: https://blog.nuget.org/20150203/package-signing.html
What I have done so far:
- Build an empty project
- Sign the dll file (signtool sign /t http://timestamp.digicert.com /a ".\app.dll")
- Create a NuGet package from it (nuget spec add.dll, nuget pack .\app.dll.nuspec)
The dll file inside the NuGet package is now signed and I can upload it to a NuGet repo.
This is my application code:
public static void installPackage(string packageId, string connectionString, string path){
IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository(connectionString);
PackageManager packageManager = new PackageManager(repo, path);
packageManager.InstallPackage(packageId);
}
The example is taken from here:
https://blog.nuget.org/20130520/Play-with-packages.html
The only possible solution I can imagine at the moment would be to use a download package function from the NuGet API, unpack the downloaded package, do the check and install afterwards. Sadly I can not find any hint in the API that the install process could be done in those two steps.
Alternatively, I could use PGP to create a detached signature, sign the NuGet package itself and do a check on the NuGet package with the detached signature. However, that leads to the same problem of first being able to download the package.
I would be grateful for any hint! Thank you.
--- Update ---
I think I have found a way to use NuGet and PGP signing for package verification. I am doing the following:
- Get list of available NuGets from NuGet Server (I am using Nexus)
- Mark a file for installation
The Package provides a download link:
IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository(<connectionString>); DataServicePackage package = (DataServicePackage) repo.FindPackage(packageId); String downloadUrl = package.DownloadUrl.AbsoluteUri;
Download the package and store on disk:
using (var client = new WebClient()){
client.UseDefaultCredentials = true;
client.Credentials = new NetworkCredential(<User>, <Pass>);
var content = client.DownloadData(downloadUrl);
using (MemoryStream memoryStream = new MemoryStream(content)){
FileStream fs = new FileStream(<pathToLocalRepo>, FileMode.CreateNew);
memoryStream.CopyTo(fs);
fs.Close();
}
}
- Download the detached signature from a different server
- Verify the detached signature and the downloaded nupkg (I used BouncyCastle)
- If verification succeeds:
- Use the directory the file is stored as new repository and install the package from there
//Initialize local repository
string path = <pathToLocalRepo>;
IPackageRepository localRepo = PackageRepositoryFactory.Default.CreateRepository(path);
var packages = repo.GetPackages();
//Initialize the package manager
PackageManager packageManager = new PackageManager(localRepo, path);
//Install
packageManager.InstallPackage(<packageId>);
Using this approach still leaves you with the possibility to authenticode the files inside the NuGet package.
Happy to hear what you guys think about this solution. Thanks!