klient e-recepty

0

Czy komuś udało się podpiąć do e-recepty? Ciągle dostaję błąd:

Could not establish secure channel for SSL/TLS with authority 'isus.ezdrowie.gov.pl'.

Mój kod:

        var certificate = getCert(); 
        var certificate2 = getCert(); 

        var binding = new CustomBinding();

        var security = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);

        security.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters
        {
            InclusionMode = SecurityTokenInclusionMode.Never,
            ReferenceStyle = SecurityTokenReferenceStyle.Internal,
        });

        security.RecipientTokenParameters.InclusionMode = SecurityTokenInclusionMode.Never;
        security.RecipientTokenParameters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;

        security.MessageSecurityVersion =
            MessageSecurityVersion.
                WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
        security.IncludeTimestamp = false;
        security.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;

        security.RequireSignatureConfirmation = true;
        
        security.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
        security.AllowSerializedSigningTokenOnReply = true;
        

        binding.Elements.Add(security);
        binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
        binding.Elements.Add(new HttpsTransportBindingElement());

        var client = new ObslugaReceptyWSClient(binding, new EndpointAddress(new Uri("https://isus.ezdrowie.gov.pl/services/ObslugaReceptyWS"), new DnsEndpointIdentity("xxxxxx"), new AddressHeaderCollection()));

        client.ClientCredentials.ServiceCertificate.DefaultCertificate = certificate;
        client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
            System.ServiceModel.Security.X509CertificateValidationMode.None;
        client.ClientCredentials.ClientCertificate.Certificate = certificate;

        client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.Sign;
        try
        {
            client.Open();

            KontekstMT kontekst = new KontekstMT();
            AtrybutMT atr = new AtrybutMT();
            kontekst.atrybut = new AtrybutMT[1];
            kontekst.atrybut[0] = atr;
            OdczytReceptyRequest rq = new OdczytReceptyRequest();
            KluczReceptyMT klucz = new KluczReceptyMT();
            klucz.kluczRecepty = "abababa";
            rq.kluczRecepty = klucz;

            ClassLibrary1.ServiceReference1.OdczytReceptyResponse resp = client.odczytRecepty(kontekst, rq);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

W dokumentacji integracji jest informacja taka:

W komunikacji z systemem P1 wymagane jest użycie rozszerzenia Web Services Security i profilu Web Services Security X.509 Certificate Token Profile. Podpisem powinno być objęte całe ciało komunikatu (element soap:Body). W nagłówku SOAP wymagany jest element WS-Security Signature. Informacja o certyfikacie, który służy do weryfikacji podpisu powinna być umieszczona jako BinarySecurityToken z następującymi parametrami:
• EncodingType=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary”
• ValueType=”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3”

0

Cześć!
Udało Ci się może rozwiązać problem połączenia z E-receptą? Walczę od kilku dni z tym samym problemem. Gdy używam BasicHttpsBinding lub WSHttpBinding udaje mi się dojść do momentu uzyskania połączenia z serwerem i nawiązania komunikacji, ale dalej dostaję odpowiedź o braku nagłówka wsse i nie umiem go wygenerować.

Dzięki za wszelkie wsparcie,
Pozdrawiam!

0

Niestety nie udało się. Jeśli możesz to podeślij swój kod, może uda się coś z tym zrobić.

0

Z tego co rozumiem po przeczytaniu dokumentacji to zabezpieczenia mają być trzy.

  • Zabezpieczenie transportu (certyfikat TLS ten sam który jest potrzebny do strony dla integratorów)
  • Podpis wiadomości SOAP czyli ten nieszczęsny nagłówek WSSE koperty SOAP z użyciem BinarySecurityToken - do tego potrzebny jest certyfikat WSS
  • Podpis każdej recepty z osobna certyfikatem wystawiającego - do tego jest ten trzeci certyfikat wystawiony na osobę a w przypadku produkcyjnym może być to certyfikat ZUS.

Trzecia sprawa jest generalnie prosta, klasa X509Certificate2 to załatwia automatycznie.

Pierwsza sprawa łączy się z drugą najwyraźniej bo trzeba to załatwić na poziomie Binding. Dane w poniższym kodzie są oczywiście niekompletne i zamarkowane.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp2.ObslugaRecepty;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            EndpointAddress endpoint = new EndpointAddress(new Uri("https://isus.ezdrowie.gov.pl/services/ObslugaReceptyWS"));
            BasicHttpsBinding binding = new BasicHttpsBinding()
            {
                Name = "P1_SSL_Certificate",
            };
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
            ObslugaReceptyWSClient obsluga = new ObslugaReceptyWSClient(binding, endpoint);
            obsluga.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(@"/*ŚCIEŻKA DO CERTYFIKATU TLS.P12*/", "/*HASŁO CERTYFIKATU*/");
            KontekstMT kontekst = new KontekstMT();
            kontekst.Id = "1234567890";
            List<AtrybutMT> listOfAttrybut = new List<AtrybutMT>();
            listOfAttrybut.Add(
                new AtrybutMT()
                {
                    nazwa = "urn:csioz:p1:erecepta:kontekst:idPodmiotuOidRoot",
                    wartosc = new string[1] { "2.16.840.1.113883.3.4424.2.4.68" }
                }
            );
            kontekst.atrybut = listOfAttrybut.ToArray();
            ReceptaMT recepta = new ReceptaMT();
            recepta.tresc = Encoding.ASCII.GetBytes("TUTAJ BEDZIE TRESC RECEPTY");
            ReceptyMT recepty = new ReceptyMT();
            recepty.recepta = new ReceptaMT[1] { recepta };
            PakietReceptMT pakiet = new PakietReceptMT();
            pakiet.Item = recepty;
            WeryfikacjaPakietuReceptRequest weryfikacja = new WeryfikacjaPakietuReceptRequest();
            weryfikacja.pakietRecept = pakiet;
            System.Threading.Tasks.Task<ObslugaRecepty.weryfikacjaPakietuReceptRequestResponse> response = obsluga.weryfikacjaPakietuReceptAsync(kontekst, weryfikacja);
            while (!response.IsCompleted) { Console.WriteLine("."); System.Threading.Thread.Sleep(1000); };
            Console.WriteLine(response.Exception.InnerExceptions.First().Message);
            Console.WriteLine("Any key to exit...");
            Console.ReadKey();
        }
    }
}

