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.netty5.handler.ssl.util;
17  
18  import javax.security.auth.x500.X500Principal;
19  import java.io.ByteArrayInputStream;
20  import java.math.BigInteger;
21  import java.security.InvalidKeyException;
22  import java.security.NoSuchAlgorithmException;
23  import java.security.NoSuchProviderException;
24  import java.security.Principal;
25  import java.security.Provider;
26  import java.security.PublicKey;
27  import java.security.SignatureException;
28  import java.security.cert.CertificateEncodingException;
29  import java.security.cert.CertificateException;
30  import java.security.cert.CertificateExpiredException;
31  import java.security.cert.CertificateFactory;
32  import java.security.cert.CertificateNotYetValidException;
33  import java.security.cert.CertificateParsingException;
34  import java.security.cert.X509Certificate;
35  import java.util.Collection;
36  import java.util.Date;
37  import java.util.List;
38  import java.util.Set;
39  
40  import static java.util.Objects.requireNonNull;
41  
42  public final class LazyX509Certificate extends X509Certificate {
43  
44      static final CertificateFactory X509_CERT_FACTORY;
45      static {
46          try {
47              X509_CERT_FACTORY = CertificateFactory.getInstance("X.509");
48          } catch (CertificateException e) {
49              throw new ExceptionInInitializerError(e);
50          }
51      }
52  
53      private final byte[] bytes;
54      private X509Certificate wrapped;
55  
56      /**
57       * Creates a new instance which will lazy parse the given bytes. Be aware that the bytes will not be cloned.
58       */
59      public LazyX509Certificate(byte[] bytes) {
60          this.bytes = requireNonNull(bytes, "bytes");
61      }
62  
63      @Override
64      public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
65          unwrap().checkValidity();
66      }
67  
68      @Override
69      public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
70          unwrap().checkValidity(date);
71      }
72  
73      @Override
74      public X500Principal getIssuerX500Principal() {
75          return unwrap().getIssuerX500Principal();
76      }
77  
78      @Override
79      public X500Principal getSubjectX500Principal() {
80          return unwrap().getSubjectX500Principal();
81      }
82  
83      @Override
84      public List<String> getExtendedKeyUsage() throws CertificateParsingException {
85          return unwrap().getExtendedKeyUsage();
86      }
87  
88      @Override
89      public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
90          return unwrap().getSubjectAlternativeNames();
91      }
92  
93      @Override
94      public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
95          return unwrap().getSubjectAlternativeNames();
96      }
97  
98      // No @Override annotation as it was only introduced in Java8.
99      @Override
100     public void verify(PublicKey key, Provider sigProvider)
101             throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
102         unwrap().verify(key, sigProvider);
103     }
104 
105     @Override
106     public int getVersion() {
107         return unwrap().getVersion();
108     }
109 
110     @Override
111     public BigInteger getSerialNumber() {
112         return unwrap().getSerialNumber();
113     }
114 
115     @Override
116     public Principal getIssuerDN() {
117         return unwrap().getIssuerDN();
118     }
119 
120     @Override
121     public Principal getSubjectDN() {
122         return unwrap().getSubjectDN();
123     }
124 
125     @Override
126     public Date getNotBefore() {
127         return unwrap().getNotBefore();
128     }
129 
130     @Override
131     public Date getNotAfter() {
132         return unwrap().getNotAfter();
133     }
134 
135     @Override
136     public byte[] getTBSCertificate() throws CertificateEncodingException {
137         return unwrap().getTBSCertificate();
138     }
139 
140     @Override
141     public byte[] getSignature() {
142         return unwrap().getSignature();
143     }
144 
145     @Override
146     public String getSigAlgName() {
147         return unwrap().getSigAlgName();
148     }
149 
150     @Override
151     public String getSigAlgOID() {
152         return unwrap().getSigAlgOID();
153     }
154 
155     @Override
156     public byte[] getSigAlgParams() {
157         return unwrap().getSigAlgParams();
158     }
159 
160     @Override
161     public boolean[] getIssuerUniqueID() {
162         return unwrap().getIssuerUniqueID();
163     }
164 
165     @Override
166     public boolean[] getSubjectUniqueID() {
167         return unwrap().getSubjectUniqueID();
168     }
169 
170     @Override
171     public boolean[] getKeyUsage() {
172         return unwrap().getKeyUsage();
173     }
174 
175     @Override
176     public int getBasicConstraints() {
177         return unwrap().getBasicConstraints();
178     }
179 
180     @Override
181     public byte[] getEncoded() {
182         return bytes.clone();
183     }
184 
185     @Override
186     public void verify(PublicKey key)
187             throws CertificateException, NoSuchAlgorithmException,
188             InvalidKeyException, NoSuchProviderException, SignatureException {
189         unwrap().verify(key);
190     }
191 
192     @Override
193     public void verify(PublicKey key, String sigProvider)
194             throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
195             NoSuchProviderException, SignatureException {
196         unwrap().verify(key, sigProvider);
197     }
198 
199     @Override
200     public String toString() {
201         return unwrap().toString();
202     }
203 
204     @Override
205     public PublicKey getPublicKey() {
206         return unwrap().getPublicKey();
207     }
208 
209     @Override
210     public boolean hasUnsupportedCriticalExtension() {
211         return unwrap().hasUnsupportedCriticalExtension();
212     }
213 
214     @Override
215     public Set<String> getCriticalExtensionOIDs() {
216         return unwrap().getCriticalExtensionOIDs();
217     }
218 
219     @Override
220     public Set<String> getNonCriticalExtensionOIDs() {
221         return unwrap().getNonCriticalExtensionOIDs();
222     }
223 
224     @Override
225     public byte[] getExtensionValue(String oid) {
226         return unwrap().getExtensionValue(oid);
227     }
228 
229     private X509Certificate unwrap() {
230         X509Certificate wrapped = this.wrapped;
231         if (wrapped == null) {
232             try {
233                 wrapped = this.wrapped = (X509Certificate) X509_CERT_FACTORY.generateCertificate(
234                         new ByteArrayInputStream(bytes));
235             } catch (CertificateException e) {
236                 throw new IllegalStateException(e);
237             }
238         }
239         return wrapped;
240     }
241 }