1 | <?php |
||
9 | class Signer |
||
10 | { |
||
11 | public const FILENAME = 'signature'; |
||
12 | |||
13 | /** |
||
14 | * @var mixed |
||
15 | * in PHP 7.4 this is a resource, in PHP 8.0 this is a OpenSSLCertificate |
||
16 | */ |
||
17 | private $certificate; |
||
18 | |||
19 | /** |
||
20 | * @var mixed |
||
21 | * in PHP 7.4 this is a resource, in PHP 8.0 this is a OpenSSLAsymmetricKey |
||
22 | */ |
||
23 | private $privateKey; |
||
24 | private string $appleWWDRCA; |
||
|
|||
25 | |||
26 | /** |
||
27 | * @throws CertificateException |
||
28 | */ |
||
29 | public function __construct(?string $certificatePath = null, ?string $password = null) |
||
30 | { |
||
31 | if ($certificatePath !== null && $password !== null) { |
||
32 | $this->setCertificate($certificatePath, $password); |
||
33 | } |
||
34 | |||
35 | $this->setAppleWWDRCA(__DIR__ . '/../../certificates/AppleWWDRCA.pem'); |
||
36 | } |
||
37 | |||
38 | /** |
||
39 | * @throws CertificateException |
||
40 | */ |
||
41 | public function setCertificate(string $path, string $password): void |
||
42 | { |
||
43 | if (!file_exists($path)) { |
||
44 | throw CertificateException::fileDoesNotExist($path); |
||
45 | } |
||
46 | |||
47 | $data = []; |
||
48 | if (!openssl_pkcs12_read((string) file_get_contents($path), $data, $password)) { |
||
49 | throw CertificateException::failedToReadPkcs12($path); |
||
50 | } |
||
51 | |||
52 | $this->certificate = openssl_x509_read($data['cert']); |
||
53 | $this->privateKey = openssl_pkey_get_private($data['pkey'], $password); |
||
54 | } |
||
55 | |||
56 | /** |
||
57 | * @throws CertificateException |
||
58 | */ |
||
59 | public function setAppleWWDRCA(string $path): void |
||
60 | { |
||
61 | if (!file_exists($path)) { |
||
62 | throw CertificateException::fileDoesNotExist($path); |
||
63 | } |
||
64 | $this->appleWWDRCA = $path; |
||
65 | } |
||
66 | |||
67 | public function sign(string $temporaryDirectory): void |
||
68 | { |
||
69 | $manifestFile = $temporaryDirectory . ManifestGenerator::FILENAME; |
||
70 | |||
71 | $openSslArguments = [ |
||
72 | $manifestFile, |
||
73 | $temporaryDirectory . self::FILENAME, |
||
74 | $this->certificate, |
||
75 | $this->privateKey, |
||
76 | [], |
||
77 | PKCS7_BINARY | PKCS7_DETACHED |
||
78 | ]; |
||
79 | |||
80 | if ($this->appleWWDRCA) { |
||
81 | $openSslArguments[] = $this->appleWWDRCA; |
||
82 | } |
||
83 | |||
84 | call_user_func_array('openssl_pkcs7_sign', $openSslArguments); |
||
85 | |||
86 | $signature = (string) file_get_contents($temporaryDirectory . self::FILENAME); |
||
87 | $signature = $this->convertPEMtoDER($signature); |
||
88 | file_put_contents($temporaryDirectory . self::FILENAME, $signature); |
||
89 | } |
||
90 | |||
91 | private function convertPEMtoDER(string $signature): string |
||
92 | { |
||
93 | $begin = 'filename="smime.p7s"'; |
||
94 | $end = '------'; |
||
95 | $signature = substr($signature, strpos($signature, $begin) + strlen($begin)); |
||
96 | |||
97 | $signature = substr($signature, 0, (int) strpos($signature, $end)); |
||
98 | $signature = trim($signature); |
||
99 | $signature = base64_decode($signature); |
||
100 | |||
101 | return $signature; |
||
102 | } |
||
103 | } |
||
104 |