Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add arbitrary extension to X.509 certificate #625

Open
asherkin opened this issue Feb 24, 2015 · 3 comments
Open

Add arbitrary extension to X.509 certificate #625

asherkin opened this issue Feb 24, 2015 · 3 comments

Comments

@asherkin
Copy link

I've poked around a bit in the ASN1 and X509 classes, but it looks like everything has to be hard-coded in the X509 class? _getMapping appears to have a provision for unknown extensions, but it seems to only be considered for parsing (which is also alluded to by a comment in said function).

I'm after something like https://www.openssl.org/docs/apps/x509v3_config.html#arbitrary_extensions.

@terrafrost
Copy link
Member

In theory, with phpseclib, you'd use File_ASN1_Element to create arbitrary extensions. In practice, it looks like you'll have to add one line to File/X509.php:

#
#-----[ OPEN ]------------------------------------------
#
File/X509.php
#
#-----[ FIND ]------------------------------------------
#
    function _mapOutExtensions(&$root, $path, $asn1)
    {
        $extensions = &$this->_subArray($root, $path);

        if (is_array($extensions)) {
            $size = count($extensions);
            for ($i = 0; $i < $size; $i++) {
#
#-----[ AFTER, ADD ]------------------------------------
#
if (is_object($extensions[$i]) && strtolower(get_class($extensions[$i])) == 'file_asn1_element') continue;

Once that's done you can do this:

<?php

include('File/X509.php');

$x509 = new File_X509();
$cert = $x509->loadX509('-----BEGIN CERTIFICATE-----
MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM
MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x
MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy
wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B
d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM
BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp
ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le
IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==
-----END CERTIFICATE-----');

$asn1 = new File_ASN1();

$value = encodeOID('1.2.3.4');
$ext = chr(FILE_ASN1_TYPE_OBJECT_IDENTIFIER) . $asn1->_encodeLength(strlen($value)) . $value;
$value = 'zzzzzzzzz';
$ext.= chr(FILE_ASN1_TYPE_OCTET_STRING) . $asn1->_encodeLength(strlen($value)) . $value;
$ext = chr(FILE_ASN1_TYPE_SEQUENCE | 0x20) . $asn1->_encodeLength(strlen($ext)) . $ext;

function encodeOID($oid)
{
                if ($oid === false) {
                    user_error('Invalid OID');
                    return false;
                }
                $value = '';
                $parts = explode('.', $oid);
                $value = chr(40 * $parts[0] + $parts[1]);
                for ($i = 2; $i < count($parts); $i++) {
                    $temp = '';
                    if (!$parts[$i]) {
                        $temp = "\0";
                    } else {
                        while ($parts[$i]) {
                            $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
                            $parts[$i] >>= 7;
                        }
                        $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
                    }
                    $value.= $temp;
                }
                return $value;
}

$cert['tbsCertificate']['extensions'][4] = new File_ASN1_Element($ext);

echo $x509->saveX509($cert);

I mean, I guess I could add support for creating them in a manner more consistent with OpenSSL. eg. maybe create a new object - File_X509_ArbitraryExtension - or some such.

@terrafrost
Copy link
Member

Oh - also, I'll try to do the code change later today or something as time permits.

As for File_X509_ArbitraryExtension (or whatever)... I'll probably hold off on that until I can do an overall of File_X509. There are a number of things I want to change about it. BC breaking changes that I think would improve usability that'll go in the master branch.

@asherkin
Copy link
Author

Sweet, thanks for the detailed example! I look forward to seeing where File_X509 goes in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants