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 подписью органа власти /// </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); } }
/// <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)); }
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> /// Метод подписи 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); } }