Ten kod łączy się z isus-em i wymienia komunikat SOAP. Następnie zwraca błąd - brak nagłówka WSSE - jest to komunikat już od ISUSa. Jest to jakby oczywiste bo nie wiem jak ten podpis dodać, ale samo połączenie TLS działa. Na wiresharku widać wymianę pakietów. Przejście w Bindingu z zabezpieczenia Transport na TransportWithMessageCredentials powoduje, że nie można już nawiązać nawet połączenia TLS. Instrukcja Microsoftu na temat WCF wspomina, że w przypadku TransportWithMessageCredentials właściwość Security.Transport.ClientCredentialType jest ignorowana. Najwyraźniej więc droga nie prowadzi przez BasicHttpsBinding tylko trzeba walczyć z CustomBinding...

0

Po dodaniu custombinding jest ten sam błąd, który miałem wcześniej, być może coś źle ustawiam, poniżej co zakomentowałem w Twoim kodzie i co dodałem:

//EndpointAddress endpoint = new EndpointAddress(new Uri("https://isus.ezdrowie.gov.pl/services/ObslugaReceptyWS"));

            var wssCert = new X509Certificate2(@"WSS.p12", "haslo");
          
            EndpointAddress endpoint = new EndpointAddress(new Uri("https://isus.ezdrowie.gov.pl/services/ObslugaReceptyWS"), EndpointIdentity.CreateDnsIdentity(wssCert.GetNameInfo(X509NameType.SimpleName, false)));

            /*BasicHttpsBinding binding = new BasicHttpsBinding()
            {
                Name = "P1_SSL_Certificate",
            };
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;*/

            CustomBinding binding = new CustomBinding()
            {
                Name = "P1_SSL_Certificate",
            };

            var security = TransportSecurityBindingElement.CreateMutualCertificateBindingElement();// CreateUserNameOverTransportBindingElement();
            security.IncludeTimestamp = true;
            security.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
            security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
            security.EnableUnsecuredResponse = true;
            security.KeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;


            TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement();
            encoding.MessageVersion = MessageVersion.Soap11WSAddressing10;



            var transport = new HttpsTransportBindingElement();
            transport.MaxReceivedMessageSize = 2000000;

            binding.Elements.Add(security);
            binding.Elements.Add(encoding);
            binding.Elements.Add(transport);

