简体   繁体   中英

How to generate a JWK from a PEM encoded public key in Java?

I have a PEM encoded public key and want to generate a JWK key from it in Java. This is what I tried:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwGhr2bd1u5JVSWEQjo+UWfH1pE0iK9lm
C//yb5my5PnQ2O62etGX3odWvb10J95pWvhahQcC8wPnjvedZtBxcgHiFOprbYYgZWcXarpw9EO6
H/brPiK1h4akjgNxTdBsFHikzaZ1Erd3T4FEzop8j4pRNrjA/tUHEqxdqOl7H0xHJmbv9odn4Mmq
E/azyohY8LhZ/+YUNbEAT3RCb1Z64tUHow4K+K3QFbNTcEQdN69wNvuAskYsSPCR2f8c6hYShhdf
s8NxnGAKgb9APWvkbLw8+n2/sbHyCmWw5ofW1LokXiCxczqK87UCPMaqFwOt2rlBNrzoMMzWAmH7
s9O6qQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIICuTCCAaGgAwIBAgIJALza9IWWJsHkMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMMEVN0ZXBo
YW4gV2lzc2VsL09VMB4XDTIxMDEyMDE5MDAxM1oXDTIxMDMwNjEzMDAxM1owHDEaMBgGA1UEAwwR
U3RlcGhhbiBXaXNzZWwvT1UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAaGvZt3W7
klVJYRCOj5RZ8fWkTSIr2WYL//JvmbLk+dDY7rZ60Zfeh1a9vXQn3mla+FqFBwLzA+eO951m0HFy
AeIU6mtthiBlZxdqunD0Q7of9us+IrWHhqSOA3FN0GwUeKTNpnUSt3dPgUTOinyPilE2uMD+1QcS
rF2o6XsfTEcmZu/2h2fgyaoT9rPKiFjwuFn/5hQ1sQBPdEJvVnri1QejDgr4rdAVs1NwRB03r3A2
+4CyRixI8JHZ/xzqFhKGF1+zw3GcYAqBv0A9a+RsvDz6fb+xsfIKZbDmh9bUuiReILFzOorztQI8
xqoXA63auUE2vOgwzNYCYfuz07qpAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIHX2SudJ6vtpenZ
IhR44/t4WTSfN53lCB2AxOrMFDoa1zZDfM/w7ewtfAND3Y0VGNerpxCh3D2M9NDImgTVKr42ip/+
Dxkfubrph24lW7o3gR2ujlLoY4K9Xvt8xD5jo1PRQC6G9YgS6nOeJjpu55QH1BVT1s2i09WAzNID
l4rIsyRoP9r4FZu2W21UYEzs39uOM81r/zEM+7o2UZXVmx6CLdnPZG4HLvPcqNO2waMBNxGXpwAU
jiND/72QMzzENl/Su5Sc//4TOuNYKdTjMZ5GhCBftpMRL6FebFa9lkhES07e5aVzW4UyC94KpHXH
h+a3MDv2zYm070cF44zDTFQ=
-----END CERTIFICATE-----

Java method using com.nimbusds.jose.jwk and vert.x 's JsonObject :

  String getJWTKey(final String rawKey) throws Exception {
    final KeyFactory kf = KeyFactory.getInstance("RSA");
    final SubjectPublicKeyInfo pubKeyInfo =
        (SubjectPublicKeyInfo) new PEMParser(new StringReader(rawKey)).readObject();
    final X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(pubKeyInfo.getEncoded());
    final RSAPublicKey rsaPubKey = (RSAPublicKey) kf.generatePublic(keySpecX509);

    // How to get these two?
    List<Base64> certChain = null;
    Base64URL thumbprint = null;

    final RSAKey key = new RSAKey.Builder(rsaPubKey)
        .keyUse(KeyUse.SIGNATURE)
        .algorithm(new Algorithm("RS256"))
        .keyID("mykey")
        .x509CertChain(certChain)
        .x509CertSHA256Thumbprint(thumbprint)
        .build();
 
    return key.toJSONString();

The result is:

{
  "keys": [
    {
      "kty": "RSA",
      "e": "AQAB",
      "use": "sig",
      "alg" : "RS256",
      "kid": "mykey",
      "n": "wGhr2bd1u5JVSWEQjo-UWfH1pE0iK9lmC__yb5my5PnQ2O62etGX3odWvb10J95pWvhahQcC8wPnjvedZtBxcgHiFOprbYYgZWcXarpw9EO6H_brPiK1h4akjgNxTdBsFHikzaZ1Erd3T4FEzop8j4pRNrjA_tUHEqxdqOl7H0xHJmbv9odn4MmqE_azyohY8LhZ_-YUNbEAT3RCb1Z64tUHow4K-K3QFbNTcEQdN69wNvuAskYsSPCR2f8c6hYShhdfs8NxnGAKgb9APWvkbLw8-n2_sbHyCmWw5ofW1LokXiCxczqK87UCPMaqFwOt2rlBNrzoMMzWAmH7s9O6qQ"
    }
  ]
}

Looking at documentation I'm missing:

  • x5c
  • x5t

What do I miss in my code? A solution using bouncycastle would be very much welcome. I have access to the cert file (self generated) if required

Along the way I learned that I need the certificate besides the public key. So the 2 method solution (until I learn better) is:

/**
   * Returns the JSON formatted JWK based on provided public key / cert
   *
   * @param rawKey - public key as read from disk in pem format
   * @param cert - certificate as read from disk in pem format
   * @return JWK Key as Optional<String>
   */
  public static Optional<String> getJwkString(final String rawKey, final String cert) {
    try {
      final KeyFactory kf = KeyFactory.getInstance("RSA");
      final CertificateFactory cf = CertificateFactory.getInstance("X.509");
      final SubjectPublicKeyInfo pubKeyInfo =
          (SubjectPublicKeyInfo) new PEMParser(new StringReader(rawKey)).readObject();
      final X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(pubKeyInfo.getEncoded());
      final RSAPublicKey rsaPubKey = (RSAPublicKey) kf.generatePublic(keySpecX509);

      final X509Certificate rsaCert =
          (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(cert.getBytes()));
      final byte[] certEncoded = rsaCert.getEncoded();
      final List<Base64> certChain = new ArrayList<>();
      certChain.add(Base64.encode(certEncoded));

      final Base64URL thumbprint = Base64URL.from(SamlResourceUtils.getThumbprint(certEncoded));

      final RSAKey key = new RSAKey.Builder(rsaPubKey)
          .keyUse(KeyUse.SIGNATURE)
          .algorithm(new Algorithm("RS256"))
          .x509CertChain(certChain)
          .x509CertThumbprint(thumbprint)
          .keyID("mykey")
          .build();

      return Optional.of(key.toJSONString());

    } catch (final Exception e) {
      SamlResourceUtils.logger.error(e);
    }

    return Optional.empty();
  }

  public static String getThumbprint(final byte[] bytes)
      throws NoSuchAlgorithmException {
    final MessageDigest md = MessageDigest.getInstance("SHA-1");
    md.update(bytes);
    return Hex.toHexString(md.digest());
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM