drupflare/worker - v1.0.4
    Preparing search index...

    Variable OPENSSL_FIX_PHPConst

    OPENSSL_FIX_PHP: "\nuse Drupal\\drupflare\\Degradation;\n\nif (!extension_loaded('openssl') && !function_exists('cfw_openssl_installed')) {\n\t$__cfw_sign = function_exists('vrzno_env') ? vrzno_env('cfwSign') : null;\n\tif ($__cfw_sign !== null) {\n\t\t$GLOBALS['__cfw_sign'] = $__cfw_sign;\n\t\t$GLOBALS['__cfw_openssl_errors'] = [];\n\n\t\t// __CFW_OPENSSL_DEFINES__\n\t\tif (!defined('OPENSSL_VERSION_TEXT')) {\n\t\t\tdefine('OPENSSL_VERSION_TEXT', 'BoringSSL (node:crypto)');\n\t\t}\n\n\t\tif (!class_exists('OpenSSLAsymmetricKey', false)) {\n\t\t\t/**\n\t\t\t * A key, holding PEM text rather than a native handle.\n\t\t\t */\n\t\t\tfinal class OpenSSLAsymmetricKey\n\t\t\t{\n\t\t\t\tpublic function __construct(\n\t\t\t\t\tpublic readonly string $cfwPublicPem,\n\t\t\t\t\tpublic readonly string $cfwPrivatePem = '',\n\t\t\t\t) {}\n\t\t\t}\n\t\t}\n\t\tif (!class_exists('OpenSSLCertificate', false)) {\n\t\t\t/**\n\t\t\t * A certificate, holding its PEM text.\n\t\t\t */\n\t\t\tfinal class OpenSSLCertificate\n\t\t\t{\n\t\t\t\tpublic function __construct(public readonly string $cfwPem) {}\n\t\t\t}\n\t\t}\n\n\t\tfunction cfw_openssl_installed(): bool\n\t\t{\n\t\t\treturn true;\n\t\t}\n\n\t\t/**\n\t\t * Runs one op over the bridge.\n\t\t *\n\t\t * @param array<string, mixed> $payload\n\t\t * The request, including its `op`.\n\t\t *\n\t\t * @return array<string, mixed>\n\t\t * The decoded reply, always with an 'ok' key.\n\t\t */\n\t\tfunction cfw_sign_call($payload): array\n\t\t{\n\t\t\t$fn = $GLOBALS['__cfw_sign'];\n\t\t\t$reply = json_decode($fn(json_encode($payload)), true);\n\t\t\tif (!is_array($reply)) {\n\t\t\t\t$reply = ['ok' => false, 'error' => 'unreadable reply'];\n\t\t\t}\n\t\t\tif (($reply['ok'] ?? false) !== true) {\n\t\t\t\t$GLOBALS['__cfw_openssl_errors'][] = (string) ($reply['error'] ?? 'failed');\n\t\t\t}\n\t\t\treturn $reply;\n\t\t}\n\n\t\t/**\n\t\t * Declares a failure to the operator, the way curl-fix.ts does.\n\t\t *\n\t\t * A per-call trigger_error reaches the log and never the status report, and a failed verify\n\t\t * had neither -- so a caller misreading -1 as \"forged\" was invisible from outside.\n\t\t *\n\t\t * @param string $capability\n\t\t * The capability that degraded.\n\t\t * @param string $why\n\t\t * Why it did.\n\t\t */\n\t\tfunction cfw_openssl_degraded($capability, $why): void\n\t\t{\n\t\t\tif (class_exists(Degradation::class)) {\n\t\t\t\tDegradation::record($capability, $why);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * The PEM text for whatever ext-openssl would accept as a key or certificate.\n\t\t *\n\t\t * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array<int|string, string>|string $key\n\t\t * A key object, a certificate object, a two-key array, a PEM or a file:// path.\n\t\t * @param string $want\n\t\t * 'private' for the private half, 'public' for the public half or a certificate.\n\t\t */\n\t\tfunction cfw_openssl_pem($key, $want): string\n\t\t{\n\t\t\tif ($key instanceof OpenSSLAsymmetricKey) {\n\t\t\t\treturn $want === 'private' && $key->cfwPrivatePem !== ''\n\t\t\t\t\t? $key->cfwPrivatePem\n\t\t\t\t\t: $key->cfwPublicPem;\n\t\t\t}\n\t\t\tif ($key instanceof OpenSSLCertificate) {\n\t\t\t\treturn $key->cfwPem;\n\t\t\t}\n\t\t\tif (is_array($key) && (isset($key['private']) || isset($key['public']))) {\n\t\t\t\treturn (string) ($key[$want] ?? ($key['private'] ?? ''));\n\t\t\t}\n\t\t\tif (is_array($key)) {\n\t\t\t\t$key = $key[0] ?? '';\n\t\t\t}\n\t\t\t$key = (string) $key;\n\t\t\tif (str_starts_with($key, 'file://')) {\n\t\t\t\t$read = @file_get_contents(substr($key, 7));\n\t\t\t\treturn $read === false ? '' : $read;\n\t\t\t}\n\t\t\treturn $key;\n\t\t}\n\n\t\t/** @return string|false */\n\t\tfunction openssl_error_string()\n\t\t{\n\t\t\treturn array_shift($GLOBALS['__cfw_openssl_errors']) ?? false;\n\t\t}\n\n\t\t/**\n\t\t * @param int $length\n\t\t * The number of bytes.\n\t\t * @param bool|null $strong_result\n\t\t * Set to TRUE, since the bytes come from random_bytes().\n\t\t * @param-out true $strong_result\n\t\t */\n\t\tfunction openssl_random_pseudo_bytes($length, &$strong_result = null): string\n\t\t{\n\t\t\t$strong_result = true;\n\t\t\treturn random_bytes(max(1, (int) $length));\n\t\t}\n\n\t\t/**\n\t\t * @param bool $aliases\n\t\t * Ignored; there are no aliases here.\n\t\t *\n\t\t * @return list<string>\n\t\t */\n\t\tfunction openssl_get_cipher_methods($aliases = false): array\n\t\t{\n\t\t\t$out = [];\n\t\t\tforeach ([128, 192, 256] as $bits) {\n\t\t\t\tforeach (['cbc', 'ctr', 'ecb', 'gcm'] as $mode) {\n\t\t\t\t\t$out[] = 'aes-' . $bits . '-' . $mode;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $out;\n\t\t}\n\n\t\t/**\n\t\t * Key and IV length for a supported cipher, or NULL.\n\t\t *\n\t\t * @param string $cipher\n\t\t * A cipher name.\n\t\t *\n\t\t * @return array{0: int, 1: int, 2: string}|null\n\t\t * [key bytes, iv bytes, mode].\n\t\t */\n\t\tfunction cfw_openssl_cipher($cipher): ?array\n\t\t{\n\t\t\tif (\n\t\t\t\t!preg_match(\n\t\t\t\t\t'/^aes-(128|192|256)-(cbc|ctr|ecb|gcm)$/',\n\t\t\t\t\tstrtolower((string) $cipher),\n\t\t\t\t\t$m,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t$iv = ['cbc' => 16, 'ctr' => 16, 'ecb' => 0, 'gcm' => 12][$m[2]];\n\t\t\treturn [intdiv((int) $m[1], 8), $iv, $m[2]];\n\t\t}\n\n\t\t/**\n\t\t * @param string $cipher_algo\n\t\t * A cipher name.\n\t\t *\n\t\t * @return int|false\n\t\t */\n\t\tfunction openssl_cipher_iv_length($cipher_algo)\n\t\t{\n\t\t\t$c = cfw_openssl_cipher($cipher_algo);\n\t\t\tif ($c === null) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_cipher_iv_length(): Unknown cipher algorithm',\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn $c[1];\n\t\t}\n\n\t\t/**\n\t\t * @param string $cipher_algo\n\t\t * A cipher name.\n\t\t *\n\t\t * @return int|false\n\t\t */\n\t\tfunction openssl_cipher_key_length($cipher_algo)\n\t\t{\n\t\t\t$c = cfw_openssl_cipher($cipher_algo);\n\t\t\tif ($c === null) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_cipher_key_length(): Unknown cipher algorithm',\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn $c[0];\n\t\t}\n\n\t\t/**\n\t\t * The shared half of encrypt and decrypt: key and IV sized the way ext-openssl sizes them.\n\t\t *\n\t\t * A short key is padded with NUL and a long one truncated, silently, as ext-openssl does.\n\t\t * A short IV is padded with a warning; a GCM IV keeps whatever length the caller gave.\n\t\t *\n\t\t * @param string $dir\n\t\t * 'enc' or 'dec'.\n\t\t * @param string $data\n\t\t * The plaintext, or the ciphertext.\n\t\t * @param string $cipher_algo\n\t\t * A cipher name.\n\t\t * @param string $passphrase\n\t\t * The key material.\n\t\t * @param int $options\n\t\t * OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING flags.\n\t\t * @param string $iv\n\t\t * The initialisation vector.\n\t\t * @param string|false|null $tag\n\t\t * The GCM tag, on decrypt.\n\t\t * @param string $aad\n\t\t * Additional authenticated data, for GCM.\n\t\t * @param int $tag_length\n\t\t * The GCM tag length in bytes.\n\t\t *\n\t\t * @return array<string, mixed>|false\n\t\t * The bridge reply, or FALSE for an unknown cipher or a malformed ciphertext.\n\t\t */\n\t\tfunction cfw_openssl_crypt(\n\t\t\t$dir,\n\t\t\t$data,\n\t\t\t$cipher_algo,\n\t\t\t$passphrase,\n\t\t\t$options,\n\t\t\t$iv,\n\t\t\t$tag,\n\t\t\t$aad,\n\t\t\t$tag_length,\n\t\t) {\n\t\t\t$c = cfw_openssl_cipher($cipher_algo);\n\t\t\tif ($c === null) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_' .\n\t\t\t\t\t\t($dir === 'enc' ? 'encrypt' : 'decrypt') .\n\t\t\t\t\t\t'(): Unknown cipher algorithm',\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t[$keyLen, $ivLen, $mode] = $c;\n\t\t\t$key = substr(str_pad((string) $passphrase, $keyLen, \"\\0\"), 0, $keyLen);\n\t\t\t$iv = (string) $iv;\n\t\t\tif ($mode !== 'gcm' && strlen($iv) !== $ivLen) {\n\t\t\t\tif ($ivLen > 0 && strlen($iv) < $ivLen) {\n\t\t\t\t\ttrigger_error(\n\t\t\t\t\t\t'openssl_' .\n\t\t\t\t\t\t\t($dir === 'enc' ? 'encrypt' : 'decrypt') .\n\t\t\t\t\t\t\t'(): IV passed is only ' .\n\t\t\t\t\t\t\tstrlen($iv) .\n\t\t\t\t\t\t\t' bytes long, cipher expects an IV of precisely ' .\n\t\t\t\t\t\t\t$ivLen .\n\t\t\t\t\t\t\t' bytes, padding with \\\\0',\n\t\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t$iv = substr(str_pad($iv, $ivLen, \"\\0\"), 0, $ivLen);\n\t\t\t}\n\t\t\t$raw = (bool) ((int) $options & 1);\n\t\t\t$bytes = (string) $data;\n\t\t\tif ($dir === 'dec' && !$raw) {\n\t\t\t\t$bytes = base64_decode($bytes, true);\n\t\t\t\tif ($bytes === false) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t$payload = [\n\t\t\t\t'op' => 'cipher',\n\t\t\t\t'dir' => $dir,\n\t\t\t\t'cipher' => strtolower((string) $cipher_algo),\n\t\t\t\t'b64' => base64_encode($bytes),\n\t\t\t\t'keyB64' => base64_encode($key),\n\t\t\t\t'ivB64' => base64_encode($iv),\n\t\t\t\t'padding' => !((int) $options & 2),\n\t\t\t\t'tagLength' => (int) $tag_length,\n\t\t\t];\n\t\t\tif ($mode === 'gcm') {\n\t\t\t\tif ((string) $aad !== '') {\n\t\t\t\t\t$payload['aadB64'] = base64_encode((string) $aad);\n\t\t\t\t}\n\t\t\t\tif ($dir === 'dec') {\n\t\t\t\t\t$payload['tagB64'] = base64_encode((string) $tag);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn cfw_sign_call($payload);\n\t\t}\n\n\t\t/**\n\t\t * @param string $data\n\t\t * The plaintext.\n\t\t * @param string $cipher_algo\n\t\t * A cipher name.\n\t\t * @param string $passphrase\n\t\t * The key material.\n\t\t * @param int $options\n\t\t * OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING flags.\n\t\t * @param string $iv\n\t\t * The initialisation vector.\n\t\t * @param string|false|null $tag\n\t\t * Set to the GCM tag.\n\t\t * @param string $aad\n\t\t * Additional authenticated data, for GCM.\n\t\t * @param int $tag_length\n\t\t * The GCM tag length in bytes.\n\t\t *\n\t\t * @return string|false\n\t\t */\n\t\tfunction openssl_encrypt(\n\t\t\t$data,\n\t\t\t$cipher_algo,\n\t\t\t$passphrase,\n\t\t\t$options = 0,\n\t\t\t$iv = '',\n\t\t\t&$tag = null,\n\t\t\t$aad = '',\n\t\t\t$tag_length = 16,\n\t\t) {\n\t\t\t$r = cfw_openssl_crypt(\n\t\t\t\t'enc',\n\t\t\t\t$data,\n\t\t\t\t$cipher_algo,\n\t\t\t\t$passphrase,\n\t\t\t\t$options,\n\t\t\t\t$iv,\n\t\t\t\tnull,\n\t\t\t\t$aad,\n\t\t\t\t$tag_length,\n\t\t\t);\n\t\t\tif (!is_array($r) || ($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (isset($r['tagB64'])) {\n\t\t\t\t$tag = base64_decode((string) $r['tagB64'], true);\n\t\t\t}\n\t\t\t$out = base64_decode((string) ($r['b64'] ?? ''), true);\n\t\t\tif ($out === false) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn (int) $options & 1 ? $out : base64_encode($out);\n\t\t}\n\n\t\t/**\n\t\t * @param string $data\n\t\t * The ciphertext.\n\t\t * @param string $cipher_algo\n\t\t * A cipher name.\n\t\t * @param string $passphrase\n\t\t * The key material.\n\t\t * @param int $options\n\t\t * OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING flags.\n\t\t * @param string $iv\n\t\t * The initialisation vector.\n\t\t * @param string|false|null $tag\n\t\t * The GCM tag.\n\t\t * @param string $aad\n\t\t * Additional authenticated data, for GCM.\n\t\t *\n\t\t * @return string|false\n\t\t */\n\t\tfunction openssl_decrypt(\n\t\t\t$data,\n\t\t\t$cipher_algo,\n\t\t\t$passphrase,\n\t\t\t$options = 0,\n\t\t\t$iv = '',\n\t\t\t$tag = null,\n\t\t\t$aad = '',\n\t\t) {\n\t\t\t$r = cfw_openssl_crypt(\n\t\t\t\t'dec',\n\t\t\t\t$data,\n\t\t\t\t$cipher_algo,\n\t\t\t\t$passphrase,\n\t\t\t\t$options,\n\t\t\t\t$iv,\n\t\t\t\t$tag,\n\t\t\t\t$aad,\n\t\t\t\t$tag === null ? 16 : strlen((string) $tag),\n\t\t\t);\n\t\t\tif (!is_array($r) || ($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn base64_decode((string) ($r['b64'] ?? ''), true);\n\t\t}\n\n\t\t/**\n\t\t * @param string $data\n\t\t * The bytes to sign.\n\t\t * @param string|false|null $signature\n\t\t * Set to the raw signature.\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $private_key\n\t\t * The signing key.\n\t\t * @param int|string $algorithm\n\t\t * An OPENSSL_ALGO_* value or a digest name.\n\t\t */\n\t\tfunction openssl_sign($data, &$signature, $private_key, $algorithm = 1): bool\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'sign',\n\t\t\t\t'b64' => base64_encode((string) $data),\n\t\t\t\t'key' => cfw_openssl_pem($private_key, 'private'),\n\t\t\t\t'algo' => is_string($algorithm) ? $algorithm : (int) $algorithm,\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_sign(): ' . (string) ($r['error'] ?? 'failed'),\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\tcfw_openssl_degraded(\n\t\t\t\t\t'openssl signing',\n\t\t\t\t\t'a signature could not be produced: ' .\n\t\t\t\t\t\t(string) ($r['error'] ?? 'no reason given'),\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$signature = base64_decode((string) ($r['sigB64'] ?? ''), true);\n\t\t\treturn $signature !== false;\n\t\t}\n\n\t\t/**\n\t\t * Answers 1, 0 or -1, matching ext-openssl.\n\t\t *\n\t\t * -1 means the call itself failed -- an unreadable key, an unsupported digest -- and is NOT\n\t\t * the same as 0, which means the signature was read and did not match. A caller treating\n\t\t * -1 as \"invalid\" would report a broken key as a forged token.\n\t\t *\n\t\t * @param string $data\n\t\t * The signed bytes.\n\t\t * @param string $signature\n\t\t * The raw signature.\n\t\t * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array<int|string, string>|string $public_key\n\t\t * The verification key.\n\t\t * @param int|string $algorithm\n\t\t * An OPENSSL_ALGO_* value or a digest name.\n\t\t */\n\t\tfunction openssl_verify($data, $signature, $public_key, $algorithm = 1): int\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'verify',\n\t\t\t\t'b64' => base64_encode((string) $data),\n\t\t\t\t'sigB64' => base64_encode((string) $signature),\n\t\t\t\t'key' => cfw_openssl_pem($public_key, 'public'),\n\t\t\t\t'algo' => is_string($algorithm) ? $algorithm : (int) $algorithm,\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\tcfw_openssl_degraded(\n\t\t\t\t\t'openssl verification',\n\t\t\t\t\t'a signature could not be checked, so callers see -1 rather than a verdict: ' .\n\t\t\t\t\t\t(string) ($r['error'] ?? 'no reason given'),\n\t\t\t\t);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\treturn ($r['valid'] ?? false) === true ? 1 : 0;\n\t\t}\n\n\t\t/**\n\t\t * Turns a PEM, a certificate or a JWKS entry into a public key openssl_verify() accepts.\n\t\t *\n\t\t * THE MISSING STEP IN EVERY OIDC LIBRARY. A provider publishes a key SET, the library reads\n\t\t * the entry it needs and hands it here.\n\t\t *\n\t\t * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array<int|string, mixed>|string $public_key\n\t\t * A PEM, a certificate, a file:// path or a JWK array.\n\t\t *\n\t\t * @return OpenSSLAsymmetricKey|false\n\t\t * The public key, or FALSE.\n\t\t */\n\t\tfunction openssl_pkey_get_public($public_key)\n\t\t{\n\t\t\t$payload = ['op' => 'pkeyGetPublic'];\n\t\t\tif (is_array($public_key) && isset($public_key['kty'])) {\n\t\t\t\t$payload['jwk'] = $public_key;\n\t\t\t} else {\n\t\t\t\t$payload['key'] = cfw_openssl_pem($public_key, 'public');\n\t\t\t}\n\t\t\t$r = cfw_sign_call($payload);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_pkey_get_public(): ' . (string) ($r['error'] ?? 'failed'),\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn new OpenSSLAsymmetricKey((string) ($r['pem'] ?? ''));\n\t\t}\n\n\t\t/**\n\t\t * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array<int|string, mixed>|string $public_key\n\t\t * A PEM, a certificate, a file:// path or a JWK array.\n\t\t *\n\t\t * @return OpenSSLAsymmetricKey|false\n\t\t */\n\t\tfunction openssl_get_publickey($public_key)\n\t\t{\n\t\t\treturn openssl_pkey_get_public($public_key);\n\t\t}\n\n\t\t/**\n\t\t * Reads a private key, decrypting it with the passphrase when one was used to write it.\n\t\t *\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $private_key\n\t\t * A PEM, a key object or a file:// path.\n\t\t * @param string|null $passphrase\n\t\t * The passphrase the PEM was written with.\n\t\t *\n\t\t * @return OpenSSLAsymmetricKey|false\n\t\t * The key, or FALSE.\n\t\t */\n\t\tfunction openssl_pkey_get_private($private_key, $passphrase = null)\n\t\t{\n\t\t\t$payload = [\n\t\t\t\t'op' => 'pkeyGetPrivate',\n\t\t\t\t'key' => cfw_openssl_pem($private_key, 'private'),\n\t\t\t];\n\t\t\tif ($passphrase !== null && $passphrase !== '') {\n\t\t\t\t$payload['passphrase'] = (string) $passphrase;\n\t\t\t}\n\t\t\t$r = cfw_sign_call($payload);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn new OpenSSLAsymmetricKey(\n\t\t\t\t(string) ($r['publicPem'] ?? ''),\n\t\t\t\t(string) ($r['privatePem'] ?? ''),\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $private_key\n\t\t * A PEM, a key object or a file:// path.\n\t\t * @param string|null $passphrase\n\t\t * The passphrase the PEM was written with.\n\t\t *\n\t\t * @return OpenSSLAsymmetricKey|false\n\t\t */\n\t\tfunction openssl_get_privatekey($private_key, $passphrase = null)\n\t\t{\n\t\t\treturn openssl_pkey_get_private($private_key, $passphrase);\n\t\t}\n\n\t\t/**\n\t\t * What ext-openssl reports about a key: bits, the public PEM, the type and its parameters.\n\t\t *\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $key\n\t\t * The key to describe.\n\t\t *\n\t\t * @return array<string, mixed>|false\n\t\t * The details, or FALSE.\n\t\t */\n\t\tfunction openssl_pkey_get_details($key)\n\t\t{\n\t\t\t$pem = cfw_openssl_pem($key, 'private');\n\t\t\t$r = cfw_sign_call(['op' => 'pkeyDetails', 'key' => $pem]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$d = (array) ($r['details'] ?? []);\n\t\t\t$types = ['rsa' => 0, 'dsa' => 1, 'dh' => 2, 'ec' => 3];\n\t\t\t$out = [\n\t\t\t\t'bits' => (int) ($d['bits'] ?? 0),\n\t\t\t\t'key' => (string) ($d['publicPem'] ?? ''),\n\t\t\t\t'type' => $types[(string) ($d['keyType'] ?? '')] ?? -1,\n\t\t\t];\n\t\t\tforeach (['rsa', 'ec'] as $family) {\n\t\t\t\tif (isset($d[$family]) && is_array($d[$family])) {\n\t\t\t\t\t$params = [];\n\t\t\t\t\tforeach ($d[$family] as $k => $v) {\n\t\t\t\t\t\t$params[$k] = in_array($k, ['curve_name', 'curve_oid'], true)\n\t\t\t\t\t\t\t? (string) $v\n\t\t\t\t\t\t\t: base64_decode((string) $v, true);\n\t\t\t\t\t}\n\t\t\t\t\t$out[$family] = $params;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $out;\n\t\t}\n\n\t\t/**\n\t\t * A new RSA or EC key pair.\n\t\t *\n\t\t * @param array<string, mixed>|null $options\n\t\t * private_key_bits, private_key_type or curve_name.\n\t\t *\n\t\t * @return OpenSSLAsymmetricKey|false\n\t\t * The key, or FALSE.\n\t\t */\n\t\tfunction openssl_pkey_new($options = null)\n\t\t{\n\t\t\t$options = is_array($options) ? $options : [];\n\t\t\t$payload = ['op' => 'pkeyNew', 'bits' => (int) ($options['private_key_bits'] ?? 2048)];\n\t\t\tif (($options['private_key_type'] ?? 0) === 3 || isset($options['curve_name'])) {\n\t\t\t\t$payload['type'] = 'ec';\n\t\t\t\t$payload['curve'] = (string) ($options['curve_name'] ?? 'prime256v1');\n\t\t\t}\n\t\t\t$r = cfw_sign_call($payload);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_pkey_new(): ' . (string) ($r['error'] ?? 'failed'),\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn new OpenSSLAsymmetricKey(\n\t\t\t\t(string) ($r['publicPem'] ?? ''),\n\t\t\t\t(string) ($r['privatePem'] ?? ''),\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * Writes a private key out as PEM.\n\t\t *\n\t\t * PASSPHRASES ARE REFUSED rather than ignored. ext-openssl encrypts the output when one is\n\t\t * given, and answering with an UNENCRYPTED key to a caller who asked for an encrypted one\n\t\t * would hand them a secret they believe is protected.\n\t\t *\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $key\n\t\t * The key to export.\n\t\t * @param string|null $out\n\t\t * Set to the PEM.\n\t\t * @param string|null $passphrase\n\t\t * Refused when not empty.\n\t\t *\n\t\t * @return bool\n\t\t * TRUE on success.\n\t\t */\n\t\tfunction openssl_pkey_export($key, &$out, $passphrase = null): bool\n\t\t{\n\t\t\tif ($passphrase !== null && $passphrase !== '') {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_pkey_export(): a passphrase is not supported here',\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$r = cfw_sign_call(['op' => 'pkeyExport', 'key' => cfw_openssl_pem($key, 'private')]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_pkey_export(): ' . (string) ($r['error'] ?? 'failed'),\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$out = (string) ($r['pem'] ?? '');\n\t\t\treturn $out !== '';\n\t\t}\n\n\t\t/**\n\t\t * ECDH: the shared secret between a private key and a peer public key.\n\t\t *\n\t\t * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array<int|string, string>|string $public_key\n\t\t * The peer's public key.\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $private_key\n\t\t * This side's private key.\n\t\t * @param int $key_length\n\t\t * Truncate the secret to this many bytes, or 0 for all of it.\n\t\t *\n\t\t * @return string|false\n\t\t * The secret, or FALSE.\n\t\t */\n\t\tfunction openssl_pkey_derive($public_key, $private_key, $key_length = 0)\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'derive',\n\t\t\t\t'peer' => cfw_openssl_pem($public_key, 'public'),\n\t\t\t\t'key' => cfw_openssl_pem($private_key, 'private'),\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$out = base64_decode((string) ($r['b64'] ?? ''), true);\n\t\t\treturn $out !== false && $key_length > 0 ? substr($out, 0, (int) $key_length) : $out;\n\t\t}\n\n\t\t/** @param OpenSSLAsymmetricKey $key */\n\t\tfunction openssl_pkey_free($key): void {}\n\t\t/** @param OpenSSLAsymmetricKey $key */\n\t\tfunction openssl_free_key($key): void {}\n\t\t/** @param OpenSSLCertificate $certificate */\n\t\tfunction openssl_x509_free($certificate): void {}\n\n\t\t/**\n\t\t * RSA sign-with-private, which is what a legacy licence check or an older SSO handshake uses.\n\t\t *\n\t\t * @param string $data\n\t\t * The bytes to encrypt.\n\t\t * @param string|false|null $encrypted_data\n\t\t * Set to the result.\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $private_key\n\t\t * The key.\n\t\t * @param int $padding\n\t\t * An OPENSSL_*_PADDING value; ignored here.\n\t\t *\n\t\t * @return bool\n\t\t * TRUE on success.\n\t\t */\n\t\tfunction openssl_private_encrypt($data, &$encrypted_data, $private_key, $padding = 1): bool\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'privateEncrypt',\n\t\t\t\t'b64' => base64_encode((string) $data),\n\t\t\t\t'key' => cfw_openssl_pem($private_key, 'private'),\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_private_encrypt(): ' . (string) ($r['error'] ?? 'failed'),\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$encrypted_data = base64_decode((string) ($r['b64'] ?? ''), true);\n\t\t\treturn $encrypted_data !== false;\n\t\t}\n\n\t\t/**\n\t\t * The other half of the pair above.\n\t\t *\n\t\t * @param string $data\n\t\t * The bytes to decrypt.\n\t\t * @param string|false|null $decrypted_data\n\t\t * Set to the result.\n\t\t * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array<int|string, string>|string $public_key\n\t\t * The key.\n\t\t * @param int $padding\n\t\t * An OPENSSL_*_PADDING value; ignored here.\n\t\t *\n\t\t * @return bool\n\t\t * TRUE on success.\n\t\t */\n\t\tfunction openssl_public_decrypt($data, &$decrypted_data, $public_key, $padding = 1): bool\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'publicDecrypt',\n\t\t\t\t'b64' => base64_encode((string) $data),\n\t\t\t\t'key' => cfw_openssl_pem($public_key, 'public'),\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\ttrigger_error(\n\t\t\t\t\t'openssl_public_decrypt(): ' . (string) ($r['error'] ?? 'failed'),\n\t\t\t\t\tE_USER_WARNING,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$decrypted_data = base64_decode((string) ($r['b64'] ?? ''), true);\n\t\t\treturn $decrypted_data !== false;\n\t\t}\n\n\t\t/**\n\t\t * Encrypt to a public key, PKCS#1 v1.5 or OAEP, which is how XML encryption wraps its key.\n\t\t *\n\t\t * @param string $data\n\t\t * The bytes to encrypt.\n\t\t * @param string|false|null $encrypted_data\n\t\t * Set to the result.\n\t\t * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array<int|string, string>|string $public_key\n\t\t * The key.\n\t\t * @param int $padding\n\t\t * OPENSSL_PKCS1_PADDING or OPENSSL_PKCS1_OAEP_PADDING.\n\t\t *\n\t\t * @return bool\n\t\t * TRUE on success.\n\t\t */\n\t\tfunction openssl_public_encrypt($data, &$encrypted_data, $public_key, $padding = 1): bool\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'publicEncrypt',\n\t\t\t\t'b64' => base64_encode((string) $data),\n\t\t\t\t'key' => cfw_openssl_pem($public_key, 'public'),\n\t\t\t\t'pad' => (int) $padding,\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$encrypted_data = base64_decode((string) ($r['b64'] ?? ''), true);\n\t\t\treturn $encrypted_data !== false;\n\t\t}\n\n\t\t/**\n\t\t * @param string $data\n\t\t * The bytes to decrypt.\n\t\t * @param string|false|null $decrypted_data\n\t\t * Set to the result.\n\t\t * @param OpenSSLAsymmetricKey|array<int|string, string>|string $private_key\n\t\t * The key.\n\t\t * @param int $padding\n\t\t * OPENSSL_PKCS1_PADDING or OPENSSL_PKCS1_OAEP_PADDING.\n\t\t *\n\t\t * @return bool\n\t\t */\n\t\tfunction openssl_private_decrypt($data, &$decrypted_data, $private_key, $padding = 1): bool\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'privateDecrypt',\n\t\t\t\t'b64' => base64_encode((string) $data),\n\t\t\t\t'key' => cfw_openssl_pem($private_key, 'private'),\n\t\t\t\t'pad' => (int) $padding,\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$decrypted_data = base64_decode((string) ($r['b64'] ?? ''), true);\n\t\t\treturn $decrypted_data !== false;\n\t\t}\n\n\t\t/**\n\t\t * Reads a certificate from PEM, a file:// path or another certificate.\n\t\t *\n\t\t * @param OpenSSLCertificate|string $certificate\n\t\t * A PEM, a file:// path or a certificate object.\n\t\t *\n\t\t * @return OpenSSLCertificate|false\n\t\t * The certificate, or FALSE.\n\t\t */\n\t\tfunction openssl_x509_read($certificate)\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'x509Export',\n\t\t\t\t'key' => cfw_openssl_pem($certificate, 'public'),\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn new OpenSSLCertificate((string) ($r['pem'] ?? ''));\n\t\t}\n\n\t\t/**\n\t\t * @param OpenSSLCertificate|string $certificate\n\t\t * A PEM, a file:// path or a certificate object.\n\t\t * @param string|null $output\n\t\t * Set to the PEM.\n\t\t * @param bool $no_text\n\t\t * Ignored.\n\t\t */\n\t\tfunction openssl_x509_export($certificate, &$output, $no_text = true): bool\n\t\t{\n\t\t\t$cert = openssl_x509_read($certificate);\n\t\t\tif ($cert === false) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$output = $cert->cfwPem;\n\t\t\treturn true;\n\t\t}\n\n\t\t/**\n\t\t * @param OpenSSLCertificate|string $certificate\n\t\t * A PEM, a file:// path or a certificate object.\n\t\t * @param string $digest_algo\n\t\t * A digest name.\n\t\t * @param bool $binary\n\t\t * Return raw bytes instead of hex.\n\t\t *\n\t\t * @return string|false\n\t\t */\n\t\tfunction openssl_x509_fingerprint($certificate, $digest_algo = 'sha1', $binary = false)\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'x509Fingerprint',\n\t\t\t\t'key' => cfw_openssl_pem($certificate, 'public'),\n\t\t\t\t'digest' => strtolower((string) $digest_algo),\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$hex = (string) ($r['hex'] ?? '');\n\t\t\treturn $binary ? hex2bin($hex) : $hex;\n\t\t}\n\n\t\t/**\n\t\t * The fields of a certificate that node:crypto exposes, under ext-openssl's key names.\n\t\t *\n\t\t * @param OpenSSLCertificate|string $certificate\n\t\t * A PEM, a file:// path or a certificate object.\n\t\t * @param bool $short_names\n\t\t * Ignored.\n\t\t *\n\t\t * @return array<string, mixed>|false\n\t\t * The parsed certificate, or FALSE.\n\t\t */\n\t\tfunction openssl_x509_parse($certificate, $short_names = true)\n\t\t{\n\t\t\t$r = cfw_sign_call([\n\t\t\t\t'op' => 'x509Parse',\n\t\t\t\t'key' => cfw_openssl_pem($certificate, 'public'),\n\t\t\t]);\n\t\t\tif (($r['ok'] ?? false) !== true) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn (array) ($r['parsed'] ?? []);\n\t\t}\n\n\t\t/**\n\t\t * Purpose checking needs a trust store and purpose table this runtime does not carry.\n\t\t *\n\t\t * @param OpenSSLCertificate|string $certificate\n\t\t * The certificate to check.\n\t\t * @param int $purpose\n\t\t * An X509_PURPOSE_* value.\n\t\t * @param array<int, string> $ca_info\n\t\t * Trusted CA locations.\n\t\t * @param string|null $untrusted_certificates_file\n\t\t * Intermediate certificates.\n\t\t *\n\t\t * @return int\n\t\t * -1, which ext-openssl uses for \"could not be determined\".\n\t\t */\n\t\tfunction openssl_x509_checkpurpose(\n\t\t\t$certificate,\n\t\t\t$purpose,\n\t\t\t$ca_info = [],\n\t\t\t$untrusted_certificates_file = null,\n\t\t): int {\n\t\t\tcfw_openssl_degraded(\n\t\t\t\t'openssl_x509_checkpurpose',\n\t\t\t\t'there is no trust store or purpose table here, so the answer is -1 (undetermined)',\n\t\t\t);\n\t\t\treturn -1;\n\t\t}\n\t}\n}\n"