How to use multiple TLS certificates for LDAP from php/Zend? - php

In our web based application we support LDAP authentication. It works fine with the code below. Now we want to support LDAP over TLS. We host our product for our customers on SUSE Linux Enterprise Server 11 and each customer can have different TLS certificate.
My questions are:
how to set up out SUSE server (that is LDAP client) - where to place certificates for each customer, do I need to edit any conf file?
how to make LDAP authentication over TLS with different certificates from php. What would be exact php syntax?
does it matter what type of the server is? Exchange, OpenLDAP etc?
right now we have .cer certificate from Exchange. Is that ok for OpenLDAP or it must be converted (how) to .pem?
SUSE server = LDAP client configuration
SUSE Linux Enterprise Server 11 (x86_64)
ldapsearch: #(#) $OpenLDAP: ldapsearch 2.4.26 (Sep 26 2012 13:14:42)
PHP Version 5.4.9
Zend Engine v2.4.0
From reading http://php.net/ldap_connect I understood that I can use different certificates but I didn't get how.
function authenticateZendAuth($username, $password){
require_once 'Zend/Auth.php';
$auth = Zend_Auth::getInstance();
$ldapOptions = getConfigVariableValue('->ldap');
$options = $ldapOptions->toArray();
unset($options['log_path']);
require_once 'Zend/Auth/Adapter/Ldap.php';
$adapter = new Zend_Auth_Adapter_Ldap($options, $username, $password);
$authenticated = $auth->authenticate($adapter);
$log_path = $ldapOptions->log_path;
if ($log_path) {
$messages = $authenticated->getMessages();
require_once("Zend/Log.php");
require_once("Zend/Log/Writer/Stream.php");
require_once("Zend/Log/Filter/Priority.php");
$logger = new Zend_Log();
$logger->addWriter(new Zend_Log_Writer_Stream($log_path));
$filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG);
$logger->addFilter($filter);
foreach ($messages as $i => $message) {
if ($i-- > 1) { // $messages[2] and up are log messages
$message = str_replace("\n", "\n ", $message);
$logger->log("Ldap: $i: $message", Zend_Log::DEBUG);
}
}
}
return $authenticated;
}

How to set up our SUSE server (that is LDAP client) - where to place certificates for each customer, do I need to edit any conf file?
If you are using openssl (slapd) it doesn't really matter where you put the certificate, as long as you can set the configuration file to point to. It will look something like this perhaps:
TLSCACertificateFile /usr/var/openldap-data/cacert.pem
TLSCertificateFile /usr/var/openldap-data/servercrt.pem
TLSCertificateKeyFile /usr/var/openldap-data/serverkey.pem
You will need to request (or create your own) Certificates, these are the same as the certificates you use for HTTPS. This is where the domain name is imported, when you create/request the cert, it needs to match the domain name that you are going to be using it on. See: http://www.openldap.org/pub/ksoper/OpenLDAP_TLS.html for more details.
How to make LDAP authentication over TLS with different certificates from php. What would be exact php syntax?
You really don't need to do anything special here. Make sure you set your LDAP server up with the appropriate domain named certificate. And make sure that the signing authority for that cert is recognized by your local openladap client (running your php) via it's config file. Then notice that many of the Zend Examples (http://files.zend.com/help/Zend-Framework/zend.auth.adapter.ldap.html) use a config file to set up the Zend LDPA client and turn on TLS. You can also use Zend_Ldap::setOptions() - see the notes on http://framework.zend.com/manual/1.12/en/zend.auth.adapter.ldap.html
Does it matter what type of the server is? Exchange, OpenLDAP etc?
No, not really. I mean, configuring the LDAP server will matter, but the php client won't really care at all.
Right now we have .cer certificate from Exchange. Is that ok for OpenLDAP or it must be converted (how) to .pem?
See: http://www.sslshopper.com/article-most-common-openssl-commands.html
openssl x509 -inform der -in certificate.cer -out certificate.pem

Related

How to get SSL certificate for local website

I want to get SSL certificate for my webpage that chat with each other. I also using AES 265 hashing algorithm for dealing more secure with my webpage data and using sha512 for password hashing. But i don't know how to get SSL certificate in industrial level. I tried with many of giving free SSL websites but i still haven't got that. What is Server signature? and how i get that? thanks
This is really a server admin question, not a programming issue.
You can either do a self signed certificate, or get one from a certificate authority.
Self signed certificates are secure, BUT many times programming languages don't like them OR when you connect to something using them you need to tell the function that self-signed is OK.
That said, if you want a "real" certificate you may want to look at Let's Encrypt - https://en.wikipedia.org/wiki/Let%27s_Encrypt
You need to create your own keystore for setting up SSL enabled one.
After you create your own Keystore it has to be signed by the Certificate Authority for example, Go Daddy or GlobalSign.
But for testing purpose, you need to create self-signed certificate using Keytool which comes with your JDK or JRE (C:\Program Files\Java\jdk1.8.0_60\bin\keystool.exe).
You can create self-signed certificate using below command:
keytool - genkey -dname "CN=SERVER_NAME, OU=ABC, O=company.com, L=Morrisville, S=NC, C=US" -alias myalias -keyalg RSA -validity 365 -keysize 2048 -keystore keystore.jks -storepass password -keypass password
Here, storepass and keypass should be same for avoiding some confusions.
Now, after creating your own keystore.jks, its time for server configuration.
I am considering that you are using Apache tomcat or if you are using some other server, you can find server configurations very easily over other tutorials.
You need to edit two files: server.xml and setenv.sh/bat
1) Go to $CATALINA_HOME/conf --> Here you will find server.xml and now you have to edit the port information so that communication will go through SSL enabled port. You need to create one more connector other than default 8080 port like below:
<Connector
port="33380" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="500"
compressableMimeType="application/json,application/atom+xml,application/xml"
compression="on"
maxKeepAliveRequests="-1"
connectionTimeout="20000"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="conf/keystore/keystore.jks" keystorePass="password"
clientAuth="false" sslProtocol="TLS"/>
Here, specify the path of the generated keystore file for keystoreFile attribute and keystorepass equals to the password that you have chosen while creating the keystore file.
2) Go to $CATALINA_HOME/bin --> Here you will find setenv.sh/bat files.
Here, you need to specify the keystore password and path of the keystore file.
Add these server environment variables inside JAVA_OPTS
-Djavax.net.ssl.keyStore=../../../keystore/keystore.jks -Djavax.net.ssl.keyStorePassword=password
I hope this will give some direction to you for configuration purpose.

