Using X.509 certificate with OpenSSL in iPhone App - objective-c

I'm trying to figure out how to use the self compiled OpenSSL API to load an existing X.509 certificate (.crt) which I have included in Xcode's project structure.
I need a X509 object (from OpenSSL x509.h) which should be created/loaded from an existing file. Including the header works fine but I really can't find a way to load an existing certificate... There are sooo many methods in the x509.h but no sufficient documentation.
Thanks,
Chris

If you've read the character data into a char* s, something like
BIO* bio = BIO_new_mem_buf((void*)s, -1);
X509* cert = 0;
PEM_read_bio_X509(bio, &cert, 0, NULL);
...
X509_free(cert);
BIO_free(bio);

Related

Error when setting Root Certificate on SIM800L

I desperately need some help on 2 questions:
I'm trying to connect a LILYGO TTGO T-Call SIM800L (IP5306 20190610) to AWS IoT, which requires an SSL authentication through a Root Certificate, a Client Certificate and a Private Key.
I'm able to successfully create the .crt files, write on them and set the Client Certificate through the AT Command:
modem.sendAT(GF("+SSLSETCERT=C:\User\clientcert.crt"));
But when I try to set the RootCA like this:
modem.sendAT(GF("+SSLSETROOT=C:\User\rootca.crt,1188"));
the GSM module returns "ERROR".
This is the documentation I'm using as a reference (Page 13):
https://microchip.ua/simcom/2G/Application%20Notes/SIM800%20Series_SSL_Application%20Note_V1.05.pdf
In the "Reference" section of the command "AT+SSLSETROOT", it's written "The files to be imported must be binary encoded". This confused me a little, so at first I simply wrote on the file the string format of the certificate, but I've also tried to change the extension to .der (which technically is the binary encoded format for certificates). I've tried to write on the file the hexdump version of the string format, and tried all the other avaiable extensions (.crt, .cer, .pem, .p12).
I've also tried to update the firmware following the procedure here: https://github.com/Xinyuan-LilyGO/LilyGo-T-Call-SIM800/blob/master/doc/How%20to%20update%20firmware.md
The only difference is that I used the Download Tool v1.10, because the other versions of the tool hanged on "Waiting" whenever I started the update. I retrieved it from here: https://simcom.ee/documents/?dir=SIM800x
I saw on other discussions that the SIM800L does not support TLS 1.2, but on page 6 of the SIM800 documentation regarding SSL, it's reported that "SIM800 series support SSL2.0, SSL3.0, TLS1.0 and TLS1.2."
On top of that, the command "AT+CIPSSL=1" works fine since it returns "OK".
I also read this: https://github.com/vshymanskyy/TinyGSM/issues/29#issuecomment-328802556
I'm attaching the function that sets up the certificates.
void setCertificates() {
modem.getModemInfo();
modem.sendAT(GF("+FSCREATE=C:\\User\\rootca.crt"));
modem.waitResponse();
modem.sendAT(GF("+FSCREATE=C:\\User\\clientcert.crt"));
modem.waitResponse();
char rootcertific[1188];
strcpy(rootcertific,rootCA);
modem.sendAT(GF("+FSWRITE=C:\\User\\rootca.crt,0,1188,1"));
modem.waitResponse(">");
SerialAT.print(rootcertific);
modem.waitResponse();
delay(1000 / portTICK_PERIOD_MS);
char clientcertific[2903];
strcpy(clientcertific,certificate_pem_crt);
modem.sendAT(GF("+FSWRITE=C:\\User\\clientcert.crt,0,2900,2"));
modem.waitResponse(">");
Serial1.print(strcat(clientcertific,private_pem_key));
modem.waitResponse();
delay(1000 / portTICK_PERIOD_MS);
modem.sendAT(GF("+FSREAD=C:\\User\\rootca.crt,0,1188,1"));
modem.waitResponse();
modem.waitResponse();
modem.sendAT(GF("+FSREAD=C:\\User\\clientcert.crt,0,2900,1"));
modem.waitResponse();
modem.waitResponse();
modem.sendAT(GF("+SSLSETROOT=C:\\User\\rootca.crt,1188"));
modem.waitResponse();
modem.sendAT(GF("+SSLSETCERT=C:\\User\\clientcert.crt"));
modem.waitResponse();
}
On page 11 of the SIM800 SSL documentation, the command AT+SSLSETCERT is described as "Client Client Certificate File with Private Key". Does this mean that I somehow have to write both the Client Cert and the Private Key on the same file?
As you might have noticed in the function, I used "strcat(clientcertific,private_pem_key)" and it returns no error, but I'm not sure whether this is the correct way to do this.
If anyone can help me out on this one I'd be infinitely grateful. It's been keeping me stuck for almost a month now.
Thank you!

ACE SSL Error: peer did not return a certificate

