.Net Standard 2.0 RSA.ExportParameters(bool) not working on Linux - cryptography

Have implemented some https support infrastructure. In one place need to Convert RSA to pem format. Here found the solution, that works fine on Windows, but as soon as run it in docker with linux, after the construction
var parameters = rsa.ExportParameters(true); have got next error
System.Security.Cryptography.CryptographicException Cannot open an invalid handle. Void CheckInvalidKey(Microsoft.Win32.SafeHandles.SafeRsaHandle)
Is there any alternative to export RSA in pem format ? If not is there any alternative way to get parameters from RSA ?

Related

Apache VFS SFTP Connection hangs

I am using Apache VFS to upload a file to an SFTP server, if the file is newer than the file on the server or doesn't exist there yet. The server connection uses SSH Keys for Authentication.
I am using the following java code (plus error handling etc.) to connect to the server and check the file modification date-time:
DefaultFileSystemManager manager = new DefaultFileSystemManager();
manager.addProvider("sftp", new SftpFileProvider());
manager.init();
FileSystemOptions opts = createDefaultOptions();
BytesIdentityInfo identityInfo = new BytesIdentityInfo(server.sshKey.getBytes(), null);
SftpFileSystemConfigBuilder.getInstance().setIdentityProvider(opts, identityInfo);
remoteFileObject = manager.resolveFile(new URI("sftp",server.UserName,server.HostName,server.Port,remoteFilePath,null,null).toString(), createDefaultOptions(server.Key));
FileContent content = remoteFileObject.getContent();
return content.getLastModifiedTime();
The SSH key is in the format -----BEGIN RSA PRIVATE KEY----- etc.; as exported by puttyGen under Conversions -> Export OpenSSH Key (i.e. the old format of OpenSSH key, not the new one).
I have tested this code on Windows, with a locally hosted SFTP server (i.e. also on the same Windows machine), and it works successfully.
I am now wanting to use this in a Linux environment (RHEL), connecting to an AWS Transfer SFTP server, secured using SSH keys as described.
I can connect successfully using the SFTP command from the Linux OS shell:
sftp -oIdentityFile=/path/to/test.ppk USER#xxx.xxx.xxx.xxx
But, when I try to run the java code, the code hangs on the call to manager.resolveFile.
After half an hour (I think - this might not be related), I get the following in /var/log/messages:
systemd-logind[1297]: Session 115360 logged out. Waiting for processes to exit.
systemd[1]: session-115360.scope: Succeeded.
systemd-logind[1297]: Removed session 115360.
I don't have SELinux enabled, so I don't think that's interfering in any way.
Can anyone help suggest what might be causing this?
There were a couple of things, as it turns out:
Timeout
The timeout can be set when you configure the SftpFileSystemConfigBuilder, by using the .setSessionTimeout(FileSystemOptions, Duration) method call. This reduces the timeout which, if nothing else, makes the issue easier to debug.
The Session comments in the messages log were not related to the issue. Instead, the issue happened because the exec channel is disabled on the SFTP server, but VFS is trying to use it. At a simple level, this can be disabled using setDisableDetectExecChannel on the SftpFileSystemConfigBuilder object - but you should know the implications of this before doing so.

EppLib.net - Which SSL Certificate to use

