Hello,

I came across this problem when migrating a L2L VPN (VTI) from PSK to Digital 
Certificates, between Strongswan 5.9.7 and Cisco Firepower 7.0.4

Problem:
After switching to certificate (auth=pubkey, ...) this error showed up in 
Strongswan:
signature validation failed, looking for another key

During troubleshooting I found this issue:
https://wiki.strongswan.org/issues/3059
===
Don't know what that is, but maybe you configured something incorrectly there 
or the implementation does something wrong when it produces the signature 
value. One possible cause could be if it doesn't use SHA-1 for the signature 
(it's the only hash algorithm strongSwan uses for the legacy IKEv2 RSA 
authentication, i.e. if RFC 7427 is not supported/used by the peer)
===

And also, in Cisco:
https://bst.cisco.com/quickview/bug/CSCuw01249 (Enhancement request to support 
RFC 7427). Still open (not implemented).
https://bst.cisco.com/quickview/bug/CSCvb21927
===
Cisco Adaptive Security Appliance (ASA) Software
Symptom:
3rd party IKEv2 client will fail to validate authentication response from the 
ASA when certificates are being used.
For example, Strongswan will return:
"signature validation failed, looking for another key"
Windows native IKEv2 client will return:
"Error 13826: Failed to verify signature"
*Conditions:**
**- PRF SHA2 (SHA256 or SHA512) is in use under "crypto ikev2 policy"*
*Workaround:**
**- Use PRF SHA1**
*- Apple iOS built-in client works with SHA-256 but fails with SHA512
Further Problem Description:
With PRF SHA2 ASA uses SHA2 to sign authentication payload. The rfc7427 say 
*SHA-1 should be used, but it is not mandatory*.
For the sake of interoperability with 3rd party implementations unable to use 
SHA2 the following command was introduced:
tunnel-group TUN-GROUP ipsec-attributes
 ikev2 rsa-sig-hash sha1
===

_*In my tests I found out that Cisco uses the same algorithm for RSA Digital 
Signature than the one agreed PRF in proposal*_.
So, if Strongswan uses proposals = aes256gcm128-prfsha512-ecp521 and Cisco 
Firepower is using defaults, SHA2-512 is used in PRF and in RSA authentication.
===
charon-systemd[3442731]: received proposals: 
IKE:AES_GCM_16_256/AES_GCM_16_192/AES_GCM_16_128/PRF_HMAC_SHA2_512/PRF_HMAC_SHA2_384/PRF_HMAC_SHA2_256/PRF_HMAC_SHA1/ECP_521/ECP_384/ECP_256/MODP_4096/MODP_3072/MODP_2048
charon-systemd: charon-systemd[3442731]: configured proposals: 
IKE:AES_GCM_16_256/PRF_HMAC_SHA2_512/ECP_521
charon-systemd: charon-systemd[3442731]: selected proposal: 
IKE:AES_GCM_16_256/PRF_HMAC_SHA2_512/ECP_521
...
charon-systemd: charon-systemd[3442731]:   using cached ocsp response
charon-systemd: charon-systemd[3442731]: certificate status is good
charon-systemd: charon-systemd[3442731]:   certificate "C=ES, O=XXX, CN=XXXX" 
key: 2048 bit RSA
charon-systemd: charon-systemd[3442731]:   reached self-signed root ca with a 
path length of 0
charon-systemd: charon-systemd[3442731]: signature validation failed, looking 
for another key
===
This is because Strongswan is using SHA-1 but Cisco is sending SHA2-512.

Actually, it is the rfc7296 the one mentioning SHA-1.
https://www.rfc-editor.org/rfc/rfc7296#section-3.8
===
   RSA Digital Signature                  1
      Computed as specified in Section 2.15 using an RSA private key
      with RSASSA-PKCS1-v1_5 signature scheme specified in [PKCS1]
      (implementers should note that IKEv1 used a different method for
      RSA signatures).  To promote interoperability, implementations
      that support this type *SHOULD* support signatures that use SHA-1
      as the hash function and *SHOULD* use SHA-1 as the default hash
      function when generating signatures.  Implementations can use the
      certificates received from a given peer as a hint for selecting a
      mutually understood hash function for the AUTH payload signature.
      Note, however, that the hash algorithm used in the AUTH payload
      signature doesn't have to be the same as any hash algorithm(s)
      used in the certificate(s).
===

Without RFC 7427 we only have a recommendation (SHOULD), as per RFC 2119
===
3. SHOULD   This word, or the adjective "RECOMMENDED", mean that there
   may exist valid reasons in particular circumstances to ignore a
   particular item, but the full implications must be understood and
   carefully weighed before choosing a different course.
===

So, considering all this, I have made a patch to try SHA2-512, SHA2-384, SHA2-256 if SHA1 
fails. It is more a "quick and dirty" patch, sorry, my knowledge of Strongswan 
internals is limited.
Another approach could be to use the pre-agreed PRF algorithm for RSA Auth, if 
SHA-1 fails.

