WS-Security,sslv3警报握手失败

时间:2018-01-26 14:53:54

标签: php xml web-services soap ws-security

该服务的文档说我需要使用WS-Security。 从他们的支持,我得到了一个p12文件,我应该使用它。

什么有用
我运行了SoapUI应用程序,配置它,添加了wsdl等,并获得了消息 <faultstring>These policy alternatives can not be satisfied: (...)</faultstring> 所以我发现我需要在请求中添加基本的Auth。我得到了正确的答案。 enter image description here

到目前为止我做了什么
找到一个生成与SoapUI几乎相同的xml的函数,所以我可能会使用它 我用它来称呼$x = callSecRequest('https://int.pz.gov.pl/pz-services/tpSigning?wsdl', 'addDocumentToSigning', $xmltosign, $pub, $priv, $msgback);

function callSecRequest($serviceUrl,$serviceMethod,$requestContent,$pubKey,$privKey,&$msg,$style='document',$use='literal')
{
    require_once('libs/xmlseclibs-master/xmlseclibs.php');
    require_once('libs/nuSoap/nusoap.php');
    $client=new nusoap_client($serviceUrl);
    $client->soap_defencoding = 'UTF-8';
    $client->decode_utf8 = true;
    $client->http_encoding = 'UTF-8';
    $client->xml_encoding = 'UTF-8';
    $client->setCurlOption(CURLOPT_SSLVERSION, 3);
    $securityStart="<wsse:Security \n"
                    ."xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"\n"
                    ."xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">\n";
    $securityEnd="</wsse:Security>\n";
    $BinarySecurityToken="<wsse:BinarySecurityToken \n"
                        ."wsu:Id=\"binarytoken\" \n"
                        ."ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\" \n"
                        ."EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">\n"
                        .implode("\n",array_slice(explode("\n",$pubKey),1,-1))  //a tu wycinamy napisy BEGIN CERTYFICATE i END CERTYFICATE ponieważ EPUAP oczekuje BinarySecurityToken jako base64 bez tych nagłówków
                        ."</wsse:BinarySecurityToken>\n";   
    $timestamp =    "<wsu:Timestamp>"
                    ."<wsu:Created>".getTimestamp()."</wsu:Created>"
                    ."<wsu:Expires>".getTimestamp(60*60)."</wsu:Expires>"  //przesuniecie o godzinę
                    ."</wsu:Timestamp>";    

    $sheaders = $securityStart.$BinarySecurityToken.$timestamp.$securityEnd; //komponujemy dodatek "security" który zostanie umieszczony w nagłówku SOAP:Header

    $soapEnvelope = $client->serializeEnvelope($requestContent, $sheaders, array(), $style, $use);  //tworzymy całą kopertę SOAP z zawartym tam nagłówkiem (jeszcze nie podpisanym i nie są przydzielone również referencje
    //w tym momecie mamy już wstępnie utworzoną kopertę SOAP z zawartością SOAP:BODY jednak nie jest jeszcze w pełni utworzony nagłówek security ani nie jest tam wstawiony podpis które będzie wstawiony tam w elemencie "signature" brakuje również referecji wskazujących które elementy koperty SOAp są podpisane
    //dlatego teraz zajmiemy się dalszym wstawianiem odpowiednich danych do elementu security.
    $doc = new DOMDocument();
    $doc->loadXML($soapEnvelope); //całą kopertę soap wczytujemy do drzewa dom i na tym drzewie będziemy już rzeźbić
    //znajdujemy element body aby dodac do niego referencje poniewaz tylko body bedziemy podpisywali
    $xp = new DOMXPath($doc);
    $wsseNamespace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
    $wsuNamespace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
    //musimy zarejestrować właściwe namespaces z prefixami aby zapytania xpath umiały znaleść właściwe węzły 
    $xp->registerNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/'); //namespace sekcji body
    $xp->registerNamespace('wsse',$wsseNamespace); //namespace node security
    $xp->registerNamespace('wsu',$wsuNamespace);
    $xp->registerNamespace('ds',XMLSecurityDSig::XMLDSIGNS);

    $bodyNode = $xp->query('//soapenv:Body')->item(0);
    if($bodyNode)                                   //znaleźliśmy element soap:body mozemy przypisać mu id i dodać do niego referencje w elemencie "Signature"->"SignedInfo"->"Reference[URI]" 
    {
        //echo "jest BODY";
        $objDSig = new XMLSecurityDSig();           //tworzymy obiekt za pomocą którego będziemy podpisywali kopertę SOAP
        $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
        $objDSig->addReference($bodyNode, XMLSecurityDSig::SHA1,NULL,array('prefix'=>'wsu','prefix_ns'=>$wsuNamespace));  //dodajemy referencje do body możemy tu użyć gotowej funkcji z biblioteki "xmlseclibs"

        //teraz dodamy referencję do elementu Timestamp opisującego moment czasowy podpisu
        $timestampNode = $xp->query('//wsu:Timestamp')->item(0);
        if($timestampNode)
            $objDSig->addReference($timestampNode, XMLSecurityDSig::SHA1,NULL,array('prefix'=>'wsu','prefix_ns'=>$wsuNamespace));
        $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
        $objKey->loadKey($privKey);   //tworzymy obiekt klucza prywatnego, w tym wypadku odczytujemy go z konfiguracji
        $objDSig->sign($objKey);                            //podpisujemy kopertę SOAP kluczem prywatnym
        //$objDSig->add509Cert($pub_key);\              
        //znajdujemy element do którego wstawimy sekcję podpisu w tym wypadku jest to Security
        $securityNode = $xp->query('//wsse:Security')->item(0);                         
        if($securityNode)
        {
            //echo "jest Security node";
            //teraz musimy dodać właśnie wygenerowany podpis (na podstawie referecji do zewnętrzego obiektu) do całośći koperty SOAP
            $timestampNode = $xp->query('//wsu:Timestamp')->item(0);
            if($timestampNode)
                $objDSig->insertSignature($securityNode,$timestampNode);  //wstawiamy podpis do węzła "Security" ale ma być umieszczony przed węzłem "TimeStamp" (to ważne aby był przed nim)
                //$objDSig->appendSignature($securityNode);
                //Teraz ustawimy referencje do BinarySecurityToken niestety ponieważ funkcja addRefInternal jest prywatna nie możemy jej stąd wywołać i musimy dodanie atrybutu reference zrobić na piechotę
            $binarySecurityTokenNode = $xp->query('//wsse:BinarySecurityToken')->item(0);
            if($binarySecurityTokenNode)
            {
                $uri = XMLSecurityDSig::generate_GUID();
                $binarySecurityTokenNode->setAttributeNS($wsuNamespace,'Id', $uri); //dodajemy atrybut Id do BinarySecurityToken aby potem użyć tego samego identyfikatora przy dodawaniu referencji w elemencie securityTokenReference
                $keyInfoNode = $xp->query('//ds:KeyInfo')->item(0);
                if(!$keyInfoNode)
                {
                    $signatureNode = $xp->query('//ds:Signature')->item(0); 
                    $keyInfoNode = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS,'ds:KeyInfo');
                    if($signatureNode)
                        $signatureNode->appendChild($keyInfoNode);
                }
                $securityTokenReferenceNode = $xp->query('//wsse:SecurityTokenReference')->item(0);
                if($keyInfoNode && ! $securityTokenReferenceNode)
                {
                    $securityTokenReferenceNode = $doc->createElementNS($wsseNamespace, 'wsse:SecurityTokenReference');
                    $referenceNode = $doc->createElementNS($wsseNamespace,'wsse:Reference');
                    $referenceNode->setAttribute("URI", '#'.$uri);         //dodajemy teraz do referencji ten sam identyfikator co jest w BinarySecurityToken z elementu Security który właściwie to nie wchodzi do podpisu
                    $securityTokenReferenceNode->appendChild($referenceNode);
                    $keyInfoNode->appendChild($securityTokenReferenceNode);
                }
            }
            $soapEnvelope = $doc->saveXML();

        }//if($securityNode)
        else
        {
            $msg .="Nie odnaleziono elementu wsse:Security";    
        }
    }//if($bodyNode)
    else
    {
        $msg .="Nie odnaleziono elementu soapenv:Body";
    }               
    $result2  = $client->send($soapEnvelope, $serviceMethod);   //wysyłamy kopertę SOAP

    if($client->fault)
    {
        $msg .= "ERROR przy wysyłaniu metody ".$serviceMethod." :".$client->fault." ".var_export($result2,true);        
    }
    else
    {
        if ($client->getError())
        {       
            $msg .= "ERROR przy wysyłaniu metody ".$serviceMethod." :".$client->getError()." ".var_export($result2,true);   
        }
        else 
        {               
            if(isset($result2['faultcode']))
            {
                $msg .=  'faultcode='.$result2['faultcode'].' faultstring='.$result2['faultstring'].' detail='.$result2['detail'];
                return false;
            }
            return $result2;                
        }
    }
    return false;                       
}

问题
我收到错误: SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure。并且不知道可能是什么原因。我从他们那里得到了证书和私钥,所以不应该成为问题。 我尝试过使用SSL v 2,或者根本没有设置它,但这也没有成功。

我实际上尝试过现在在网络上找到的8-10个解决方案,而且我的想法已经不多了。这是我得到的最接近的,它至少会产生它应该的xml(或者至少非常接近它)

0 个答案:

没有答案
相关问题