HOW TO:將已驗證的屬性加入至已簽署的訊息
此範例會使用 System.Security.Cryptography.Pkcs 建立 CMS/PKCS #7 簽署訊息。此訊息由單一簽署者簽署。訊息中含有時間戳記做為已驗證的屬性。這表示訊息內容和時間戳記都已經過簽署。接下來訊息的簽章會受到驗證,確認訊息內容和時間戳記是否有效。
範例
此範例也示範如何使用中斷連結的 CMS/PKCS #7 訊息。這表示訊息內容不是儲存在 CMS/PKCS #7 訊息中。因此訊息內容必須被傳遞到驗證 CMS/PKCS #7 訊息的方法中。
本範例使用下列類別:
下列範例要求「我的」憑證存放區中必須有主體名稱為 "MessageSigner1" 的公開金鑰憑證,且關聯的私密金鑰必須存在。
注意: |
---|
此範例僅用於示範。實際執行環境中可能使用不同的模型,其中訊息的傳送者和收件者會使用其唯一公開金鑰認證,在不同的處理序中執行。 |
使用 Makecert.exe 公用程式設定此範例,這是完成此工作的方法之一。Certificate Creation Tool (Makecert.exe) 是測試憑證的方便公用程式。在實際執行環境中,憑證是由憑證授權單位所產生。
下面的 Makecert 命令會產生必要的公開金鑰憑證和私密金鑰。
Makecert -n "CN=MessageSigner1" -ss My
// Copyright (c) Microsoft Corporation. All rights reserved.
#region Using directives
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;
#endregion
namespace AddAnAuthenticatedAttributeToASignedMessage
{
class SignedCmsAuthenticatedAttribute
{
const String signerName = "MessageSigner1";
static void Main(string[] args)
{
Console.WriteLine("System.Security.Cryptography.Pkcs " +
"Sample: Single-signer signed and verified message");
// Original message.
const String msg = "This is the message to be signed. " +
"A time stamp is included as an authenticated " +
"attribute.";
Console.WriteLine("\nOriginal message (len {0}): {1} ",
msg.Length, msg);
// Convert message to 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");
X509Certificate2 signerCert = GetSignerCert();
Console.WriteLine("\n\n----------------------");
Console.WriteLine(" SENDER SIDE ");
Console.WriteLine("----------------------\n");
byte[] encodedSignedCms = SignMsg(msgBytes, signerCert);
Console.WriteLine("\n\n------------------------");
Console.WriteLine(" RECIPIENT SIDE ");
Console.WriteLine("------------------------\n");
if (VerifyMsg(msgBytes, encodedSignedCms))
{
Console.WriteLine("\nMessage verified");
}
else
{
Console.WriteLine("\nMessage failed to verify");
}
}
// Open the My (or Personal) certificate store and search for
// credentials to sign the message with. The certificate
// must have the subject name "MessageSigner1".
static public X509Certificate2 GetSignerCert()
{
// 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);
}
// Find the signer's certificate.
X509Certificate2Collection certColl =
storeMy.Certificates.Find(X509FindType.FindBySubjectName,
signerName, false);
Console.WriteLine(
"Found {0} certificates in the {1} store with name {2}",
certColl.Count, storeMy.Name, signerName);
// Check to see if the certificate suggested by the example
// requirements is not present.
if (certColl.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.");
}
storeMy.Close();
// If more than one matching cert, return the first one.
return certColl[0];
}
// Sign the message with the private key of the signer.
static public byte[] SignMsg(
Byte[] msg,
X509Certificate2 signerCert)
{
// Place message in a ContentInfo object.
// This is required to build a SignedCms object.
ContentInfo contentInfo = new ContentInfo(msg);
// Instantiate SignedCms object with the ContentInfo above.
// Has default SubjectIdentifierType IssuerAndSerialNumber.
// Set the Detached property value to true, so message is
// not included in the encoded SignedCms.
SignedCms signedCms = new SignedCms(contentInfo, true);
// Formulate a CmsSigner object for the signer.
CmsSigner cmsSigner = new CmsSigner(signerCert);
// Add an authenticated time stamp attribute to the signer.
// The signing time is the current time.
cmsSigner.SignedAttributes.Add(new Pkcs9SigningTime());
// Sign the CMS/PKCS #7 message.
Console.Write("Computing signature with signer subject " +
"name {0} ... ", signerCert.SubjectName.Name);
signedCms.ComputeSignature(cmsSigner);
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[] msgBytes, byte[] encodedSignedCms)
{
Pkcs9SigningTime st = new Pkcs9SigningTime();
// Build a ContentInfo object with the message bytes. This
// is necessary because the message is detached from the
// SignedCms object.
ContentInfo contentInfo = new ContentInfo(msgBytes);
// Prepare an object in which to decode and verify.
SignedCms signedCms = new SignedCms(contentInfo, true);
signedCms.Decode(encodedSignedCms);
// Catch a verification exception if you want to
// advise the message recipient that
// security actions might be appropriate.
try
{
// Verify signature. Do not validate signer
// certificate 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 on message ... ");
signedCms.CheckSignature(true);
Console.WriteLine("Done.");
// Report the signing time for the CMS/PKCS #7 message.
for (int i = 0; i < signedCms.SignerInfos[0].SignedAttributes.Count; i++)
{
//if (signedCms.SignerInfos[0].SignedAttributes[i].
//Values[0].GetType().Equals(st.GetType()))
if (signedCms.SignerInfos[0].SignedAttributes[i].Values[0] is Pkcs9SigningTime)
{
Pkcs9SigningTime signingTime = (Pkcs9SigningTime)signedCms.SignerInfos[0].SignedAttributes[i].Values[0];
Console.WriteLine("Signing time: {0}", signingTime.SigningTime);
}
}
}
catch (System.Security.Cryptography.CryptographicException e)
{
Console.WriteLine("VerifyMsg caught exception: {0}",
e.Message);
Console.WriteLine("Verification of the signed PKCS #7 " +
"failed. The message, signatures, " +
" countersignatures, or authenticated attributes " +
" may have been modified in transit or storage. The " +
" message signers or countersigners may not be who " +
" they claim to be. The message's authenticity or " +
" integrity, or both, are not guaranteed.");
return false;
}
return true;
}
}
}
請參閱
參考
CmsSigner
ContentInfo
SignedCms
X509Certificate2
X509Certificate2Collection
X509Store
Copyright © 2007 by Microsoft Corporation. All rights reserved.