Johan Broddfelt
/* Comments on code */

Swish Merchant payment setup

Certificates can be confusing to implement. I have done this for different types of solutions and almost every time I'm just trying out different things and basically guessing until I get things to work. The main reason for my struggle is that there are almost always multiple documentations in play and the naming of files are different everywhere. And the reason for all the different types of files are not that well described. Right now I'm trying to get the Swedish payment service Swish to work on my website, using Apache. So, that is what I will use as the basis for my exploration. You will probably have another integration to figure out. But hopefully this post can help you get some things clearer. After a couple of roundtrips with the support, reading a lot of different posts online, speaking to my old coluege and friend Jacob and me building a RESTful API in php for another project. I finally manage to understand what the necessary steps were to get things to work.

Check your environment

First check that you are using the right version of TSL by running openssl s_client -connect YOUR_URL.COM:443 -tls1_1. This command cal also be used to verify that you have installed the certificate correctly when you are done. So, remember it.
If it works you should find this line in the output Secure Renegotiation IS supported and not this one Secure Renegotiation IS NOT supported.

- Use of HTTPS
You should know this. But if you want to check see if you can access your website using https://YOUR_URL.COM. If your site works using this URL you are good to go.

Creating certificates

You need to get a client TLS certificate from Swish Certificate Management and install it on your server.
- Generate a pair of 4096 bit RSA keys on your server and create a certificate request (CSR) in a PKCS#10 format.

For details please consult your web solution documentation... Now, in my case I use apache and is refered to the openSSL documentation.
1. Create an empty Keystore: (A KeyStore is a file that serves as a container for private keys, certificates and symetric keys)
keytool -genkey -alias YOUR_OWN_ALIAS -keyalg RSA -keystore KeyStore.jks -keysize 4096

In my case I used "C:/Program Files/Java/jdk1.8.0_161/bin/keytool.exe" -genkey -alias my_key_123 -keyalg RSA -keystore KeyStore.jks -keysize 4096

Ange nyckellagerlösenord:
Ange det nya lösenordet igen:
Vad heter du i för- och efternamn?
  [Unknown]:  Johan Broddfelt
Vad heter din avdelning inom organisationen?
  [Unknown]:  Utveckling
Vad heter din organisation?
  [Unknown]:  Citypolarna
Vad heter din ort eller plats?
  [Unknown]:  Malmoe
Vad heter ditt land eller din provins?
  [Unknown]:  Sweden
Vilken är den tvåställiga landskoden?
  [Unknown]:  SE
Är CN=Johan Broddfelt, OU=Citypolarna, O=Firma Johan Broddfelt,
L=Malmoe, ST=Sweden, C=SE korrekt?
  [nej]:  ja

Ange nyckellösenord för 
        (RETURN om det är identiskt med nyckellagerlösenordet):

Warning:
Nyckellagret JKS använder ett proprietärt format. Du bör migrera till PKCS12, som är ett branschstandardformat, med "keytool -importkeystore -srckeystore KeyStore.jks -destkeystore KeyStore.jks -deststoretype pkcs12".

Now we change this to a PKCS12 key:
keytool -importkeystore -srckeystore KeyStore.jks -destkeystore KeyStore.jks -deststoretype pkcs12 converts the keystore file to the correct version
Extract the CSR from the KeyStore: ("csr.txt" is the Certificate Signing Requestthat you should use at "https://comcert.getswish.net" to generate your new certificate with.) keytool -certreq -alias YOUR_OWN_ALIAS -file csr.txt -keystore KeyStore.jks
or as I used it:

"C:/Program/Java/jdk1.8.0_161/bin/keytool.exe" -certreq -alias my_key_123 -file csr.txt -keystore KeyStore.jks


Extract the private key from the KeyStore

openssl pkcs12 -in KeyStore.jks -nodes -nocerts -out swish.key


Now this swish.key certificate from the pkcs12 keystore should be converted into the pkcs12 format.

openssl pkcs12 -export -in Your_Swish_Cert.pem -inkey swish.key -out swish.p12


