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

com.dropbox.maven.pem_converter.PemLoader Maven / Gradle / Ivy

package com.dropbox.maven.pem_converter;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Reader;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;

/**
 * Loads a PEM X.509 certificate file.  Basically just parses it and base64-decodes the data.
 */
public class PemLoader
{
    public static byte[][] load(Reader in)
        throws IOException, LoadException
    {
        return load(Utils.createX509CertificateFactory(), in);
    }

    public static byte[][] load(CertificateFactory certFactory, Reader in)
        throws IOException, LoadException
    {
        HashSet aliases = new HashSet();
        ArrayList raw = new ArrayList();
        LineReader lin = new LineReader(in);
        try {
            while (true) {
                String line = lin.readLine();
                if (line == null) break;
                String trimmed = line.trim();
                if (trimmed.startsWith("#")) continue;  // Skip comment lines.
                if (trimmed.length() == 0) continue;    // Skip empty lines.
                if (!line.equals("-----BEGIN CERTIFICATE-----")) {
                    throw new LoadException("Expecting \"-----BEGIN CERTIFICATE-----\", blank line, or comment line starting with \"#\", got \"" + line + "\"");
                }
                int certStartLine = lin.getLastLineNumber();
                byte[] certData = loadCertData(lin, certStartLine);
                X509Certificate certificate;
                try {
                    certificate = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(certData));
                }
                catch (CertificateException ex) {
                    throw new LoadException(certStartLine, "unable to load cert: " + ex.getMessage());
                }
                String alias = certificate.getSubjectX500Principal().getName();
                boolean added = aliases.add(alias);
                if (!added) {
                    throw new LoadException(certStartLine, "duplicate cert alias: \"" + alias + "\"");
                }
                if (certData.length > Utils.MaxCertLength) {
                    throw new LoadException(certStartLine, "cert data too long: " + certData.length + " bytes (max: " + Utils.MaxCertLength + " bytes)");
                }
                raw.add(certData);
            }
        }
        catch (LoadException ex) {
            // If there's no line number in the exception, this will add one in.
            ex.addLineNumber(lin.getLastLineNumber());
            throw ex;
        }
        return raw.toArray(new byte[raw.size()][]);
    }

    private static byte[] loadCertData(LineReader in, int certStartLine)
            throws IOException, LoadException
    {
        StringBuilder base64 = new StringBuilder();
        while (true) {
            String line = in.readLine();
            if (line == null) {
                throw new LoadException("No end found for cert beginning on line " + certStartLine);
            }
            if (line.startsWith("-")) {
                String endMarker = "-----END CERTIFICATE-----";
                if (!line.equals(endMarker)) {
                    throw new LoadException("Expecting \"" + endMarker + "\" or valid base-64 data, got \"" + line + "\"");
                }
                try {
                    return javax.xml.bind.DatatypeConverter.parseBase64Binary(base64.toString());
                }
                catch (IllegalArgumentException ex) {
                    throw new LoadException(certStartLine, "Invalid base-64 in cert data block: " + ex.getMessage());
                }
            }
            else {
                base64.append(line);
            }
        }
    }

    public static final class LoadException extends Exception
    {
        private final int lineNumber;

        public LoadException(String msg)
        {
            super(msg);
            this.lineNumber = -1;
        }

        public LoadException(int lineNumber, String msg)
        {
            super("line " + lineNumber + ": " + msg);
            this.lineNumber = lineNumber;
        }

        public LoadException addLineNumber(int lineNumber)
        {
            if (this.lineNumber >= 0) return this;
            return new LoadException(lineNumber, this.getMessage());
        }
    }

    public static final class LineReader
    {
        private final BufferedReader in;
        private int lastLineNumber;

        public LineReader(Reader in)
        {
            this.in = new BufferedReader(in);
            this.lastLineNumber = 0;
        }

        public String readLine()
            throws IOException
        {
            String line = in.readLine();
            if (line == null) return null;
            lastLineNumber++;
            return line;
        }

        private int getLastLineNumber()
        {
            return lastLineNumber;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy