Loading X509Certificate results in exception CryptographicException "Cannot find the original signer" - c#

I am trying to instantiate an X509Certificate object, but I keep running into the same CryptographicException, with the error message:
"Cannot find the original signer".
I have tried several ways of loading the certificate:
// some different things that I have tried
var cert = X509Certificate.CreateFromCertFile(certFileName);
var cert2 = new X509Certificate(byteArray);
var cert3 = new X509Certificate(byteArray, secretString);
var cert4 = X509Certificate.CreateFromSignedFile(certFileName);
I have tried both loading from a file and from a byte array. Each time I get the same error. What could be causing this?

I figured out the problem. I was attempting to load just the certificate file, which did not include the private key. To fix the problem, I had to install the private key on the machine on which the certificate was purchased, and then export it as a .pfx file and move it to where I actually wanted to use it. I'm sure was a newbie mistake. Hopefully, my silly issue will help other newbies in the future.

var collection = new X509Certificate2Collection();
collection.Import(byteArray);
return collection;
via https://stackoverflow.com/a/44073265, by https://stackoverflow.com/users/6535399, who writes crypto for msft - e.g. https://github.com/dotnet/corefx/pull/25920

Related

C# Launching another WPF program from a byte array [duplicate]

This question already has answers here:
Load WPF application from the memory
(2 answers)
Closed 6 years ago.
First of all, let me say that I've looked through this, and i still haven't been able to find a great solution to my problem. (I will elaborate in post)
Now to the point.
I have a program which I want to secure with a login.
My setup is as follows:
Login.exe
Application.exe (Gathered from server into byte[])
The user should login, and when successfully logged in, get the server file (Application.exe) and run it, however this file must not be stored locally on the users machine. Instead, this file, which is stored as a byte array, should be launched as a program, but, if possible, not with a location on the harddrive.
Here's how the user would see it:
First they'd get the login application, login and the application
would download the file from server, and execute it.
Now the main problem i've been struggling with is, that whenever i load this byte array, i get the following Exception:
System.Reflection.TargetInvocationException: The destination of an activation triggered an exception. ---> System.InvalidOperationException: Can not create more than one instance of System.Windows.Application in the same AppDomain.
I've tried with multiple ways, but I've always ended up with the following code:
Assembly a = Assembly.Load(tmpbytearray);
MethodInfo method = a.EntryPoint;
if (method != null)
{
object o = a.CreateInstance(method.Name);
method.Invoke(o, null);
}
I've also tried with
Assembly assembly = Assembly.Load(tmpsrc);
//entrypoint: MyMainApplication.App.Main
Type type = assembly.GetType("MyMainApplication.App");
var obj = Activator.CreateInstance(type);
type.InvokeMember("Main",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
null);
But still stuck with the same Exception.
As I've read through the reference (Section B and C) from the top I've also seen the usage of CreateInstanceFromAndUnwrap, but as I can't find a way to supply it with a byte array, instead of a file path, I've decided not to go that way.
Now I'm back to square one, and therefore asking here in my last hopes to sum up a solution to this project.
If i've made some misunderstandings throughout the post, feel free to ask, as I will do my best to be as clear and understandable as possible.
Thanks in advance!
UPDATE (Maybe another approach)
I've now thought of making a small console based application, which would act as a "launcher" for this application. However this also gives an exception:
System.Reflection.TargetInvocationException: The destination of an activation triggered an exception. ---> System.IO.IOException: The resource mainwindow.xaml was not found.
This exception is really weird, as the application itself works when ran. So the following:
Assembly a = Assembly.Load(tmpsrc);
MethodInfo method = a.EntryPoint;
if (method != null)
{
object o = a.CreateInstance(method.Name);
method.Invoke(o, null); //Exception.
}
Depending on what might be the most easy solution, what would you prefer, and how would you think of a possible solution to any of the approaches (The second, or first approach)?
(I cannot mark this as complete, but this question has now been solved)
So, some struggles later, I've finally managed to get this working.
I ended up trying many things, but the solution for me was based on this question.
I took the loader class in my Login Application and added the rest after the login has been authorized successfully:
var domain = AppDomain.CreateDomain("test");
domain.Load("Login");
var loader = (Loader)domain.CreateInstanceAndUnwrap("Login", "Login.Loader");
loader.Load(tmpsrc);
After that it somehow worked, which i'm quite surprised for. But anyways, thanks for the help and pinpoints into the proper subjects!