But we still need to get (Your_Swish_Cert.pem) and we get that using the instructions in this documentation that describes how we use Swish website to generate the Swish_Cert using our Certificate Signing Request (CSR), (PKCS#12 with 4096-bit RSA key) we named csr.txt. We can use the PEM or PKCS#7 format. Since we are expecting to get a PEM file I go with the default selected PEM format.

Now I successfully generated that and copy the new Swish certificate into a file I call swish_cert.pem. Now we can run the following:

openssl pkcs12 -export -in swish_cert.pem -inkey swish.key -out swish.p12


Now we want to import the swish.p12 file in to the KeyStore.jks as well. Here is how we do that:

keytool -v -importkeystore -srckeystore swish.p12 -srcstoretype PKCS12 -destkeystore KeyStore.jks


The next step might not be needed in most cases but if there are issues with the handshake it might help. Since the reason I'm writing this documentation is because I got the following error (Curl error: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure). I think I will try this step as well this time.

keytool -importcert -alias YOUR_OWN_ALIAS -keystore Your_TrustStore.jks -file Swish_Server_Root.crt


Now we take the swish.key and copy the text from "-----BEGIN PRIVATE KEY-----" to "-----END PRIVATE KEY-----" into a new file and call it swish.pem. Then we take the three certificates from swish_cert.pem and paste after the key in the same file.

Now we have one file called swish.pem containing something like this:

-----BEGIN PRIVATE KEY-----
MOIJQwIBADA...
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MOIFezCCA2O...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MOIFzTCCA7W...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MOIFrTCCA5W...
-----END CERTIFICATE-----

This is our pem certificate file we will use in the integration.

The code

Now for the code. You can try to call swish using curl in console. This is what the test sample from Swish looks like.

curl.exe" -v --request POST https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests --header "Content-Type: application/json" --cert "Swish Merchant Test Certificate 1231181189.p12":swish --cert-type p12 --cacert "Swish TLS Root CA.pem" --tlsv1.1 --data @- <<!{ "payeePaymentReference": "0123456789","callbackUrl": https://callback.se/"https://example.com/api/swishcb/paymentrequests","payerAlias": "4671234768","payeeAlias": "1231181189","amount": "100","currency": "SEK","message": "Kingston USB Flash Drive 8 GB"}

But it is slightly missleading if you are about to use cURL in php. Because as you saw above, we merged the two files with certificates into one swish.pem. So, this is what it looks like using php.

$postData = '
{
    "payeePaymentReference": "' . $paymentReference . '",' // Code provided by you as a reference
   . '"callbackUrl": "' . $callbackUrl . '",' // See below swish_ipn.php
   . '"payerAlias": "' . $payerAlias . '",' // 4670xxxxxxxx - eg. the phone number of the user
   . '"payeeAlias": "' . $payeeAlias . '",' // 123xxxxxxx - eg. your number
   . '"amount": "' . $amount . '",' // Amount in SEK
   . '"currency": "' . $currency . '",' // 'SEK'
   . '"message": "' . $message . '"}'; // If the user included a message when paying
$ch = curl_init();
$header = array(
	'Content-Type: application/json',                                                                                
	'Content-Length: ' . strlen($postData)
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, $url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
if (substr($url, 0, 5) == 'https') { curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); }
curl_setopt($ch, CURLOPT_SSLCERT, '/path/swish.pem');
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'pem');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, '***PASSWORD***');

$result = curl_exec($ch);
if ($result === false) {
	echo curl_error($ch);
}
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($response_code == 200 or $response_code == 201) {
	echo 'The request was successfull.'; // Actually you should expect to get 201 in return.
} else {
	echo 'The request failed. Code: ' . $response_code;
}

Get payment notifications

Now all you need is the swish_ipn.php file the get the response from Swish when a payment has been completed.

$postData = file_get_contents("php://input");
// You want to write this to a log or a file for starters, so that you can see what comes back so you know how to deal with it.
file_put_contents('swish_payments.log', $postData)

That's it for this post, hope you find it useful and that it make it easier to implement Swish payments using php.

- Swish, Payment

<< MySQL to DB2

Comment

Name
Mail (Not public)
Send mail uppdates on new comments

Comments

0 post found