5

私はあらゆる場所 (MSDN、Stackoverflow、ブログなど) を調べて、次のパターンを考え出しました。

  1. クライアントは、SMIME 標準と互換性のある証明書をサーバーに要求します。(AD 証明書サービス テンプレートの部分は失われます)

  2. サーバーは PKCS10 要求を受信して​​変更するか、API を使用して、正しいテンプレートを使用して登録されていることを確認します

  3. サーバーが応答を生成し、それがクライアントに送信されます

  4. クライアントは応答を受け入れ、登録を完了します。

ノート

ここでは Windows クライアントで .NET を使用していますが、このプロセスを十分に一般的なものにして、OSX のユーザーが組み込みのキーチェーンまたは OpenSSL を使用して証明書を要求し、証明書について言及することなく証明書を要求できるようにしたいと考えています。 EKU のテンプレート。

私の目標は、サーバーでリクエストを変更し、結果をクライアントに送り返すことです。

これは私がこれまでに試みたものです。

 class Program
   {
    private const int CC_DEFAULTCONFIG = 0;
    private const int CC_UIPICKCONFIG = 0x1;
    private const int CR_IN_BASE64 = 0x1;
    private const int CR_IN_FORMATANY = 0;
    private const int CR_IN_PKCS10 = 0x100;
    private const int CR_DISP_ISSUED = 0x3;
    private const int CR_DISP_UNDER_SUBMISSION = 0x5;
    private const int CR_OUT_BASE64 = 0x1;
    private const int CR_OUT_CHAIN = 0x100;
    private static string requestText = "";

    static string SMIMEEncrypt = "1.3.6.1.4.1.311.21.8.4946465.16405226.12930948.10533807.2139545.33.10793632.14573168";
    static string SMIMESign    = "1.3.6.1.4.1.311.21.8.4946465.16405226.12930948.10533807.2139545.33.5005369.11644649";


    enum FullResponsePropertyPropID
    {
        FR_PROP_NONE =0,
        FR_PROP_FULLRESPONSE =1,
        FR_PROP_STATUSINFOCOUNT=2,
        FR_PROP_BODYPARTSTRING=3,
        FR_PROP_STATUS=4,
        FR_PROP_STATUSSTRING=5,
        FR_PROP_OTHERINFOCHOICE=6,
        FR_PROP_FAILINFO=7,
        FR_PROP_PENDINFOTOKEN=8,
        FR_PROP_PENDINFOTIME=9,
        FR_PROP_ISSUEDCERTIFICATEHASH=10,
        FR_PROP_ISSUEDCERTIFICATE=11,
        FR_PROP_ISSUEDCERTIFICATECHAIN=12,
        FR_PROP_ISSUEDCERTIFICATECRLCHAIN=13,
        FR_PROP_ENCRYPTEDKEYHAS=14,
        FR_PROP_FULLRESPONSENOPKCS7=15,
        FR_PROP_CAEXCHANGECERTIFICATEHASH=16,
        FR_PROP_CAEXCHANGECERTIFICATE=17,
        FR_PROP_CAEXCHANGECERTIFICATECHAIN=18,
        FR_PROP_CAEXCHANGECERTIFICATECRLCHAIN=19,
        FR_PROP_ATTESTATIONCHALLENGE=20,
        FR_PROP_ATTESTATIONPROVIDERNAME=21
    }
    public static void Main()
    {
        int PROPTYPE_BINARY = 3;
        //// Client
        //var objEnroll = new CX509Enrollment();
        //string RequestStr = objEnroll.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64);

        ////TEST SERVER
        //CCertRequest  CertRequest = new CCertRequest ();
        // int Disposition = CertRequest.Submit(CR_IN_BASE64, RequestStr, string.Empty, @"caName");


        string subjectName = "E= makerofthings7@me.com, CN = makerofthings7@me.com, OU = Technology, L= NYC, S= NY, C=US";
        string friendlyName = "makerofthings7 - Encrypt...";
        string templateName = SMIMEEncrypt;

        //  --------------
        //  --------------
        // Client
        //  --------------
        //  --------------

        // 1. Call any initialization method implemented by the IX509Enrollment object.
        CX509Enrollment req1 = new CX509Enrollment();
        req1.Initialize(X509CertificateEnrollmentContext.ContextUser);

        // 2. Call the CreateRequest method.
        string req1a = req1.CreateRequest();
        // 3. Store the request for a period of time such as days or weeks.

        // --------------
        // --------------
        // Server
        // --------------
        // --------------

        // 4. Call the Initialize method to create a request object when you are ready to enroll.
        var reqServer = new CX509CertificateRequestPkcs10();
        reqServer.InitializeFromCertificate(
            X509CertificateEnrollmentContext.ContextUser,
            req1a  //    Beginning with Windows 7 and Windows Server 2008 R2, you can specify 
                   //    a certificate thumb print or serial number rather than an encoded certificate
            );

        // Add template (Sign or Encrypt or Both)
        CX509ExtensionTemplateName tmplateData2 = new CERTENROLLLib.CX509ExtensionTemplateName();
        tmplateData2.InitializeEncode(templateName);
        var tmplatex5092 = (IX509Extension)tmplateData2;
        reqServer.X509Extensions.Add(new CX509Extension(tmplatex5092));

        // -----------------------------------------------------------------------------------
        // The following properties can be set before calling the Encode method:
        //    AlternateSignatureAlgorithm
        //    ClientId
        //    HashAlgorithm
        //    ParentWindow
        //    RenewalCertificate
        //    Silent
        reqServer.Silent = true;
        //    SuppressDefaults
        //    ContextMessage
        //
        // The following properties must be set, if at all, before calling the Encode method:
        //    CspInformations
        //    KeyContainerNamePrefix
        //    SmimeCapabilities
        reqServer.SmimeCapabilities = true;
        //    Subject
        CX500DistinguishedName objName2 = new CX500DistinguishedName();
        objName2.Encode(subjectName, X500NameFlags.XCN_CERT_NAME_STR_NONE);
        reqServer.Subject = objName2;
        // -----------------------------------------------------------------------------------
        reqServer.Encode();
        //reqServer.get_RawDataToBeSigned();

        // InitializeFromRequest() does the following:
        //    Verifies that the request is a PKCS #10, PKCS #7, or CMC request object.
        //    Retrieves the template, if any, associated with the request.
        //    Validates the template.
        //    Sets the request object on the Request property.
        //    Retrieves the signature count, issuance policies, and application policies from the template.
        //    Retrieves the renewal certificate if one exists.
        CX509Enrollment enroll2 = new CX509Enrollment();
        enroll2.InitializeFromRequest(reqServer);

        // Enroll()
        // -  The method may create a key pair if necessary. Depending on how you initialize the enrollment
        //    object and on what properties you set, there may be no need to create a key pair. For example, 
        //    if you are renewing a certificate by using an existing key, or if the IX509PrivateKey object 
        //    associated with the certificate request represents an existing key, this method does not create a new key pair.
        enroll2.Enroll();

        // ALTERNATE IMPLEMENTATION
        //CERTCLILib.ICertRequest3 serverReq2 = new CCertRequest();
        //var retVAl2 = serverReq2.Submit(CR_IN_ENCODEANY, reqr3.Request.get_RawData(), string.Empty, "a.issue01.bitclear.us\\Secure Issuer 01a-001");
        //var serverSignedResponse = serverReq2.GetCertificate(CR_OUT_BASE64HEADER);
        //var certwChain2 = serverReq2.GetCertificate(CR_OUT_BASE64HEADER | CR_OUT_CHAIN);



        //  --------------
        //  --------------
        // Client
        //  --------------
        //  --------------

        // 5.Populate the request object from your stored request.
        CCertRequest CertRequest = new CCertRequest();
        var disposition3 = CertRequest.RetrievePending(1, ""); // pretend we checked the server for result status, and it was OK

        // If Issued...
        if (true)
        {
            // 6. Call the InstallResponse method.
            X509CertificateEnrollmentContext context = X509CertificateEnrollmentContext.ContextUser;

            CX509Enrollment enroll3 = new CX509Enrollment();
            string serverSignedResponse = CertRequest.GetFullResponseProperty(
               (int) FullResponsePropertyPropID.FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64).ToString();
            enroll3.Initialize(context);

            // InstallResponse()
            // -  Retrieves the dummy certificate from the external store.
            // -  Retrieves the certificate contained in the response and installs it on the computer.
            // -  Copies properties from the dummy certificate in the external store onto the newly installed certificate in the personal store.
            enroll3.InstallResponse(
                InstallResponseRestrictionFlags.AllowNone
                | InstallResponseRestrictionFlags.AllowUntrustedRoot         //Perform the same action as the AllowUntrustedCertificate flag 
                // but also installs the certificate even if the certificate chain 
                //  cannot be built because the root is not trusted.
                , serverSignedResponse, EncodingType.XCN_CRYPT_STRING_BASE64
                , string.Empty // If there is a password, clear it from memory when you have finished using it by calling the SecureZeroMemory function
                );

            // CreatePFX()
            // - Opens the certificate store in memory for the default provider.
            // - Adds the installed certificate to the store or builds the certificate chain adds a link to it.
            // - Exports the certificate and the private key to a PFX message depending on the export options specified.
            // - Encodes the exported message by using DER.
            string pfx = enroll3.CreatePFX(
                "q", // When you have finished using the password, clear it from memory by calling the SecureZeroMemory function.
                PFXExportOptions.PFXExportChainNoRoot);
        }
4

0 に答える 0