Ruby Error reading in Certificate File with OpenSSL - ruby-on-rails

I am trying to do a simple
OpenSSL::X509::Certificate.new(File.read("testuser.p12"))
from irb with ruby 1.8.7 (or 1.9.2), same result for both. The error I get back is OpenSSL::X509::CertificateError: nested asn1 error
Is this a ruby issue, or does this suggest the cert itself is malformed? I've found some similar reports revolving around an amazon cert demonstrating such errors, which turned out to be the cert itself. It works in the browser though. Suggestions on how to resolve this?

"testuser.p12" seems to be a PKCS#12 file according to the postfix. Reading PKCS#12 format as X.509 certificate format causes ASN.1 decoding error.
You should do OpenSSL::PKCS12.new(File.read("testuser.p12")) instead. If the file is protected with passphrase (it's normal), give the passphrase as the second parameter for PKCS12.new like OpenSSL::PKCS12.new(File.read("testuser.p12"), "pass")
You can extract certificate and CA certificates by PKCS12#certificate and PKCS12#ca_certs methods.
p12 = OpenSSL::PKCS12.new(File.read("testuser.p12"), "pass")
p p12.certificate
p p12.ca_certs

Related

MQTT connection to Microsoft Azure cloud in Twincat 3

I'm developing some code to connect my Beckhoff controller to microsoft Azure through MQTT Iot. To start I have used the example code provided by Beckhoff. Azure side is configured and I have the SAS Token. In Twincat I pasted the code and configured everything except the TLS/certification configuration since Beckhoff documentation it's a bit confusing at this point
https://infosys.beckhoff.com/content/1033/tf6701_tc3_iot_communication_mqtt/3528172299.html?id=376207444360410914
(¿CA is optional but mandatory at the same time?)
Anyway I tried to get a CA certificate to test. As I don't how/where to get it, I tried to export Baltimore certificate to a file with certmgr.exe but the format it is not .crt type as in documentation example. Export formats are cert and p7b type. If I try with any of these types of files I get a TLS validating error in connection.
I'm a bit lost at this moment so any steps to help me in this part?
I'm not familiar with certification/TLS so can you please guys provide some tips or info links focused in this matter so I can get this kind of certificates to validate the connection?
Thanks in advance.
The CA location is optional, since it will be searched for at its default location. Nevertheless, the CA file has to be at the specified location or at the default location. The CA file has to be saved with PEM formatting, but it doesn't matter which extension the file has.
The connection configuration regarding the SAS-token is different whether you connect to an azure-device or -module.
To connect to an azure-device, the following has to be configured:
sUserName := ''; and sUserPassword := '';
copy-paste the SAS-token from e.g. Azure Iot Explorer into stTLS.sAzureSas (the SAS-token is formatted like this: HostName=<hub-name>.azure-devices.net;DeviceId=<device-id>;SharedAccessSignature=SharedAccessSignature sr=<hub-name>.azure-devices.net%2Fdevices%2F<device-id>&sig=...&se=...)
To connect to an azure-module, the following has to be configured (like in python):
sUserName := '<hub-name>.azure-devices.net/<device>/<module>/?api-version=2018-06-30';
sUserPassword := 'SharedAccessSignature sr=<hub-name>.azure-devices.net%2Fdevices%2F<device-id>&sig=...&se=...'; (this is part of the SAS-token, copy everything after ...SharedAccessSignature=)
stTLS.sAzureSas := '';
Publishing messages, take care to send to only send to the expected topic, otherwise the message won't be sent and the connection temporarily lost.
(¿CA is optional but mandatory at the same time?)
Because you must connect over TLS/SSL, you will need to reference the DigiCert Baltimore Root Certificate to connect to Azure IoT Hub.
You can find this certificate in the Azure-iot-sdk-c repository
My recommendation is that you follow steps described in the documentation on how to Communicate with your IoT hub using the MQTT protocol

pem files to get https work in Intraweb VCL For the web

I am studying the SSLCustomIOHandler Intraweb example to figure out to make the intraweb standalone webserver work in https.
The example uses 3 .pem files:
basically the code that uses the files is
{ TIWIOHandlerClass }
procedure TIWIOHandlerClass.Init;
var
Path: string;
begin
Path := TIWAppInfo.GetAppPath;
with SSLOptions do begin
CipherList := 'AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:RC4:HIGH:!MD5:!aNULL:!EDH';
SSLVersions := [sslvSSLv2, sslvSSLv23, sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2];
CertFile := Path + 'cert.pem';
KeyFile := Path + 'key.pem';
RootCertFile := Path + 'root.pem';
OnGetPassword := DoGetPassoword;
end;
inherited;
end;
Now i don't find documentation on this thing. This Indy documentation page says something about certfile and keyfile.
But Rootcertfile and cipherlist are not clear.
Do you have some knowledge to share about this? Basically I'd like to have a https webserver with valid certificate ("green https" in chrome).
Thanks.
This question has a lot to to with with SSL and public key infrastructure (PKI). You can find a lot of information on that topic on the web, but I'll try to help you get started. I don't have a version of Intraweb that supports SSL so I could not compile the sample, but hopefully this will get you somewhere.
In order to get "green https" in Chrome a few things must be fulfilled. In simple terms, this means that the certificate presented by the server must be valid in terms of expiry date, it must have a supported crypto algorithm, the hostname must be the same hostname as the requester, or client, used etc. This is far from a complete list, but you get the idea. In addition to this, the client must trust the certificate, either directly or through a hierarchy (hence the "infrastructure" in PKI). Browsers and operating systems come preloaded with authorative certificate issuers that we are assumed to trust, often called CA's (Certificate Authority). Since it is a hierarchy, there can be a path between who issued your certificate and who your browser trusts. For this reason, many clients need the server to provide a "certificate chain", that shows the path all the way to the highest CA. This is what the Rootcertfile is for.
If you want a server that is trusted for normal internet users, you need to get a certificate from a trusted authority. You can get simple free certificates from sites like "Let's Encrypt", but there are a few prerequisities that has to be fulfilled (for example having administrative authority of a domain), and there is also things like certificate renewal that need to be handled.
An easy way to get started is to create a self-signed certificate. This will give you the cert.pem and the key.pem. Since the certificate is "self-signed", you are your own root, so if you must have a root.pem I think you can use the cert.pem there as well. You don't have a hierarchy, and your certificate will not be trusted by anyone until you convince them otherwise.
I think that the cipherlist has to do with which ciphers the server supports. You can probably use the default as a start.
In order to make Chrome happy you need to import the self-signed certificate into the Trusted CA store on your client. You also need to make sure you can resolve the name(s) in the certificate. The easiest way is to add the name to the clients hostfile. This does not have to be the computers actual hostname, you can use.whatever.you.want.
This is a good thread regarding self-signed certificates. Since you want to get started quickly, I'll cover the basics here. I guess you are on Windows since you are running Delphi.
Download and install OpenSSL. I used
Win64OpenSSL_Light-1_1_0g.exe from Shining Light
Productions.
Create a text file called req.cnf with the contents below. This file
is required because modern browsers requires that the hostname is
present in the SAN field.
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = NA
ST = NA
L = lab
O = lab
OU = lab
CN = www.myintrawebserver.local <--- Replace with your name
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = #alt_names
[alt_names]
DNS.1 = www.myintrawebserver.local <--- Replace with your name
DNS.2 = myintrawebserver.local <--- Optional additional name(s)
Go to a DOS prompt and run the following command (The backslash
after "365" is just to make this easier to read, it won't work on
Windows):
C:\home>\OpenSSL-Win64\bin\openssl req -x509 -sha256 -nodes -days 365 \
-newkey rsa:4096 -keyout key.pem -out cert.pem -config req.cnf
If everything work you'll get the files cert.pem and key.pem written in
the current directory.
Generating a 4096 bit RSA private key
.......................................................................
...................................++
.......................................................................
.......................................................................
.......................................................................
......................................................++
writing new private key to 'key.pem'
-----
Add the hostname into the C:\Windows\System32\drivers\etc\hosts file on the client computer. Remember that you need to edit the file as Administrator.
Import the cert.pem into the truststore. This can be done via settings->advanced->certificates (or something like that). Add the certificate to the Trusted Root Authorities (I don't know the exact name, my computer has a non-english language).
Run and access your application. Hopefully your browser is happy :-)
The key.pem is not password protected in this example. I don't know if the
OnGetPassword has something to do the key password or if it is a password
that the user is expected to provide.
SSLSHopper has some useful tools to check certificates. Try for example to paste the content of the cert.pem in the Certificate Decoder. Sample output below.
The certificate is divided in two parts, so to speak. The cert.pem is the public part, and the key.pem is the part that needs to be kept secret. The public part needs to be decoded by clients in order to determine if they can trust it or not.
How2SSL also has some good information on SSL. Here can you read more about PEM-files specifically. PEM is just one of the many file formats that help complicate the world of PKI ;-)

