001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.util.jce.provider;
019    
020    import java.io.ByteArrayOutputStream;
021    import java.io.IOException;
022    import java.math.BigInteger;
023    import java.security.InvalidKeyException;
024    import java.security.NoSuchAlgorithmException;
025    import java.security.NoSuchProviderException;
026    import java.security.Principal;
027    import java.security.Provider;
028    import java.security.PublicKey;
029    import java.security.Security;
030    import java.security.Signature;
031    import java.security.SignatureException;
032    import java.security.cert.CRLException;
033    import java.security.cert.Certificate;
034    import java.security.cert.X509CRL;
035    import java.security.cert.X509CRLEntry;
036    import java.security.cert.X509Certificate;
037    import java.util.Date;
038    import java.util.Enumeration;
039    import java.util.HashSet;
040    import java.util.Set;
041    
042    import javax.security.auth.x500.X500Principal;
043    
044    import org.apache.geronimo.util.asn1.ASN1OutputStream;
045    import org.apache.geronimo.util.asn1.DERObjectIdentifier;
046    import org.apache.geronimo.util.asn1.DEROutputStream;
047    import org.apache.geronimo.util.asn1.x509.CertificateList;
048    import org.apache.geronimo.util.asn1.x509.TBSCertList;
049    import org.apache.geronimo.util.asn1.x509.X509Extension;
050    import org.apache.geronimo.util.asn1.x509.X509Extensions;
051    import org.apache.geronimo.util.jce.X509Principal;
052    
053    /**
054     * The following extensions are listed in RFC 2459 as relevant to CRLs
055     *
056     * Authority Key Identifier
057     * Issuer Alternative Name
058     * CRL Number
059     * Delta CRL Indicator (critical)
060     * Issuing Distribution Point (critical)
061     */
062    public class X509CRLObject
063        extends X509CRL
064    {
065        private CertificateList c;
066    
067        public X509CRLObject(
068            CertificateList c)
069        {
070            this.c = c;
071        }
072    
073        /**
074         * Will return true if any extensions are present and marked
075         * as critical as we currently dont handle any extensions!
076         */
077        public boolean hasUnsupportedCriticalExtension()
078        {
079            Set extns = getCriticalExtensionOIDs();
080            if ( extns != null && !extns.isEmpty() )
081            {
082                return true;
083            }
084    
085            return false;
086        }
087    
088        private Set getExtensionOIDs(boolean critical)
089        {
090            if (this.getVersion() == 2)
091            {
092                HashSet         set = new HashSet();
093                X509Extensions  extensions = c.getTBSCertList().getExtensions();
094                Enumeration     e = extensions.oids();
095    
096                while (e.hasMoreElements())
097                {
098                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
099                    X509Extension       ext = extensions.getExtension(oid);
100    
101                    if (critical == ext.isCritical())
102                    {
103                        set.add(oid.getId());
104                    }
105                }
106    
107                return set;
108            }
109    
110            return null;
111        }
112    
113        public Set getCriticalExtensionOIDs()
114        {
115            return getExtensionOIDs(true);
116        }
117    
118        public Set getNonCriticalExtensionOIDs()
119        {
120            return getExtensionOIDs(false);
121        }
122    
123        public byte[] getExtensionValue(String oid)
124        {
125            X509Extensions exts = c.getTBSCertList().getExtensions();
126    
127            if (exts != null)
128            {
129                X509Extension   ext = exts.getExtension(new DERObjectIdentifier(oid));
130    
131                if (ext != null)
132                {
133                    ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
134                    DEROutputStream dOut = new DEROutputStream(bOut);
135    
136                    try
137                    {
138                        dOut.writeObject(ext.getValue());
139    
140                        return bOut.toByteArray();
141                    }
142                    catch (Exception e)
143                    {
144                        throw new RuntimeException("error encoding " + e.getMessage(), e);
145                    }
146                }
147            }
148    
149            return null;
150        }
151    
152        public byte[] getEncoded()
153            throws CRLException
154        {
155            ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
156            DEROutputStream            dOut = new DEROutputStream(bOut);
157    
158            try
159            {
160                dOut.writeObject(c);
161    
162                return bOut.toByteArray();
163            }
164            catch (IOException e)
165            {
166                throw (CRLException)new CRLException(e.getMessage()).initCause(e);
167            }
168        }
169    
170        public void verify(PublicKey key)
171            throws CRLException,  NoSuchAlgorithmException,
172            InvalidKeyException, NoSuchProviderException,
173            SignatureException
174        {
175            verify(key, "BC");
176        }
177    
178        public void verify(PublicKey key, String sigProvider)
179            throws CRLException, NoSuchAlgorithmException,
180            InvalidKeyException, NoSuchProviderException,
181            SignatureException
182        {
183            if ( !c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()) )
184            {
185                throw new CRLException("Signature algorithm on CertifcateList does not match TBSCertList.");
186            }
187    
188            Signature sig = Signature.getInstance(getSigAlgName(), sigProvider);
189    
190            sig.initVerify(key);
191            sig.update(this.getTBSCertList());
192            if ( !sig.verify(this.getSignature()) )
193            {
194                throw new SignatureException("CRL does not verify with supplied public key.");
195            }
196        }
197    
198        public int getVersion()
199        {
200            return c.getVersion();
201        }
202    
203        public Principal getIssuerDN()
204        {
205            return new X509Principal(c.getIssuer());
206        }
207    
208        public X500Principal getIssuerX500Principal()
209        {
210            try
211            {
212                ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
213                ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
214    
215                aOut.writeObject(c.getIssuer());
216    
217                return new X500Principal(bOut.toByteArray());
218            }
219            catch (IOException e)
220            {
221                throw new IllegalStateException("can't encode issuer DN", e);
222            }
223        }
224    
225        public Date getThisUpdate()
226        {
227            return c.getThisUpdate().getDate();
228        }
229    
230        public Date getNextUpdate()
231        {
232            if (c.getNextUpdate() != null)
233            {
234                return c.getNextUpdate().getDate();
235            }
236    
237            return null;
238        }
239    
240        public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
241        {
242            TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
243    
244            if ( certs != null )
245            {
246                for ( int i = 0; i < certs.length; i++ )
247                {
248                    if ( certs[i].getUserCertificate().getValue().equals(serialNumber) ) {
249                        return new X509CRLEntryObject(certs[i]);
250                    }
251                }
252            }
253    
254            return null;
255        }
256    
257        public Set getRevokedCertificates()
258        {
259            TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
260    
261            if ( certs != null )
262            {
263                HashSet set = new HashSet();
264                for ( int i = 0; i < certs.length; i++ )
265                {
266                    set.add(new X509CRLEntryObject(certs[i]));
267    
268                }
269    
270                return set;
271            }
272    
273            return null;
274        }
275    
276        public byte[] getTBSCertList()
277            throws CRLException
278        {
279            ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
280            DEROutputStream            dOut = new DEROutputStream(bOut);
281    
282            try
283            {
284                dOut.writeObject(c.getTBSCertList());
285    
286                return bOut.toByteArray();
287            }
288            catch (IOException e)
289            {
290                throw (CRLException)new CRLException(e.getMessage()).initCause(e);
291            }
292        }
293    
294        public byte[] getSignature()
295        {
296            return c.getSignature().getBytes();
297        }
298    
299        public String getSigAlgName()
300        {
301            Provider[] provs = Security.getProviders();
302    
303            //
304            // search every provider looking for a real algorithm
305            //
306            for (int i = 0; i != provs.length; i++)
307            {
308                String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
309                if ( algName != null )
310                {
311                    return algName;
312                }
313            }
314    
315            return this.getSigAlgOID();
316        }
317    
318        public String getSigAlgOID()
319        {
320            return c.getSignatureAlgorithm().getObjectId().getId();
321        }
322    
323        public byte[] getSigAlgParams()
324        {
325            ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
326    
327            if ( c.getSignatureAlgorithm().getParameters() != null )
328            {
329                try
330                {
331                    DEROutputStream    dOut = new DEROutputStream(bOut);
332    
333                    dOut.writeObject(c.getSignatureAlgorithm().getParameters());
334                }
335                catch (Exception e)
336                {
337                    throw new RuntimeException("exception getting sig parameters " + e.getMessage(), e);
338                }
339    
340                return bOut.toByteArray();
341            }
342    
343            return null;
344        }
345    
346        /**
347         * Returns a string representation of this CRL.
348         *
349         * @return a string representation of this CRL.
350         */
351        public String toString()
352        {
353            return "X.509 CRL";
354        }
355    
356        /**
357         * Checks whether the given certificate is on this CRL.
358         *
359         * @param cert the certificate to check for.
360         * @return true if the given certificate is on this CRL,
361         * false otherwise.
362         */
363        public boolean isRevoked(Certificate cert)
364        {
365            if ( !cert.getType().equals("X.509") )
366            {
367                throw new RuntimeException("X.509 CRL used with non X.509 Cert");
368            }
369    
370            TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
371    
372            if ( certs != null )
373            {
374                BigInteger serial = ((X509Certificate)cert).getSerialNumber();
375    
376                for ( int i = 0; i < certs.length; i++ )
377                {
378                    if ( certs[i].getUserCertificate().getValue().equals(serial) )
379                    {
380                        return true;
381                    }
382                }
383            }
384    
385            return false;
386        }
387    }
388