C# Certificate Renewal Request

The code below tries to renew existing certificate.
The certificate is renewed, but new public/private key is generated despite that the option X509RequestInheritOptions.InheritPrivateKey is specified.
What is wrong in the code below, because the intention was to keep the existing private key?
In the certficates management console, I can renew the certificate and keep the exisintg private key.
string certificateSerial = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
X509Certificate certificate = getCertificate(certificateSerial);
var objPkcs7 = new CX509CertificateRequestPkcs7();
objPkcs7.InitializeFromCertificate(X509CertificateEnrollmentContext.ContextUser, true,
Convert.ToBase64String(enrollmentAgentCertificate.GetRawCertData()),
EncodingType.XCN_CRYPT_STRING_BASE64,
X509RequestInheritOptions.InheritPrivateKey & X509RequestInheritOptions.InheritValidityPeriodFlag);
IX509Enrollment ca = new CX509EnrollmentClass();
ca.InitializeFromRequest(objPkcs7);
ca.Enroll();
Thanks
It seems the problem is in the MSDN documentation:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa379430%28v=vs.85%29.aspx
The page states: "..You can also use a bitwise-AND operation to combine the key inheritance choice with InheritNone or with any combination of the following flags...".
However, if we use bitwise-AND between InheritPrivateKey = 0x00000003 and InheritValidityPeriodFlag= 0x00000400 we get 0 which is InheritDefault (i.e. no private key inheritance)
For my use case we need to use bitwise-OR. It seems the C++ SDK example does the same:
https://github.com/theonlylawislove/WindowsSDK7-Samples/blob/master/security/x509%20certificate%20enrollment/vc/enrollpkcs7/enrollPKCS7.cpp
hr = pPkcs7->InitializeFromCertificate(
ContextUser,VARIANT_FALSE, strOldCert,
XCN_CRYPT_STRING_BINARY,
(X509RequestInheritOptions)(InheritPrivateKey|InheritTemplateFlag));
In that context the code above shall be modified as:
X509RequestInheritOptions.InheritPrivateKey | X509RequestInheritOptions.InheritTemplateFlag);

Slow performance of X509Certificate2.PrivateKey

I'm loading a certificate from the certificate store. So I have a X509Certificate2 object.
Next I load the private key which I use for signing a message. The code I'm using is:
public static RSACryptoServiceProvider GetPrivateKey(X509Certificate2 cert)
{
var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
var privateKey = (RSACryptoServiceProvider)cert.PrivateKey; //very slow
var cspparams = new CspParameters(enhCsp.ProviderType, enhCsp.ProviderName, privateKey.CspKeyContainerInfo.KeyContainerName);
return new RSACryptoServiceProvider(cspparams);
}
The issue I'm having is that the line:
var privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
takes very very long. Around 9 seconds on my laptop. It would seem that this does not happen every time I try to access the private key. Sometimes it's in the order of milliseconds and other times it takes as long as described.
Any insight into why? Is there a way to avoid that?
UPDATE:
I've been experimenting a bit after noticing this KB article and some other SO issues.
It really seems like that delay is never there when there is no network connectivity.
I wonder if I really have to go decompiling .NET assemblies to sort this out...
UPDATE 1:
It appears as though certificates/key pairs that are issued by a real authority are not affected. I'm seeing this issue when trying to load private key for issuers which I've manually added to the trusted root certification authorities

ssh.net sftp Bad Packet length / open SSH version 2 RSA?