Neo4j Certificate Chain

I am trying to set up a neo4j server with a set of certificates for https. I have the key used to get the certs, the certificate itself, and the ca certificate chain file. According to the documentation:
Neo4j also supports chained SSL certificates. This requires to have all certificates in PEM format combined in one file and the private key needs to be in DER format.
I've encoded my key in DER format and have that set up, however I am having trouble getting the certificate chain set up correctly. I combined all the certificates in one file (PEM) and gave it to neo4j, and it crashed silently trying to start the server. On the off hand, I took the first certificate and changed it to DER, changed neo4j to use that, and it started but browsers/curl throw a fit because there's no CA chain along with it.
This is using neo4j 2.2.0 community edition.
Any suggestions as to how to get neo4j to use PEM certificate chains correctly?
See https://github.com/neo4j/neo4j/tree/2.2/community/server/src/test/resources/certificates for certifcates used when running the unit tests of Neo4j. Most interesting test case is https://github.com/neo4j/neo4j/blob/2.2/community/server/src/test/java/org/neo4j/server/security/ssl/KeyStoreFactoryTest.java#L82
Double check if your pem file has the same structure than the one provided there.

API authentication using private and public keys

I'd like to authorize user in CLI using web API in similar way the SSH does it (uploading public key on server, and then using private key to authorize). Is it possible?
I don't mean to generate public / private key par, but rather re-use existing id_rsa and id_rsa.pub.
Do you know any software packages that make it easier (preferably Ruby on Rails gems?)
#edit:
Specifically, I want to log in on website, upload and connect my public key with online account, and then be able to use website's API (authentication) through CLI interface.
You can use the openssl library. As far as a more complete solution for what you want, I don't think it's available. Should not be too much work to implement with the library though.
http://ruby-doc.org/stdlib-1.9.2/libdoc/openssl/rdoc/OpenSSL/PKey/RSA.html
Basically do something like:
# private_key_str can be in PEM or DER format
OpenSSL::PKey::RSA.new(private_key_str, 'passphrase').public_key
And compare it to the public key. You can get a string representation of the key with #to_pem or #to_der depending on the format you use (play around with it a little). You can alternatively use the rsa library also.
I think you can use
ssh-keygen -e -f id_rsa.pub > pemkey.pub
To convert from the default format of ssh-keygen to PEM. You can run this command on the server to make the conversion, if necessary - you'll have to try and see to match the formats properly, since I'm not sure if OpenSSL::PKey::RSA accepts the default format of ssh-keygen. You can also make ssh-keygen read from STDIN and write to STDOUT so you don't need to use files to do the conversion.

