org.apache.hadoop.gateway.services.security.impl.X509CertificateUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.gateway.services.security.impl.X509CertificateUtil.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hadoop.gateway.services.security.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;

import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.hadoop.gateway.i18n.GatewaySpiMessages;

public class X509CertificateUtil {

    private static GatewaySpiMessages LOG = MessagesFactory.get(GatewaySpiMessages.class);

    /**
     * Create a self-signed X.509 Certificate
     * @param dn the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
     * @param pair the KeyPair
     * @param days how many days from now the Certificate is valid for
     * @param algorithm the signing algorithm, eg "SHA1withRSA"
     */
    public static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm)
            throws GeneralSecurityException, IOException {

        PrivateKey privkey = pair.getPrivate();
        Object x509CertImplObject = null;
        try {
            Date from = new Date();
            Date to = new Date(from.getTime() + days * 86400000l);

            Class<?> certInfoClass = Class.forName(getX509CertInfoModuleName());
            Constructor<?> certInfoConstr = certInfoClass.getConstructor();
            Object certInfoObject = certInfoConstr.newInstance();

            // CertificateValidity interval = new CertificateValidity(from, to);
            Class<?> certValidityClass = Class.forName(getX509CertifValidityModuleName());
            Constructor<?> certValidityConstr = certValidityClass
                    .getConstructor(new Class[] { Date.class, Date.class });
            Object certValidityObject = certValidityConstr.newInstance(from, to);

            BigInteger sn = new BigInteger(64, new SecureRandom());

            // X500Name owner = new X500Name(dn);
            Class<?> x500NameClass = Class.forName(getX509X500NameModuleName());
            Constructor<?> x500NameConstr = x500NameClass.getConstructor(new Class[] { String.class });
            Object x500NameObject = x500NameConstr.newInstance(dn);

            Method methodSET = certInfoObject.getClass().getMethod("set", String.class, Object.class);

            // info.set(X509CertInfo.VALIDITY, interval);
            methodSET.invoke(certInfoObject, getSetField(certInfoObject, "VALIDITY"), certValidityObject);

            // info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
            Class<?> certificateSerialNumberClass = Class.forName(getCertificateSerialNumberModuleName());
            Constructor<?> certificateSerialNumberConstr = certificateSerialNumberClass
                    .getConstructor(new Class[] { BigInteger.class });
            Object certificateSerialNumberObject = certificateSerialNumberConstr.newInstance(sn);
            methodSET.invoke(certInfoObject, getSetField(certInfoObject, "SERIAL_NUMBER"),
                    certificateSerialNumberObject);

            // info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
            try {
                Class<?> certificateSubjectNameClass = Class.forName(getCertificateSubjectNameModuleName());
                Constructor<?> certificateSubjectNameConstr = certificateSubjectNameClass
                        .getConstructor(new Class[] { x500NameClass });
                Object certificateSubjectNameObject = certificateSubjectNameConstr.newInstance(x500NameObject);
                methodSET.invoke(certInfoObject, getSetField(certInfoObject, "SUBJECT"),
                        certificateSubjectNameObject);
            } catch (InvocationTargetException ite) {
                methodSET.invoke(certInfoObject, getSetField(certInfoObject, "SUBJECT"), x500NameObject);
            }

            // info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
            try {
                Class<?> certificateIssuerNameClass = Class.forName(getCertificateIssuerNameModuleName());
                Constructor<?> certificateIssuerNameConstr = certificateIssuerNameClass
                        .getConstructor(new Class[] { x500NameClass });
                Object certificateIssuerNameObject = certificateIssuerNameConstr.newInstance(x500NameObject);
                methodSET.invoke(certInfoObject, getSetField(certInfoObject, "ISSUER"),
                        certificateIssuerNameObject);
            } catch (InvocationTargetException ite) {
                methodSET.invoke(certInfoObject, getSetField(certInfoObject, "ISSUER"), x500NameObject);
            }

            // info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
            Class<?> certificateX509KeyClass = Class.forName(getCertificateX509KeyModuleName());
            Constructor<?> certificateX509KeyConstr = certificateX509KeyClass
                    .getConstructor(new Class[] { PublicKey.class });
            Object certificateX509KeyObject = certificateX509KeyConstr.newInstance(pair.getPublic());
            methodSET.invoke(certInfoObject, getSetField(certInfoObject, "KEY"), certificateX509KeyObject);
            // info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
            Class<?> certificateVersionClass = Class.forName(getCertificateVersionModuleName());
            Constructor<?> certificateVersionConstr = certificateVersionClass
                    .getConstructor(new Class[] { int.class });
            Constructor<?> certificateVersionConstr0 = certificateVersionClass.getConstructor();
            Object certInfoObject0 = certificateVersionConstr0.newInstance();
            Field v3IntField = certInfoObject0.getClass().getDeclaredField("V3");
            v3IntField.setAccessible(true);
            int fValue = (int) v3IntField.getInt(certInfoObject0);
            Object certificateVersionObject = certificateVersionConstr.newInstance(fValue);
            methodSET.invoke(certInfoObject, getSetField(certInfoObject, "VERSION"), certificateVersionObject);

            // AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
            Class<?> algorithmIdClass = Class.forName(getAlgorithmIdModuleName());
            Field md5WithRSAField = algorithmIdClass.getDeclaredField("md5WithRSAEncryption_oid");
            md5WithRSAField.setAccessible(true);
            Class<?> objectIdentifierClass = Class.forName(getObjectIdentifierModuleName());

            Object md5WithRSAValue = md5WithRSAField.get(algorithmIdClass);

            Constructor<?> algorithmIdConstr = algorithmIdClass
                    .getConstructor(new Class[] { objectIdentifierClass });
            Object algorithmIdObject = algorithmIdConstr.newInstance(md5WithRSAValue);

            // info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
            Class<?> certificateAlgorithmIdClass = Class.forName(getCertificateAlgorithmIdModuleName());
            Constructor<?> certificateAlgorithmIdConstr = certificateAlgorithmIdClass
                    .getConstructor(new Class[] { algorithmIdClass });
            Object certificateAlgorithmIdObject = certificateAlgorithmIdConstr.newInstance(algorithmIdObject);
            methodSET.invoke(certInfoObject, getSetField(certInfoObject, "ALGORITHM_ID"),
                    certificateAlgorithmIdObject);

            // Sign the cert to identify the algorithm that's used.
            // X509CertImpl cert = new X509CertImpl(info);
            Class<?> x509CertImplClass = Class.forName(getX509CertImplModuleName());
            Constructor<?> x509CertImplConstr = x509CertImplClass.getConstructor(new Class[] { certInfoClass });
            x509CertImplObject = x509CertImplConstr.newInstance(certInfoObject);

            // cert.sign(privkey, algorithm);
            Method methoSIGN = x509CertImplObject.getClass().getMethod("sign", PrivateKey.class, String.class);
            methoSIGN.invoke(x509CertImplObject, privkey, algorithm);

            // Update the algorith, and resign.
            // algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
            Method methoGET = x509CertImplObject.getClass().getMethod("get", String.class);
            String sig_alg = getSetField(x509CertImplObject, "SIG_ALG");

            String certAlgoIdNameValue = getSetField(certificateAlgorithmIdObject, "NAME");
            String certAlgoIdAlgoValue = getSetField(certificateAlgorithmIdObject, "ALGORITHM");
            // info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
            methodSET.invoke(certInfoObject, certAlgoIdNameValue + "." + certAlgoIdAlgoValue,
                    methoGET.invoke(x509CertImplObject, sig_alg));

            // cert = new X509CertImpl(info);
            x509CertImplObject = x509CertImplConstr.newInstance(certInfoObject);
            // cert.sign(privkey, algorithm);
            methoSIGN.invoke(x509CertImplObject, privkey, algorithm);
        } catch (Exception e) {
            LOG.failedToGenerateCertificate(e);
        }
        return (X509Certificate) x509CertImplObject;
    }

    private static String getX509CertInfoModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.X509CertInfo"
                : "sun.security.x509.X509CertInfo";
    }

    private static String getX509CertifValidityModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.CertificateValidity"
                : "sun.security.x509.CertificateValidity";
    }

    private static String getX509X500NameModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.X500Name"
                : "sun.security.x509.X500Name";
    }

    private static String getCertificateSerialNumberModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.CertificateSerialNumber"
                : "sun.security.x509.CertificateSerialNumber";
    }

    private static String getCertificateSubjectNameModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.CertificateSubjectName"
                : "sun.security.x509.CertificateSubjectName";
    }

    private static String getCertificateIssuerNameModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.CertificateIssuerName"
                : "sun.security.x509.CertificateIssuerName";
    }

    private static String getCertificateX509KeyModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.CertificateX509Key"
                : "sun.security.x509.CertificateX509Key";
    }

    private static String getCertificateVersionModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.CertificateVersion"
                : "sun.security.x509.CertificateVersion";
    }

    private static String getAlgorithmIdModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.AlgorithmId"
                : "sun.security.x509.AlgorithmId";
    }

    private static String getObjectIdentifierModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.util.ObjectIdentifier"
                : "sun.security.util.ObjectIdentifier";
    }

    private static String getCertificateAlgorithmIdModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.CertificateAlgorithmId"
                : "sun.security.x509.CertificateAlgorithmId";
    }

    private static String getX509CertImplModuleName() {
        return System.getProperty("java.vendor").contains("IBM") ? "com.ibm.security.x509.X509CertImpl"
                : "sun.security.x509.X509CertImpl";
    }

    private static String getSetField(Object obj, String setString) throws Exception {
        Field privateStringField = obj.getClass().getDeclaredField(setString);
        privateStringField.setAccessible(true);
        String fieldValue = (String) privateStringField.get(obj);
        return fieldValue;
    }

    public static void writeCertificateToFile(Certificate cert, final File file)
            throws CertificateEncodingException, IOException {
        byte[] bytes = cert.getEncoded();
        Base64 encoder = new Base64(76, "\n".getBytes("ASCII"));
        try (final FileOutputStream out = new FileOutputStream(file)) {
            out.write("-----BEGIN CERTIFICATE-----\n".getBytes("ASCII"));
            out.write(encoder.encodeToString(bytes).getBytes("ASCII"));
            out.write("-----END CERTIFICATE-----\n".getBytes("ASCII"));
        }
    }

    public static void writeCertificateToJKS(Certificate cert, final File file)
            throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

        char[] password = "changeit".toCharArray();
        ks.load(null, password);
        ks.setCertificateEntry("gateway-identity", cert);
        FileOutputStream fos = new FileOutputStream(file);
        /* Coverity Scan CID 1361992 */
        try {
            ks.store(fos, password);
        } finally {
            fos.close();
        }
    }
}