web-dev-qa-db-fra.com

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

J'ai besoin de créer un certificat auto-signé (pour le cryptage local - ce n'est pas utilisé pour sécuriser les communications), en utilisant C #. 

J'ai vu des implémentations qui utilisent P/Invoke avec Crypt32.dll , mais elles sont compliquées et il est difficile de mettre à jour les paramètres - et j'aimerais aussi éviter P/Invoke si possible .

Je n'ai pas besoin de quelque chose qui est multi-plateforme - fonctionner uniquement sous Windows me suffit.

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

43
Guss

Cette implémentation utilise l'objet COM CX509CertificateRequestCertificate (et amis - doc. MSDN ) de certenroll.dll pour créer une demande de certificat auto-signée et la signer. 

L'exemple ci-dessous est assez simple (si vous ignorez les éléments de COM qui se déroulent ici) et il y a quelques parties du code qui sont vraiment optionnelles (comme EKU) qui sont néanmoins utiles et faciles à utiliser. s'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 X509Store ou exporté à l'aide des méthodes X509Certificate2.

Pour une gestion entièrement gérée et non liée à la plate-forme Microsoft, et si les licences de Mono vous conviennent, vous pouvez consulter X509CertificateBuilder from Mono.Security . Mono.Security est autonome chez Mono, en ce sens qu'il n'a pas besoin du reste de Mono pour s'exécuter et peut être utilisé dans tout environnement .Net conforme (par exemple, l'implémentation de Microsoft).

61
Guss

Une autre option consiste à utiliser la bibliothèque des extensions de sécurité CLR de CodePlex, qui implémente une fonction d'assistance pour générer des certificats x509 autosignés:

X509Certificate2 cert = CngKey.CreateSelfSignedCertificate(subjectName);

Vous pouvez également regarder l'implémentation de cette fonction (dans CngKeyExtensionMethods.cs ) pour voir comment créer explicitement le certificat auto-signé en code managé.

17
dthorpe

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

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-----");
    }
}
11
Duncan Smart

Vous pouvez utiliser la bibliothèque gratuite PluralSight.Crypto pour simplifier la création par programme de certificats x509 autosigné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 version ultérieure.

9
dthorpe

Voici la version de Powershell sur la création d'un certificat. Vous pouvez l'utiliser en exécutant la commande . Vérifiez https://technet.Microsoft.com/itpro/powershell/windows/pkiclient/new-selfsignedcertificate

Éditer: j'ai oublié de dire qu'après la création du certificat, vous pouvez utiliser le programme Windows "gérer les certificats d'ordinateur" pour exporter le certificat au format .CER ou d'un autre type.

0
Roger Deep