SSH in Engine Yard

I've got some large problems with my ruby on rails deployment on EY. Support has said I need to SSH in to clear the errors... but I get the following:
###########################################################
# WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! #
###########################################################
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
80:4c:5f:dd:98:bb:cb:01:6c:a9:11:41:29:56:66:86.
Please contact your system administrator.
Add correct host key in /Users/jameshughes/.ssh/known_hosts to get rid of this message.
Offending key in /Users/jameshughes/.ssh/known_hosts:1
RSA host key for ec2-184-73-167-153.compute-1.amazonaws.com has changed and you have requested strict checking.
Host key verification failed.
[Process completed]
How do I add the correct key to the Known_hosts file?
Open up known_hosts in your favorite text editor, find the entry for "ec2-184-73-167-153.compute-1.amazonaws.com" and delete the entire line. The next time you ssh in, it will add the correct key to the known_hosts file.
Note that this error is for security purposes, so I'm assuming that you know that there is not a "man-in-the-middle" attack going on and that the server key has actually changed. If it has not, there might be something else going on.
To fix your "Permission denied (public key)" problem, you'll need to add your public key to engineyard via the Tools menu, then apply your changes to your environment (by clicking apply).
Hope that helps.
Update
Please see #womble's comment below and my reply. As #womble notes, if you use StrictHostKeyChecking no you will be open to man in the middle attacks. I've talked with EngineYard about this (last time I checked, StrictHostKeyChecking no was what they were recommending in their help documentation). I believe using StrictHostKeyChecking=ask is a better alternative. Does anyone else know if there is a better solution than using StrictHostKeyChecking=ask?
I ran into the same issue and this seemed to work for me. You just need to add "StrictHostKeyChecking no" to after "'~/.ssh/config'':"
Engine yard has a pretty good article on it. The Man in the middle issue is near the bottom.
http://docs.engineyard.com/ssh-keys-and-configuration.html
Now when I SSH I still get the warning, but am able to access the server. I started getting the warning after I stopped and restarted my instance.

Resources