I have a DLL which creates a signature based off a JSON. The signing is used with X509 self signed certificate with a public \ private keys (.crt and .pfx files), the DLL is using the private key (pfx file) to sign the data.
This DLL is used twice: once in my actual project, which runs on a linux container, and once in my local tests project, which runs on my windows machine.
There is a second DLL uses the public key to verify the signature (crt file).
Here's the thing: the signature created in my test project matches the signature created in my verifier project, both are windows machines. The project on the linux machine signs differently.
What is going on here?? I have several directions:
Different newlines between linux and windows: I have changed the signing DLL so that it takes the JSON string, deserializes into Newtonsoft.JSON object, serializes again with flag Formatting.None, and then deserializes for the final time. This did not help.
Different invisible characters \ encoding: my code is calling UTF8.GetBytes internally on the string, so don't think it's that.
Additionaly, I took the literall byte array from the linux machine into the windows machine, and got different signatures.
Which leads me to think, is the library System.Security.Cryptography.Xml(5.0.0) behaves differently between the OSs? this page says yes, but does not say how:
Cryptographic operations in .NET Core and .NET 5 are done by operating system (OS) libraries. This dependency has advantages
Any ideas as to why this is happening, and maybe a solution?
My signer code:
...
JToken data = JToken.Parse("{}") //obviously a different string
var certificate = new X509Certificate2(...);
var rsaCSP = new RSACryptoServiceProvider();
rsaCSP.FromXmlString(certificate.PrivateKey.ToXmlString(true));
var signatureBytes = rsaCSP.SignData(Encoding.UTF8.GetBytes(data.ToString(), CryptoConfig.MapNameToIOD(...));
Related
We have created a signature in a .Net Core web api, using X509Certificate2.GetECDsaPrivateKey on a .pfx certificate file, and need to verify this signature in our Xamarin Android app, using the public key (.crt). I can run the code on a normal Windows .Net Framework 4.6.1 app and it works. If I change the Framework version to anything lower, my app doesn't compile, as the GetECDsaPublicKey method was only implemented in 4.6.1. In my Xamarin app, I can compile the app and it runs, but as soon as I reach the line that executes the GetECDsaPublicKey method, I get a NotImplemented exception. There is literally no information on this on the internet, apart from the Microsoft documentation, which doesn't give much in any case. Can anyone shed any light onto why this error occurs? Here are the few lines of code to load the certificate and verify the signature (I've taken out some unnecessary error checking code):
string FileName = "public_key.crt";
string certPath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), FileName);
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath);
System.Security.Cryptography.ECDsa eCDsa = certificate.GetECDsaPublicKey(); // This line causes the exception
Even just executing this line, gives the same error:
System.Security.Cryptography.ECDsa eCDsa = System.Security.Cryptography.ECDsa.Create();
So if anyone comes across this also struggling with it, there is a post that answers this question - Are ECDSA and ECDH available for mono?
Sadly, we will have to either use a different encryption/signing algorithm or use something like BouncyCastle...
I'm looking to generate ssh keypairs in open SSH format via code within my web-app (hosted in windows machine) instead of having to manually create it using puttygen.
So, far I've not found any free library that can do this. (There doesn't seem to be a ssh-keygen equivalent for windows.) I am aware of the Cygwin route but I'm trying to avoid this as this would involve having to install cygwin on any servers hosting the app making it not ideal.
What are my options? Will I have to extract out the key-gen function from putty-gen-source and re-write it in c#?
RSA rsa = new RSACryptoServiceProvider(2048);
string publicPrivateKeyXML = rsa.ToXmlString(true);
string publicOnlyKeyXML = rsa.ToXmlString(false);
and then you can parse the XML using XML reader or XML document to get the value you want.
Our organization recently adopted Box to replace Windows shared folders. The small development group I'm a part of will need to upload and download files from at least one Box share and so we are just getting started with the API.
Our group currently uses Visual Studio 2013 to develop in C# with a preferred target of .NET 4.0. The current version of the SDK (2.15.6) isn't compatible with our platform but looking at prior versions it appears we should be able to leverage version 2.12.1 with our existing platform. The SDK includes a solution with C# methods to access the API calls and a solution with sample code.
Presently I'm trying to get the sample code to consume my credentials and authenticate to the server.
Within the Box developer tools I have created an application and used the built-in Box configuration option to generate a Public/Private keypair which is presented as a JSON file.
Where I'm getting hung up is when I try to use the keypair with the Box.V2.Samples.JWTAuth project. I copied the private key out of the JSON file, replaced the \n's with actual carriage returns, and pasted it into the private_key.pem file:
Private Key
I placed the other values in app.config and started the console app, which produces an Unable to cast error:
Error message
How can I get from a BouncyCastle RsaPrivateCrtKeyParamaters object to a BouncyCastle AsymmetricCipherKeyPair object?
Edit
I was able to track down the problematic code block. From SDK\Box.V2.JWTAuth\BoxJWTAuth.cs:
var pwf = new PEMPasswordFinder(this.boxConfig.JWTPrivateKeyPassword);
AsymmetricCipherKeyPair key;
using (var reader = new StringReader(this.boxConfig.JWTPrivateKey))
{
key = (AsymmetricCipherKeyPair)new PemReader(reader, pwf).ReadObject();
}
var rsa = DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)key.Private);
this.credentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest);
From my reading it seems like the code is anticipating having to extract the Private key from a Public/Private pair which isn't what Box is supplying (at least, not currently) and what I'm supplying appears to already be of the RsaPrivateCrtKeyParameters type so this cast may (no longer be) necessary.
It's not clear from your question whether you are trying to write code to do this, or trying to configure a tool, but programmatically, it would be:
RSAPrivateCrtKeyParameters priv = ...;
RSAKeyParameters pub = new RSAKeyParameters(false, priv.getModulus(), priv.getPublicExponent());
AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(pub, priv);
What I currently do is that I use OpenSSL to generate PFX file. This is causing an unwanted dependency, especially for Windows users. So I found some examples on how to create your own certificate using BouncyCastle, but this library is not .NET Core compatible (or I failed to find the compatible package).
So, is it possible to create your own self signed X509 certificate using just .NET core to avoid dependency on OpenSSL (or any other certificate generating external tool)?
EDIT: It was suggested by someone (editor?) that this SO question How to create a self-signed certificate using C#? provides an answer. Sadly again, this has nothing to do with .NET Core. The accepted answer there starts with This implementation uses the CX509CertificateRequestCertificate COM object (and friends - MSDN doc) from certenroll.dll to create a self signed certificate request and sign it, which is obviously NOT .NET Core ... In fact, none of the answers there is .NET Core compatible.
I found this other SO question that put me on the right track. Certificates API was added to .Net Core on 2.0 version. I have a function like the next one to create self signed certificates that I later import into My store to use them on IIS.
private X509Certificate2 buildSelfSignedServerCertificate()
{
SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddIpAddress(IPAddress.Loopback);
sanBuilder.AddIpAddress(IPAddress.IPv6Loopback);
sanBuilder.AddDnsName("localhost");
sanBuilder.AddDnsName(Environment.MachineName);
X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN={CertificateName}");
using (RSA rsa = RSA.Create(2048))
{
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature , false));
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));
request.CertificateExtensions.Add(sanBuilder.Build());
var certificate= request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
certificate.FriendlyName = CertificateName;
return new X509Certificate2(certificate.Export(X509ContentType.Pfx, "WeNeedASaf3rPassword"), "WeNeedASaf3rPassword", X509KeyStorageFlags.MachineKeySet);
}
}
If you want the pfx, the Export function on X509Certificate2 should do the trick. It returns a byte array with the raw pfx data.
The Microsoft way is doing this with makecert and pvk2pfx (from the windows SDK), and not in the .net code itself. Now Im not very familiar with .net core, but since the full blown .net doesn't have native support, it would surprise me very much if the core version does have the function.
here's a description of how to do that:
https://msdn.microsoft.com/en-us/library/ff699202.aspx
Edit: Let me rephrase it: Without external dependancies it is not available in .net (core)..
There are ways in full blown .net but you need external dll's for that.
I believe I have a foundational understanding of the X509Certificate and have created certificates and private keys for my Development environment. Getting more acquainted now with the X509Certificate Class and other relevant permissions also.
So in the process, I decided to test a certificate after having installed it on my system. Then using the following code, I attempted to validate the check process for certification authentication:
const string x509Cert = #"\PathToMyCertificate\LMC.cer";
var cert = new X509Certificate(x509Cert);
var pmc = new PublisherMembershipCondition(cert);
if(pmc.Check(Assembly.GetCallingAssembly().Evidence))
{
Console.WriteLine("Assembly belongs to publisher");
}
Of course as expected, the inner block of code doesn't execute. So then I figured to simply sign my assembly using the certificate key, but "simply" wasn't as simple as I'd anticipated.
I used the following code in effort of assigning the certificate to my applications Evidence:
var publisher = new Publisher(X509Certificate.CreateFromCertFile(x509Cert));
var evidence = Assembly.GetCallingAssembly().Evidence;
evidence.AddHost(publisher);
// Create an identity permission based on publisher evidence.
var x509Permission = (PublisherIdentityPermission)publisher.CreateIdentityPermission(evidence);
x509Permission.Demand();
But this didn't seem to work either. Next, I checked the properties of my project to see if there was any way to sign it there using the X509Certificate key but nothing. The only option I see that comes close is to sign with Click Once manifests; but the "Select from file" option is looking for a .pfx extension. So I think maybe this method only works to support certificates generated by Click-Once?
Per BOL, "If you have a key file or certificate in another format, store it in the Windows certificate store and select the certificate is described in the previous procedure." I installed my X509Certificate in the Trusted Root Certificate Authorities store. Wouldn't that be a Windows certificate store? Because nothing shows up in the Certificate Store window.
Searching online resources didn't yield much either unless I am using the wrong combination of keywords. Now I could create another X509Certificate and key ensuring that the extension of the key is .pfx but I wanted to make certain that I am on the right course of resolve before spinning my wheels for nothing and I don't believe that would be the answer.
So, can a .NET assembly be signed using an X509Certificate? If so, what documentation is available to assist in performing this task?
Publisher* classes are associated with Authenticode(tm).
Look for the command-line tools:
* signcode (or signtool)
* chktrust
for how you can sign any .exe, .dll (and .cab, .ocx) using a valid code-signing certificate. A google search on Authenticode or "code-signing certificate" can also be helpful.
The question is what you want to do. There exist .NET signing (using RSA keypair) used for strong-naming the assemblies, and there exists Authenticode which lets you sign any file in PE format including assemblies in DLL files. Note, that Authenticode is not .NET-specific and knows nothing about .NET. It signs PE structure.
As said by poupou, for Authenticode signing (using X.509 certificates suitable for Code Signing) you can use SignTool.exe tool. .NET will verify the signature when it loads the assembly, but in some cases such verification can take extra seconds (if the OS performs CRL and OCSP checking of certificates in the chain), slowing down assembly loading.
So you need to choose the right tool and define what you want to achieve (signing is a method, not a goal).