Skip to content

Commit 133a570

Browse files
committed
Support specify custom keyring details for Electronic Signature.
1 parent 49f23d9 commit 133a570

File tree

9 files changed

+136
-12
lines changed

9 files changed

+136
-12
lines changed

.editorconfig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ insert_final_newline = true
99
trim_trailing_whitespace = true
1010

1111
[*.md]
12-
trim_trailing_whitespace = false
12+
trim_trailing_whitespace = false
13+
14+
[*.{key,pwd,crt,csr}]
15+
insert_final_newline = false

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## 2.3
22

3+
* Support specify custom keyring details for Electronic Signature.
34
* Support switching A005/A006
45
* Change signature for KeyringManagerInterface. Attributes `USER.A.Version` moved from Bank to Keyring.
56
* Add `withES` param for downloading order types. Default `withES=false`.

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ ifdef WIN_ETH_DRIVER
44
WIN_ETH_IP := $(shell ipconfig.exe | grep ${WIN_ETH_DRIVER} -A3 | cut -d':' -f 2 | tail -n1 | sed -e 's/\s*//g')
55
endif
66

7-
docker-up u:
7+
docker-up u start:
88
cd docker && docker-compose -p ebics-client-php up -d;
99
@if [ "$(WIN_ETH_IP)" ]; then cd docker && docker-compose -p ebics-client-php exec php-cli-ebics-client-php sh -c "echo '$(WIN_ETH_IP) host.docker.internal' >> /etc/hosts"; fi
1010

11-
docker-down d:
11+
docker-down d stop:
1212
cd docker && docker-compose -p ebics-client-php down
1313

14-
docker-build:
14+
docker-build build:
1515
cd docker && docker-compose -p ebics-client-php build --no-cache
1616

1717
docker-php php:

src/Contracts/EbicsClientInterface.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ interface EbicsClientInterface
3535

3636
/**
3737
* Create user signatures A, E and X on first launch.
38+
* @param string $aVersion Version of Electronic Signature (A005|A006)
39+
* @param array|null $aDetails Custom Certificate, private_key and
40+
* password details for Electronic Signature.
3841
*/
39-
public function createUserSignatures(string $aVersion): void;
42+
public function createUserSignatures(string $aVersion, array $aDetails = null): void;
4043

