SOAP Server side certificate verification on PHP - php

Previously I have created system that was sending SOAP messages using certificate.
Example shows how it was done:
$client_options = array();
$client_options['local_cert'] = '<path to .pem file>';
$client_options['passphrase'] = '<.pem file password>';
$client = new SoapClient('<address to wsdl file>', $client_options);
$tmp_res = $client->some_function($params);
But now I have to create server that receives messages like these.
I found many resources, all suggesting this code:
$classmap = array('<class_name2>'=>'<class_name2>');
$server = new SoapServer('<path to wdsl file>',array('classmap'=>$classmap));
$server->setClass("<class_name>");
$server->handle();
Code itself works, but what I can't understand is - how certificates work within this client-server communication.
As I understand, for secure communication two pairs of private key and certificate are required. One for each of parties.
There is way to add .pem file with one private key and certificate pair for SoapClient.
Incoming messages (at the both sides) comes unencrypted.
.
Mustn't there be a way to pass certificate and key pair for SoapServer?
How exactly verification of certificates are performed (at what point and what is checked)?
How I can filter out messages only from the user I'm interested in, provided, I can get his certificate?
Sorry for such childish questions, but can You point me out, where I am wrong and provide appropriate resources to find information about this?
Thanks.

Related

How to create a Qualified Electronic Signature Creation Device

A QSCD can be deployed as a cloud service as long as it meets the required standards. I am not looking to, as of such, create one for legislation reasons but more of a way of my software being able to prove that the certificate come from us.
The idea is to create a PKI where the QSCD 'issues' the user the keys, which then Electronically signs a PDF file. If the public key can decode the file, it proves that it did come from that user (in this case will be a bot account that signs certificates).
I have found online solutions which entitle you to pay for such services but wanted to know how to create my own solution. I came across using openssl_* to achieve this. I took a look at a few answers to find how to create these keys.
The part I am now stuck on is how to load a PDF document and use the private key to electronically sign it and then export the new PDF file and then how to then decrypt it with the public key ensuring that it hasn't been tampered with.
My current attempt looks like this:
$config = array(
"digest_alg" => 'sha512',
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA
);
$keyPair = openssl_pkey_new($config);
$privateKey = NULL;
openssl_pkey_export($keyPair, $privateKey);
$keyDetails = openssl_pkey_get_details($keyPair);
$publicKey = $keyDetails['key'];
openssl_pkcs7_sign("toSign.pdf", "signed.pdf"); // how to sign using the private key?
penssl_public_decrypt("signed.pdf", $publicKey);

Communicate with backend server securely