I'm new to sftp and i'm trying to get a c# program to send a file via sftp to a remote server not under my control.
Using code like:
using (var sftp = new SftpClient(FTPAddress, FTPName, FTPPassword))
{
ConnectionInfo myCI = sftp.ConnectionInfo;
sftp.Connect(); // <<<< Exception on connect
sftp.UploadFile(sftp_ms, FileName,true);
sftp.Disconnect();
}
I receive a "Bad packet length" exception.
Google searching reveals that a bad packet length is likely to be a mismatch in encryption formats but I don't know how to resolve that.
The specification i've received from the client is:
Keys must be in Open SSH version 2 format RSA format
I don't know how to do this. A previous SO question How to resolve a 'Bad packet length' error in SSH.NET? has a link to sshnet.codeplex discussion where removing the encryption keys that you don't want solved the issue for that poster.
I can see 16 entries in ssh.net's connectioninfo class but none of them state open SSH version 2 RSA though one of them may very well be (i've tried googling).
I have tried the ip, name and password i've been given with filezilla and I connect no problems; so filezilla somehow uses the correct encryption; I don't know how to tell what it's using.
Help ?
Andrew
You've got two different problems here. If you're getting the bad packet length problem, then you probably have to follow the guide in the ssh.net Codeplex discussion to resolve the negotiation. This should resolve the establishing of the initial connection.
If you're required to use an ssh private key for connection, then you have to use one of the constructors that takes an array of PrivateKey objects. One of the constructors for a PrivateKey takes a stream, and you can convert the private key string to the stream using code like:
var privKey = new PrivateKey(new MemoryStream(Encoding.ASCII.getBytes(sshPrivateKeyString)));
var sftpclient = new SftpClient(FTPAddress, FTPName, new PrivateKeyFile[] { privKey });
Other mechanisms are to use an explicit PrivateKeyConnectionInfo instance:
var privKey = new PrivateKey(new MemoryStream(Encoding.ASCII.getBytes(sshPrivateKeyString)));
var privConnInfo = new PrivateKeyConnectionInfo(FTPAddress, FTPName, privKey);
var sftpClient = new SftpClient(privConnInfo);

Reading a certificate signing request with C#

