From c20a0f7179245f8ac3b15b925f3489b3675dbcb2 Mon Sep 17 00:00:00 2001 From: Steve Wall Date: Thu, 2 Oct 2025 09:15:15 -0400 Subject: [PATCH 1/6] Add a function to parse a CSR and return the information as an array, similar to openssl_x509_parse(). --- ext/openssl/openssl.c | 179 ++++++++++++++++++ ext/openssl/openssl.stub.php | 2 + ext/openssl/openssl_arginfo.h | 4 + .../tests/openssl_csr_parse_basic.phpt | 83 ++++++++ ext/openssl/tests/parse.csr | 77 ++++++++ 5 files changed, 345 insertions(+) create mode 100644 ext/openssl/tests/openssl_csr_parse_basic.phpt create mode 100644 ext/openssl/tests/parse.csr diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 2c09b89e31200..942fc9ea42386 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1998,6 +1998,185 @@ PHP_FUNCTION(openssl_csr_get_public_key) } /* }}} */ +/* {{{ Returns an array of the fields/values of the Certificate Request */ +PHP_FUNCTION(openssl_csr_parse) +{ + X509_REQ * csr = NULL; + zend_object *csr_obj; + zend_string *csr_str; + int i, sig_nid; + bool useshortnames = 1; + zval subitem; + X509_EXTENSION *extension; + X509_NAME *subject_name; + char *csr_name; + char *extname; + BIO *bio_out; + BUF_MEM *bio_buf; + char buf[256]; + STACK_OF(X509_EXTENSION) *exts; + char *crit_name = NULL; + int crit_len = 0; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_OBJ_OF_CLASS_OR_STR(csr_obj, php_openssl_request_ce, csr_str) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(useshortnames) + ZEND_PARSE_PARAMETERS_END(); + + csr = php_openssl_csr_from_param(csr_obj, csr_str, 1); + if (csr == NULL) { + // TODO Add Warning? + RETURN_FALSE; + } + array_init(return_value); + + subject_name = X509_REQ_get_subject_name(csr); + csr_name = X509_NAME_oneline(subject_name, NULL, 0); + if (csr_name) { + add_assoc_string(return_value, "name", csr_name); + OPENSSL_free(csr_name); + } + + php_openssl_add_assoc_name_entry(return_value, "subject", subject_name, useshortnames); + /* hash as used in CA directories to lookup csr by subject name */ + { + char buf[32]; + snprintf(buf, sizeof(buf), "%08lx", X509_NAME_hash_ex(subject_name, NULL, NULL, NULL)); + add_assoc_string(return_value, "hash", buf); + } + + add_assoc_long(return_value, "version", X509_REQ_get_version(csr)); + + sig_nid = X509_REQ_get_signature_nid(csr); + add_assoc_string(return_value, "signatureTypeSN", (char*)OBJ_nid2sn(sig_nid)); + add_assoc_string(return_value, "signatureTypeLN", (char*)OBJ_nid2ln(sig_nid)); + add_assoc_long(return_value, "signatureTypeNID", sig_nid); + + array_init(&subitem); + int attrcnt = X509_REQ_get_attr_count(csr); + if (attrcnt > 0) { + for (i = 0; i < attrcnt; i++) { + X509_ATTRIBUTE *attr = X509_REQ_get_attr(csr,i); + char unknown[] = "Unknown"; + if (attr) { + char objbuf[80]; + /* Adapted from openssl's "req" app */ + ASN1_TYPE *at; + ASN1_BIT_STRING *bs = NULL; + ASN1_OBJECT *aobj; + int j, type = 0, count = 1, ii = 0; + + aobj = X509_ATTRIBUTE_get0_object(attr); + if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) + continue; + if ((j = i2t_ASN1_OBJECT(objbuf, sizeof(objbuf), aobj)) > 0) { + ii = 0; + count = X509_ATTRIBUTE_count(attr); + if (count == 0) { + RETURN_FALSE; + } +get_next: + at = X509_ATTRIBUTE_get0_type(attr, ii); + type = at->type; + bs = at->value.asn1_string; + } else { + strcpy(objbuf, unknown); + } + switch (type) { + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_NUMERICSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_IA5STRING: + add_assoc_stringl(&subitem, objbuf, bs->data, bs->length); + break; + default: + add_assoc_stringl(&subitem, objbuf, unknown, sizeof(unknown)); + break; + } + if (++ii < count) + goto get_next; + + } + } + add_assoc_zval(return_value, "attributes", &subitem); + } + + array_init(&subitem); + exts = X509_REQ_get_extensions(csr); + if (exts) { + int count = sk_X509_EXTENSION_num(exts); + for (i = 0; i < count; i++) { + int nid; + extension = sk_X509_EXTENSION_value(exts, i); + nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension)); + if (nid != NID_undef) { + extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension))); + } else { + OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1); + extname = buf; + } + if (X509_EXTENSION_get_critical(extension)) { + int new_len = strlen(extname) + 10; + if (new_len > crit_len) { + if (crit_name) { + efree(crit_name); + } + crit_len = new_len; + crit_name = emalloc(crit_len); + } + if (crit_name) { + strcpy(crit_name, extname); + strcat(crit_name, ":critical"); + add_assoc_bool(&subitem, crit_name, 1); + } + } + bio_out = BIO_new(BIO_s_mem()); + if (bio_out == NULL) { + php_openssl_store_errors(); + goto err_subitem; + } + if (nid == NID_subject_alt_name) { + if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) { + BIO_get_mem_ptr(bio_out, &bio_buf); + add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length); + } else { + BIO_free(bio_out); + goto err_subitem; + } + } + else if (X509V3_EXT_print(bio_out, extension, 0, 0)) { + BIO_get_mem_ptr(bio_out, &bio_buf); + add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length); + } else { + php_openssl_add_assoc_asn1_string(&subitem, extname, X509_EXTENSION_get_data(extension)); + } + BIO_free(bio_out); + } + add_assoc_zval(return_value, "extensions", &subitem); + if (crit_name) { + efree(crit_name); + } + } + if (csr) { + X509_REQ_free(csr); + } + return; + +err_subitem: + zval_ptr_dtor(&subitem); + if (crit_name) { + efree(crit_name); + } + zend_array_destroy(Z_ARR_P(return_value)); + if (csr) { + X509_REQ_free(csr); + } + RETURN_FALSE; +} +/* }}} */ + /* }}} */ /* {{{ EVP Public/Private key functions */ diff --git a/ext/openssl/openssl.stub.php b/ext/openssl/openssl.stub.php index 94902a4acf0da..04a13d177f020 100644 --- a/ext/openssl/openssl.stub.php +++ b/ext/openssl/openssl.stub.php @@ -501,6 +501,8 @@ function openssl_csr_get_subject(OpenSSLCertificateSigningRequest|string $csr, b function openssl_csr_get_public_key(OpenSSLCertificateSigningRequest|string $csr, bool $short_names = true): OpenSSLAsymmetricKey|false {} +function openssl_csr_parse(OpenSSLCertificateSigningRequest|string $csr, bool $short_names = true): array|false {} + function openssl_pkey_new(?array $options = null): OpenSSLAsymmetricKey|false {} /** diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index 796582c185bb6..97a9c954a689e 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -110,6 +110,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_openssl_csr_get_public_key, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, short_names, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() +#define arginfo_openssl_csr_parse arginfo_openssl_csr_get_subject + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_openssl_pkey_new, 0, 0, OpenSSLAsymmetricKey, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() @@ -424,6 +426,7 @@ ZEND_FUNCTION(openssl_csr_sign); ZEND_FUNCTION(openssl_csr_new); ZEND_FUNCTION(openssl_csr_get_subject); ZEND_FUNCTION(openssl_csr_get_public_key); +ZEND_FUNCTION(openssl_csr_parse); ZEND_FUNCTION(openssl_pkey_new); ZEND_FUNCTION(openssl_pkey_export_to_file); ZEND_FUNCTION(openssl_pkey_export); @@ -493,6 +496,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(openssl_csr_new, arginfo_openssl_csr_new) ZEND_FE(openssl_csr_get_subject, arginfo_openssl_csr_get_subject) ZEND_FE(openssl_csr_get_public_key, arginfo_openssl_csr_get_public_key) + ZEND_FE(openssl_csr_parse, arginfo_openssl_csr_parse) ZEND_FE(openssl_pkey_new, arginfo_openssl_pkey_new) ZEND_FE(openssl_pkey_export_to_file, arginfo_openssl_pkey_export_to_file) ZEND_FE(openssl_pkey_export, arginfo_openssl_pkey_export) diff --git a/ext/openssl/tests/openssl_csr_parse_basic.phpt b/ext/openssl/tests/openssl_csr_parse_basic.phpt new file mode 100644 index 0000000000000..4f02859d18835 --- /dev/null +++ b/ext/openssl/tests/openssl_csr_parse_basic.phpt @@ -0,0 +1,83 @@ +--TEST-- +openssl_csr_parse() tests +--EXTENSIONS-- +openssl +--SKIPIF-- += 0x30200000) die('skip For OpenSSL < 3.2'); +?> +--FILE-- + +--EXPECTF-- +bool(true) +array(8) { + ["name"]=> + string(71) "/C=UK/ST=England/L=London/CN=test.php.net/emailAddress=test.php@php.net" + ["subject"]=> + array(5) { + ["C"]=> + string(2) "UK" + ["ST"]=> + string(7) "England" + ["L"]=> + string(6) "London" + ["CN"]=> + string(12) "test.php.net" + ["emailAddress"]=> + string(16) "test.php@php.net" + } + ["hash"]=> + string(8) "b21872c1" + ["version"]=> + int(0) + ["signatureTypeSN"]=> + string(10) "RSA-SHA256" + ["signatureTypeLN"]=> + string(23) "sha256WithRSAEncryption" + ["signatureTypeNID"]=> + int(668) + ["extensions"]=> + array(1) { + ["basicConstraints"]=> + string(8) "CA:FALSE" + } +} +array(8) { + ["name"]=> + string(71) "/C=UK/ST=England/L=London/CN=test.php.net/emailAddress=test.php@php.net" + ["subject"]=> + array(5) { + ["countryName"]=> + string(2) "UK" + ["stateOrProvinceName"]=> + string(7) "England" + ["localityName"]=> + string(6) "London" + ["commonName"]=> + string(12) "test.php.net" + ["emailAddress"]=> + string(16) "test.php@php.net" + } + ["hash"]=> + string(8) "b21872c1" + ["version"]=> + int(0) + ["signatureTypeSN"]=> + string(10) "RSA-SHA256" + ["signatureTypeLN"]=> + string(23) "sha256WithRSAEncryption" + ["signatureTypeNID"]=> + int(668) + ["extensions"]=> + array(1) { + ["basicConstraints"]=> + string(8) "CA:FALSE" + } +} diff --git a/ext/openssl/tests/parse.csr b/ext/openssl/tests/parse.csr new file mode 100644 index 0000000000000..44e9481b3fdb9 --- /dev/null +++ b/ext/openssl/tests/parse.csr @@ -0,0 +1,77 @@ +Certificate Request: + Data: + Version: 1 (0x0) + Subject: C = UK, ST = England, L = London, CN = test.php.net, emailAddress = test.php@php.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ad:b5:26:55:6d:58:fa:b2:73:65:10:b7:0d:80: + 74:91:d2:20:be:4e:cc:01:d6:b2:ef:cc:9b:18:f3: + c3:85:59:5b:01:be:02:8d:66:da:3e:ce:27:c9:40: + 93:12:df:4a:54:6d:07:ee:95:c7:c4:36:d6:4a:c0: + b6:f7:be:33:76:fa:a5:3f:42:f6:a2:9d:7f:33:64: + ad:79:37:06:08:13:9d:c0:61:f6:8c:e4:55:01:92: + fc:fd:66:d3:39:ff:48:a4:a0:0c:ef:ba:0d:d7:8b: + 1c:b3:23:a5:40:12:6a:86:1f:b1:ac:b8:3c:92:c0: + 76:74:ea:2c:e7:8c:83:aa:8d:13:ab:b4:79:b6:57: + 55:f9:a9:4a:65:75:a5:26:7a:91:09:f1:6e:c6:fa: + ad:7d:62:39:9c:64:c0:79:d5:59:86:f8:d0:7c:b4: + 10:82:e8:df:5c:7a:05:5a:81:9b:5e:7d:9b:bb:37: + f0:28:62:44:7a:a5:8f:6d:03:99:17:f1:5e:38:93: + e5:80:e0:61:84:36:f7:04:01:4d:54:2b:4c:de:4e: + f5:45:b9:63:e7:8a:4d:77:7c:af:ab:5e:76:c6:c8: + 05:77:4a:37:b3:5e:5f:b9:2c:19:81:ea:d4:8d:e1: + 2e:c3:fc:13:2b:d9:3b:bf:2a:7e:32:b2:10:1d:09: + 8f:75 + Exponent: 65537 (0x10001) + Attributes: + streetAddress : + facsimileTelephoneNumber : + postalCode :N11 + telephoneNumber :012345678 + name :Organisation + 1.3.6.1.4.1.11278.1150.2.1:11112222 + 1.3.6.1.4.1.11278.1150.2.2:12345678 + emailAddress :info@example.com + Requested Extensions: + X509v3 Basic Constraints: + CA:FALSE + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 0a:0f:23:fb:16:63:44:0a:3c:c1:01:b9:1a:7a:30:77:2f:5a: + 04:84:c7:09:24:41:f4:49:41:99:58:75:ea:6e:e9:3c:34:89: + 9c:18:45:33:91:e2:c1:27:57:3f:79:aa:ca:d6:a8:7a:7a:42: + 45:f1:74:51:bd:14:f1:e2:e0:de:ba:39:7d:97:6f:94:ed:1e: + 00:c6:33:1a:c9:4f:06:c7:fb:b5:5d:b0:98:97:2e:45:9b:78: + bb:a8:cc:ab:fc:06:ca:e1:2d:16:22:66:49:7e:55:62:2b:37: + 23:9c:2b:b6:a8:da:c0:fe:0f:76:24:08:10:38:24:ae:0e:16: + 17:e1:c5:8e:37:0f:6b:26:7b:b6:84:41:58:eb:4b:e5:2f:12: + 3b:88:00:b3:74:00:fe:a0:3b:60:0c:89:43:83:3c:1a:e3:b0: + f2:37:36:93:78:d1:55:2f:55:4f:87:b2:9d:53:96:ab:ed:87: + f0:18:01:2b:86:4f:6c:ad:33:96:1d:71:29:bb:27:06:86:03: + 02:20:3a:ff:17:3d:44:06:7a:6e:76:c8:c1:2f:cf:24:91:0b: + 86:72:4d:d7:5f:89:90:24:79:32:e6:6e:1f:92:31:56:c7:5d: + 73:a4:51:e1:33:f9:fb:e6:43:82:fe:b1:cd:d1:13:cb:be:33: + c8:37:d4:b3 +-----BEGIN CERTIFICATE REQUEST----- +MIIDcDCCAlgCAQAwaDELMAkGA1UEBhMCVUsxEDAOBgNVBAgMB0VuZ2xhbmQxDzAN +BgNVBAcMBkxvbmRvbjEVMBMGA1UEAwwMdGVzdC5waHAubmV0MR8wHQYJKoZIhvcN +AQkBFhB0ZXN0LnBocEBwaHAubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEArbUmVW1Y+rJzZRC3DYB0kdIgvk7MAday78ybGPPDhVlbAb4CjWbaPs4n +yUCTEt9KVG0H7pXHxDbWSsC2974zdvqlP0L2op1/M2SteTcGCBOdwGH2jORVAZL8 +/WbTOf9IpKAM77oN14scsyOlQBJqhh+xrLg8ksB2dOos54yDqo0Tq7R5tldV+alK +ZXWlJnqRCfFuxvqtfWI5nGTAedVZhvjQfLQQgujfXHoFWoGbXn2buzfwKGJEeqWP +bQOZF/FeOJPlgOBhhDb3BAFNVCtM3k71Rblj54pNd3yvq152xsgFd0o3s15fuSwZ +gerUjeEuw/wTK9k7vyp+MrIQHQmPdQIDAQABoIHCMAkGA1UECTECDAAwCQYDVQQX +MQIMADAMBgNVBBExBQwDTjExMBIGA1UEFDELDAkwMTIzNDU2NzgwFQYDVQQpMQ4M +DE9yZ2FuaXNhdGlvbjAZBgsrBgEEAdgOiH4CATEKDAgxMTExMjIyMjAZBgsrBgEE +AdgOiH4CAjEKDAgxMjM0NTY3ODAaBgkqhkiG9w0BCQ4xDTALMAkGA1UdEwQCMAAw +HwYJKoZIhvcNAQkBMRIWEGluZm9AZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQAD +ggEBAAoPI/sWY0QKPMEBuRp6MHcvWgSExwkkQfRJQZlYdepu6Tw0iZwYRTOR4sEn +Vz95qsrWqHp6QkXxdFG9FPHi4N66OX2Xb5TtHgDGMxrJTwbH+7VdsJiXLkWbeLuo +zKv8BsrhLRYiZkl+VWIrNyOcK7ao2sD+D3YkCBA4JK4OFhfhxY43D2sme7aEQVjr +S+UvEjuIALN0AP6gO2AMiUODPBrjsPI3NpN40VUvVU+Hsp1Tlqvth/AYASuGT2yt +M5YdcSm7JwaGAwIgOv8XPUQGem52yMEvzySRC4ZyTddfiZAkeTLmbh+SMVbHXXOk +UeEz+fvmQ4L+sc3RE8u+M8g31LM= +-----END CERTIFICATE REQUEST----- From b4e0245193e825b0ce0c3f6dddd4d2fcce14ff77 Mon Sep 17 00:00:00 2001 From: Steve Wall Date: Thu, 30 Oct 2025 18:05:40 -0400 Subject: [PATCH 2/6] address type mismatch --- ext/openssl/openssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 942fc9ea42386..99e63e240d8ca 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2089,7 +2089,7 @@ PHP_FUNCTION(openssl_csr_parse) case V_ASN1_NUMERICSTRING: case V_ASN1_UTF8STRING: case V_ASN1_IA5STRING: - add_assoc_stringl(&subitem, objbuf, bs->data, bs->length); + add_assoc_stringl(&subitem, objbuf, (char *)bs->data, bs->length); break; default: add_assoc_stringl(&subitem, objbuf, unknown, sizeof(unknown)); From a1c9189d2dab66f5691cb1066588f3f7c8713701 Mon Sep 17 00:00:00 2001 From: Steve Wall Date: Thu, 30 Oct 2025 18:49:26 -0400 Subject: [PATCH 3/6] Update openssl_parse_csr() test --- .../tests/openssl_csr_parse_basic.phpt | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/ext/openssl/tests/openssl_csr_parse_basic.phpt b/ext/openssl/tests/openssl_csr_parse_basic.phpt index 4f02859d18835..1161ef2351192 100644 --- a/ext/openssl/tests/openssl_csr_parse_basic.phpt +++ b/ext/openssl/tests/openssl_csr_parse_basic.phpt @@ -2,10 +2,6 @@ openssl_csr_parse() tests --EXTENSIONS-- openssl ---SKIPIF-- -= 0x30200000) die('skip For OpenSSL < 3.2'); -?> --FILE-- --EXPECTF-- bool(true) -array(8) { +array(9) { ["name"]=> string(71) "/C=UK/ST=England/L=London/CN=test.php.net/emailAddress=test.php@php.net" ["subject"]=> @@ -43,13 +39,32 @@ array(8) { string(23) "sha256WithRSAEncryption" ["signatureTypeNID"]=> int(668) + ["attributes"]=> + array(8) { + ["streetAddress"]=> + string(0) "" + ["facsimileTelephoneNumber"]=> + string(0) "" + ["postalCode"]=> + string(3) "N11" + ["telephoneNumber"]=> + string(9) "012345678" + ["name"]=> + string(12) "Organisation" + ["1.3.6.1.4.1.11278.1150.2.1"]=> + string(8) "11112222" + ["1.3.6.1.4.1.11278.1150.2.2"]=> + string(8) "12345678" + ["emailAddress"]=> + string(16) "info@example.com" + } ["extensions"]=> array(1) { ["basicConstraints"]=> string(8) "CA:FALSE" } } -array(8) { +array(9) { ["name"]=> string(71) "/C=UK/ST=England/L=London/CN=test.php.net/emailAddress=test.php@php.net" ["subject"]=> @@ -75,6 +90,25 @@ array(8) { string(23) "sha256WithRSAEncryption" ["signatureTypeNID"]=> int(668) + ["attributes"]=> + array(8) { + ["streetAddress"]=> + string(0) "" + ["facsimileTelephoneNumber"]=> + string(0) "" + ["postalCode"]=> + string(3) "N11" + ["telephoneNumber"]=> + string(9) "012345678" + ["name"]=> + string(12) "Organisation" + ["1.3.6.1.4.1.11278.1150.2.1"]=> + string(8) "11112222" + ["1.3.6.1.4.1.11278.1150.2.2"]=> + string(8) "12345678" + ["emailAddress"]=> + string(16) "info@example.com" + } ["extensions"]=> array(1) { ["basicConstraints"]=> From bfa3a44b45690af4c06f0b10c6461c554bf129d0 Mon Sep 17 00:00:00 2001 From: Steve Wall Date: Sun, 2 Nov 2025 20:54:52 -0500 Subject: [PATCH 4/6] Fix unfreed memory error --- ext/openssl/openssl.c | 97 +++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 99e63e240d8ca..5b20232cfad27 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2056,51 +2056,51 @@ PHP_FUNCTION(openssl_csr_parse) array_init(&subitem); int attrcnt = X509_REQ_get_attr_count(csr); if (attrcnt > 0) { - for (i = 0; i < attrcnt; i++) { - X509_ATTRIBUTE *attr = X509_REQ_get_attr(csr,i); - char unknown[] = "Unknown"; - if (attr) { - char objbuf[80]; - /* Adapted from openssl's "req" app */ - ASN1_TYPE *at; - ASN1_BIT_STRING *bs = NULL; - ASN1_OBJECT *aobj; - int j, type = 0, count = 1, ii = 0; - - aobj = X509_ATTRIBUTE_get0_object(attr); - if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) - continue; - if ((j = i2t_ASN1_OBJECT(objbuf, sizeof(objbuf), aobj)) > 0) { - ii = 0; - count = X509_ATTRIBUTE_count(attr); - if (count == 0) { - RETURN_FALSE; - } + for (i = 0; i < attrcnt; i++) { + X509_ATTRIBUTE *attr = X509_REQ_get_attr(csr,i); + char unknown[] = "Unknown"; + if (attr) { + char objbuf[80]; + /* Adapted from openssl's "req" app */ + ASN1_TYPE *at; + ASN1_BIT_STRING *bs = NULL; + ASN1_OBJECT *aobj; + int j, type = 0, count = 1, ii = 0; + + aobj = X509_ATTRIBUTE_get0_object(attr); + if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) + continue; + if ((j = i2t_ASN1_OBJECT(objbuf, sizeof(objbuf), aobj)) > 0) { + ii = 0; + count = X509_ATTRIBUTE_count(attr); + if (count == 0) { + goto err_subitem; + } get_next: - at = X509_ATTRIBUTE_get0_type(attr, ii); - type = at->type; - bs = at->value.asn1_string; - } else { - strcpy(objbuf, unknown); - } - switch (type) { - case V_ASN1_PRINTABLESTRING: - case V_ASN1_T61STRING: - case V_ASN1_NUMERICSTRING: - case V_ASN1_UTF8STRING: - case V_ASN1_IA5STRING: - add_assoc_stringl(&subitem, objbuf, (char *)bs->data, bs->length); - break; - default: - add_assoc_stringl(&subitem, objbuf, unknown, sizeof(unknown)); - break; - } - if (++ii < count) - goto get_next; + at = X509_ATTRIBUTE_get0_type(attr, ii); + type = at->type; + bs = at->value.asn1_string; + } else { + strcpy(objbuf, unknown); + } + switch (type) { + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_NUMERICSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_IA5STRING: + add_assoc_stringl(&subitem, objbuf, (char *)bs->data, bs->length); + break; + default: + add_assoc_stringl(&subitem, objbuf, unknown, sizeof(unknown)); + break; + } + if (++ii < count) + goto get_next; + } } - } - add_assoc_zval(return_value, "attributes", &subitem); + add_assoc_zval(return_value, "attributes", &subitem); } array_init(&subitem); @@ -2156,22 +2156,27 @@ PHP_FUNCTION(openssl_csr_parse) } add_assoc_zval(return_value, "extensions", &subitem); if (crit_name) { - efree(crit_name); + efree(crit_name); } + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + exts = NULL; } if (csr) { - X509_REQ_free(csr); + X509_REQ_free(csr); } return; err_subitem: zval_ptr_dtor(&subitem); if (crit_name) { - efree(crit_name); + efree(crit_name); } zend_array_destroy(Z_ARR_P(return_value)); if (csr) { - X509_REQ_free(csr); + X509_REQ_free(csr); + } + if (exts) { + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); } RETURN_FALSE; } From 263c4700ab9ec41380a88a7c0f6929f4963d86bd Mon Sep 17 00:00:00 2001 From: Steve Wall Date: Sun, 2 Nov 2025 21:04:19 -0500 Subject: [PATCH 5/6] fix stub hash --- ext/openssl/openssl_arginfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index 97a9c954a689e..18ca4f5080fd0 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 8233a8abc8ab7145d905d0fa51478edfe1e55a06 */ + * Stub hash: 7eeae72288dfe690115b837ea8ed372f9c3a734b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 2, _IS_BOOL, 0) ZEND_ARG_OBJ_TYPE_MASK(0, certificate, OpenSSLCertificate, MAY_BE_STRING, NULL) From bd0f226729f3f074caa2844c01df0aa1f03324da Mon Sep 17 00:00:00 2001 From: Steve Wall Date: Mon, 3 Nov 2025 10:38:58 -0500 Subject: [PATCH 6/6] fix possible uninitialize variable --- ext/openssl/openssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 5b20232cfad27..1132b482c117d 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2014,7 +2014,7 @@ PHP_FUNCTION(openssl_csr_parse) BIO *bio_out; BUF_MEM *bio_buf; char buf[256]; - STACK_OF(X509_EXTENSION) *exts; + STACK_OF(X509_EXTENSION) *exts = NULL; char *crit_name = NULL; int crit_len = 0;