87 votes

Comment puis-je créer un certificat auto-signé en utilisant C# ?

Je dois créer un certificat auto-signé (pour le cryptage local - il n'est pas utilisé pour sécuriser les communications), en utilisant C#.

J'ai vu certaines implémentations qui utilisent P/Invocation con Crypt32.dll mais ils sont compliqués et il est difficile de mettre à jour les paramètres - et je voudrais également éviter P/Invoke si possible.

Je n'ai pas besoin de quelque chose qui soit multiplateforme - fonctionner uniquement sous Windows me suffit.

Idéalement, le résultat serait un objet X509Certificate2 que je pourrais utiliser pour insérer dans le magasin de certificats de Windows ou exporter vers un fichier de type PFX fichier.

99voto

Duncan Smart Points 9195

Depuis .NET 4.7.2, vous pouvez créer des certificats auto-signés à l'aide de la fonction CertificatRequest de System.Security.Cryptography.X509Certificates. .

Par exemple :

using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public class CertificateUtil
{
    static void MakeCert()
    {
        var ecdsa = ECDsa.Create(); // generate asymmetric key pair
        var req = new CertificateRequest("cn=foobar", ecdsa, HashAlgorithmName.SHA256);
        var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));

        // Create PFX (PKCS #12) with private key
        File.WriteAllBytes("c:\\temp\\mycert.pfx", cert.Export(X509ContentType.Pfx, "P@55w0rd"));

        // Create Base 64 encoded CER (public key only)
        File.WriteAllText("c:\\temp\\mycert.cer",
            "-----BEGIN CERTIFICATE-----\r\n"
            + Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)
            + "\r\n-----END CERTIFICATE-----");
    }
}

81voto

Guss Points 6512

Cette mise en œuvre utilise le CX509CertificateRequestCertificate Objet COM (et ses amis) Document MSDN ) de certenroll.dll pour créer une demande de certificat auto-signé et le signer.

L'exemple ci-dessous est assez simple (si vous ne tenez pas compte de la partie COM qui se déroule ici) et il y a quelques parties du code qui sont vraiment facultatives (comme EKU) mais qui sont néanmoins utiles et faciles à adapter à votre utilisation.

public static X509Certificate2 CreateSelfSignedCertificate(string subjectName)
{
    // create DN for subject and issuer
    var dn = new CX500DistinguishedName();
    dn.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_NONE);

    // create a new private key for the certificate
    CX509PrivateKey privateKey = new CX509PrivateKey();
    privateKey.ProviderName = "Microsoft Base Cryptographic Provider v1.0";
    privateKey.MachineContext = true;
    privateKey.Length = 2048;
    privateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE; // use is not limited
    privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
    privateKey.Create();

    // Use the stronger SHA512 hashing algorithm
    var hashobj = new CObjectId();
    hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
        ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, 
        AlgorithmFlags.AlgorithmFlagsNone, "SHA512");

    // add extended key usage if you want - look at MSDN for a list of possible OIDs
    var oid = new CObjectId();
    oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server
    var oidlist = new CObjectIds();
    oidlist.Add(oid);
    var eku = new CX509ExtensionEnhancedKeyUsage();
    eku.InitializeEncode(oidlist); 

    // Create the self signing request
    var cert = new CX509CertificateRequestCertificate();
    cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, "");
    cert.Subject = dn;
    cert.Issuer = dn; // the issuer and the subject are the same
    cert.NotBefore = DateTime.Now;
    // this cert expires immediately. Change to whatever makes sense for you
    cert.NotAfter = DateTime.Now; 
    cert.X509Extensions.Add((CX509Extension)eku); // add the EKU
    cert.HashAlgorithm = hashobj; // Specify the hashing algorithm
    cert.Encode(); // encode the certificate

    // Do the final enrollment process
    var enroll = new CX509Enrollment();
    enroll.InitializeFromRequest(cert); // load the certificate
    enroll.CertificateFriendlyName = subjectName; // Optional: add a friendly name
    string csr = enroll.CreateRequest(); // Output the request in base64
    // and install it back as the response
    enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
        csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); // no password
    // output a base64 encoded PKCS#12 so we can import it back to the .Net security classes
    var base64encoded = enroll.CreatePFX("", // no password, this is for internal consumption
        PFXExportOptions.PFXExportChainWithRoot);

    // instantiate the target class with the PKCS#12 data (and the empty password)
    return new System.Security.Cryptography.X509Certificates.X509Certificate2(
        System.Convert.FromBase64String(base64encoded), "", 
        // mark the private key as exportable (this is usually what you want to do)
        System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable
    );
}