4144
/**
4245
* Download supported protocol versions for the Bank.

src/EbicsClient.php

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
use AndrewSvirin\Ebics\Models\UploadOrderResult;
5151
use AndrewSvirin\Ebics\Models\UploadTransaction;
5252
use AndrewSvirin\Ebics\Models\User;
53+
use AndrewSvirin\Ebics\Models\X509\ContentX509Generator;
5354
use AndrewSvirin\Ebics\Services\CryptService;
5455
use AndrewSvirin\Ebics\Services\CurlHttpClient;
5556
use AndrewSvirin\Ebics\Services\XmlService;
@@ -125,9 +126,11 @@ public function __construct(Bank $bank, User $user, Keyring $keyring)
125126
* @inheritDoc
126127
* @throws EbicsException
127128
*/
128-
public function createUserSignatures(string $aVersion = SignatureInterface::A_VERSION6): void
129-
{
130-
$signatureA = $this->createUserSignature(SignatureInterface::TYPE_A);
129+
public function createUserSignatures(
130+
string $aVersion = SignatureInterface::A_VERSION6,
131+
array $aDetails = null
132+
): void {
133+
$signatureA = $this->createUserSignature(SignatureInterface::TYPE_A, $aDetails);
131134
$this->keyring->setUserSignatureAVersion($aVersion);
132135
$this->keyring->setUserSignatureA($signatureA);
133136

@@ -1310,14 +1313,27 @@ private function getUserSignature(string $type): SignatureInterface
13101313
* @return SignatureInterface
13111314
* @throws EbicsException
13121315
*/
1313-
private function createUserSignature(string $type): SignatureInterface
1316+
private function createUserSignature(string $type, array $details = null): SignatureInterface
13141317
{
13151318
switch ($type) {
13161319
case SignatureInterface::TYPE_A:
1320+
if (null === $details) {
1321+
$keys = $this->cryptService->generateKeys($this->keyring->getPassword());
1322+
$certificateGenerator = $this->keyring->getCertificateGenerator();
1323+
} else {
1324+
$keys = $this->cryptService->changePrivateKeyPassword(
1325+
$details['privatekey'],
1326+
$details['password'],
1327+
$this->keyring->getPassword()
1328+
);
1329+
$certificateGenerator = new ContentX509Generator();
1330+
$certificateGenerator->setAContent($details['certificate']);
1331+
}
1332+
13171333
$signature = $this->signatureFactory->createSignatureAFromKeys(
1318-
$this->cryptService->generateKeys($this->keyring->getPassword()),
1334+
$keys,
13191335
$this->keyring->getPassword(),
1320-
$this->keyring->getCertificateGenerator()
1336+
$certificateGenerator
13211337
);
13221338
break;
13231339
case SignatureInterface::TYPE_E:

src/Models/X509/BankX509Generator.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace AndrewSvirin\Ebics\Models\X509;
44

5-
use AndrewSvirin\Ebics\Contracts\EbicsClientInterface;
65
use AndrewSvirin\Ebics\Models\Bank;
76
use LogicException;
87

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace AndrewSvirin\Ebics\Models\X509;
4+
5+
use AndrewSvirin\Ebics\Contracts\Crypt\RSAInterface;
6+
use AndrewSvirin\Ebics\Contracts\Crypt\X509Interface;
7+
use AndrewSvirin\Ebics\Contracts\X509GeneratorInterface;
8+
use AndrewSvirin\Ebics\Models\Crypt\X509;
9+
10+
/**
11+
* Generator simulation for already created certificates and loaded from content.
12+
*
13+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
14+
* @author Andrew Svirin
15+
*/
16+
final class ContentX509Generator implements X509GeneratorInterface
17+
{
18+
private string $aContent;
19+
20+
private string $eContent;
21+
22+
private string $xContent;
23+
24+
public function setAContent(string $content): void
25+
{
26+
$this->aContent = $content;
27+
}
28+
29+
public function setEContent(string $content): void
30+
{
31+
$this->eContent = $content;
32+
}
33+
34+
public function setXContent(string $content): void
35+
{
36+
$this->xContent = $content;
37+
}
38+
39+
public function generateAX509(RSAInterface $privateKey, RSAInterface $publicKey): X509Interface
40+
{
41+
$cert = new X509();
42+
43+
$cert->loadX509($this->aContent);
44+
45+
return $cert;
46+
}
47+
48+
public function generateEX509(RSAInterface $privateKey, RSAInterface $publicKey): X509Interface
49+
{
50+
$cert = new X509();
51+
52+
$cert->loadX509($this->eContent);
53+
54+
return $cert;
55+
}
56+
57+
public function generateXX509(RSAInterface $privateKey, RSAInterface $publicKey): X509Interface
58+
{
59+
$cert = new X509();
60+
61+
$cert->loadX509($this->xContent);
62+
63+
return $cert;
64+
}
65+
}

tests/EbicsClientV30Test.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,43 @@ public function testChangeKeyringPassword(int $credentialsId, array $codes)
5858
$this->assertResponseOk($code, $reportText);
5959
}
6060

61+
/**
62+
* @dataProvider serversDataProvider
63+
*
64+
* @group INI-CUSTOM
65+
* @group INI-V30-CUSTOM
66+
*
67+
* @param int $credentialsId
68+
* @param array $codes
69+
*
70+
* @covers
71+
*/
72+
public function testINIWithCustomCrt(int $credentialsId, array $codes)
73+
{
74+
$client = $this->setupClientV30($credentialsId, $codes['INI']['fake']);
75+
76+
$client->createUserSignatures('A005', [
77+
'privatekey' => file_get_contents($this->data.'/electronic_signature/user.key'),
78+
'certificate' => file_get_contents($this->data.'/electronic_signature/user.crt'),
79+
'password' => file_get_contents($this->data.'/electronic_signature/passphrase.txt'),
80+
]);
81+
82+
// Check that keyring is empty and or wait on success or wait on exception.
83+
$userExists = $client->getKeyring()->getUserSignatureA();
84+
if ($userExists) {
85+
$this->expectException(InvalidUserOrUserStateException::class);
86+
$this->expectExceptionCode(91002);
87+
}
88+
$ini = $client->INI();
89+
if (!$userExists) {
90+
$responseHandler = $client->getResponseHandler();
91+
$this->saveKeyring($credentialsId, $client->getKeyring());
92+
$code = $responseHandler->retrieveH00XReturnCode($ini);
93+
$reportText = $responseHandler->retrieveH00XReportText($ini);
94+
$this->assertResponseOk($code, $reportText);
95+
}
96+
}
97+
6198
/**
6299
* @dataProvider serversDataProvider
63100
*

tests/_data.zip

9.15 KB
Binary file not shown.

0 commit comments

Comments
 (0)