phpseclib

phpseclib

  • Docs
  • API
  • Support
  • GitHub

›X.509

Introduction

  • Why phpseclib?
  • Installation
  • Speed
  • Versioning

SSH2

  • Connecting
  • Authenticating
  • Running Commands
  • SFTP
  • Diagnosing Issues

Public Keys

  • Overview
  • RSA
  • DSA
  • Elliptic Curves
  • (EC)DH
  • Example: JWT

Symmetric Keys

  • Overview

X.509

  • X.509
  • CSR
  • SPKAC
  • CRL

Interoperability

  • Overview
  • Python
  • Java
  • JavaScript
  • Node.js
  • Go
  • Ruby
  • C#
  • C
  • PHP

X.509

Reading Certificates

use phpseclib3\File\X509;

$x509 = new X509();
$cert = $x509->loadX509(file_get_contents('google.crt'));

var_dump($cert);

(download google.crt)

Running the above will produce an array that looks something like this:

$cert

  • tbsCertificate
    • version
      • v3
    • serialNumber
      • 105827261859531100510423749949966875981
    • signature
      • algorithm
        • sha1WithRSAEncryption
      • parameters
        • null
    • issuer
      • rdnSequence
        • 0
          • 0
            • type
              • id-at-countryName
            • value
              • printableString
                • ZA
        • 1
          • 0
            • type
              • id-at-organizationName
            • value
              • printableString
                • Thawte Consulting (Pty) Ltd.
        • 2
          • 0
            • type
              • id-at-commonName
            • value
              • printableString
                • Thawte SGC CA
    • validity
      • notBefore
        • utcTime
          • Wed, 26 Oct 2011 00:00:00 +0000
      • notAfter
        • utcTime
          • Mon, 30 Sep 2013 23:59:59 +0000
    • subject
      • rdnSequence
        • 0
          • 0
            • type
              • id-at-countryName
            • value
              • printableString
                • US
        • 1
          • 0
            • type
              • id-at-stateOrProvinceName
            • value
              • printableString
                • California
        • 2
          • 0
            • type
              • id-at-localityName
            • value
              • teletexString
                • Mountain View
        • 3
          • 0
            • type
              • id-at-organizationName
            • value
              • teletexString
                • Google Inc
        • 4
          • 0
            • type
              • id-at-commonName
            • value
              • teletexString
                • www.google.com
    • subjectPublicKeyInfo
      • algorithm
        • algorithm
          • rsaEncryption
        • parameters
          • null
      • subjectPublicKey
        • -----BEGIN PUBLIC KEY-----
          MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDetyZDppmFzTinFQm5zw/Jw1WM
          iO6MjSgnJEsqXqDYFvphGEvPbWCA0zVAMnLAjxLY5U6PubL22RVeWoYxo7qGqmvI
          2XGMzM0nEx6dQl049qes7/pi8xiB1CRGfwF3fMYqiRSZu5g5HagZ+zkARH0blGp4
          LWmtwHos+tDaIBKY0wIDAQAB
          -----END PUBLIC KEY-----
          
    • extensions
      • 0
        • extnId
          • id-ce-basicConstraints
        • critical
          • 1
        • extnValue
          • cA
      • 1
        • extnId
          • id-ce-cRLDistributionPoints
        • critical
        • extnValue
          • 0
            • distributionPoint
              • fullName
                • 0
                  • uniformResourceIdentifier
                    • http://crl.thawte.com/ThawteSGCCA.crl
      • 2
        • extnId
          • id-ce-extKeyUsage
        • critical
        • extnValue
          • 0
            • id-kp-serverAuth
          • 1
            • id-kp-clientAuth
          • 2
            • 2.16.840.1.113730.4.1
      • 3
        • extnId
          • id-pe-authorityInfoAccess
        • critical
        • extnValue
          • 0
            • accessMethod
              • id-ad-ocsp
            • accessLocation
              • uniformResourceIdentifier
                • http://ocsp.thawte.com
          • 1
            • accessMethod
              • id-ad-caIssuers
            • accessLocation
              • uniformResourceIdentifier
                • http://www.thawte.com/repository/Thawte_SGC_CA.crt
  • signatureAlgorithm
    • algorithm
      • sha1WithRSAEncryption
    • parameters
      • null
  • signature
    • ...

getDNProp()

print_r($x509->getDNProp('CN'));

That will produce the following:

  • 0
    • www.google.com

An array is returned because each distinguished name property can (in theory) have multiple values

