-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSigner.php
131 lines (114 loc) · 3.57 KB
/
Signer.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
namespace PetervdBroek\iDEAL2\Utils;
use PetervdBroek\iDEAL2\Exceptions\InvalidDigestException;
use PetervdBroek\iDEAL2\Exceptions\InvalidSignatureException;
use OpenSSLAsymmetricKey;
use OpenSSLCertificate;
class Signer
{
private OpenSSLCertificate $certificate;
private OpenSSLAsymmetricKey $privateKey;
/**
* @param $certificateFilePath
* @param $privateKeyFilePath
* @param $publicCertificateFilePath
*/
public function __construct($certificateFilePath, $privateKeyFilePath, $publicCertificateFilePath)
{
$this->certificate = openssl_x509_read(file_get_contents($certificateFilePath));
$this->privateKey = openssl_get_privatekey(file_get_contents($privateKeyFilePath));
$this->publicCertificate = openssl_x509_read(file_get_contents($publicCertificateFilePath));
}
/**
* @param string $body
* @return string
*/
public static function getDigest(string $body): string
{
return "SHA-256=" . base64_encode(hash('sha256', $body, true));
}
/**
* @param array $headers
* @return string
*/
public function getSignature(array $headers): string
{
$signString = $this->getSignString($headers);
$headersToSign = strtolower(implode(' ', array_keys($headers)));
return sprintf(
'keyId="%s", algorithm="SHA256withRSA", headers="%s", signature="%s"',
$this->getFingerprint(),
$headersToSign,
$this->getSignedString($signString)
);
}
/**
* @param array $headers
* @param string $body
* @throws InvalidDigestException
*/
public function verifyResponse(array $headers, string $body): void
{
$this->verifyDigest($headers, $body);
$this->verifySignature($headers);
}
/**
* @param array $headers
* @return string
*/
private function getSignString(array $headers): string
{
$signString = "";
foreach ($headers as $key => $header) {
$signString .= sprintf("%s: %s\n", strtolower($key), trim($header));
}
return trim($signString);
}
/**
* @return string
*/
private function getFingerprint(): string
{
return openssl_x509_fingerprint($this->certificate);
}
/**
* @param $signString
* @return string
*/
private function getSignedString($signString): string
{
$binary = "";
openssl_sign($signString, $binary, $this->privateKey, OPENSSL_ALGO_SHA256);
return base64_encode($binary);
}
/**
* @param array $headers
* @param string $body
* @return void
* @throws InvalidDigestException
*/
private function verifyDigest(array $headers, string $body): void
{
if ($headers['Digest'][0] !== self::getDigest($body)) {
throw new InvalidDigestException();
}
}
/**
* @param array $headers
* @return void
* @throws InvalidSignatureException
*/
private function verifySignature(array $headers): void
{
preg_match('/signature="([^"]+)"/', $headers['Signature'][0], $matches);
$signature = base64_decode($matches[1]);
$signString = $this->getSignString([
'MessageCreateDateTime' => $headers['MessageCreateDateTime'][0],
'X-Request-ID' => $headers['X-Request-ID'][0],
'Digest' => $headers['Digest'][0]
]);
if (openssl_verify($signString, $signature, $this->publicCertificate, 'SHA256') !== 1) {
throw new InvalidSignatureException();
}
}
}