A mi me paso lo mismo, pero envie un correo al proveedor y me enviaron la solucion. Te la paso, solo que Yo estoy desarrollando en PHP, espero te sirva:
Es requerido que se tenga la llave privada en la siguiente estructura, (Este es el formato XML de como debiera obtenerse el contenido de la llavePrivada):
Código: Seleccionar todo
<RSAKeyValue>
<Modulus>...</Modulus>
<Exponent>...</Exponent>
<P>...</P>
<Q>...</Q>
<DP>...</DP>
<DQ>...</DQ>
<InverseQ>...</InverseQ>
<D>...</D>
</RSAKeyValue>
y esto lo tendrías que pasar a base 64.
Paso 1: Generar archivos PEM a partir de los key y cer (si ya generabas CFD, esto ya lo sabes hacer), (Se hace sólo una vez al instalar el sello del cliente en nuestro sistema):
Código: Seleccionar todo
<?php
system('openssl x509 -in 00001000000201532020.cer -inform DER -out 00001000000201532020.cer.pem -outform PEM');
system('openssl pkcs8 -in mars7001114w6_1207111111s.key -inform DER -passin pass:xxxxxx -out mars7001114w6_1207111111s.key.pem -outform PEM'); ?>
Esto genera los archivos 00001000000201532020.cer.pem y mars7001114w6_1207111111s.key.pem que ya todos conocemos y que son los que se están usando actualmente para el "sellado" del XML.
(Ahora, esto es lo nuevo):
Paso 2: Obtener los datos internos de la llave privada, Con el siguiente código en php:
Código: Seleccionar todo
<?php
$Comando = "openssl rsa -inform PEM -outform PEM -in mars7001114w6_1207111111s.key.pem -out 1.txt -text";
?>
El comando anterior genera un archivo de texto plano (1.txt) con la siguiente información:
Código: Seleccionar todo
Private-Key: (1024 bit) modulus: 00:9c:d3:00:13:f9:f7:7f:58:40:16:20:63:13:e2: a7:91:75:42:ca:17:1a:0a:e7:1f:81:5c:6f:c2:49: f2:ed:60:3c:7c:57:8b:c6:c7:37:58:d1:bd:40:40: e6:a8:9c:c0:7c:4d:6a:23:f7:ae:ab:d3:e6:ce:6a: 05:b0:c7:98:14:6d:ef:9b:e5:c2:d8:17:1f:13:f0: d9:5d:ad:42:a3:d4:4e:b6:4d publicExponent: 65537 (0x10001) privateExponent: 7a:d0:99:26:27:d0:47:8e:59:41:fa:c3:1c:c3:97: 23:36:41:33:1e:ee:65:6c:67:03:ce:5e:85:bc:2b: d3:1f:be:57:42:4b:ee:21:6a:35:2b:00:2c:a5:3f: 28:0e:9b:8a:e2:d7:e7:ff:7f:cc:04:3b:b2:33:ca: e7:03:36:45:a9:fe:95:01 prime1: 00:ce:75:67:31:cf:96:0b:c5:0b:9f:45:67:f1:4b:
21:d7:88:e1:b0:76:6f:6c:5c:e5:66:8c:00:21:ed: 01:da:2b:76:18:a6:7d:12:12:98:56:a0:22:c9:7d: 73:8f:f6:74:51 prime2: 00:c2:75:06:18:aa:6b:26:7c:1a:fa:d0:03:36:4c: 31:ca:3a:0f:3c:0a:e6:f3:54:20:d6:2a:77:1a:e5: 71:5b:11:ce:2d:28:bf:19:ed:58:96:fc:62:24:e2: da:31:b0:4f:3d exponent1: 7b:64:7d:bd:ae:84:ce:1a:01:9d:3a:7d:2a:20:ae: 64:44:16:27:16:51:f7:e0:f9:96:35:7c:6a:ca:8a: 15:26:be:99:73:00:2c:aa:62:73:fb:97:6e:f7:54: 97:29:44:51 exponent2: 0e:31:dc:b7:12:39:a0:25:8f:12:9f:fc:9c:0a:14: ce:a6:d6:90:09:33:36:ed:4c:5c:e5:7f:f7:09:ed: d8:85:44:77:6d:94:4e:4e:e5:d6:bc:62:d5:63:ca: dd:87:b1:41 coefficient: 55:43:8b:f1:e1:c0:9e:59:65:06:ce:0f:6d:ec:53: 74:fa:88:ad:83:c3:00:0a:f4:f2:8c:6a:09:84:61: 27:3c:7f:63 -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQCc01kT+fd/WEAWIGMT4qeRdULKFxoK5x+BXG/CSfLtYDx8V4vG xzdY0b1AQPQnmRoHSJB30X3yFbJQZmRlQ6TWRSrn/PtZ/QXSyR/5q+SZGGMkps80 UNolceaonMB8TWoj966r0+bOagWwx5gUbe+b5cLYFx8T8NldrUKj1E62TQIDAQAB AoGAetCZJifQR45ZQfrDHMOX7zYhxBorbvZpmelGLKW09Wk0dTwqXtWM5qX6y+MS UiB4XdPaL7uEIp4TMxu87AD5iQpQpHsQiPTi6OU+IzZBMx7uZWxnA85ehbwr0x++ UiB4XdPaL7uEIp4TMxu87AD5iQpQpHsQiPTi6OU+IzZBMx7uZWxnA85ehbwr0x++9+D5ljV8asqKTOMr7q7Qh4/Q6mG7smc/FSa+mXMALKpic/uXbvdUlylEUQJADjHc txI5oCWPEp/8nAoUzqbWkAkzNu1MXOV/9wnt2IVEd22UTk7l1rxi1WPKUouKMWG4 EXxx6xOhVm/43Yex KA6biuLX5/9/zAQ7sjPK5wM2Ran lBs4PbexTdPqIrYPDJAr08oxqCYRhg6Os JNIUov9QKBl1czFpR9yiBguZBmmKtxvFnZrXJzx/Yw== -----END RSA PRIVATE KEY-----
Esto lo guardo en la variable $LLaveCertif.
Paso 3: Extraer los datos de cada "modulo". Guardando en variables, la informacion de cada "modulo" del archivo obtenido. Por ejemplo:
Código: Seleccionar todo
$Modulus = "00:9c:d3:59:13:f9:f7:7f:58:40:16:20:63:13:e2:a7:91:75:42:ca:17:1a:0a:e7:1f:81:5c:6f:c2:49:f2: 3:a4:d6:45:2a:e7:fc:fb:59:fd:05:d2:c9:1f:f9:ab:e4:99:18:63:24:a6:cf:34:50:da:25:71:e6:a8:9c:c0:
7c:4d:6a:23:f7:ae:ab:d3:e6:ce:6a:05:b0:14:6d:ef:9b:e5:c2:d8:17:1f:13:f0:d9:5d:ad:42:a3:d4:4e:b6:4d";
$PrivateExponent = "7a:d0:99:26:27:d0:47:8e:59:41:fa:c3:1c:c3:97:ef:36:21:c4:1a:2b:6e:f6:69:99:e9:46:2c:a5:b4:f5:69:34:75:3c:2a:5e:d5:8c:e6:a5:fa:cb:e3:12:52:20:78:5d:d3:da:2f:bb:84:22:9e:13:33:1b:bc:ec:00::42:4b:ee:27:6a:35:2b:00:2c:a5:3f:28:0e:9b:8a:e2:d7:e7:ff:7f:cc:04:3b:b2:33:ca:e7:03:36:45:a9:fe:95:01";
etc...
Yo lo hago con esta funcion:
Código: Seleccionar todo
$Modulus = obtenerCadena($LLaveCertif, 'modulus:', 'publicExponent:');
....
function obtenerCadena($contenido,$inicio,$fin){
$r = explode($inicio, $contenido);
if (isset($r[1])){
$r = explode($fin, $r[1]);
$saltos = array("\r\n", "\n\r", "\n", "\r");
$r[0] = str_replace ($saltos, "", $r[0]);
$r[0] = str_replace(" ", "", $r[0]);
return $r[0];
}
return '';
}
Despues aplico otra funcion para eliminar los dos puntos ":" y convertir de hexadecimal a string y convertir a base64:
Código: Seleccionar todo
$Modulus = SSLDataExtractedToXMLData($Modulus, true);
...
function SSLDataExtractedToXMLData($SSLData, $JumpFirst)
{
$ArrVals = explode(":", $SSLData);
$a = "";
if ($JumpFirst)
{
$inicio = 1;
} else {
$inicio = 0;
}
for($i = $inicio; $i < count($ArrVals); $i = $i + 1)
{
$a = $a.hexToStr($ArrVals[$i]);
}
return base64_encode($a);
}
function hexToStr($hex)
{
$string='';
for ($i=0; $i < strlen($hex)-1; $i+=2)
{
$string .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $string;
}
Paso 4: Agrego las variables a la estructura requerida para la cancelacion
Código: Seleccionar todo
$KeyInXML = base64_encode("<RSAKeyValue><Modulus>".[u]$Modulus[/u]."</Modulus><Exponent>".[u]$PublicExponent[/u]."</Exponent><P>".[u]$Prime1[/u]."</P><Q>".[u]$Prime2[/u]."</Q><DP>".[u]$Exponent1[/u]."</DP><DQ>".[u]$Exponent2[/u]."</DQ><InverseQ>".[u]$Coefficient[/u]."</InverseQ><D>".[u]$PrivateExponent[/u]."</D></RSAKeyValue>");
echo "<br>KeyInXML base64: " . $KeyInXML . "<br><br>";
(Y al final guardo el resultado de este proceso en un campo de mi base de datos, y asi lo utilizo cada que necesito hacer una cancelacion, "pegandoselo" al requerimiento del web-service para cancelacion)...
Cuando voy a cancelar a "$xml" le asigno el Dato que guarde anteriormente con el XML base64 de la llave privada.
Código: Seleccionar todo
//<Funcion cancelarComprobante
$params = array(
"xmlCancelacion" => $xml,
"usuario" => $user,
"password" => $pw
);
$resultado = $client->call("cancelarComprobante", $params, $mynamespace);
Y con eso ya me funciono correctamente la Cancelacion del CFDI con dicho web-service.
Espero te sirva.
Saludos...