I have Facebook and Google login in my application, I use my backend server to store data about the user, such as name and status.
I am sending the token along side with some info like user points, the server uses the token identifies the user and does his work just fine.
Before publishing the app i want to encrypt everything, I know I can use SSL however my provider charges A LOT of money for SSL support.
My idea was to genarate a RSA Keypair, save the private on a safe place, and have the public in the apk.
I can generate encrypt and decrypt using rsa within my app very easily, but I'm not an expert in php i tried a lot of things to decrypt stuff in server side but i can't figure it out how to do it.
I have one Keypair generated by android, i used,
getPublic().getEncoded()
getPrivate().getEncoded()
How can if use the private key in php to decrypt and encrypt data?
I know that this may not be the best way to do things but i think i won't have a problem, the target audience is really far from hackers.
Because you added the tag PHP, i am assuming that you have some kind of rest api running that you are calling from your android app. Now you don't need encrypt and decrypt in PHP. Those are handled by your web servers. As far as ssl goes have a look at let's encrypt which is opensource. Enforcing ssl alone on web server is pretty good security measure.
I think i achived what i was tring to do, login is 100% handle by facebook and google via https, i only use tokens to identity the user in my server and increment the score
1- Token and score is encrypted and sent to the server
2- Using the private key the server finds the token and i use https to make calls to Facebook or Google to retrieve the user id and increment the score
Note that all data stored in my server is 100% public, i don't store private information about anyone, i just want to protect the token, if someone gets the token and starts to make a lot of calls it may reach the facebook limit of 200 calls/hour per user, making my app inoperable.
I will upgrade to SSL in the future, when i start to earn revenue from the app
Android
String pubKeyPEM = "***";
public void something(){
String sendToServer = Base64.encodeToString(RSAEncrypt("test"),0);
}
public byte[] RSAEncrypt(final String request) throws Exception {
PublicKey publicKey = getPublicKey();
cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(plain.getBytes());
}
public PublicKey getPublicKey() throws Exception {
PublicKey publicKey;
byte[] decoded = Base64.decode(pubKeyPEM, Base64.DEFAULT);
KeyFactory kf = KeyFactory.getInstance("RSA");
publicKey = kf.generatePublic(new X509EncodedKeySpec(decoded));
return publicKey;
}
PHP
$privkey = '-----BEGIN RSA PRIVATE KEY-----';
function decrypt($data){
global $privkey;
if (openssl_private_decrypt(base64_decode($data), $decrypted, $privkey))
$data = $decrypted;
else
$data = '';
return $data;
}
The private key will be moved to a safer place, but this is working just as i wanted
my server is also checking if the token was generated by my app id, so if someone tries to use a diferent token, it will show a diferent app id.

How to verify digital certificate by CA's public key

