org.digidoc4j.X509Cert.java Source code

Java tutorial

Introduction

Here is the source code for org.digidoc4j.X509Cert.java

Source

/* DigiDoc4J library
*
* This software is released under either the GNU Library General Public
* License (see LICENSE.LGPL).
*
* Note that the only valid version of the LGPL license as far as this
* project is concerned is the original GNU Library General Public License
* Version 2.1, February 1999
*/

package org.digidoc4j;

import org.apache.commons.lang.StringUtils;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * Wrapper for java.security.cert.X509Certificate object.
 */
public class X509Cert implements Serializable {
    private static final Logger logger = LoggerFactory.getLogger(X509Cert.class);
    private X509Certificate originalCert;
    private Map<String, String> issuerPartMap;
    private Map<String, String> subjectNamePartMap;

    /**
     * Key usage.
     */
    public enum KeyUsage {
        DIGITAL_SIGNATURE,
        /**
         * Used for signing certificate selection in the current library
         */
        NON_REPUDIATION, KEY_ENCIPHERMENT, DATA_ENCIPHERMENT, KEY_AGREEMENT, KEY_CERTIFICATESIGN, CRL_SIGN, ENCIPHER_ONLY, DECIPHER_ONLY
    }

    /**
     * Issuer parts.
     */
    public enum Issuer {
        EMAILADDRESS, C, O, CN
    }

    /**
     * Subject Name parts.
     */
    public enum SubjectName {
        SERIALNUMBER, GIVENNAME, SURNAME, CN, OU, O, C
    }

    /**
     * Creates a copy of the X509Certificate.
     *
     * @param cert X509 certificate to be wrapped
     */
    public X509Cert(X509Certificate cert) {
        logger.debug("");
        originalCert = cert;
    }

    /**
     * Creates an X509 certificate from a path.
     *
     * @param path X509 certificate path
     * @throws Exception throws an exception if the X509 certificate parsing fails
     */
    X509Cert(String path) throws CertificateException, IOException {
        logger.debug("");
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        try (FileInputStream inStream = new FileInputStream(new File(path))) {
            originalCert = (X509Certificate) certificateFactory.generateCertificate(inStream);
        }
        logger.debug("Certificate created from path: " + path);
    }

    /**
     * Returns current certificate policies or null if no policies was found.
     *
     * @return list of policies
     * @throws IOException when policy parsing fails
     */
    public List<String> getCertificatePolicies() throws IOException {
        logger.debug("");
        byte[] extensionValue = originalCert.getExtensionValue("2.5.29.32");
        List<String> policies = new ArrayList<>();

        byte[] octets = ((DEROctetString) DEROctetString.fromByteArray(extensionValue)).getOctets();
        ASN1Sequence sequence = (ASN1Sequence) ASN1Sequence.fromByteArray(octets);

        Enumeration sequenceObjects = sequence.getObjects();
        while (sequenceObjects.hasMoreElements()) {
            DLSequence next = (DLSequence) sequenceObjects.nextElement();
            Object objectAt = next.getObjectAt(0);
            if (objectAt != null) {
                policies.add(objectAt.toString());
            }
        }
        return policies;
    }

    /**
     * Returns the internal X509 Certificate of the certificate.
     *
     * @return X509Certificate
     */
    public X509Certificate getX509Certificate() {
        logger.debug("");
        return originalCert;
    }

    /**
     * Retrieves part of the issuer name (for example if set to CN it returns the Common Name part).
     *
     * @param part sets part of issuer name to return
     * @return part of issuer name
     */
    public String issuerName(Issuer part) {
        logger.debug("Part: " + part);
        if (issuerPartMap == null) {
            loadIssuerParts();
        }
        String issuerName = issuerPartMap.get(part.name());
        logger.debug("Issuer name: " + issuerName);
        return issuerName;
    }

    private void loadIssuerParts() {
        logger.debug("");
        String[] parts = StringUtils.split(issuerName(), ',');
        issuerPartMap = new HashMap<>();
        for (String part : parts) {
            String[] strings = StringUtils.split(part, "=");
            String key = strings[0].trim();
            String value = strings[1].trim();
            issuerPartMap.put(key, value);
            logger.debug("Subject name part key: " + key + " value: " + value);
        }
    }

    /**
     * Reads the the whole issuer name from the X.509 certificate.
     *
     * @return issuer name
     */
    public String issuerName() {
        logger.debug("");
        String name = originalCert.getIssuerDN().getName();
        logger.debug("Issuer name: " + name);
        return name;
    }

    /**
     * Validates if the certificate is in a valid time slot.
     *
     * @param date sets date to compare
     * @return boolean indicating if the certificate is in a valid time slot
     */
    public boolean isValid(Date date) {
        logger.debug("Date: " + date);
        try {
            originalCert.checkValidity(date);
        } catch (CertificateExpiredException e) {
            logger.debug("Date " + date + " is not valid");
            return false;
        } catch (CertificateNotYetValidException e) {
            logger.debug("Date " + date + " is not valid");
            return false;
        }
        logger.debug("Date " + date + " is valid");
        return true;
    }

    /**
     * Validates if the current time is between the certificate's validity start date and expiration date.
     *
     * @return boolean indicating if the current time is between the certificate's validity start and expiration date
     */
    public boolean isValid() {
        logger.debug("");
        return (isValid(new Date()));
    }

    /**
     * Returns the current certificate key usage.
     *
     * @return list of key usages
     */
    public List<KeyUsage> getKeyUsages() {
        logger.debug("");
        List<KeyUsage> keyUsages = new ArrayList<>();
        boolean[] keyUsagesBits = originalCert.getKeyUsage();
        for (int i = 0; i < keyUsagesBits.length; i++) {
            if (keyUsagesBits[i]) {
                keyUsages.add(KeyUsage.values()[i]);
            }
        }

        logger.debug("Returning " + keyUsages.size() + "key usages:");
        for (KeyUsage keyUsage : keyUsages) {
            logger.debug("\t" + keyUsage.toString());
        }

        return keyUsages;
    }

    /**
     * Reads serial number from X.509 certificate.
     *
     * @return serial number of the X.509 certificate
     */
    public String getSerial() {
        logger.debug("");
        String serial = Hex.toHexString(originalCert.getSerialNumber().toByteArray());
        logger.debug("Serial number: " + serial);
        return serial;
    }

    /**
     * Returns part of the subject name (for example if set to CN it returns the Common Name part).
     *
     * @param part sets part of subject name to return
     * @return subject name
     */
    public String getSubjectName(SubjectName part) {
        logger.debug("Part: " + part);
        if (subjectNamePartMap == null) {
            loadSubjectNameParts();
        }
        String subjectName = subjectNamePartMap.get(part.name());
        logger.debug("Subject name: " + subjectName);
        return subjectName;
    }

    private void loadSubjectNameParts() {
        logger.debug("");
        String[] parts = getSubjectName().split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
        subjectNamePartMap = new HashMap<>();
        for (String part : parts) {
            String[] strings = part.split("=(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
            String key = strings[0].trim();
            String value = strings[1].trim();
            subjectNamePartMap.put(key, value);
            logger.debug("Subject name part key: " + key + " value: " + value);
        }
    }

    /**
     * Returns the whole subject name.
     *
     * @return subject name
     */
    public String getSubjectName() {
        logger.debug("");
        String subjectName = originalCert.getSubjectX500Principal().toString();
        logger.debug("Subject name: " + subjectName);
        return subjectName;
    }
}