View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.ssl.util;
17  
18  import io.netty.util.internal.ObjectUtil;
19  import io.netty.util.internal.SuppressJava6Requirement;
20  
21  import javax.security.auth.x500.X500Principal;
22  import java.io.ByteArrayInputStream;
23  import java.math.BigInteger;
24  import java.security.InvalidKeyException;
25  import java.security.NoSuchAlgorithmException;
26  import java.security.NoSuchProviderException;
27  import java.security.Principal;
28  import java.security.Provider;
29  import java.security.PublicKey;
30  import java.security.SignatureException;
31  import java.security.cert.CertificateEncodingException;
32  import java.security.cert.CertificateException;
33  import java.security.cert.CertificateExpiredException;
34  import java.security.cert.CertificateFactory;
35  import java.security.cert.CertificateNotYetValidException;
36  import java.security.cert.CertificateParsingException;
37  import java.security.cert.X509Certificate;
38  import java.util.Collection;
39  import java.util.Date;
40  import java.util.List;
41  import java.util.Set;
42  
43  public final class LazyX509Certificate extends X509Certificate {
44  
45      static final CertificateFactory X509_CERT_FACTORY;
46      static {
47          try {
48              X509_CERT_FACTORY = CertificateFactory.getInstance("X.509");
49          } catch (CertificateException e) {
50              throw new ExceptionInInitializerError(e);
51          }
52      }
53  
54      private final byte[] bytes;
55      private X509Certificate wrapped;
56  
57      /**
58       * Creates a new instance which will lazy parse the given bytes. Be aware that the bytes will not be cloned.
59       */
60      public LazyX509Certificate(byte[] bytes) {
61          this.bytes = ObjectUtil.checkNotNull(bytes, "bytes");
62      }
63  
64      @Override
65      public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
66          unwrap().checkValidity();
67      }
68  
69      @Override
70      public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
71          unwrap().checkValidity(date);
72      }
73  
74      @Override
75      public X500Principal getIssuerX500Principal() {
76          return unwrap().getIssuerX500Principal();
77      }
78  
79      @Override
80      public X500Principal getSubjectX500Principal() {
81          return unwrap().getSubjectX500Principal();
82      }
83  
84      @Override
85      public List<String> getExtendedKeyUsage() throws CertificateParsingException {
86          return unwrap().getExtendedKeyUsage();
87      }
88  
89      @Override
90      public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
91          return unwrap().getSubjectAlternativeNames();
92      }
93  
94      @Override
95      public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
96          return unwrap().getIssuerAlternativeNames();
97      }
98  
99      // No @Override annotation as it was only introduced in Java8.
100     @SuppressJava6Requirement(reason = "Can only be called from Java8 as class is package-private")
101     public void verify(PublicKey key, Provider sigProvider)
102             throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
103         unwrap().verify(key, sigProvider);
104     }
105 
106     @Override
107     public int getVersion() {
108         return unwrap().getVersion();
109     }
110 
111     @Override
112     public BigInteger getSerialNumber() {
113         return unwrap().getSerialNumber();
114     }
115 
116     @Override
117     public Principal getIssuerDN() {
118         return unwrap().getIssuerDN();
119     }
120 
121     @Override
122     public Principal getSubjectDN() {
123         return unwrap().getSubjectDN();
124     }
125 
126     @Override
127     public Date getNotBefore() {
128         return unwrap().getNotBefore();
129     }
130 
131     @Override
132     public Date getNotAfter() {
133         return unwrap().getNotAfter();
134     }
135 
136     @Override
137     public byte[] getTBSCertificate() throws CertificateEncodingException {
138         return unwrap().getTBSCertificate();
139     }
140 
141     @Override
142     public byte[] getSignature() {
143         return unwrap().getSignature();
144     }
145 
146     @Override
147     public String getSigAlgName() {
148         return unwrap().getSigAlgName();
149     }
150 
151     @Override
152     public String getSigAlgOID() {
153         return unwrap().getSigAlgOID();
154     }
155 
156     @Override
157     public byte[] getSigAlgParams() {
158         return unwrap().getSigAlgParams();
159     }
160 
161     @Override
162     public boolean[] getIssuerUniqueID() {
163         return unwrap().getIssuerUniqueID();
164     }
165 
166     @Override
167     public boolean[] getSubjectUniqueID() {
168         return unwrap().getSubjectUniqueID();
169     }
170 
171     @Override
172     public boolean[] getKeyUsage() {
173         return unwrap().getKeyUsage();
174     }
175 
176     @Override
177     public int getBasicConstraints() {
178         return unwrap().getBasicConstraints();
179     }
180 
181     @Override
182     public byte[] getEncoded() {
183         return bytes.clone();
184     }
185 
186     @Override
187     public void verify(PublicKey key)
188             throws CertificateException, NoSuchAlgorithmException,
189             InvalidKeyException, NoSuchProviderException, SignatureException {
190         unwrap().verify(key);
191     }
192 
193     @Override
194     public void verify(PublicKey key, String sigProvider)
195             throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
196             NoSuchProviderException, SignatureException {
197         unwrap().verify(key, sigProvider);
198     }
199 
200     @Override
201     public String toString() {
202         return unwrap().toString();
203     }
204 
205     @Override
206     public PublicKey getPublicKey() {
207         return unwrap().getPublicKey();
208     }
209 
210     @Override
211     public boolean hasUnsupportedCriticalExtension() {
212         return unwrap().hasUnsupportedCriticalExtension();
213     }
214 
215     @Override
216     public Set<String> getCriticalExtensionOIDs() {
217         return unwrap().getCriticalExtensionOIDs();
218     }
219 
220     @Override
221     public Set<String> getNonCriticalExtensionOIDs() {
222         return unwrap().getNonCriticalExtensionOIDs();
223     }
224 
225     @Override
226     public byte[] getExtensionValue(String oid) {
227         return unwrap().getExtensionValue(oid);
228     }
229 
230     private X509Certificate unwrap() {
231         X509Certificate wrapped = this.wrapped;
232         if (wrapped == null) {
233             try {
234                 wrapped = this.wrapped = (X509Certificate) X509_CERT_FACTORY.generateCertificate(
235                         new ByteArrayInputStream(bytes));
236             } catch (CertificateException e) {
237                 throw new IllegalStateException(e);
238             }
239         }
240         return wrapped;
241     }
242 }