0
votes

how does mutual SSL work in wso2, I am following the link https://apim.docs.wso2.com/en/latest/learn/api-security/api-authentication/secure-apis-using-mutual-ssl/ it works in local where domain is localhost

But in our production environment, where our gateway is fronted with AWS ALB it does not work, for the same certificate and key which I used in local.

Error in logs

ERROR - MutualSSLAuthenticator Mutual SSL authentication failure [2020-11-02 10:20:56,302] ERROR - MutualSSLAuthenticator Mutual SSL authentication failure

On wso2 documentation is mentioned that the following prerequisites need to be met by the Load Balancer.

Terminate the mutual SSL connection from the client. Pass the client SSL certificate to the Gateway in an HTTP Header

But from AWS team i came to know that "So is not possible to achieve Client<=>Backend TLS mutual authentication with an ALB in the middle."

It will be great if someone will be able to clear the confusion

1

1 Answers

0
votes

In your scenario, the Load balancer terminates the SSL connection with the wso2 server.

Hence, you have to pass the certificate in a special header when invoking the request.

X-WSO2-CLIENT-CERTIFICATE

If the certificate is not presented by default (due to the SSL termination from the LB level), it checks the above header and extracts the certificate. That certificate will be checked against the client-trustore.jks and authenticated.

The following is the logic in which was extracted and verified.

https://github.com/wso2/carbon-apimgt/blob/master/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/Utils.java#L386

public static X509Certificate getClientCertificate(org.apache.axis2.context.MessageContext axis2MessageContext)
            throws APIManagementException {

        Map headers =
                (Map) axis2MessageContext.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
        Object sslCertObject = axis2MessageContext.getProperty(NhttpConstants.SSL_CLIENT_AUTH_CERT_X509);
        X509Certificate certificateFromMessageContext = null;
        if (sslCertObject != null) {
            X509Certificate[] certs = (X509Certificate[]) sslCertObject;
            certificateFromMessageContext = certs[0];
        }
        if (headers.containsKey(Utils.getClientCertificateHeader())) {

            try {
                if (!isClientCertificateValidationEnabled() || APIUtil
                        .isCertificateExistsInTrustStore(certificateFromMessageContext)){
                    String base64EncodedCertificate = (String) headers.get(Utils.getClientCertificateHeader());
                    if (base64EncodedCertificate != null) {
                        base64EncodedCertificate = URLDecoder.decode(base64EncodedCertificate).
                                replaceAll(APIConstants.BEGIN_CERTIFICATE_STRING, "")
                                .replaceAll(APIConstants.END_CERTIFICATE_STRING, "");

                        byte[] bytes = Base64.decodeBase64(base64EncodedCertificate);
                        try (InputStream inputStream = new ByteArrayInputStream(bytes)) {
                            X509Certificate x509Certificate = X509Certificate.getInstance(inputStream);
                            if (APIUtil.isCertificateExistsInTrustStore(x509Certificate)) {
                                return x509Certificate;
                            }else{
                                log.debug("Certificate in Header didn't exist in truststore");
                                return null;
                            }
                        } catch (IOException | CertificateException | APIManagementException e) {
                            String msg = "Error while converting into X509Certificate";
                            log.error(msg, e);
                            throw new APIManagementException(msg, e);
                        }
                    }

                }
            } catch (APIManagementException e) {
                String msg = "Error while validating into Certificate Existence";
                log.error(msg, e);
                throw new APIManagementException(msg, e);

            }

        }
        return certificateFromMessageContext;
    }


Hope the above will clarifies your concerns.

Thanks, Dileepa