How the server must be configured to be able to connect to mailbox via php script

I have spent 8 hours on this, and still can't get it right.
My situation:
My server is running on Linux xrm 2.6.32-5-amd64;
In console: openssl s_client -connect ns1.example.com:995 works flawlessly, successful connection.
But when i execute this script:
a)
$res = imap_open("{ns1.example.com:993}",
"user#example.lv", "password");
Response is: Array ( [0] => [CLOSED] IMAP connection broken (server response) )
b)
$res = imap_open("{ns1.example.com:993/ssl}",
"user#example.lv", "password");
Response: Array ( [0] => Certificate failure for ns1.example.com: self signed certificate: /CN=ns1.example.com/emailAddress=ssl#ns1.example.com )
Is it connected with the fact that, this script is under drupal directory?
And it uses different php.ini than server does?
Even though when i execute php_info(), it says that imap and imap/ssl is enbaled.
i have tried all the imap_open() flags, but still no luck.
I even can't connect to a standart gmail mailbox.
Please get me out of here.
How the server must be configured to be able to connect to mailbox
It depends. The server can use a certificate signed by a public CA if the CA is a trust anchor on the client. The server can use a certifcate signed by a non-public CA used in a private PKI as long as the client uses it as a trust anchor.
The server can also use a self signed certificate if the client trusts the certificate. See Marc B's comments.
In the case of the mail protocols, opportunistic encryption is the next big push. As such, your script should be using DNSSEC and DANE to fetch the certificate from DNS's CERT resource record. See, for example, RFC 6944 and RFC 7218.
As a fallback, the script should be using security diversification techniques like Trust on First Use (TOFU), certificate pinning or public key pinning. Peter Gutmann talks about it in his book Engineering Security. (The other choice - disable validation - is really bad).
... via php script
This is likely your problem. Its not robust and it does not do the right thing.
In console: openssl s_client -connect ns1.example.com:995 works flawlessly
Probably not. Are you certain about that? I would have expected s_client to return non-0. At minimum, you would have needed the -CAfile option to tell OpenSSL what certificate to use as a trust anchor.
Also, OpenSSL prior to OpenSSL 1.1.0 does not perform hostname matching. So the name in the certifcate could be anything and s_client would accept it as long as its signed by a CA (modulo the -CAfile option). That mistake does not show up anywhere. You have to manually inspect the end entity certificate to discover the problem (if its present).

How to perform a LDAP SASL bind to Active Directory using GSS-API mech in PHP from Windows?

I have an Active Directory server and a Windows WAMP server hosting PHP web applications that need to be able to authenticate to Active Directory using Kerberos.
I was able to easily connect and bind to the Active Directory host using some sample PHP code, but I'm not sure how to do so with Kerberos. I have see many forums and blogs detailing how to do this on *NIX machines, but that doesn't help me with my situation.
I did use Wireshark and Fiddler to confirm that there is no Kerberos or NTLM negotiating happening.
Sample code I used to connect and bind to LDAP:
<?php
$ldaphost = "example.domain.com";
$ldapport = 389;
$ldapuser = "user";
$ldappass = "password";
$ldapconn = ldap_connect( $ldaphost, $ldapport )
or die( "Unable to connect to the LDAP server {$ldaphost}" );
if ($ldapconn)
{
$ldapbind = ldap_bind($ldapconn, $ldapuser, $ldappass);
if ($ldapbind)
{
echo "LDAP connection successful";
}
else
{
echo "LDAP connction failed";
}
}
?>
Any help will be greatly appreciated, thanks!
Update: I've been wrestling with this all day and I think I need to use ldap_sasl_bind(), possibly using GSSAPI as the mechanism... No matter what parameters I put in to ldap_sasl_bind(), I get the following error: 'Unable to bind to server: Unknown authentication method'
I'm not sure how to implement GSSAPI, but some examples I've seen show using ldap_start_tls(), but I keep getting a 'Unable to start TLS: Server is unavailable' error.
I don't know if anyone knows anything about ldap_sasl_bind() (which is undocumented by PHP) or ldap_start_tls, but if this is the way I should be going, please point me in the right direction.
I cannot help with the Kerberos issue yet, as I am still struggling with it myself. However, I can point you in the right direction for TLS. TLS will at least prevent your credentials from being transmitted over the network in clear text. TLS requires proper configuration of OpenLDAP. At the very least, you can configure your client to not request or check any server certificates. You do this by adding the following line to the top of your ldap.conf configuration file.
TLS_REQCERT never
Your ldap.conf file should be located in C:\ or C:\openldap\sysconf, depending on your version of PHP and OpenLDAP. The file most likely does not yet exist in your setup. You may also be able to set the configuration via an environment variable as well putenv(TLS_REQCERT=never);, but I have not tried that myself, and there appear to be mixed results reported by others.
What you need to do: Make sure that the LDAP interface in PHP is compiled against SASL, supports GSS-API mech and either uses keytabs or the Windows-own SSPI interface. Good luck.
I solved this problem on windows by creating executable based on c++ ldap_bind_s. I use this executable as a command line with the parameters: host, username,password. This is the only way I got it work for GSSAPI.
WINLDAPAPI ULONG LDAPAPI ldap_bind_s(
LDAP *ld,
const PSTR dn,
const PCHAR cred,
ULONG method
);
I used LDAP_AUTH_NEGOTIATE.

SSL peer certificate or SSH remote key was not OK

I'm testing an API that uses curl_exec php function and a CA certificate but something is going wrong and I'm a little lost.
I have configured SSL on my apache VirtualHost and looks ok ( opening https:://[myVHost]... works ).
However the API curl call give me back this message:
SSL peer certificate or SSH remote key was not OK
I'm not very experienced with SSL so I have few ideas about the cause of that.
UPDATE:
This is the code I'm using in my cURL request, I have commented 2 lines and changes their value (look at 'TODO' line ) and in this way it is working, however this is just a work arround ...
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_CONNECTTIMEOUT] = 50;
$opts[CURLOPT_TIMEOUT] = 100;
$headers = array(
'Accept: application/json',
"User-Agent: APIXXX-PHP-Client");
$opts[CURLOPT_HTTPHEADER] = $headers;
$opts[CURLOPT_USERPWD] = $env->getApiKey() . ':';
if (certificatePresent()) {
// $opts[CURLOPT_SSL_VERIFYPEER] = true;
// $opts[CURLOPT_SSL_VERIFYHOST] = 2;
// TODO: SET IT BACK
$opts[CURLOPT_SSL_VERIFYPEER] = 0;
$opts[CURLOPT_SSL_VERIFYHOST] = 0;
$opts[CURLOPT_CAINFO] = $path
}
curl_setopt_array($curl, $opts);
$response = curl_exec($curl);
You are probably using self-signed SSL certifiacate, which will not pass when the CURLOPT_SSL_VERIFYPEER options is set.
There are two solutions:
Set up valid SSL certificate.
Disable SSL verification in Curl. (add --insecure option)
If you disable verification, you can't be sure if you are really communicating with your host.
So it depends on level of security you need.
Beside CURLOPT_SSL_VERIFYPEER there are two other settings which might be changed to false/0:
CURLOPT_SSL_VERIFYHOST
CURLOPT_SSL_VERIFYSTATUS
Beware that you should fix your SSL certificates & settings instead of disable security!
Although I am answering an old post, I think it will help the new viewers-
You can check the problem by adding
$opts[CURLOPT_VERBOSE] = 1
For self signed certificate your client may connect with the server using IP address, because the host name is not available in DNS cache. In that case the COMMON NAME(CN) of your server certificate needs to match with the Server IP (put IP address as common name when generating the server certificate). When you do it correctly, you can see this message:
common name: 192.168.0.1 (matched)
Here 192.168.0.1 is an example.
You're right to want to enable SSL_VERIFYPEER if you are worried about man-in-the-middle attacks.
Is your $path set to point to the certificate (or certificate bundle) provided by the API owner? Is that certificate readable by the web server user? If so, have you verified that the certificate(s) is the same as when you visit the https address manually in a browser and inspect the certificate?
If you can't get it to work, and the API you are connecting to has a SSL certificate that works in your normal browser without warnings, you should be able to set $path to your CA root bundle on your server.
You can build a valid SSL certificate and ensure that it is stored in the trusted folder.
Valid SSL certificate can be created by including the following command in the developer command prompt of VS2012. (This can be obtained by typing developer in the start)
The following command creates a self-signed certificate that can be used to test a web application that uses Secure Sockets Layer (SSL) on a web server whose URL is www.example.com. The OID defined by the -eku option identifies that certificate as an SSL server certificate. The certificate is stored in the my store and is available at the machine (rather than user) level. The certificate's private key is exportable, and the certificate is valid from May 10, 2010 through December 22, 2011.
Makecert -r -pe -n CN="www.example.com" -b 05/10/2010 -e 12/22/2011 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
For more on how to create the SSL certificate
Now make sure that this certificate is trusted, this can be done by typing CERTMGR in the cmd..
now the cert created is in the PERSONAL folder.. copy it and paste it to the TRUSTED PEOPLE FOLDER.
This should do the trick. Let me know if that doesn't work.
I had the same issue. I follow the instruction here: http://siteber.com/download-failed-ssl-peer-certificate-or-ssh-remote-key-was-not-ok/ and it fixed mine.
basically I went to /etc/resolv.conf
and Replace any
OpenDNS server:
208.67.222.222
208.67.220.220
With
Google’s public DNS servers:
nameserver 8.8.8.8
nameserver 8.8.4.4
This error can also occur if you update packages on a linux server that has a self-signed certificate.
Solution:
Stop your existing Apache/nginx server.
Run certbot (if you are using lets encrypt)
Restart your Apache/nginx server.
Note: If you're using Springboot, add System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,TLSv1.3"); to your application.properties file
Voila!
I spent almost all day for this error, and problem was in using ipv6, and called api server does not support ipv6.
Solution:
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_VERSION_IPV4);

