php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71050 SubjectAltName (SAN) is Not included in openssl_csr_sign of a new CSR
Submitted: 2015-12-07 12:37 UTC Modified: -
Votes:17
Avg. Score:4.5 ± 0.8
Reproduced:14 of 14 (100.0%)
Same Version:6 (42.9%)
Same OS:5 (35.7%)
From: jimmmaaay at hotmail dot com Assigned:
Status: Open Package: OpenSSL related
PHP Version: 7.0.0 OS: Windows & CentOS 6.7
Private report: No CVE-ID: None
 [2015-12-07 12:37 UTC] jimmmaaay at hotmail dot com
Description:
------------
When creating a new CSR and self-signing it. The SAN (Subject Alternative Name) is not included .

---
From manual page: http://www.php.net/function.openssl-csr-sign
---


Test script:
---------------
$certificate_key_private_resource=openssl_pkey_new(["digest_alg"=>"sha256","private_key_bits"=>2048,"private_key_type"=>OPENSSL_KEYTYPE_RSA]);
$csr=openssl_csr_new(["countryName"=>'CA',"stateOrProvinceName"=>'State',"localityName"=>'City',"organizationName"=>'Company','organizationalUnitName'=>'Unit',"commonName"=>'example.org',"emailAddress"=>'email@email.com'],$certificate_key_private_resource,['config'=>'CUSTOM_CONFIG_FILE_PATH']);
$sscert=openssl_csr_sign($csr,null,$certificate_key_private_resource,365);openssl_x509_export($sscert,$c,false);
echo $c;




----------------------------
OPENSSL CUSTOM CONFIG FILE 
----------------------------

[ req ]
default_bits        = 2048
default_keyfile     = privkey.pem
distinguished_name  = req_distinguished_name
req_extensions     = req_ext 

[ req_distinguished_name ]
countryName           = Country Name (2 letter code)
countryName_default   = US
stateOrProvinceName   = State or Province Name (full name)
stateOrProvinceName_default = Illinois
localityName          = Locality Name (eg, city)
localityName_default  = Chicago
organizationName          = Organization Name (eg, company)
organizationName_default  = Example, Co.
commonName            = Common Name (eg, YOUR name)
commonName_max        = 64

[ req_ext ]
subjectAltName          = @alt_names

[alt_names]
DNS.1 = exmaple.org
DNS.2 = www.example.org


----------------------------
OPENSSL CUSTOM CONFIG FILE END 
----------------------------




Expected result:
----------------
outputted cert should contain Subject Alternative Name

Actual result:
--------------
outputted cert does not contain Subject Alternative Name

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-01-08 00:26 UTC] doldev at snowgarden dot ch
This is not a bug.

Even though the CSR contains the Subject Alternative Name it's up to the CA (Certificate Authority) to include the x509 extension (in your case Subject Alternative Name) requested in the CSR.
To openssl_csr_sign function is not copying the x509 extensions to the certificate. This behavior needs to be configured as well in the openssl.cnf.

Addition to the '[ req ]' config settings you need a '[ ca ]' section [1]. A basic configuration example can be found here [2]. Similar to your 'req' config 
a 'subjectAltName' must be added. For a self signed I recommend setting 'basicConstraints' [3] as well.
Similar to openssl_csr_new you have to define the 'config' parameter for openssl_csr_sign.

IMHO this bug can be closed. I hope it clear that the certificate not automatically inherits all the x509 extensions from the CSR. This would be very dangerous. Especially if someone could trick a CA to generate a certificate with the basicConstraints=CA:TRUE, which is comparable to an intermediate certificate.

[1] https://github.com/openssl/openssl/blob/2cc7acd273bc39f1360aed52400d18bb65b88a95/apps/openssl.cnf#L36
[2] https://www.openssl.org/docs/manmaster/apps/ca.html#EXAMPLES
[3] https://www.openssl.org/docs/manmaster/apps/x509v3_config.html#Basic-Constraints
 [2017-03-26 00:11 UTC] bouvrette dot nicolas at gmail dot com
