views:

439

answers:

5

How convert RSA public key, from XML to PEM (PHP)?

+1  A: 

There is no standard for storing RSA public keys in XML. So the manner of conversion will depend on the XML you have.

Borealid
There is a W3C recommendation that specifies this: http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
Bruno
@Bruno: Post an answer!
GregS
@GregS, OK, I've just done that.
Bruno
A: 

Maybe you should have a look here:

http://stackoverflow.com/questions/3368137/how-can-i-create-a-cryptrsa-object-from-modulus-exponent-and-private-exponent

Extract the two base64-encoded strings, convert and pass to PEAR::Crypt_RSA, then export as text file, then openssl convert?

http://www.mail-archive.com/[email protected]/msg17007.html

mario
+1  A: 

we know

.pem - (Privacy Enhanced Mail) Base64 encoded DER certificate, enclosed between "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----"

X.509

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.

XML_Signature

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-----";
maggie
Maybe 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.
Bruno
since we don't have any information about the mysterious xml... see it as an example. will modify the code to reflect that more clearly
maggie
Sure, 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.
Bruno
i always try to "think simple" if there is no clear definition. but of course your right.
maggie
+2  A: 

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).

Bruno
A: 

Here's an example of how to read XML RSA keys in PHP:

http://www.frostjedi.com/phpbb/viewtopic.php?f=46&amp;t=18085

fruzer