Handle X509 certificates in base64 without prefix/suffix

Issue #201 resolved
Fabricio Gregorio created an issue

The method fromBase64Der https://bitbucket.org/b_c/jose4j/src/master/src/main/java/org/jose4j/keys/X509Util.java#lines-108 tries to parse base64 certificate to X509Certificate using https://docs.oracle.com/javase/7/docs/api/java/security/cert/CertificateFactory.html#generateCertificate(java.io.InputStream).

If the remote base64 certificate does not start with “-----BEGIN CERTIFICATE-----” and ends with “-----END CERTIFICATE-----” the parsing fails with:

Unable to convert <X> value to X509Certificate: java.security.cert.CertificateException: Unable to initialize, java.io.IOException: Short read of DER length; caused by: java.security.cert.CertificateException: Unable to initialize, java.io.IOException: Short read of DER length; caused by: java.io.IOException: Short read of DER length).

Can we check in this method if the string has the necesarry prefix/suffix and add them otherwise?

Thanks

Comments (8)

  1. Brian Campbell

    Hi Fabricio,

    That method fromBase64Der decodes the base64 first (https://bitbucket.org/b_c/jose4j/src/dad416151f06bcffb8ffc1a2c31b1fe741c29256/src/main/java/org/jose4j/keys/X509Util.java#lines-110) and passes the binary to generateCertificate, which does not need the “-----BEGIN/END CERTIFICATE-----” header/footer - the CertificateFactory.generateCertificate javadoc says that only applies to printable (Base64) encoding not binary. In fact, the fromBase64Der method only will parse encoded certs without the header/footer. The method is meant to help processing of the JOSE’s x5c, which has base64-encoded DER certs - see https://www.rfc-editor.org/rfc/rfc7517#section-4.7 and an example at https://www.rfc-editor.org/rfc/rfc7517#appendix-B

    This unit test also shows fromBase64Der processing input without the header/footer https://bitbucket.org/b_c/jose4j/src/master/src/test/java/org/jose4j/keys/X509UtilTest.java#lines-37

    So I’m not sure what’s causing the issue you are running into (probably some kind of encoding something) but what you’ve described here isn’t it.

    And changing the fromBase64Der method to do something different/more than working with x5c values isn’t really in scope.

  2. Fabricio Gregorio reporter

    Thank you for your response! You are right. It seems that the service I am consuming is exposing the base64 public key in the x5c field, instead of the certificate. Is the service wrong?

  3. Brian Campbell

    Yeah, x5c is defined as follows (which is definitely not the base64 public key)

    https://www.rfc-editor.org/rfc/rfc7517#section-4.7 :

    4.7. "x5c" (X.509 Certificate Chain) Parameter

    The "x5c" (X.509 certificate chain) parameter contains a chain of one

    or more PKIX certificates [RFC5280]. The certificate chain is

    represented as a JSON array of certificate value strings. Each

    string in the array is a base64-encoded (Section 4 of [RFC4648] --

    not base64url-encoded) DER [ITU.X690.1994] PKIX certificate value.

    The PKIX certificate containing the key value MUST be the first

    certificate. This MAY be followed by additional certificates, with

    each subsequent certificate being the one used to certify the

    previous one. The key in the first certificate MUST match the public

    key represented by other members of the JWK. Use of this member is

    OPTIONAL.

  4. Fabricio Gregorio reporter

    As a workaround, I am using the JwksVerificationKeyResolver like this:

    byte[] byteKey = Base64.getDecoder().decode(key.getX5c()[0]); //I have the public key here
    X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
    KeyFactory kf = KeyFactory.getInstance(key.getKty());
    
    Key k = kf.generatePublic(X509publicKey);
    JsonWebKey jwk = JsonWebKey.Factory.newJwk(k);
    jwk.setKeyId(key.getKid());
    jwk.setAlgorithm(key.getKty());
    jwk.setUse(key.getUse());
    JsonWebKeySet jsonWebKeySet = new JsonWebKeySet(jwk);
    JwksVerificationKeyResolver jwksResolver = new JwksVerificationKeyResolver(jsonWebKeySet.getJsonWebKeys());
    

    This way, I can generate a resolver without having a certificate. Is there a way of generating a HttpsJwksVerificationKeyResolver without the certificate and only with the public key?

    Thanks

  5. Brian Campbell

    HttpsJwksVerificationKeyResolver doesn’t need certificates at all - it uses the public keys from JWKs. But a malformed x5c in the JWKs might cause problems. I’m not sure, to be honest.

  6. Log in to comment