Generalenie jest to to, co podaje Microsoft na stronach MSDN. Nie mam pojęcia co może być w tym źle.

0

Cześć!
Czy udało się Wam rozwiązać ten problem?
Też z tym walczę.

0

Niestety nie.

0

Po dodaniu do Twojego kodu linijki
transport.RequireClientCertificate = true;
błąd dotyczący TLS'a udało się naprawić, ale pojawił się kolejny

"Odebrano niezabezpieczony lub nieprawidłowo zabezpieczony błąd od drugiej strony. Kod i szczegóły błędu można uzyskać w wewnętrznym wyjątku FaultException."
Info z FaultException:
"General security error (No certificates were found for decryption (KeyId))"

0

Nie próbowałeś pobrać przykładowego połączenia ze strony https://www.csioz.gov.pl/komunikaty/zsmopl-komunikaty/szczegoly/news/fragment-kodow-zrodlowych-generatora-komunikatow-z-wersji-v-11/ ?
W jednym z plików jest taki kod :

// przykład połączenia
var securityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
securityBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
securityBindingElement.IncludeTimestamp = false;
securityBindingElement.EnableUnsecuredResponse = true;

var textMessageEncoding = new CustomMessageEncoderBindingElement(new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.Soap11 });

var httpsTransport = new HttpsTransportBindingElement();
httpsTransport.RequireClientCertificate = false;

var binding = new CustomBinding();
binding.Elements.Add(securityBindingElement);
binding.Elements.Add(textMessageEncoding);
binding.Elements.Add(httpsTransport);

var messageSigningCertificate = new X509Certificate2(certificatePath, certificatePassword);
string cn = messageSigningCertificate.GetNameInfo(X509NameType.SimpleName, false);
var address = new EndpointAddress(new Uri("https://ewa-zsmopl.ezdrowie.gov.pl/cxf/zsmopl/ws/"), EndpointIdentity.CreateDnsIdentity(cn));
var client = new ObslugaKomunikatowClient(binding, address);
client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
client.ChannelFactory.Credentials.ClientCertificate.Certificate = messageSigningCertificate;
client.ChannelFactory.Credentials.ServiceCertificate.DefaultCertificate = messageSigningCertificate;
var response = client.zapiszKomunikatOS(new KomunikatOSMT
{
	// dane komunikatu
});

0
BS napisał(a):

Po dodaniu do Twojego kodu linijki
transport.RequireClientCertificate = true;
błąd dotyczący TLS'a udało się naprawić, ale pojawił się kolejny

"Odebrano niezabezpieczony lub nieprawidłowo zabezpieczony błąd od drugiej strony. Kod i szczegóły błędu można uzyskać w wewnętrznym wyjątku FaultException."
Info z FaultException:
"General security error (No certificates were found for decryption (KeyId))"

To już może oznaczać, że wysyłany xml nie jest podpisany, jeśli dobrze rozumie to wysyłany xml również powinen być podpisany, nie tylko cała koperta SOAP.

0
amator963 napisał(a):

Nie próbowałeś pobrać przykładowego połączenia ze strony https://www.csioz.gov.pl/komunikaty/zsmopl-komunikaty/szczegoly/news/fragment-kodow-zrodlowych-generatora-komunikatow-z-wersji-v-11/ ?
W jednym z plików jest taki kod :

