All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.safelayer.rap.json.PublicKeyDeserializer Maven / Gradle / Ivy

Go to download

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);
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy