From c0e61c21f07cacf0cacfd215160031e5153c25b4 Mon Sep 17 00:00:00 2001 From: eater <=@eater.me> Date: Mon, 25 Nov 2019 23:05:11 +0100 Subject: [PATCH] add ability export PKCS7 to DER --- resources/crypto.h | 2 ++ resources/openssl.h | 2 +- src/OpenSSL/PKCS7.php | 28 ++++++++++++++++++++-------- tests/PKCS7Test.php | 14 +++++++++++++- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/resources/crypto.h b/resources/crypto.h index 060ea4e..f33bf2e 100644 --- a/resources/crypto.h +++ b/resources/crypto.h @@ -1,3 +1,5 @@ +void CRYPTO_free(void *addr); + typedef struct crypto_ex_data_st CRYPTO_EX_DATA; struct crypto_ex_data_st { struct stack_st_void *sk; diff --git a/resources/openssl.h b/resources/openssl.h index e7cf1d8..3b2f51f 100644 --- a/resources/openssl.h +++ b/resources/openssl.h @@ -6,4 +6,4 @@ void OPENSSL_add_all_algorithms_conf(void); void OPENSSL_add_all_algorithms_noconf(void); void ERR_load_crypto_strings(void); -void ERR_free_strings(void); +void ERR_free_strings(void); \ No newline at end of file diff --git a/src/OpenSSL/PKCS7.php b/src/OpenSSL/PKCS7.php index 9ee47f0..e8dac1f 100644 --- a/src/OpenSSL/PKCS7.php +++ b/src/OpenSSL/PKCS7.php @@ -36,8 +36,20 @@ class PKCS7 extends OpenSSL\C\CBackedObjectWithOwner if (!in_array($type, [PKCS7::NID_DIGEST, self::NID_SIGNED, self::NID_SIGNED_AND_ENVELOPED])) { throw new \RuntimeException("Can only verify signed or digested data"); } + } + public function toDER(): string + { + $buf = $this->ffi->new("uint8_t*"); + $ptr = FFI::addr($buf); + $len = $this->ffi->i2d_PKCS7($this->cObj, $ptr); + if ($len < 0) { + throw new \RuntimeException("Failed to create DER from PKCS7 object"); + } + $val = FFI::string($buf, $len); + $this->ffi->CRYPTO_free($buf); + return $val; } public function freeObject() @@ -54,16 +66,16 @@ class PKCS7 extends OpenSSL\C\CBackedObjectWithOwner public static function loadFromDER(string $der): PKCS7 { - $pkcs = static::new(); - $pkcs->loadDER($der); - return $pkcs; - } - - private function loadDER(string $der) - { + $ffi = OpenSSL::getFFI(); $derLen = strlen($der); $mem = Memory::buffer($der); - $this->ffi->d2i_PKCS7(FFI::addr($this->cObj), $mem->pointer(), $derLen); + $res = $ffi->d2i_PKCS7(null, $mem->pointer(), $derLen); + + if ($res === null) { + throw new \RuntimeException("Failed loading DER"); + } + $mem->freed(); + return new static($ffi, $res); } } \ No newline at end of file diff --git a/tests/PKCS7Test.php b/tests/PKCS7Test.php index 879c1e6..ded2b74 100644 --- a/tests/PKCS7Test.php +++ b/tests/PKCS7Test.php @@ -4,6 +4,7 @@ namespace Cijber\OpenSSL\Tests; use Cijber\OpenSSL\PKCS7; use PHPUnit\Framework\TestCase; +use RuntimeException; class PKCS7Test extends TestCase { @@ -14,9 +15,20 @@ class PKCS7Test extends TestCase unset($pkcs7); } - public function testLoadDER() { + public function testLoadDER() + { $der = file_get_contents(__DIR__ . "/data/pkcs7/1.RSA"); $pkcs7 = PKCS7::loadFromDER($der); + $newDer = $pkcs7->toDER(); + $this->assertEquals($der, $newDer); $this->assertEquals(PKCS7::NID_SIGNED, $pkcs7->getType()); } + + public function testLoadingGarbageDER() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage("Failed loading DER"); + + PKCS7::loadFromDER("blaat"); + } }