I want to read the contents of a CSR in C#. However, I haven't found any way to do it in C#.
What I've found was the namespace System.Security.Cryptography.X509Certificates, but it only handles existing certificates, not certificate requests.
Can anyone give me an hint about it?
Thanks in advance.
There is a way, the CertEnroll library which comes with Windows (although I can't say how far back it's been there) allows you to load certificate requests and have them parsed.
First you need to import a reference to the CERTENROLLLib COM library into your project. This will create a CERTENROLLLib name space you can then use.
Then you do something like this;
string csr = "-----BEGIN CERTIFICATE REQUEST-----\r\n" +
"MIIBnTCCAQYCAQAwXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIw\r\n" +
"EAYDVQQDEwlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5l\r\n" +
"eGFtcGxlLmRvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr1nYY1Qrll1r\r\n" +
"uB/FqlCRrr5nvupdIN+3wF7q915tvEQoc74bnu6b8IbbGRMhzdzmvQ4SzFfVEAuM\r\n" +
"MuTHeybPq5th7YDrTNizKKxOBnqE2KYuX9X22A1Kh49soJJFg6kPb9MUgiZBiMlv\r\n" +
"tb7K3CHfgw5WagWnLl8Lb+ccvKZZl+8CAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GB\r\n" +
"AHpoRp5YS55CZpy+wdigQEwjL/wSluvo+WjtpvP0YoBMJu4VMKeZi405R7o8oEwi\r\n" +
"PdlrrliKNknFmHKIaCKTLRcU59ScA6ADEIWUzqmUzP5Cs6jrSRo3NKfg1bd09D1K\r\n" +
"9rsQkRc9Urv9mRBIsredGnYECNeRaK5R1yzpOowninXC\r" +
"-----END CERTIFICATE REQUEST-----";
CX509CertificateRequestPkcs10 request = new CX509CertificateRequestPkcs10();
request.InitializeDecode(csr, EncodingType.XCN_CRYPT_STRING_BASE64_ANY);
request.CheckSignature();
Console.WriteLine(((CX500DistinguishedName)request.Subject).Name);
Console.WriteLine(request.PublicKey.Length);
Console.WriteLine(request.HashAlgorithm.FriendlyName);
You can see the only fun part is getting the subject name out, as you need to cast it to a CX500DistinguishedName instance first.
Look at BouncyCastle's C# implementation. Used it for PGP stuff in the past, worked great. Something like this should get you started (not tested):
var textReader = File.OpenText(...);
var reader = new Org.BouncyCastle.OpenSsl.PEMReader(textReader);
var req = reader.ReadObject() as Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest;
var info = req.GetCertificationRequestInfo();
Console.WriteLine(info.Subject);
This is how you do it with OpenSSL.NET library:
// Load the CSR file
var csr = new X509Request(BIO.File("C:/temp/test.csr", "r"));
OR
var csr = new X509Request(#"-----BEGIN CERTIFICATE REQUEST-----...");
// Read CSR file properties
Console.WriteLine(csr.PublicKey.GetRSA().PublicKeyAsPEM);
Console.WriteLine(csr.Subject.SerialNumber);
Console.WriteLine(csr.Subject.Organization);
.
.
.
X509Request type has properties to get everything out of your CSR file text.
It seems to me the best way for you is usage unmanaged CryptoAPI or P/Invoke. CryptoAPI has CERT_REQUEST_INFO data struct and CryptSignAndEncodeCertificate function which can be used with X509_CERT_REQUEST_TO_BE_SIGNED parameter. Of cause theoretically it's possible to encode request manually with respect of AsnEncodedData, because CSR is not complex (see http://en.wikipedia.org/wiki/Certificate_signing_request and http://www.rfc-editor.org/rfc/rfc2311.txt), but I don't think that it has a sense if an implementation already exist in CryptoAPI.
A good examples to create CSR with respect of CryptoAPI you will find in http://msdn.microsoft.com/en-us/library/aa382364(VS.85).aspx and http://msdn.microsoft.com/en-us/library/ms867026.aspx.
To read Certificate Signing request , you can use method LoadSigningRequestPem availaible in class - "System.Security.Cryptography.X509Certificates.CertificateRequest".
using System.Security.Cryptography.X509Certificates;
string csr = #"-----BEGIN CERTIFICATE REQUEST-----
MIICvDCCAaQCAQAwdzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDzANBgNV
BAcMBkxpbmRvbjEWMBQGA1UECgwNRGlnaUNlcnQgSW5jLjERMA8GA1UECwwIRGln
aUNlcnQxHTAbBgNVBAMMFGV4YW1wbGUuZGlnaWNlcnQuY29tMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8+To7d+2kPWeBv/orU3LVbJwDrSQbeKamCmo
wp5bqDxIwV20zqRb7APUOKYoVEFFOEQs6T6gImnIolhbiH6m4zgZ/CPvWBOkZc+c
1Po2EmvBz+AD5sBdT5kzGQA6NbWyZGldxRthNLOs1efOhdnWFuhI162qmcflgpiI
WDuwq4C9f+YkeJhNn9dF5+owm8cOQmDrV8NNdiTqin8q3qYAHHJRW28glJUCZkTZ
wIaSR6crBQ8TbYNE0dc+Caa3DOIkz1EOsHWzTx+n0zKfqcbgXi4DJx+C1bjptYPR
BPZL8DAeWuA8ebudVT44yEp82G96/Ggcf7F33xMxe0yc+Xa6owIDAQABoAAwDQYJ
KoZIhvcNAQEFBQADggEBAB0kcrFccSmFDmxox0Ne01UIqSsDqHgL+XmHTXJwre6D
hJSZwbvEtOK0G3+dr4Fs11WuUNt5qcLsx5a8uk4G6AKHMzuhLsJ7XZjgmQXGECpY
Q4mC3yT3ZoCGpIXbw+iP3lmEEXgaQL0Tx5LFl/okKbKYwIqNiyKWOMj7ZR/wxWg/
ZDGRs55xuoeLDJ/ZRFf9bI+IaCUd1YrfYcHIl3G87Av+r49YVwqRDT0VDV7uLgqn
29XI1PpVUNCPQGn9p/eX6Qo7vpDaPybRtA2R7XLKjQaF9oXWeCUqy1hvJac9QFO2
97Ob1alpHPoZ7mWiEuJwjBPii6a9M9G30nUo39lBi1w=
-----END CERTIFICATE REQUEST-----";
CertificateRequest certReq = CertificateRequest.LoadSigningRequestPem(csr,HashAlgorithmName.SHA256);
Console.WriteLine("Subject Name: {0}",certReq.SubjectName.Name);
I had the same issue. I didn;t find a solution so "invented" ;) on a work around. CertUtil.exe is microsoft's command line utility to create, read,submit, accept and install certs.
I used System.Diagnostics.Process to create external process and passed the CSR request file as argument to read the file into a stream. Heres the code for it.
using (System.Diagnostics.Process extProc = new System.Diagnostics.Process())
{
extProc.StartInfo.CreateNoWindow = true;
extProc.StartInfo.UseShellExecute = false;
extProc.StartInfo.RedirectStandardOutput = true;
extProc.StartInfo.FileName = #"C:\certtest\Util_xpVersion\certutil.exe";
extProc.StartInfo.Arguments = "-dump \"C:\\certtest\\Util_xpVersion\\ToolCSR.crq\"";
extProc.Start();
extProc.WaitForExit();
string sTemp = extProc.StandardOutput.ReadToEnd();
extProc.Close();
}

Categories