Skip to content

Commit

Permalink
Introduce new serial_hex parameter to openssl_csr_sign
Browse files Browse the repository at this point in the history
Co-authored-by: Florian Sowade <[email protected]>

Closes phpGH-13023
Closes phpGH-9851
  • Loading branch information
bukka committed Jan 5, 2024
1 parent bb1109d commit e0679f3
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 8 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ OpenSSL:
(Jakub Zelenka)
. Implement request #48520 (openssl_csr_new - allow multiple values in DN).
(Jakub Zelenka)
. Introduced new serial_hex parameter to openssl_csr_sign. (Jakub Zelenka)

PDO:
. Fixed setAttribute and getAttribute (SakiTakamachi)
Expand Down
2 changes: 2 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ PHP 8.4 UPGRADE NOTES
instead of subject DN which was incorrectly done previously.
. The dn parameter in openssl_csr_new allows setting array of values for
a single entry.
. New serial_hex parameter added to openssl_csr_sign to allow setting serial
number in the hexadecimal format.

- PDO:
. getAttribute, enabled to get the value of ATTR_STRINGIFY_FETCHES.
Expand Down
37 changes: 31 additions & 6 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3189,6 +3189,12 @@ PHP_FUNCTION(openssl_csr_export)
}
/* }}} */

#if PHP_OPENSSL_API_VERSION >= 0x10100 && !defined (LIBRESSL_VERSION_NUMBER)
#define PHP_OPENSSL_ASN1_INTEGER_set ASN1_INTEGER_set_int64
#else
#define PHP_OPENSSL_ASN1_INTEGER_set ASN1_INTEGER_set
#endif

/* {{{ Signs a cert with another CERT */
PHP_FUNCTION(openssl_csr_sign)
{
Expand All @@ -3202,20 +3208,22 @@ PHP_FUNCTION(openssl_csr_sign)
zval *zpkey, *args = NULL;
zend_long num_days;
zend_long serial = Z_L(0);
zend_string *serial_hex = NULL;
X509 *cert = NULL, *new_cert = NULL;
EVP_PKEY * key = NULL, *priv_key = NULL;
int i;
bool new_cert_used = false;
struct php_x509_request req;

ZEND_PARSE_PARAMETERS_START(4, 6)
ZEND_PARSE_PARAMETERS_START(4, 7)
Z_PARAM_OBJ_OF_CLASS_OR_STR(csr_obj, php_openssl_request_ce, csr_str)
Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(cert_obj, php_openssl_certificate_ce, cert_str)
Z_PARAM_ZVAL(zpkey)
Z_PARAM_LONG(num_days)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_OR_NULL(args)
Z_PARAM_LONG(serial)
Z_PARAM_STR_OR_NULL(serial_hex)
ZEND_PARSE_PARAMETERS_END();

RETVAL_FALSE;
Expand Down Expand Up @@ -3284,11 +3292,28 @@ PHP_FUNCTION(openssl_csr_sign)
goto cleanup;
}

#if PHP_OPENSSL_API_VERSION >= 0x10100 && !defined (LIBRESSL_VERSION_NUMBER)
ASN1_INTEGER_set_int64(X509_get_serialNumber(new_cert), serial);
#else
ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
#endif
if (serial_hex != NULL) {
char buffer[256];
if (ZSTR_LEN(serial_hex) > 200) {
php_error_docref(NULL, E_WARNING, "Error parsing serial number because it is too long");
goto cleanup;
}
BIO *in = BIO_new_mem_buf(ZSTR_VAL(serial_hex), ZSTR_LEN(serial_hex));
if (in == NULL) {
php_openssl_store_errors();
php_error_docref(NULL, E_WARNING, "Error parsing serial number because memory allocation failed");
goto cleanup;
}
int success = a2i_ASN1_INTEGER(in, X509_get_serialNumber(new_cert), buffer, sizeof(buffer));
BIO_free(in);
if (!success) {
php_openssl_store_errors();
php_error_docref(NULL, E_WARNING, "Error parsing serial number");
goto cleanup;
}
} else {
PHP_OPENSSL_ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
}

X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));

Expand Down
2 changes: 1 addition & 1 deletion ext/openssl/openssl.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ function openssl_csr_export(OpenSSLCertificateSigningRequest|string $csr, &$outp
/**
* @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key
*/
function openssl_csr_sign(OpenSSLCertificateSigningRequest|string $csr, OpenSSLCertificate|string|null $ca_certificate, #[\SensitiveParameter] $private_key, int $days, ?array $options = null, int $serial = 0): OpenSSLCertificate|false {}
function openssl_csr_sign(OpenSSLCertificateSigningRequest|string $csr, OpenSSLCertificate|string|null $ca_certificate, #[\SensitiveParameter] $private_key, int $days, ?array $options = null, int $serial = 0, ?string $serial_hex = null): OpenSSLCertificate|false {}

/**
* @param OpenSSLAsymmetricKey $private_key
Expand Down
3 changes: 2 additions & 1 deletion ext/openssl/openssl_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions ext/openssl/tests/openssl_csr_sign_with_serial_hex.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
--TEST--
openssl_csr_sign() with serial and serial_hex parameters
--EXTENSIONS--
openssl
--FILE--
<?php
$config = __DIR__ . DIRECTORY_SEPARATOR . 'openssl.cnf';
$config_arg = array('config' => $config);

$dn = array(
"countryName" => "BR",
"stateOrProvinceName" => "Rio Grande do Sul",
"localityName" => "Porto Alegre",
"commonName" => "Henrique do N. Angelo",
"emailAddress" => "[email protected]"
);

$args = array(
"digest_alg" => "sha256",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_DSA,
"encrypt_key" => true,
"config" => $config
);

$privkey = openssl_pkey_new($config_arg);
$csr = openssl_csr_new($dn, $privkey, $args);

var_dump($cert1 = openssl_csr_sign($csr, null, $privkey, 365, $args, 1234567));
var_dump($cert2 = openssl_csr_sign($csr, null, $privkey, 365, $args, serial_hex: 'DEADBEEF'));
var_dump($cert3 = openssl_csr_sign($csr, null, $privkey, 365, $args, 10, 'DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF'));

var_dump(openssl_csr_sign($csr, null, $privkey, 365, $args, 0, 'DEADBEEG'));
var_dump(openssl_csr_sign($csr, null, $privkey, 365, $args, 0, '0xDEADBEEF'));
var_dump(openssl_csr_sign($csr, null, $privkey, 365, $args, 0, str_repeat('FF', 500)));

var_dump(openssl_x509_parse($cert1)['serialNumber']);
var_dump(openssl_x509_parse($cert1)['serialNumberHex']);
var_dump(openssl_x509_parse($cert2)['serialNumber']);
var_dump(openssl_x509_parse($cert2)['serialNumberHex']);
var_dump(openssl_x509_parse($cert3)['serialNumber']);
var_dump(openssl_x509_parse($cert3)['serialNumberHex']);
?>
--EXPECTF--
object(OpenSSLCertificate)#%d (0) {
}
object(OpenSSLCertificate)#%d (0) {
}
object(OpenSSLCertificate)#%d (0) {
}

Warning: openssl_csr_sign(): Error parsing serial number in %s on line %d
bool(false)

Warning: openssl_csr_sign(): Error parsing serial number in %s on line %d
bool(false)

Warning: openssl_csr_sign(): Error parsing serial number because it is too long in %s on line %d
bool(false)
string(7) "1234567"
string(6) "12D687"
string(10) "3735928559"
string(8) "DEADBEEF"
string(42) "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
string(40) "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"

0 comments on commit e0679f3

Please sign in to comment.