Le résultat peut être ajouté à un magasin de certificats à l'aide de la fonction X509Store ou exporté en utilisant le X509Certificate2 méthodes.

Pour une solution entièrement gérée et non liée à la plateforme de Microsoft, et si vous êtes d'accord avec les licences de Mono, vous pouvez vous tourner vers Générateur de certificat X509 de Mono.Security . Mono.Security est autonome par rapport à Mono, en ce sens qu'il n'a pas besoin du reste de Mono pour fonctionner et peut être utilisé dans n'importe quel environnement .Net conforme (par exemple, la mise en œuvre de Microsoft).

20voto

dthorpe Points 23314

Une autre option consiste à utiliser le Bibliothèque d'extensions de sécurité CLR de CodePlex, qui implémente une fonction d'aide pour générer des certificats X.509 auto-signés :

X509Certificate2 cert = CngKey.CreateSelfSignedCertificate(subjectName);

Vous pouvez également examiner l'implémentation de cette fonction (dans la section CngKeyExtensionMethods.cs ) pour voir comment créer le certificat auto-signé explicitement dans le code géré.

11voto

dthorpe Points 23314

Vous pouvez utiliser l'outil gratuit Bibliothèque PluralSight.Crypto pour simplifier la création programmatique de certificats X.509 auto-signés :

    using (CryptContext ctx = new CryptContext())
    {
        ctx.Open();

        X509Certificate2 cert = ctx.CreateSelfSignedCertificate(
            new SelfSignedCertProperties
            {
                IsPrivateKeyExportable = true,
                KeyBitLength = 4096,
                Name = new X500DistinguishedName("cn=localhost"),
                ValidFrom = DateTime.Today.AddDays(-1),
                ValidTo = DateTime.Today.AddYears(1),
            });

        X509Certificate2UI.DisplayCertificate(cert);
    }

PluralSight.Crypto nécessite .NET 3.5 ou plus.

6voto

0909EM Points 922

Si cela peut aider quelqu'un d'autre, j'ai eu besoin de générer un certificat de test au format PEM (j'avais donc besoin des fichiers crt et key), en utilisant la méthode suivante réponse de Duncan Smart j'ai obtenu le résultat suivant...

public static void MakeCert(string certFilename, string keyFilename)
{
    const string CRT_HEADER = "-----BEGIN CERTIFICATE-----\n";
    const string CRT_FOOTER = "\n-----END CERTIFICATE-----";

    const string KEY_HEADER = "-----BEGIN RSA PRIVATE KEY-----\n";
    const string KEY_FOOTER = "\n-----END RSA PRIVATE KEY-----";

    using var rsa = RSA.Create();
    var certRequest = new CertificateRequest("cn=test", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

    // We're just going to create a temporary certificate, that won't be valid for long
    var certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(1));

    // export the private key
    var privateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks);

    File.WriteAllText(keyFilename, KEY_HEADER + privateKey + KEY_FOOTER);

    // Export the certificate
    var exportData = certificate.Export(X509ContentType.Cert);

    var crt = Convert.ToBase64String(exportData, Base64FormattingOptions.InsertLineBreaks);
    File.WriteAllText(certFilename, CRT_HEADER + crt + CRT_FOOTER);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X