EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Connection failed: Error 100354

Also by EldoS: BizCrypto
Components for BizTalk® and SQL Server® Integration Services that let you securely store and transfer information in your business automation solutions.
#20437
Posted: 06/13/2012 14:50:54
by Eduardo Helminsky (Standard support level)
Joined: 08/20/2010
Posts: 102

Hi

I am consuming a WebService with the code below. The connection is OK because if I access the WebService thru IE it opens OK. The certificate is OK. How can I solve this ?

I am using the function EnviaSoap with the following parameters:
WebService:
https://homologacao.nfe.fazenda.sp.gov.br/cteWEB/services/cteStatusServico.asmx

SoapAction:
cteStatusServicoCT

XML:
<?xml version="1.0" encoding="utf-8"?>

<soap12:Header>
<cteCabecMsg xmlns="http://www.portalfiscal.inf.br/cte/wsdl/CteStatusServico">
<cUF>SP</cUF>
<versaoDados>1.04</versaoDados>
</cteCabecMsg>


<cteDadosMsg xmlns="http://www.portalfiscal.inf.br/cte/wsdl/CteStatusServico">
<consStatServCte xmlns="http://www.portalfiscal.inf.br/cte/wsdl/CteStatusServico" versao="1.04">
<tpAmb>2</tpAmb>
<cUF>SP</cUF>
<xServ>STATUS</xServ>
</consStatServCte>
</cteDadosMsg>

</soap12:Envelope>

And the code I am using to do it is the following:
Code
unit https;

// {$D-}

{
Comunicação HTTPS + Assinatura XML
Última atualização: 13/06/2012
}

interface

uses Windows, Messages, SysUtils, Classes, Graphics, SBHttpsConstants,
     SBXMLCore, SBXMLSec, SBXMLSig, SBX509, SBXMLEnc,  SBXMLUtils,
     SBXMLTransform, SBXMLDefs, SBCustomCertStorage, SBUtils,  SBWinCertStorage,
     SBLicenseManager, SBSimpleSSL, SBHTTPSClient, SBConstants;

type
   TMyHttps = class(TObject)
   public
      procedure ClientCertificateValidate(Sender: TObject; X509Certificate: TElX509Certificate; var Validate: Boolean);
      procedure ClientData(Sender: TObject; Buffer: Pointer; Size: Integer);
   end;

   function EnviarSoap(cWebService: String; cXml: String; cSoapAction: String = ''): Boolean;
   procedure PrepararCertificado(cCertSerial: String);

var WSRetorno: String;
    ProxyHost: String;
    ProxyUser: String;
    ProxyPort: String;
    ProxyPassword: String;
    FWinCert: TElWinCertStorage;
    FHttpsClient: TElHTTPSClient;
    FMemCert: TElMemoryCertStorage;
    FCert: TElX509Certificate;
    FCACert: TElX509Certificate;
    FHttpResult: Integer;
    FMyHttps: TMyHttps;

implementation

procedure PrepararCertificado(cCertSerial: String);
var nI: Integer;
    nK: Integer;
    cAux: String;
    IsOk: Boolean;
begin
     // Inicializa os certificados digitais
     FMemCert.Clear;

     FWinCert.SystemStores.Clear;
     FWinCert.SystemStores.Add('MY');
     FWinCert.SystemStores.Add('CA');
     FWinCert.SystemStores.Add('ROOT');

     for nI := 0 to FWinCert.Count-1 do begin
        FCert := FWinCert.Certificates[nI];

        cAux := BinaryToString(FCert.SerialNumber);
        IsOk := UpperCase(cAux) = UpperCase(cCertSerial);

        if IsOk then begin
           FMemCert.Add(FCert,True);
           nK := FWinCert.GetIssuerCertificate(FCert);
           while nK <> -1 do begin
              FCACert := FWinCert.Certificates[nK];
              FMemCert.Add(FCACert);
              nK := FWinCert.GetIssuerCertificate(FCACert);
           end;
           break;
        end;
     end;

     if FMemCert.Count = 0 then begin
        raise Exception.Create('O certificado com número de série "' + cCertSerial + '" NÃO foi encontrado');
     end;
