1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util.ssl;
20
21 import java.security.cert.CertificateParsingException;
22 import java.security.cert.X509Certificate;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28
29 import javax.naming.InvalidNameException;
30 import javax.naming.ldap.LdapName;
31 import javax.naming.ldap.Rdn;
32 import javax.security.auth.x500.X500Principal;
33
34 import org.eclipse.jetty.util.StringUtil;
35 import org.eclipse.jetty.util.log.Log;
36 import org.eclipse.jetty.util.log.Logger;
37
38 public class X509
39 {
40 private static final Logger LOG = Log.getLogger(X509.class);
41
42
43
44
45 private static final int KEY_USAGE__KEY_CERT_SIGN=5;
46
47
48
49
50
51 private static final int SUBJECT_ALTERNATIVE_NAMES__DNS_NAME=2;
52
53 public static boolean isCertSign(X509Certificate x509)
54 {
55 boolean[] key_usage=x509.getKeyUsage();
56 return key_usage!=null && key_usage[KEY_USAGE__KEY_CERT_SIGN];
57 }
58
59 private final X509Certificate _x509;
60 private final String _alias;
61 private final List<String> _hosts=new ArrayList<>();
62 private final List<String> _wilds=new ArrayList<>();
63
64 public X509(String alias,X509Certificate x509) throws CertificateParsingException, InvalidNameException
65 {
66 _alias=alias;
67 _x509 = x509;
68
69
70 boolean named=false;
71 Collection<List<?>> altNames = x509.getSubjectAlternativeNames();
72 if (altNames!=null)
73 {
74 for (List<?> list : altNames)
75 {
76 if (((Number)list.get(0)).intValue() == SUBJECT_ALTERNATIVE_NAMES__DNS_NAME)
77 {
78 String cn = list.get(1).toString();
79 if (LOG.isDebugEnabled())
80 LOG.debug("Certificate SAN alias={} CN={} in {}",alias,cn,this);
81 if (cn!=null)
82 {
83 named=true;
84 addName(cn);
85 }
86 }
87 }
88 }
89
90
91 if (!named)
92 {
93 LdapName name=new LdapName(x509.getSubjectX500Principal().getName(X500Principal.RFC2253));
94 for (Rdn rdn : name.getRdns())
95 {
96 if (rdn.getType().equalsIgnoreCase("CN"))
97 {
98 String cn = rdn.getValue().toString();
99 if (LOG.isDebugEnabled())
100 LOG.debug("Certificate CN alias={} CN={} in {}",alias,cn,this);
101 if (cn!=null && cn.contains(".") && !cn.contains(" "))
102 addName(cn);
103 }
104 }
105 }
106 }
107
108 protected void addName(String cn)
109 {
110 cn=StringUtil.asciiToLowerCase(cn);
111 if (cn.startsWith("*."))
112 _wilds.add(cn.substring(2));
113 else
114 _hosts.add(cn);
115 }
116
117 public String getAlias()
118 {
119 return _alias;
120 }
121
122 public X509Certificate getCertificate()
123 {
124 return _x509;
125 }
126
127 public Set<String> getHosts()
128 {
129 return new HashSet<>(_hosts);
130 }
131
132 public Set<String> getWilds()
133 {
134 return new HashSet<>(_wilds);
135 }
136
137 public boolean matches(String host)
138 {
139 host=StringUtil.asciiToLowerCase(host);
140 if (_hosts.contains(host) || _wilds.contains(host))
141 return true;
142
143 int dot = host.indexOf('.');
144 if (dot>=0)
145 {
146 String domain=host.substring(dot+1);
147 if (_wilds.contains(domain))
148 return true;
149 }
150 return false;
151 }
152
153 @Override
154 public String toString()
155 {
156 return String.format("%s@%x(%s,h=%s,w=%s)",
157 getClass().getSimpleName(),
158 hashCode(),
159 _alias,
160 _hosts,
161 _wilds);
162 }
163 }