Verfahrensweise: Gegensignieren einer Nachricht

In diesem Beispiel wird eine CMS/PKCS #7-signierte Nachricht unter Verwendung von System.Security.Cryptography.Pkcs erstellt. Zuerst wird die Nachricht von einem einzelnen Signierer signiert, und anschließend wird diese Signatur von zwei weiteren Signierern gegensigniert. Die Signatur und Gegensignaturen dieser Nachricht werden anschließend überprüft.

Beispiel

In diesem Beispiel werden die folgenden Klassen verwendet:

Für das folgende Beispiel ist es erforderlich, dass der Zertifikatspeicher "My" drei Zertifikate mit öffentlichem Schlüssel mit den Antragstellernamen "MessageSigner1", "CounterSigner1" und "CounterSigner2" enthält und dass diese über zugeordnete private Schlüssel verfügen.

NoteHinweis:

Dieses Beispiel dient nur der Veranschaulichung. In Produktionsumgebungen kann ein anderes Modell verwendet werden, in dem Absender und Empfänger der Nachricht in verschiedenen Prozessen mit ihren eindeutigen Anmeldeinformationen des öffentlichen Schlüssels ausgeführt werden.

Richten Sie dieses Beispiel mithilfe des Dienstprogramms Makecert.exe ein; dies ist nur eine von vielen Möglichkeiten. Certificate Creation Tool (Makecert.exe) ist ein komfortables Dienstprogramm zum Generieren von Testzertifikaten. In einer Produktionsumgebung werden Zertifikate von einer Zertifizierungsstelle generiert.

Mithilfe der folgenden Makecert-Befehle werden die erforderlichen Zertifikate mit öffentlichem Schlüssel und die privaten Schlüssel generiert.

Makecert -n "CN=MessageSigner1" -ss My

Makecert -n "CN=CounterSigner1" -ss My

Makecert -n "CN=CounterSigner2" -ss My

// Copyright (c) Microsoft Corporation. All rights reserved. 
#region Using directives

using System;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;

#endregion

namespace CountersignAMessage
{
    class SignedCmsCountersigned
    {
        const String signerName = "MessageSigner1";
        const String countersignerName1 = "CounterSigner1";
        const String countersignerName2 = "CounterSigner2";

        static void Main(string[] args)
        {
            Console.WriteLine("System.Security.Cryptography.Pkcs " +
                "Sample: Single-signer multiple " +
                "countersigner signed and verified message.");
            //  The original message.

            const String msg = "The following is the approved corporate" +
                      " reorganization plan.";

            Console.WriteLine("\nOriginal message (len {0}): {1}  ",
                msg.Length, msg);

            //  Convert the message to an array of bytes for signing.
            Encoding unicode = Encoding.Unicode;
            byte[] msgBytes = unicode.GetBytes(msg);

            Console.WriteLine("\n\n------------------------------");
            Console.WriteLine("     SETUP OF CREDENTIALS     ");
            Console.WriteLine("------------------------------\n");

            X509Certificate2Collection signerCerts = GetSignerCerts();
            X509Certificate2Collection countersignerCerts =
                GetCountersignerCerts();

            Console.WriteLine("\n\n----------------------");
            Console.WriteLine("     SENDER SIDE      ");
            Console.WriteLine("----------------------\n");

            byte[] encodedSignedCms = null;

            try
            {
                encodedSignedCms = SignMsg(msgBytes, signerCerts,
                    countersignerCerts);
            }
            catch (ArgumentOutOfRangeException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("The proper sample certificates are " +
                    "not in the My store. Refer to the documentation " +
                    "about this sample for instructions to correct this.");
                return;
            }

            Console.WriteLine("\n\n------------------------");
            Console.WriteLine("     RECIPIENT SIDE     ");
            Console.WriteLine("------------------------\n");

            if (VerifyMsg(encodedSignedCms))
            {
                Console.WriteLine("\nMessage verified");
            }
            else
            {
                Console.WriteLine("\nMessage failed to verify");
            }
        }