With this patch the VPN between Strongswan and Cisco Firepower is successful 
with any proposal I tested.
===
charon-systemd: charon-systemd[3523065]:   using certificate "C=XX, O=XXXX, 
CN=XXXX"
charon-systemd: charon-systemd[3523065]:   certificate "C=XX, O=XXXX, CN=XXXX" 
key: 4096 bit RSA
charon-systemd: charon-systemd[3523065]:   using trusted ca certificate "C=XX, 
O=XXXX, CN=CAXXXX"
charon-systemd: charon-systemd[3523065]: checking certificate status of "C=XX, 
O=XXXX, CN=XXXX"
charon-systemd: charon-systemd[3523065]:   ocsp response correctly signed by "C=XX, 
O=XXXX, CN=OCSPXXXX"
charon-systemd: charon-systemd[3523065]:   ocsp response is valid: until Sep 23 
15:54:09 2022
charon-systemd: charon-systemd[3523065]:   using cached ocsp response
charon-systemd: charon-systemd[3523065]: certificate status is good
charon-systemd: charon-systemd[3523065]:   certificate "C=XX, O=XXXX, 
CN=CAXXXX" key: 2048 bit RSA
charon-systemd: charon-systemd[3523065]:   reached self-signed root ca with a 
path length of 0
charon-systemd: charon-systemd[3523065]: *authentication of 'C=XX, O=XXXX, 
CN=XXXX' with RSA_EMSA_PKCS1_SHA1 failed. Retrying with RSA_EMSA_PKCS1_SHA2_512*
charon-systemd: charon-systemd[3523065]:   using certificate "C=XX, O=XXXX, 
CN=XXXX"
charon-systemd: charon-systemd[3523065]:   certificate "C=XX, O=XXXX, CN=XXXX" 
key: 4096 bit RSA
charon-systemd: charon-systemd[3523065]:   using trusted ca certificate "C=XX, 
O=XXXX, CN=CAXXXX"
charon-systemd: charon-systemd[3523065]: checking certificate status of "C=XX, 
O=XXXX, CN=XXXX"
charon-systemd: charon-systemd[3523065]:   ocsp response correctly signed by "C=XX, 
O=XXXX, CN=OCSPXXXX"
charon-systemd: charon-systemd[3523065]:   ocsp response is valid: until Sep 23 
15:54:09 2022
charon-systemd: charon-systemd[3523065]:   using cached ocsp response
charon-systemd: charon-systemd[3523065]: certificate status is good
 charon-systemd: charon-systemd[3523065]:   certificate "C=XX, O=XXXX, 
CN=CAXXXX" key: 2048 bit RSA
charon-systemd: charon-systemd[3523065]:   reached self-signed root ca with a 
path length of 0
charon-systemd: charon-systemd[3523065]: *authentication of 'C=XX, O=XXXX, 
CN=XXXX with RSA_EMSA_PKCS1_SHA2_512 successful*
===

Patch is attached.

Regards,
Carlos Velasco
diff -ur a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c 
b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c      
2022-07-19 14:14:08.000000000 +0200
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c      
2022-09-23 15:46:17.850804518 +0200
@@ -634,6 +634,62 @@
                                                                                
  COND_ONLINE_VALIDATION_SUSPENDED);
        enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
                                                                                
                        key_type, id, auth, online);
+
+       if (auth_method == AUTH_RSA)
+       {
+               while (status == NOT_FOUND)
+               {
+                       while (enumerator->enumerate(enumerator, &public, 
&current_auth))
+                       {
+                               if (public->verify(public, params->scheme, 
params->params, octets,
+                                                                  auth_data) &&
+                                       is_compliant_cert(current_auth))
+                               {
+                                       DBG1(DBG_IKE, "authentication of '%Y' 
with %N successful", id,
+                                               signature_scheme_names, 
params->scheme);
+                                       status = SUCCESS;
+                                       auth->merge(auth, current_auth, FALSE);
+                                       auth->add(auth, AUTH_RULE_AUTH_CLASS, 
AUTH_CLASS_PUBKEY);
+                                       auth->add(auth, 
AUTH_RULE_IKE_SIGNATURE_SCHEME,
+                                                         
signature_params_clone(params));
+                                       if (!online)
+                                       {
+                                               auth->add(auth, 
AUTH_RULE_CERT_VALIDATION_SUSPENDED, TRUE);
+                                       }
+                                       break;
+                               }
+                               else
+                               {
+                                       if (params->scheme == 
SIGN_RSA_EMSA_PKCS1_SHA1)
+                                       {
+                                               DBG1(DBG_IKE, "authentication 
of '%Y' with %N failed. Retrying with %N", id,
+                                                       signature_scheme_names, 
params->scheme, signature_scheme_names, SIGN_RSA_EMSA_PKCS1_SHA2_512);
+                                               params->scheme = 
SIGN_RSA_EMSA_PKCS1_SHA2_512;
+                                               break;
+                                       }
+                                       if (params->scheme == 
SIGN_RSA_EMSA_PKCS1_SHA2_512)
+                                       {
+                                               DBG1(DBG_IKE, "authentication 
of '%Y' with %N failed. Retrying with %N", id,
+                                                       signature_scheme_names, 
params->scheme, signature_scheme_names, SIGN_RSA_EMSA_PKCS1_SHA2_384);
+                                               params->scheme = 
SIGN_RSA_EMSA_PKCS1_SHA2_384;
+                                               break;
+                                       }
+                                       if (params->scheme == 
SIGN_RSA_EMSA_PKCS1_SHA2_384)
+                                       {
+                                               DBG1(DBG_IKE, "authentication 
of '%Y' with %N failed. Retrying with %N", id,
+                                                       signature_scheme_names, 
params->scheme, signature_scheme_names, SIGN_RSA_EMSA_PKCS1_SHA2_256);
+                                               params->scheme = 
SIGN_RSA_EMSA_PKCS1_SHA2_256;
+                                               break;
+                                       }
+                                       status = FAILED;
+                                       DBG1(DBG_IKE, "signature validation 
failed, looking for another key");
+                                       break;
+                               }
+                       }
+               }
+       }
+       else
+       {
        while (enumerator->enumerate(enumerator, &public, &current_auth))
        {
                if (public->verify(public, params->scheme, params->params, 
octets,
@@ -674,6 +730,7 @@
                        DBG1(DBG_IKE, "signature validation failed, looking for 
another key");
                }
        }
+       }
        enumerator->destroy(enumerator);
        chunk_free(&octets);
        signature_params_destroy(params);

Reply via email to