Convert RSA public key, from XML to PEM (PHP)
Solution 1
we know
.pem - (Privacy Enhanced Mail) Base64 encoded DER certificate, enclosed between "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----"
The SignatureValue element contains the Base64 encoded signature result - the signature generated with the parameters specified in the SignatureMethod element - of the SignedInfo element after applying the algorithm specified by the CanonicalizationMethod.
so we end up with
$xml = simplexml_load_file($xmlFile); // or simplexml_load_string
$pem = "-----BEGIN CERTIFICATE-----\n";
$pem .= $xml->SignatureValue;
$pem .= "\n-----END CERTIFICATE-----";
// save to file
if your xml-file isn't a XML_Signature
$xml = simplexml_load_file($xmlFile); // or simplexml_load_string
$pem = "-----BEGIN CERTIFICATE-----\n";
$pem .= $xml->nodeWithWantedValue; // use base64_encode if needed
$pem .= "\n-----END CERTIFICATE-----";
Solution 2
I'm assuming that by XML format, you mean XML DSig RSAKeyValue, and that by PEM format you mean what OpenSSL exports in between -----BEGIN PUBLIC KEY-----
and -----END PUBLIC KEY-----
.
You need first to extract the modulus and public exponent from the XML.
<RSAKeyValue>
<Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W
jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV
5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U=
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
You can easily convert these into a bit string using base64_decode
.
Once this is done, you need to build the ASN.1 public key structure somehow.
What OpenSSL exports between BEGIN/END PUBLIC KEY is an X.509 SubjectPublicKeyInfo structure.
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING }
The subjectPublicKey
is made of a sequnce is described in the PKCS#1 spec:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER,
publicExponent INTEGER
}
The algorithm
(an AlgorithmIdentifier
) is also described in the PKCS#1 spec (see section A.1):
rsaEncryption
OBJECT IDENTIFIER ::= { pkcs-1 1 }
This structure needs to be serialized in DER form, then base64-encoded and then placed between the BEGIN/END delimiters.
I don't know of any PHP library to do the ASN.1/DER encoding unfortunately (the rest is relatively easy, but dealing with ASN.1 tends to be tedious).
The PHP/PEAR Crypt_RSA module can construct RSA public keys from modulus and exponent, but its toString()
method uses a custom format (just the base64-encoding of the result of PHP serialize
on the array structure, which has nothing to do with the ASN.1/DER encoding).
Solution 3
Here's an example of how to read XML RSA keys in PHP:
slamer
Updated on June 14, 2022Comments
-
slamer about 2 years
How convert RSA public key, from XML to PEM (PHP)?
-
Bruno almost 14 yearsWhat do you mean by "XML", do you mean from a document using XML Signature: en.wikipedia.org/wiki/XML_Signature
-
-
Bruno almost 14 yearsThere is a W3C recommendation that specifies this: w3.org/TR/xmldsig-core/#sec-RSAKeyValue
-
Bruno almost 14 yearsMaybe it's the variable name that's misleading, but the signature value and the certificate (which you're putting in between the BEGIN/END CERTIFICATE) are two different things. In addition, the original question was about public keys, not certificate. In the XML Signature spec, the public key is split between modulus and exponent.
-
teemitzitrone almost 14 yearssince we don't have any information about the mysterious xml... see it as an example. will modify the code to reflect that more clearly
-
Bruno almost 14 yearsSure, but if it's the RSAKeyValue XML DSig format, you still need to reconstruct the ASN.1 structure and re-encode in into base-64 before putting it in between BEGIN/END PUBLIC KEY. It's not just a matter of extracting the text from the XML. @mario's pointers would help then.
-
teemitzitrone almost 14 yearsi always try to "think simple" if there is no clear definition. but of course your right.