SPKAC
SPKAC is an acronym for Signed Public Key and Challenge, a lesser used CSR format without distinguished names or extensions.
Reading SPKACs
use phpseclib4\File\SPKAC;
$spkac = SPKAC::load(file_get_contents('spkac.txt'));
print_r($spkac);
$spkac, in this case, is a SPKAC object which, in turn, is basically a thin wrapper around an instance of \phpseclib4\File\ASN1\Constructed. Passing $spkac through print_r() or var_dump() triggers the __debugInfo() magic method which, in turn, produces the following output:
publicKeyAndChallenge
spki
phpseclib4\Crypt\RSA\PublicKey
-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCM00BBEr4iRFui8QRALkTZ/yJj TbVsemyekfIYlIsmqolpgkhXNkXv2RNSkM8yWGS7+45YEo2Vb3X98/2z+8j4b24c eB5g0Z6B/RXc6EpvHnX1GYMYofsfjP2U3is8qYWvuzPvmc7xD+QOb6wF5p9FXSOG jXmnuljjPaeLwAF3AwIDAQAB -----END PUBLIC KEY-----
challenge
phpseclib4\File\ASN1\Types\IA5String
signatureAlgorithm
algorithm
phpseclib4\File\ASN1\Types\OID
signature
phpseclib4\File\ASN1\Types\BitString
All elements and subelements of the above SPKAC object can be accessed as array elements vis-a-vis ArrayAccess. As a consequence of this there are two ways to get (for example) the public key. You could do $spkac['publicKeyAndChallenge']['spki'] or you could do $spkac->getPublicKey(). It's these helper functions that set the SPKAC class apart from \phpseclib4\File\ASN1\Constructed.
To learn more about the capabilities afforded to the SPKAC class by virtue of it being a thin wrapper around \phpseclib4\File\ASN1\Constructed please refer to Deep Dive: ASN1\Constructed Objects.
getPublicKey()
echo $spkac->getPublicKey();
Returns a \phpseclib4\Crypt\Common\PublicKey object that, by default, gets cast to a PKCS8-encoded public key:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCM00BBEr4iRFui8QRALkTZ/yJj
TbVsemyekfIYlIsmqolpgkhXNkXv2RNSkM8yWGS7+45YEo2Vb3X98/2z+8j4b24c
eB5g0Z6B/RXc6EpvHnX1GYMYofsfjP2U3is8qYWvuzPvmc7xD+QOb6wF5p9FXSOG
jXmnuljjPaeLwAF3AwIDAQAB
-----END PUBLIC KEY-----
Note that if the key is in an unsupported format then $spkac->getPublicKey() will throw a UnexpectedValueException. If you want to see what the public key is, regardless of whether or not it's in a supported format, then you can do $spkac['publicKeyAndChallenge']['spki'].
Very rarely, SPKACs may not have a public key at all. You can test for this by doing $spkac->hasPublicKey(), which returns a boolean based on whether or not the SPKAC in question has a public key or not.
getChallenge()
$spkac->getChallenge() is a shorthand way of getting $spkac['publicKeyAndChallenge']['challenge'].
Creating SPKACs
Minimalistic SPKAC
Consider the following:
use phpseclib4\File\SPKAC;
$spkac = new SPKAC();
echo $spkac;
The SPKAC that that would produce would look something like this:
SPKAC=MBYwDDAIMAMGAQADAQAWADADBgEAAwEA
This SPKAC has no public key, no challenge and no signature.
If you did print_r($spkac) on that SPKAC you'd get this:
publicKeyAndChallenge
spki
algorithm
algorithm
phpseclib4\File\ASN1\Types\OID
subjectPublicKey
phpseclib4\File\ASN1\Types\BitString
challenge
phpseclib4\File\ASN1\Types\IA5String
signatureAlgorithm
algorithm
phpseclib4\File\ASN1\Types\OID
signature
phpseclib4\File\ASN1\Types\BitString
Setting the Public Key
Let's say you created your public key thusly:
use phpseclib4\Crypt\EC;
$private = EC::createKey('nistp256');
$public = $private->getPublicKey();
At this point you could set the public key for the SPKAC using one of two techniques:
$spkac = new SPKAC($public);
echo $spkac;
$spkac = new SPKAC();
$spkac->setPublicKey($public);
echo $spkac;
You can also remove a public key be calling $spkac->removePublicKey().
Setting the Challenge
The challenge can be set by calling $spkac->setChallenge() and passing a string to that function. It can also be set by setting $spkac['publicKeyAndChallenge']['challenge'] to a string.
Note that the challenge field is an IA5String (7-bit ASCII), so setChallenge() silently ANDs each byte of the input with 0x7F to clamp it into the 7-bit range. If you pass a UTF-8 challenge with multi-byte characters, you'll get back a clamped 7-bit version rather than an error. For interoperability, pass plain ASCII.
Signing
Let's say you created your public key thusly:
use phpseclib4\Crypt\EC;
$private = EC::createKey('nistp256');
$public = $private->getPublicKey();
At that point you can sign your SPKAC like so:
$spkac = new SPKAC($public);
// do stuff
$private->sign($spkac);
echo $spkac;
Note that $pfx->sign($spkac) works syntactically but is unusual: an SPKAC is signed by the requester (proving they control the private key corresponding to the embedded public key), whereas a PFX represents a CA's signing identity. In normal flows you'd use a bare PrivateKey to sign an SPKAC.
Validating Signatures
SPKAC's are always self-signed and can be validated thusly:
$spkac = SPKAC::load('...');
echo $spkac->validateSignature() ? 'valid' : 'invalid';