italia / spid-testenv2

New test Identity Provider for SPID
GNU Affero General Public License v3.0
35 stars 38 forks source link

InvalidInput - Both X509Data and KeyValue found. Use verify(ignore_ambiguous_key_info=True) to ignore KeyValue and validate using X509Data only. #325

Open vincenzocorso opened 3 years ago

vincenzocorso commented 3 years ago

Salve, sto utilizzando l'SDK di Spring per fare dei test.

Quando invio la richiesta ricevo questo errore: signxml.exceptions.InvalidInput: Both X509Data and KeyValue found. Use verify(ignore_ambiguous_key_info=True) to ignore KeyValue and validate using X509Data only.

File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2309, in __call__
  return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2295, in wsgi_app
  response = self.handle_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1741, in handle_exception
  reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
  raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
  response = self.full_dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
  rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
  reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
  raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
  rv = self.dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
  return self.view_functions[rule.endpoint](**req.view_args)
File "/app/testenv/server.py", line 306, in single_sign_on_service
  spid_request = self._parse_message(action='login')
File "/app/testenv/server.py", line 243, in _parse_message
  return self._handle_http_post(action)
File "/app/testenv/server.py", line 282, in _handle_http_post
  HTTPPostSignatureVerifier(cert, request_data).verify()
File "/app/testenv/crypto.py", line 244, in verify
  self._verify_signature()
File "/app/testenv/crypto.py", line 293, in _verify_signature
  self._request.saml_request, x509_cert=self._cert)
