-
Notifications
You must be signed in to change notification settings - Fork 252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Spec]: Add support to allow package authors to sign packages #5907
Comments
The spec is currently in review and it is available here. Update: I have updated the link to the public spec. |
404 |
@forki please check the link now. You should be able to access it. |
Is a timestamper provided or is this something the package author must provide? |
@maartenba Current spec requires the user to provide a timestamper service url. |
I am not sure I understand what is
but in my experience the signing algorithm is chosen by the type of public key present in the certificate. ECDSA cannot be used with certificate issued to RSA key pair and vice versa. Are you sure this option is needed? |
If you plan to provide built-in multiplatform support for HSMs and other hardware based key stores then IMO there is currently only one viable option and that is PKCS#11 ANSI C API. It's been here since 1995 when it was created by RSA Laboratories and currently it is being maintained by OASIS PKCS11 Technical Committee that released latest version of specification in 2015. In my experience, most (if not all) of the commercially available HSMs and smartcards come with an unmanaged library implementing PKCS#11 interface. There is even an pure software implementation available called SoftHSM which is invaluable for testing. When it comes to .NET support there is an open source PKCS#11 wrapper library called Pkcs11Interop (I am the shameless self-promoting author) that is
It would be really nice to have built-in PKCS#11 support in NuGet but I understand it might not be entirely possible. For example it might not be allowed to introduce additional dependencies to NuGet code base or it might not be allowed to load unmanaged libraries into nuget process. So as an alternative to built-in HSM support you may also consider making signing API pluggable so I would be able to write and maintain PKCS#11 plugin and other authors would be able to do the same for other key stores (I can imagine @onovotny and @vcsjones would want to write Azure KeyVault plugin). |
@jariq To be clear, we'd most likely reappropriate the signing digest code and wrap it into a different utility. Key Vault doesn't have a PKCS#11 windows api yet (afaik), and we'd want something that doesn't require any installation on the machine. That's one nice thing of our utilities, is that it's pure xcopy. |
@jariq -
Thanks for the feedback. I will investigate this a bit to make sure that I have the right params outlined.
That is correct.
Thanks for your detailed feedback on HSMs. I will look into this and the feasibility of your suggestion. |
Agree. That should (must) be dictated by the signing key being used. Regardless, much kudos for supporting ECC. This is often overlooked in code signing. I suppose the standard NIST curves would apply here. However, macOS doesn't readily support some of the curves Windows does (p521, brainpool). I don't know if you want to limit at signing time which curves you support for signing. I would recommend getting rid of this. It doesn't do anything. You can't set this value to anything other than what the certificate is. This can be determined by the OID of the SPKI of the certificate.
SHA512 is overboard as a default, in my opinion. I understand the notion of "bigger numbers are better". Frankly I would just use SHA256 though would be perfectly fine with 384 as well if there is some concern around SHA256 weaknesses. Though I see no problem with defaulting with SHA512 except for the next item.
There is no option to specify the digest algorithm for the timestamp (the I would recommend introducing a
I honestly wouldn't bother too much with this. An encrypted password in a config file would need to be decryptable by the person running the tool, anyhow. If users are serious about the private key's protection they will use the certificate store and keep the key in a KSP, which could be a smart card, HSM, or the Microsoft Software Key Storage Provider. I would have a
I don't think so? I would however make sure there is a timeout. Perhaps configurable. Other things... It would be really nice if there was support for a signing "callback" mechanism. I don't know if this needs to exist in the CLI, but in the library it would be very help for 3rd parties to sign with whatever they want (selfishly I am thinking of Key Vault support). Windows recently introduced this for Authenticode with It would also be nice if, perhaps later, but the more information the better, it was made clear what different exit codes mean. I assume some people will automate this signing process with a CICD tool, and being able to fail the build for certain exit codes would be nice. |
For that callback, it should be async. The signature should essentially be Idea being that the public certificate (and its chain) come in externally to the library. It should not assume |
I would suggest that last parameter be a public class SignResult
{
public byte[] Signature {get;}
public X509Certificate2 Certificate { get; }
public X509Certificate2Collection AdditionalCertificates { get; }
}
Task<SignResult> SignCallback(byte[] digest, HashAlgorithmName algorithmName, string certificateIdentifier); The
|
@vcsjones I think Therefore I would propose following modification of your pseudo code: public class GetSigningCertResult
{
public X509Certificate2 Certificate { get; }
public X509Certificate2Collection AdditionalCertificates { get; }
}
Task<GetSigningCertResult> GetSigningCertCallback(string certificateIdentifier);
public class SignHashResult
{
public byte[] Signature {get;}
}
Task<SignHashResult> SignHashCallback(byte[] digest, HashAlgorithmName algorithmName, string certificateIdentifier); Both could be wrapped into an interface: public interface IExternalSigner
{
Task<GetSigningCertResult> GetSigningCertCallback(string certificateIdentifier);
Task<SignHashResult> SignHashCallback(byte[] digest, HashAlgorithmName algorithmName, string certificateIdentifier);
} |
I am not quite sure that "certificate store" and "CNG/CAPI" providers need to be treated as a separate certificate sources and I also don't understand what are In my experience certificate that is present in the store can be linked with the private key managed by CNG or CAPI provider. And since .NET Framework 4.6 I almost never need to know which particular one because new APIs work nicely with both of them. Let me demonstrate that with a code sample that signs and verifies some data with two certificates located in Sample demonstrates that using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace CryptoProvidersTest
{
public static class Program
{
private static readonly byte[] _testData = Encoding.ASCII.GetBytes("Hello world!");
public static void Main(string[] args)
{
// Find both CAPI and CNG certificates in CurrentUser\My store
X509Store x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
x509Store.Open(OpenFlags.ReadOnly);
X509Certificate2 capiCert = x509Store.Certificates.Find(X509FindType.FindBySubjectName, "CAPITestCert", false)[0];
X509Certificate2 cngCert = x509Store.Certificates.Find(X509FindType.FindBySubjectName, "CNGTestCert", false)[0];
x509Store.Close();
// Sign and verify some data with both CAPI and CNG certificates using the same code
foreach (X509Certificate2 cert in new X509Certificate2[] { capiCert, cngCert })
{
if (cert.PublicKey.Oid.FriendlyName == "RSA")
{
// Note: cert.GetRSAPrivateKey() is available since net46
RSA rsaPrivKey = cert.GetRSAPrivateKey();
byte[] signature = rsaPrivKey.SignData(_testData, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// Note: cert.GetRSAPublicKey() is available since net46
RSA rsaPubKey = cert.GetRSAPublicKey();
if (!rsaPubKey.VerifyData(_testData, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
throw new Exception("Signature is invalid");
}
else
{
// Note: ECDSA keys can be supported with cert.GetECDsaPrivateKey() and cert.GetECDsaPublicKey() available since net461
throw new Exception("Unsupported type of private key");
}
}
}
}
} My questions:
|
@jariq Thanks for the detailed feedback. I agree, certificate store and CNG/CAPI do not need to be a separate source. -CryptographicServiceProvider and -KeyContainer options can be used to supply the private key in case the certificate does not contain the private key. |
@emgarten can you please look at the API requests/feedback? |
@mishra14 in my experience all you need to do in such case is to import certificate into the store and run Feel free to correct me if I am wrong but in my opinion |
Please provide more details about the expected format of the file specified by |
@jariq Thanks for the feedback.
csp and kc are helpful in org level signing where the private keys are not directly accessible.
The option is primarily for using PKCS#12 (pfx) files. |
Unfortunately this does not really provide much more detail to me but I guess I'm OK with |
Closing this issue as the spec is done. |
Folks couple of updates to the spec -
|
Goal: Tracking the spec for #5904
The text was updated successfully, but these errors were encountered: