Signer::sign()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 13
nc 2
nop 1
dl 0
loc 22
ccs 0
cts 12
cp 0
crap 6
rs 9.8333
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LauLamanApps\ApplePassbook\Build;
6
7
use LauLamanApps\ApplePassbook\Build\Exception\CertificateException;
8
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