I am studying the digital certificates in PKI ( Public Key Infrastructure ). Almost all manuals / pages regarding this give following similar steps.
Get subject identity + subject public key, (AND/OR Encrypted Message hash with subject's private key) and build a certificate.
Sign certificate with CA's private key
At destination, verify certificate with CA's public key
Now I am able to find way in php (using openssl lib) to for 1st and 2nd step which can generate a certificate and sign it ( optionally generate a signature hash and sign it too ) through openssl APIs.
But Issue with third step, Their are no guide line or function call which show how to verify certificate with CA's public key.
If I am missing something ?
Example code I checking is like below
$data = 'my data';
//create new private and public key
$req_key = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
$dn = array(
"countryName" => "IN",
"stateOrProvinceName" => "Delhi",
"organizationName" => "example.net",
"organizationalUnitName" => "Security",
"commonName" => "example.net"
);
$req_csr = openssl_csr_new ($dn, $req_key);
$req_cert = openssl_csr_sign($req_csr, null, $req_key, 365);
openssl_x509_export ($req_cert, $out_cert);
echo $out_cert;
BACKGROUND : I need to implement PKI based data sharing/validating for some application. It would be involve some data entity (data entity would have its on public and private key) encrypted at source side and then send to destination. Then destination decrypt and get clear data. But that whole must involve PKI that means digital signature + digital certificate implementation along with.
This task isn't pretty straightforward in PHP. In fact, PHP isn't good tool for implementing CA stuff. It supports basic PKI operations but that's all. I see three options:
X.509 is just DER encoded ASN.1 structure. You can inspect it with guiDumpASN-ng for example. There are also some ASN.1 libraries in PHP world. Basicaly, the CA signature is inside certificate. If you'll able to extract it, you can then verify digital signature on your own.
http://php.net/manual/en/function.openssl-verify.php#98282
Try to use function like openssl-x509-checkpurpose that should be able to check certificate chain.
Try to use phpseclib - look at Validate X.509 certificates -> validateSignature().
I hope it will help you a little bit.
Do not mess up with implementing certificates validation by yourself but look for an implementation of the CPV (Certification Path Validation) algorithm, which includes all the validations required to be performed in a certification chain, where certificate signature validation is only one of them.
Now, I've been looking for a PHP API to perform CPV but I found none so I resorted to execute the following external OpenSSL command from PHP:
exec("openssl verify -CAfile trusted_root_cas.pem -untrusted intermediate_cas.pem endentity_cert.pem", $output, $return_var);
if ($return_var == 0) {
echo "Certification path validation completed successfully";
} else {
echo "Certification path validation completed with errors";
}
Where all trusted_root_cas.pem, intermediate_cas.pem and endentity_cert.pem could be temporal files created just for the execution of the previous command.
Now, if you want to know what openssl verify does, execute man verify:
The verify command verifies certificate chains.

Can't receive request token from Etsy using PHP and OAuth

This is my first time posting here, so forgive me if I leave out something important. Anyway, I'm trying to connect to Etsy's API using PHP and OAuth. I've been following the guide here: https://www.etsy.com/developers/documentation/getting_started/oauth#section_obtaining_temporary_credentials
I already created an account and app on Etsy, so I have my consumer key and secret. I've copied their code for getting a request token 100% and defined the two variables using my unique key and secret. However, when I try to make the http request, I get an "ERR_EMPTY_RESPONSE". When I click to get more detail it says: "Unable to load the webpage because the server sent no data". Here is a screenshot of the error page: http://imgur.com/dgxAlci
I'm using MAMP to make a localhost on port 8888 in order to test any PHP code that I write (e.g. to get to this php file I enter this url: localhost:8888/Etsy/EtsyOAuth.php).
My code is below. I edited out my key and secret.
define('OAUTH_CONSUMER_KEY', "****");
define('OAUTH_CONSUMER_SECRET', "****");
// instantiate the OAuth object
// OAUTH_CONSUMER_KEY and OAUTH_CONSUMER_SECRET are constants holding your key and secret
// and are always used when instantiating the OAuth object
$oauth = new OAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
// make an API request for your temporary credentials
$req_token = $oauth->getRequestToken("https://openapi.etsy.com/v2/oauth/request_token?scope=email_r%20listings_r", 'oob');
print $req_token['login_url']."\n";
I'm using pHP 5.6.7 and OAuth 1.2.3 says phpinfo().
Any help is much appreciated. Thanks in advance!

Consuming a WCF Service from PHP

first off let me "warn" you that i am not a PHP developer and am pretty clueless about PHP. I'm the developer of the WCF Service in question and am trying to support the PHP developer on staff who is trying to consume this service.
He doesn't have a Stackoverflow login and is to busy beeing pissed off at WCF to type anything without profanity ;-)
Anyhow, the service is using the following security configuration:
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="true" algorithmSuite="Default" />
</security>
This means the message is encrypted over the line, i believe this requires a certificate which has been installed on the webserver and when consuming the service from .NET works without any problems at all.
We've looked at fiddler communication and suspect RequestSecurityTokenResponse to be of import. I'm suspecting a handshake where a securitytoken is requested by the client, this is generated with a GUID as reference, the value is used to encrypt the request and the GUID is send as a reference.
This is all speculation though, so far we have been unable to get the requests to even remotely look the same.
Any pointers in the right direction would be much appreciated.
So far we're trying this with WSE-PHP, which can be found through google.
EDIT:
We've been able to confirm our thoughts with Fiddler and working clients do seem to do a handshake, there are three requests (and responses) in total which seem to exchange only security information, they are calling the following actions:
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue
http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT
After this last call a request is made with an action which seems to indicate a call to the actual webservice method:
http://XXXXXXXXXXXXXX/WCF/ICompany/TestConnection
This seems to have to do with SAML (i love you google) so i added this as a tag.
Yes, there is support for WS-Security in PHP. Some assembly is required. See, for example, Secured Web Services with PHP. The WS-* specifications are written and implemented for interoperability, that is, so that the will operate across different platforms, vendors, transports, and languages. It is widely adopted, and the 1.1 version has been an OASIS standard since 2006.
Perhaps it would help defuse the tenion and be instructive if your PHP developer would show the ability to consume any web service that uses WS-Security, just to take your service and WCF out of the equation for a little while.
After my long workout for Email WCF service with attachment. Now i am able to send an email from PHP using WCF service. Here is code snippet.
<?php
ini_set('display_errors',1);
require_once ('nusoap.php');
$parameters= new StdClass();
$parameters->emailinfo = new StdClass();
$fileAttachmentPath = 'example.csv';
$data = base64_encode(file_get_contents($fileAttachmentPath));
$parameters->emlinfo->NoFileInfo = true;
$parameters->emlinfo->FileNameWithExt = "example.csv";
$parameters->emlinfo->FileContentBase64 = $data;
//$parameters->emlinfo->FileAttachment = $parameters->ArrayOfFileAttachment;
//$parameters->emlinfo->FileAttachment = (array) $parameters->emlinfo->FileAttachment;
$parameters->emlinfo->MailTo='';
$parameters->emlinfo->MailFrom='';
$parameters->emlinfo->MailMessage='';
$parameters->emlinfo->MailBody='';
$parameters->emlinfo->MailSubject='';
$parameters->emlinfo->MailType='';
$parameters->emlinfo->UserId='';
$parameters->emlinfo->Password='';
$parameters->emlinfo->SmtpId='';
$parameters->emlinfo->Token='';
$parameters->emlinfo->ApplicationId='';
$parameters->emlinfo->VisitorName='';
$parameters->emlinfo->VendorId='';
$parameters->emlinfo->ReplyTo='';
try {
$braspag = new SoapClient('WSDL Sevice',
array(
'trace' => 1,
'exceptions' => 1,
'style' => SOAP_DOCUMENT,
'use' => SOAP_LITERAL,
'soap_version' => SOAP_1_1,
'encoding' => 'UTF-8'
)
);
//$SendEmailResponse = $braspag->__getTypes();
$SendEmailResponse = $braspag->SendEmail($parameters);
}
catch(SoapFault $fault) {
//echo 'Ocorreu um erro: ' , $fault->getMessage();
}
var_dump($parameters->emlinfo);
?>
Regards,
Rahul Soni.
Why dont you setup a platform independent UI project using something like SOAP UI where it will enable you to have automated tests against your WCF service, guaranteeing your contracts are sound while benefiting the PHP consumer. The reason this benefits the PHP consumer is that he will have automated test cases which he can profile/run/precident he can use to make his php side of things.
One thing to note is that .net namespacing can cause issues for other languages with SOAP. I really really recommend you investigate SOAP UI or a free alternative. Possibly an alternative that is free is fiddler, however I believe that is not automated.
Here are some other helpers for your PHP consumer:
http://weblogs.asp.net/gunnarpeipman/archive/2007/09/17/using-wcf-services-with-php.aspx
https://github.com/geersch/WcfServicesWithPhp5
I don't know a lot about WCF but it seems that is SOAP based. You can start by looking at php Soap functions. I see that also supports JSON communication, check JSON functions from php.
(this is a bit long to add as comment to Visual Stewart's answer)
clientCredentialType="UserName"....This means the message is encrypted over the line
Not really. The message is not encrypted, but it will be sent via SSL. From the published docs:
Username
Allows the service to require that the client be authenticated with a user name credential. Note that WCF does not allow any cryptographic operations with user names, such as generating a signature or encrypting data. WCF ensures that the transport is secured when using user name credentials.
--
Note the difference between the message and the transport.
Authentication may be derived from a client certificate used for the transport, or negotiated (NTLM).
If the server is configured with clientCredentialType="UserName" PHP consumer must use some WS-Security implementation to send Username and Password SOAP security headers to the server.
<soapenv:Envelope>
<soapenv:Header>
<wsse:Security >
<wsse:UsernameToken>
<wsse:Username>bob</ wsse:Username>
<wsse:Password Type="PasswordText">bob1</ wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body> ... </soapenvBody>
</soapenv:Envelope>
Keep in mind that the server can be configure to acept plain or hashed password. So the client must send plain or hashed password.

Categories