com.safelayer.rap.json.PublicKeyDeserializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pki-connector-restapi Show documentation
Show all versions of pki-connector-restapi Show documentation
The PKI Connector RESTAPI is a library that helps developing new PKI Connectors for TrustedX
The newest version!
package com.safelayer.rap.json;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyException;
import java.security.KeyFactory;
import java.security.ProviderException;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.codec.binary.Base64;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class PublicKeyDeserializer extends JsonDeserializer {
public static class PublicKeyDetector {
private static int SEQUENCE_TAG = 0x30;
private static int OID_TAG = 0x06;
private static int LENGTH_LIMIT = 0x80;
// RSA 1.2.840.113549.1.1.1
private static byte[] RSA_OID_BYTES = {0x2A,(byte)0x86,0x48,(byte)0x86,(byte)0xF7,0x0D,0x01,0x01,0x01};
// EC 1.2.840.10045.2.1
private static byte[] EC_OID_BYTES = {0x2A,(byte)0x86,0x48,(byte)0xCE,0x3D,0x02,0x01};
public static String getPublicKeyAlgorithm(byte[] publicKeyBytes) throws Exception {
// 0x30 (SEQUENCE)
//
// - 0x80 --> UndefinedLength
// - < 0x80 (bit a 0) ---> Longitud =
// - > 0x80 ---> Longitud de la logitug =
// 0x30 (SEQUENCE)
//
// 0x06 (OID)
//
//
ByteArrayInputStream stream = new ByteArrayInputStream(publicKeyBytes);
int keySequenceTag = stream.read();
if (keySequenceTag == SEQUENCE_TAG) {
int length = stream.read();
boolean lengthSkipped;
if (length <= LENGTH_LIMIT) {
lengthSkipped = true;
}
else {
int lengthBytes = length - LENGTH_LIMIT;
lengthSkipped = (lengthBytes == stream.skip(lengthBytes));
}
if (lengthSkipped) {
int algSequenceTag = stream.read();
if (algSequenceTag == SEQUENCE_TAG && stream.read() != -1) {
int oidTag = stream.read();
if (oidTag == OID_TAG) {
int oidBytesLength = stream.read();
byte[] oid = new byte[oidBytesLength];
if (oidBytesLength == stream.read(oid)) {
if (Arrays.equals(oid, RSA_OID_BYTES)) {
return "RSA";
}
if (Arrays.equals(oid, EC_OID_BYTES)) {
return "EC";
}
throw new KeyException("Unknown public key algorithm OID " + DatatypeConverter.printHexBinary(oid));
}
}
}
}
}
throw new KeyException("Unable to get public key algorithm");
}
}
private static final String RSA_KEY_FACTORY = "RSA";
private static final String EC_KEY_FACTORY = "EC";
private KeyFactory rsaKeyFactory;
private volatile KeyFactory ecKeyFactory = null;
public PublicKeyDeserializer() throws Exception {
//instantiate factories only once
rsaKeyFactory = KeyFactory.getInstance(RSA_KEY_FACTORY);
//but do not instantiate here the factory for EC algorithm in order not to require bouncy castle provider to be installed unless
//there is the real need for EC keys
}
private KeyFactory getEcKeyFactory() throws Exception {
if (ecKeyFactory == null) {
synchronized(this) {
if (ecKeyFactory == null) {
ecKeyFactory = KeyFactory.getInstance(EC_KEY_FACTORY);
}
}
}
if (ecKeyFactory == null)
throw new ProviderException("Cannot instanticate KeyFactory for algorithm EC");
return ecKeyFactory;
}
@Override
public PublicKey deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
if (parser.getText() == null)
return null;
byte[] keyBytes = Base64.decodeBase64(parser.getText());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
String keyAlgorithm;
try {
keyAlgorithm = PublicKeyDetector.getPublicKeyAlgorithm(keyBytes);
} catch (Exception e) {
throw new JsonException("Unsupported key algorithm", e);
}
KeyFactory keyFactory;
if ("RSA".equals(keyAlgorithm))
keyFactory = rsaKeyFactory;
else if ("EC".equals(keyAlgorithm)) {
try {
keyFactory = getEcKeyFactory();
} catch (Exception e) {
throw new JsonException("Unsupported EC key algorithm", e);
}
}
else
throw new JsonException("Unsupported key algorithm " + keyAlgorithm);
try {
return keyFactory.generatePublic(keySpec);
}
catch (Exception e) {
throw new JsonException(e);
}
}
}