end;

function EnviarSoap(cWebService: String; cXml: String; cSoapAction: String = ''): Boolean;
begin
     if FMemCert.Count > 0 then begin
        FHttpsClient.ClientCertStorage := FMemCert;
     end else begin
        FHttpsClient.ClientCertStorage := nil;
     end;
     FHttpsClient.UseHTTPProxy := False;
     if ProxyHost <> '' then begin
        FHttpsClient.UseHTTPProxy := True;
        FHttpsClient.HTTPProxyHost := ProxyHost;
        FHttpsClient.HTTPProxyPort := StrToIntDef(ProxyPort,0);
        FHttpsClient.HTTPProxyUsername := ProxyUser;
        FHttpsClient.HTTPProxyPassword := ProxyPassword;
     end;
     with FHttpsClient.RequestParameters do begin
        UserAgent := 'HPRO Soap 1.2';
        ContentType := 'application/soap+xml; charset=utf-8';
        if cSoapAction <> '' then begin
           CustomHeaders.Clear;
           CustomHeaders.Add('SOAPAction: ' + cSoapAction);
        end;
     end;
     WSRetorno := '';

     try
        FHttpResult := FHttpsClient.Post(cWebService,cXml);
     except
        on E: Exception do begin
           raise Exception.Create('@Ocorreu um erro durante a comunicação com o Webservice;;' + E.Message);
        end;
     end;
     Result := FHttpResult = 200;
end;

procedure TMyHttps.ClientCertificateValidate(Sender: TObject; X509Certificate: TElX509Certificate; var Validate: Boolean);
begin
     Validate := True;
end;

procedure TMyHttps.ClientData(Sender: TObject; Buffer: Pointer; Size: Integer);
var cAux: String;
begin
     cAux := Utf8ToString(Buffer);
     if Length(cAux) > Size then begin
        cAux := Copy(cAux,1,Size);
     end;
     WSRetorno := WSRetorno + cAux;
end;

function AssinarXML(cXml: String; cUri: String = ''; bDetached: Boolean = False): String;
var Signer: TElXMLSigner;
    X509KeyData: TElXMLKeyInfoX509Data;
    SigNode: TElXMLDOMNode;
    Ref: TElXMLReference;
    Refs: TElXMLReferenceList;
    FXMLDocument: ElXMLDOMDocument;
    S: TStringStream;
begin
     Refs := TElXMLReferenceList.Create;
     try
        FXMLDocument := TElXMLDOMDocument.Create;
        S := TStringStream.Create('');
        try
           S.WriteString(cXml);
           S.Position := 0;
           FXMLDocument.LoadFromStream(S);
        finally
           S.Free;
        end;

        Ref := TElXMLReference.Create;
        Ref.URINode := FXMLDocument.FirstChild;
        Ref.URI := '#' + cUri;
        Ref.TransformChain.Add(TElXMLEnvelopedSignatureTransform.Create);
        Ref.TransformChain.Add(TElXMLC14NTransform.Create);
        Refs.Add(Ref);

        Signer := TElXMLSigner.Create(nil);
        try
           if bDetached then begin
              Signer.SignatureType := xstDetached;
           end else begin
              Signer.SignatureType := xstEnveloped;
           end;
           Signer.CanonicalizationMethod := xcmCanon;
           Signer.SignatureMethodType := xmtSig;
           Signer.SignatureMethod := xsmRSA_SHA1;
           Signer.References := Refs;
           Signer.IncludeKey := True;

           if Assigned(FCert) and FCert.PrivateKeyExists then begin
              X509KeyData := TElXMLKeyInfoX509Data.Create(False);
              X509KeyData.IncludeDataParams := [xkidX509Certificate];
              X509KeyData.IncludeKeyValue := False;
              X509KeyData.Certificate := FCert;
              Signer.KeyData := X509KeyData;
           end;
           Signer.UpdateReferencesDigest;
           Signer.GenerateSignature;
           Signer.Signature.SignaturePrefix := '#default';

           if Signer.SignatureType = xstDetached then begin
              FreeAndNil(FXMLDocument);
              SigNode := nil;
              Signer.Save(SigNode);
              FXMLDocument := SigNode.OwnerDocument;
           end else begin
              SigNode := FXMLDocument.DocumentElement;
              Signer.Save(SigNode);
           end;

           // Result := UTF8Encode(FXMLDocument.DocumentElement.OuterXML);
           Result := FXMLDocument.DocumentElement.OuterXML;
        finally
           FreeAndNil(FXMLDocument);
           FreeAndNil(Signer);
           FreeAndNil(X509KeyData);
        end;
     finally
        FreeAndNil(Refs);
     end;