Connecting to a web service with PHP given only username, password and certificate authority

I am successfully connecting, using Microsoft C#, to a Microsoft web service. I have to supply a username, password (in the C# code); and install a certificate (in .cer format) into the "Root Certificate Authorities" section of the system's certificates.
How can I connect to such a web service in PHP? The reason I ask is that all methods I have seen (such as wsdl2php, which creates a SoapClient subclass), seem to assume various things, such as SSL certificate, SSL key file and SSL key passphrase.
So it all confuses me. I'm not sure what should go where. I'm not sure where my "root certificate authority" (the .cer file) should go, and where the username and password should go. Any ideas?
all can be done whith soapclient and stream_context_create using ssl options
<?php
$context = stream_context_create(array(
'https' => array(
'cafile' => '/path to file',
'verify_peer' => true
)));
new soapclient("https://localhost/index.php?wsdl",array(
'login'=>'admin',
'password'=>'passss',
'stream_context'=> $context
));
it is not uncommon in soap to not use http auth but just an soap-call, the documnetation is essential
it can be rewarding to use soapclient whith classes using classmap to map soaptypes to php clases
Typically if you're calling a webservice using regular SSL your URL will look like:
https://username:password#myserver.com/mywebservice.php
Then there is the issue of the SSL certificate. I'm using something similar to read from an SSL protected SVN web front. I don't know of any other solution other than to log into the server as the user that is running your webserver (apache/IIS) and accepting the certificate manually. In the case of SVN you could make a checkout and it will ask you to accept the certificate. I'm not entirely sure how this would work for a plain HTTPS request but perhaps you can get the certificate by loading the webservice in a browser? (or using wget or something fancy if you're lucky enough to be running Linux)
Also, is your code the PHP code or the C# code? If it's C# you may need to do something else entirely.

Categories