Skip to content

Commit e0679f3

Browse files
committed
Introduce new serial_hex parameter to openssl_csr_sign
Co-authored-by: Florian Sowade <[email protected]> Closes GH-13023 Closes GH-9851
1 parent bb1109d commit e0679f3

File tree

6 files changed

+102
-8
lines changed

6 files changed

+102
-8
lines changed

NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ OpenSSL:
4949
(Jakub Zelenka)
5050
. Implement request #48520 (openssl_csr_new - allow multiple values in DN).
5151
(Jakub Zelenka)
52+
. Introduced new serial_hex parameter to openssl_csr_sign. (Jakub Zelenka)
5253

5354
PDO:
5455
. Fixed setAttribute and getAttribute (SakiTakamachi)

UPGRADING

+2
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ PHP 8.4 UPGRADE NOTES
231231
instead of subject DN which was incorrectly done previously.
232232
. The dn parameter in openssl_csr_new allows setting array of values for
233233
a single entry.
234+
. New serial_hex parameter added to openssl_csr_sign to allow setting serial
235+
number in the hexadecimal format.
234236

235237
- PDO:
236238
. getAttribute, enabled to get the value of ATTR_STRINGIFY_FETCHES.

ext/openssl/openssl.c

+31-6
Original file line numberDiff line numberDiff line change
@@ -3189,6 +3189,12 @@ PHP_FUNCTION(openssl_csr_export)
31893189
}
31903190
/* }}} */
31913191

3192+
#if PHP_OPENSSL_API_VERSION >= 0x10100 && !defined (LIBRESSL_VERSION_NUMBER)
3193+
#define PHP_OPENSSL_ASN1_INTEGER_set ASN1_INTEGER_set_int64
3194+
#else
3195+
#define PHP_OPENSSL_ASN1_INTEGER_set ASN1_INTEGER_set
3196+
#endif
3197+
31923198
/* {{{ Signs a cert with another CERT */
31933199
PHP_FUNCTION(openssl_csr_sign)
31943200
{
@@ -3202,20 +3208,22 @@ PHP_FUNCTION(openssl_csr_sign)
32023208
zval *zpkey, *args = NULL;
32033209
zend_long num_days;
32043210
zend_long serial = Z_L(0);
3211+
zend_string *serial_hex = NULL;
32053212
X509 *cert = NULL, *new_cert = NULL;
32063213
EVP_PKEY * key = NULL, *priv_key = NULL;
32073214
int i;
32083215
bool new_cert_used = false;
32093216
struct php_x509_request req;
32103217

3211-
ZEND_PARSE_PARAMETERS_START(4, 6)
3218+
ZEND_PARSE_PARAMETERS_START(4, 7)
32123219
Z_PARAM_OBJ_OF_CLASS_OR_STR(csr_obj, php_openssl_request_ce, csr_str)
32133220
Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(cert_obj, php_openssl_certificate_ce, cert_str)
32143221
Z_PARAM_ZVAL(zpkey)
32153222
Z_PARAM_LONG(num_days)
32163223
Z_PARAM_OPTIONAL
32173224
Z_PARAM_ARRAY_OR_NULL(args)
32183225
Z_PARAM_LONG(serial)
3226+
Z_PARAM_STR_OR_NULL(serial_hex)
32193227
ZEND_PARSE_PARAMETERS_END();
32203228

32213229
RETVAL_FALSE;
@@ -3284,11 +3292,28 @@ PHP_FUNCTION(openssl_csr_sign)
32843292
goto cleanup;
32853293
}
32863294