        //  Open the My (or Personal) certificate store and search for
        //  credentials with which to sign the message. There must be
        //  a certificate with subject name "MessageSigner1".
        static public X509Certificate2Collection GetSignerCerts()
        {
            //  Open the My certificate store.
            X509Store storeMy = new X509Store(StoreName.My,
                StoreLocation.CurrentUser);
            storeMy.Open(OpenFlags.ReadOnly);

            //  Display certificates to help troubleshoot 
            //  the example's setup.
            Console.WriteLine("Found certs with the following subject " +
                "names in the {0} store:",
                storeMy.Name);
            foreach (X509Certificate2 cert in storeMy.Certificates)
                Console.WriteLine("\t{0}", cert.SubjectName.Name);

            //  Start the collection of signer certificates to be returned.
            X509Certificate2Collection signerCertsColl = new
                X509Certificate2Collection();

            //  Find the signer's certificate. 
            //  Add it to the signers' certificates collection.
            X509Certificate2Collection foundCertColl = storeMy.
                Certificates.Find(X509FindType.FindBySubjectName,
                signerName, false);
            Console.WriteLine(
                "Found {0} certificates in the {1} store with name {2}",
                foundCertColl.Count, storeMy.Name, signerName);

            //  Check to see if the certificate suggested by the example
            //  requirements is not present.
            if (foundCertColl.Count == 0)
            {
                Console.WriteLine(
                    "A suggested certificate to use for this example " +
                    "is not in the certificate store. Select " +
                    "an alternate certificate to use for " +
                    "signing the message.");
            }

            signerCertsColl.Add(foundCertColl[0]);

            storeMy.Close();

            return signerCertsColl;
        }

        //  Open the My (or Personal) certificate store and search for
        //  credentials with which to countersign the message. There must
        //  be two certificates: one with the subject name         
        //  "Countersigner1", and the other with the subject name 
        //  "Countersigner2".
        static public X509Certificate2Collection GetCountersignerCerts()
        {
            //  Open the My certificate store.
            X509Store storeMy = new X509Store(StoreName.My,
                StoreLocation.CurrentUser);
            storeMy.Open(OpenFlags.ReadOnly);

            //  Start the collection of signer certificates to be returned.
            X509Certificate2Collection countersignerCertsColl = new
                X509Certificate2Collection();

            //  Find the first countersigner's certificate.
            //  Add it to the countersigners' certificates collection.
            X509Certificate2Collection foundCertColl = storeMy.
                Certificates.Find(X509FindType.FindBySubjectName,
                countersignerName1, false);
            Console.WriteLine(
                "Found {0} certificates in the {1} store with name {2}",
                foundCertColl.Count, storeMy.Name, countersignerName1);

            //  Check to see if the certificate suggested by the example
            //  requirements is not present.
            if (foundCertColl.Count == 0)
            {
                Console.WriteLine(
                    "A suggested certificate to use for this example " +
                    "is not in the certificate store. Select " +
                    "an alternate certificate to use for " +
                    "signing the message.");
            }
            
            countersignerCertsColl.Add(foundCertColl[0]);

            //  Find the second countersigner's certificate.
            //  Add it to the countersigners' certificates collection.
            foundCertColl = storeMy.
                Certificates.Find(X509FindType.FindBySubjectName,
                countersignerName2, false);
            Console.WriteLine(
                "Found {0} certificates in the {1} store with name {2}",
                foundCertColl.Count, storeMy.Name, countersignerName2);

            //  Check to see if the certificate suggested by the example
            //  requirements is not present.
            if (foundCertColl.Count == 0)
            {
                Console.WriteLine(
                    "A suggested certificate to use for this example " +
                    "is not in the certificate store. Select " +
                    "an alternate certificate to use for " +
                    "signing the message.");
            }

            countersignerCertsColl.Add(foundCertColl[0]);

            storeMy.Close();

            return countersignerCertsColl;
        }

