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