Openssl spki new: примеры (PHP)

Работа с подписанными открытыми ключами через openssl_spki_new
Раздел: Шифрование (OpenSSL)
openssl_spki_new(OpenSSLAsymmetricKey $private_key, string $challenge, int $digest_algo = OPENSSL_ALGO_MD5): string|false

Функция openssl_spki_new

Описание и назначение

openssl_spki_new создает подписанный открытый ключ и запрос (SPKAC). Эта функция генерирует новую пару открытого и закрытого ключей, подписывает открытый ключ с использованием закрытого и возвращает закодированную строку в формате SPKAC.

Основное применение

Функция применяется в веб-криптографии, например для генерации ключей непосредственно в браузере через элемент <keygen> (устаревший) или Web Crypto API, с последующей передачей на сервер для обработки и верификации.

Аргументы функции
  • private_key (resource) — ресурс закрытого ключа, созданный с помощью openssl_pkey_new().
  • challenge (string) — строка челленджа (обычно случайные данные), используемая для подписи. Может быть пустой строкой.
  • digest_algo (int) — алгоритм хеширования. По умолчанию OPENSSL_ALGO_MD5 (устаревший). Рекомендуется использовать OPENSSL_ALGO_SHA256 или другие современные алгоритмы.

Простые примеры использования

Базовый пример с SHA256
<?php
$privateKey = openssl_pkey_new([
    'private_key_bits' => 2048,
    'private_key_type' => OPENSSL_KEYTYPE_RSA,
]);

$spkac = openssl_spki_new($privateKey, 'random_challenge', OPENSSL_ALGO_SHA256);
echo $spkac;
?>
SPKAC=MII... (длинная закодированная строка)
Пример с пустым челленджем
<?php
$config = [
    'digest_alg' => 'sha512',
    'private_key_bits' => 4096,
    'private_key_type' => OPENSSL_KEYTYPE_RSA,
];

$pkey = openssl_pkey_new($config);
$spkac = openssl_spki_new($pkey, '', OPENSSL_ALGO_SHA512);
var_dump(strlen($spkac) > 100);
?>
bool(true)

Похожие функции в PHP

Создает запрос на подпись сертификата (CSR). Более сложная структура, предназначенная для инфраструктуры открытых ключей (PKI). Используется для получения сертификатов от центра сертификации.

Генерирует новую пару ключей. Является основой для openssl_spki_new, но не создает подписанный запрос.

Выбор функции

openssl_spki_new применяется для простых сценариев веб-аутентификации. openssl_csr_new используется при работе с полными SSL/TLS сертификатами.

Типичные ошибки

Неверный ресурс ключа
<?php
$spkac = openssl_spki_new('not_a_resource', 'test', OPENSSL_ALGO_SHA256);
var_dump($spkac);
?>
bool(false)
// Также генерируется предупреждение: openssl_spki_new(): supplied key param cannot be coerced into a private key
Использование устаревшего алгоритма
<?php
$pkey = openssl_pkey_new(['private_key_bits' => 2048]);
$spkac = openssl_spki_new($pkey, 'test', OPENSSL_ALGO_MD5);
// MD5 считается криптографически небезопасным
echo $spkac !== false ? 'Успешно, но небезопасно' : 'Ошибка';
?>
Успешно, но небезопасно
Недостаточные права доступа
<?php
// При отсутствии настроек openssl.cnf может возникнуть ошибка
$pkey = @openssl_pkey_new();
if ($pkey === false) {
    echo 'Не удалось сгенерировать ключ. Проверьте конфигурацию OpenSSL.';
}
?>
Не удалось сгенерировать ключ. Проверьте конфигурацию OpenSSL.

Изменения в версиях PHP

PHP 8.0

Тип возвращаемого значения для ошибок изменен с false на null в некоторых случаях, хотя документация указывает false. Рекомендуется строгая проверка на идентичность (===).

PHP 7.4

Добавлена поддержка алгоритма SHA256 и более новых в качестве рекомендуемых значений по умолчанию вместо MD5.

Предупреждения

В PHP 8.0 усилены строгие типы, поэтому передача неверного типа аргумента вызывает TypeError вместо предупреждения.

Расширенные примеры

Полный цикл: генерация, проверка и извлечение
Пример php
<?php
// Генерация
$pkey = openssl_pkey_new([
    'private_key_bits' => 2048,
    'private_key_type' => OPENSSL_KEYTYPE_RSA,
]);
$challenge = base64_encode(random_bytes(16));
$spkac = openssl_spki_new($pkey, $challenge, OPENSSL_ALGO_SHA384);

// Проверка
$verify = openssl_spki_verify(preg_replace('/SPKAC=/', '', $spkac));
var_dump($verify);

// Извлечение открытого ключа
$pubKey = openssl_spki_export(preg_replace('/SPKAC=/', '', $spkac));
echo substr($pubKey, 0, 50) . "...\n";

// Извлечение челленджа
$extractedChallenge = openssl_spki_export_challenge(preg_replace('/SPKAC=/', '', $spkac));
echo $extractedChallenge === $challenge ? 'Челлендж совпадает' : 'Не совпадает';
?>
bool(true)
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
Челлендж совпадает
Интеграция с HTML-формой (исторический пример)
Пример php
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['spkac'])) {
    $spkac = $_POST['spkac'];
    if (openssl_spki_verify(preg_replace('/SPKAC=/', '', $spkac))) {
        echo '<div class="fw-bold">SPKAC верифицирован успешно</div>';
    }
}
?>
<!-- Устаревший элемент keygen -->
<form method="post">
  <keygen name="spkac" challenge="random123" keytype="RSA">
  <input type="submit">
</form>
Генерация с использованием разных типов ключей
Пример php
<?php
// Генерация EC-ключа (требует PHP 7.1+)
$ecKey = openssl_pkey_new([
    'private_key_type' => OPENSSL_KEYTYPE_EC,
    'curve_name' => 'prime256v1',
]);

if ($ecKey) {
    $spkacEc = openssl_spki_new($ecKey, 'ec_challenge', OPENSSL_ALGO_SHA256);
    var_dump($spkacEc !== false);
}
?>
bool(true)

Альтернативы в других языках

JavaScript (Web Crypto API)
// Генерация ключей и экспорт в формате SPKI
window.crypto.subtle.generateKey(
  {
    name: "RSASSA-PKCS1-v1_5",
    modulusLength: 2048,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256",
  },
  true,
  ["sign", "verify"]
).then(keyPair => {
  return window.crypto.subtle.exportKey("spki", keyPair.publicKey);
}).then(spki => {
  console.log(btoa(String.fromCharCode(...new Uint8Array(spki))));
});
MIIBIjANBgkq... (Base64 SPKI)
Python (cryptography)
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend

private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

public_key = private_key.public_key()
spki = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)
print(spki.decode())
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
Отличия

Python и JavaScript работают с форматом SPKI, а не SPKAC. SPKAC включает подпись и челлендж, что делает его уникальным форматом для запросов.

PHP openssl_spki_new function comments

En
Openssl spki new Generate a new signed public key and challenge