3287-
#if PHP_OPENSSL_API_VERSION >= 0x10100 && !defined (LIBRESSL_VERSION_NUMBER)
3288-
ASN1_INTEGER_set_int64(X509_get_serialNumber(new_cert), serial);
3289-
#else
3290-
ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
3291-
#endif
3295+
if (serial_hex != NULL) {
3296+
char buffer[256];
3297+
if (ZSTR_LEN(serial_hex) > 200) {
3298+
php_error_docref(NULL, E_WARNING, "Error parsing serial number because it is too long");
3299+
goto cleanup;
3300+
}
3301+
BIO *in = BIO_new_mem_buf(ZSTR_VAL(serial_hex), ZSTR_LEN(serial_hex));
3302+
if (in == NULL) {
3303+
php_openssl_store_errors();
3304+
php_error_docref(NULL, E_WARNING, "Error parsing serial number because memory allocation failed");
3305+
goto cleanup;
3306+
}
3307+
int success = a2i_ASN1_INTEGER(in, X509_get_serialNumber(new_cert), buffer, sizeof(buffer));
3308+
BIO_free(in);
3309+
if (!success) {
3310+
php_openssl_store_errors();
3311+
php_error_docref(NULL, E_WARNING, "Error parsing serial number");
3312+
goto cleanup;
3313+
}
3314+
} else {
3315+
PHP_OPENSSL_ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
3316+
}
32923317

32933318
X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));
32943319

ext/openssl/openssl.stub.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ function openssl_csr_export(OpenSSLCertificateSigningRequest|string $csr, &$outp
440440
/**
441441
* @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key
442442
*/
443-
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 {}
443+
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 {}
444444

445445
/**
446446
* @param OpenSSLAsymmetricKey $private_key

ext/openssl/openssl_arginfo.h

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
openssl_csr_sign() with serial and serial_hex parameters
3+
--EXTENSIONS--
4+
openssl
5+
--FILE--
6+
<?php
7+
$config = __DIR__ . DIRECTORY_SEPARATOR . 'openssl.cnf';
8+
$config_arg = array('config' => $config);
9+
10+
$dn = array(
11+
"countryName" => "BR",
12+
"stateOrProvinceName" => "Rio Grande do Sul",
13+
"localityName" => "Porto Alegre",
14+
"commonName" => "Henrique do N. Angelo",
15+
"emailAddress" => "[email protected]"
16+
);
17+
18+
$args = array(
19+
"digest_alg" => "sha256",
20+
"private_key_bits" => 2048,
21+
"private_key_type" => OPENSSL_KEYTYPE_DSA,
22+
"encrypt_key" => true,
23+
"config" => $config
24+
);
25+
26+
$privkey = openssl_pkey_new($config_arg);
27+
$csr = openssl_csr_new($dn, $privkey, $args);
28+
29+
var_dump($cert1 = openssl_csr_sign($csr, null, $privkey, 365, $args, 1234567));
30+
var_dump($cert2 = openssl_csr_sign($csr, null, $privkey, 365, $args, serial_hex: 'DEADBEEF'));
31+
var_dump($cert3 = openssl_csr_sign($csr, null, $privkey, 365, $args, 10, 'DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF'));
32+
33+
var_dump(openssl_csr_sign($csr, null, $privkey, 365, $args, 0, 'DEADBEEG'));
34+
var_dump(openssl_csr_sign($csr, null, $privkey, 365, $args, 0, '0xDEADBEEF'));
35+
var_dump(openssl_csr_sign($csr, null, $privkey, 365, $args, 0, str_repeat('FF', 500)));
36+
37+
var_dump(openssl_x509_parse($cert1)['serialNumber']);
38+
var_dump(openssl_x509_parse($cert1)['serialNumberHex']);
39+
var_dump(openssl_x509_parse($cert2)['serialNumber']);
40+
var_dump(openssl_x509_parse($cert2)['serialNumberHex']);
41+
var_dump(openssl_x509_parse($cert3)['serialNumber']);
42+
var_dump(openssl_x509_parse($cert3)['serialNumberHex']);
43+
?>
44+
--EXPECTF--
45+
object(OpenSSLCertificate)#%d (0) {
46+
}
47+
object(OpenSSLCertificate)#%d (0) {
48+
}
49+
object(OpenSSLCertificate)#%d (0) {
50+
}
51+
52+
Warning: openssl_csr_sign(): Error parsing serial number in %s on line %d
53+
bool(false)
54+
55+
Warning: openssl_csr_sign(): Error parsing serial number in %s on line %d
56+
bool(false)
57+
58+
Warning: openssl_csr_sign(): Error parsing serial number because it is too long in %s on line %d
59+
bool(false)
60+
string(7) "1234567"
61+
string(6) "12D687"
62+
string(10) "3735928559"
63+
string(8) "DEADBEEF"
64+
string(42) "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
65+
string(40) "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"

0 commit comments

Comments
 (0)