7100b55708918777bd33f4fb83826ce467878ccd
[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         // TODO missing alias processing
91         while (caa.length == 0 && name.contains(".")) {
92             name = name.split("\\.", 2)[1];
93             caa = DNSUtil.getCAAEntries(name);
94             if (name.equals(publicSuffix)) {
95                 return caa;
96             }
97         }
98         return caa;
99     }
100
101     private static boolean authorized(CertificateOwner owner, CertificateProfile p, String data) {
102         String[] parts = data.split(";");
103         String ca = parts[0].trim();
104         if ( !ca.equals(SystemKeywords.CAA_NAME)) {
105             return false;
106         }
107         for (int i = 1; i < parts.length; i++) {
108             String[] pa = parts[i].split("=");
109             String key = pa[0].trim();
110             String v = pa[1].trim();
111             if (key.equals("account")) {
112                 int id = Integer.parseInt(v);
113                 if (id != owner.getId()) {
114                     return false;
115                 }
116             } else { // unknown key... be conservative
117                 return false;
118             }
119         }
120         return true;
121     }
122
123 }