end;

initialization

  // Licença SSL
  SetLicenseKey('...');

  // Licença XML
  SetLicenseKey('...');

   FWinCert := TElWinCertStorage.Create(nil);
   FMemCert := TElMemoryCertStorage.Create(nil);
   FMyHttps := TMyHttps.Create;
   FHttpsClient := TElHTTPSClient.Create(nil);
   FHttpsClient.OnCertificateValidate := FMyHttps.ClientCertificateValidate;
   FHttpsClient.OnData := FMyHttps.ClientData;
   FHttpsClient.HttpVersion := hvHTTP11;
finalization
   if FWinCert <> nil then begin
      FWinCert.Free;
      FWinCert := nil;
   end;
   if FHttpsClient <> nil then begin
      FHttpsClient.Free;
      FHttpsClient := nil;
   end;
   if FMemCert <> nil then begin
      FMemCert.Free;
      FMemCert := nil;
   end;
   FMyHttps.Free;
end.
#20438
Posted: 06/13/2012 14:54:26
by Eduardo Helminsky (Standard support level)
Joined: 08/20/2010
Posts: 102

I forgot to mention it. I am using Delphi XE Update 1
#20439
Posted: 06/13/2012 15:41:12
by Ken Ivanov (EldoS Corp.)

Thank you for getting in touch with us.

1) Does the TElHTTPSClient component pass back any information through the OnData event?

2) Please handle the OnReceivingHeaders and OnError events and check if they are fired and what values are they reporting.

3) Please handle the OnSendData event, capture the value the component passes to it and post it to the ticket so that we could inspect it.

Please also take care not to post license information to the public forum. Now that you've posted your license keys here, they became available to all the readers of the forum, and thus we are forced to revoke them and provide you with the new ones.
#20441
Posted: 06/13/2012 16:29:59
by Eduardo Helminsky (Standard support level)
Joined: 08/20/2010
Posts: 102

Sorry about license. It was my fault.

1) No

2) and 3) I will do it and check the results. After that, I will post the new scenario here.

Thank you for prompt answer
#20457
Posted: 06/14/2012 05:37:15
by Eduardo Helminsky (Standard support level)
Joined: 08/20/2010
Posts: 102

I have done what you suggest and here is what happened.

1) The event OnError never occurs.

2) The event OnSendData occurs with (formatted for reading purposes):
POST /cteWEB/services/cteStatusServico.asmx HTTP/1.1
Content-Type: text/xml
Host: nfe.fazenda.sp.gov.br
User-Agent: HPRO Soap 1.2
Accept-Encoding: gzip, deflate
Connection: Close
SOAPAction: cteStatusServicoCT
Content-Length: 639


<soap12:Header>
<cteCabecMsg xmlns="http://www.portalfiscal.inf.br/cte/wsdl/CteStatusServico">
<cUF>35</cUF>
<versaoDados>1.04</versaoDados>
</cteCabecMsg>


<cteDadosMsg xmlns="http://www.portalfiscal.inf.br/cte/wsdl/CteStatusServico">
<consStatServCte xmlns="http://www.portalfiscal.inf.br/cte/wsdl/CteStatusServico" versao="1.04">
<tpAmb>1</tpAmb>
<cUF>35</cUF>
<xServ>STATUS</xServ>
</consStatServCte>
</cteDadosMsg>

</soap12:Envelope>

3) The event OnPreparedHeader occurs with:
POST /cteWEB/services/cteStatusServico.asmx HTTP/1.1
Content-Type: text/xml
Host: nfe.fazenda.sp.gov.br
User-Agent: HPRO Soap 1.2
Accept-Encoding: gzip, deflate
Connection: Close
SOAPAction: cteStatusServicoCT
Content-Length: 639

