Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,183 @@ 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;
zval critext;
int critcount = 0;
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 = NULL;

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) {
php_error_docref(NULL, E_WARNING, "First parameter must be a valid CSR");
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);
array_init(&critext);

int attrcnt = X509_REQ_get_attr_count(csr);
if (attrcnt > 0) {
const char unknown[] = "Unknown";
for (i = 0; i < attrcnt; i++) {
X509_ATTRIBUTE *attr = X509_REQ_get_attr(csr,i);
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;

}
}
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(nid);
} else {
if (OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1) < 0) {
php_openssl_store_errors();
goto err_subitem;
}
extname = buf;
}
if (X509_EXTENSION_get_critical(extension)) {
add_next_index_string(&critext, extname);
critcount++;
}
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 (critcount > 0) {
add_assoc_zval(return_value, "criticalExtensions", &critext);
} else {
zval_ptr_dtor(&critext);
}
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
exts = NULL;
}
if (csr) {
X509_REQ_free(csr);
}
return;

err_subitem:
zval_ptr_dtor(&subitem);
zval_ptr_dtor(&critext);
zend_array_destroy(Z_ARR_P(return_value));
if (csr) {
X509_REQ_free(csr);
}
if (exts) {
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
}
RETURN_FALSE;
}

/* }}} */

/* {{{ EVP Public/Private key functions */
Expand Down
2 changes: 2 additions & 0 deletions ext/openssl/openssl.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

/**
Expand Down
6 changes: 5 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.

117 changes: 117 additions & 0 deletions ext/openssl/tests/openssl_csr_parse_basic.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
--TEST--
openssl_csr_parse() tests
--EXTENSIONS--
openssl
--FILE--
<?php
$csr = "file://" . __DIR__ . "/parse.csr";

$parsedCSR = openssl_csr_parse($csr);
var_dump($parsedCSR === openssl_csr_parse(file_get_contents($csr)));
var_dump($parsedCSR);
var_dump(openssl_csr_parse($csr, false));
?>
--EXPECT--
bool(true)
array(9) {
["name"]=>
string(71) "/C=UK/ST=England/L=London/CN=test.php.net/[email protected]"
["subject"]=>
array(5) {
["C"]=>
string(2) "UK"
["ST"]=>
string(7) "England"
["L"]=>
string(6) "London"
["CN"]=>
string(12) "test.php.net"
["emailAddress"]=>
string(16) "[email protected]"
}
["hash"]=>
string(8) "b21872c1"
["version"]=>
int(0)
["signatureTypeSN"]=>
string(10) "RSA-SHA256"
["signatureTypeLN"]=>
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) "[email protected]"
}
["extensions"]=>
array(1) {
["basicConstraints"]=>
string(8) "CA:FALSE"
}
}
array(9) {
["name"]=>
string(71) "/C=UK/ST=England/L=London/CN=test.php.net/[email protected]"
["subject"]=>
array(5) {
["countryName"]=>
string(2) "UK"
["stateOrProvinceName"]=>
string(7) "England"
["localityName"]=>
string(6) "London"
["commonName"]=>
string(12) "test.php.net"
["emailAddress"]=>
string(16) "[email protected]"
}
["hash"]=>
string(8) "b21872c1"
["version"]=>
int(0)
["signatureTypeSN"]=>
string(10) "RSA-SHA256"
["signatureTypeLN"]=>
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) "[email protected]"
}
["extensions"]=>
array(1) {
["basicConstraints"]=>
string(8) "CA:FALSE"
}
}
21 changes: 21 additions & 0 deletions ext/openssl/tests/parse.csr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----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-----
Loading