Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit e84c5083e8fd0069c65910b60ff7b6e1738b95b9 1 parent b3da6d2
@tekul tekul authored
View
55 spring-security-jwt/src/main/java/org/springframework/security/jwt/crypto/sign/RsaKeyHelper.java
@@ -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);
View
20 spring-security-jwt/src/test/java/org/springframework/security/jwt/crypto/cipher/RsaTestKeyData.java
@@ -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-----";
+
}
View
12 spring-security-jwt/src/test/java/org/springframework/security/jwt/crypto/sign/RsaSigningTests.java
@@ -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);
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.