Java Callout reading PublicKeys from HTTP Header

Dear Madame or Sir

I have a java callout reading the client certificate chain out of an HTTP header:

messageContext.getRequestMessage().getHeadersAsObject("javax.servlet.request.X509Certificate");

The trace shows that the returned value is of type Object[] and that the first element of this Array is of type java.security.cert.X509Certificate []

CDR.JWSTCredentialMapper.getUser.objCerts[] [Ljava.lang.Object;@47b95597
CDR.JWSTCredentialMapper.getUser.objCerts[0] [Ljava.security.cert.X509Certificate;@1f774476

Unfortunately when I try to cast the first element of the array to java.security.cert.X509Certificate [] I get

Exception: java.lang.ClassCastException: java.lang.String cannot be cast to [Ljava.security.cert.X509Certificate;

How can I extract the X509Certificate object?

Gladly awaiting your answer

Kind Regards

Carlo De Rossi

0 2 383
2 REPLIES 2

Hi Carlo

What is "CDR.JWSTCredentialMapper.getUser.objCerts[]" ?

is that a context variable name?

I think you are getting a ClassCastException.

It would be good to see the Java code that triggers this exception, along with the exact exception message with the line number included, correlated to where in your source code that line number is.

Can you provide that?

Also, you are using "messageContext.getRequestMessage().getHeadersAsObject("javax.servlet.request.X509Certificate");"

I'm not sure that method will do for you, what you want.

I think Maybe your cert, passed in the header, looks like...a very long base64 encoded (PEM-encoded) string. Simply casting that to an X509Certificate is not going to work. (Even though there is a method named getHeadersAsObject() which seems to say "I can do this for you", it's not possible to arbitrarily convert between string forms and objects in Java.)

There are libraries that can de-serialize from certs in PEM-encoded form into actual cert objects. Or, you can "do it yourself" by base64-decoding the string, then converting that byte array into a ByteArrayInputStream and reading the Cert that way.

    private static X509Certificate certStringToCert(String s)
        throws InvalidKeySpecException, CertificateException, UnsupportedEncodingException {
        if (s==null) return null;
        s = s.trim();
        if (s.startsWith("-----BEGIN CERTIFICATE-----") &&
            s.endsWith("-----END CERTIFICATE-----")) {
            // This is an X509 cert;
            // Strip the prefix and suffix.
            s = s.substring(27, s.length() - 25);
        }
        // else, assume it is a bare base-64 encoded string
        s = s.replaceAll("\\\\n","");
        s = s.replaceAll("[\\r|\\n| ]","");
        // base64-decode it, and  produce a public key from the result
        byte[] certBytes = Base64.decodeBase64(s);
        ByteArrayInputStream is = new ByteArrayInputStream(certBytes);
        CertificateFactory fact = CertificateFactory.getInstance("X.509");
        X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
        return cer;
    }

Ciao Dino

thanks for your answer.

The problem is that a Java Callout has no access to the client certificate (public key, two way TSL), a callout can only access the client certificate's Common Name (CN) via property: hence I modified my TomCAT client to send the Public Keys certificate chain (Client certificate and CAs) as a standard Java header. Unfortunately the JAX-RS library I was using had a bug and did not serialized properly the objects: I am using the Jersey (JAX-RS RI) library now and it works fine.

It would be good if it would be possible to access the client's certificate chain as object (javax.servlet.request.X509Certificate[]).

Problem solved by now 🙂

Thanks for your help!

ciao

carlo