Skip to content

Commit

Permalink
Implement a workaround for compatibility with legacy openssl pkcs12 f…
Browse files Browse the repository at this point in the history
…iles (#19)

* Happier mkdir avoids need to use @ while still avoiding race condition

* Workaround for legacy pkcs12 format issues from openssl 3.x, fixes #16 in chiiya/laravel-passes

* Fix a second instance of mkdir issue

* Include the error message in the exception

* Clarify comment
  • Loading branch information
Synchro authored Aug 20, 2023
1 parent d20bdf6 commit 6f7bf72
Showing 1 changed file with 63 additions and 7 deletions.
70 changes: 63 additions & 7 deletions src/Apple/PassFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ protected function createTempDirectory(Pass $pass): string
{
$dir = $this->tempDir.$pass->serialNumber.DIRECTORY_SEPARATOR;

if (! @mkdir($dir, 0o755) && ! is_dir($dir)) {
if (! is_dir($dir) && ! mkdir($dir, 0o755) && ! is_dir($dir)) {
throw new RuntimeException(sprintf('Directory "%s" could not be created', $dir));
}

Expand Down Expand Up @@ -333,7 +333,7 @@ protected function createLocalizations(Pass $pass, string $dir): void
foreach ($pass->getLocalizations() as $localization) {
$localizationDir = $dir.$localization->language.self::LOCALIZATION_EXTENSION;

if (! mkdir($localizationDir, 0o755) && ! is_dir($localizationDir)) {
if (! is_dir($localizationDir) && ! mkdir($localizationDir, 0o755) && ! is_dir($localizationDir)) {
throw new RuntimeException(sprintf('Directory "%s" could not be created', $dir));
}
$strings = '';
Expand Down Expand Up @@ -385,11 +385,7 @@ protected function sign(string $dir): void
throw new RuntimeException(sprintf('The WWDR certificate at "%s" could not be read', $this->wwdr));
}

$certs = [];

if (! openssl_pkcs12_read($p12, $certs, $this->password)) {
throw new RuntimeException(sprintf('Invalid certificate file: "%s"', $this->certificate));
}
$certs = $this->openssl_pkcs12_read_wrapper($p12, $this->password);

$certData = openssl_x509_read($certs['cert']);
$privateKey = openssl_pkey_get_private($certs['pkey'], $this->password);
Expand All @@ -410,6 +406,66 @@ protected function sign(string $dir): void
file_put_contents($signatureFile, $signature);
}

/**
* Wrapper for the openssl_pkcs12_read function allowing for fallback to a shell_exec call
* to work around a problem reading legacy p12 files in newer versions of PHP.
* Adapted from an implementation in the php-pkpass project.
*
* @see https://github.com/includable/php-pkpass/issues/122
*/
protected function openssl_pkcs12_read_wrapper(string $pkcs12, string $passphrase): array
{
$certs = [];
// If the openssl_pkcs12_read function works ok, go with that
if (openssl_pkcs12_read($pkcs12, $certs, $passphrase)) {
return $certs;
}

// That failed, get error message
$error = '';

while ($text = openssl_error_string()) {
$error .= $text;
}

// If an error occurred that wasn't due to a legacy p12 file, the workaround won't help, so give up now
if (! str_contains($error, 'digital envelope routines::unsupported')) {
throw new RuntimeException(
sprintf('Invalid certificate file: "%s". Error: %s', $this->certificate, $error),
);
}

// Try an alternative route using shell_exec to allow legacy support
try {
$value = @shell_exec(
'openssl pkcs12 -in '.escapeshellarg($this->certificate)
.' -passin '.escapeshellarg('pass:'.$passphrase)
.' -passout '.escapeshellarg('pass:'.$passphrase)
.' -legacy',
);

if ($value) {
$certMatches = [];
$keyMatches = [];
// Search separately so that they can appear in either order
if (
preg_match('/-----BEGIN CERTIFICATE-----.*-----END CERTIFICATE-----/s', $value, $certMatches)
&& preg_match(
'/-----BEGIN ENCRYPTED PRIVATE KEY-----.*-----END ENCRYPTED PRIVATE KEY-----/s',
$value,
$keyMatches,
)
) {
return ['cert' => $certMatches[0], 'pkey' => $keyMatches[0]];
}
}
} catch (\Throwable) {
// no need to do anything
}

throw new RuntimeException(sprintf('Invalid certificate file: "%s". Error: %s', $this->certificate, $error));
}

/**
* Converts PKCS7 PEM to PKCS7 DER
* Parameter: string, holding PKCS7 PEM, binary, detached
Expand Down

0 comments on commit 6f7bf72

Please sign in to comment.