File "/usr/local/lib/python3.7/site-packages/signxml/__init__.py", line 874, in verify
 [Open an interactive python shell in this frame] raise InvalidInput("Both X509Data and KeyValue found. Use verify(ignore_ambiguous_key_info=True)"

La richiesta che provo ad inviare è questa:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceIndex="0" AttributeConsumingServiceIndex="1" Destination="http://localhost:8088/sso" ID="_53d4af8588354677b4f9cf383b4805c4" IssueInstant="2021-02-27T07:21:31.467Z" Version="2.0">
   <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" NameQualifier="http://localhost:8080">http://localhost:8080</saml2:Issuer>
   <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <ds:SignedInfo>
         <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
         <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
         <ds:Reference URI="#_53d4af8588354677b4f9cf383b4805c4">
            <ds:Transforms>
               <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
               <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <ds:DigestValue>NWRKCz+7t/CPGP6atdJwzvcQQ6E=</ds:DigestValue>
         </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>mMhJWKwMs7D/ArWbZLxoBz0Mtfzv/WR3ITtmNHreiI2x+LqWQQTnWedXj82WP7a3HkUH+vDja+XNbkFrySgTv10NCYSGXenttRlwLJGXIz57R8LSVU3/t/quXkLiiY91RIT4hEPY80FPDZqjIl8T0BqUlWJjFsm806uNtJrJRl5CUeQUjoS1oaGzQy0WTCS20WOtW99NOSYLkcc7GJa3LMgAldrR7r44C1HNKrNnXyXtYK79BQNd02n9+5e80Bmsw049YbTinOHj9THwingK5sjqFQpjUJK9pdUnvwf4RXer3ArcQiPJqkhL13V2Jsc63RxTHehXEE4Vg35hssmb1g==</ds:SignatureValue>
      <ds:KeyInfo>
         <ds:KeyValue>
            <ds:RSAKeyValue>
               <ds:Modulus>vx4qAxptDe6NkHqXGUTRurYXLuXy5kja0x0So1JVQOOluKwtDHVrlcophtkCNr5TI1Vc6znGuwro
j6OKepo6PLsjPVWYZq+mLZKUyJ6/yFOPDDQwfsvNMxjZ28j6hFE+fPozQ2WPltQsRBOXipn/InhV
M1HM+tIwJ6+PK4eRJkaXo6aPD45ffYwlA21jZYp5hcjCGvwG8FNIZrUbLqjwppcY7vcN2LpiAm4t
ypachQzJOqKJx1F1UZE4wEE1H8yHZgtdo3wL0NGGZ5zRiV5ECjHvpz+EYckBL9DDpzFy95g7tn0S
zTcB/ktIQL4iKfnzezHl5jMBf8tJPn6ImOE69w==</ds:Modulus>
               <ds:Exponent>AQAB</ds:Exponent>
            </ds:RSAKeyValue>
         </ds:KeyValue>
         <ds:X509Data>
            <ds:X509Certificate>MIIEMDCCAxigAwIBAgIJAK8BDpV2YZ66MA0GCSqGSIb3DQEBCwUAMIGsMQswCQYDVQQGEwJJVDER
MA8GA1UECAwIVmVyY2VsbGkxETAPBgNVBAcMCFZlcmNlbGxpMRswGQYDVQQKDBJDb211bmUgZGkg
VmVyY2VsbGkxDTALBgNVBAsMBFNwaWQxHzAdBgNVBAMMFmNvbXVuZS52ZXJjZWxsaS5nb3YuaXQx
KjAoBgkqhkiG9w0BCQEWG3NwaWRAY29tdW5lLnZlcmNlbGxpLmdvdi5pdDAeFw0yMTAyMjYxNTU0
NDRaFw0yNDAyMjYxNTU0NDRaMIGsMQswCQYDVQQGEwJJVDERMA8GA1UECAwIVmVyY2VsbGkxETAP
BgNVBAcMCFZlcmNlbGxpMRswGQYDVQQKDBJDb211bmUgZGkgVmVyY2VsbGkxDTALBgNVBAsMBFNw
aWQxHzAdBgNVBAMMFmNvbXVuZS52ZXJjZWxsaS5nb3YuaXQxKjAoBgkqhkiG9w0BCQEWG3NwaWRA
Y29tdW5lLnZlcmNlbGxpLmdvdi5pdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL8e
KgMabQ3ujZB6lxlE0bq2Fy7l8uZI2tMdEqNSVUDjpbisLQx1a5XKKYbZAja+UyNVXOs5xrsK6I+j
inqaOjy7Iz1VmGavpi2SlMiev8hTjww0MH7LzTMY2dvI+oRRPnz6M0Nlj5bULEQTl4qZ/yJ4VTNR
zPrSMCevjyuHkSZGl6Omjw+OX32MJQNtY2WKeYXIwhr8BvBTSGa1Gy6o8KaXGO73Ddi6YgJuLcqW
nIUMyTqiicdRdVGROMBBNR/Mh2YLXaN8C9DRhmec0YleRAox76c/hGHJAS/Qw6cxcveYO7Z9Es03
Af5LSEC+Iin583sx5eYzAX/LST5+iJjhOvcCAwEAAaNTMFEwHQYDVR0OBBYEFDIUYHNbbiU61Tuw
v6GEJ+OM+eO1MB8GA1UdIwQYMBaAFDIUYHNbbiU61Tuwv6GEJ+OM+eO1MA8GA1UdEwEB/wQFMAMB
Af8wDQYJKoZIhvcNAQELBQADggEBAI/pCiIce1EJkSu8Nt/t8C2veVE9PlKKcVTIkk7FsEBPgOeN
y0iMvJzWeunj1/oJWl2EGVPQP1WCkv2wPipFyo4q3sudzK3yeIPRBrdllCqmtIEsQ/tb+fgNbVyP
EHQ0495eQlwOk4M6YIsmFRt4czKMF2RvgorXbWRCh1enLTkLsR8M3kA82olM0IOUH1KWTLr1df27
3GgJk6sCl5TF/xEhk9fGvvabM476t8ZnCktimvjTk9+ZvH0AIGHRrlcMpPrFSIOmCLnWV0hhMZCF
K0xRJhsKMZqmQmamL1MxLOC8Wuckqw29JQxNV2LqOXZzJ8DWQpG1+y07Y/Gnq4r7FoM=</ds:X509Certificate>
         </ds:X509Data>
      </ds:KeyInfo>
   </ds:Signature>
   <saml2p:NameIDPolicy xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" />
   <saml2p:RequestedAuthnContext xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Comparison="exact">
      <saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://www.spid.gov.it/SpidL2</saml:AuthnContextClassRef>
   </saml2p:RequestedAuthnContext>
</samlp:AuthnRequest>
peppelinux commented 3 years ago

Ciao Vincenzo, Pare il log sia abbastanza eloquente, guarda nella composizione del tuo metadata

vincenzocorso commented 3 years ago

Si ho appena risolto. Il problema era dato dall'sdk di spring che aggiungeva entrambi gli elementi (<KeyValue> e <X509Data>). Basta rimuovere il campo <KeyValue> dalla richiesta.

Per chi stesse utilizzando lo stesso sdk, si deve commentare una linea.

public Signature getSignature() {

        XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();

        Signature signature = (Signature) builderFactory.getBuilder(Signature.DEFAULT_ELEMENT_NAME).buildObject(Signature.DEFAULT_ELEMENT_NAME);
        signature.setSigningCredential(getCredential());
        signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
        signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
        KeyInfo keyInfo = (KeyInfo) builderFactory.getBuilder(KeyInfo.DEFAULT_ELEMENT_NAME).buildObject(KeyInfo.DEFAULT_ELEMENT_NAME);

        KeyStore ks = getKeyStore();
        try {
            X509Certificate certificate = (X509Certificate) ks.getCertificate(certificateAliasName);
            //KeyInfoHelper.addPublicKey(keyInfo, certificate.getPublicKey()); // campo KeyData
            KeyInfoHelper.addCertificate(keyInfo, certificate); // campo X509Data
        }
        catch (CertificateEncodingException e) {
            log.error("buildAuthenticationRequest :: " + e.getMessage(), e);
        }
        catch (KeyStoreException e) {
            log.error("buildAuthenticationRequest :: " + e.getMessage(), e);
        }
        catch (IllegalArgumentException e) {
            log.error("buildAuthenticationRequest :: " + e.getMessage(), e);
        }

        signature.setKeyInfo(keyInfo);

        return signature;
    }
peppelinux commented 3 years ago

Grande,

Ti prego apri una issue sul progetto spring dedicato a spid e referenzia questa issue, se puoi fai una pull request sul progetto per la risoluzione di questa anomalia

lscorcia commented 3 years ago

Buongiorno, mi hanno segnalato questo problema nell'ambito del componente di integrazione SPID con Keycloak (https://github.com/lscorcia/keycloak-spid-provider). L'errore si verifica da quando è stata aggiornata la libreria signxml, e lo stesso autore dichiara di voler lasciare al chiamante la scelta su come operare nel caso in cui la chiave pubblica sia presente due volte, nel certificato e nel tag KeyValue (https://github.com/XML-Security/signxml/issues/143).

Specifica XML Signature alla mano non è vietato avere due rappresentazioni dello stesso certificato (https://tools.ietf.org/html/rfc3075#page-28), anzi, l'indicazione è recommended. Questo errore è una forzatura dell'autore della libreria tutta frutto della sua inventiva.

Considerato anche che questo problema esiste solo per le implementazioni Python, e infatti non si verifica con spid-saml-validator, credo che sarebbe opportuno utilizzare il flag ignore_ambiguous_key_info come suggerito dal messaggio di errore. Sul lungo termine la soluzione è quella già delineata nella issue sul progetto signxml, ovvero restituire errore solo se le due chiavi pubbliche non coincidono.

Che ne pensate?

lscorcia commented 3 years ago

Ho aperto la PR https://github.com/XML-Security/signxml/pull/169 sul repo della libreria. Se l'autore me la accetta potremo semplicemente aggiornare la libreria al prossimo rilascio, sennò preparerò una PR per aggiungere qui il parametro ignore_ambiguous_key_info alla chiamata.