Wednesday, August 3, 2016

Manually create JWKS_URI for public certificates

A JWK is a JSON representation of a cryptographic key.  More details on this can be found in https://tools.ietf.org/html/rfc7517#section-4. Following blog would give out the steps on how you can manually extract modulus and exponent values of a public certificate , in the format expected in this JWKS_URI.

For this example, we will be trying to extract the values from WSO2 Identity Server's public certificate.

1. Find the public keystore .jks file which is located in <WSO2_IS>/repository/resources/security folder. (wso2carbon.jks)

2. Next step is to extract the public certificate from the keystore, and get the RSAPublic Key of it. For all these steps I will be creating a java client which will be using java.security.KeyStore functions.

 FileInputStream file = new FileInputStream("/Desktop/wso2IS/repository/resources/security/wso2carbon.jks");
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            keystore.load(file, "wso2carbon".toCharArray());
            String alias = "wso2carbon";
            // Get certificate of public key
            Certificate cert = keystore.getCertificate(alias);
            // Get public key
            publicKey = (RSAPublicKey) cert.getPublicKey();

3. Now that you have the publicKey extracted, you can get the modulus and exponent values.
 like below.
BigInteger n =  publicKey.getModulus();
BigInterger e =  publicKey.getPublicExponent();


 But in order to add these into JWKS_URI format , as explained in [1], you need to have those integer values, base64url encoded in their bigendian format. So for this following code snippets will be used.
Following function can be called, where bytes represents n.toByteArray() and e.toByteArray() accordingly.
base64Encode(bytes, 0, bytes.length, false);
So you could invoke like below.

base64Encode(n.toByteArray(), 0 , n.toByteArray().length,false);
base64Encode(e.toByteArray(), 0 , e.toByteArray().length,false);

 this base64Encode function code will be like below.

 public String base64Encode(final byte[] bytes, final int offset, final int length, final boolean padding) {
        final StringBuilder buffer = new StringBuilder(length * 3);
        for (int i = offset; i < offset + length; i += 3) {

            int p0 = bytes[i] & 0xFC;
            p0 >>= 2;

            int p1 = bytes[i] & 0x03;
            p1 <<= 4;

            int p2;
            int p3;
            if (i + 1 < offset + length) {
                p2 = bytes[i + 1] & 0xF0;
                p2 >>= 4;
                p3 = bytes[i + 1] & 0x0F;
                p3 <<= 2;
            } else {
                p2 = 0;
                p3 = 0;
            }
            int p4;
            int p5;
            if (i + 2 < offset + length) {
                p4 = bytes[i + 2] & 0xC0;
                p4 >>= 6;
                p5 = bytes[i + 2] & 0x3F;
            } else {
                p4 = 0;
                p5 = 0;
            }

            if (i + 2 < offset + length) {
                buffer.append(ENCODE_MAP[p0]);
                buffer.append(ENCODE_MAP[p1 | p2]);
                buffer.append(ENCODE_MAP[p3 | p4]);
                buffer.append(ENCODE_MAP[p5]);
            } else if (i + 1 < offset + length) {
                buffer.append(ENCODE_MAP[p0]);
                buffer.append(ENCODE_MAP[p1 | p2]);
                buffer.append(ENCODE_MAP[p3]);
                if (padding) {
                    buffer.append('=');
                }
            } else {
                buffer.append(ENCODE_MAP[p0]);
                buffer.append(ENCODE_MAP[p1 | p2]);
                if (padding) {
                    buffer.append("==");
                }
            }
        }
        return buffer.toString();
    }
This code block will convert the exponent and modulus values to their big endian format, and finally encode them. ENCODE_MAP value will be "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray();

After you get these value in proper format, you can look into [1] and create the json representation as required.

[1] https://tools.ietf.org/html/rfc7517#section-4.

No comments:

Post a Comment