diff --git a/composer.json b/composer.json index 751b1fe..51b790c 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,8 @@ "type": "library", "require": { "ext-FFI": "*", - "php": "^7.4" + "php": "^7.4", + "ext-openssl": "*" }, "require-dev": { "phpstan/phpstan": "^0.11.19", diff --git a/resources/x509.h b/resources/x509.h index 8c596d1..e72c646 100644 --- a/resources/x509.h +++ b/resources/x509.h @@ -234,6 +234,42 @@ struct stack_st_X509_CRL { _STACK stack; }; +typedef struct x509_lookup_st X509_LOOKUP; + +typedef struct x509_object_st + { + + int type; + union { + char *ptr; + X509 *x509; + X509_CRL *crl; + EVP_PKEY *pkey; + } data; + } X509_OBJECT; + +struct stack_st_X509_LOOKUP { _STACK stack; }; +struct stack_st_X509_OBJECT { _STACK stack; }; + +typedef struct x509_lookup_method_st { + const char *name; + int (*new_item)(X509_LOOKUP *ctx); + void (*free)(X509_LOOKUP *ctx); + int (*init)(X509_LOOKUP *ctx); + int (*shutdown)(X509_LOOKUP *ctx); + int (*ctrl)(X509_LOOKUP *ctx, int cmd, const char *argc, long argl, + char **ret); + int (*get_by_subject)(X509_LOOKUP *ctx, int type, X509_NAME *name, + X509_OBJECT *ret); + int (*get_by_issuer_serial)(X509_LOOKUP *ctx, int type, X509_NAME *name, + ASN1_INTEGER *serial, X509_OBJECT *ret); + int (*get_by_fingerprint)(X509_LOOKUP *ctx, int type, + const unsigned char *bytes, int len, + X509_OBJECT *ret); + int (*get_by_alias)(X509_LOOKUP *ctx, int type, const char *str, int len, + X509_OBJECT *ret); +} X509_LOOKUP_METHOD; + X509 *X509_new(void); X509 *X509_dup(X509 *x509); void X509_free(X509 *a); @@ -241,7 +277,13 @@ void X509_free(X509 *a); X509_STORE *X509_STORE_new(void); void X509_STORE_free(X509_STORE *v); +X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); + X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void); - X509_LOOKUP_METHOD *X509_LOOKUP_file(void); +X509_LOOKUP_METHOD *X509_LOOKUP_file(void); +X509_LOOKUP_METHOD *X509_LOOKUP_mem(void); + +int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type); - int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type); \ No newline at end of file +int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); \ No newline at end of file diff --git a/src/OpenSSL.php b/src/OpenSSL.php index 79b0a78..afa7a0b 100644 --- a/src/OpenSSL.php +++ b/src/OpenSSL.php @@ -5,6 +5,7 @@ namespace Cijber; use Cijber\OpenSSL\FFIWrapper; use Cijber\OpenSSL\Instance; +use Cijber\OpenSSL\X509Store; use FFI; /** @@ -71,6 +72,10 @@ class OpenSSL public static function CAStore() { - + if (static::$caStore === null) { + static::$caStore = X509Store::default(); + } + + return static::$caStore; } } diff --git a/src/OpenSSL/PKCS7/Signed.php b/src/OpenSSL/PKCS7/Signed.php index 432476d..6fe4c6c 100644 --- a/src/OpenSSL/PKCS7/Signed.php +++ b/src/OpenSSL/PKCS7/Signed.php @@ -5,18 +5,14 @@ namespace Cijber\OpenSSL\PKCS7; use Cijber\OpenSSL; use Cijber\OpenSSL\BIO; -use Cijber\OpenSSL\PKCS7; use Cijber\OpenSSL\Stack\X509Stack; use Cijber\OpenSSL\X509Store; -use FFI; -use FFI\CData; class Signed { use Helpers; - public function getCerts(): X509Stack { @@ -25,14 +21,14 @@ class Signed return $stack; } - public function verify(string $plain, ?X509Store $x509Store = null) + public function verify(string $plain, int $flags, ?X509Store $x509Store = null) { if ($x509Store === null) { $x509Store = OpenSSL::CAStore(); } $buffer = BIO::buffer($plain); - $x = $this->ffi->PKCS7_verify($this->parent, null, null, $buffer->getCData(), null, 0); + $x = $this->ffi->PKCS7_verify($this->parent, null, $x509Store->getCData(), $buffer->getCData(), null, $flags); return $x === 1; } } diff --git a/src/OpenSSL/X509.php b/src/OpenSSL/X509.php index 29cfbf9..fb8a2bb 100644 --- a/src/OpenSSL/X509.php +++ b/src/OpenSSL/X509.php @@ -9,6 +9,8 @@ use FFI; class X509 extends CBackedObjectWithOwner { + const FILETYPE_DEFAULT = 3; + const TYPE = "X509*"; public static function new(): X509 diff --git a/src/OpenSSL/X509Store.php b/src/OpenSSL/X509Store.php index 3b73a3f..16b2bd2 100644 --- a/src/OpenSSL/X509Store.php +++ b/src/OpenSSL/X509Store.php @@ -15,6 +15,24 @@ class X509Store extends CBackedObjectWithOwner return new X509Store($ffi, $x509); } + public static function default(): X509Store + { + $store = X509Store::new(); + $obj = $store->cObj; + $ffi = $store->ffi; + $lookup = $ffi->X509_STORE_add_lookup($obj, $ffi->X509_LOOKUP_file()); + if ($lookup === null || !$ffi->X509_LOOKUP_ctrl($lookup, 1, null, X509::FILETYPE_DEFAULT, null)) { + throw new \RuntimeException("Couldn't load default CA files"); + } + + $lookup = $ffi->X509_STORE_add_lookup($obj, $ffi->X509_LOOKUP_hash_dir()); + if ($lookup === null || !$ffi->X509_LOOKUP_ctrl($lookup, 2, null, X509::FILETYPE_DEFAULT, null)) { + throw new \RuntimeException("Couldn't load default CA files"); + } + + return $store; + } + public function freeObject() { $this->ffi->X509_STORE_free($this->cObj); diff --git a/tests/PKCS7Test.php b/tests/PKCS7Test.php index f80237c..883805b 100644 --- a/tests/PKCS7Test.php +++ b/tests/PKCS7Test.php @@ -37,7 +37,8 @@ class PKCS7Test extends TestCase $plain = file_get_contents(__DIR__ . "/data/pkcs7/1.SF"); $pkcs7 = PKCS7::loadFromDER($der); $signed = $pkcs7->asSigned(); - $result = $signed->verify($plain); + $result = $signed->verify($plain, PKCS7_NOVERIFY); + $this->assertTrue($result); } public function testLoadingGarbageDER()