// przykład połączenia
var securityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
securityBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
securityBindingElement.IncludeTimestamp = false;
securityBindingElement.EnableUnsecuredResponse = true;

var textMessageEncoding = new CustomMessageEncoderBindingElement(new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.Soap11 });

var httpsTransport = new HttpsTransportBindingElement();
httpsTransport.RequireClientCertificate = false;

var binding = new CustomBinding();
binding.Elements.Add(securityBindingElement);
binding.Elements.Add(textMessageEncoding);
binding.Elements.Add(httpsTransport);

var messageSigningCertificate = new X509Certificate2(certificatePath, certificatePassword);
string cn = messageSigningCertificate.GetNameInfo(X509NameType.SimpleName, false);
var address = new EndpointAddress(new Uri("https://ewa-zsmopl.ezdrowie.gov.pl/cxf/zsmopl/ws/"), EndpointIdentity.CreateDnsIdentity(cn));
var client = new ObslugaKomunikatowClient(binding, address);
client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
client.ChannelFactory.Credentials.ClientCertificate.Certificate = messageSigningCertificate;
client.ChannelFactory.Credentials.ServiceCertificate.DefaultCertificate = messageSigningCertificate;
var response = client.zapiszKomunikatOS(new KomunikatOSMT
{
	// dane komunikatu
});

Próbowałem, niestety przełożenie 1 do 1 nie działa, lub popełniam jakiś błąd.

0
przewa napisał(a):
amator963 napisał(a):

Nie próbowałeś pobrać przykładowego połączenia ze strony https://www.csioz.gov.pl/komunikaty/zsmopl-komunikaty/szczegoly/news/fragment-kodow-zrodlowych-generatora-komunikatow-z-wersji-v-11/ ?
W jednym z plików jest taki kod :

// przykład połączenia
var securityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
securityBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
securityBindingElement.IncludeTimestamp = false;
securityBindingElement.EnableUnsecuredResponse = true;

var textMessageEncoding = new CustomMessageEncoderBindingElement(new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.Soap11 });

var httpsTransport = new HttpsTransportBindingElement();
httpsTransport.RequireClientCertificate = false;

var binding = new CustomBinding();
binding.Elements.Add(securityBindingElement);
binding.Elements.Add(textMessageEncoding);
binding.Elements.Add(httpsTransport);

var messageSigningCertificate = new X509Certificate2(certificatePath, certificatePassword);
string cn = messageSigningCertificate.GetNameInfo(X509NameType.SimpleName, false);
var address = new EndpointAddress(new Uri("https://ewa-zsmopl.ezdrowie.gov.pl/cxf/zsmopl/ws/"), EndpointIdentity.CreateDnsIdentity(cn));
var client = new ObslugaKomunikatowClient(binding, address);
client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
client.ChannelFactory.Credentials.ClientCertificate.Certificate = messageSigningCertificate;
client.ChannelFactory.Credentials.ServiceCertificate.DefaultCertificate = messageSigningCertificate;
var response = client.zapiszKomunikatOS(new KomunikatOSMT
{
	// dane komunikatu
});

Próbowałem, niestety przełożenie 1 do 1 nie działa, lub popełniam jakiś błąd.

Ja mam w tym przypadku komunikat "The certificate used for the signature is not trusted"

0

Cześć

Udało się komuś pomyślnie wysłać komunikat za pomocą C#? Obecnie stoję na tym samym błędzie..

0

Niestety mi się nie udało.

0

Czy możecie podzielić sie kodem zródłowym:
klasy ObslugaKomunikatowClient(binding, address);

var client = new ObslugaKomunikatowClient(binding, address);
client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
client.ChannelFactory.Credentials.ClientCertificate.Certificate = messageSigningCertificate;
client.ChannelFactory.Credentials.ServiceCertificate.DefaultCertificate = messageSigningCertificate;
var response = client.zapiszKomunikatOS(new KomunikatOSMT
{
// dane komunikatu
});

komunikat bledu: Missing wsse:Security header in request

1 użytkowników online, w tym zalogowanych: 0, gości: 1