Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Pkcs / SignerInfo.cs / 1 / SignerInfo.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // // SignerInfo.cs // namespace System.Security.Cryptography.Pkcs { using System.Collections; using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class SignerInfo { private X509Certificate2 m_certificate; private SubjectIdentifier m_signerIdentifier; private CryptographicAttributeObjectCollection m_signedAttributes; private CryptographicAttributeObjectCollection m_unsignedAttributes; private SignedCms m_signedCms; private SignerInfo m_parentSignerInfo; private byte[] m_encodedSignerInfo; private SafeLocalAllocHandle m_pbCmsgSignerInfo; private CAPI.CMSG_SIGNER_INFO m_cmsgSignerInfo; // // Constructors. // private SignerInfo () {} internal unsafe SignerInfo (SignedCms signedCms, SafeLocalAllocHandle pbCmsgSignerInfo) { // Sanity check. Debug.Assert(signedCms != null && pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid); m_signedCms = signedCms; m_parentSignerInfo = null; m_encodedSignerInfo = null; m_pbCmsgSignerInfo = pbCmsgSignerInfo; m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); } internal unsafe SignerInfo (SignedCms signedCms, SignerInfo parentSignerInfo, byte[] encodedSignerInfo) { // Sanity check. Debug.Assert(signedCms != null && encodedSignerInfo != null && encodedSignerInfo.Length > 0); uint cbCmsgSignerInfo = 0; SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle; fixed (byte * pEncodedSignerInfo = &encodedSignerInfo[0]) { if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS7_SIGNER_INFO), new IntPtr(pEncodedSignerInfo), (uint) encodedSignerInfo.Length, out pbCmsgSignerInfo, out cbCmsgSignerInfo)) throw new CryptographicException(Marshal.GetLastWin32Error()); } m_signedCms = signedCms; m_parentSignerInfo = parentSignerInfo; m_encodedSignerInfo = (byte[]) encodedSignerInfo.Clone(); m_pbCmsgSignerInfo = pbCmsgSignerInfo; m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); } // // Public APIs. // public int Version { get { return (int) m_cmsgSignerInfo.dwVersion; } } public X509Certificate2 Certificate { get { if (m_certificate == null) m_certificate = PkcsUtils.FindCertificate(this.SignerIdentifier, m_signedCms.Certificates); return m_certificate; } } public SubjectIdentifier SignerIdentifier { get { if (m_signerIdentifier == null) m_signerIdentifier = new SubjectIdentifier(m_cmsgSignerInfo); return m_signerIdentifier; } } public Oid DigestAlgorithm { get { return new Oid(m_cmsgSignerInfo.HashAlgorithm.pszObjId); } } public CryptographicAttributeObjectCollection SignedAttributes { get { if (m_signedAttributes == null) m_signedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.AuthAttrs); return m_signedAttributes; } } public CryptographicAttributeObjectCollection UnsignedAttributes { get { if (m_unsignedAttributes == null) m_unsignedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.UnauthAttrs); return m_unsignedAttributes; } } public SignerInfoCollection CounterSignerInfos { get { // We only support one level of counter signing. if (m_parentSignerInfo != null) return new SignerInfoCollection(); return new SignerInfoCollection(m_signedCms, this); } } public void ComputeCounterSignature () { ComputeCounterSignature(new CmsSigner(m_signedCms.Version == 2 ? SubjectIdentifierType.SubjectKeyIdentifier : SubjectIdentifierType.IssuerAndSerialNumber)); } public void ComputeCounterSignature (CmsSigner signer) { // We only support one level of counter signing. if (m_parentSignerInfo != null) throw new CryptographicException(CAPI.E_NOTIMPL); if (signer == null) throw new ArgumentNullException("signer"); if (signer.Certificate == null) signer.Certificate = PkcsUtils.SelectSignerCertificate(); if (!signer.Certificate.HasPrivateKey) throw new CryptographicException(CAPI.NTE_NO_KEY); CounterSign(signer); } public void RemoveCounterSignature (int index) { // We only support one level of counter signing. if (m_parentSignerInfo != null) throw new CryptographicException(CAPI.E_NOTIMPL); RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); return; } public void RemoveCounterSignature (SignerInfo counterSignerInfo) { // We only support one level of counter signing. if (m_parentSignerInfo != null) throw new CryptographicException(CAPI.E_NOTIMPL); if (counterSignerInfo == null) throw new ArgumentNullException("counterSignerInfo"); foreach (CryptographicAttributeObject attribute in UnsignedAttributes) { if (String.Compare(attribute.Oid.Value, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) { for (int index = 0; index < attribute.Values.Count; index++) { AsnEncodedData encodedCounterSignature = (AsnEncodedData) attribute.Values[index]; SignerInfo counterSignerInfo2 = new SignerInfo(m_signedCms, m_parentSignerInfo, encodedCounterSignature.RawData); if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber) && (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)) { X509IssuerSerial issuerSerial1 = (X509IssuerSerial) counterSignerInfo.SignerIdentifier.Value; X509IssuerSerial issuerSerial2 = (X509IssuerSerial) counterSignerInfo2.SignerIdentifier.Value; if ((String.Compare(issuerSerial1.IssuerName, issuerSerial2.IssuerName, StringComparison.OrdinalIgnoreCase) == 0) && (String.Compare(issuerSerial1.SerialNumber, issuerSerial2.SerialNumber, StringComparison.OrdinalIgnoreCase) == 0)) { RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); return; } } else if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier) && (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier)) { string keyIdentifier1 = counterSignerInfo.SignerIdentifier.Value as string; string keyIdentifier2 = counterSignerInfo2.SignerIdentifier.Value as string; if (String.Compare(keyIdentifier1, keyIdentifier2, StringComparison.OrdinalIgnoreCase) == 0) { RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); return; } } } } } throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); } public void CheckSignature (bool verifySignatureOnly) { CheckSignature(new X509Certificate2Collection(), verifySignatureOnly); } public void CheckSignature (X509Certificate2Collection extraStore, bool verifySignatureOnly) { if (extraStore == null) throw new ArgumentNullException("extraStore"); X509Certificate2 certificate = this.Certificate; if (certificate == null) { certificate = PkcsUtils.FindCertificate(SignerIdentifier, extraStore); if (certificate == null) throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); } Verify(extraStore, certificate, verifySignatureOnly); } public void CheckHash() { int cvseSize = Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)); CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse = new CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA(cvseSize); cvse.dwSignerType = CAPI.CMSG_VERIFY_SIGNER_NULL; cvse.dwSignerIndex = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0); unsafe { if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(), 0, CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX, new IntPtr(&cvse))) throw new CryptographicException(Marshal.GetLastWin32Error()); } } // // Internal methods. // internal CAPI.CMSG_SIGNER_INFO GetCmsgSignerInfo () { return m_cmsgSignerInfo; } // // Private methods. // private unsafe void CounterSign (CmsSigner signer) { // Sanity check. Debug.Assert(signer != null); // CspParameters parameters = new CspParameters(); if (X509Utils.GetPrivateKeyInfo(X509Utils.GetCertContext(signer.Certificate), ref parameters) == false) throw new CryptographicException(Marshal.GetLastWin32Error()); KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags); KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open | KeyContainerPermissionFlags.Sign); kp.AccessEntries.Add(entry); kp.Demand(); // Get the signer's index. uint index = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0); // Create CMSG_SIGNER_ENCODE_INFO structure. SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)))); CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer); try { // Marshal to unmanaged memory. Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false); // Counter sign. if (!CAPI.CryptMsgCountersign(m_signedCms.GetCryptMsgHandle(), index, 1, pSignerEncodeInfo.DangerousGetHandle())) throw new CryptographicException(Marshal.GetLastWin32Error()); // CAPI requires that the messge be re-encoded if any unauthenticated // attribute has been added. So, let's re-open it to decode to work // around this limitation. m_signedCms.ReopenToDecode(); } finally { Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)); pSignerEncodeInfo.Dispose(); // and don't forget to dispose of resources allocated for the structure. signerEncodeInfo.Dispose(); } // Finally, add certs to bag of certs. PkcsUtils.AddCertsToMessage(m_signedCms.GetCryptMsgHandle(), m_signedCms.Certificates, PkcsUtils.CreateBagOfCertificates(signer)); return; } private unsafe void Verify (X509Certificate2Collection extraStore, X509Certificate2 certificate, bool verifySignatureOnly) { // We need to find out if DSS parameters inheritance is necessary. If so, we need to // first build the chain to cause CAPI to inherit and set the parameters in the // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. Once we have the parameters in // the property, we then need to retrieve a copy and point to it in the CERT_INFO // structure. SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle; CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT)); // Point to SubjectPublicKeyInfo field inside the CERT_INFO structure. IntPtr pSubjectPublicKeyInfo = new IntPtr((long) pCertContext.pCertInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_INFO), "SubjectPublicKeyInfo")); // Point to Algorithm field inside the SubjectPublicKeyInfo field. IntPtr pAlgorithm = new IntPtr((long) pSubjectPublicKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO), "Algorithm")); // Point to Parameters field inside the Algorithm field. IntPtr pParameters = new IntPtr((long) pAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters")); // Retrieve the pszObjId pointer. IntPtr pObjId = Marshal.ReadIntPtr(pAlgorithm); // Translate the OID to AlgId value. CAPI.CRYPT_OID_INFO pOIDInfo = CAPI.CryptFindOIDInfo(CAPI.CRYPT_OID_INFO_OID_KEY, pObjId, CAPI.CRYPT_PUBKEY_ALG_OID_GROUP_ID); // Is this DSS? if (pOIDInfo.Algid == CAPI.CALG_DSS_SIGN) { bool inheritParameters = false; // This is DSS, so inherit the parameters if necessary. IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); if (Marshal.ReadInt32(pcbData) == 0) { inheritParameters = true; } else { // Need to inherit if NULL pbData or *pbData is 0x05 (NULL ASN tag). if (Marshal.ReadIntPtr(ppbData) == IntPtr.Zero) { inheritParameters = true; } else { IntPtr pbData = Marshal.ReadIntPtr(ppbData); if ((uint) Marshal.ReadInt32(pbData) == CAPI.ASN_TAG_NULL) { inheritParameters = true; } } } // Do we need to copy inherited DSS parameters? if (inheritParameters) { // Build the chain to force CAPI to propagate the parameters to // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. SafeCertChainHandle pChainContext = SafeCertChainHandle.InvalidHandle; X509Utils.BuildChain(new IntPtr(CAPI.HCCE_CURRENT_USER), X509Utils.GetCertContext(certificate), null, null, null, X509RevocationMode.NoCheck, X509RevocationFlag.ExcludeRoot, DateTime.Now, new TimeSpan(0, 0, 0), // default ref pChainContext); pChainContext.Dispose(); // The parameter is inherited in the extended property, but not copied // to CERT_INFO, so we need to do it ourselves. uint cbParameters = 0; if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, pbParameters, ref cbParameters)) throw new CryptographicException(Marshal.GetLastWin32Error()); if (cbParameters > 0) { pbParameters = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbParameters)); if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, pbParameters, ref cbParameters)) throw new CryptographicException(Marshal.GetLastWin32Error()); Marshal.WriteInt32(pcbData, (int)cbParameters); Marshal.WriteIntPtr(ppbData, pbParameters.DangerousGetHandle()); } } } // Is this counter signer? if (m_parentSignerInfo == null) { // Just plain signer. if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(), 0, CAPI.CMSG_CTRL_VERIFY_SIGNATURE, pCertContext.pCertInfo)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } else { // Counter signer, so need to first find parent signer's index. int index = -1; int lastWin32Error = 0; // Since we allow the same signer to sign more than once, // we must than try all signatures of the same signer. while (true) { try { // Find index of parent signer. index = PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), m_parentSignerInfo, index + 1); } catch (CryptographicException) { // Did we ever find a signature of the same signer? if (lastWin32Error == 0) { // No. So we just re-throw, which is most likely CAPI.CRYPT_E_SIGNER_NOT_FOUND. throw; } else { // Yes. Throw previous error, which is most likely CAPI.NTE_BAD_SIGNATURE. throw new CryptographicException(lastWin32Error); } } // Now get the parent encoded singer info. uint cbParentEncodedSignerInfo = 0; SafeLocalAllocHandle pbParentEncodedSignerInfo = SafeLocalAllocHandle.InvalidHandle; PkcsUtils.GetParam(m_signedCms.GetCryptMsgHandle(), CAPI.CMSG_ENCODED_SIGNER, (uint) index, out pbParentEncodedSignerInfo, out cbParentEncodedSignerInfo); // Try next signer if we can't get parent of this signer. if (cbParentEncodedSignerInfo == 0) { lastWin32Error = CAPI.CRYPT_E_NO_SIGNER; continue; } fixed (byte * pbEncodedSignerInfo = m_encodedSignerInfo) { if (!CAPI.CryptMsgVerifyCountersignatureEncoded(IntPtr.Zero, CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, pbParentEncodedSignerInfo.DangerousGetHandle(), cbParentEncodedSignerInfo, new IntPtr(pbEncodedSignerInfo), (uint) m_encodedSignerInfo.Length, pCertContext.pCertInfo)) { // Cache the error, and try next signer. lastWin32Error = Marshal.GetLastWin32Error(); continue; } } // Keep alive. pbParentEncodedSignerInfo.Dispose(); // The signature is successfully verified. break; } } // Verfiy the cert if requested. if (!verifySignatureOnly) { int hr = VerifyCertificate(certificate, extraStore); if (hr != CAPI.S_OK) throw new CryptographicException(hr); } // Keep alive. pbParameters.Dispose(); } private unsafe void RemoveCounterSignature (int parentIndex, int childIndex) { // Just make sure this is non-negative. if (parentIndex < 0) throw new ArgumentOutOfRangeException("parentIndex"); if (childIndex < 0) throw new ArgumentOutOfRangeException("childIndex"); uint cbCmsgCmsSignerInfo = 0; SafeLocalAllocHandle pbCmsgCmsSignerInfo = SafeLocalAllocHandle.InvalidHandle; uint cbCmsgSignerInfo = 0; SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle; uint index = 0; uint cAttr = 0; IntPtr pAttr = IntPtr.Zero; SafeCryptMsgHandle hMsg = m_signedCms.GetCryptMsgHandle(); if (PkcsUtils.CmsSupported()) { PkcsUtils.GetParam(hMsg, CAPI.CMSG_CMS_SIGNER_INFO_PARAM, (uint) parentIndex, out pbCmsgCmsSignerInfo, out cbCmsgCmsSignerInfo); CAPI.CMSG_CMS_SIGNER_INFO cmsgCmsSignerInfo = (CAPI.CMSG_CMS_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgCmsSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_CMS_SIGNER_INFO)); cAttr = cmsgCmsSignerInfo.UnauthAttrs.cAttr; pAttr = new IntPtr((long) cmsgCmsSignerInfo.UnauthAttrs.rgAttr); } else { PkcsUtils.GetParam(hMsg, CAPI.CMSG_SIGNER_INFO_PARAM, (uint) parentIndex, out pbCmsgSignerInfo, out cbCmsgSignerInfo); CAPI.CMSG_SIGNER_INFO cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); cAttr = cmsgSignerInfo.UnauthAttrs.cAttr; pAttr = new IntPtr((long) cmsgSignerInfo.UnauthAttrs.rgAttr); } // Find index for counter signature attribute. // Note: It is not guaranteed that CAPI will keep all counter signatures // in one single unauthenticated attribute. So we need to find the correct // unauthenticated attribute containing this counter signer which is // identified by index. for (index = 0; index < cAttr; index++) { CAPI.CRYPT_ATTRIBUTE attr = (CAPI.CRYPT_ATTRIBUTE) Marshal.PtrToStructure(pAttr, typeof(CAPI.CRYPT_ATTRIBUTE)); if (String.Compare(attr.pszObjId, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) { if (attr.cValue > 0) { // Is it in this attribute? if (childIndex < (int) attr.cValue) { // Found the desired counter signature attribute. So, first remove the // entire attribute, then remove just the counter signature from the // retrieved attribute, and finally add back the modified attribute, // if necessary. CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA delPara = new CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA))); delPara.dwSignerIndex = (uint) parentIndex; delPara.dwUnauthAttrIndex = index; if (!CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR, new IntPtr(&delPara))) throw new CryptographicException(Marshal.GetLastWin32Error()); // No need to add back if only one counter signature in this attribute. if (attr.cValue > 1) { try { // There were more than one counter signatures in this attribute, so // need to add back a new counter signature attribute which includes // the remaining counter signatures. uint cbCounterSignatureValue = (uint) ((attr.cValue - 1) * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))); SafeLocalAllocHandle pbCounterSignatureValue = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbCounterSignatureValue)); // Copy everything except the one being removed. CAPI.CRYPTOAPI_BLOB * pOldValue = (CAPI.CRYPTOAPI_BLOB *) attr.rgValue; CAPI.CRYPTOAPI_BLOB * pNewValue = (CAPI.CRYPTOAPI_BLOB *) pbCounterSignatureValue.DangerousGetHandle(); for (int i = 0; i < (int) attr.cValue; i++, pOldValue++, pNewValue++) { if (i != childIndex) { *pNewValue = *pOldValue; } } // Encode the new counter signature attribute. byte[] encodedNewAttribute; CAPI.CRYPT_ATTRIBUTE newAttr = new CAPI.CRYPT_ATTRIBUTE(); newAttr.pszObjId = attr.pszObjId; newAttr.cValue = attr.cValue - 1; newAttr.rgValue = pbCounterSignatureValue.DangerousGetHandle(); SafeLocalAllocHandle pNewAttr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE)))); Marshal.StructureToPtr(newAttr, pNewAttr.DangerousGetHandle(), false); try { if (!CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE), pNewAttr.DangerousGetHandle(), out encodedNewAttribute)) throw new CryptographicException(Marshal.GetLastWin32Error()); } finally { Marshal.DestroyStructure(pNewAttr.DangerousGetHandle(), typeof(CAPI.CRYPT_ATTRIBUTE)); pNewAttr.Dispose(); } // Finally, add it back. fixed (byte * pbData = &encodedNewAttribute[0]) { CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA))); addPara.dwSignerIndex = (uint) parentIndex; addPara.blob.cbData = (uint) encodedNewAttribute.Length; addPara.blob.pbData = new IntPtr(pbData); if (!CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, new IntPtr(&addPara))) throw new CryptographicException(Marshal.GetLastWin32Error()); } // Keep alive. pbCounterSignatureValue.Dispose(); } catch (CryptographicException) { // Roll back. byte[] encodedAttribute; if (CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE), pAttr, out encodedAttribute)) { fixed (byte * pbData = &encodedAttribute[0]) { CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA))); addPara.dwSignerIndex = (uint) parentIndex; addPara.blob.cbData = (uint) encodedAttribute.Length; addPara.blob.pbData = new IntPtr(pbData); CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, new IntPtr(&addPara)); } } throw; } } return; } childIndex -= (int) attr.cValue; } } pAttr = new IntPtr((long) pAttr + (long) Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE))); } // Keep alive. if (pbCmsgCmsSignerInfo != null && !pbCmsgCmsSignerInfo.IsInvalid) { pbCmsgCmsSignerInfo.Dispose(); } if (pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid) { pbCmsgSignerInfo.Dispose(); } throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); } // // Private static. // private static unsafe int VerifyCertificate (X509Certificate2 certificate, X509Certificate2Collection extraStore) { int dwErrorStatus; int hr = X509Utils.VerifyCertificate(X509Utils.GetCertContext(certificate), null, null, X509RevocationMode.Online, X509RevocationFlag.ExcludeRoot, DateTime.Now, new TimeSpan(0, 0, 0), extraStore, new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE), new IntPtr(&dwErrorStatus)); if (hr != CAPI.S_OK) return dwErrorStatus; // Check key usages to make sure it is good for signing. foreach (X509Extension extension in certificate.Extensions) { if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) { X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); keyUsage.CopyFrom(extension); if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 && (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) { hr = CAPI.CERT_E_WRONG_USAGE; break; } } } return hr; } } [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class SignerInfoCollection : ICollection { private SignerInfo[] m_signerInfos; internal SignerInfoCollection () { m_signerInfos = new SignerInfo[0]; } internal unsafe SignerInfoCollection (SignedCms signedCms) { uint dwSigners = 0; uint cbCount = (uint) Marshal.SizeOf(typeof(uint)); SafeCryptMsgHandle safeCryptMsgHandle = signedCms.GetCryptMsgHandle(); if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, CAPI.CMSG_SIGNER_COUNT_PARAM, 0, new IntPtr(&dwSigners), new IntPtr(&cbCount))) throw new CryptographicException(Marshal.GetLastWin32Error()); SignerInfo[] signerInfos = new SignerInfo[dwSigners]; for (int index = 0; index < dwSigners; index++) { uint cbCmsgSignerInfo = 0; if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, CAPI.CMSG_SIGNER_INFO_PARAM, (uint) index, IntPtr.Zero, new IntPtr(&cbCmsgSignerInfo))) throw new CryptographicException(Marshal.GetLastWin32Error()); SafeLocalAllocHandle pbCmsgSignerInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbCmsgSignerInfo)); if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, CAPI.CMSG_SIGNER_INFO_PARAM, (uint) index, pbCmsgSignerInfo, new IntPtr(&cbCmsgSignerInfo))) throw new CryptographicException(Marshal.GetLastWin32Error()); signerInfos[index] = new SignerInfo(signedCms, pbCmsgSignerInfo); } m_signerInfos = signerInfos; } internal unsafe SignerInfoCollection (SignedCms signedCms, SignerInfo signerInfo) { SignerInfo[] signerInfos = new SignerInfo[0]; int count = 0; int index = 0; foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) { if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) { count += attribute.Values.Count; } } signerInfos = new SignerInfo[count]; foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) { if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) { for (int i = 0; i < attribute.Values.Count; i++) { AsnEncodedData encodedSignerInfo = (AsnEncodedData) attribute.Values[i]; signerInfos[index++] = new SignerInfo(signedCms, signerInfo, encodedSignerInfo.RawData); } } } m_signerInfos = signerInfos; } public SignerInfo this[int index] { get { if (index < 0 || index >= m_signerInfos.Length) throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index")); Debug.Assert(m_signerInfos[index] != null); return m_signerInfos[index]; } } public int Count { get { return m_signerInfos.Length; } } public SignerInfoEnumerator GetEnumerator() { return new SignerInfoEnumerator(this); } ///IEnumerator IEnumerable.GetEnumerator() { return new SignerInfoEnumerator(this); } public void CopyTo(Array array, int index) { if (array == null) throw new ArgumentNullException("array"); if (array.Rank != 1) throw new ArgumentException(SecurityResources.GetResourceString("Arg_RankMultiDimNotSupported")); if (index < 0 || index >= array.Length) throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index")); if (index + this.Count > array.Length) throw new ArgumentException(SecurityResources.GetResourceString("Argument_InvalidOffLen")); for (int i=0; i < this.Count; i++) { array.SetValue(this[i], index); index++; } } public void CopyTo(SignerInfo[] array, int index) { ((ICollection)this).CopyTo(array, index); } public bool IsSynchronized { get { return false; } } public Object SyncRoot { get { return this; } } } [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class SignerInfoEnumerator : IEnumerator { private SignerInfoCollection m_signerInfos; private int m_current; private SignerInfoEnumerator() {} internal SignerInfoEnumerator(SignerInfoCollection signerInfos) { m_signerInfos = signerInfos; m_current = -1; } public SignerInfo Current { get { return m_signerInfos[m_current]; } } /// Object IEnumerator.Current { get { return (Object) m_signerInfos[m_current]; } } public bool MoveNext() { if (m_current == ((int) m_signerInfos.Count - 1)) { return false; } m_current++; return true; } public void Reset() { m_current = -1; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // // SignerInfo.cs // namespace System.Security.Cryptography.Pkcs { using System.Collections; using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class SignerInfo { private X509Certificate2 m_certificate; private SubjectIdentifier m_signerIdentifier; private CryptographicAttributeObjectCollection m_signedAttributes; private CryptographicAttributeObjectCollection m_unsignedAttributes; private SignedCms m_signedCms; private SignerInfo m_parentSignerInfo; private byte[] m_encodedSignerInfo; private SafeLocalAllocHandle m_pbCmsgSignerInfo; private CAPI.CMSG_SIGNER_INFO m_cmsgSignerInfo; // // Constructors. // private SignerInfo () {} internal unsafe SignerInfo (SignedCms signedCms, SafeLocalAllocHandle pbCmsgSignerInfo) { // Sanity check. Debug.Assert(signedCms != null && pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid); m_signedCms = signedCms; m_parentSignerInfo = null; m_encodedSignerInfo = null; m_pbCmsgSignerInfo = pbCmsgSignerInfo; m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); } internal unsafe SignerInfo (SignedCms signedCms, SignerInfo parentSignerInfo, byte[] encodedSignerInfo) { // Sanity check. Debug.Assert(signedCms != null && encodedSignerInfo != null && encodedSignerInfo.Length > 0); uint cbCmsgSignerInfo = 0; SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle; fixed (byte * pEncodedSignerInfo = &encodedSignerInfo[0]) { if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS7_SIGNER_INFO), new IntPtr(pEncodedSignerInfo), (uint) encodedSignerInfo.Length, out pbCmsgSignerInfo, out cbCmsgSignerInfo)) throw new CryptographicException(Marshal.GetLastWin32Error()); } m_signedCms = signedCms; m_parentSignerInfo = parentSignerInfo; m_encodedSignerInfo = (byte[]) encodedSignerInfo.Clone(); m_pbCmsgSignerInfo = pbCmsgSignerInfo; m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); } // // Public APIs. // public int Version { get { return (int) m_cmsgSignerInfo.dwVersion; } } public X509Certificate2 Certificate { get { if (m_certificate == null) m_certificate = PkcsUtils.FindCertificate(this.SignerIdentifier, m_signedCms.Certificates); return m_certificate; } } public SubjectIdentifier SignerIdentifier { get { if (m_signerIdentifier == null) m_signerIdentifier = new SubjectIdentifier(m_cmsgSignerInfo); return m_signerIdentifier; } } public Oid DigestAlgorithm { get { return new Oid(m_cmsgSignerInfo.HashAlgorithm.pszObjId); } } public CryptographicAttributeObjectCollection SignedAttributes { get { if (m_signedAttributes == null) m_signedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.AuthAttrs); return m_signedAttributes; } } public CryptographicAttributeObjectCollection UnsignedAttributes { get { if (m_unsignedAttributes == null) m_unsignedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.UnauthAttrs); return m_unsignedAttributes; } } public SignerInfoCollection CounterSignerInfos { get { // We only support one level of counter signing. if (m_parentSignerInfo != null) return new SignerInfoCollection(); return new SignerInfoCollection(m_signedCms, this); } } public void ComputeCounterSignature () { ComputeCounterSignature(new CmsSigner(m_signedCms.Version == 2 ? SubjectIdentifierType.SubjectKeyIdentifier : SubjectIdentifierType.IssuerAndSerialNumber)); } public void ComputeCounterSignature (CmsSigner signer) { // We only support one level of counter signing. if (m_parentSignerInfo != null) throw new CryptographicException(CAPI.E_NOTIMPL); if (signer == null) throw new ArgumentNullException("signer"); if (signer.Certificate == null) signer.Certificate = PkcsUtils.SelectSignerCertificate(); if (!signer.Certificate.HasPrivateKey) throw new CryptographicException(CAPI.NTE_NO_KEY); CounterSign(signer); } public void RemoveCounterSignature (int index) { // We only support one level of counter signing. if (m_parentSignerInfo != null) throw new CryptographicException(CAPI.E_NOTIMPL); RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); return; } public void RemoveCounterSignature (SignerInfo counterSignerInfo) { // We only support one level of counter signing. if (m_parentSignerInfo != null) throw new CryptographicException(CAPI.E_NOTIMPL); if (counterSignerInfo == null) throw new ArgumentNullException("counterSignerInfo"); foreach (CryptographicAttributeObject attribute in UnsignedAttributes) { if (String.Compare(attribute.Oid.Value, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) { for (int index = 0; index < attribute.Values.Count; index++) { AsnEncodedData encodedCounterSignature = (AsnEncodedData) attribute.Values[index]; SignerInfo counterSignerInfo2 = new SignerInfo(m_signedCms, m_parentSignerInfo, encodedCounterSignature.RawData); if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber) && (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)) { X509IssuerSerial issuerSerial1 = (X509IssuerSerial) counterSignerInfo.SignerIdentifier.Value; X509IssuerSerial issuerSerial2 = (X509IssuerSerial) counterSignerInfo2.SignerIdentifier.Value; if ((String.Compare(issuerSerial1.IssuerName, issuerSerial2.IssuerName, StringComparison.OrdinalIgnoreCase) == 0) && (String.Compare(issuerSerial1.SerialNumber, issuerSerial2.SerialNumber, StringComparison.OrdinalIgnoreCase) == 0)) { RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); return; } } else if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier) && (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier)) { string keyIdentifier1 = counterSignerInfo.SignerIdentifier.Value as string; string keyIdentifier2 = counterSignerInfo2.SignerIdentifier.Value as string; if (String.Compare(keyIdentifier1, keyIdentifier2, StringComparison.OrdinalIgnoreCase) == 0) { RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); return; } } } } } throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); } public void CheckSignature (bool verifySignatureOnly) { CheckSignature(new X509Certificate2Collection(), verifySignatureOnly); } public void CheckSignature (X509Certificate2Collection extraStore, bool verifySignatureOnly) { if (extraStore == null) throw new ArgumentNullException("extraStore"); X509Certificate2 certificate = this.Certificate; if (certificate == null) { certificate = PkcsUtils.FindCertificate(SignerIdentifier, extraStore); if (certificate == null) throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); } Verify(extraStore, certificate, verifySignatureOnly); } public void CheckHash() { int cvseSize = Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)); CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse = new CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA(cvseSize); cvse.dwSignerType = CAPI.CMSG_VERIFY_SIGNER_NULL; cvse.dwSignerIndex = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0); unsafe { if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(), 0, CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX, new IntPtr(&cvse))) throw new CryptographicException(Marshal.GetLastWin32Error()); } } // // Internal methods. // internal CAPI.CMSG_SIGNER_INFO GetCmsgSignerInfo () { return m_cmsgSignerInfo; } // // Private methods. // private unsafe void CounterSign (CmsSigner signer) { // Sanity check. Debug.Assert(signer != null); // CspParameters parameters = new CspParameters(); if (X509Utils.GetPrivateKeyInfo(X509Utils.GetCertContext(signer.Certificate), ref parameters) == false) throw new CryptographicException(Marshal.GetLastWin32Error()); KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags); KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open | KeyContainerPermissionFlags.Sign); kp.AccessEntries.Add(entry); kp.Demand(); // Get the signer's index. uint index = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0); // Create CMSG_SIGNER_ENCODE_INFO structure. SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)))); CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer); try { // Marshal to unmanaged memory. Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false); // Counter sign. if (!CAPI.CryptMsgCountersign(m_signedCms.GetCryptMsgHandle(), index, 1, pSignerEncodeInfo.DangerousGetHandle())) throw new CryptographicException(Marshal.GetLastWin32Error()); // CAPI requires that the messge be re-encoded if any unauthenticated // attribute has been added. So, let's re-open it to decode to work // around this limitation. m_signedCms.ReopenToDecode(); } finally { Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)); pSignerEncodeInfo.Dispose(); // and don't forget to dispose of resources allocated for the structure. signerEncodeInfo.Dispose(); } // Finally, add certs to bag of certs. PkcsUtils.AddCertsToMessage(m_signedCms.GetCryptMsgHandle(), m_signedCms.Certificates, PkcsUtils.CreateBagOfCertificates(signer)); return; } private unsafe void Verify (X509Certificate2Collection extraStore, X509Certificate2 certificate, bool verifySignatureOnly) { // We need to find out if DSS parameters inheritance is necessary. If so, we need to // first build the chain to cause CAPI to inherit and set the parameters in the // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. Once we have the parameters in // the property, we then need to retrieve a copy and point to it in the CERT_INFO // structure. SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle; CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT)); // Point to SubjectPublicKeyInfo field inside the CERT_INFO structure. IntPtr pSubjectPublicKeyInfo = new IntPtr((long) pCertContext.pCertInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_INFO), "SubjectPublicKeyInfo")); // Point to Algorithm field inside the SubjectPublicKeyInfo field. IntPtr pAlgorithm = new IntPtr((long) pSubjectPublicKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO), "Algorithm")); // Point to Parameters field inside the Algorithm field. IntPtr pParameters = new IntPtr((long) pAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters")); // Retrieve the pszObjId pointer. IntPtr pObjId = Marshal.ReadIntPtr(pAlgorithm); // Translate the OID to AlgId value. CAPI.CRYPT_OID_INFO pOIDInfo = CAPI.CryptFindOIDInfo(CAPI.CRYPT_OID_INFO_OID_KEY, pObjId, CAPI.CRYPT_PUBKEY_ALG_OID_GROUP_ID); // Is this DSS? if (pOIDInfo.Algid == CAPI.CALG_DSS_SIGN) { bool inheritParameters = false; // This is DSS, so inherit the parameters if necessary. IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); if (Marshal.ReadInt32(pcbData) == 0) { inheritParameters = true; } else { // Need to inherit if NULL pbData or *pbData is 0x05 (NULL ASN tag). if (Marshal.ReadIntPtr(ppbData) == IntPtr.Zero) { inheritParameters = true; } else { IntPtr pbData = Marshal.ReadIntPtr(ppbData); if ((uint) Marshal.ReadInt32(pbData) == CAPI.ASN_TAG_NULL) { inheritParameters = true; } } } // Do we need to copy inherited DSS parameters? if (inheritParameters) { // Build the chain to force CAPI to propagate the parameters to // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. SafeCertChainHandle pChainContext = SafeCertChainHandle.InvalidHandle; X509Utils.BuildChain(new IntPtr(CAPI.HCCE_CURRENT_USER), X509Utils.GetCertContext(certificate), null, null, null, X509RevocationMode.NoCheck, X509RevocationFlag.ExcludeRoot, DateTime.Now, new TimeSpan(0, 0, 0), // default ref pChainContext); pChainContext.Dispose(); // The parameter is inherited in the extended property, but not copied // to CERT_INFO, so we need to do it ourselves. uint cbParameters = 0; if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, pbParameters, ref cbParameters)) throw new CryptographicException(Marshal.GetLastWin32Error()); if (cbParameters > 0) { pbParameters = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbParameters)); if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, pbParameters, ref cbParameters)) throw new CryptographicException(Marshal.GetLastWin32Error()); Marshal.WriteInt32(pcbData, (int)cbParameters); Marshal.WriteIntPtr(ppbData, pbParameters.DangerousGetHandle()); } } } // Is this counter signer? if (m_parentSignerInfo == null) { // Just plain signer. if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(), 0, CAPI.CMSG_CTRL_VERIFY_SIGNATURE, pCertContext.pCertInfo)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } else { // Counter signer, so need to first find parent signer's index. int index = -1; int lastWin32Error = 0; // Since we allow the same signer to sign more than once, // we must than try all signatures of the same signer. while (true) { try { // Find index of parent signer. index = PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), m_parentSignerInfo, index + 1); } catch (CryptographicException) { // Did we ever find a signature of the same signer? if (lastWin32Error == 0) { // No. So we just re-throw, which is most likely CAPI.CRYPT_E_SIGNER_NOT_FOUND. throw; } else { // Yes. Throw previous error, which is most likely CAPI.NTE_BAD_SIGNATURE. throw new CryptographicException(lastWin32Error); } } // Now get the parent encoded singer info. uint cbParentEncodedSignerInfo = 0; SafeLocalAllocHandle pbParentEncodedSignerInfo = SafeLocalAllocHandle.InvalidHandle; PkcsUtils.GetParam(m_signedCms.GetCryptMsgHandle(), CAPI.CMSG_ENCODED_SIGNER, (uint) index, out pbParentEncodedSignerInfo, out cbParentEncodedSignerInfo); // Try next signer if we can't get parent of this signer. if (cbParentEncodedSignerInfo == 0) { lastWin32Error = CAPI.CRYPT_E_NO_SIGNER; continue; } fixed (byte * pbEncodedSignerInfo = m_encodedSignerInfo) { if (!CAPI.CryptMsgVerifyCountersignatureEncoded(IntPtr.Zero, CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, pbParentEncodedSignerInfo.DangerousGetHandle(), cbParentEncodedSignerInfo, new IntPtr(pbEncodedSignerInfo), (uint) m_encodedSignerInfo.Length, pCertContext.pCertInfo)) { // Cache the error, and try next signer. lastWin32Error = Marshal.GetLastWin32Error(); continue; } } // Keep alive. pbParentEncodedSignerInfo.Dispose(); // The signature is successfully verified. break; } } // Verfiy the cert if requested. if (!verifySignatureOnly) { int hr = VerifyCertificate(certificate, extraStore); if (hr != CAPI.S_OK) throw new CryptographicException(hr); } // Keep alive. pbParameters.Dispose(); } private unsafe void RemoveCounterSignature (int parentIndex, int childIndex) { // Just make sure this is non-negative. if (parentIndex < 0) throw new ArgumentOutOfRangeException("parentIndex"); if (childIndex < 0) throw new ArgumentOutOfRangeException("childIndex"); uint cbCmsgCmsSignerInfo = 0; SafeLocalAllocHandle pbCmsgCmsSignerInfo = SafeLocalAllocHandle.InvalidHandle; uint cbCmsgSignerInfo = 0; SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle; uint index = 0; uint cAttr = 0; IntPtr pAttr = IntPtr.Zero; SafeCryptMsgHandle hMsg = m_signedCms.GetCryptMsgHandle(); if (PkcsUtils.CmsSupported()) { PkcsUtils.GetParam(hMsg, CAPI.CMSG_CMS_SIGNER_INFO_PARAM, (uint) parentIndex, out pbCmsgCmsSignerInfo, out cbCmsgCmsSignerInfo); CAPI.CMSG_CMS_SIGNER_INFO cmsgCmsSignerInfo = (CAPI.CMSG_CMS_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgCmsSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_CMS_SIGNER_INFO)); cAttr = cmsgCmsSignerInfo.UnauthAttrs.cAttr; pAttr = new IntPtr((long) cmsgCmsSignerInfo.UnauthAttrs.rgAttr); } else { PkcsUtils.GetParam(hMsg, CAPI.CMSG_SIGNER_INFO_PARAM, (uint) parentIndex, out pbCmsgSignerInfo, out cbCmsgSignerInfo); CAPI.CMSG_SIGNER_INFO cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); cAttr = cmsgSignerInfo.UnauthAttrs.cAttr; pAttr = new IntPtr((long) cmsgSignerInfo.UnauthAttrs.rgAttr); } // Find index for counter signature attribute. // Note: It is not guaranteed that CAPI will keep all counter signatures // in one single unauthenticated attribute. So we need to find the correct // unauthenticated attribute containing this counter signer which is // identified by index. for (index = 0; index < cAttr; index++) { CAPI.CRYPT_ATTRIBUTE attr = (CAPI.CRYPT_ATTRIBUTE) Marshal.PtrToStructure(pAttr, typeof(CAPI.CRYPT_ATTRIBUTE)); if (String.Compare(attr.pszObjId, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) { if (attr.cValue > 0) { // Is it in this attribute? if (childIndex < (int) attr.cValue) { // Found the desired counter signature attribute. So, first remove the // entire attribute, then remove just the counter signature from the // retrieved attribute, and finally add back the modified attribute, // if necessary. CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA delPara = new CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA))); delPara.dwSignerIndex = (uint) parentIndex; delPara.dwUnauthAttrIndex = index; if (!CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR, new IntPtr(&delPara))) throw new CryptographicException(Marshal.GetLastWin32Error()); // No need to add back if only one counter signature in this attribute. if (attr.cValue > 1) { try { // There were more than one counter signatures in this attribute, so // need to add back a new counter signature attribute which includes // the remaining counter signatures. uint cbCounterSignatureValue = (uint) ((attr.cValue - 1) * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))); SafeLocalAllocHandle pbCounterSignatureValue = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbCounterSignatureValue)); // Copy everything except the one being removed. CAPI.CRYPTOAPI_BLOB * pOldValue = (CAPI.CRYPTOAPI_BLOB *) attr.rgValue; CAPI.CRYPTOAPI_BLOB * pNewValue = (CAPI.CRYPTOAPI_BLOB *) pbCounterSignatureValue.DangerousGetHandle(); for (int i = 0; i < (int) attr.cValue; i++, pOldValue++, pNewValue++) { if (i != childIndex) { *pNewValue = *pOldValue; } } // Encode the new counter signature attribute. byte[] encodedNewAttribute; CAPI.CRYPT_ATTRIBUTE newAttr = new CAPI.CRYPT_ATTRIBUTE(); newAttr.pszObjId = attr.pszObjId; newAttr.cValue = attr.cValue - 1; newAttr.rgValue = pbCounterSignatureValue.DangerousGetHandle(); SafeLocalAllocHandle pNewAttr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE)))); Marshal.StructureToPtr(newAttr, pNewAttr.DangerousGetHandle(), false); try { if (!CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE), pNewAttr.DangerousGetHandle(), out encodedNewAttribute)) throw new CryptographicException(Marshal.GetLastWin32Error()); } finally { Marshal.DestroyStructure(pNewAttr.DangerousGetHandle(), typeof(CAPI.CRYPT_ATTRIBUTE)); pNewAttr.Dispose(); } // Finally, add it back. fixed (byte * pbData = &encodedNewAttribute[0]) { CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA))); addPara.dwSignerIndex = (uint) parentIndex; addPara.blob.cbData = (uint) encodedNewAttribute.Length; addPara.blob.pbData = new IntPtr(pbData); if (!CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, new IntPtr(&addPara))) throw new CryptographicException(Marshal.GetLastWin32Error()); } // Keep alive. pbCounterSignatureValue.Dispose(); } catch (CryptographicException) { // Roll back. byte[] encodedAttribute; if (CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE), pAttr, out encodedAttribute)) { fixed (byte * pbData = &encodedAttribute[0]) { CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA))); addPara.dwSignerIndex = (uint) parentIndex; addPara.blob.cbData = (uint) encodedAttribute.Length; addPara.blob.pbData = new IntPtr(pbData); CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, new IntPtr(&addPara)); } } throw; } } return; } childIndex -= (int) attr.cValue; } } pAttr = new IntPtr((long) pAttr + (long) Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE))); } // Keep alive. if (pbCmsgCmsSignerInfo != null && !pbCmsgCmsSignerInfo.IsInvalid) { pbCmsgCmsSignerInfo.Dispose(); } if (pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid) { pbCmsgSignerInfo.Dispose(); } throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); } // // Private static. // private static unsafe int VerifyCertificate (X509Certificate2 certificate, X509Certificate2Collection extraStore) { int dwErrorStatus; int hr = X509Utils.VerifyCertificate(X509Utils.GetCertContext(certificate), null, null, X509RevocationMode.Online, X509RevocationFlag.ExcludeRoot, DateTime.Now, new TimeSpan(0, 0, 0), extraStore, new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE), new IntPtr(&dwErrorStatus)); if (hr != CAPI.S_OK) return dwErrorStatus; // Check key usages to make sure it is good for signing. foreach (X509Extension extension in certificate.Extensions) { if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) { X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); keyUsage.CopyFrom(extension); if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 && (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) { hr = CAPI.CERT_E_WRONG_USAGE; break; } } } return hr; } } [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class SignerInfoCollection : ICollection { private SignerInfo[] m_signerInfos; internal SignerInfoCollection () { m_signerInfos = new SignerInfo[0]; } internal unsafe SignerInfoCollection (SignedCms signedCms) { uint dwSigners = 0; uint cbCount = (uint) Marshal.SizeOf(typeof(uint)); SafeCryptMsgHandle safeCryptMsgHandle = signedCms.GetCryptMsgHandle(); if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, CAPI.CMSG_SIGNER_COUNT_PARAM, 0, new IntPtr(&dwSigners), new IntPtr(&cbCount))) throw new CryptographicException(Marshal.GetLastWin32Error()); SignerInfo[] signerInfos = new SignerInfo[dwSigners]; for (int index = 0; index < dwSigners; index++) { uint cbCmsgSignerInfo = 0; if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, CAPI.CMSG_SIGNER_INFO_PARAM, (uint) index, IntPtr.Zero, new IntPtr(&cbCmsgSignerInfo))) throw new CryptographicException(Marshal.GetLastWin32Error()); SafeLocalAllocHandle pbCmsgSignerInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbCmsgSignerInfo)); if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, CAPI.CMSG_SIGNER_INFO_PARAM, (uint) index, pbCmsgSignerInfo, new IntPtr(&cbCmsgSignerInfo))) throw new CryptographicException(Marshal.GetLastWin32Error()); signerInfos[index] = new SignerInfo(signedCms, pbCmsgSignerInfo); } m_signerInfos = signerInfos; } internal unsafe SignerInfoCollection (SignedCms signedCms, SignerInfo signerInfo) { SignerInfo[] signerInfos = new SignerInfo[0]; int count = 0; int index = 0; foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) { if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) { count += attribute.Values.Count; } } signerInfos = new SignerInfo[count]; foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) { if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) { for (int i = 0; i < attribute.Values.Count; i++) { AsnEncodedData encodedSignerInfo = (AsnEncodedData) attribute.Values[i]; signerInfos[index++] = new SignerInfo(signedCms, signerInfo, encodedSignerInfo.RawData); } } } m_signerInfos = signerInfos; } public SignerInfo this[int index] { get { if (index < 0 || index >= m_signerInfos.Length) throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index")); Debug.Assert(m_signerInfos[index] != null); return m_signerInfos[index]; } } public int Count { get { return m_signerInfos.Length; } } public SignerInfoEnumerator GetEnumerator() { return new SignerInfoEnumerator(this); } /// IEnumerator IEnumerable.GetEnumerator() { return new SignerInfoEnumerator(this); } public void CopyTo(Array array, int index) { if (array == null) throw new ArgumentNullException("array"); if (array.Rank != 1) throw new ArgumentException(SecurityResources.GetResourceString("Arg_RankMultiDimNotSupported")); if (index < 0 || index >= array.Length) throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index")); if (index + this.Count > array.Length) throw new ArgumentException(SecurityResources.GetResourceString("Argument_InvalidOffLen")); for (int i=0; i < this.Count; i++) { array.SetValue(this[i], index); index++; } } public void CopyTo(SignerInfo[] array, int index) { ((ICollection)this).CopyTo(array, index); } public bool IsSynchronized { get { return false; } } public Object SyncRoot { get { return this; } } } [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class SignerInfoEnumerator : IEnumerator { private SignerInfoCollection m_signerInfos; private int m_current; private SignerInfoEnumerator() {} internal SignerInfoEnumerator(SignerInfoCollection signerInfos) { m_signerInfos = signerInfos; m_current = -1; } public SignerInfo Current { get { return m_signerInfos[m_current]; } } /// Object IEnumerator.Current { get { return (Object) m_signerInfos[m_current]; } } public bool MoveNext() { if (m_current == ((int) m_signerInfos.Count - 1)) { return false; } m_current++; return true; } public void Reset() { m_current = -1; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XamlRtfConverter.cs
- _NegoStream.cs
- TextDecorationCollection.cs
- BitFlagsGenerator.cs
- FormViewCommandEventArgs.cs
- _UriSyntax.cs
- PropertyGridEditorPart.cs
- DiscoveryVersionConverter.cs
- X509Certificate.cs
- JoinGraph.cs
- DBConcurrencyException.cs
- FrameworkEventSource.cs
- GridSplitter.cs
- ContextMarshalException.cs
- ServiceDiscoveryBehavior.cs
- TransformPattern.cs
- WmlLabelAdapter.cs
- EmptyQuery.cs
- ContainerParaClient.cs
- DataGridColumnFloatingHeader.cs
- ValueProviderWrapper.cs
- DocumentXPathNavigator.cs
- WriteableBitmap.cs
- ClearCollection.cs
- HttpInputStream.cs
- CellConstantDomain.cs
- ConditionalAttribute.cs
- DataSourceControl.cs
- MonitoringDescriptionAttribute.cs
- SecuritySessionSecurityTokenAuthenticator.cs
- SurrogateSelector.cs
- ScriptingScriptResourceHandlerSection.cs
- WindowsPen.cs
- EventRecordWrittenEventArgs.cs
- unitconverter.cs
- RemoveStoryboard.cs
- DataGridRowDetailsEventArgs.cs
- LayoutTable.cs
- _AutoWebProxyScriptHelper.cs
- SchemaObjectWriter.cs
- SqlCharStream.cs
- WebPartVerbCollection.cs
- TemplateBamlRecordReader.cs
- safelink.cs
- DecoderNLS.cs
- UndoManager.cs
- EntityClassGenerator.cs
- ErrorReporting.cs
- SmtpAuthenticationManager.cs
- SafeTokenHandle.cs
- ErrorTableItemStyle.cs
- Helpers.cs
- HttpProfileGroupBase.cs
- WebBrowserEvent.cs
- FailedToStartupUIException.cs
- DefaultBinder.cs
- ResourceDisplayNameAttribute.cs
- RolePrincipal.cs
- CallbackHandler.cs
- COMException.cs
- CheckableControlBaseAdapter.cs
- Application.cs
- DataGridItemEventArgs.cs
- AnnotationAdorner.cs
- VirtualizedContainerService.cs
- PermissionAttributes.cs
- SecureStringHasher.cs
- TriggerAction.cs
- RequestResizeEvent.cs
- MonitoringDescriptionAttribute.cs
- ADMembershipProvider.cs
- XmlSchemaInferenceException.cs
- CommandValueSerializer.cs
- TCEAdapterGenerator.cs
- AtomMaterializerLog.cs
- PolicyUnit.cs
- ItemCollection.cs
- LeafCellTreeNode.cs
- BrowserCapabilitiesCodeGenerator.cs
- TextDecorationCollection.cs
- HostedHttpContext.cs
- AppDomainGrammarProxy.cs
- StylusOverProperty.cs
- GridViewRowPresenter.cs
- FixedStringLookup.cs
- TypeConverterHelper.cs
- GuidTagList.cs
- RtfToXamlLexer.cs
- StringConverter.cs
- SessionEndedEventArgs.cs
- ObjectListItemCollection.cs
- XmlCodeExporter.cs
- FloatAverageAggregationOperator.cs
- WebPartConnectionsDisconnectVerb.cs
- ClipboardProcessor.cs
- LocalizabilityAttribute.cs
- HyperLink.cs
- SwitchExpression.cs
- ParameterModifier.cs
- SeekStoryboard.cs