Permalink
Browse files

Add JWT support for RSA public key PEM formats.

This makes it possible to create an RsaVerifier with
a PEM encoded public key. Previously it could only be
done with a private key or an ssh-keygen format public
key.
  • Loading branch information...
tekul committed Mar 1, 2013
1 parent b3da6d2 commit e84c5083e8fd0069c65910b60ff7b6e1738b95b9
@@ -18,18 +18,13 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
+import java.security.*;
import java.security.interfaces.RSAPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.*;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
/**
@@ -50,32 +45,38 @@ static KeyPair parseKeyPair(String pemData) {
}
String type = m.group(1);
+ final byte[] content = b64Decode(utf8Encode(m.group(2)));
- if (!type.equals("RSA PRIVATE KEY")) {
- throw new IllegalArgumentException("Only private key data is currently supported");
- }
-
- String content = m.group(2);
+ PublicKey publicKey;
+ PrivateKey privateKey = null;
try {
- ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(b64Decode(utf8Encode(content))));
- if (seq.size() != 9) {
- throw new IllegalArgumentException("Invalid RSA Key ASN1 sequence.");
- }
- org.bouncycastle.asn1.pkcs.RSAPrivateKey key = org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(seq);
- RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent());
- RSAPrivateCrtKeySpec privSpec = new RSAPrivateCrtKeySpec(key.getModulus(), key.getPublicExponent(),
+ KeyFactory fact = KeyFactory.getInstance("RSA");
+ if (type.equals("RSA PRIVATE KEY")) {
+ ASN1Sequence seq = ASN1Sequence.getInstance(content);
+ if (seq.size() != 9) {
+ throw new IllegalArgumentException("Invalid RSA Private Key ASN1 sequence.");
+ }
+ org.bouncycastle.asn1.pkcs.RSAPrivateKey key = org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(seq);
+ RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent());
+ RSAPrivateCrtKeySpec privSpec = new RSAPrivateCrtKeySpec(key.getModulus(), key.getPublicExponent(),
key.getPrivateExponent(), key.getPrime1(), key.getPrime2(), key.getExponent1(), key.getExponent2(),
key.getCoefficient());
+ publicKey = fact.generatePublic(pubSpec);
+ privateKey = fact.generatePrivate(privSpec);
+ } else if (type.equals("PUBLIC KEY")) {
+ KeySpec keySpec = new X509EncodedKeySpec(content);
+ publicKey = fact.generatePublic(keySpec);
+ } else if (type.equals("RSA PUBLIC KEY")) {
+ ASN1Sequence seq = ASN1Sequence.getInstance(content);
+ org.bouncycastle.asn1.pkcs.RSAPublicKey key = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(seq);
+ RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent());
+ publicKey = fact.generatePublic(pubSpec);
+ } else {
+ throw new IllegalArgumentException(type + " is not a supported format");
+ }
- KeyFactory fact = KeyFactory.getInstance("RSA");
-
- return new KeyPair(
- fact.generatePublic(pubSpec),
- fact.generatePrivate(privSpec));
- }
- catch (IOException e) {
- throw new RuntimeException(e);
+ return new KeyPair(publicKey, privateKey);
}
catch (InvalidKeySpecException e) {
throw new RuntimeException(e);
@@ -97,4 +97,24 @@
+ "eJQ4nUR0pkfEaeRWOmzWE/3wC9DHoSmYoTF7B3gwyPvuBFgB5KjSk+G6AuubLkMs+jFJQZJkQcI+UJ859MC3024ThjBukLAN8OZBv7"
+ "2d6rtDQ/Ca0/qMWtXhVneKvZxZg5MXoVwvtkidwbdoK9fGnylRDs0+KZh3vR0Q+67V blah@blah.local";
+
+ public static final String SSH_PUBLIC_KEY_OPENSSL_PEM_STRING = "-----BEGIN PUBLIC KEY-----\n" +
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwARN4S7Z0asSEj61+SIv\n" +
+ "tUUuHopd/ffne1CbaHXNxj/cI4rY0k5ELZ2SGCFVgmx9XADJJhYoQImO+vMxFAqb\n" +
+ "WxyO45B1rZR1q0ChEFWLGPmNB+fY8TrFHIjJb873s0d2FTYDOwst6HdKPjXkLdgG\n" +
+ "HO4K1fLnO1cQHKGglBKvc4ZSVniUOJ1EdKZHxGnkVjps1hP98AvQx6EpmKExewd4\n" +
+ "MMj77gRYAeSo0pPhugLrmy5DLPoxSUGSZEHCPlCfOfTAt9NuE4YwbpCwDfDmQb+9\n" +
+ "neq7Q0PwmtP6jFrV4VZ3ir2cWYOTF6FcL7ZIncG3aCvXxp8pUQ7NPimYd70dEPuu\n" +
+ "1QIDAQAB\n" +
+ "-----END PUBLIC KEY-----";
+
+ public static final String SSH_PUBLIC_KEY_PEM_STRING = "-----BEGIN RSA PUBLIC KEY-----\n" +
+ "MIIBCgKCAQEAwARN4S7Z0asSEj61+SIvtUUuHopd/ffne1CbaHXNxj/cI4rY0k5E\n" +
+ "LZ2SGCFVgmx9XADJJhYoQImO+vMxFAqbWxyO45B1rZR1q0ChEFWLGPmNB+fY8TrF\n" +
+ "HIjJb873s0d2FTYDOwst6HdKPjXkLdgGHO4K1fLnO1cQHKGglBKvc4ZSVniUOJ1E\n" +
+ "dKZHxGnkVjps1hP98AvQx6EpmKExewd4MMj77gRYAeSo0pPhugLrmy5DLPoxSUGS\n" +
+ "ZEHCPlCfOfTAt9NuE4YwbpCwDfDmQb+9neq7Q0PwmtP6jFrV4VZ3ir2cWYOTF6Fc\n" +
+ "L7ZIncG3aCvXxp8pUQ7NPimYd70dEPuu1QIDAQAB\n" +
+ "-----END RSA PUBLIC KEY-----";
+
}
@@ -41,12 +41,20 @@ public void keysFromPrivateAndPublicKeyStringDataAreCorrect() throws Exception {
byte[] content = Codecs.utf8Encode("Hi I'm the data");
RsaSigner signer = new RsaSigner(RsaTestKeyData.SSH_PRIVATE_KEY_STRING);
+ final byte[] signed = signer.sign(content);
// First extract the public key from the private key data
RsaVerifier verifier = new RsaVerifier(RsaTestKeyData.SSH_PRIVATE_KEY_STRING);
- verifier.verify(content, signer.sign(content));
+ verifier.verify(content, signed);
// Then try with the ssh-rsa public key format
verifier = new RsaVerifier(RsaTestKeyData.SSH_PUBLIC_KEY_STRING);
- verifier.verify(content, signer.sign(content));
+ verifier.verify(content, signed);
+
+ // Try with the PEM format public keys
+ verifier = new RsaVerifier(RsaTestKeyData.SSH_PUBLIC_KEY_PEM_STRING);
+ verifier.verify(content, signed);
+
+ verifier = new RsaVerifier(RsaTestKeyData.SSH_PUBLIC_KEY_OPENSSL_PEM_STRING);
+ verifier.verify(content, signed);
}
}

0 comments on commit e84c508

Please sign in to comment.