-
Notifications
You must be signed in to change notification settings - Fork 252
Repository Signatures
Status: Reviewing
The discussion around this spec is tracked here - Repository Signatures issue #6378
NuGet packages do not include any mechanism to determine if a given package has been modified from creation to consumption or who is the legitimate author of the package. Content integrity depends on the HTTPS connection used to download the package, but once downloaded it’s not easy to check if the package has been tampered.
Author signatures provide content integrity checks, but they do not address the fact that many packages might depend on packages that have not been signed by their authors.
Repository signatures provide an integrity guarantee for all packages in a repository whether they are author signed or not, even if those packages are obtained from a different location than the original repository where they were signed.
NuGet servers that implement repository signatures must announce the list of certificates used to generate the repository signatures. This announcement will be available as part of the NuGet protocol v3.
NuGet clients who support repository signatures will define the list of repositories they trust. This information is stored in a configuration file that can be customized at different scopes.
During package validation NuGet clients must require that all packages from the claimed repository of origin are signed with one of the certificates included in the configuration file.
NuGet clients will help synchronize the config file with the certificates exposed by the feed with new gestures to keep the configuration file up to date.
Note: NuGet servers may choose to produce repository signatures or just host unsigned packages or packages signed by other repositories.
Repository signatures do not protect against other threats where the repository certificate's private key, or even the whole repository service has been compromised. These threats are protected by advanced monitoring techniques outside the scope of this document.
Package signing in general does not protect from a compromised local machine, where an attacker can change the trusted roots, the repository keys or even the original packages.
Considering author and repository signatures there are four possible package signing configurations; no other configurations of these signature types are allowed:
Package Type | Notes |
---|---|
Unsigned | The package does not include any signature. |
Author | The primary signature is an author signature. |
Repo | The primary signature is a repository signature. |
Author and Repo | The primary signature is an author signature, and the signature is repository countersigned. |
Note: Package repositories can host packages of any of these four types, however once NuGet.org implements repository signatures, all packages in NuGet.org will fall in the last two types.
Repository certificates should chain to a trusted root on the local machine, in the case where the certificate does not, package readers will produce a warning unless the configuration specifies that untrusted certificates are allowed.
The Package Signatures Technical Details spec defines the requirements for all package signatures. The Repository Signatures and Countersignatures Technical Specification describes the requirements for repository signatures
The repository signature will include the following metadata:
Name | Description | Required |
---|---|---|
V3 Service Index URL | Official HTTPS URL to the repository V3 service index. (must be HTTPS) | Yes |
Package Owners | List of the package owners in that repository at the time of submission. | No |
Repository signatures require a NuGet server with a v3 service endpoint. Repositories based on local or shared folders can host packages signed in a different repository, however to produce their own repository signatures they will need to configure an HTTP server to publish the certificates.
Repositories who implement the updated service protocol, and sign all their packages with a repository signature will be considered as Secure Repositories.
Repositories will announce the certificates used for repository signing as part of the NuGet protocol v3.
If a repository announces that all packages are repository signed, then a package reader should verify that a package received from the repository is signed as expected or resolve validation failure by a policy.
The service index API will expose a new resource to allow clients verify the certificates used for package signing. Index service example with new resource:
{
"version": "3.0.0-beta.1",
"resources": [
{
"@id": "https://api.nuget.org/v3/registration2/",
"@type": "RegistrationsBaseUrl/3.0.0-rc",
"comment": "Base URL of Azure storage where NuGet package registration info is stored used by RC clients. This base URL does not include SemVer 2.0.0 packages."
},
{
"@id": "https://api.nuget.org/v3/repository-signature/",
"@type": "CertificatesBaseUrl/3.0.0-rc",
"comment" : "BaseUrl for certificate endpoints"
}
]
}
This new resource will include an endpoint to discover the list of certificates. For each certificate the next properties will be shown. Additionally, the complete certificate will be available as a DER encoded file.
Certificate Property | Purpose |
---|---|
Thumbprint SHA256 | Uniquely identify the certificate |
Subject Name | Text to display if needed |
Issued By | Name of the issuer |
Valid From | Initial date to produce repository signatures |
Valid To | Last date producing repository signatures |
Repository administrators can configure the certificates used for repository signing. Over time the certificates will expire and would need to be renewed. Once renewed it will be added to the certificates list, previous certificates should not be removed from the list since that operation will invalidate existing signed packages.
If the repository private key is compromised the certificate must be revoked and all packages signed after the revocation effective date will become invalid and should be signed again with the new certificate.
Repositories should keep the list of certificate used over time, including the validity period for each.
Note: There are some limitations in non-Windows platforms, where the revocation status does not include the revocation effective date. If the repository certificate is compromised, all packages should be signed again with the updated certificate.
Client policies allow to customize the security checks when restoring packages.
-
Accept Mode. This is the default mode of operation. It will always verify signed packages, but will enforce signed packages only if the package is downloaded from a repository announcing repository signatures.
-
Require Mode. Enables advanced locked-down configuration by requiring to explicitly trust package signers.
Accept | Require |
---|---|
Allow unsigned from unsecure repositories | Require signed (author or repo) |
Enforce content integrity (if signed) | Enforce content integrity |
Perform revocation checks | Perform revocation checks |
Enforce trust based con configuration (author or repo) |
Package readers configure the client policy with the new signatureValidationMode
property in the packageRestore
configuration section. NuGet docs will include instructions to update the configuration file even without connection to the repository service index.
The rules to locate this file will follow the NuGet.config rules to work at different scopes.
The sample below shows a sample configuration file:
<configuration>
<packageRestore>
<add key="enabled" value="true" />
<add key="automatic" value="true" />
<add key="signatureValidationMode" value="Require" /> <!-- Default to Accept-->
</packageRestore>
<packageSources>
<add key="NuGet.org"
value="https://api.nuget.org/v3/index.json"
protocolVersion="3" />
<add key="ContosoSharedRepo"
value="https://api.myget.org/F/ContosoRepository"
protocolVersion="3" />
<add key="ContosoInternalRepo"
value="\\Contoso-FS01\ContosoRepository"/>
</packageSources>
</configuration>
Users trust specific authors and repositories by listing the certificates in the NuGet configuration file.
<configuration>
<trustedRepositories>
<repository key="NuGet.org">
<certificate subjectName="NuGet.org"
thumbprint="a897009b809809c..." />
<certificate subjectName="NuGet.org"
thumbprint="6565a656c65b65d..." />
</repository>
<repository key="ContosoSharedRepo"
allowSelfSignedCerts="true" >
<certificate subjectName="ContosoCert"
thumbprint="98098a0980b980c..." />
</repository>
<trustedRepositories>
</configuration>
Note: This configuration schema is a high level proposal. The final schema is being definied in a the related Spec NuGet Config schema changes to enable repository signatures
NuGet official clients (VS, NuGet.exe and dotNet.exe) will include the NuGet.org keys by default. Future versions will add new certificates before the previous one gets expired. This means that clients who maintain their versions up to date will have the certificates registered by default.
Clients running a specific version forever will need to update the keys when they expire, or they won't be able to restore packages. To update the keys the can use the CLI or the IDE, or make a manually edit in the configuration file.
Signers should use a code signing certificate issued by a CA, with revocation information support. If the certificate is not trusted, or the certificate revocation information is not available, the restore operation will produce a warning unless the allowSelfSignedCerts
option is set.
How to mantain the configuration file is defined in the Spec NuGet Config schema changes to enable repository signatures
Repository signatures will be added to packages as part of the server ingestion process using the NuGet libraries. NuGet client tools will not expose any CLI command to generate repository signatures but it will support viewing and eventually removing a repository signature from a given package.
Note: As described in the repository signatures technical specification, only one repository signature is allowed per package. If a repository receives a package with an existing repository signature, the repository should reject or remove the signature to apply their own. NuGet.org will remove the repository signature of a received packages before adding the NuGet.org repository signature.
Official clients like Visual Studio and Nuget.exe (dotnet.exe will be included later) will verify signed packages following the next matrix to evaluate trust for author and repository signatures.
One of the key elements of signature validation is how to evaluate trust.
-
Author Trust. The author will be considered trusted if it chains to a trusted root but users can explicitely trust one author by adding the certificate to the configuration file.
-
Repository Trust. Repository trust is determined based on the configuration file, the user can specify if the certificate must be trusted in the local root certificate store.
<configuration>
<trustedRepositories>
<repository key="NuGet.org">
<certificate subjectName="NuGet.org"
thumbprint="a897009b809809c..." />
<certificate subjectName="NuGet.org"
thumbprint="6565a656c65b65d..." />
</repository>
<repository key="ContosoSharedRepo"
requireTrustedRoot="false" > <!-- Default to true -->
<certificate subjectName="ContosoCert"
thumbprint="98098a0980b980c..." />
</repository>
<trustedRepositories>
<trustedAuthors>
<author key="Microsoft">
<certificate subjectName="Microsoft Corporation"
thumbprint="a897009b809809c..." />
<certificate subjectName="Xamarin Inc"
thumbprint="6565a656c65b65d..." />
</author>
<auhtor key="Rido"
requireTrustedRoot="false" >
<certificate subjectName="RidoTestCert"
thumbprint="98098a0980b980c..." />
</author>
<author key="RidoNuGet">
<owners inRepository="NuGet.org" value="rido,ridomin" >
</author>
<trustedAuthors>
</configuration>
Author Trusted | Repo Trusted | Unsigned | Author | Repo | AuthorRepo |
---|---|---|---|---|---|
No | No | ✅ | |||
No | Undetermined | ✅ | |||
No | Yes | ✅ | ✅ | ✅ | |
Yes | No | ✅ | ✅ | ✅ | ✅ |
Yes | Undetermined | ✅ | ✅ | ✅ | ✅ |
Yes | Yes | ✅ | ✅ | ✅ | ✅ |
Undertermined | No | ✅ | |||
Undertermined | Undertermined | ✅ | |||
Undertermined | Yes | ✅ | ✅ | ✅ |
Note: Undertemined refers to the case where the signer trust cannot be fully verified for different reasons like: cert does not chain to a trusted root, expired certificate and timestamp is not present or invalid, etc...
Author Trusted | Repo Trusted | Unsigned | Author | Repo | AuthorRepo |
---|---|---|---|---|---|
No | No | ❌ | ❌ | ❌ | ❌ |
No | Undetermined | ❌ | ❌ | ❌ | ❌ |
No | Yes | ❌ | ❌ | ✅ | ✅ |
Yes | No | ❌ | ✅ | ✅ | ✅ |
Yes | Undetermined | ❌ | ✅ | ✅ | ✅ |
Yes | Yes | ❌ | ✅ | ✅ | ✅ |
Undertermined | No | ❌ | ❌ | ❌ | ❌ |
Undertermined | Undertermined | ❌ | ❌ | ❌ | ❌ |
Undertermined | Yes | ❌ | ❌ | ✅ | ✅ |
Check out the proposals in the accepted
& proposed
folders on the repository, and active PRs for proposals being discussed today.