4) The event OnReceivingHeader never occurs.

Note: You can check yourself because this webservice only reports if it is running. It does nothing. The only thing need is a valid certificate for https.
#20458
Posted: 06/14/2012 05:51:00
by Vsevolod Ievgiienko (EldoS Corp.)

Hello.

I've just successfully made a few GET and POST requests to the WebService without any problems.
#20459
Posted: 06/14/2012 06:09:17
by Eduardo Helminsky (Standard support level)
Joined: 08/20/2010
Posts: 102

I have solved the problem. I replaced the certificate after contact the customer that informs me that it was revoked. I have checked with another certificate and it works very well.

Sorry to bother you.

Regards.
#23663
Posted: 02/22/2013 16:21:21
by Leonardo Herrera (Standard support level)
Joined: 02/14/2011
Posts: 66

Hello,

I know this issue has been reported before, but I haven't been able to solve it. I'm getting error code 100354 when posting to an SSL server. I suspect that the certificate is somehow attached to the computer where I generated it (this is a commercial certificate, generated by VeriSign) because I have exported it to a two different computers and in both I'm getting this error.

I really want to avoid using anything other than WinCertStorage - there are lots of reasons for that.

I'm obtaining both the certificate and the storage by using the following code. (Please ignore the TRUT and GetCertRUT part, these are only utilities that parse part of the OID so they select the appropriate certificate):

Code
function pickCert(rut: TRUT; var Storage: TElWinCertStorage)
  : TElX509Certificate;
var
  Cert: TElX509Certificate;
  i: Integer;
  CompRut: TRUT;
begin
  Result := nil;

  Storage := TElWinCertStorage.Create(nil);
  Storage.AccessType := atCurrentUser;
  Storage.SystemStores.Text := 'MY';
  for i := 0 to Storage.Count - 1 do
  begin
    Cert := Storage.Certificates[i];

    CompRut := GetCertRUT(Cert);
    if (CompRut <> nil) and (CompRut.rut = rut.rut) then
      Result := Cert;
    CompRut.Free;
    if Result <> nil then
      Exit(Result);
  end;
end;


The certificate appears to load correctly. I can use it for signing things, for example. But when I try to post some information to an SSL server I get the dreaded 100354 error. What else should I check on my side?
#23665
Posted: 02/22/2013 16:38:42
by Ken Ivanov (EldoS Corp.)

Leonardo,

Thank you for getting in touch with us.

Several quick questions to shape the problem:

1. Does your code work on the machine you've generated the certificate (or private key) on?

2. When picking the certificate with the above method, what is the value of TElX509Certificate.PrivateKeyExists property?

3. How exactly are you passing the certificate to TElHTTPSClient?

The issue is really likely to be related to some problem with the certificate, and we only need to find out where exactly the problem is. I would guess that the server expects you to provide the entire certificate chain, and you've only copied the end-entity certificate to the machines that are in problem now.
#23667
Posted: 02/22/2013 17:19:57
by Leonardo Herrera (Standard support level)
Joined: 02/14/2011
Posts: 66

Hello,

Just moments after sending this message (and after having worked at the problem all day) I decided to take a look at the HTTPS part. And I found that I assigned the WinCertStorage I'm using to the CertStorage property instead of ClientCertStorage. I changed it and the problem appears to have been solved.

To your other questions: 1) yes, 2) true, and 3) I never passed the certificate to the HTTPSClient explicitly, I think. I have assigned OnClientCertificateNeededEx but it didn't fire. I think this is because the server actually doesn't request a specific certificate; they use some cookie validation that I'm handling elsewhere. So it appears that this was a simple SSL problem and not related to certificate handling (other than setting ClientCertStorage appropriatedly!)

Hope this helps,
Leonardo Herrera
Also by EldoS: MsgConnect
Cross-platform protocol-independent communication framework for building peer-to-peer and client-server applications and middleware components.

Reply

Statistics

Topic viewed 4042 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!