/// <summary> /// Метод вычисления подписи без использования закрытого ключа /// </summary> /// <param name="prefix"></param> /// <param name="certificate"></param> public void ComputeSignatureWithoutPrivateKey(string prefix, IntPtr certificate) { if (SignServiceUtils.IsUnix) { CryptoConfig.AddAlgorithm(typeof(HashAlgGost2001Unix), new string[1] { "http://www.w3.org/2001/04/xmldsig-more#gostr3411" }); CryptoConfig.AddAlgorithm(typeof(HashAlgGost2012_256Unix), new string[1] { "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256" }); CryptoConfig.AddAlgorithm(typeof(HashAlgGost2012_512Unix), new string[1] { "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-512" }); } else { CryptoConfig.AddAlgorithm(typeof(HashAlgGost2001Win), new string[1] { "http://www.w3.org/2001/04/xmldsig-more#gostr3411" }); CryptoConfig.AddAlgorithm(typeof(HashAlgGost2012_256Win), new string[1] { "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256" }); CryptoConfig.AddAlgorithm(typeof(HashAlgGost2012_512Win), new string[1] { "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-512" }); } CryptoConfig.AddAlgorithm(typeof(SmevTransformAlg), new string[1] { SmevTransformAlg.ALGORITHM_URI }); BuildDigestedReferences(); int algId = 0; HashAlgorithm hash = SignServiceUtils.GetHashAlgObject(certificate, ref algId); GetDigest(hash, prefix); uint keySpec = CApiExtConst.AT_SIGNATURE; IntPtr cpHandle = (SignServiceUtils.IsUnix) ? UnixExtUtil.GetHandler(certificate, out keySpec) : Win32ExtUtil.GetHandler(certificate, out keySpec); byte[] sign = (SignServiceUtils.IsUnix) ? UnixExtUtil.SignValue(cpHandle, (int)keySpec, hash.Hash, (int)0, algId) : Win32ExtUtil.SignValue(cpHandle, (int)keySpec, hash.Hash, (int)0, algId); Array.Reverse(sign); m_signature.SignatureValue = sign; SignServiceUtils.ReleaseProvHandle(cpHandle); }
/// <summary> /// Метод рассчета хэш /// </summary> /// <param name="data"></param> /// <param name="publicKeyAlg"></param> /// <param name="pluginHashAlg"></param> /// <returns></returns> private string ComputeHash(Stream data, string publicKeyAlg, ref int pluginHashAlg) { log.LogDebug($"Определяем алгоритм хэширования по значению алгоритма публичного ключа: {publicKeyAlg}."); // Определение алгоритма. var algId = GetHashAlg(publicKeyAlg); log.LogDebug("Определяем идентификатор алгоритма для использования в плагине КриптоПро."); // Определение идентификатора алгоритма для использование в плагине КриптоПро. var hashAlgForPlugin = SignServiceUtils.GetHashCodeForPlugin(algId); pluginHashAlg = hashAlgForPlugin; log.LogDebug("Вычисляем хэш."); // Вычисление хэш. var base64Hash = GetHashBySigAlgId(data, algId); return(base64Hash); }
/// <summary> /// Метод получения хэш /// </summary> /// <param name="data"></param> /// <param name="algId"></param> /// <returns></returns> internal string GetHashBySigAlgId(Stream data, uint algId) { log.LogDebug("Запущен метод получения хэш под Windows платформой."); byte[] hashResult = null; if (algId == CApiExtConst.GOST341194) { log.LogDebug($"Полученный алгоритм хэширования {algId} соответствует ГОСТ-2001"); HashAlgorithm hash = new HashAlgGost2001Win(); hashResult = hash.ComputeHash(data); } else if (algId == CApiExtConst.GOST2012_256) { log.LogDebug($"Полученный алгоритм хэширования {algId} соответствует ГОСТ-2012-256"); var hash = new HashAlgGost2012_256Win(); hashResult = hash.ComputeHash(data); } else if (algId == CApiExtConst.GOST2012_512) { log.LogDebug($"Полученный алгоритм хэширования {algId} соответствует ГОСТ-2012-512"); var hash = new HashAlgGost2012_512Win(); hashResult = hash.ComputeHash(data); } else { log.LogError($"Полученный алгоритм хэширования {algId} не соответствует поддерживаемым ГОСТ алгоритмам."); throw new Exception($"Полученный алгоритм хэширования {algId} не соответствует поддерживаемым ГОСТ алгоритмам."); } if (hashResult == null || hashResult.Length <= 0) { log.LogError("Не удалось вычислить хэш. Отсутствует значение."); throw new CryptographicException("Ошибка при получении хэш."); } log.LogDebug($"Хэш получен. Преобразуем в Hex строку."); var hexStr = SignServiceUtils.ConvertByteToHex(hashResult); log.LogDebug("Преобразование выполнено успешно."); return(hexStr); }
/// <summary> /// Метод получения алгоритма хэширования /// </summary> /// <param name="signatureAlgOid"></param> /// <returns></returns> private uint GetHashAlg(string publicKeyAlg) { string signatureAlgOid = SignServiceUtils.GetSignatureAlg(publicKeyAlg); if (SignServiceUtils.IsUnix) { log.LogDebug("Получаем алгоритм хэширования под Unix платформой."); var cryptOidInfo = SignServiceUnix.GetHashAlg(signatureAlgOid); return(cryptOidInfo.Algid); } else { log.LogDebug("Получаем алгоритм хэширования под Windows платформой."); var cryptOidInfo = SignServiceWin.GetHashAlg(signatureAlgOid); return(cryptOidInfo.Algid); } }
internal X509Certificate2Collection GetTrustedCertificates() { log.LogDebug("Пытаемся получить доступ к хранилищу доверенных сертификатов текущего пользователя."); IntPtr handleSysStore = IntPtr.Zero; try { // Открываем хранилище сертификатов handleSysStore = CApiExtUnix.CertOpenStore(CApiExtConst.CERT_STORE_PROV_SYSTEM, 0, IntPtr.Zero, CApiExtConst.CURRENT_USER, "TrustedPublisher"); if (handleSysStore == IntPtr.Zero || handleSysStore == null) { log.LogError("Не удалось открыть хранилище Доверенных издателей для текущего пользователя. Handler == 0."); throw new CryptographicException("Ошибка, не удалось открыть хранилище Доверенных издателей для текущего пользователя."); } IntPtr currentCertContext = CApiExtUnix.CertEnumCertificatesInStore(handleSysStore, IntPtr.Zero); X509Certificate2Collection trustedList = new X509Certificate2Collection(); while (currentCertContext != IntPtr.Zero) { // Формируем X509Certificate2 из IntPtr var x509Certificate2 = SignServiceUtils.GetX509Certificate2(currentCertContext); trustedList.Add(x509Certificate2); currentCertContext = CApiExtUnix.CertEnumCertificatesInStore(handleSysStore, currentCertContext); } return(trustedList); } finally { // Закрываем хранилище сертификатов CApiExtUnix.CertCloseStore(handleSysStore, 0); } }
/// <summary> /// Метод добавляет в XML тэг <ds:Reference></Reference> /// </summary> /// <param name="doc"></param> /// <param name="signedXml"></param> /// <param name="customTag"></param> /// <param name="customNamespace"></param> /// <param name="precedingSibling"></param> /// <returns></returns> internal static SignedXml AddReference(XmlDocument doc, SignedXml signedXml, IntPtr certificate, bool signWithId, Mr mr, SignedTag elemForSign, ref int idCounter, string tagForSign, string tagForSignNamespaceUri, string namespaceIdAttr = "", string customTag = "", string customNamespace = "" ) { Reference reference = new Reference(); string id = string.Empty; if (elemForSign == SignedTag.CustomTag && string.IsNullOrEmpty(customTag) != true) { id = SmevXmlHelper.GetElemId(doc, customTag, customNamespace, signWithId); if (string.IsNullOrEmpty(id) && signWithId) { if (mr == Mr.MR300) { SmevXmlHelper.SetElemId(doc, customTag, NamespaceUri.WSSoap11, signWithId, mr, ref idCounter); } else { id = "#" + SmevXmlHelper.SetElemId(doc, customTag, tagForSignNamespaceUri, signWithId, mr, ref idCounter, "", namespaceIdAttr); } } } else { id = SmevXmlHelper.GetElemId(doc, tagForSign, tagForSignNamespaceUri, signWithId); if (string.IsNullOrEmpty(id) && signWithId) { if (mr == Mr.MR300) { id = SmevXmlHelper.SetElemId(doc, tagForSign, tagForSignNamespaceUri, signWithId, mr, ref idCounter); } else { id = "#" + SmevXmlHelper.SetElemId(doc, tagForSign, tagForSignNamespaceUri, signWithId, mr, ref idCounter, "", namespaceIdAttr); } } } reference.Uri = (signWithId) ? id : string.Empty; reference.DigestMethod = SignServiceUtils.GetDigestMethod(SignServiceUtils.GetAlgId(certificate)); if (string.IsNullOrEmpty(customTag) != true && elemForSign == SignedTag.CustomTag) { XmlDsigEnvelopedSignatureTransform envelop = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(envelop); } XmlDsigExcC14NTransform c14 = new XmlDsigExcC14NTransform(); reference.AddTransform(c14); if (mr == Mr.MR300) { SmevTransformAlg smevTransform = new SmevTransformAlg(); reference.AddTransform(smevTransform); } signedXml.AddReference(reference); return(signedXml); }
/// <summary> /// Метод подписи XML подписью органа власти /// </summary> /// <param name="doc"></param> /// <param name="certificate"></param> /// <returns></returns> public XmlDocument SignMessageAsOv(XmlDocument doc, IntPtr certificate) { try { // Подписываем вложения log.LogDebug("Пытаемся подписать вложения."); doc = SignAttachmentsOv(doc, certificate); } catch (Exception ex) { log.LogError($"Ошибка при попытке проверить и подписать вложения в методе. {ex.Message}."); throw new CryptographicException($"Ошибка при попытке проверить и подписать вложения. {ex.Message}"); } try { // Подписываем XML log.LogDebug("Пытаемся подписать XML."); Smev3xxSignedXml signedXml = new Smev3xxSignedXml(doc); ElemForSign = SignedTag.Smev3TagType; try { log.LogDebug($"Пытаемся найти тэг для подписи."); tagForSign = FindSmevTagForSign(doc); log.LogDebug($"Тэг для подписи: {tagForSign}."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке определить тэг для подписи. {ex.Message}."); } try { log.LogDebug("Пытаемся удалить информацию о подписи, если есть."); RemoveCallerInformationSystemSignature(doc.DocumentElement); log.LogDebug("Удаление выполнено успешно."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке удалить информацию о подписи. {ex.Message}."); } try { log.LogDebug($"Пытаемся установить значение идентификатора элемента. Флаг SignWithId: {SignWithId}."); SmevXmlHelper.SetElemId(doc, tagForSign, tagForSignNamespaceUri, SignWithId, MrVersion, ref idCounter, SmevMr3xxTags.InformationSystemSignatureId); log.LogDebug($"Установка значения идентификатора элемента выполнена успешно."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке установить идентификатор элемента. {ex.Message}."); } try { log.LogDebug($"Пытаемся добавить в XML тэг Reference."); signedXml = (Smev3xxSignedXml)SmevXmlHelper.AddReference(doc, signedXml, certificate, SignWithId, MrVersion, ElemForSign, ref idCounter, tagForSign, tagForSignNamespaceUri ); log.LogDebug($"Тэг Reference успешно добавлен."); } catch (Exception ex) { throw new Exception($"Ошибка при добавлении тэга Reference. {ex.Message}."); } signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; try { log.LogDebug($"Пытаемся получить значение SignatureMethod."); signedXml.SignedInfo.SignatureMethod = SignServiceUtils.GetSignatureMethod(SignServiceUtils.GetAlgId(certificate)); log.LogDebug($"Значение SignatureMethod успешно получено: {signedXml.SignedInfo.SignatureMethod}."); } catch (Exception ex) { throw new Exception($"Ошибка при получении значения алгоритма подписи. {ex.Message}."); } try { KeyInfo keyInfo = new KeyInfo(); X509Certificate2 cert = SignServiceUtils.GetX509Certificate2(certificate); keyInfo.AddClause(new KeyInfoX509Data(cert)); signedXml.KeyInfo = keyInfo; } catch (Exception ex) { throw new Exception($"Ошибка при формировании элемента KeyInfo. {ex.Message}."); } try { log.LogDebug($"Пытаемся вычислить подпись."); signedXml.ComputeSignatureWithoutPrivateKey(xmldsigPrefix, certificate); log.LogDebug($"Вычисление подписи выполнено успешно."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке вычислить подпись для XML. {ex.Message}."); } XmlElement signatureElem = null; XmlElement sysSignature = null; try { log.LogDebug("Пытаемся получить элемент с подписью."); signatureElem = signedXml.GetXml(xmldsigPrefix); log.LogDebug("Элемент с подписью успешно получен."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить элемент содержащий подпись. {ex.Message}."); } string prefix = FindPrefix(doc.DocumentElement, false); try { log.LogDebug("Заполняем объект sysSignature элементом в с подписью и префиксом."); if (!string.IsNullOrEmpty(prefix)) { sysSignature = doc.CreateElement(prefix, SignatureTags.CallerInformationSystemSignatureTag, SignatureTags.CallerInformationSystemSignatureNamespace); sysSignature.PrependChild(doc.ImportNode(signatureElem, true)); } else { sysSignature = doc.CreateElement("", SignatureTags.CallerInformationSystemSignatureTag, SignatureTags.CallerInformationSystemSignatureNamespace); sysSignature.PrependChild(doc.ImportNode(signatureElem, true)); } log.LogDebug("Заполнение объекта sysSignature успешно выполнено."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке сформировать элемент sysSignature. {ex.Message}."); } try { log.LogDebug("Пытаемся добавить подпись в XML содержимое."); FillSignatureElement(doc, sysSignature, certificate, tagForRequest, tagForRequestNamespaceUri, true); log.LogDebug("Подпись успешно добавлена."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке заполнить XML информацией о подписи. {ex.Message}."); } return(doc); } catch (Exception ex) { log.LogError($"Ошибка при попытке подписать XML. {ex.Message}. StackTrace: {ex.StackTrace}."); throw new CryptographicException($"Ошибка при попытке подписать XML для версии МР300. {ex.Message}."); } finally { SignServiceUtils.FreeHandleCertificate(certificate); } }
internal static byte[] Sign(byte[] data, IntPtr hCert) { // Структура содержит информацию для подписания сообщений с использованием указанного контекста сертификата подписи CApiExtConst.CRYPT_SIGN_MESSAGE_PARA pParams = new CApiExtConst.CRYPT_SIGN_MESSAGE_PARA { // Размер этой структуры в байтах cbSize = (uint)Marshal.SizeOf(typeof(CApiExtConst.CRYPT_SIGN_MESSAGE_PARA)), // Используемый тип кодирования dwMsgEncodingType = CApiExtConst.PKCS_7_OR_X509_ASN_ENCODING, // Указатель на CERT_CONTEXT, который будет использоваться при подписании. // Для того чтобы контекст предоставил доступ к закрытому сигнатурному ключу, // необходимо установить свойство CERT_KEY_PROV_INFO_PROP_ID или CERT_KEY_CONTEXT_PROP_ID pSigningCert = hCert, // Количество элементов в rgpMsgCert массиве CERT_CONTEXT структур.Если установлено ноль, // в подписанное сообщение не включаются сертификаты. cMsgCert = 1 }; CApiExtConst.CERT_CONTEXT contextCert = Marshal.PtrToStructure <CApiExtConst.CERT_CONTEXT>(hCert); CApiExtConst.CERT_INFO certInfo = Marshal.PtrToStructure <CApiExtConst.CERT_INFO>(contextCert.pCertInfo); var signatureAlg = SignServiceUtils.GetSignatureAlg(certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId); var cryptOidInfo = GetHashAlg(signatureAlg); //Содержащий алгоритм хеширования, используемый для хеширования данных, подлежащих подписке. pParams.HashAlgorithm.pszObjId = cryptOidInfo.pszOID; // Массив указателей на буферы, содержащие содержимое, подлежащее подписке. IntPtr rgpbToBeSigned = Marshal.AllocHGlobal(data.Length); // Выделяем память под хранение сертификата GCHandle pGC = GCHandle.Alloc(hCert, GCHandleType.Pinned); try { // Массив указателей на контексты сертификатов для включения в подписанное сообщение. // Если хотим использовать сертификат для подписания, указатель на него должен быть в массиве rgpMsgCert. pParams.rgpMsgCert = pGC.AddrOfPinnedObject(); Marshal.Copy(data, 0, rgpbToBeSigned, data.Length); // Указатель, определяющий размер в байтах буфера signArray . // Когда функция возвращается, эта переменная содержит размер в байтах подписанного и закодированного сообщения. uint signArrayLength = 0; // Указатель на буфер , для получения кодированного подписанного хэш, если detached является значение TRUE , // или как кодированного контента и подписанного хэша , если detached является FALSE. byte[] signArray = null; // TRUE, если это должна быть отдельная подпись, Если для этого параметра установлено значение TRUE , в pbSignedBlob кодируется только подписанный хеш . // В противном случае кодируются как rgpbToBeSigned, так и подписанный хеш. bool detached = true; // Количество элементов массива в rgpbToBeSigned. // Этот параметр должен быть установлен в единицу, если для параметра fDetachedSignature установлено значение TRUE uint cToBeSigned = 1; // Подписываем данные // new uint[1] { (uint)data.Length } - Массив размеров в байтах буферов содержимого, на которые указывает rgpbToBeSigned if (!CApiExtWin.CryptSignMessage(ref pParams, detached, cToBeSigned, new IntPtr[1] { rgpbToBeSigned }, new uint[1] { (uint)data.Length }, signArray, ref signArrayLength)) { throw new CryptographicException($"Ошибка при подписании данных. Первый вызов CryptSignMessage вернул false. Код ошибки: {Marshal.GetLastWin32Error()}."); } signArray = new byte[signArrayLength]; if (!CApiExtWin.CryptSignMessage(ref pParams, detached, cToBeSigned, new IntPtr[1] { rgpbToBeSigned }, new uint[1] { (uint)data.Length }, signArray, ref signArrayLength)) { throw new CryptographicException($"Ошибка при подписании данных. Второй вызов CryptSignMessage вернул false. Код ошибки: {Marshal.GetLastWin32Error()}."); } return(signArray); } finally { Marshal.FreeHGlobal(rgpbToBeSigned); pGC.Free(); } }
internal IntPtr FindCertificate(string thumbprint) { IntPtr handleSysStore = IntPtr.Zero; IntPtr handleCert = IntPtr.Zero; // Формируем параметр для метода поиска CApiExtConst.CRYPT_HASH_BLOB hashb = new CApiExtConst.CRYPT_HASH_BLOB(); try { log.LogDebug($"Пытаемся открыть 'MY' хранилище сертификатов для Текущего пользователя."); // Открываем хранилище сертификатов handleSysStore = CApiExtWin.CertOpenStore(CApiExtConst.CERT_STORE_PROV_SYSTEM, 0, IntPtr.Zero, CApiExtConst.CURRENT_USER, "MY"); if (handleSysStore == IntPtr.Zero || handleSysStore == null) { log.LogError("Не удалось открыть хранилище 'MY' для текущего пользователя."); throw new CryptographicException("Ошибка, не удалось открыть хранилище 'MY' для текущего пользователя."); } log.LogDebug($"Личное хранилище сертификатов для Текущего пользователя успешно открыто."); log.LogDebug($"Пытаемся преобразовать значение Thumbprint в массив байт."); // Получаем значение thumbprint в виде массива байт byte[] sha1Hash = SignServiceUtils.HexStringToBinary(thumbprint); log.LogDebug("Значение Thumbprint успешно преобразовано в массив байт."); log.LogDebug("Пытаемся разместить бинарное значение Thumbprint в неуправляемой памяти."); try { hashb.pbData = Marshal.AllocHGlobal(thumbprint.Length); Marshal.Copy(sha1Hash, 0, hashb.pbData, sha1Hash.Length); hashb.cbData = sha1Hash.Length; } catch (Exception ex) { log.LogError($"Ошибка при попытке разместить значение Thumbprint в неуправляемой памяти. {ex.Message}."); Marshal.FreeHGlobal(hashb.pbData); throw new CryptographicException($"Ошибка при попытке разместить значение Thumbprint в неуправляемой памяти. {ex.Message}."); } log.LogDebug("Бинарное значение Thumbprint успешно размещено в неуправляемой памяти."); log.LogDebug("Пытаемся найти сертификат по Thumbprint данным в неуправляемой памяти."); // Ищем сертификат в хранилище handleCert = CApiExtWin.CertFindCertificateInStore(handleSysStore, CApiExtConst.PKCS_7_OR_X509_ASN_ENCODING, 0, CApiExtConst.CERT_FIND_SHA1_HASH, ref hashb, IntPtr.Zero); if (handleCert == IntPtr.Zero || handleCert == null) { log.LogError("Ошибка при получении дескриптора сертификата из хранилища 'MY', для текущего пользователя."); throw new CryptographicException("Ошибка при получении дескриптора сертификата из хранилища 'MY', для текущего пользователя."); } return(handleCert); } finally { Marshal.FreeHGlobal(hashb.pbData); CApiExtWin.CertCloseStore(handleSysStore, 0); } }
internal bool VerifyDetachedMessage(byte[] signatureData, byte[] messageData, bool isCheckTrusted, ref X509Certificate2 certFromSign) { log.LogDebug("Запущен метод проверки открепленной подписи под Unix платформой."); // Заполняем буфер с информацией о данных на основе которых получена подпись IntPtr messagePtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(byte)) * messageData.Length); Marshal.Copy(messageData, 0, messagePtr, messageData.Length); IntPtr[] rgpbToBeSigned = new IntPtr[1] { messagePtr }; int[] rgcbToBeSigned = new int[1] { messageData.Length }; GCHandle pCertContext = GCHandle.Alloc(IntPtr.Zero, GCHandleType.Pinned); CRYPT_VERIFY_MESSAGE_PARA verifyParams = new CRYPT_VERIFY_MESSAGE_PARA() { cbSize = (int)Marshal.SizeOf(typeof(CRYPT_VERIFY_MESSAGE_PARA)), dwMsgAndCertEncodingType = PKCS_7_OR_X509_ASN_ENCODING, hCryptProv = 0, pfnGetSignerCertificate = IntPtr.Zero, pvGetArg = IntPtr.Zero }; try { log.LogDebug("Выполняем проверку открепленной подписи."); bool result = CApiExtUnix.CryptVerifyDetachedMessageSignature( ref verifyParams, // Verify parameters. 0, // Signer index. signatureData, // Buffer for decoded message. signatureData.Length, // Size of buffer. 1, rgpbToBeSigned, // Pointer to signed BLOB. rgcbToBeSigned, // Size of signed BLOB. pCertContext.AddrOfPinnedObject() ); if (!result) { log.LogError($"Метод проверки подписи CryptVerifyDetachedMessageSignature вернул ошибку. Статус код ошибки: {Marshal.GetLastWin32Error()}."); return(result); } log.LogDebug($"Метод CryptVerifyDetachedMessageSignature вернул true. Пытаемся получить сертификат из подписи."); try { log.LogDebug($"Флаг проверки сертификата в списке доверенных издателей {(isCheckTrusted ? "установлен" : "не установлен")}"); if ((IntPtr)pCertContext.Target != IntPtr.Zero) { certFromSign = SignServiceUtils.GetX509Certificate2((IntPtr)pCertContext.Target); } if (isCheckTrusted) { log.LogDebug("Сертификат из подписи успешно получен. Проверяем наличие сертификата в списке доверенных издателей."); var trustedCerts = GetTrustedCertificates(); if (trustedCerts.Count <= 0) { log.LogError("Список доверенных издателей пуст. Отсутствует доверие к сертификату."); return(false); } if (!trustedCerts.Contains(certFromSign)) { log.LogError("Сертификат указанный в подписи не найден среди доверенных издателей."); return(false); } } } catch (Exception ex) { log.LogError($"Необработанная ошибка при попытке проверить сертификат из подписи на наличие в списке доверенных. {ex.Message}."); return(false); } finally { CApiExtUnix.CertFreeCertificateContext((IntPtr)pCertContext.Target); } log.LogDebug("Проверка выполнена. Подпись корректна."); return(result); } finally { pCertContext.Free(); } }
/// <summary> /// Добавляет тэг с подписью целиком. Сертификат должен быть в тэге подписи. /// </summary> /// <param name="doc"></param> /// <param name="signatureElem"></param> /// <param name="certificate"></param> /// <param name="token"></param> private void FillSignatureElement(XmlDocument doc, XmlElement signatureElem, IntPtr certificate, XmlElement token) { XmlElement wsseSecurity = doc.CreateElement("wsse", SignatureTags.SecurityTag, SignatureTags.SecurityNamespace); // <wsse:Security soap:actor="http://smev.gosuslugi.ru/actors/recipient" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> XmlAttribute actorAttr = doc.CreateAttribute("soap", "actor", NamespaceUri.WSSoap11); // МР 2.4.5. Информационная система органа власти Потребителя или ПГУ при формировании // запроса к ИС поставщика, а также ИС Поставщика при формировании ответа должны // проставлять в атрибуте actor значение, соответствующее СМЭВ как стороне проверяющей // подпись: // 38 // soapenv:actor="http://smev.gosuslugi.ru/actors/smev" // СМЭВ при формировании электронной подписи в запросе при отправке его поставщику // или при отправке ответа к потребителю проставляет в атрибуте actor значение: // soapenv:actor="http://smev.gosuslugi.ru/actors/recipient" // МР 2.5.5. При взаимодействии на уровне регионального узла СМЭВ между региональными // участниками, подключенными к данному узлу, предусматриваются такие же правила // взаимодействия информационных систем участников с узлом РСМЭВ, как и для // федерального узла СМЭВ: // формирование ЭП-ОВ от имени ИС регионального участника осуществляется с // использованием атрибута actor="http://smev.gosuslugi.ru/actors/smev"; // региональный узел СМЭВ формирует ЭП-РСМЭВ с использованием атрибута // actor="http://smev.gosuslugi.ru/actors/recipient" (данный формат является // локальным). actorAttr.Value = SmevAttributes.ActorSmev; wsseSecurity.Attributes.Append((XmlAttribute)doc.ImportNode(actorAttr, true)); XmlElement keyInfoElem = doc.CreateElement("KeyInfo", NamespaceUri.WSXmlDSig); XmlElement binaryTokenElem = doc.CreateElement("wsse", "BinarySecurityToken", NamespaceUri.OasisWSSecuritySecext); XmlElement tokenReferenceElem = doc.CreateElement("wsse", "SecurityTokenReference", NamespaceUri.OasisWSSecuritySecext); XmlElement referenceElem = doc.CreateElement("wsse", "Reference", NamespaceUri.OasisWSSecuritySecext); string certId = "uuid-" + Guid.NewGuid().ToString(); XmlAttribute idAttr = doc.CreateAttribute("u", "Id", NamespaceUri.OasisWSSecurityUtility); idAttr.Value = certId; binaryTokenElem.Attributes.Append((XmlAttribute)doc.ImportNode(idAttr, true)); XmlAttribute valueTypeAttr = doc.CreateAttribute("ValueType"); valueTypeAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"; referenceElem.Attributes.Append((XmlAttribute)doc.ImportNode(valueTypeAttr, true)); XmlAttribute uriAttr = doc.CreateAttribute("URI"); // URI="#CertId-5F344A8A21BB6902C113550467558881327" uriAttr.Value = "#" + certId; referenceElem.Attributes.Append((XmlAttribute)doc.ImportNode(uriAttr, true)); tokenReferenceElem.PrependChild(doc.ImportNode(referenceElem, true)); keyInfoElem.PrependChild(doc.ImportNode(tokenReferenceElem, true)); X509Certificate2 cert = SignServiceUtils.GetX509Certificate2(certificate); binaryTokenElem.InnerText = Convert.ToBase64String(cert.RawData); wsseSecurity.PrependChild(doc.ImportNode(signatureElem, true)); wsseSecurity.PrependChild(doc.ImportNode(token, true)); XmlElement headerElem = (XmlElement)doc.GetElementsByTagName("Header", NamespaceUri.WSSoap11)[0]; if (headerElem == null) { headerElem = doc.CreateElement("Header", NamespaceUri.WSSoap11); doc.DocumentElement.PrependChild(headerElem); } RemoveSecurityBodes(headerElem); headerElem.PrependChild(doc.ImportNode(wsseSecurity, true)); }
/// <summary> /// Метод подписи XML подписью органа власти /// </summary> /// <param name="doc"></param> /// <param name="certificate"></param> /// <returns></returns> private XmlDocument SignMessage2XX(XmlDocument xml, IntPtr certificate) { try { // Удаляем тэг Actor string message = string.Empty; try { log.LogDebug("Пытаемся удалить атрибут 'Actor'."); message = SoapDSigUtil.RemoveActor(xml); log.LogDebug("Атрибут 'Actor' успешно удален."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке удалить атрибут 'Actor'. {ex.Message}."); } XmlDocument doc = new XmlDocument() { PreserveWhitespace = true }; try { doc.LoadXml(message); } catch (Exception ex) { throw new Exception($"Ошибка при формировании XML после удаления атрибута 'Actor'. {ex.Message}."); } try { log.LogDebug("Получаем значение тэга для подписи."); this.tagForSign = this.FindSmevTagForSign(doc); log.LogDebug($"Значение тэга для подписи получено. {tagForSign}."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить тэг с элементом для подписи. {ex.Message}."); } SmevSignedXml signedXml = new SmevSignedXml(doc); try { log.LogDebug($"Выполняем добавление элемента Reference в XML."); signedXml = (SmevSignedXml)SmevXmlHelper.AddReference(doc, signedXml, certificate, SignWithId, mrVersion, ElemForSign, ref idCounter, tagForSign, tagForSignNamespaceUri, namespaceIdAttr: NamespaceUri.OasisWSSecurityUtility ); log.LogDebug($"Добавление элемента Reference в XML выполнено успешно."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке добавить элемент Reference. {ex.Message}."); } signedXml.NamespaceForReference = NamespaceUri.OasisWSSecurityUtility; signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; try { log.LogDebug($"Пытаемся получить значение SignatureMethod."); signedXml.SignedInfo.SignatureMethod = SignServiceUtils.GetSignatureMethod(SignServiceUtils.GetAlgId(certificate)); log.LogDebug($"Значение SignatureMethod успешно получено: {signedXml.SignedInfo.SignatureMethod}."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить значение метода подписи. {ex.Message}."); } XmlElement keyInfoElem = doc.CreateElement("KeyInfo", NamespaceUri.WSXmlDSig); XmlElement binaryTokenElem = doc.CreateElement("wsse", "BinarySecurityToken", NamespaceUri.OasisWSSecuritySecext); XmlElement tokenReferenceElem = doc.CreateElement("wsse", "SecurityTokenReference", NamespaceUri.OasisWSSecuritySecext); XmlElement referenceElem = doc.CreateElement("wsse", "Reference", NamespaceUri.OasisWSSecuritySecext); string certId = "uuid-" + Guid.NewGuid().ToString(); XmlAttribute idAttr = doc.CreateAttribute("u", "Id", NamespaceUri.OasisWSSecurityUtility); XmlAttribute valueTypeTokenAttr = doc.CreateAttribute("ValueType"); XmlAttribute encodingTypeTokenAttr = doc.CreateAttribute("EncodingType"); idAttr.Value = certId; valueTypeTokenAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"; encodingTypeTokenAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"; binaryTokenElem.Attributes.Append((XmlAttribute)doc.ImportNode(idAttr, true)); binaryTokenElem.Attributes.Append((XmlAttribute)doc.ImportNode(valueTypeTokenAttr, true)); binaryTokenElem.Attributes.Append((XmlAttribute)doc.ImportNode(encodingTypeTokenAttr, true)); X509Certificate2 cert = SignServiceUtils.GetX509Certificate2(certificate); binaryTokenElem.InnerText = Convert.ToBase64String(cert.RawData); XmlAttribute valueTypeAttr = doc.CreateAttribute("ValueType"); valueTypeAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"; referenceElem.Attributes.Append((XmlAttribute)doc.ImportNode(valueTypeAttr, true)); XmlAttribute uriAttr = doc.CreateAttribute("URI"); uriAttr.Value = "#" + certId; referenceElem.Attributes.Append((XmlAttribute)doc.ImportNode(uriAttr, true)); tokenReferenceElem.PrependChild(doc.ImportNode(referenceElem, true)); keyInfoElem.PrependChild(doc.ImportNode(tokenReferenceElem, true)); try { KeyInfoNode keyNode = new KeyInfoNode(tokenReferenceElem); KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(keyNode); signedXml.KeyInfo = keyInfo; } catch (Exception ex) { throw new Exception($"Ошибка при формировании элемента KeyInfo. {ex.Message}."); } try { log.LogDebug($"Пытаемся вычислить подпись."); signedXml.ComputeSignatureWithoutPrivateKey(xmldsigPrefix, certificate); log.LogDebug($"Вычисление подписи выполнено успешно."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке вычислить подпись для XML. {ex.Message}."); } XmlElement signatureElem = null; try { log.LogDebug("Пытаемся получить элемент с подписью."); signatureElem = signedXml.GetXml(xmldsigPrefix); log.LogDebug("Элемент с подписью успешно получен."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить элемент содержащий подпись. {ex.Message}."); } try { log.LogDebug("Пытаемся добавить подпись в XML содержимое."); FillSignatureElement(doc, signatureElem, certificate, binaryTokenElem); log.LogDebug("Подпись успешно добавлена."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке заполнить XML информацией о подписи. {ex.Message}."); } try { log.LogDebug("Пытаемся добавить атрибут 'Actor'."); SoapDSigUtil.AddActor(doc); log.LogDebug("Атрибут 'Actor' успешно добавлен."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке добавить атрибут 'Actor'. {ex.Message}."); } return(doc); } catch (Exception ex) { log.LogError($"Ошибка при попытке подписать XML. {ex.Message}."); throw new CryptographicException($"Ошибка при попытке подписать XML для версии {mrText[mrVersion]}. {ex.Message}."); } finally { SignServiceUtils.FreeHandleCertificate(certificate); } }