Source Code Cross Referenced for X509Factory.java in  » 6.0-JDK-Modules » j2me » sun » security » provider » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » sun.security.provider 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * @(#)X509Factory.java	1.4 06/10/10
003:         *
004:         * Copyright  1990-2006 Sun Microsystems, Inc. All Rights Reserved.  
005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER  
006:         *   
007:         * This program is free software; you can redistribute it and/or  
008:         * modify it under the terms of the GNU General Public License version  
009:         * 2 only, as published by the Free Software Foundation.   
010:         *   
011:         * This program is distributed in the hope that it will be useful, but  
012:         * WITHOUT ANY WARRANTY; without even the implied warranty of  
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  
014:         * General Public License version 2 for more details (a copy is  
015:         * included at /legal/license.txt).   
016:         *   
017:         * You should have received a copy of the GNU General Public License  
018:         * version 2 along with this work; if not, write to the Free Software  
019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  
020:         * 02110-1301 USA   
021:         *   
022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa  
023:         * Clara, CA 95054 or visit www.sun.com if you need additional  
024:         * information or have any questions. 
025:         *
026:         */
027:
028:        /*
029:         * Note that there are two versions of X509Factory, this subsetted
030:         * version for CDC/FP and another for the security optional package.
031:         * Be sure you're editing the right one!
032:         */
033:
034:        package sun.security.provider;
035:
036:        import java.io.*;
037:        import java.util.Collection;
038:        import java.util.*;
039:        import java.security.cert.*;
040:        import sun.security.x509.X509CertImpl;
041:        import sun.security.x509.X509CRLImpl;
042:        import sun.security.pkcs.PKCS7;
043:        import sun.security.provider.certpath.X509CertPath; // CDC/FP X509CertificatePair subsetted out for space savings.
044:        // import sun.security.provider.certpath.X509CertificatePair;
045:        import sun.security.util.DerValue;
046:        import sun.security.util.Cache;
047:        import sun.misc.BASE64Decoder;
048:
049:        /**
050:         * This class defines a certificate factory for X.509 v3 certificates &
051:         * certification paths, and X.509 v2 certificate revocation lists (CRLs).
052:         *
053:         * @author Jan Luehe
054:         * @author Hemma Prafullchandra
055:         * @author Sean Mullan
056:         *
057:         * @version 1.4, 10/10/06
058:         *
059:         * @see java.security.cert.CertificateFactorySpi
060:         * @see java.security.cert.Certificate
061:         * @see java.security.cert.CertPath
062:         * @see java.security.cert.CRL
063:         * @see java.security.cert.X509Certificate
064:         * @see java.security.cert.X509CRL
065:         * @see sun.security.x509.X509CertImpl
066:         * @see sun.security.x509.X509CRLImpl
067:         */
068:
069:        public class X509Factory extends CertificateFactorySpi {
070:
071:            public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
072:            public static final String END_CERT = "-----END CERTIFICATE-----";
073:
074:            private static final int defaultExpectedLineLength = 80;
075:
076:            private static final char[] endBoundary = "-----END".toCharArray();
077:
078:            private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX
079:
080:            private static final Cache certCache = Cache
081:                    .newSoftMemoryCache(750);
082:            private static final Cache crlCache = Cache.newSoftMemoryCache(750);
083:
084:            /**
085:             * Generates an X.509 certificate object and initializes it with
086:             * the data read from the input stream <code>is</code>.
087:             *
088:             * @param is an input stream with the certificate data.
089:             *
090:             * @return an X.509 certificate object initialized with the data
091:             * from the input stream.
092:             *
093:             * @exception CertificateException on parsing errors.
094:             */
095:            public Certificate engineGenerateCertificate(InputStream is)
096:                    throws CertificateException {
097:                if (is == null) {
098:                    // clear the caches (for debugging)
099:                    certCache.clear();
100:                    // CDC/FP - X509CertificatePair has been subsetted
101:                    // out to save space.
102:                    // X509CertificatePair.clearCache();
103:                    throw new CertificateException("Missing input stream");
104:                }
105:                try {
106:                    if (is.markSupported() == false) {
107:                        // consume the entire input stream
108:                        byte[] totalBytes;
109:                        totalBytes = getTotalBytes(new BufferedInputStream(is));
110:                        is = new ByteArrayInputStream(totalBytes);
111:                    }
112:                    byte[] encoding = readSequence(is);
113:                    if (encoding != null) {
114:                        X509CertImpl cert = (X509CertImpl) getFromCache(
115:                                certCache, encoding);
116:                        if (cert != null) {
117:                            return cert;
118:                        }
119:                        cert = new X509CertImpl(encoding);
120:                        addToCache(certCache, cert.getEncodedInternal(), cert);
121:                        return cert;
122:                    } else {
123:                        X509CertImpl cert;
124:                        // determine if binary or Base64 encoding. If Base64 encoding,
125:                        // the certificate must be bounded at the beginning by
126:                        // "-----BEGIN".
127:                        if (isBase64(is)) {
128:                            // Base64
129:                            byte[] data = base64_to_binary(is);
130:                            cert = new X509CertImpl(data);
131:                        } else {
132:                            // binary
133:                            cert = new X509CertImpl(new DerValue(is));
134:                        }
135:                        return intern(cert);
136:                    }
137:                } catch (IOException ioe) {
138:                    throw (CertificateException) new CertificateException(
139:                            "Could not parse certificate: " + ioe.toString())
140:                            .initCause(ioe);
141:                }
142:            }
143:
144:            /**
145:             * Read a DER SEQUENCE from an InputStream and return the encoding.
146:             * If data does not represent a SEQUENCE, it uses indefinite length
147:             * encoding, or is longer than ENC_MAX_LENGTH, the stream is reset
148:             * and this method returns null.
149:             */
150:            private static byte[] readSequence(InputStream in)
151:                    throws IOException {
152:                in.mark(ENC_MAX_LENGTH);
153:                byte[] b = new byte[4];
154:                int i = readFully(in, b, 0, b.length);
155:                if ((i != b.length) || (b[0] != 0x30)) { // first byte must be SEQUENCE
156:                    in.reset();
157:                    return null;
158:                }
159:                i = b[1] & 0xff;
160:                int totalLength;
161:                if (i < 0x80) {
162:                    int valueLength = i;
163:                    totalLength = valueLength + 2;
164:                } else if (i == 0x81) {
165:                    int valueLength = b[2] & 0xff;
166:                    totalLength = valueLength + 3;
167:                } else if (i == 0x82) {
168:                    int valueLength = ((b[2] & 0xff) << 8) | (b[3] & 0xff);
169:                    totalLength = valueLength + 4;
170:                } else { // ignore longer length forms
171:                    in.reset();
172:                    return null;
173:                }
174:                if (totalLength > ENC_MAX_LENGTH) {
175:                    in.reset();
176:                    return null;
177:                }
178:                byte[] encoding = new byte[totalLength];
179:                System.arraycopy(b, 0, encoding, 0, b.length);
180:                int n = totalLength - b.length;
181:                i = readFully(in, encoding, b.length, n);
182:                if (i != n) {
183:                    in.reset();
184:                    return null;
185:                }
186:                return encoding;
187:            }
188:
189:            /**
190:             * Read from the stream until length bytes have been read or EOF has
191:             * been reached. Return the number of bytes actually read.
192:             */
193:            private static int readFully(InputStream in, byte[] buffer,
194:                    int offset, int length) throws IOException {
195:                int read = 0;
196:                while (length > 0) {
197:                    int n = in.read(buffer, offset, length);
198:                    if (n <= 0) {
199:                        break;
200:                    }
201:                    read += n;
202:                    length -= n;
203:                    offset += n;
204:                }
205:                return read;
206:            }
207:
208:            /**
209:             * Return an interned X509CertImpl for the given certificate.
210:             * If the given X509Certificate or X509CertImpl is already present
211:             * in the cert cache, the cached object is returned. Otherwise,
212:             * if it is a X509Certificate, it is first converted to a X509CertImpl.
213:             * Then the X509CertImpl is added to the cache and returned.
214:             *
215:             * Note that all certificates created via generateCertificate(InputStream)
216:             * are already interned and this method does not need to be called.
217:             * It is useful for certificates that cannot be created via
218:             * generateCertificate() and for converting other X509Certificate 
219:             * implementations to an X509CertImpl.
220:             */
221:            public static synchronized X509CertImpl intern(X509Certificate c)
222:                    throws CertificateException {
223:                if (c == null) {
224:                    return null;
225:                }
226:                boolean isImpl = c instanceof  X509CertImpl;
227:                byte[] encoding;
228:                if (isImpl) {
229:                    encoding = ((X509CertImpl) c).getEncodedInternal();
230:                } else {
231:                    encoding = c.getEncoded();
232:                }
233:                X509CertImpl newC = (X509CertImpl) getFromCache(certCache,
234:                        encoding);
235:                if (newC != null) {
236:                    return newC;
237:                }
238:                if (isImpl) {
239:                    newC = (X509CertImpl) c;
240:                } else {
241:                    newC = new X509CertImpl(encoding);
242:                    encoding = newC.getEncodedInternal();
243:                }
244:                addToCache(certCache, encoding, newC);
245:                return newC;
246:            }
247:
248:            /**
249:             * Return an interned X509CRLImpl for the given certificate.
250:             * For more information, see intern(X509Certificate).
251:             */
252:            public static synchronized X509CRLImpl intern(X509CRL c)
253:                    throws CRLException {
254:                if (c == null) {
255:                    return null;
256:                }
257:                boolean isImpl = c instanceof  X509CRLImpl;
258:                byte[] encoding;
259:                if (isImpl) {
260:                    encoding = ((X509CRLImpl) c).getEncodedInternal();
261:                } else {
262:                    encoding = c.getEncoded();
263:                }
264:                X509CRLImpl newC = (X509CRLImpl) getFromCache(crlCache,
265:                        encoding);
266:                if (newC != null) {
267:                    return newC;
268:                }
269:                if (isImpl) {
270:                    newC = (X509CRLImpl) c;
271:                } else {
272:                    newC = new X509CRLImpl(encoding);
273:                    encoding = newC.getEncodedInternal();
274:                }
275:                addToCache(crlCache, encoding, newC);
276:                return newC;
277:            }
278:
279:            /**
280:             * Get the X509CertImpl or X509CRLImpl from the cache.
281:             */
282:            private static synchronized Object getFromCache(Cache cache,
283:                    byte[] encoding) {
284:                Object key = new Cache.EqualByteArray(encoding);
285:                Object value = cache.get(key);
286:                return value;
287:            }
288:
289:            /**
290:             * Add the X509CertImpl or X509CRLImpl to the cache.
291:             */
292:            private static synchronized void addToCache(Cache cache,
293:                    byte[] encoding, Object value) {
294:                if (encoding.length > ENC_MAX_LENGTH) {
295:                    return;
296:                }
297:                Object key = new Cache.EqualByteArray(encoding);
298:                cache.put(key, value);
299:            }
300:
301:            /**
302:             * Generates a <code>CertPath</code> object and initializes it with
303:             * the data read from the <code>InputStream</code> inStream. The data
304:             * is assumed to be in the default encoding.
305:             *
306:             * @param inStream an <code>InputStream</code> containing the data
307:             * @return a <code>CertPath</code> initialized with the data from the
308:             *   <code>InputStream</code>
309:             * @exception CertificateException if an exception occurs while decoding
310:             * @since 1.4
311:             */
312:            public CertPath engineGenerateCertPath(InputStream inStream)
313:                    throws CertificateException {
314:                if (inStream == null) {
315:                    throw new CertificateException("Missing input stream");
316:                }
317:                try {
318:                    if (inStream.markSupported() == false) {
319:                        // consume the entire input stream
320:                        byte[] totalBytes;
321:                        totalBytes = getTotalBytes(new BufferedInputStream(
322:                                inStream));
323:                        inStream = new ByteArrayInputStream(totalBytes);
324:                    }
325:                    // determine if binary or Base64 encoding. If Base64 encoding,
326:                    // each certificate must be bounded at the beginning by
327:                    // "-----BEGIN".
328:                    if (isBase64(inStream)) {
329:                        // Base64
330:                        byte[] data = base64_to_binary(inStream);
331:                        return new X509CertPath(new ByteArrayInputStream(data));
332:                    } else {
333:                        return new X509CertPath(inStream);
334:                    }
335:                } catch (IOException ioe) {
336:                    throw new CertificateException(ioe.getMessage());
337:                }
338:            }
339:
340:            /**
341:             * Generates a <code>CertPath</code> object and initializes it with
342:             * the data read from the <code>InputStream</code> inStream. The data
343:             * is assumed to be in the specified encoding.
344:             *
345:             * @param inStream an <code>InputStream</code> containing the data
346:             * @param encoding the encoding used for the data
347:             * @return a <code>CertPath</code> initialized with the data from the
348:             *   <code>InputStream</code>
349:             * @exception CertificateException if an exception occurs while decoding or
350:             *   the encoding requested is not supported
351:             * @since 1.4
352:             */
353:            public CertPath engineGenerateCertPath(InputStream inStream,
354:                    String encoding) throws CertificateException {
355:                if (inStream == null) {
356:                    throw new CertificateException("Missing input stream");
357:                }
358:                try {
359:                    if (inStream.markSupported() == false) {
360:                        // consume the entire input stream
361:                        byte[] totalBytes;
362:                        totalBytes = getTotalBytes(new BufferedInputStream(
363:                                inStream));
364:                        inStream = new ByteArrayInputStream(totalBytes);
365:                    }
366:                    // determine if binary or Base64 encoding. If Base64 encoding,
367:                    // each certificate must be bounded at the beginning by
368:                    // "-----BEGIN".
369:                    if (isBase64(inStream)) {
370:                        // Base64
371:                        byte[] data = base64_to_binary(inStream);
372:                        return new X509CertPath(new ByteArrayInputStream(data),
373:                                encoding);
374:                    } else {
375:                        return (new X509CertPath(inStream, encoding));
376:                    }
377:                } catch (IOException ioe) {
378:                    throw new CertificateException(ioe.getMessage());
379:                }
380:            }
381:
382:            /**
383:             * Generates a <code>CertPath</code> object and initializes it with
384:             * a <code>List</code> of <code>Certificate</code>s.
385:             * <p>
386:             * The certificates supplied must be of a type supported by the
387:             * <code>CertificateFactory</code>. They will be copied out of the supplied
388:             * <code>List</code> object.
389:             *
390:             * @param certificates a <code>List</code> of <code>Certificate</code>s
391:             * @return a <code>CertPath</code> initialized with the supplied list of
392:             *   certificates
393:             * @exception CertificateException if an exception occurs
394:             * @since 1.4
395:             */
396:            public CertPath engineGenerateCertPath(List certificates)
397:                    throws CertificateException {
398:                return (new X509CertPath(certificates));
399:            }
400:
401:            /**
402:             * Returns an iteration of the <code>CertPath</code> encodings supported 
403:             * by this certificate factory, with the default encoding first.
404:             * <p>
405:             * Attempts to modify the returned <code>Iterator</code> via its
406:             * <code>remove</code> method result in an
407:             * <code>UnsupportedOperationException</code>.
408:             *
409:             * @return an <code>Iterator</code> over the names of the supported
410:             *         <code>CertPath</code> encodings (as <code>String</code>s)
411:             * @since 1.4
412:             */
413:            public Iterator engineGetCertPathEncodings() {
414:                return (X509CertPath.getEncodingsStatic());
415:            }
416:
417:            /**
418:             * Returns a (possibly empty) collection view of X.509 certificates read
419:             * from the given input stream <code>is</code>.
420:             *
421:             * @param is the input stream with the certificates.
422:             *
423:             * @return a (possibly empty) collection view of X.509 certificate objects
424:             * initialized with the data from the input stream.
425:             *
426:             * @exception CertificateException on parsing errors.
427:             */
428:            public Collection engineGenerateCertificates(InputStream is)
429:                    throws CertificateException {
430:                if (is == null) {
431:                    throw new CertificateException("Missing input stream");
432:                }
433:                try {
434:                    if (is.markSupported() == false) {
435:                        // consume the entire input stream
436:                        is = new ByteArrayInputStream(
437:                                getTotalBytes(new BufferedInputStream(is)));
438:                    }
439:                    return parseX509orPKCS7Cert(is);
440:                } catch (IOException ioe) {
441:                    ioe.printStackTrace();
442:                    throw new CertificateException(ioe.getMessage());
443:                }
444:            }
445:
446:            /**
447:             * Generates an X.509 certificate revocation list (CRL) object and
448:             * initializes it with the data read from the given input stream
449:             * <code>is</code>.
450:             *
451:             * @param is an input stream with the CRL data.
452:             *
453:             * @return an X.509 CRL object initialized with the data
454:             * from the input stream.
455:             *
456:             * @exception CRLException on parsing errors.
457:             */
458:            public CRL engineGenerateCRL(InputStream is) throws CRLException {
459:                if (is == null) {
460:                    // clear the cache (for debugging)
461:                    crlCache.clear();
462:                    throw new CRLException("Missing input stream");
463:                }
464:                try {
465:                    if (is.markSupported() == false) {
466:                        // consume the entire input stream
467:                        byte[] totalBytes;
468:                        totalBytes = getTotalBytes(new BufferedInputStream(is));
469:                        is = new ByteArrayInputStream(totalBytes);
470:                    }
471:                    byte[] encoding = readSequence(is);
472:                    if (encoding != null) {
473:                        X509CRLImpl crl = (X509CRLImpl) getFromCache(crlCache,
474:                                encoding);
475:                        if (crl != null) {
476:                            return crl;
477:                        }
478:                        crl = new X509CRLImpl(encoding);
479:                        addToCache(crlCache, crl.getEncodedInternal(), crl);
480:                        return crl;
481:                    } else {
482:                        X509CRLImpl crl;
483:                        // determine if binary or Base64 encoding. If Base64 encoding,
484:                        // the CRL must be bounded at the beginning by
485:                        // "-----BEGIN".
486:                        if (isBase64(is)) {
487:                            // Base64
488:                            byte[] data = base64_to_binary(is);
489:                            crl = new X509CRLImpl(data);
490:                        } else {
491:                            // binary
492:                            crl = new X509CRLImpl(new DerValue(is));
493:                        }
494:                        return intern(crl);
495:                    }
496:                } catch (IOException ioe) {
497:                    throw new CRLException(ioe.getMessage());
498:                }
499:            }
500:
501:            /**
502:             * Returns a (possibly empty) collection view of X.509 CRLs read
503:             * from the given input stream <code>is</code>.
504:             *
505:             * @param is the input stream with the CRLs.
506:             *
507:             * @return a (possibly empty) collection view of X.509 CRL objects
508:             * initialized with the data from the input stream.
509:             *
510:             * @exception CRLException on parsing errors.
511:             */
512:            public Collection engineGenerateCRLs(InputStream is)
513:                    throws CRLException {
514:                if (is == null) {
515:                    throw new CRLException("Missing input stream");
516:                }
517:                try {
518:                    if (is.markSupported() == false) {
519:                        // consume the entire input stream
520:                        is = new ByteArrayInputStream(
521:                                getTotalBytes(new BufferedInputStream(is)));
522:                    }
523:                    return parseX509orPKCS7CRL(is);
524:                } catch (IOException ioe) {
525:                    throw new CRLException(ioe.getMessage());
526:                }
527:            }
528:
529:            /*
530:             * Parses the data in the given input stream as a sequence of DER
531:             * encoded X.509 certificates (in binary or base 64 encoded format) OR 
532:             * as a single PKCS#7 encoded blob (in binary or base64 encoded format).
533:             */
534:            private Collection parseX509orPKCS7Cert(InputStream is)
535:                    throws CertificateException, IOException {
536:                Collection coll = new ArrayList();
537:                boolean first = true;
538:                while (is.available() != 0) {
539:                    // determine if binary or Base64 encoding. If Base64 encoding,
540:                    // each certificate must be bounded at the beginning by
541:                    // "-----BEGIN".
542:                    InputStream is2 = is;
543:                    if (isBase64(is2)) {
544:                        // Base64
545:                        is2 = new ByteArrayInputStream(base64_to_binary(is2));
546:                    }
547:                    if (first)
548:                        is2.mark(is2.available());
549:                    try {
550:                        // treat as X.509 cert
551:                        coll.add(intern(new X509CertImpl(new DerValue(is2))));
552:                    } catch (CertificateException e) {
553:                        Throwable cause = e.getCause();
554:                        // only treat as PKCS#7 if this is the first cert parsed 
555:                        // and the root cause of the decoding failure is an IOException
556:                        if (first && cause != null
557:                                && (cause instanceof  IOException)) {
558:                            // treat as PKCS#7
559:                            is2.reset();
560:                            PKCS7 pkcs7 = new PKCS7(is2);
561:                            X509Certificate[] certs = pkcs7.getCertificates();
562:                            // certs are optional in PKCS #7
563:                            if (certs != null) {
564:                                return Arrays.asList(certs);
565:                            } else {
566:                                // no certs provided
567:                                return new ArrayList(0);
568:                            }
569:                        } else {
570:                            throw e;
571:                        }
572:                    }
573:                    first = false;
574:                }
575:                return coll;
576:            }
577:
578:            /*
579:             * Parses the data in the given input stream as a sequence of DER encoded
580:             * X.509 CRLs (in binary or base 64 encoded format) OR as a single PKCS#7 
581:             * encoded blob (in binary or base 64 encoded format).
582:             */
583:            private Collection parseX509orPKCS7CRL(InputStream is)
584:                    throws CRLException, IOException {
585:                Collection coll = new ArrayList();
586:                boolean first = true;
587:                while (is.available() != 0) {
588:                    // determine if binary or Base64 encoding. If Base64 encoding,
589:                    // the CRL must be bounded at the beginning by
590:                    // "-----BEGIN".
591:                    InputStream is2 = is;
592:                    if (isBase64(is)) {
593:                        // Base64
594:                        is2 = new ByteArrayInputStream(base64_to_binary(is2));
595:                    }
596:                    if (first)
597:                        is2.mark(is2.available());
598:                    try {
599:                        // treat as X.509 CRL
600:                        coll.add(new X509CRLImpl(is2));
601:                    } catch (CRLException e) {
602:                        // only treat as PKCS#7 if this is the first CRL parsed 
603:                        if (first) {
604:                            is2.reset();
605:                            PKCS7 pkcs7 = new PKCS7(is2);
606:                            X509CRL[] crls = pkcs7.getCRLs();
607:                            // CRLs are optional in PKCS #7
608:                            if (crls != null) {
609:                                return Arrays.asList(crls);
610:                            } else {
611:                                // no crls provided
612:                                return new ArrayList(0);
613:                            }
614:                        }
615:                    }
616:                    first = false;
617:                }
618:                return coll;
619:            }
620:
621:            /*
622:             * Converts a Base64-encoded X.509 certificate or X.509 CRL or PKCS#7 data
623:             * to binary encoding.
624:             * In all cases, the data must be bounded at the beginning by
625:             * "-----BEGIN", and must be bounded at the end by "-----END".
626:             */
627:            private byte[] base64_to_binary(InputStream is) throws IOException {
628:                long len = 0; // total length of base64 encoding, including boundaries
629:
630:                is.mark(is.available());
631:
632:                BufferedInputStream bufin = new BufferedInputStream(is);
633:                BufferedReader br = new BufferedReader(new InputStreamReader(
634:                        bufin));
635:
636:                // First read all of the data that is found between
637:                // the "-----BEGIN" and "-----END" boundaries into a buffer.
638:                String temp;
639:                if ((temp = readLine(br)) == null
640:                        || !temp.startsWith("-----BEGIN")) {
641:                    throw new IOException("Unsupported encoding");
642:                } else {
643:                    len += temp.length();
644:                }
645:                StringBuffer strBuf = new StringBuffer();
646:                while ((temp = readLine(br)) != null
647:                        && !temp.startsWith("-----END")) {
648:                    strBuf.append(temp);
649:                }
650:                if (temp == null) {
651:                    throw new IOException("Unsupported encoding");
652:                } else {
653:                    len += temp.length();
654:                }
655:
656:                // consume only as much as was needed
657:                len += strBuf.length();
658:                is.reset();
659:                is.skip(len);
660:
661:                // Now, that data is supposed to be a single X.509 certificate or
662:                // X.509 CRL or PKCS#7 formatted data... Base64 encoded.
663:                // Decode into binary and return the result.
664:                BASE64Decoder decoder = new BASE64Decoder();
665:                return decoder.decodeBuffer(strBuf.toString());
666:            }
667:
668:            /*
669:             * Reads the entire input stream into a byte array.
670:             */
671:            private byte[] getTotalBytes(InputStream is) throws IOException {
672:                byte[] buffer = new byte[8192];
673:                ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
674:                int n;
675:                baos.reset();
676:                while ((n = is.read(buffer, 0, buffer.length)) != -1) {
677:                    baos.write(buffer, 0, n);
678:                }
679:                return baos.toByteArray();
680:            }
681:
682:            /*
683:             * Determines if input is binary or Base64 encoded.
684:             */
685:            private boolean isBase64(InputStream is) throws IOException {
686:                if (is.available() >= 10) {
687:                    is.mark(10);
688:                    int c1 = is.read();
689:                    int c2 = is.read();
690:                    int c3 = is.read();
691:                    int c4 = is.read();
692:                    int c5 = is.read();
693:                    int c6 = is.read();
694:                    int c7 = is.read();
695:                    int c8 = is.read();
696:                    int c9 = is.read();
697:                    int c10 = is.read();
698:                    is.reset();
699:                    if (c1 == '-' && c2 == '-' && c3 == '-' && c4 == '-'
700:                            && c5 == '-' && c6 == 'B' && c7 == 'E' && c8 == 'G'
701:                            && c9 == 'I' && c10 == 'N') {
702:                        return true;
703:                    } else {
704:                        return false;
705:                    }
706:                } else {
707:                    return false;
708:                }
709:            }
710:
711:            /*
712:             * Read a line of text.  A line is considered to be terminated by any one
713:             * of a line feed ('\n'), a carriage return ('\r'), a carriage return
714:             * followed immediately by a linefeed, or an end-of-certificate marker.
715:             *
716:             * @return     A String containing the contents of the line, including
717:             *             any line-termination characters, or null if the end of the
718:             *             stream has been reached.
719:             */
720:            private String readLine(BufferedReader br) throws IOException {
721:                int c;
722:                int i = 0;
723:                boolean isMatch = true;
724:                boolean matched = false;
725:                StringBuffer sb = new StringBuffer(defaultExpectedLineLength);
726:                do {
727:                    c = br.read();
728:                    if (isMatch && (i < endBoundary.length)) {
729:                        isMatch = ((char) c != endBoundary[i++]) ? false : true;
730:                    }
731:                    if (!matched)
732:                        matched = (isMatch && (i == endBoundary.length));
733:                    sb.append((char) c);
734:                } while ((c != -1) && (c != '\n') && (c != '\r'));
735:
736:                if (!matched && c == -1) {
737:                    return null;
738:                }
739:                if (c == '\r') {
740:                    br.mark(1);
741:                    int c2 = br.read();
742:                    if (c2 == '\n') {
743:                        sb.append((char) c);
744:                    } else {
745:                        br.reset();
746:                    }
747:                }
748:                return sb.toString();
749:            }
750:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.