Skip to content

Commit

Permalink
Signing: update to August 2022 CTL (#4791) (#4850)
Browse files Browse the repository at this point in the history
Resolve NuGet/Home#12033.

Co-authored-by: Damon Tivel <dtivel@microsoft.com>
  • Loading branch information
kartheekp-ms and dtivel committed Oct 12, 2022
1 parent ab43b9b commit 125f673
Show file tree
Hide file tree
Showing 54 changed files with 10,796 additions and 331 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ project.json text
*.vcxproj text eol=crlf

# Denote all files that are truly binary and should not be modified.
*.gif binary
*.jpg binary
*.pem binary
*.png binary
*.gif binary
*.zip binary
18 changes: 5 additions & 13 deletions build/common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,9 @@ Function Install-DotnetCLI {
$arch = "x86";
}

# The Quality option:
# Daily links are those from daily builds
# Signed have been post-build signed (in the case of 6.0+, pre-6.0 is signed even in daily builds)
# Validated have gone through CTI testing and other validation
# Preview are released bits that are preview versions
# GA are released servicing and GA builds
Trace-Log "$DotNetInstall -Channel $($cli.Channel) -Quality signed -InstallDir $($cli.Root) -Version $($cli.Version) -Architecture $arch -NoPath"

# dotnet-install might make http requests that fail, but it handles those errors internally
# However, Invoke-BuildStep checks if any error happened, ever. Hence we need to run dotnet-install
# in a different process, to avoid treating their handled errors as build errors.
& powershell $DotNetInstall -Channel $cli.Channel -Quality signed -InstallDir $cli.Root -Version $cli.Version -Architecture $arch -NoPath
Trace-Log "$DotNetInstall -Channel $($cli.Channel) -InstallDir $($cli.Root) -Version $($cli.Version) -Architecture $arch -NoPath"

& powershell $DotNetInstall -Channel $cli.Channel -InstallDir $cli.Root -Version $cli.Version -Architecture $arch -NoPath
if ($LASTEXITCODE -ne 0)
{
throw "dotnet-install.ps1 exited with non-zero exit code"
Expand All @@ -230,12 +221,13 @@ Function Install-DotnetCLI {
}
}

# Install the 2.x runtime because our tests target netcoreapp2x
# Install the 3.x runtime because our tests target netcoreapp2x
Trace-Log "$DotNetInstall -Runtime dotnet -Channel 3.1 -InstallDir $CLIRoot -NoPath"
# dotnet-install might make http requests that fail, but it handles those errors internally
# However, Invoke-BuildStep checks if any error happened, ever. Hence we need to run dotnet-install
# in a different process, to avoid treating their handled errors as build errors.
& powershell $DotNetInstall -Runtime dotnet -Channel 3.1 -InstallDir $CLIRoot -NoPath

if ($LASTEXITCODE -ne 0)
{
throw "dotnet-install.ps1 exited with non-zero exit code"
Expand Down
2 changes: 1 addition & 1 deletion build/config.props
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
6.0:6.0.100-preview.7.21379.14 means install the preview version 6.0.100-preview.7.21379.14.
Refer to https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script#options for more details.
-->
<CliBranchForTesting Condition="'$(CliBranchForTesting)' == ''">6.0.4xx</CliBranchForTesting>
<CliBranchForTesting Condition="'$(CliBranchForTesting)' == ''">7.0:7.0.100-rtm.22510.17</CliBranchForTesting>
</PropertyGroup>

<!-- Config -->
Expand Down
17 changes: 7 additions & 10 deletions scripts/funcTests/runFuncTests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,9 @@ do
fi
unset IFS

# The quality option:
# Daily links are those from daily builds
# Signed have been post-build signed (in the case of 6.0+, pre-6.0 is signed even in daily builds)
# Validated have gone through CTI testing and other validation
# Preview are released bits that are preview versions
# GA are released servicing and GA builds
echo "cli/dotnet-install.sh --install-dir cli --channel $Channel --quality signed --version $Version -nopath"
cli/dotnet-install.sh --install-dir cli --channel $Channel --quality signed --version $Version -nopath

echo "cli/dotnet-install.sh --install-dir cli --channel $Channel --version $Version -nopath"
cli/dotnet-install.sh --install-dir cli --channel $Channel --version $Version -nopath

if (( $? )); then
echo "The .NET CLI Install for $DOTNET_BRANCH failed!!"
exit 1
Expand All @@ -91,7 +85,10 @@ if (( $? )); then
exit 1
fi

# Install .NET 5 runtimes and .NETCoreapp3.1 runtimes
# Install .NET 5, 6, and .NETCoreapp3.1 runtimes

echo "cli/dotnet-install.sh --install-dir cli --runtime dotnet --channel 6.0 -nopath"
cli/dotnet-install.sh --install-dir cli --runtime dotnet --channel 6.0 -nopath

echo "cli/dotnet-install.sh --install-dir cli --runtime dotnet --channel 5.0 -nopath"
cli/dotnet-install.sh --install-dir cli --runtime dotnet --channel 5.0 -nopath
Expand Down
3 changes: 2 additions & 1 deletion src/NuGet.Core/NuGet.Packaging/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
[assembly: CLSCompliant(true)]

[assembly: InternalsVisibleTo("Dotnet.Integration.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("NuGet.Packaging.FuncTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("NuGet.Packaging.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("NuGet.CommandLine.FuncTest, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("NuGet.Commands.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Test.Utility, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public virtual SignatureVerificationSummary Verify(
else
{
timestamp = timestamp ?? new Timestamp();
using (var chainHolder = new X509ChainHolder())
using (X509ChainHolder chainHolder = X509ChainHolder.CreateForCodeSigning())
{
var chain = chainHolder.Chain;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ internal SignatureVerificationStatusFlags Verify(

var certificateExtraStore = SignedCms.Certificates;

using (var chainHolder = new X509ChainHolder())
using (X509ChainHolder chainHolder = X509ChainHolder.CreateForTimestamping())
{
var chain = chainHolder.Chain;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ internal sealed class FallbackCertificateBundleX509ChainFactory : CertificateBun
{
// These constants are dictated by the .NET SDK.
internal const string SubdirectoryName = "trustedroots";
internal const string FileName = "codesignctl.pem";
internal const string CodeSigningFileName = "codesignctl.pem";
internal const string TimestampingFileName = "timestampctl.pem";

private static readonly Lazy<string> ThisAssemblyDirectoryPath = new(GetThisAssemblyDirectoryPath, LazyThreadSafetyMode.ExecutionAndPublication);

Expand All @@ -23,14 +24,27 @@ private FallbackCertificateBundleX509ChainFactory(X509Certificate2Collection cer
{
}

internal static bool TryCreate(out FallbackCertificateBundleX509ChainFactory factory, string fileName = FileName)
internal static bool TryCreate(
X509StorePurpose storePurpose,
string fileName,
out FallbackCertificateBundleX509ChainFactory factory)
{
factory = null;

if (string.IsNullOrEmpty(fileName))
{
fileName = storePurpose switch
{
X509StorePurpose.CodeSigning => CodeSigningFileName,
X509StorePurpose.Timestamping => TimestampingFileName,
_ => throw new ArgumentException(Strings.InvalidX509StorePurpose, nameof(storePurpose))
};
}

string fullFilePath = Path.Combine(
ThisAssemblyDirectoryPath.Value,
SubdirectoryName,
fileName ?? FileName);
fileName);

if (TryImportFromPemFile(fullFilePath, out X509Certificate2Collection certificates))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// 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.

namespace NuGet.Packaging.Signing
{
internal enum X509StorePurpose
{
CodeSigning = 1,
Timestamping = 2
}
}
94 changes: 70 additions & 24 deletions src/NuGet.Core/NuGet.Packaging/Signing/TrustStore/X509TrustStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ namespace NuGet.Packaging.Signing
/// </summary>
public static class X509TrustStore
{
private static IX509ChainFactory Instance;
private static IX509ChainFactory CodeSigningX509ChainFactory;
private static IX509ChainFactory TimestampingX509ChainFactory;
private static readonly object LockObject = new();

/// <summary>
Expand All @@ -24,51 +25,85 @@ public static class X509TrustStore
/// <exception cref="ArgumentNullException">Thrown if <paramref name="logger" /> is <c>null</c>.</exception>
public static void InitializeForDotNetSdk(ILogger logger)
{
_ = GetX509ChainFactory(logger, CreateX509ChainFactoryForDotNetSdk);
_ = GetX509ChainFactory(X509StorePurpose.CodeSigning, logger, CreateX509ChainFactoryForDotNetSdk);
_ = GetX509ChainFactory(X509StorePurpose.Timestamping, logger, CreateX509ChainFactoryForDotNetSdk);
}

internal static IX509ChainFactory GetX509ChainFactory(ILogger logger)
internal static IX509ChainFactory GetX509ChainFactory(X509StorePurpose storePurpose, ILogger logger)
{
return GetX509ChainFactory(logger, CreateX509ChainFactory);
return GetX509ChainFactory(storePurpose, logger, CreateX509ChainFactory);
}

private static IX509ChainFactory GetX509ChainFactory(ILogger logger, Func<ILogger, IX509ChainFactory> creator)
private static IX509ChainFactory GetX509ChainFactory(
X509StorePurpose storePurpose,
ILogger logger,
Func<X509StorePurpose, ILogger, IX509ChainFactory> creator)
{
if (logger is null)
{
throw new ArgumentNullException(nameof(logger));
}

if (Instance is not null)
if (storePurpose == X509StorePurpose.CodeSigning)
{
return Instance;
if (CodeSigningX509ChainFactory is not null)
{
return CodeSigningX509ChainFactory;
}

lock (LockObject)
{
if (CodeSigningX509ChainFactory is not null)
{
return CodeSigningX509ChainFactory;
}

CodeSigningX509ChainFactory = creator(storePurpose, logger);
}

return CodeSigningX509ChainFactory;
}

lock (LockObject)
if (storePurpose == X509StorePurpose.Timestamping)
{
if (Instance is not null)
if (TimestampingX509ChainFactory is not null)
{
return Instance;
return TimestampingX509ChainFactory;
}

Instance = creator(logger);
lock (LockObject)
{
if (TimestampingX509ChainFactory is not null)
{
return TimestampingX509ChainFactory;
}

TimestampingX509ChainFactory = creator(storePurpose, logger);
}

return TimestampingX509ChainFactory;
}

return Instance;
throw new ArgumentException(Strings.InvalidX509StorePurpose, nameof(storePurpose));
}

internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger logger)
private static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(X509StorePurpose storePurpose, ILogger logger)
{
return CreateX509ChainFactoryForDotNetSdk(logger, fallbackCertificateBundleFile: null);
return CreateX509ChainFactoryForDotNetSdk(storePurpose, logger, fallbackCertificateBundleFile: null);
}

// Non-private for testing purposes only
internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger logger, FileInfo fallbackCertificateBundleFile)
internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(
X509StorePurpose storePurpose,
ILogger logger,
FileInfo fallbackCertificateBundleFile)
{
#if NET5_0_OR_GREATER
if (RuntimeEnvironmentHelper.IsLinux)
{
if (SystemCertificateBundleX509ChainFactory.TryCreate(
// System certificate bundle probe paths only support code signing not timestamping.
if (storePurpose == X509StorePurpose.CodeSigning &&
SystemCertificateBundleX509ChainFactory.TryCreate(
out SystemCertificateBundleX509ChainFactory systemBundleFactory))
{
logger.LogInformation(
Expand All @@ -81,8 +116,9 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log
}

if (FallbackCertificateBundleX509ChainFactory.TryCreate(
out FallbackCertificateBundleX509ChainFactory fallbackBundleFactory,
fallbackCertificateBundleFile?.FullName))
storePurpose,
fallbackCertificateBundleFile?.FullName,
out FallbackCertificateBundleX509ChainFactory fallbackBundleFactory))
{
logger.LogInformation(
string.Format(
Expand All @@ -101,8 +137,9 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log
if (RuntimeEnvironmentHelper.IsMacOSX)
{
if (FallbackCertificateBundleX509ChainFactory.TryCreate(
out FallbackCertificateBundleX509ChainFactory fallbackBundleFactory,
fallbackCertificateBundleFile?.FullName))
storePurpose,
fallbackCertificateBundleFile?.FullName,
out FallbackCertificateBundleX509ChainFactory fallbackBundleFactory))
{
logger.LogInformation(
string.Format(
Expand All @@ -119,23 +156,32 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log
}
#endif

return CreateX509ChainFactory(logger);
return CreateX509ChainFactory(storePurpose, logger);
}

// Non-private for testing purposes only
internal static IX509ChainFactory CreateX509ChainFactory(ILogger logger)
internal static IX509ChainFactory CreateX509ChainFactory(X509StorePurpose storePurpose, ILogger logger)
{
logger.LogInformation(Strings.ChainBuilding_UsingDefaultTrustStore);

return new DotNetDefaultTrustStoreX509ChainFactory();
}

// Only for testing
internal static void SetX509ChainFactory(IX509ChainFactory chainFactory)
internal static void SetCodeSigningX509ChainFactory(IX509ChainFactory chainFactory)
{
lock (LockObject)
{
CodeSigningX509ChainFactory = chainFactory;
}
}

// Only for testing
internal static void SetTimestampingX509ChainFactory(IX509ChainFactory chainFactory)
{
lock (LockObject)
{
Instance = chainFactory;
TimestampingX509ChainFactory = chainFactory;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public static IX509CertificateChain GetCertificateChain(
throw new ArgumentException(Strings.InvalidArgument, nameof(certificateType));
}

using (var chainHolder = new X509ChainHolder())
using (X509ChainHolder chainHolder = certificateType == CertificateType.Signature
? X509ChainHolder.CreateForCodeSigning() : X509ChainHolder.CreateForTimestamping())
{
var chain = chainHolder.Chain;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ public static bool IsSelfIssued(X509Certificate2 certificate)
throw new ArgumentNullException(nameof(certificate));
}

using (var chainHolder = new X509ChainHolder())
using (X509ChainHolder chainHolder = X509ChainHolder.CreateForCodeSigning())
{
X509Chain chain = chainHolder.Chain;

Expand Down
Loading

0 comments on commit 125f673

Please sign in to comment.