]> WPIA git - gigi.git/blob - src/org/cacert/gigi/dbObjects/CACertificate.java
ADD: root structure awareness.
[gigi.git] / src / org / cacert / gigi / dbObjects / CACertificate.java
1 package org.cacert.gigi.dbObjects;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.FileNotFoundException;
6 import java.security.GeneralSecurityException;
7 import java.security.cert.CertificateException;
8 import java.security.cert.CertificateFactory;
9 import java.security.cert.X509Certificate;
10 import java.util.ArrayDeque;
11 import java.util.Deque;
12 import java.util.HashMap;
13
14 import javax.security.auth.x500.X500Principal;
15
16 import org.cacert.gigi.database.DatabaseConnection;
17 import org.cacert.gigi.database.GigiPreparedStatement;
18 import org.cacert.gigi.database.GigiResultSet;
19
20 public class CACertificate implements IdCachable {
21
22     final String keyname;
23
24     final int id;
25
26     CACertificate parent = null;
27
28     final X509Certificate cert;
29
30     final String link;
31
32     private CACertificate(int id) {
33         this.id = id;
34         GigiPreparedStatement conn = DatabaseConnection.getInstance().prepare("SELECT keyname, parentRoot, link FROM cacerts WHERE id = ?");
35         conn.setInt(1, id);
36         GigiResultSet res = conn.executeQuery();
37         if ( !res.next()) {
38             throw new IllegalArgumentException();
39         }
40         keyname = res.getString("keyname");
41         link = res.getString("link");
42         int parentRoot = res.getInt("parentRoot");
43         if (res.next()) {
44             throw new RuntimeException("DB is broken");
45         }
46         if (parentRoot == id) {
47             parent = this;
48         } else {
49             parent = getById(parentRoot);
50         }
51         try {
52             FileInputStream fis = new FileInputStream("config/ca/" + keyname + ".crt");
53             CertificateFactory cf = CertificateFactory.getInstance("X509");
54             cert = (X509Certificate) cf.generateCertificate(fis);
55         } catch (FileNotFoundException e) {
56             throw new Error(e);
57         } catch (GeneralSecurityException e) {
58             throw new Error(e);
59         }
60     }
61
62     public CACertificate getParent() {
63         return parent;
64     }
65
66     public X509Certificate getCertificate() {
67         return cert;
68     }
69
70     @Override
71     public String toString() {
72         return "CACertificate: " + keyname;
73     }
74
75     static {
76         try {
77             update();
78         } catch (CertificateException e) {
79             throw new Error(e);
80         } catch (FileNotFoundException e) {
81             throw new Error(e);
82         }
83     }
84
85     private static void update() throws CertificateException, FileNotFoundException {
86         File scandir = new File("config/ca");
87         CertificateFactory xf = CertificateFactory.getInstance("X509");
88         HashMap<X500Principal, X509Certificate> map = new HashMap<>();
89         HashMap<X500Principal, String> names = new HashMap<>();
90         for (File f : scandir.listFiles()) {
91             X509Certificate cert = (X509Certificate) xf.generateCertificate(new FileInputStream(f));
92             X500Principal princip = cert.getSubjectX500Principal();
93             map.put(princip, cert);
94             String name = f.getName();
95             names.put(princip, name.substring(0, name.length() - 4));
96         }
97         HashMap<X500Principal, Integer> inserted = new HashMap<>();
98         for (X509Certificate i : map.values()) {
99             if (inserted.containsKey(i.getSubjectX500Principal())) {
100                 continue;
101             }
102             Deque<X509Certificate> toInserts = new ArrayDeque<>();
103             toInserts.add(i);
104             while ( !inserted.containsKey(i.getIssuerX500Principal()) && !i.getIssuerX500Principal().equals(i.getSubjectX500Principal())) {
105                 i = map.get(i.getIssuerX500Principal());
106                 toInserts.addFirst(i);
107             }
108             for (X509Certificate toInsert : toInserts) {
109
110                 X500Principal subj = toInsert.getSubjectX500Principal();
111                 boolean self = toInsert.getIssuerX500Principal().equals(subj);
112                 GigiPreparedStatement q = DatabaseConnection.getInstance().prepare("SELECT id, parentRoot FROM cacerts WHERE keyname=?");
113                 q.setString(1, names.get(subj));
114                 GigiResultSet res = q.executeQuery();
115                 int id;
116                 if (res.next()) {
117                     id = res.getInt("id");
118                     if (res.getInt("parentRoot") != (self ? id : inserted.get(toInsert.getIssuerX500Principal()))) {
119                         throw new Error("Invalid DB structure: " + subj + "->" + inserted.get(toInsert.getIssuerX500Principal()) + " vs " + res.getInt("parentRoot"));
120                     }
121                 } else {
122                     String link;
123                     String keyname = names.get(subj);
124                     if ( !keyname.contains("_")) {
125                         link = "http://g2.crt.cacert.org/g2/" + keyname + ".crt";
126                     } else {
127                         String[] parts = keyname.split("_");
128                         link = "http://g2.crt.cacert.org/g2/" + parts[1] + "/" + parts[0] + "-" + parts[2] + ".crt";
129
130                     }
131                     GigiPreparedStatement q2 = DatabaseConnection.getInstance().prepare("INSERT INTO cacerts SET parentRoot=?, keyname=?, link=?");
132                     q2.setInt(1, self ? 0 : inserted.get(toInsert.getIssuerX500Principal()));
133                     q2.setString(2, keyname);
134                     q2.setString(3, link);
135                     q2.execute();
136                     id = q2.lastInsertId();
137                     if (self) {
138                         GigiPreparedStatement q3 = DatabaseConnection.getInstance().prepare("UPDATE cacerts SET parentRoot=?, id=?");
139                         q3.setInt(1, id);
140                         q3.setInt(2, id);
141                         q3.execute();
142                     }
143                 }
144                 inserted.put(subj, id);
145             }
146         }
147     }
148
149     @Override
150     public int getId() {
151         return id;
152     }
153
154     private static ObjectCache<CACertificate> myCache = new ObjectCache<>();
155
156     public String getKeyname() {
157         return keyname;
158     }
159
160     public String getLink() {
161         return link;
162     }
163
164     public static synchronized CACertificate getById(int id) throws IllegalArgumentException {
165         CACertificate em = myCache.get(id);
166         if (em == null) {
167             myCache.put(em = new CACertificate(id));
168         }
169         return em;
170     }
171
172     public boolean isSelfsigned() {
173         return this == getParent();
174     }
175 }