Valid property names are enumerated upon at Distinguished Property Names.

getIssuerDNProp() returns the issuer distinguished name as opposed to the subject distinguished name.

getDN()

print_r($x509->getDN());

getDN() / getIssuerDN() accept several different parameters:

  • X509::DN_ARRAY (the default value) returns an array who's keys are based on the ASN.1 syntax for X.509:

    • rdnSequence
      • 0
        • 0
          • type
            • id-at-countryName
          • value
            • printableString
              • US
      • 1
        • 0
          • type
            • id-at-stateOrProvinceName
          • value
            • printableString
              • California
      • 2
        • 0
          • type
            • id-at-localityName
          • value
            • teletexString
              • Mountain View
      • 3
        • 0
          • type
            • id-at-organizationName
          • value
            • teletexString
              • Google Inc
      • 4
        • 0
          • type
            • id-at-commonName
          • value
            • teletexString
              • www.google.com
  • X509::DN_STRING returns an OpenSSL-style string:

    C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com
    
  • X509::DN_OPENSSL returns an OpenSSL-style array:

    • C
      • US
    • ST
      • California
    • L
      • Mountain View
    • O
      • Google Inc
    • CN
      • www.google.com
  • X509::DN_ASN1 returns a DER encoded binary string

  • X509::DN_CANON returns a "canonicalized" DER encoded binary string wherein SEQUENCE around RDNs and all string values normalized as trimmed lowercase UTF-8 with all spacing as one blank. Constructed RDNs are not canonicalized.

getPublicKey()

echo $x509->getPublicKey();

Returns a \phpseclib3\Crypt\Common\PublicKey object that, by default, gets cast to a PKCS8-encoded public key:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDetyZDppmFzTinFQm5zw/Jw1WM
iO6MjSgnJEsqXqDYFvphGEvPbWCA0zVAMnLAjxLY5U6PubL22RVeWoYxo7qGqmvI
2XGMzM0nEx6dQl049qes7/pi8xiB1CRGfwF3fMYqiRSZu5g5HagZ+zkARH0blGp4
LWmtwHos+tDaIBKY0wIDAQAB
-----END PUBLIC KEY-----

Validating Certificates

Signatures

$x509 = new X509();
$x509->loadCA('...');
$cert = $x509->loadX509('...');
echo $x509->validateSignature() ? 'valid' : 'invalid';

Certificate authority certificates can be downloaded from curl - SSL CA Certificates. Parsing that is left as an exercise to the reader.

Self-signed Signatures

$x509 = new X509();
$cert = $x509->loadX509('...');
echo $x509->validateSignature(false) ?
    'valid' :
    'invalid';

URLs

$x509 = new File_X509();
$cert = $x509->loadX509('...');
echo $x509->validateURL('https://www.domain.tld/path/to/whatever.ext') ?
    'valid' :
    'invalid';

Dates

$x509 = new X509();
$cert = $x509->loadX509('...');
echo $x509->validateDate() ? 'valid' : 'invalid';

By default validateDate checks to see if the current date is within the date range. If, however, you want to use a custom date you may do so by either passing a string (eg. validateDate('January 1, 2001')) or a DateTime object (eg. validateDate(new DateTime('January 1, 2001'))).

Chains

Let's say you have a certificate chain that has at least one intermediate cert and let's further say that you wanted to see all the certs in this chain. To do that you could do $x509>getChain(). That'll return an array of X509 objects who's first element is the current cert and who's last element is the CA cert.

If you want to retrieve the array contents of any cert in the chain you'll need to do $x509->getCurrentCert().

Creating Certificates

The General Idea

In a nutshell...

$result = $x509->sign($issuer, $subject); 
$x509->saveX509($result);

Public / Private Keys

$issuer and $subject are, themselves, X509 objects. They need private and public keys, respectively. Here's an example of how to create them from scratch for a brand new self-signed cert:

$privKey = RSA::createKey();
$pubKey = $privKey->getPublicKey();

$issuer->setPrivateKey($privKey); 
$subject->setPublicKey($pubKey);

The public key can also be set by $subject->loadCSR('...') or $subject->loadX509('...'). If you're using $subject->loadX509() you'll effectively be re-signing $subject. The issuer DN of $subject will be updated as will some of the other "transactional properties" (see below), if appropriate, but all (well, most) of the extensions will be preserved.

Note that whereas in the 1.0 and 2.0 branches, the signature algorithm was set by using an additional parameter in the sign method (or signCSR, signCRL, etc) in this case it's set based on the key. So if you want to create an rsaEncryption X509 cert you'd need to do $publicKey = $publicKey->withHashing(RSA::SIGNATURE_PKCS1) since, by default, RSA keys use RSA::SIGNATURE_PSS.

Key Identifiers

Sometimes an $issuer or a $subject will have multiple private keys. To disambiguate between them key identifiers are used. Quoting RFC5280 § 4.2.1.1, "the value of the keyIdentifier field SHOULD be derived from the public key used to verify the certificate's signature or a method that generates unique values". An example follows:

$issuer->setKeyIdentifier($issuer->computeKeyIdentifier($pubKey));

Note that computeKeyIdentifier is already called by saveX509() unless you've specifically over-written the key identifier.

Distinguished Names

$issuer and $subject also need to have their distinguished names set. That can be done in a number of ways. The following are all equivalent to one another:

$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert'); 
$subject->setDN( 
    array( 
        'rdnSequence' => array( 
            array( 
                array( 
                    'type' => 'id-at-organizationName', 
                    'value'=> 'phpseclib demo cert' 
                ) 
            ) 
        ) 
    ) 
); 
$subject->setDN(array( 
    'O' => 'phpseclib demo cert' 
)); 
$subject->setDN('/O=phpseclib demo cert');

DN properties can also be removed thusly:

$subject->removeDNProp('id-at-organizationName');

DN properties can be set via $subject->loadCSR('...') and $subject->loadX509('...') as well.

In the case of $subject->setDN().. the value will be assumed to be utf8String unless you explicitely tell phpseclib to set it to another type by doing something like 'value'=> array('ia5String' => 'phpseclib demo cert').

See also: List of DN property names

Domain Names

If your X.509 certificate is supposed to be valid for a single domain name that domain name can be set by either setting the id-at-commonName or CN distinguished name property. If your X.509 certificate is supposed to be valid for multiple domain names an X.509 extension - id-ce-subjectAltName - is required. setDomain() takes care of all of this for you. Here's an example of how to make your certificate valid for two domains:

$subject->setDomain('www.google.com', 'www.yahoo.com');

Transactional Properties

Some properties belong neither to $issuer or $subject. Rather they belong to "transaction". The functions to set those properties are as follows:

$x509->setSerialNumber(...);
$x509->makeCA();
$x509->setStartDate(...); 
$x509->setEndDate(...);

$subject->setDomain() isn't considered a transactional property because, in theory, the issuing certificate could have at least one domain too since that's based on a particular distinguished name property.

The start time is, by default, when the cert is created. The current time is converted to UTC time and the fact that it's UTC time is denoted in the cert. Other X.509 decoders (eg. browsers or email clients or whatever) should decode this to their timezone so there's no need to set it to do $x509->setStartDate('-1 day') or anything like that.

The end date, by default, is one year from the current time.

setStartDate() / setEndDate() can accept strings or DateTime objects. If you want the cert to last forever pass 'lifetime' to it.

Function List

Functions affecting properties common to both $issuer and $subject are as follows:

  • setDNProp
  • removeDNProp
  • setDN
  • loadCSR
  • loadX509
  • setKeyIdentifier / computeKeyIdentifier

Functions affecting $issuer only properties:

  • setPrivateKey

Functions affecting $subject only properties:

  • setPublicKey
  • setDomain

Functions affecting $x509 properties:

  • setSerialNumber
  • makeCA
  • setStartDate
  • setEndDate

Minimalistic Example

$subject = new X509(); 
$subject->setPublicKey($pubKey); // $pubKey is a PublicKey objet
$subject->setDN('/O=phpseclib demo cert'); 

$issuer = new X509(); 
$issuer->setPrivateKey($privKey); // $privKey is a PrivateKey object
$issuer->setDN('/O=phpseclib demo cert'); 

$x509 = new X509(); 
$result = $x509->sign($issuer, $subject); 
echo $x509->saveX509($result);

For self-signed certs the DN of the subject and issuer will match and the issuer's private key will correspond to the subject's public key.

Example: Self-signed cert

use phpseclib3\File\X509;
use phpseclib3\Crypt\RSA;

// create private key / x.509 cert for stunnel / website
$CAPrivKey = RSA::createKey();
$CAPubKey = $CAPrivKey->getPublicKey();

$CASubject = new X509;
$CASubject->setDNProp('id-at-organizationName', 'phpseclib CA cert');
$CASubject->setPublicKey($CAPubKey);

$CAIssuer = new X509;
$CAIssuer->setPrivateKey($CAPrivKey);
$CAIssuer->setDN($CASubject->getDN());

$x509 = new X509;
$x509->makeCA();
$result = $x509->sign($CAIssuer, $CASubject);
echo "private key for CA cert (can be discarded):\r\n\r\n";
echo $CAPrivKey;
echo "\r\n\r\nCA cert to be imported into browser:\r\n\r\n";
echo $x509->saveX509($result);
echo "\r\n";

The cert that this script creates is a CA cert. If you don't want it to be a CA cert you can comment out the $x509->makeCA() line.

Example: CA-signed cert

The following code requires the previous code to work and should follow the code in the previous section.

$privKey = RSA::createKey();
$pubKey = $privKey->getPublicKey();

$subject = new X509;
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
$subject->setPublicKey($pubKey);

$x509 = new X509;
$result = $x509->sign($CAIssuer, $subject);
echo "\r\nthe stunnel.pem contents are as follows:\r\n\r\n";
echo $privKey;
echo "\r\n";
echo $x509->saveX509($result);
echo "\r\n";

Example: Arbitrary and Custom Extensions

phpseclib can be used to implement add arbitrary extensions as well.

Building off of the previous example (using the phpBB MOD Text Template):

#
#-----[ FIND ]------------------------------------------
#
$result = $x509->sign($issuer, $subject);
#
#-----[ BEFORE, ADD ]-----------------------------------
#
$x509->setExtensionValue('id-pe-authorityInfoAccess', [
    [
        "accessMethod" => "id-ad-ocsp",
        "accessLocation" => [
            "uniformResourceIdentifier" => 'https://ocsp.test.ca/',
        ]
    ],
    [
        "accessMethod" => "id-ad-caIssuers",
        "accessLocation" => [
            "uniformResourceIdentifier" => 'https://crt.test.ca/test.crt',
        ],
    ],
], true);

The first two parameters are pretty self explanatory. The third parameter is used to denote if the extension is critical or not. A fourth parameter - $replace - also exists if you want this extension to replace an existant extension with the same id as the one you're adding. This parameter defaults to false (don't replace) but can also be set to true (do replace).

Now let's say you wanted to include not just an arbitrary extension but a custom one as well (eg. one that phpseclib doesn't have pre built-in support for). That can be done thusly:

#
#-----[ FIND ]------------------------------------------
#
use phpseclib3\File\X509;
use phpseclib3\Crypt\RSA;
#
#-----[ AFTER, ADD ]------------------------------------
#
use phpseclib3\File\ASN1;

$customExtensionName = 'cust';
$customExtensionNumber = '2.16.840.1.101.3.4.2.99';

ASN1::loadOIDs([
    $customExtensionName => $customExtensionNumber,
]);

X509::registerExtension($customExtensionName, [
    'type' => ASN1::TYPE_SEQUENCE,
    'children' => [
        'toggle' => ['type' => ASN1::TYPE_BOOLEAN],
        'num' => ['type' => ASN1::TYPE_INTEGER],
        'name' => ['type' => ASN1::TYPE_OCTET_STRING],
        'list' => [
            'type' => ASN1::TYPE_SEQUENCE,
            'min' => 0,
            'max' => -1,
            'children' => ['type' => ASN1::TYPE_OCTET_STRING],
        ],
    ],
]);
#
#-----[ FIND ]------------------------------------------
#
$result = $x509->sign($issuer, $subject);
#
#-----[ BEFORE, ADD ]-----------------------------------
#
$x509->setExtensionValue($customExtensionName, $customExtensionData);
← OverviewCSR →
  • Reading Certificates
    • getDNProp()
    • getDN()
    • getPublicKey()
  • Validating Certificates
    • Signatures
    • Self-signed Signatures
    • URLs
    • Dates
    • Chains
  • Creating Certificates
    • The General Idea
    • Public / Private Keys
    • Key Identifiers
    • Distinguished Names
    • Domain Names
    • Transactional Properties
    • Function List
    • Minimalistic Example
    • Example: Self-signed cert
    • Example: CA-signed cert
    • Example: Arbitrary and Custom Extensions
phpseclib
Docs
IntroductionSSH2 / SFTPPublic Key CryptoSymmetric Key CryptoX.509 / CSR / SPKAC / CRLInteroperability
Support
Docs (1.0 / 2.0)Stack OverflowGitHubStar
Sponsor
PatreonGitHubPayPal
Copyright © 2025 Jim Wigginton