En este post te voy a explicar como puedes generar un archivo .Pfx a partir de la contraseña, el archivo .key y el archivo .cer con la librería Chilkat y C#.
Antes de empezar.
- El ejemplo está codificado en Windows.
- El ejemplo usa los certificados generados para facturación electrónica en México (SHA256/RSA 2048 bits).
- Chilkat es un componente de paga, puedes requerir de una clave de licencia válida.
- Chilkat tiene un periodo de 30 días de prueba.
- Chilkat requiere de Visual C++ Redistribuible.
- Se requieren permisos de lectura y escritura en disco para la creación del archivo .Pfx.
- Chilkat es multiplataforma y compatible con DotNet Core.
- Puedes descargar el Package Nuget aquí, o los binarios en este vínculo.
Primeros pasos.
- Obvio, debes descargar los componentes, ya sea descargándolos manualmente o con Nuget.
- Necesitas generar una ruta temporal de archivo, si solo necesitas los bytes del certificado. En el caso de que requieras guardar el archivo Pfx físico, necesitas saber con anticipación donde será guardado.
- Necesitas tener los bytes del archivo .key y .cer asignados en variables. También es necesaria la contraseña del certificado en texto plano.
- Creación de objetos PrivateKey y Cert. Estos dos objetos se componen a partir de los 3 insumos antes mencionados.
El código.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Globalization; | |
using System.IO; | |
using System.Security.Cryptography.X509Certificates; | |
using Chilkat; | |
namespace HappyDevops.ChilkatPfxExample | |
{ | |
class Program | |
{ | |
static void Main() | |
{ | |
//El archivo de pruebas es un certificado de pruebas, viejo y caduco. | |
var password = "12345678a"; | |
var certFile = "MIIF0TCCA7mgAwIBAgIUMjAwMDEwMDAwMDAzMDAwMjI4MTYwDQYJKoZIhvcNAQELBQAwggFmMSAwHgYDVQQDDBdBLkMuIDIgZGUgcHJ1ZWJhcyg0MDk2KTEvMC0GA1UECgwmU2VydmljaW8gZGUgQWRtaW5pc3RyYWNpw7NuIFRyaWJ1dGFyaWExODA2BgNVBAsML0FkbWluaXN0cmFjacOzbiBkZSBTZWd1cmlkYWQgZGUgbGEgSW5mb3JtYWNpw7NuMSkwJwYJKoZIhvcNAQkBFhphc2lzbmV0QHBydWViYXMuc2F0LmdvYi5teDEmMCQGA1UECQwdQXYuIEhpZGFsZ28gNzcsIENvbC4gR3VlcnJlcm8xDjAMBgNVBBEMBTA2MzAwMQswCQYDVQQGEwJNWDEZMBcGA1UECAwQRGlzdHJpdG8gRmVkZXJhbDESMBAGA1UEBwwJQ295b2Fjw6FuMRUwEwYDVQQtEwxTQVQ5NzA3MDFOTjMxITAfBgkqhkiG9w0BCQIMElJlc3BvbnNhYmxlOiBBQ0RNQTAeFw0xNjEwMjUyMTU0MTlaFw0yMDEwMjUyMTU0MTlaMIG9MR4wHAYDVQQDExVNQiBJREVBUyBESUdJVEFMRVMgU0MxHjAcBgNVBCkTFU1CIElERUFTIERJR0lUQUxFUyBTQzEeMBwGA1UEChMVTUIgSURFQVMgRElHSVRBTEVTIFNDMSUwIwYDVQQtExxMQU44NTA3MjY4SUEgLyBGVUFCNzcwMTE3QlhBMR4wHAYDVQQFExUgLyBGVUFCNzcwMTE3TURGUk5OMDkxFDASBgNVBAsUC1BydWViYV9DRkRJMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjHr4KeoEx3BdkQP93AuN4fKo0rCZQsd9RJGBzQFvhmPJjGaVP81OUORM+lCRllxZxATZCAIFPOT3jl5wYgtolGYWWrt1HoAiuja1LKDGKrYgph0qWYKYeuew10fTyV+AeSbx1jTKz1PAAak06hx4M0rvmdiGO/Kg00/0wKz5/L3ZIMXEj+Hgr0IGh/yUIy8m5aKf+9jwuNttm/xDoeW3A8pxuidPU1Z1vliaZs75n89hC9LNwshhoaF3AvXIsgLDeuh9WoMGSm0HrilP9umFnm3nGUESiJa15Ep7LbG4CIhZrrknSm4fyrPk9KAigqLYMJhRsRwfp2qncAnAA+FuSQIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQsFAAOCAgEAd7t48tgawC9aczrGYt+4GFRcjj1LVKV3NElG+VH2s51KPkKPLj2Sw6OiEOGd+49spxHj1VR5MFvJo/pEJLY3EuLTifC9YZZYC8pHNDiA/eSvKqW5JNzp5/rgs3qAG1GrfdNGuSD3FkqhDdB6tJYqzTc12IC7xEAhKXrWZYCqa+zb9ogtzrUVL3vRRLMpnGEHK2yx8dhvG35qjHEfXyuoBsWILrVmnPpDCFO/CCLQB1OuMti1mlir6voBN0L1EbFK30w2bEuVihAeVLX8vVfMq4ZPI7UTLnblGnN11CCqiZkWhhehYrMdCjb5thMkEA+CMlIaFJYp7pNkLxQd4Y5+r8pTrdxxyvpA51DIWdoxvwaOiz1bzZk6ElVY2rfxwyZaJ17cJ1jmS4Yb5P4h8+5zkmZnPmRqfmaVO3nsApLWP6A38ZBrwwss429PJMSpfeXKGysPsqwF0yP3blsM7Cw53393LSHGKNm2GgG0kcrHnbbku6z6fjBdXMQQ5vjPuMNyw/pe3PzQLVoNOrD5AOoZmSG2TI3DtY4edLdiGmNQjo3MmAMMq4s7lr4AELPWAZRbnOlD1nEWGLdRp1mViteDvXwBL9E98EB4K9xK21DvgJ6rzw/D9rX6epeANfoXazWC0iCYcBNXiPikApcW73a/Jl/WjkEwEdkL/jLj0KCep58="; | |
var keyFile = "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIAgEAAoIBAQACAggAMBQGCCqGSIb3DQMHBAgwggS9AgEAMASCBMh4EHl7aNSCaMDA1VlRoXCZ5UUmqErAbucRBAKNQXH8t14jAYpBDzQIJ3ARNPvtVfGybZjOF6+rDa3lO0L1E7y+kmPfx4QJBXq1pLcoe2OxuCcNcJO8AyzdutAztFDzrOpuqoUy30JragQAGtwBFv1YdGSQT/1ODyLfpAZ7jsg0JpFpWZoBEThn/5UlO2ixxf0v1jzq+Pzv+Doz1H5GLHKUxwBDfdVAaJ3OGSRkBI+GtXp+V5sT5CNh3i4Jn+G1BKllMDIDBN0wVnOQv6ovxRREYMLhb9dcTVX3xceZjQJ9Q9NvU1OEaxxPcPbELC9oPjbjZgnjEvG/tXrbU4hxFwzePh9zOyEmeNt2LLIkCAvpZ2A90Aeu4IBPwEYMvWg4DbaNtZRw85TbLds8cX6GtpB1ETHD6gemPs9Q1mLsF4zRGZsFXPLkHr1+Pg8egb26Wv5+FcUm8Pah5lIMI+rk+C7L2lgoGIeh/CdEioI5a/VkbjiiA/Akfw65fg1hksZe19lBsuF1uh3zA+LKYwia3YvgYTajNKHWlDv/PVHO/Nw1WKCbiX2rFG35HU3PGUVcNh9/n8+UdOqI/9l0+M/uMbkzdbDX/D/+bmAtzHmJGixyrLft+ZzX+wRP2LATUHdzWKYMmHMkSjZVQaWCOI1o58YWR4j6r4ZqNEXwliQ/GlEIpvkldOmCjhc/167sKkMctxHLU2XkCRag04RrhZsN7iAneg4QnjrbPRHYtfaaf+L6a+L9I4UBsxHYU5lnL4uPBKj81pDQ+6ueyaMS4ItgPQYt7wbJU/QvVxgJ3S0sGTgYzO3EEoqmncdyEzQfnifqcqyTNpttoHhT5ncEIOUs8PZ5IUN57KRg6htyAsg1/vs4Hkl8g3sSCjC5tlYYxkANvUuZnvDcBIVaiY4SBi6kg5wb6Jq2gVf0NiHdgLjyjK/Ox+XjKJ/E12VE5cy0RNN75jcMnNskhA9vQLmwFDKmJWxggNcrdbhcCTvZGU5DODxRTD2Ks5Z+SwWsadULc2XilHGEpRB63zh/VnyUCIIdJuonyu6sGS6PRhYms/mC/bVL7O6gmWC5qmZpbKxf/5kcRs/uSjwlCOlahcfjPyUl3YwquI5IXd5eeLJx3h6MzO2Q8BCTb5czs5xamOL7/lG7yjiGysXi+CV6Dzf0MlO8vDk7FQsOiAKn8Kd76sQUFo9stSE1CqcJ+RCVMefZnZd71ZiBX56zxJm2qT9VJJDeW330MYqPIq7W8quttm9Fo9/LscJNJzYw1YdaQJdim787ONqt06/FIUpIKsgT/3i6w+byD5LW80UaqIh4calKETF8/X045C1xxfSsLsVmXO4AZ1/goJGlm1LXkKaenCteMoH6U3E+0nFjrxvd1C9H83JKoFFN5cqwt78Vz4sRfQqqQuxmjtnmbxM1yR/zd3mG7q1QX2rVITkiK4bse0ky8pdrYDTW9bGA7CBntGO5xutdwUEBfTo7kQZ4SwLJmyT9a/9w7ruTG2sQNDCHawWVP6BB75UnckEmA0g2xogCgK+n8LajU1qulDvt/ZgVkS6pv9TpI3o6I27sfSfIVXntBNvRUwry9Fw4SrW0f0jj6TCYUoUETo23Zv0H84Vf06Pkmy3vEwGhHO823iM="; | |
var bytesKey = Convert.FromBase64String(keyFile); | |
var bytesCer = Convert.FromBase64String(certFile); | |
var pfxPath = GetNewTempPathPfx(); | |
var privateKey = ComposePrivateKeyComponent(bytesKey, password); | |
var cert = ComposeCertificateComponent(bytesCer, privateKey); | |
//Exportar en archivo certificado Pfx. | |
var success = cert.ExportToPfxFile(pfxPath, password, false); | |
Debug.Assert(success, "Error processing certificate.."); | |
var bytesPfx = File.ReadAllBytes(pfxPath); | |
File.Delete(pfxPath); | |
//Procesar archivo PFX | |
ProcessCertificate(bytesPfx, password); | |
Console.Read(); | |
} | |
private static void ProcessCertificate(byte[] bytesPfx, string password) | |
{ | |
var certificate2 = new X509Certificate2(bytesPfx, password); | |
Console.WriteLine($"Serial Number: {certificate2.SerialNumber}"); | |
Console.WriteLine($"SubjectName: {certificate2.SubjectName.Name}"); | |
Console.WriteLine($"NotBefore: {certificate2.NotAfter.ToString(CultureInfo.InvariantCulture)}"); | |
Console.WriteLine($"NotAfter: {certificate2.NotAfter.ToString(CultureInfo.InvariantCulture)}"); | |
Debug.Assert(certificate2.HasPrivateKey, "Invalid pfx file..."); | |
} | |
private static PrivateKey ComposePrivateKeyComponent(byte[] bytesKey, string password) | |
{ | |
var privateKey = new PrivateKey(); | |
privateKey.LoadPkcs8Encrypted(bytesKey, password); | |
return privateKey; | |
} | |
private static string GetNewTempPathPfx() | |
{ | |
return $"{Path.GetTempPath()}/{Guid.NewGuid()}.tmp"; | |
} | |
private static Cert ComposeCertificateComponent(byte[] bytesCert, PrivateKey privateKey) | |
{ | |
var cert = new Cert(); | |
cert.LoadFromBinary(bytesCert); | |
cert.SetPrivateKey(privateKey); | |
return cert; | |
} | |
} | |
} |
Últimas entradas de Gustavo Sánchez (ver todo)
- NVL in SQL Server - 2023-11-01
- ¿Que es Cake Build? - 2023-02-22
- #How to fix error: MSB4019: The imported project «Microsoft.Data.Tools.Schema.SqlTasks.targets» was not found - 2023-02-20