]> WPIA git - gigi.git/blob - src/club/wpia/gigi/util/CAA.java
fix: CAA records on non-existing domains
[gigi.git] / src / club / wpia / gigi / util / CAA.java
1 package club.wpia.gigi.util;
2
3 import javax.naming.NamingException;
4
5 import club.wpia.gigi.GigiApiException;
6 import club.wpia.gigi.dbObjects.CertificateOwner;
7 import club.wpia.gigi.dbObjects.CertificateProfile;
8 import club.wpia.gigi.output.template.SprintfCommand;
9
10 public class CAA {
11
12     public static class CAARecord {
13
14         private byte flags;
15
16         private String tag;
17
18         private String data;
19
20         public CAARecord(byte[] rec) {
21             byte length = (byte) (rec[1] & 0xFF);
22             tag = new String(rec, 2, length);
23             data = new String(rec, 2 + length, rec.length - 2 - length);
24             flags = rec[0];
25         }
26
27         @Override
28         public String toString() {
29             return "CAA " + (flags & 0xFF) + " " + tag + " " + data;
30         }
31
32         public String getData() {
33             return data;
34         }
35
36         public byte getFlags() {
37             return flags;
38         }
39
40         public String getTag() {
41             return tag;
42         }
43
44         public boolean isCritical() {
45             return (flags & (byte) 0x80) == (byte) 0x80;
46         }
47     }
48
49     public static boolean verifyDomainAccess(CertificateOwner owner, CertificateProfile p, String name) throws GigiApiException {
50         try {
51             if (name.startsWith("*.")) {
52                 return verifyDomainAccess(owner, p, name.substring(2), true);
53             }
54             return verifyDomainAccess(owner, p, name, false);
55         } catch (NamingException e) {
56             throw new GigiApiException(SprintfCommand.createSimple("Internal Name Server/Resolution Error: {0}", e.getMessage()));
57         }
58     }
59
60     private static boolean verifyDomainAccess(CertificateOwner owner, CertificateProfile p, String name, boolean wild) throws NamingException {
61         CAARecord[] caa = getEffectiveCAARecords(name);
62         if (caa.length == 0) {
63             return true; // default assessment is beeing granted
64         }
65         for (int i = 0; i < caa.length; i++) {
66             CAARecord r = caa[i];
67             if (r.getTag().equals("issuewild")) {
68                 if (wild && authorized(owner, p, r.getData())) {
69                     return true;
70                 }
71             } else if (r.getTag().equals("iodef")) {
72                 // TODO send mail/form
73             } else if (r.getTag().equals("issue")) {
74                 if ( !wild && authorized(owner, p, r.getData())) {
75                     return true;
76                 }
77             } else {
78                 if (r.isCritical()) {
79                     return false; // found critical, unkown entry
80                 }
81                 // ignore unkown tags
82             }
83         }
84         return false;
85     }
86
87     private static CAARecord[] getEffectiveCAARecords(String name) throws NamingException {
88         CAARecord[] caa = DNSUtil.getCAAEntries(name);
89         String publicSuffix = PublicSuffixes.getInstance().getRegistrablePart(name);
90         if (name.equals(publicSuffix)) {
91             return caa;
92         }
93         // TODO missing alias processing
94         while (caa.length == 0 && name.contains(".")) {
95             name = name.split("\\.", 2)[1];
96             caa = DNSUtil.getCAAEntries(name);
97             if (name.equals(publicSuffix)) {
98                 return caa;
99             }
100         }
101         return caa;
102     }
103
104     private static boolean authorized(CertificateOwner owner, CertificateProfile p, String data) {
105         String[] parts = data.split(";");
106         String ca = parts[0].trim();
107         if ( !ca.equals(SystemKeywords.CAA_NAME)) {
108             return false;
109         }
110         for (int i = 1; i < parts.length; i++) {
111             String[] pa = parts[i].split("=");
112             String key = pa[0].trim();
113             String v = pa[1].trim();
114             if (key.equals("account")) {
115                 int id = Integer.parseInt(v);
116                 if (id != owner.getId()) {
117                     return false;
118                 }
119             } else { // unknown key... be conservative
120                 return false;
121             }
122         }
123         return true;
124     }
125
126 }