|
|
|
@ -21,9 +21,12 @@ import java.io.IOException;
|
|
|
|
|
import java.security.GeneralSecurityException;
|
|
|
|
|
import java.security.KeyFactory;
|
|
|
|
|
import java.security.PrivateKey;
|
|
|
|
|
import java.security.spec.InvalidKeySpecException;
|
|
|
|
|
import java.security.spec.PKCS8EncodedKeySpec;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.Base64;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
@ -35,6 +38,7 @@ import java.util.regex.Pattern;
|
|
|
|
|
*
|
|
|
|
|
* @author Scott Frederick
|
|
|
|
|
* @author Phillip Webb
|
|
|
|
|
* @author Moritz Halbritter
|
|
|
|
|
*/
|
|
|
|
|
final class PemPrivateKeyParser {
|
|
|
|
|
|
|
|
|
@ -55,9 +59,12 @@ final class PemPrivateKeyParser {
|
|
|
|
|
private static final List<PemParser> PEM_PARSERS;
|
|
|
|
|
static {
|
|
|
|
|
List<PemParser> parsers = new ArrayList<>();
|
|
|
|
|
parsers.add(new PemParser(PKCS1_HEADER, PKCS1_FOOTER, "RSA", PemPrivateKeyParser::createKeySpecForPkcs1));
|
|
|
|
|
parsers.add(new PemParser(EC_HEADER, EC_FOOTER, "EC", PemPrivateKeyParser::createKeySpecForEc));
|
|
|
|
|
parsers.add(new PemParser(PKCS8_HEADER, PKCS8_FOOTER, "RSA", PKCS8EncodedKeySpec::new));
|
|
|
|
|
parsers.add(new PemParser(PKCS1_HEADER, PKCS1_FOOTER, Collections.singleton("RSA"),
|
|
|
|
|
PemPrivateKeyParser::createKeySpecForPkcs1));
|
|
|
|
|
parsers.add(new PemParser(EC_HEADER, EC_FOOTER, Collections.singleton("EC"),
|
|
|
|
|
PemPrivateKeyParser::createKeySpecForEc));
|
|
|
|
|
parsers.add(new PemParser(PKCS8_HEADER, PKCS8_FOOTER, Arrays.asList("RSA", "EC", "DSA", "Ed25519"),
|
|
|
|
|
PKCS8EncodedKeySpec::new));
|
|
|
|
|
PEM_PARSERS = Collections.unmodifiableList(parsers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -134,14 +141,14 @@ final class PemPrivateKeyParser {
|
|
|
|
|
|
|
|
|
|
private final Pattern pattern;
|
|
|
|
|
|
|
|
|
|
private final String algorithm;
|
|
|
|
|
private final Collection<String> algorithms;
|
|
|
|
|
|
|
|
|
|
private final Function<byte[], PKCS8EncodedKeySpec> keySpecFactory;
|
|
|
|
|
|
|
|
|
|
PemParser(String header, String footer, String algorithm,
|
|
|
|
|
PemParser(String header, String footer, Collection<String> algorithms,
|
|
|
|
|
Function<byte[], PKCS8EncodedKeySpec> keySpecFactory) {
|
|
|
|
|
this.pattern = Pattern.compile(header + BASE64_TEXT + footer, Pattern.CASE_INSENSITIVE);
|
|
|
|
|
this.algorithm = algorithm;
|
|
|
|
|
this.algorithms = algorithms;
|
|
|
|
|
this.keySpecFactory = keySpecFactory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -158,8 +165,15 @@ final class PemPrivateKeyParser {
|
|
|
|
|
private PrivateKey parse(byte[] bytes) {
|
|
|
|
|
try {
|
|
|
|
|
PKCS8EncodedKeySpec keySpec = this.keySpecFactory.apply(bytes);
|
|
|
|
|
KeyFactory keyFactory = KeyFactory.getInstance(this.algorithm);
|
|
|
|
|
return keyFactory.generatePrivate(keySpec);
|
|
|
|
|
for (String algorithm : this.algorithms) {
|
|
|
|
|
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
|
|
|
|
|
try {
|
|
|
|
|
return keyFactory.generatePrivate(keySpec);
|
|
|
|
|
}
|
|
|
|
|
catch (InvalidKeySpecException ignored) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
catch (GeneralSecurityException ex) {
|
|
|
|
|
throw new IllegalArgumentException("Unexpected key format", ex);
|
|
|
|
|