PGP Encryption with BouncyCastle C# causes invalid key warning on signature verification - c#

We need to PGP encrypt files and send them over FTP to a third party. The files are encrypted with the DH/DSS public key of the third party and signed with our private key.
The third party have our public key and their own private key. The encryption/decryption works, but the third party are getting warnings when they try to verify our signature.
When we try to decrypt and verify similarly encrypted files using PGP Desktop the files verify without warning.
The third party are using "McAfee E-Business Server"
The exact warning is:
WARNING: Bad signature, doesn't match file contents!
Bad signature from user "users name"
The code is a little involved, but I posted it on my blog. I can post it here instead of a link if that is more appropriate.
Any insight as to how to solve this issue is appreciated.

While I can't give a thorough explanation as to the details of the problem, here is a solution that works.
First of all it seems that the different PGP implementations are very sensitive to which program was used to genereate the keys in use.
The failing scenario:
Create keys in PGP Desktop (RSA v4, 2048/2048)
Encrypt in BouncyCastle (DH/DSS, Elgamal)
Sign in BouncyCastle (With the RSA key)
Decryption and signature verification success in PGP Desktop.
Decryption success but signature verification fails in McAfee Business Server.
In order to make McAfee Business Server succeed in verifying the keys either create the keys in BouncyCastle using the code from the BouncyCastle source code.(Org.BouncyCastle.Bcpg.OpenPgp.Examples.RsaKeyRingGenerator)
This code can be changed if you need specific key properties.
Another alternative is to use McAfee Business Server to generate the keys. For that you need access to the software. I did my tests with a trial version. (Which by the way was a pain in the neck to get up and running)
Update: I did all my tests on E-Business Server 8.5.3 (trial). I reached the point where I could encrypt and sign in Bounty and decrypt and verify in E-Business Server. Turns out the third party are using E-Business Server 7.0 which refused to verify the signature.
In order to get everything working we needed to create V3 signatures.
We changed from:
PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(m_encryptionKeys.SecretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
to
PgpV3SignatureGenerator pgpV3SignatureGenerator = new PgpV3SignatureGenerator(m_encryptionKeys.SecretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);

Related

Download file from SFTP with p12 certificate in C#

I have tried searching for the above and found SSH.NET, but I am not sure:
If it suits my case.
How to use it the way I need it to work.
I have a client with an SFTP - to which he connects using a normal third party tool like FileZilla.
I have the credentials etc. and need to download files from that SFTP.
Unfortunately for me, the SFTP requires a p12 certificate (which I have), which I do not know how to use. I have not yet worked with SFTP's.
The connection is: "interactive"
For a "normal" FTP I would simply get the response stream of a FtpRequest and cast its information to whatever I need it to be.
Question: How do I use a p12 certificate to establish a connection to a SFTP using C# without buying one of the commercial third party libraries?
I would be thankful, for both direct tips, but also reading material for the topic.
Are you sure you want to use the SFTP? I've never seen anyone using P12 key with the SSH/SFTP. Maybe you mistake the SFTP with the FTPS [FTP over TLS/SSL]?
Anyway, the NET.SSH library supports only OpenSSH and ssh.com private key file formats. So you need to convert your P12 key to either of them.
Quote from Extract public/private key from PKCS12 file for later use in SSH-PK-Authentication:
You can use following commands to extract public/private key from a
PKCS#12 container:
PKCS#1 Private key
openssl pkcs12 -in yourP12File.pfx -nocerts -out privateKey.pem
Certificates:
openssl pkcs12 -in yourP12File.pfx -clcerts -nokeys -out publicCert.pem
First of all you seem to confuse SFTPwith FTP-over-SSL. These are two different protocols. From your question it seems that you need FTP-over-SSL.
In simple cases where you need to just download a file, FtpWebRequest class of .NET will work. In more complex cases third-party libraries are required.
If you need to deal with SFTP, the situation is more complicated. SSH doesn't usually work with X.509 certificates (such configuration is possible but is almost never used). You won't get this functionality with open-source libraries.

Where should I put the public key in a standalone application

I wrote an C# WPF application that signs a license xml file using the standard .Net SignedXml class. I am able to extract the public and private key as xml strings. I can safely tuck away my private key locally for the signing application, but what about the public key needed in the remote sign check application (library)? Options considered:
KeyContainer: no good, because signing and checking happens in 2 separate environments
Hardcoded: hardcode the public key as xml string in my checking library. I know the public key is not secret, but how can I prevent hackers from replacing the key with their own? I can sign the library, but then they could tamper with the application using the library....
Put the public key in a standard digital certificate that you distribute with your app. The integrity of the certificate will then be guaranteed by Windows, and you can tell if it's been changed.
Of course both the hardware and Windows itself is under the control of any potential attacker, so you can't really prevent a compromise of a specific machine.
Here's an example from a program that I used to distribute. When the program was activated from a licence perspective, it sent a hardware hash to a web service. This returned a self-signed certificate containing the hardware hash, which my program then checked whenever it was started. If the certificate had been changed in any way, the program would stop.
I put the public key in a directory outside of the inetpub directory, and if you move the private key off of the computer, then the worst someone could do is to replace the public key and it no longer can decrypt, but you could be informed when it can't decrypt to know something happened.
But, if someone was able to change your file you will have bigger problems that just having this one file changed.
UPDATE:
Oops, I missed that this is a WPF program. Unfortunately the best you can do is to have the private key separate from the public key, so, you can decrypt, but if the hacker changes the public key the application won't function properly.
That is one of the advantages of using the public/private key, to verify that only you can do the encryption.
The other option is to fetch the public key from a webserver, but then you have the same problem in that it is possible for someone to trick the application to go to the wrong server, so it isn't full-proof, and it will require that the user had an Internet connection, and for you to uniquely identify them.

Auto Update Downloading Latest .exe file - how to verify it's not been tampered with?

We have a small console application (under 200kb) that will be distributed to clients and we want to ensure they run the latest version (verified by a WCF service). Currently it downloads the new .exe file over HTTPS and replaces the current .exe file with it.
Assuming our server isn't compromised, this would be ok. However we also sign our .exe file with a Code Signing certificate. Is there a way to verify this and delete the file if it doesn't match? We would need to be able to verify and delete the file without it ever being executed in case it is a virus.
How can we verify our signed .exe file? For example, Windows will show if it is invalid:
Edit: would this code do the job?
X509Certificate basicSigner = X509Certificate.CreateFromSignedFile(file);
X509Certificate2 cert = new X509Certificate2(basicSigner);
if (cert.Subject.Contains("CN=MY COMPANY NAME IN CERTIFICATE"))
valid = true;
Edit: if we also check StrongNameSignatureVerificationEx, it comes back failed if one bit is changed in the file. Perhaps this is enough?
[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);
Edit: I've implemented this code too which calls WinVerifyTrust in WinTrust.dll to actually verify the Authenticode signature: http://www.pinvoke.net/default.aspx/wintrust.winverifytrust
Now, it checks if the digital signature contains the correct subject, is from a valid trusted root, the signature is valid and if the code is strong named with it's digital signature. This must be safe enough now?
This is a nice walkthrough including source code on the options available to achieve what you want...
Basically you need to pinvoke StrongNameSignatureVerificationEx since there is no managed API to do what you need.
Another option might be to call SignTool.
This is a pretty fundamentally wrong way to go about it. The only thing that a code signing certificate proves is the identity of the person or company that signed the EXE. The certificate authority merely proves that identity is valid. What you haven't proved at all is that it is your certificate, you only proved that it is somebody's certificate. An attacker could trivially replace your EXE with another one that was signed by him.
You'll probably object with "but can't I just verify it is mine!". And the answer is no, if the attacker can replace the EXE then he'll have no trouble replacing your checking code either. There is zero security in having the verification performed on the same machine.
Code certificates serve only one purpose, they prove the identity of the signer to the user. Making them do anything else is a security hole. The really bad kind, the kind that make you feel that your system is secure. And make you stop thinking about implementing real security.

How to set the publisher name for a Windows Forms application

I have created the setup of a Windows Forms application. After installing this setup in Windows 7, it displays something like this:
Name: my application.exe
Publisher: unknown publisher
Type: application
From: my application.exe
I want to set the publisher name. How do I set the publisher name?
You need to digitally sign the output code. I can start you off with the article Signing and Checking Code with Authenticode.
The whole purpose of this is to guarantee your code has not been tampered with. If you purchase a code signing certificate from one of the certificate authorities, you can prevent the "do you trust this" window from appearing at all.
It's not a simple task to set up, but it can be performed with a script once it's up and going.
You won't find a simple, quick-fix answer.
Here's a cut and paste of the most relevant sections. You may need to read further to get exactly what you want.
MakeCert
Use the MakeCert test program to generate a test X.509 certificate. MakeCert performs the following tasks:
Creates a public/private key pair for digital signatures and associates it with a name that you choose.
Associates the key pair with a publisher's name that you choose.
Creates an X.509 certificate , signed by the test root key or one you specify, that binds your name to the public part of the key pair. The certificate is output to a file, a system certificate store, or both.
MakeCert Internet Explorer 3.02 UPD Example
The following is an example that creates a certificate using the Microsoft Internet Explorer 3.02 UPD options:
MakeCert -k:c:\KeyStore\MyKey.pvk -n:CN=MySoftwareCompany Cert.cer
In this example, a certificate file called Cert.cer is created. The public part of the key pair called MyKey is bound to the publisher, MySoftwareCompany.
Cert2SPC
After you have generated a certificate, you can create an software publishing certificate with the Cert2SPC program. This program wraps multiple X.509 certificates into a PKCS #7 signed-data object. Note that this program is for test purposes only. A valid software publishing certificate is obtained from a certificate authority.
Here is an example:
Cert2SPC MyCert.cer MyCert.spc
This wraps an X.509 certificate, MyCert.cer into a PKCS #7 software publishing certificate called MyCert.spc.
SignCode
The final step is to actually sign a file using the SignCode program. This program will:
Create a Cryptographic Digest of the file.
Sign the digest with your private key.
Copy the X.509 certificates from the software publishing certificate into
a new PKCS #7 signed-data object. The PKCS #7 object contains the serial
numbers and issuers of the certificates used to create the signature, the
certificates, and the signed digest information.
Embed the object into the file.
Optionally, it can add a time stamp to the file. A time stamp should always be added when signing a file. However, SignCode also has the ability to add a time stamp to a previously signed file subject to some restrictions (see the examples that follow the options table).
Once the file has been signed (assuming you have a valid certificate) and time stamped, the file can be distributed to your customers. Note that certificates generated with the test programs MakeCert and Cert2SPC are NOT valid for signing code that will be distributed to the public. Independent software vendors must obtain a certificate from GTE, VeriSign Inc., or another certification authority for signing code that will be distributed to the public.
SignCode Examples for Internet Explorer 3.02 UPD
Here are two examples of how to sign and time stamp a file using the Microsoft Internet Explorer 3.02 UPD options. The first uses a private-key name MyKey and the second uses a private-key file My.pvk:
SignCode -prog MyControl.exe -spc Cert.spc -pvk MyKey -timeStamper http://timestamp.verisign.com/scripts/timstamp.dll
SignCode -prog MyControl.exe -spc Cert.spc -pvk My.pvk -timeStamper http://timestamp.verisign.com/scripts/timstamp.dll
Note In the URL above, timstamp.dll is correct. This is not a typographical error.
In both cases a PKCS #7 object, Cert.spc, is embedded into the digest of the file, MyControl.exe. In the first example, the digest is signed with the private key of the MyKey key pair, and a time stamp is added. In the second example, the digest is signed with the private-key file My.pvk, and a time stamp is added.

Import certificate with private key programmatically

I'm trying to use the HttpListener class in a C# application to have a mini webserver serve content over SSL. In order to do this I need to use the httpcfg tool. I have a .pfx file with my public and private key pair. If I import this key pair manually using mmc into the local machine store, everything works fine. However, if I import this key pair programmatically using the X509Store class, I am not able to connect to my mini webserver. Note that in both methods the cert is getting imported to the MY store in LocalMachine. Oddly, I am able to view the certificate in mmc once I programmatically import it and when I view it, the UI indicates that a private key is also available for this certificate.
Digging a little deeper, I notice that when I manually import the key pair, I can see a new file appear in C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys, but one does not appear when I import programmatically. On a related note, when I delete a manually imported certificate, it does not remove the corresponding private key file from the previously mentioned directory.
Ultimately, my question is this: When I programmatically add the certificate to the store, where is the private key being stored and why isn't it accessible to the HttpListener class (HttpApi)?
Note that this question is slightly related but I don't think permissioning is the problem since this is all being done as the same Windows user:
How to set read permission on the private key file of X.509 certificate from .NET
Ok, I figured it out. It had to do with the key storage parameters for the certificate object. For anyone else that runs into this problem, make sure you construct your X509Certificate2 objects that you are adding to the store using the X509KeyStorageFlags.PersistKeySet and X509KeyStorageFlags.MachineKeySet flags. This will force the private key to persist in the machine key set location which is required by HttpApi (HttpListener wraps this).
Is this a 2 way SSL? If it is then did you send over a SSL Certificate Request file generated on your machine? This Certificate Request file will be used to create the SSL and they together form a public private key pair.
Also did you try assigning the cert permission for the user account that is being used to run the web app? You can do this by using the Microsoft WSE 3.0 tool.
Not exactly the answer to your question, but here for reference of others going down this path:
Here is a link to a MS chat that gives sample C# code to do what httpcfg does, thus eliminating the need for the tool on deployment.

Categories