    001    /**
    002     *
    003     */
    004    package com.skype.util;
    005
    006    import java.io.BufferedReader;
    007    import java.io.ByteArrayInputStream;
    008    import java.io.ByteArrayOutputStream;
    009    import java.io.File;
    010    import java.io.FileInputStream;
    011    import java.io.FileNotFoundException;
    012    import java.io.IOException;
    013    import java.io.InputStream;
    014    import java.io.InputStreamReader;
    015    import java.security.KeyFactory;
    016    import java.security.NoSuchAlgorithmException;
    017    import java.security.PrivateKey;
    018    import java.security.cert.CertificateException;
    019    import java.security.cert.CertificateFactory;
    020    import java.security.cert.X509Certificate;
    021    import java.security.spec.InvalidKeySpecException;
    022    import java.security.spec.PKCS8EncodedKeySpec;
    023
    024    /**
    025     * Minimal utilities for reading and decoding PEM certificate files
    026     *
    027     * @author kcjones
    028     *
    029     */
    030    public class PemReader
    031    {
    032
    033        private static final String TAG          = "PemReader";
    034        private static final String certStart    = "-----BEGIN CERTIFICATE-----";
    035        private static final String certEnd      = "-----END CERTIFICATE-----";
    036        private InputStream         certInStream = null;
    037        private InputStream         keyInStream  = null;
    038
    039        public PemReader(InputStream cert, InputStream key)
    040        {
    041            certInStream = cert;
    042            keyInStream = key;
    043        }
    044
    045        public PemReader(String pemFilePath) throws FileNotFoundException
    046        {
    047            File file = new File(pemFilePath);
    048
    049            certInStream = new FileInputStream(file);
    050
    051            assert (pemFilePath.endsWith("pem"));
    052            String derPath = pemFilePath.substring(0, pemFilePath.length() - 3);
    053            derPath += "der";
    054
    055            file = new File(derPath);
    056            Log.d(TAG, "file length:" + file.length());
    057
    058            keyInStream = new FileInputStream(file);
    059        }
    060
    061        public X509Certificate getCertificate() throws IOException, InvalidKeySpecException
    062        {
    063            if (certInStream == null)
    064                throw new IOException("No certification source specified");
    065
    066            StringBuffer contents = new StringBuffer();
    067
    068            try {
    069                BufferedReader reader = new BufferedReader(new InputStreamReader(certInStream));
    070                String text;
    071                while ((text = reader.readLine()) != null) {
    072                    contents.append(text).append(
    073                            System.getProperty("line.separator"));
    074                }
    075
    076                // find and parse certificate
    077                int ci = contents.indexOf(certStart);
    078                int cf = contents.indexOf(certEnd) + certEnd.length();
    079                if (!(ci >= 0 && cf > ci))
    080                    throw new InvalidKeySpecException(
    081                            "Missing or malformed certificate data.");
    082
    083                String certString = contents.substring(ci, cf);
    084                certInStream = new ByteArrayInputStream(certString.getBytes());
    085
    086                CertificateFactory cfac = CertificateFactory.getInstance("X.509");
    087                return (X509Certificate) cfac.generateCertificate(certInStream);
    088            }
    089            catch (CertificateException e) {
    090                throw new IOException("Invalid certificate in PEM file: " + e.getMessage());
    091            }
    092        }
    093
    094        public PrivateKey getKey() throws IOException
    095        {
    096
    097            if (keyInStream == null)
    098                throw new IOException("No private key source specified");
    099
    100            try {
    101                ByteArrayOutputStream baos = new ByteArrayOutputStream();
    102                int bite;
    103                while ((bite = keyInStream.read()) != -1) {
    104                    baos.write(bite);
    105                }
    106
    107                byte[] encodedKey = baos.toByteArray();
    108
    109                PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedKey);
    110
    111                KeyFactory factory = KeyFactory.getInstance("RSA");
    112                return factory.generatePrivate(spec);
    113            }
    114            catch (IndexOutOfBoundsException e) {
    115                throw new IOException("Invalid private key source");
    116            }
    117            catch (InvalidKeySpecException e) {
    118                throw new IOException("Invalid private key in DER file: " + e.getMessage());
    119            }
    120            catch (NoSuchAlgorithmException e) {
    121                // I'll be damned. No RSA? I don't believe it.
    122                e.printStackTrace();
    123                System.exit(1);
    124            }
    125            return null;
    126        }
    127    }