This seems especially annoying for modern certificate management solutions such as ACME (letsencrypt.org). All PHP libraries trying to implement ACME end up with horrible hacks while other languages seems to be handling this nicely

Maybe its time to fix this?
 [2017-07-20 13:36 UTC] spam2 at rhsoft dot net
please go away mr. "This is not a bug" - in 2017 there are even clients which don't give a damn about the CN and so *you must* include a SAN
 [2017-07-20 14:55 UTC] spam2 at rhsoft dot net
that crap even don't work with $configargs set to the same values as for openssl_csr_new() while the docs say "You can finetune the CSR signing by configargs. See openssl_csr_new() for more information about configargs"

$key_config['config'] = $temp_config_file;
file_put_contents($temp_config_file, $temp_config_content);
putenv('PHP_PASS_SUBJECTALTNAME=DNS:' . implode(',DNS:', $hostnames));
$csr = openssl_csr_new($dn, $private_key, $key_config);

fine, the CSR contains "X509v3 Subject Alternative Name: DNS:www.test.rh, DNS:test.rh, DNS:test.thelounge.net"

$self_signed = openssl_csr_sign($csr, NULL, $private_key, 3650, $key_config);

the certificate don't
 [2017-07-24 09:50 UTC] spam2 at rhsoft dot net
god damned

$csr = openssl_csr_new($dn, $private_key, $key_config);
$self_signed = openssl_csr_sign($csr, NULL, $private_key, 3650, $key_config);

$key_config points with 'config' to a temporary "openssl.conf" and while the CSR has the SAN-Names the certificate does not and that means pretty sure that openssl_csr_sign() compoletly ignores the config file which is a MAJOR BUG
__________________________________________

[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = www.test.rh
DNS.2 = test.rh
DNS.3 = test.thelounge.net
__________________________________________

    [csr] => Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=AT, ST=Vienna, L=Vienna, O=the lounge interactive design gmbh, OU=Administration, CN=www.test.rh
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (3072 bit)
                Modulus:
                    00:9c:2c:b0:19:42:50:83:ed:c7:5c:d8:f7:c3:f7:
                    13:d5:17:a5:01:37:40:9a:e5:7f:43:88:22:35:89:
                    41:1b:b6:73:d7:f5:91:92:a9:54:b7:51:72:80:ef:
                    85:22:df:ac:bc:87:d3:85:f6:8a:72:35:2c:b6:16:
                    5b:d5:24:cb:4d:0f:b7:95:05:52:61:4f:bd:68:d0:
                    8e:8d:b4:86:e0:0c:02:03:63:e2:01:44:8a:d3:52:
                    24:c0:c1:07:a2:30:b2:29:9d:6c:c6:54:6b:aa:40:
                    d5:ac:6f:2c:e0:ea:8d:31:4e:e1:01:4c:3d:b0:27:
                    07:1b:c5:39:01:a3:e6:ad:a5:c6:b4:76:8a:2d:ab:
                    5c:a5:11:97:8a:f1:81:cd:ba:41:5f:88:34:a0:09:
                    d3:80:7c:32:b7:1c:74:1f:84:a3:40:2c:54:08:b7:
                    b6:08:f5:ad:34:0e:88:bb:c0:68:3f:04:f4:8f:0a:
                    09:bb:e4:6d:24:18:24:5f:62:73:d6:7a:d0:a2:c4:
                    d4:b2:02:3b:92:50:c4:3f:a4:28:2c:b9:54:0c:b1:
                    da:2d:d3:9a:fb:88:23:9f:46:3b:7b:8d:f4:c5:8f:
                    3b:af:b6:e1:98:26:fd:31:b4:da:bd:4f:31:52:8c:
                    86:1f:20:88:0c:c1:6d:3f:dd:ed:66:51:9e:99:a9:
                    aa:82:2c:0d:2f:b1:39:70:e7:b3:e3:cb:af:54:7f:
                    02:f0:9d:eb:34:d3:d5:94:fd:30:58:15:3a:4b:67:
                    a2:0b:40:30:35:ee:b7:50:81:8e:6e:3a:bb:76:25:
                    fa:66:ed:3d:d1:ad:ed:2f:24:b8:0e:e2:f8:04:99:
                    a6:25:96:4b:a9:84:c1:71:c0:7d:b1:b7:bd:c8:3b:
                    78:25:41:f6:76:69:aa:4b:4c:be:37:b8:e2:1b:ed:
                    fc:25:31:b6:0c:39:47:22:4e:8b:df:8d:7a:86:81:
                    ae:df:c0:3b:0d:bc:23:30:b9:5b:2e:a1:b8:89:f4:
                    a4:dc:90:b2:eb:58:51:86:d0:b5
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment
            X509v3 Subject Alternative Name: 
                DNS:www.test.rh, DNS:test.rh, DNS:test.thelounge.net
    Signature Algorithm: sha256WithRSAEncryption
         66:d0:4e:4d:6c:19:cc:c5:90:a4:2d:26:0d:9b:d4:12:80:d1:
         8c:d6:7c:e5:9c:62:fc:66:66:6e:9c:53:da:a0:08:ff:9c:5e:
         44:f9:a0:f8:fe:cd:82:66:9f:c2:38:d1:47:28:40:4e:08:6b:
         f2:a5:89:1b:36:25:3a:69:5b:20:e0:ee:eb:95:a4:69:2e:c9:
         a5:8d:4b:e7:1a:28:e8:b0:2f:27:78:b1:da:4f:cc:21:ed:93:
         51:95:dd:77:f5:b9:b3:c6:cf:2b:3a:c8:b7:45:40:71:b3:11:
         29:4d:d1:4e:2b:c4:b4:53:f7:e0:25:69:cf:90:4b:7a:7b:61:
         9f:2e:75:2b:46:95:40:32:7b:8a:2f:f9:8d:e6:ed:e0:a2:1e:
         de:67:15:fe:96:18:3c:7a:33:6b:6f:24:55:1e:8f:bc:7c:47:
         6e:bd:47:ab:5b:44:d9:62:84:39:87:71:05:69:95:5e:42:76:
         ab:05:fb:6b:84:49:b2:bc:bf:d2:d1:7e:d7:ab:3c:4a:69:ee:
         ac:ef:6a:aa:30:1a:84:f5:af:4f:ca:b9:0c:9e:d1:be:fa:1b:
         ed:38:f4:09:ae:a8:b3:0c:e4:9a:f4:5d:d7:b0:78:01:36:af:
         14:2a:9c:04:84:e4:f2:bd:6d:42:23:a3:0e:5e:c6:4e:d1:17:
         8f:67:b7:56:00:e8:38:32:12:28:69:c1:14:e8:68:03:0e:79:
         e7:25:47:22:70:8e:f8:ee:ef:78:e6:ce:dc:54:fa:ad:1c:a4:
         cd:27:e1:ff:56:29:31:a2:1e:1f:a9:09:c0:12:3f:56:26:af:
         e4:52:07:fb:29:4b:e2:1d:dc:61:e9:9f:ef:2f:c4:35:04:b6:
         b2:98:9d:da:4a:4e:39:83:d4:e6:a9:fd:eb:8d:d4:34:16:9d:
         5f:cf:42:53:32:68:53:9c:72:4f:ac:87:df:eb:7c:f8:92:69:
         57:b3:1b:fb:f6:b5:b5:3b:e3:c8:d0:3e:15:13:76:f6:91:81:
         fa:bd:fd:8e:99:d2
__________________________________________

[self_signed_pem] => Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 0 (0x0)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=AT, ST=Vienna, L=Vienna, O=the lounge interactive design gmbh, OU=Administration, CN=www.test.rh
        Validity
            Not Before: Jul 24 09:44:41 2017 GMT
            Not After : Jul 22 09:44:41 2027 GMT
        Subject: C=AT, ST=Vienna, L=Vienna, O=the lounge interactive design gmbh, OU=Administration, CN=www.test.rh
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (3072 bit)
                Modulus:
                    00:9c:2c:b0:19:42:50:83:ed:c7:5c:d8:f7:c3:f7:
                    13:d5:17:a5:01:37:40:9a:e5:7f:43:88:22:35:89:
                    41:1b:b6:73:d7:f5:91:92:a9:54:b7:51:72:80:ef:
                    85:22:df:ac:bc:87:d3:85:f6:8a:72:35:2c:b6:16:
                    5b:d5:24:cb:4d:0f:b7:95:05:52:61:4f:bd:68:d0:
                    8e:8d:b4:86:e0:0c:02:03:63:e2:01:44:8a:d3:52:
                    24:c0:c1:07:a2:30:b2:29:9d:6c:c6:54:6b:aa:40:
                    d5:ac:6f:2c:e0:ea:8d:31:4e:e1:01:4c:3d:b0:27:
                    07:1b:c5:39:01:a3:e6:ad:a5:c6:b4:76:8a:2d:ab:
                    5c:a5:11:97:8a:f1:81:cd:ba:41:5f:88:34:a0:09:
                    d3:80:7c:32:b7:1c:74:1f:84:a3:40:2c:54:08:b7:
                    b6:08:f5:ad:34:0e:88:bb:c0:68:3f:04:f4:8f:0a:
                    09:bb:e4:6d:24:18:24:5f:62:73:d6:7a:d0:a2:c4:
                    d4:b2:02:3b:92:50:c4:3f:a4:28:2c:b9:54:0c:b1:
                    da:2d:d3:9a:fb:88:23:9f:46:3b:7b:8d:f4:c5:8f:
                    3b:af:b6:e1:98:26:fd:31:b4:da:bd:4f:31:52:8c:
                    86:1f:20:88:0c:c1:6d:3f:dd:ed:66:51:9e:99:a9:
                    aa:82:2c:0d:2f:b1:39:70:e7:b3:e3:cb:af:54:7f:
                    02:f0:9d:eb:34:d3:d5:94:fd:30:58:15:3a:4b:67:
                    a2:0b:40:30:35:ee:b7:50:81:8e:6e:3a:bb:76:25:
                    fa:66:ed:3d:d1:ad:ed:2f:24:b8:0e:e2:f8:04:99:
                    a6:25:96:4b:a9:84:c1:71:c0:7d:b1:b7:bd:c8:3b:
                    78:25:41:f6:76:69:aa:4b:4c:be:37:b8:e2:1b:ed:
                    fc:25:31:b6:0c:39:47:22:4e:8b:df:8d:7a:86:81:
                    ae:df:c0:3b:0d:bc:23:30:b9:5b:2e:a1:b8:89:f4:
                    a4:dc:90:b2:eb:58:51:86:d0:b5
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         79:23:28:c4:4a:38:fb:e5:fd:b8:01:de:25:96:97:fe:ad:f7:
         98:9e:ee:60:66:94:72:ff:13:2b:cc:96:b7:35:ff:1e:ea:a7:
         60:39:4b:af:15:9a:0e:2d:14:46:ee:21:f8:17:e5:c5:0c:fe:
         ca:57:27:c6:40:c9:25:3d:71:70:36:ed:ec:36:e9:1d:40:6f:
         c6:81:ba:ef:ee:95:9f:0b:59:35:6d:96:44:54:80:e5:5c:63:
         29:0d:83:6c:50:5f:80:01:ec:cd:16:76:bc:ee:9b:26:02:39:
         9f:b8:f3:7e:01:d4:fe:e4:78:a6:27:4e:a5:54:7b:4d:9f:c5:
         29:56:c5:70:df:6b:22:1d:bd:b9:9a:f5:b0:5f:9c:a1:72:79:
         a0:60:90:db:6c:13:88:48:1f:24:5e:1f:fb:9a:a7:3c:24:12:
         f1:a6:f5:a6:3b:78:47:bf:29:fc:25:22:59:21:f3:14:d2:6d:
         65:8f:33:a2:0c:f6:c2:27:0e:5c:d5:ed:c8:1a:8f:d6:60:d0:
         00:44:d5:9c:e0:30:e4:99:a1:d1:05:ff:af:bd:40:07:86:0e:
         20:50:13:aa:9d:b2:7c:71:ee:4d:47:a0:56:3a:9c:f7:fe:64:
         17:09:b4:45:de:85:34:30:b5:1b:bb:06:dd:ca:7f:8c:16:ea:
         c1:0b:34:32:1b:53:3b:60:94:85:3c:22:3f:fe:b7:5e:ea:86:
         4b:97:76:0d:6a:7e:a5:be:3e:24:0b:91:6e:67:55:f2:c1:ed:
         2f:b8:77:16:08:75:ee:9d:e0:62:4d:38:7c:16:e3:4b:c6:88:
         08:62:49:3b:4b:c0:67:5e:e7:d3:11:99:c8:53:59:61:bc:23:
         76:90:b4:15:8e:63:0d:e1:db:8c:14:54:dc:1e:21:17:46:16:
         3a:81:f7:20:44:71:26:58:80:e6:1b:1a:66:0a:ab:2c:9a:d7:
         e8:9f:b3:4a:dd:14:9d:41:fc:d8:aa:82:e2:c9:3e:a1:63:8f:
         c1:64:00:98:6e:b3
 [2017-07-24 13:34 UTC] doldev at snowgarden dot ch
I repeat myself. This is not a bug. The extensions are not automatically copied over from a CSR to the finale certificate. Please read this explanation [1] which summaries the problem and security issue quite well.

To achieve the goal of signing a CSR with the SubjectAltName you may have to put some effort into.
I put together an small POC [2] to illustrate a possible way.
Please make sure you understand the security implications when receiving a CSR from a third party and then sign it. Make sure you validate and copy only the relevant x509 extension to the finale certificate.
An other possibility is to use the sop/x509 library [3] (used in the POC) the construct you certificate.

PS to Harald: Eine Auffrisching zum Thema Netiquette [4] würde dir sicherlich gut tun. [5]

[1] https://github.com/chef-cookbooks/openssl/issues/37#issuecomment-259021438
[2] https://gist.github.com/dol/e9f3d682529ae7ee368f0e6862e16a87
[3] https://packagist.org/packages/sop/x509
[4] https://de.wikipedia.org/wiki/Netiquette
[5] https://tools.ietf.org/html/rfc1855
 [2017-07-24 13:43 UTC] spam2 at rhsoft dot net
DAMEND what do you think is the "You can finetune the CSR signing by configargs. See openssl_csr_new() for more information about configargs" supposed to do? there is *nothing* to copy from the CSR - openssl_csr_sign() is feeded *with a explicit openssl.conf file* and if you would look at what i posted you would see that

and hence all your "I hope it clear that the certificate not automatically inherits all the x509 extensions from the CSR" is *nonsense* becaus eit is not asked to do so - it should read it from the *local config file*
 [2017-07-24 13:54 UTC] doldev at snowgarden dot ch
The POC [1] reads the information for the certificate from the local config file. The POC is only an extended version which extract SAN the information from a CSR. You could easily adopt the script to meet your needs.
The magic happens in this line => [2]

[1] https://gist.github.com/dol/e9f3d682529ae7ee368f0e6862e16a87
[2] https://gist.github.com/dol/e9f3d682529ae7ee368f0e6862e16a87#file-cert-php-L34
 [2017-07-24 13:54 UTC] bouvrette dot nicolas at gmail dot com
While I agree that this is more of a very annoying missing feature rather than a bug, I don't understand why this is not being implemented after all this time?

We're in 2017, there are ways to automatically get free HTTPS certificates (letsencrypt). Most other language make this easy but PHP is way behind.

The code I wrote to make this work is what I qualify "an ugly hack". I don't understand what is the goal to make this so complicated that people actually would consider moving to an other language...
 [2017-07-24 15:28 UTC] spam2 at rhsoft dot net
it also don't work with a openssl.conf duplicate the stuff from "[v3_req]" to "[usr_cert]" - and yes putenv() is a exremly dirty hack when you can generate a uniqe config file

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req

[req_distinguished_name]

[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[usr_cert]
basicConstraints=CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName = @alt_names

[alt_names]
DNS.1 = www.test.rh
DNS.2 = test.rh
DNS.3 = test.thelounge.net
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Oct 14 09:01:27 2024 UTC