When using EppLib.net (and as per the Nominet instructions - http://registrars.nominet.uk/namespace/uk/registration-and-domain-management/registrar-systems/epp/testbed)
In order to verify the identity of the secure server you will need the 'Verisign Class 3 Public Primary Certification Authority' root certificate available free from www.verisign.com (the certificate is also distributed with most web browsers).
I am supplying the Verisign Class 3 PPCA Certs in .crt format (I can't export as a pfx) within the code (and have tried every cert installed on the server).
However each one fails with the error (when trying to negotiate the connection):
An existing connection was forcibly closed by the remote host.
I've confirmed that I can connect from the server to Nominet by running cURL
curl -v https://testbed-epp.nominet.org.uk:700
and that responds as I would expect - or at least without an error!
I have also tried to use the same cert that curl appears to be using without success.
Can anyone help with pointing me in the right direction with the SSL that I should be using or how to get hold of the correct certificate?
thanks in advance
For anyone having a similar issue, it wasn't a question of which SSL certificate to use, but to ensure the correct protocol was being used. Incidentally, I got it working initially using the curl-ca-bundle.crt provided with cURL.
This certificate, in combination with a change to the target .net framework for the EppLib.net project resolved my issue.
On cloning from Github the target was .net 4.0 and Nominet needs at least TLS1.1, which wasn't available in v4.
Therefore I also updated the target to 4.5.1 for the EppLib.net project and changed the SslProtocol from
SslProtocol.Tls to
SslProtocol.Tls12

How are people authenticated in their ASP.NET Core Web APIs on Ubuntu/Docker given the bug described below?

I have come across what I think is a bug preventing me from loading an X509Certificate2 on Ubuntu or the Debian-based docker image provided by Microsoft. This means that I can't initialise JwtAuthentication in my web API on these platforms, and I'm looking for help:
Are you successfully using JwtAuthentication on Linux?
If so, how are you initialising an X509Certificate for the JwtBearerOptions?
Can you see a problem with what I'm doing, or suggest a work-around or solution?
I have logged the issue with the corefx team and you can see the full discussion here, but below is the main description of the problem:
I have a Web API running in a docker container. The container is built from the provided 1.1.0 package:
FROM microsoft/aspnetcore:1.1.0
and the Web API binaries are copied in. The API runs fine and returns data as expected until I turn on authentication, at which point it needs an X509SecurityKey to set the TokenValidationParameters.IssuerSigningKey value. It throws an exception when it attempts to initialise an X509Certificate2 from a string value:
string certValue = certificate.Value;
byte[] byteCert = Encoding.ASCII.GetBytes(certValue);
return new X509Certificate2(byteCert);
throws an OpenSslCryptographicException:
Unhandled Exception: System.Exception: Failed to extract the Token Signing certificate from the Federation metadata. --->
Interop+Crypto+OpenSslCryptographicException: error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error
at Internal.Cryptography.Pal.CertificatePal.FromBlob(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] data)
at Mercury.Shared.Rest.Authentication.AdfsFederationMetadata.GetSigningCertificate()
The string value from which the X509Certificate2 is being initialised is:
MIIC4jCCAcqgAwIBAgIQHWt3kGySgJxPtsalC0EoKzANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJBREZTIFNpZ25pbmcgLSBzdHMuYWxsYW5ncmF5LmNvLnphMB4XDTE2MDkwNzA5MDQyM1oXDTE3MDkwNzA5MDQyM1owLTErMCkGA1UEAxMiQURGUyBTaWduaW5nIC0gc3RzLmFsbGFuZ3JheS5jby56YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANdq9BEuBRPsTdpngeFyXbfH5lBg5WyENQW0qz2FtDw3AvZhiPdFyvTPZIeZDc4vhg+gPuG8pCxhFa6hPqNIwnLSVuyhUi4/CtZrLghF2wVVcyriijvirzdVp2m56nO31NB5HXbSerTmey1gJsgumr+MiaM2CEI9z5ctwAp66jqM9jVv7kzqIwB33irSck+X97jUa9XVa0/0QPBdrSVUR0i4rmfZ9orRdTKC3IA13bD9duk2Kc9V7t8t/woo80Kbbb3ZseYk5N8AI+7RRw9+oSAm8zZQzBYkNkAMeI1mto1faXsm9Aea4HXbyCbvVOx/JGj5Ki7YK/BtzWAyCgRu0TkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAd9rdJ1V9te8njMHiEuvr1DLVUBt2YdpZ8qGFC2rWDKeEW8iARrMfbtrlQovvE1radxoZ2gWR1AaaoEqzmLvF9fEAZ7xjR2P2UlT+ZgntfMn/c+3j7gWnfGNHIjosaYiyF72q4k6bgOx1TV8X08kD2AMBH27utXeeUQTZTd0bUWaWpr76NrDB95k4P6d0t5bkYsguiQjV+2t5/dSvrbTPVbXQmWGyC53IS2OI37AI2bIaeCCDkRHDoxu+L/DtgH8N60k2CLfa+pf0/cxQCR39p4Z+tquVKfYgJIsdZLD6bbrqK9VdpSR2vyUcDLMTGnO0tuDuzBd/xdhJ0GKbnBv3+g==
The same code runs with no problem on Windows, building a certificate from the same string.
Edit: Note that while I initially encountered this problem running a docker image, subsequent testing has shown that it also occurs using Ubuntu 14.04 + .NET Core 1.1
The problem here is that what is being passed to the constructor are the bytes of the base64 representation of the key, and not the bytes of the key itself.
If this code works on Windows then maybe it's a good idea to create an issue in the .net core github referencing this problem.
Thanks for the answer. For those who would like to copy and paste:
var certificateWithoutHeaderAndFooter = certificateString
.Replace("\\n","")
.Replace("-----BEGIN CERTIFICATE-----", "")
.Replace("-----END CERTIFICATE-----", "");
var certificateBytes = Convert.FromBase64String(certificateWithoutHeaderAndFooter);
var certificate = new X509Certificate2(certificateBase64Bytes);

Loading Root Certificate on Compact Framework .NET

I am trying to load an x509 certificate from file in CF.NET. The certificate I am trying to load can be downloaded here (it's a GoDaddy root cert).
My code looks like this:
byte[] bytes = null;
using (var certFile = new FileStream("\\gdroot-g2.crt", FileMode.Open, FileAccess.Read))
using (var br = new BinaryReader(certFile))
{
bytes = new byte[(int)certFile.Length];
br.Read(bytes, 0, bytes.Length);
}
//This line throws the error.
var cert = new X509Certificate2(bytes);
When I try loading the cert, I get the following error:
Creating certificate object failed. The data passed in is either
incorrect or is not supported by .NET Compact Framework. .NET Compact
Framework does not support reading from pfx files.
I've verified that the .CRT file I am using is Base-64 encoded. Also - when I run this same code on the desktop (using a mobile simulator that we've built) it parses the cert successfully.
Am I missing something basic here?
I too had the same problem and I resolved it by following the below steps.
Convert the certificate file to DER encoded binary X.509 format and then use it in the compact framework.
Steps for conversion:
Open the .cer file in the computer
Go to "Details" tab and click "Copy to File..." button
Certificate Export Wizard appears in which click Next and choose "DER encoded binary X.509(.CER)"
Click Next and specify the desired location and file name and click Finish
This will generate a .cer file in the chosen location
Use the certificate file (generated by the above process) in the compact framework and access the information programmatically as follows.
Read the contents of certificate file using BinaryReader which results in byte[] value
X509Certificate2 cert = new X509Certificate2(byte value returned by the above step)
Get the issuer name or any details required through built-in methods like cert.GetIssuerName();
When I followed this procedure, I didn't get any exception and it worked fine.
You might find it easier to interact with the certificate via the X509Store class. You can either add the root certificate by hand or programmatically.
Once you've added your certificate to the store you can retrieve an enumeration of the X509Certificate2 from the store and use LINQ to filter down to the specific GoDaddy certificate.
The linked MSDN page has some sample code showing this in action. Hope this helps.
The X509 namespace in the CF is effectively useless. I'm not sure why they bothered including it at all. I ended up wrapping the certificate APIs manually and creating a separate set of X509 classes that provide the functionality the BCL should have provided. The code is too long for a post here on SO, but those methods are part of the SDF.

Opening an SSL web-browser connection in HtmlUnit library

I've searched through web for couple hours on this issue, and none of the answers I found didn't really fit into my problem, so here's me, asking my first-ever question in SOF.
So, I'm trying to open a web-browser from a java program using the htmlunit library. The web site I need to connect requires SSL connection, and the certificate is stored in a USB key. Its iKey2023 product.
The system used to work(I did not write it), but one of the certificates in the USB key expired, so it automatically moved on to the next one (there were 4 certificates in total), and it suddenly stopped working.
It is giving me javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated error.
I'm back home now and I forgot the exact name of the method, but I remember the following.
Browser instance is created, using IE8
browser.setWebConnection method was called. This method, according to the API, is an internal API.
Make connection to the website by passing the URL as parameter
It's throwing the exception at step 3.
Some more details. The little details might be incorrect but I'm trying to describe a big picture.
At step 2, the method requites WebConnection object as a parameter, and there is a implementation of that interface. Within this implementation, a keystore is created using sun.security.pkcs11.SunPKCS11(configFileInputStream) (did I spell that correctly?)
It was sth like this.
Provider p = new sun.security.pkcs11.SunPKCS11(configFileInputStream);
Security.addProvider(p);
And create a keystore from this provider.
Using this keystore, within the WebConnection implementation, it creates a SSLSocket.
So, after the certificate has been switched to a new one, it's not picking up the certificate correctly.
Here's what I've tried.
I've tried to use different methods in the htmlunit library, something like setSecurityProvider, and I tried to put the Provider object created in above code snippet. I got class cast exception.
I tried to manually set the system properties(trustStore, trustStorePassword, keyStore, etc). In order to do this, I wanted to export the certificate out of the USB key, but it did not let me export the private key out from it, so I could not really create a valid PKCS12 file out of it (openSSL wanted a private key file along with .pem file for conversion, and I did not have that key file).
They did not work, and I'm so stuck right now.
I have a similar issue. In my case, an admin changed the certificate and I began encountering the same SSLPeerUnverifiedException.
I found that I can set the WebClient to use insecureSSL (prior to calling getPage())and I will no longer get the exception.
webClient.setUseInsecureSSL(true);
This however, doesn't resolve the issue as the server basically doesn't authenticate the client.
Its as if the WebClient is storing something that doesn't work with the new certificate.