        //  Sign the message with the private key of the signer,
        //  and countersign that signature with the private key
        //  of each of the countersigners.
        static public byte[] SignMsg(
            Byte[] msg,
            X509Certificate2Collection signerCerts,
            X509Certificate2Collection countersignerCerts)
        {
            //  There must be at least one certificate in the collection.
            if (signerCerts.Count == 0 || countersignerCerts.Count == 0)
            {
                throw new ArgumentOutOfRangeException("Empty certificate" +
                    " collection passed to SignMsg.");
            }

            //  Place the message in a ContentInfo object.
            //  This is required to build a SignedCms object.
            ContentInfo contentInfo = new ContentInfo(msg);

            //  Instantiate a SignedCms object with the ContentInfo above.
            //  Use the default SubjectIdentifierType 
            //  IssuerAndSerialNumber.
            //  Use the default Detached property value FALSE so that the  
            //  message is included in the encoded SignedCms.
            SignedCms signedCms = new SignedCms(contentInfo);

            //  Sign the CMS/PKCS #7 message once for each
            //  signer certificate.
            foreach (X509Certificate2 cert in signerCerts)
            {
                Console.Write("Computing signature with signer subject " +
                    "name {0} ... ", cert.SubjectName.Name);
                signedCms.ComputeSignature(new CmsSigner(cert));
                Console.WriteLine("Done.");
            }

            //  Countersign the first signature in the CMS/PKCS #7 message
            //  once for each countersigner certificate.
            foreach (X509Certificate2 cert in countersignerCerts)
            {
                Console.Write("Computing countersignature with signer " +
                    "subject name {0} ... ",
                    cert.SubjectName.Name);
                signedCms.SignerInfos[0].ComputeCounterSignature(new
                    CmsSigner(cert));
                Console.WriteLine("Done.");
            }

            //  Encode the CMS/PKCS #7 message.
            return signedCms.Encode();
        }

        //  Verify the encoded SignedCms message and return a Boolean
        //  value that specifies whether the verification was successful.
        static public bool VerifyMsg(byte[] encodedSignedCms)
        {
            //  Prepare an object in which to decode and verify.
            SignedCms signedCms = new SignedCms();

            signedCms.Decode(encodedSignedCms);

            //  Check the number of signers and countersigners.
            DisplaySignedCmsProperties("In VerifyMsg method", signedCms);

            //  Catch a verification exception if you want to
            //  advise the message recipient that security actions
            //  might be appropriate.
            try
            {
                //  Verify signature. Do not validate the signer
                //  certificate chain for the purposes of this example.
                //  Note that in a production environment, validating
                //  the signer certificate chain will probably 
                //  be necessary.
                Console.Write("Checking signature and countersignatures" +
                    " on message ... ");
                signedCms.CheckSignature(true);
                Console.WriteLine("Done.");
            }
            catch (System.Security.Cryptography.CryptographicException e)
            {
                Console.WriteLine("VerifyMsg caught exception:  {0}",
                    e.Message);
                Console.WriteLine("Verification of the signed " +
                    "CMS/PKCS #7 failed. The message, signatures, or " +
                    "countersignatures might have been modified " +
                    "in transit or storage. The message signers or " +
                    "countersigners might not be who they claim to be. " +
                    "The message's authenticity or integrity, or both, " +
                    "are not guaranteed.");
                return false;
            }

            return true;
        }

        //  This method displays some properties of a signed 
        //  CMS/PKCS #7 message. These properties include the number of  
        //  signers and countersigners for each signer, whether the 
        //  message is detached, and the version of the message.
        static void DisplaySignedCmsProperties(String info, SignedCms s)
        {
            Console.WriteLine();
            Console.WriteLine("\n>>>>> SignedCms Signer Info: {0}", info);
            Console.WriteLine("\tNumber of signers:\t\t\t{0}",
                s.SignerInfos.Count);
            for (int i = 0; i < s.SignerInfos.Count; i++)
            {
                Console.WriteLine("\tSubject name of signer #{0}:\t\t{1}",
                    i + 1, s.SignerInfos[i].Certificate.SubjectName.Name);
                Console.WriteLine("\tNumber of countersigners for " +
                    "signer #{0}:\t{1}",
                    i + 1, s.SignerInfos[i].CounterSignerInfos.Count);
            }

            Console.WriteLine("\tMessage detached state:\t\t\t{0}",
                s.Detached);
            Console.WriteLine("\tMessage version:\t\t\t{0}", s.Version);
            Console.WriteLine();
        }
    }
}

Siehe auch

Aufgaben

Verfahrensweise: Signieren von Nachrichten durch einen Signierer
Verfahrensweise: Signieren einer Nachricht durch mehrere Signierer
Verfahrensweise: Versehen einer Nachricht mit einem Umschlag für einen Empfänger
Verfahrensweise: Versehen einer Nachricht mit einem Umschlag für mehrere Empfänger

Konzepte

Verfahrensweise: Signieren und Versehen einer Nachricht mit einem Umschlag

Footer image

Copyright © 2007 by Microsoft Corporation. Alle Rechte vorbehalten.