-
Notifications
You must be signed in to change notification settings - Fork 252
[Spec] NuGet Config schema changes to enable trusted signers
Status: Reviewing
Issue for spec - NuGet/Home#6524
Parent spec - Repository-Signatures
Related spec - NuGet-Package-Signing-Client-Policy
As the next wave of package signing, consumers need to be able to trust specific package signers. Further, the trust information needs to be stored into the user's machine.
All NuGet package consumers.
- Enable package consumers to store repository and author trust information.
- Update the schema for the nuget.config file to be able to store repository and author trust information.
- Define a gesture for users to be able to trust signers.
-
Trusted signer name -
Allows a user add a friendly name to identify the signer's trust information. -
Trusted signer type - Identifies the trusted signer with a type. The only permitted values are
author
andrepository
. If the value isrepository
aserviceIndex
element should exist.
Further for each certificate used by the repository, we should store the following -
-
Certificate fingerprint -
Used to assert the package being verified has been signed by the trusted repository. The fingerprint should be a calculated based on theRepository Certificate Fingerprint Algorithm
described below. -
Certificate fingerprint algorithm -
Allows for crypto-agility while calculating the certificate fingerprint. The algorithm currently supported are -SHA256
SHA384
SHA512
-
Untrusted root -
Indicates if it is allowed or disallowed that this certificate chains to an untrusted root.
We should store the following information to enable a trust relationship between a package consumer and a package repository.
- Repository source service index URI -
Allows communication with the source to refresh certificate list and to match with theV3ServiceIndex
attribute in a repository signature. If this property is present in a trusted signer entry, the entry is taken to be a repository.
If the user wants to only trust specific package owners for a repository, they should be able to specify a list of trusted owners that will be compared against the Package Owners
field in the repository signature metadata.
Trust information should be stored in the nuget.config file.
<trustedSigners>
<repository name="NAME" serviceIndex="SERVICE_INDEX_URI">
<certificate fingerprint="CERT_HASH"
hashAlgorithm="FINGERPRINT_ALGORITHM"
allowUntrustedRoot="UNTRUSTED_ROOT_BOOL" /><!-- defaults to false -->
<owners>OWNER_1;OWNER_2;...;OWNER_N</owners>
</repository>
<author name="NAME">
<certificate fingerprint="CERT_HASH"
hashAlgorithm="FINGERPRINT_ALGORITHM"
allowUntrustedRoot="UNTRUSTED_ROOT_BOOL" /><!-- defaults to false -->
</author>
</trustedSigners>
Notes on schema:
- A
clear
element may be present as an immediate child of atrustedSigners
node. Aclear
element must not be an indirect descendant of atrustedSigners
node. -
repository
entries should be unique based on theserviceIndex
. -
author
entries should be unique based on thename
. - If two trusted signer entries are found to have the same unique key on different levels of the hierarchy, the closest to the current working directory should be used.
- If there are multiple certificates with the same fingerprint (e.g. multiple different trusted signer entries can share the same certificate) and conflicting
allowUntrustedRoot
values, a warning should be generated and the most restrictive setting should be used. - If no
owners
item is present, all owners will be trusted.
For example -
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="NuGet.Org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<trustedSigners>
<repository name="NuGet.Org" serviceIndex="https://api.nuget.org/v3/index.json">
<certificate fingerprint="jQCosvMgBxcgQGNesKaHU1Axvgly73B6jkRXZsf9Y8w="
hashAlgorithm="SHA256"
allowUntrustedRoot="false" />
<certificate fingerprint ="vPv9/fx05OEc4atG7ny+5KXeLbV8xuZhp8ct1fgIhpfdP97ZQ2B801YBaBP61zd="
hashAlgorithm="SHA384"
allowUntrustedRoot="false" />
<owners>aspnet;microsoft</owners>
</repository>
<repository name="vsts" serviceIndex="https://api.vsts.com/feed/index.json">
<certificate fingerprint="OdiswAGAy7da6Gs6sghKmg9e9r90wM385jRXZsf9Y5q="
hashAlgorithm="SHA256"
allowUntrustedRoot="true" />
</repository>
<author name="Microsoft">
<certificate fingerprint="jQCosvMgBxcgQGNesKaHU1Axvgly73B6jkRXZsf9Y8w="
hashAlgorithm="SHA256"
allowUntrustedRoot="false" />
</author>
<author name="PatoBeltran">
<certificate fingerprint="jQCosvMgBxcgQGNesKaHU1Axvgly73B6jkRXZsf9Y8w="
hashAlgorithm="SHA256"
allowUntrustedRoot="true" />
</author >
</trustedSigners>
</configuration>
To enable the following user gestures we need to create a new nuget trusted-signers
command.
Operation | Signer Type | Command | Remarks |
---|---|---|---|
List | All | nuget trusted-signers |
|
Add | Repository | nuget trusted-signers Add -Name <n> [-Owners <o>] |
Only works if there exists a source with the same name |
Add | Repository | nuget trusted-signers Add -Name <n> -ServiceIndex <s> [-Owners <o>] |
|
Add | Author | nuget trusted-signers Add -Name <n> -CertificateFingerprint <f> [-FingerprintAlgorithm <a>] [-AllowUntrustedRoot] |
If entry with the same name exists, append the new certificate element.FingerprintAlgorithm defaults to SHA256 . |
Add | Repository | nuget trusted-signers Add <package_path> -Repository -Name <n> [-Owners <o>] [-AllowUntrustedRoot] |
Only works if package is repository signed or repository countersigned. |
Add | Author | nuget trusted-signers Add <package_path> -Author -Name <n> [-AllowUntrustedRoot] |
Only works if package is author signed. |
Remove | Any | nuget trusted-signers Remove -Name <n> |
|
Sync | Repository | nuget trusted-signers Sync -Name <n> |
Refreshes certificates entries with the ones announced by the repository. The entry has to exist and be a trusted repository with a service index or a corresponding package source. |
This gesture will be translated to dotnet CLI by updating the dotnet nuget add
, dotnet nuget remove
commands and add a dotnet nuget sync
and a dotnet nuget list
commands.
Operation | Signer Type | Command | Remarks |
---|---|---|---|
List | All | dotnet nuget list trusted-signers |
|
Add | Repository | dotnet nuget add trusted-signers -Name <n> [-Owners <o>] |
Only works if there exists a source with the same name |
Add | Repository | dotnet nuget add trusted-signers -Name <n> -ServiceIndex <s> [-Owners <o>] |
|
Add | Author | dotnet nuget add trusted-signers -Name <n> -CertificateFingerprint <f> -FingerprintAlgorithm <a> [-UntrustedRoot <u>] |
If entry with the same name exists, append the new certificate element. untrustedRoot defaults to disallow
|
Add | Repository | dotnet nuget add trusted-signers <package_path> -Repository -Name <n> [-Owners <o>] [-UntrustedRoot <u>] |
Only works if package is repository signed or repository countersigned.untrustedRoot defaults to disallow
|
Add | Author | dotnet nuget add trusted-signers <package_path> -Author -Name <n> [-UntrustedRoot <u>] |
Only works if package is author signed.untrustedRoot defaults to disallow
|
Remove | Any | dotnet nuget remove trusted-signers -Name <n> |
|
Sync | Repository | dotnet nuget sync trusted-signers -Name <n> |
Refreshes certificates entries with the ones announced by the repository. The entry has to exist and be a trusted repository with a service index or a corresponding package source. |
Over the course of time, a repository could deprecate or add certificates to their list of supported certificates. The sync
action is designed as a way for the user to explicitly update their trust to that specific repository. This action will send a request to the appropriate service index to get a list of certificates that will replace the current trusted certificates for the corresponding trusted repository entry.
-
Given the current inheritance model of the nuget.config, what happens when two configs at different levels have a
trustedSigner
element with the same name?
PB: EachtrustedSigner
element should be atomic, therefore if an entry that has the same name is found in the hierarchy it should override the previous one found. -
What happens when there exist multiple entries with the same
serviceIndex
, different name value, but with conflicting certificate elements? (e.g. samecertificateFingerprint
but differentuntrustedRoot
value)
PB: We should considerserviceIndex
to be the unique key for a repository trusted signer entry, therefore it should only exist one entry perserviceIndex
. However, if two certificates are found with conflictinguntrustedRoot
we should warn and take the most restrictive one. -
If the sync action automatically refreshes the certificates list in a trusted repository entry with the ones announced by the server, should there be a gesture to let the update the
untrustedRoot
setting on each certificate given by the server? -
If a user has a different config on two folders inside a solution, given that we don’t have the granularity of which package asked for a specific package to be downloaded, what trusted signers will be used when verifying each of the packages downloaded?
-
The current design only lets the user add a trusted author with a single certificate and hand edit if more than one certificate should be trusted. Is there a way to create a "batch add" to let the user add a trusted author with multiple certificates?
PB: If a user does anuget trusted-signer add
with a certificate information an a name of an existing entry, it should append that certificate to the existing entry. -
Owners in a repository signature are not limited to a set of characters, therefore it is possible that a package owner in a signature has the character we chose as a delimiter (i.e. semicolon -
;
). Should we make the schema take a single line for each owner?
PB: Based on the assumption that owners will usually be repository usernames, they will be constrained by the repository to a certain set of characters, therefore choosing a semicolon to delimit this list should be safe.
Check out the proposals in the accepted
& proposed
folders on the repository, and active PRs for proposals being discussed today.