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