I am making both server and client for an application, using the ACE library with OpenSSL. I am trying to get mutual authentication to work, o the server will only accept connections from trusted clients.
I have generated a CA key and cert, and used it to sign a server cert and a client cert (each with their own keys also). I seem to be loading the trusted store correctly, but I keep getting the error "peer did not return a certificate" during handshake.
Server side code:
ACE_SSL_Context *context = ACE_SSL_Context::instance();
context->set_mode(ACE_SSL_Context::SSLv23_server);
context->certificate("../ACE-server/server_cert.pem", SSL_FILETYPE_PEM);
context->private_key("../ACE-server/server_key.pem", SSL_FILETYPE_PEM);
if (context->load_trusted_ca("../ACE-server/trusted.pem", 0, false) == -1) {
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "load_trusted_ca"), -1);
}
if (context->have_trusted_ca() <= 0) {
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "have_trusted_ca"), -1);
}
Client side code:
ACE_SSL_Context *context = ACE_SSL_Context::instance();
context->set_mode(ACE_SSL_Context::SSLv23_client);
context->certificate("../ACE-client/client_cert.pem", SSL_FILETYPE_PEM);
context->private_key("../ACE-client/client_key.pem", SSL_FILETYPE_PEM);
I generated the certificates following these instructions: https://blog.codeship.com/how-to-set-up-mutual-tls-authentication/
And checking online, I found that if the .crt and .key files are readable, they should already be in .pem format and there is no need to convert them. So I just changed the extension and used them here.
Any help is appreciated!
My problem apparently was the same as seen here: OpenSSL client not sending client certificate
I was changing the SSL context after creating the SSL Socket. Now the mutual authentication works, but my client crashes when closing the connection. Though I don't know why that is yet.

Alamofire and PEM certificate

I have a .pem file which will successfully connect to my website via the --cert parameter of curl. I then converted that to a der file:
openssl x509 -inform PEM -outform DER -in client.pem -out cert.der
Then I loaded that cert.der into my project and I'm now trying to use that with Alamofire, following the example on their homepage:
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
)
let policyManager = ServerTrustPolicyManager(policies: ["my.domain.com" : serverTrustPolicy])
manager = Alamofire.Manager(configuration: configuration, serverTrustPolicyManager: policyManager)
manager.request(.GET, url, parameters: params, encoding: .URLEncodedInURL, headers: nil)
.authenticate(usingCredential: credential)
.validate()
.responseJSON {
When that runs though it just fails and I get a 'cancelled' as the error's localizedDescription, which is what Alamofire does when authentication fails.
What am I doing wrong?
The Alamofire cert pinning logic does not currently support this use case. It is only designed to handle cert and public key pinning, not client certificates used to authenticate with the server. This is something we could support in the future if this is a common use case.
With that said, I'm assuming in this case you are receiving a NSURLAuthenticationChallenge with a protection space that has an authentication method of type .NSURLAuthenticationMethodClientCertificate. In these cases, you need to evaluate the host of the challenge, then create an NSURLCredential using the credentialWithIdentity:certificates:persistence: API. By passing this credential off to the completion handler, the client certificate should be sent to the server to authenticate the connection. More info can be found here.
Client certificate authentication (NSURLAuthenticationMethodClientCertificate) requires the system identity and all certificates needed to authenticate with the server. Create an NSURLCredential object with credentialWithIdentity:certificates:persistence:.
I've never actually had a need to use this type of authentication before. You'll need to override the auth challenge SessionDelegate closure using the task override closure to get this working.

Bouncy Castle: Creating CMS (a.k.a. PKCS7) certificate?

How do I create a CMS (a.k.a. PKCS7) certificate?
The following bouncy castle code creates a PKCS12 certificate:
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCert);
v.add(sigAlgId);
v.add(new DERBitString(signature));
X509CertificateObject clientCert = new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
PKCS12BagAttributeCarrier bagCert = clientCert;
bagCert.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
new DERBMPString("Certificate for IPSec WLAN access"));
bagCert.setBagAttribute(
PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
new SubjectKeyIdentifierStructure(pubKey));
I see there is CMSSignedDataGenerator in the API, but I am not if it's applicable to my case and if so how....
I also don't understand why, if the created certificate is a PKCS12 one, then why do they use PKCS9 variables in order to built it.
There is no such thing as a CMS certificate or PKCS#12 certificate.
CMS is the cryptographic message syntax. It specifies a container format that may contain X5.09 compatible certificates of the signer. PKCS#12 is a container format for cryptographic objects, it is often used to store one or more certificate/private key pairs. PKCS#9 explicitly defines attributes for X5.09 certificates.
You probably just need to build an X5.09 certificate, possibly using PKCS#9 defined attributes. Those certificates should be compatible with both CMS and PKCS#12.

SSL api for winsock?

I have windows c++ project.
Need to implement both ssl client and server on top of existing winsock code.
I tried with openssl but it seems too messy. I assume there is nicer/shorter/cleaner/faster way implementeing this than openssl..
Im thankful for any suggestions..
You can use Windows built-in SSL stuff -- SChannel . Searching Google fo "SChannel SSL" would give you plenty of information (though SChannel itself is poorly documented and not easy to comprehend).
On the other hand, OpenSSL is not messy once you study the source code of some project, that uses OpenSSL.
Acctually .. After some time spent with openssl hacking I wouldnt say its that messy :)
In case anyone anytime needs to add ssl to existing winsock code:
existing winsock code was like this:
0: sockett.Listen etc....
1: sockett.Accept(client, .....
2: recv(client , ...)
3: send(client , .....)
well in short if you want to implement SSL here..
delete lines 2 and 3 :) and add:
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *tlsctx;
SSL *ssl;
tlsctx = SSL_CTX_new( SSLv23_method());
// search google : generate self signed certificate openssl
SSL_CTX_use_certificate_file(tlsctx, "ssl\\server1.crt" , SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(tlsctx, "ssl\\server1.key", SSL_FILETYPE_PEM);
ssl = SSL_new(tlsctx);
SSL_set_fd(ssl, client);
SSL_accept(ssl);
/* instaed recv SSL_read(ssl, ....*/
/* instaed send SSL_write(ssl, ....*/
/* not 100% sure Sleep and shutdown/free/close are entirely correct here but in my code works fine */
Sleep(3000);
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(tlsctx);
shutdown(client, SD_BOTH);
Sleep(10);
closesocket(client);
For testing:
in command line run:
openssl s_client -host localhost -port <PORT>