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