3 Stimmen

Programmatisch mit einer Zertifizierungsstelle kommunizieren

Ich arbeite programmatisch mit Zertifikaten und kommuniziere mit einer Zertifizierungsstelle. Ich habe mit den COM-Objekten CertClient und CertEnroll in C# auf Windows 2008R2 gearbeitet.

Ich kann eine Anfrage erstellen und erhalte ein Zertifikat von der CA zurück. Ich habe mit diesem Beispiel begonnen: http://blogs.msdn.com/b/alejacma/archive/2008/09/05/how-to-create-a-certificate-request-with-certenroll-and-net-c.aspx

Ich habe zwei Probleme, die ich nicht lösen kann. Erstens: Wie kann ich auf den privaten Schlüssel zugreifen, der zur Erstellung des Zertifikats verwendet wurde? Die Methoden, die Teil der IX509PrivateKey-Schnittstelle sind, scheinen in meiner Testumgebung nicht zu funktionieren. Die Anfrage, die ich an die CA stelle, unterscheidet sich vom privaten Schlüssel, richtig?

Das zweite Problem ist, dass ich nicht herausfinden kann, wie ich bei der Anforderung eines Zertifikats ein Zertifikat des Registrierungsagenten angeben kann. Die älteren Versionen dieser API hatten eine Methode, SetSignerCertificate, die verwendet wurde. Ich kann keine Entsprechung in der neuen API finden.

5voto

Mitch Punkte 19936

Ein Beispiel für die Verwendung eines Enrollment Agent-Zertifikats finden Sie auf MSDN unter Antrag auf Registrierung im Namen eines anderen Benutzers erstellen . Das Zertifikat wird in dem von Ihnen angegebenen Zertifikatspeicher installiert, und Sie können den privaten Schlüssel wie jedes andere installierte Zertifikat verwenden.

Vollständiges Beispiel:

// Add references to CERTENROLL (CertEnroll 1.0 Type Library) 
// and CERTCLILib (CertCli 1.0 Type Library)
using CERTCLILib;
using CERTENROLLLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using X509KeyUsageFlags = CERTENROLLLib.X509KeyUsageFlags;

namespace TestSubmitEnrollment
{
    class Program
    {
        static void Main(string[] args)
        {
            string requesterName = @"DOMAIN\otherUser";
            string caName = @"CA1.DOMAIN.LOCAL\DOMAIN-CA1-CA";
            string template = "User";
            // signerCertificate's private key must be accessible to this process
            var signerCertificate = FindCertificateByThumbprint("3f817d138f32a9a8df2aa6e43b8aed76eb93a932");

            // create a new private key for the certificate
            CX509PrivateKey privateKey = new CX509PrivateKey();
            // http://blogs.technet.com/b/pki/archive/2009/08/05/how-to-create-a-web-server-ssl-certificate-manually.aspx
            privateKey.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
            privateKey.MachineContext = false;
            privateKey.Length = 2048;
            privateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
            privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_NONE;
            privateKey.Create();

            // PKCS 10 Request
            // we use v1 to avoid compat issues on w2k8
            IX509CertificateRequestPkcs10 req = (IX509CertificateRequestPkcs10)new CX509CertificateRequestPkcs10();
            req.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextUser, privateKey, template);

            // PKCS 7 Wrapper
            var signer = new CSignerCertificate();
            signer.Initialize(false, X509PrivateKeyVerify.VerifyAllowUI, EncodingType.XCN_CRYPT_STRING_BASE64_ANY, 
                Convert.ToBase64String(signerCertificate.GetRawCertData()));

            var wrapper = new CX509CertificateRequestPkcs7();
            wrapper.InitializeFromInnerRequest(req);
            wrapper.RequesterName = requesterName;
            wrapper.SignerCertificate = signer;

            // get CSR
            var enroll = new CX509Enrollment();
            enroll.InitializeFromRequest(wrapper);
            var csr = enroll.CreateRequest();
            //File.WriteAllText("csr.p7b", csr);

            // submit
            const int CR_IN_BASE64 = 1, CR_OUT_BASE64 = 1;
            const int CR_IN_PKCS7 = 0x300;
            ICertRequest2 liveCsr = new CCertRequest();
            var disposition = (RequestDisposition)liveCsr.Submit(CR_IN_BASE64 | CR_IN_PKCS7, csr, null, caName);

            if (disposition == RequestDisposition.CR_DISP_ISSUED)
            {
                string resp = liveCsr.GetCertificate(CR_OUT_BASE64);
                //File.WriteAllText("resp.cer", resp);

                // install the response
                var install = new CX509Enrollment();
                install.Initialize(X509CertificateEnrollmentContext.ContextUser);

                install.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedRoot,
                    resp, EncodingType.XCN_CRYPT_STRING_BASE64_ANY, null);
            }
            else
            {
                Console.WriteLine("disp: " + disposition.ToString());
            }
            Console.WriteLine("done");
            Console.ReadLine();
        }

        private enum RequestDisposition
        {
            CR_DISP_INCOMPLETE = 0,
            CR_DISP_ERROR = 0x1,
            CR_DISP_DENIED = 0x2,
            CR_DISP_ISSUED = 0x3,
            CR_DISP_ISSUED_OUT_OF_BAND = 0x4,
            CR_DISP_UNDER_SUBMISSION = 0x5,
            CR_DISP_REVOKED = 0x6,
            CCP_DISP_INVALID_SERIALNBR = 0x7,
            CCP_DISP_CONFIG = 0x8,
            CCP_DISP_DB_FAILED = 0x9
        }

        private static X509Certificate2 FindCertificateByThumbprint(string sslCertThumbprint)
        {
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            try
            {
                store.Open(OpenFlags.ReadOnly);

                var certs = store.Certificates.Find(X509FindType.FindByThumbprint, sslCertThumbprint, true);
                if (certs.Count > 0)
                {
                    return certs[0];
                }
                else
                {
                    throw new KeyNotFoundException();
                }
            }
            finally
            {
                store.Close();
            }
        }

        // we re-declare this to account for backcompat to 2k8
        [ComImport, Guid("884E2042-217D-11DA-B2A4-000E7BBB2B09")]
        class CX509CertificateRequestPkcs10
        {
        }
    }
}

0voto

Die Anfrage, die ich an die CA stelle, unterscheidet sich vom privaten Schlüssel, richtig?

Sie übergeben nur den öffentlichen Schlüssel an die CA.

Ich kann nicht herausfinden, wie ich bei der Beantragung eines Zertifikats ein Zertifikat für den Registrierungsagenten angeben soll.

Sie müssen den PKCS10 in ein CMS/CMC verpacken. Schauen Sie hier nach https://www.rfc-editor.org/rfc/rfc5272

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X