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