1 /*
2  * @(#) $Id: FileBasedRepository.java,v 1.2 2003/07/08 08:13:52 pankaj Exp $
3  *
4  * Copyright (c) 2002-03 by Pankaj Kumar (http://www.pankaj-k.net). 
5  * All rights reserved.
6  *
7  * The license governing the use of this file can be found in the 
8  * root directory of the containing software.
9  */
10package org.jstk.cert.rep;
11
12import java.util.Collection;
13import java.util.ArrayList;
14import java.util.Iterator;
15import java.security.cert.Certificate;
16import java.security.cert.X509Certificate;
17import java.security.cert.X509CRL;
18import java.security.cert.CertificateFactory;
19import java.io.File;
20import java.io.InputStream;
21import java.io.FileInputStream;
22import java.io.BufferedInputStream;
23import java.io.ByteArrayInputStream;
24import java.io.OutputStream;
25import java.io.FileOutputStream;
26import java.io.BufferedOutputStream;
27
28import java.io.IOException;
29import java.io.EOFException;
30
31public class FileBasedRepository {
32    private static class FBRInput {
33        private InputStream is;
34        private int off;
35
36        public FBRInput(InputStream is){
37            this.is = is;
38            off = 0;
39        }
40
41        public int getOffset(){
42            return off;
43        }
44
45        public byte readByte() throws IOException {
46            int b = is.read();
47            if (b == -1)
48                throw new EOFException();
49            off += 1;
50            return (byte)b;
51        }
52
53        public int readInt() throws IOException {
54            int b1 = is.read();
55            int b2 = is.read();
56            int b3 = is.read();
57            int b4 = is.read();
58            if ((b1 | b2 | b3 | b4) < 0)    // Encountered EOF
59                throw new EOFException();
60            off += 4;
61            return ((b1 << 24) + (b2 << 16) + (b3 << 8) + (b4 << 0));
62        }
63
64        public byte[] readBytes(int len) throws IOException {
65            if (len < 0)
66                throw new IOException("Negative no. of bytes to read");
67            byte[] data = new byte[len];
68            int nRead = 0;
69            while (nRead < len){
70                int n = is.read(data, nRead, len - nRead);
71                if (n == -1)
72                    throw new EOFException();
73                nRead += n;
74                off += n;
75            }
76            return data;
77        }
78        public X509Certificate readX509Certificate() throws Exception {
79            int len = readInt();
80            byte[] data = readBytes(len);
81
82            CertificateFactory cf = CertificateFactory.getInstance("X.509");
83            ByteArrayInputStream bais = new ByteArrayInputStream(data);
84            X509Certificate cert = (X509Certificate)cf.generateCertificate(bais);
85            return cert;
86        }
87        public X509CRL readX509CRL() throws Exception {
88            int len = readInt();
89            byte[] data = readBytes(len);
90
91            CertificateFactory cf = CertificateFactory.getInstance("X.509");
92            ByteArrayInputStream bais = new ByteArrayInputStream(data);
93            X509CRL crl = (X509CRL)cf.generateCRL(bais);
94            return crl;
95        }
96    }
97
98    private static class FBROutput {
99        private OutputStream os;
00        private int off;
01
02        public FBROutput(OutputStream os){
03            this.os = os;
04            off = 0;
05        }
06
07        public int getOffset(){
08            return off;
09        }
10
11        public void writeByte(byte b) throws IOException {
12            os.write(b);
13            this.off += 1;
14        }
15
16        public void writeInt(int v) throws IOException {
17            os.write((v >>> 24) & 0xFF);
18            os.write((v >>> 16) & 0xFF);
19            os.write((v >>>  8) & 0xFF);
20            os.write((v >>>  0) & 0xFF);
21            off += 4;
22        }
23
24        public void writeBytes(byte[] data, int off, int len) throws IOException {
25            os.write(data, off, len);
26            this.off += len;
27        }
28
29        public void writeX509Certificate(X509Certificate cert) throws Exception {
30            byte[] data = cert.getEncoded();
31            writeInt(data.length);
32            writeBytes(data, 0, data.length);
33        }
34        public void writeX509CRL(X509CRL crl) throws Exception {
35            byte[] data = crl.getEncoded();
36            writeInt(data.length);
37            writeBytes(data, 0, data.length);
38        }
39    }
40
41    public static final int FBREP_MAGIC = 15071968;
42    public static final byte X509CERT = 0x01;
43    public static final byte X509CRL = 0x02;
44    public static final byte FBREP_END = 0x00;
45
46    private String filename = null;
47    private ArrayList list = new ArrayList();
48    public FileBasedRepository(String filename) throws Exception {
49        this.filename = filename;
50        File file = new File(filename);
51        if (!file.exists()){    // Create an empty repository;
52            save();
53        }
54        load();
55    }
56    public Collection getRepository(){
57        return list;
58    }
59    public synchronized void load() throws Exception {
60        FileInputStream fis = new FileInputStream(filename);
61        FBRInput fbrInput = new FBRInput(fis);
62        int magicNo = fbrInput.readInt();
63        if (magicNo != FBREP_MAGIC)
64            throw new IOException("Not a File Based Repository");
65
66        list = new ArrayList();
67        boolean scanComplete = false;
68        while (!scanComplete){
69            byte entryId = fbrInput.readByte();
70            switch (entryId){
71                case X509CERT:
72                    X509Certificate cert = fbrInput.readX509Certificate();
73                    list.add(cert);
74                    break;
75                case X509CRL:
76                    X509CRL crl = fbrInput.readX509CRL();
77                    list.add(crl);
78                    break;
79                case FBREP_END:
80                    scanComplete = true;
81                    break;
82                default:
83                    throw new IOException("Unexpected Data at offset = " + fbrInput.getOffset());
84            }
85        }
86
87    }
88    public synchronized void save() throws Exception {
89        FileOutputStream fos = new FileOutputStream(filename);
90        FBROutput fbrOutput = new FBROutput(fos);
91        fbrOutput.writeInt(FBREP_MAGIC);
92        Iterator itr = list.iterator();
93        while (itr.hasNext()){
94            Object entry = itr.next();
95            if (entry instanceof X509Certificate){
96                fbrOutput.writeByte(X509CERT);
97                fbrOutput.writeX509Certificate((X509Certificate)entry);
98            } else if (entry instanceof X509CRL){
99                fbrOutput.writeByte(X509CRL);
00                fbrOutput.writeX509CRL((X509CRL)entry);
01            }
02        }
03        fbrOutput.writeByte(FBREP_END);
04    }
05
06    public static void main(String[] args) throws Exception {
07        if (args.length != 1){
08            System.out.println("Usage:: java FileBasedRepository <filename>");
09            return;
10        }
11        FileBasedRepository fbr = new FileBasedRepository(args[0]);
12    }
13}
14
15