| File: Signing\TrustedSigners\TrustedSignersProvider.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.Packaging\NuGet.Packaging.csproj (NuGet.Packaging) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using NuGet.Common; using NuGet.Configuration; namespace NuGet.Packaging.Signing { public sealed class TrustedSignersProvider : ITrustedSignersProvider { private readonly ISettings _settings; public TrustedSignersProvider(ISettings settings) { _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } public IReadOnlyList<TrustedSignerItem> GetTrustedSigners() { var trustedSignersSection = _settings.GetSection(ConfigurationConstants.TrustedSigners); if (trustedSignersSection == null) { return Enumerable.Empty<TrustedSignerItem>().ToList(); } return trustedSignersSection.Items.OfType<TrustedSignerItem>().ToList(); } public void Remove(IReadOnlyList<TrustedSignerItem> trustedSigners) { if (trustedSigners == null || !trustedSigners.Any()) { throw new ArgumentException(Strings.ArgumentCannotBeNullOrEmpty, nameof(trustedSigners)); } foreach (var signer in trustedSigners) { try { _settings.Remove(ConfigurationConstants.TrustedSigners, signer); } // An error means the item doesn't exist or is in a machine wide config, therefore just ignore it catch { } } _settings.SaveToDisk(); } public void AddOrUpdateTrustedSigner(TrustedSignerItem trustedSigner) { if (trustedSigner == null) { throw new ArgumentNullException(nameof(trustedSigner)); } _settings.AddOrUpdate(ConfigurationConstants.TrustedSigners, trustedSigner); _settings.SaveToDisk(); } public static IReadOnlyList<TrustedSignerAllowListEntry> GetAllowListEntries(ISettings settings, ILogger logger) { if (settings == null) { throw new ArgumentNullException(nameof(settings)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } var trustedSignersSection = settings.GetSection(ConfigurationConstants.TrustedSigners); if (trustedSignersSection == null) { return Enumerable.Empty<TrustedSignerAllowListEntry>().ToList(); } // We will dedup certificates based on fingerprint and hash algorithm, therefore // the key to this lookup will be hashAlgorithm-fingerprint var certificateLookup = new Dictionary<string, CertificateEntryLookupEntry>(); foreach (var item in trustedSignersSection.Items.OfType<TrustedSignerItem>()) { var itemTarget = GetItemTarget(item, out var itemPlacement); foreach (var certificate in item.Certificates) { ICollection<string>? owners = null; if (itemTarget == VerificationTarget.Repository) { owners = new HashSet<string>(((RepositoryItem)item).Owners); } if (certificateLookup.TryGetValue(GetCertLookupKey(certificate), out var existingEntry)) { if (existingEntry.Certificate.AllowUntrustedRoot != certificate.AllowUntrustedRoot) { // warn and take the most restrictive setting logger.Log(new LogMessage(LogLevel.Warning, string.Format(CultureInfo.CurrentCulture, Strings.ConflictingAllowUntrustedRoot, certificate.HashAlgorithm.ToString(), certificate.Fingerprint), NuGetLogCode.NU3040)); existingEntry.Certificate.AllowUntrustedRoot = false; } existingEntry.Target |= itemTarget; existingEntry.Placement |= itemPlacement; if (owners != null) { if (existingEntry.Owners == null) { existingEntry.Owners = owners; } else { existingEntry.Owners.AddRange(owners); } } } else { certificateLookup.Add(GetCertLookupKey(certificate), new CertificateEntryLookupEntry(itemTarget, itemPlacement, certificate, owners)); } } } return certificateLookup.Select(e => e.Value.ToAllowListEntry()).ToList(); } private static string GetCertLookupKey(CertificateItem certificate) { return $"{certificate.HashAlgorithm.ToString()}-{certificate.Fingerprint}"; } private static VerificationTarget GetItemTarget(TrustedSignerItem item, out SignaturePlacement placement) { if (item is RepositoryItem) { placement = SignaturePlacement.Any; return VerificationTarget.Repository; } placement = SignaturePlacement.PrimarySignature; return VerificationTarget.Author; } private class CertificateEntryLookupEntry { public VerificationTarget Target { get; set; } public SignaturePlacement Placement { get; set; } public ICollection<string>? Owners { get; set; } public CertificateItem Certificate { get; } public CertificateEntryLookupEntry(VerificationTarget target, SignaturePlacement placement, CertificateItem certificate, ICollection<string>? owners = null) { Target = target; Placement = placement; Certificate = certificate ?? throw new ArgumentNullException(nameof(certificate)); Owners = owners; } public TrustedSignerAllowListEntry ToAllowListEntry() { return new TrustedSignerAllowListEntry(Target, Placement, Certificate.Fingerprint, Certificate.HashAlgorithm, Certificate.AllowUntrustedRoot, Owners?.ToList()); } } } }