Source Code Cross Referenced for CertTools.java in  » Authentication-Authorization » ejbca » org » ejbca » util » 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 » Authentication Authorization » ejbca » org.ejbca.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*************************************************************************
0002:         *                                                                       *
0003:         *  EJBCA: The OpenSource Certificate Authority                          *
0004:         *                                                                       *
0005:         *  This software is free software; you can redistribute it and/or       *
0006:         *  modify it under the terms of the GNU Lesser General Public           *
0007:         *  License as published by the Free Software Foundation; either         *
0008:         *  version 2.1 of the License, or any later version.                    *
0009:         *                                                                       *
0010:         *  See terms of license at gnu.org.                                     *
0011:         *                                                                       *
0012:         *************************************************************************/package org.ejbca.util;
0013:
0014:        import java.io.BufferedReader;
0015:        import java.io.ByteArrayInputStream;
0016:        import java.io.ByteArrayOutputStream;
0017:        import java.io.FileInputStream;
0018:        import java.io.IOException;
0019:        import java.io.InputStream;
0020:        import java.io.InputStreamReader;
0021:        import java.io.PrintStream;
0022:        import java.math.BigInteger;
0023:        import java.net.URL;
0024:        import java.security.InvalidKeyException;
0025:        import java.security.MessageDigest;
0026:        import java.security.NoSuchAlgorithmException;
0027:        import java.security.NoSuchProviderException;
0028:        import java.security.PrivateKey;
0029:        import java.security.Provider;
0030:        import java.security.PublicKey;
0031:        import java.security.SecureRandom;
0032:        import java.security.Security;
0033:        import java.security.SignatureException;
0034:        import java.security.cert.CRLException;
0035:        import java.security.cert.Certificate;
0036:        import java.security.cert.CertificateEncodingException;
0037:        import java.security.cert.CertificateException;
0038:        import java.security.cert.CertificateFactory;
0039:        import java.security.cert.CertificateParsingException;
0040:        import java.security.cert.X509CRL;
0041:        import java.security.cert.X509Certificate;
0042:        import java.security.interfaces.RSAPublicKey;
0043:        import java.util.ArrayList;
0044:        import java.util.Collection;
0045:        import java.util.Date;
0046:        import java.util.Hashtable;
0047:        import java.util.Iterator;
0048:        import java.util.List;
0049:        import java.util.Vector;
0050:
0051:        import org.apache.commons.lang.BooleanUtils;
0052:        import org.apache.commons.lang.StringUtils;
0053:        import org.apache.log4j.Logger;
0054:        import org.bouncycastle.asn1.ASN1EncodableVector;
0055:        import org.bouncycastle.asn1.ASN1InputStream;
0056:        import org.bouncycastle.asn1.ASN1OctetString;
0057:        import org.bouncycastle.asn1.ASN1Sequence;
0058:        import org.bouncycastle.asn1.ASN1TaggedObject;
0059:        import org.bouncycastle.asn1.DERBitString;
0060:        import org.bouncycastle.asn1.DEREncodable;
0061:        import org.bouncycastle.asn1.DERIA5String;
0062:        import org.bouncycastle.asn1.DERObject;
0063:        import org.bouncycastle.asn1.DERObjectIdentifier;
0064:        import org.bouncycastle.asn1.DEROctetString;
0065:        import org.bouncycastle.asn1.DERSequence;
0066:        import org.bouncycastle.asn1.DERTaggedObject;
0067:        import org.bouncycastle.asn1.DERUTF8String;
0068:        import org.bouncycastle.asn1.x509.AccessDescription;
0069:        import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
0070:        import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
0071:        import org.bouncycastle.asn1.x509.BasicConstraints;
0072:        import org.bouncycastle.asn1.x509.GeneralName;
0073:        import org.bouncycastle.asn1.x509.GeneralNames;
0074:        import org.bouncycastle.asn1.x509.PolicyInformation;
0075:        import org.bouncycastle.asn1.x509.ReasonFlags;
0076:        import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
0077:        import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
0078:        import org.bouncycastle.asn1.x509.X509DefaultEntryConverter;
0079:        import org.bouncycastle.asn1.x509.X509Extension;
0080:        import org.bouncycastle.asn1.x509.X509Extensions;
0081:        import org.bouncycastle.asn1.x509.X509Name;
0082:        import org.bouncycastle.asn1.x509.X509NameEntryConverter;
0083:        import org.bouncycastle.asn1.x509.X509NameTokenizer;
0084:        import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
0085:        import org.bouncycastle.jce.X509KeyUsage;
0086:        import org.bouncycastle.jce.interfaces.ConfigurableProvider;
0087:        import org.bouncycastle.jce.provider.BouncyCastleProvider;
0088:        import org.bouncycastle.math.ec.ECCurve;
0089:        import org.bouncycastle.util.encoders.Hex;
0090:        import org.bouncycastle.x509.X509V3CertificateGenerator;
0091:        import org.ejbca.core.model.ca.catoken.CATokenInfo;
0092:        import org.ejbca.core.model.ca.crl.RevokedCertInfo;
0093:        import org.ejbca.util.dn.DNFieldExtractor;
0094:        import org.ejbca.util.dn.DnComponents;
0095:
0096:        /**
0097:         * Tools to handle common certificate operations.
0098:         *
0099:         * @version $Id: CertTools.java,v 1.54 2008/03/14 16:55:36 anatom Exp $
0100:         */
0101:        public class CertTools {
0102:            private static Logger log = Logger.getLogger(CertTools.class);
0103:
0104:            // Initialize dnComponents
0105:            static {
0106:                DnComponents.getDnObjects();
0107:            }
0108:            public static final String EMAIL = "rfc822name";
0109:            public static final String EMAIL1 = "email";
0110:            public static final String EMAIL2 = "EmailAddress";
0111:            public static final String EMAIL3 = "E";
0112:            public static final String DNS = "dNSName";
0113:            public static final String URI = "uniformResourceIdentifier";
0114:            public static final String URI1 = "uri";
0115:            public static final String URI2 = "uniformResourceId";
0116:            public static final String IPADDR = "iPAddress";
0117:            public static final String DIRECTORYNAME = "directoryName";
0118:
0119:            /** Microsoft altName for windows smart card logon */
0120:            public static final String UPN = "upn";
0121:            /** ObjectID for upn altName for windows smart card logon */
0122:            public static final String UPN_OBJECTID = "1.3.6.1.4.1.311.20.2.3";
0123:            /** Microsoft altName for windows domain controller guid */
0124:            public static final String GUID = "guid";
0125:            /** ObjectID for upn altName for windows domain controller guid */
0126:            public static final String GUID_OBJECTID = "1.3.6.1.4.1.311.25.1";
0127:            /** ObjectID for Mircosoft Encrypted File System Certificates */
0128:            public static final String EFS_OBJECTID = "1.3.6.1.4.1.311.10.3.4";
0129:            /** ObjectID for Mircosoft Encrypted File System Recovery Certificates */
0130:            public static final String EFSR_OBJECTID = "1.3.6.1.4.1.311.10.3.4.1";
0131:            /** Object id id-pkix */
0132:            public static final String id_pkix = "1.3.6.1.5.5.7";
0133:            /** Object id id-kp */
0134:            public static final String id_kp = id_pkix + ".3";
0135:            /** Object id id-pda */
0136:            public static final String id_pda = id_pkix + ".9";
0137:            /** Object id id-pda-dateOfBirth 
0138:             * DateOfBirth ::= GeneralizedTime
0139:             */
0140:            public static final String id_pda_dateOfBirth = id_pda + ".1";
0141:            /** Object id id-pda-placeOfBirth 
0142:             * PlaceOfBirth ::= DirectoryString 
0143:             */
0144:            public static final String id_pda_placeOfBirth = id_pda + ".2";
0145:            /** Object id id-pda-gender
0146:             *  Gender ::= PrintableString (SIZE(1))
0147:             *          -- "M", "F", "m" or "f"
0148:             */
0149:            public static final String id_pda_gender = id_pda + ".3";
0150:            /** Object id id-pda-countryOfCitizenship
0151:             * CountryOfCitizenship ::= PrintableString (SIZE (2))
0152:             *                      -- ISO 3166 Country Code 
0153:             */
0154:            public static final String id_pda_countryOfCitizenship = id_pda
0155:                    + ".4";
0156:            /** Object id id-pda-countryOfResidence
0157:             * CountryOfResidence ::= PrintableString (SIZE (2))
0158:             *                    -- ISO 3166 Country Code 
0159:             */
0160:            public static final String id_pda_countryOfResidence = id_pda
0161:                    + ".5";
0162:            /** OID used for creating MS Templates certificate extension */
0163:            public static final String OID_MSTEMPLATE = "1.3.6.1.4.1.311.20.2";
0164:            /** New OID for ipsec (rfc4945), replaces old deprecated id_kp_ipsecEndSystem, id_kp_ipsecTunnel and id_kp_ipsecUser */
0165:            public static final String id_kp_ipsecIKE = id_kp + ".17";
0166:            /** OIDs for SCVP (rfc5055) */
0167:            public static final String id_kp_scvpServer = id_kp + ".15";
0168:            public static final String id_kp_scvpClient = id_kp + ".16";
0169:
0170:            private static final String[] EMAILIDS = { EMAIL, EMAIL1, EMAIL2,
0171:                    EMAIL3 };
0172:            /** ObjectID for unstructuredName DN attribute */
0173:            //public static final DERObjectIdentifier unstructuredName = new DERObjectIdentifier("1.2.840.113549.1.9.2");
0174:            /** ObjectID for unstructuredAddress DN attribute */
0175:            //public static final DERObjectIdentifier unstructuredAddress = new DERObjectIdentifier("1.2.840.113549.1.9.8");
0176:            /** Parameters used when generating or verifying ECDSA keys/certs using the "implicitlyCA" key encoding.
0177:             * The curve parameters is then defined outside of the key and configured in the BC provider.
0178:             */
0179:            private static String IMPLICITLYCA_Q = "@ecdsa.implicitlyca.q@";
0180:            private static String IMPLICITLYCA_A = "@ecdsa.implicitlyca.a@";
0181:            private static String IMPLICITLYCA_B = "@ecdsa.implicitlyca.b@";
0182:            private static String IMPLICITLYCA_G = "@ecdsa.implicitlyca.g@";
0183:            private static String IMPLICITLYCA_N = "@ecdsa.implicitlyca.n@";
0184:
0185:            /** System provider used to circumvent a bug in Glassfish. Should only be used by 
0186:             * X509CAInfo, OCSPCAService, XKMSCAService, CMSCAService. 
0187:             * Defaults to SUN but can be changed to IBM by the installBCProvider method.
0188:             */
0189:            public static String SYSTEM_SECURITY_PROVIDER = "SUN";
0190:
0191:            /** Flag indicating if the BC provider should be removed before installing it again. When developing and re-deploying alot
0192:             * this is needed so you don't have to restart JBoss all the time. 
0193:             * In production it may cause failures because the BC provider may get removed just when another thread wants to use it.
0194:             * Therefore the default value is false. 
0195:             */
0196:            private static final boolean developmentProviderInstallation = BooleanUtils
0197:                    .toBoolean("@development.provider.installation@");
0198:
0199:            /**
0200:             * inhibits creation of new CertTools
0201:             */
0202:            protected CertTools() {
0203:            }
0204:
0205:            /** See stringToBcX509Name(String, X509NameEntryConverter), this method uses the default BC converter (X509DefaultEntryConverter)
0206:             * @see #stringToBcX509Name(String, X509NameEntryConverter)
0207:             * @param dn String containing DN that will be transformed into X509Name, The
0208:             *          DN string has the format "CN=zz,OU=yy,O=foo,C=SE". Unknown OIDs in
0209:             *          the string will be added to the end positions of OID array.
0210:             * 
0211:             * @return X509Name or null if input is null
0212:             */
0213:            public static X509Name stringToBcX509Name(String dn) {
0214:                X509NameEntryConverter converter = new X509DefaultEntryConverter();
0215:                return stringToBcX509Name(dn, converter);
0216:            }
0217:
0218:            /**
0219:             * Creates a (Bouncycastle) X509Name object from a string with a DN. Known OID
0220:             * (with order) are:
0221:             * <code> EmailAddress, UID, CN, SN (SerialNumber), GivenName, Initials, SurName, T, OU,
0222:             * O, L, ST, DC, C </code>
0223:             * To change order edit 'dnObjects' in this source file. Important NOT to mess
0224:             * with the ordering within this class, since cert vierification on some
0225:             * clients (IE :-() might depend on order.
0226:             * 
0227:             * @param dn
0228:             *          String containing DN that will be transformed into X509Name, The
0229:             *          DN string has the format "CN=zz,OU=yy,O=foo,C=SE". Unknown OIDs in
0230:             *          the string will be added to the end positions of OID array.
0231:             * @param converter BC converter for DirectoryStrings, that determines which encoding is chosen
0232:             * @return X509Name or null if input is null
0233:             */
0234:            private static X509Name stringToBcX509Name(String dn,
0235:                    X509NameEntryConverter converter) {
0236:                return stringToBcX509Name(dn, converter,
0237:                        getDefaultX509FieldOrder());
0238:            }
0239:
0240:            public static X509Name stringToBcX509Name(String dn,
0241:                    X509NameEntryConverter converter, Vector dnOrder) {
0242:                //log.debug(">stringToBcX509Name: " + dn);
0243:                if (dn == null)
0244:                    return null;
0245:
0246:                Vector defaultOrdering = new Vector();
0247:                Vector values = new Vector();
0248:                X509NameTokenizer xt = new X509NameTokenizer(dn);
0249:
0250:                while (xt.hasMoreTokens()) {
0251:                    // This is a pair key=val (CN=xx)
0252:                    String pair = xt.nextToken();
0253:                    int ix = pair.indexOf("=");
0254:
0255:                    if (ix != -1) {
0256:                        String key = pair.substring(0, ix).toLowerCase().trim();
0257:                        String val = pair.substring(ix + 1);
0258:                        if (val != null) {
0259:                            // String whitespace from the beginning of the value, to handle the case
0260:                            // where someone type CN = Foo Bar
0261:                            val = StringUtils.stripStart(val, null);
0262:                        }
0263:
0264:                        // -- First search the OID by name in declared OID's
0265:                        DERObjectIdentifier oid = DnComponents.getOid(key);
0266:
0267:                        try {
0268:                            // -- If isn't declared, we try to create it
0269:                            if (oid == null) {
0270:                                oid = new DERObjectIdentifier(key);
0271:                            }
0272:                            defaultOrdering.add(oid);
0273:                            values.add(val);
0274:                        } catch (IllegalArgumentException e) {
0275:                            // If it is not an OID we will ignore it
0276:                            log
0277:                                    .warn("Unknown DN component ignored and silently dropped: "
0278:                                            + key);
0279:                        }
0280:
0281:                    } else {
0282:                        log.warn("Huh, what's this? DN: " + dn + " PAIR: "
0283:                                + pair);
0284:                    }
0285:                }
0286:
0287:                X509Name x509Name = new X509Name(defaultOrdering, values,
0288:                        converter);
0289:
0290:                //-- Reorder fields
0291:                X509Name orderedX509Name = getOrderedX509Name(x509Name,
0292:                        dnOrder, converter);
0293:
0294:                //log.debug("<stringToBcX509Name");
0295:                return orderedX509Name;
0296:            } // stringToBcX509Name
0297:
0298:            /**
0299:             * Every DN-string should look the same. Creates a name string ordered and looking like we want
0300:             * it...
0301:             *
0302:             * @param dn String containing DN
0303:             *
0304:             * @return String containing DN, or null if input is null
0305:             */
0306:            public static String stringToBCDNString(String dn) {
0307:                //log.debug(">stringToBcDNString: "+dn);
0308:                if (isDNReversed(dn)) {
0309:                    dn = reverseDN(dn);
0310:                }
0311:                String ret = null;
0312:                X509Name name = stringToBcX509Name(dn);
0313:                if (name != null) {
0314:                    ret = name.toString();
0315:                }
0316:                // For some databases (MySQL for instance) the database column holding subjectDN
0317:                // is only 250 chars long. There have been strange error reported (clipping DN natuarally)
0318:                // that is hard to debug if DN is more than 250 chars and we don't have a good message
0319:                if ((ret != null) && (ret.length() > 250)) {
0320:                    log
0321:                            .info("Warning! DN is more than 250 characters long. Some databases have only 250 characters in the database for SubjectDN. Clipping may occur! DN ("
0322:                                    + ret.length() + " chars): " + ret);
0323:                }
0324:                //log.debug("<stringToBcDNString: "+ret);
0325:                return ret;
0326:            }
0327:
0328:            /**
0329:             * Convenience method for getting an email addresses from a DN. Uses {@link
0330:             * getPartsFromDN(String,String)} internally, and searches for {@link EMAIL}, {@link EMAIL1},
0331:             * {@link EMAIL2}, {@link EMAIL3} and returns the first one found.
0332:             *
0333:             * @param dn the DN
0334:             *
0335:             * @return ArrayList containing email or empty list if email is not present
0336:             * @return the found email address, or <code>null</code> if none is found
0337:             */
0338:            public static ArrayList getEmailFromDN(String dn) {
0339:                log.debug(">getEmailFromDN(" + dn + ")");
0340:                ArrayList ret = new ArrayList();
0341:                for (int i = 0; i < EMAILIDS.length; i++) {
0342:                    ArrayList emails = getPartsFromDN(dn, EMAILIDS[i]);
0343:                    if (emails.size() > 0) {
0344:                        ret.addAll(emails);
0345:                    }
0346:
0347:                }
0348:                log.debug("<getEmailFromDN(" + dn + "): " + ret.size());
0349:                return ret;
0350:            }
0351:
0352:            /**
0353:             * Search for e-mail address, first in SubjectAltName (as in PKIX
0354:             * recomandation) then in subject DN.
0355:             * Original author: Marco Ferrante, (c) 2005 CSITA - University of Genoa (Italy)
0356:             * 
0357:             * @param certificate
0358:             * @return subject email or null if not present in certificate
0359:             */
0360:            public static String getEMailAddress(X509Certificate certificate) {
0361:                log.debug("Searching for EMail Address in SubjectAltName");
0362:                if (certificate == null) {
0363:                    return null;
0364:                }
0365:                try {
0366:                    if (certificate.getSubjectAlternativeNames() != null) {
0367:                        java.util.Collection altNames = certificate
0368:                                .getSubjectAlternativeNames();
0369:                        Iterator iter = altNames.iterator();
0370:                        while (iter.hasNext()) {
0371:                            java.util.List item = (java.util.List) iter.next();
0372:                            Integer type = (Integer) item.get(0);
0373:                            if (type.intValue() == 1) {
0374:                                return (String) item.get(1);
0375:                            }
0376:                        }
0377:                    }
0378:                } catch (CertificateParsingException e) {
0379:                    log.error("Error parsing certificate: ", e);
0380:                }
0381:                log.debug("Searching for EMail Address in Subject DN");
0382:                ArrayList emails = CertTools.getEmailFromDN(certificate
0383:                        .getSubjectDN().getName());
0384:                if (emails.size() > 0) {
0385:                    return (String) emails.get(0);
0386:                }
0387:                return null;
0388:            }
0389:
0390:            /**
0391:             * Takes a DN and reverses it completely so the first attribute ends up last. 
0392:             * C=SE,O=Foo,CN=Bar becomes CN=Bar,O=Foo,C=SE.
0393:             *
0394:             * @param dn String containing DN to be reversed, The DN string has the format "C=SE, O=xx, OU=yy, CN=zz".
0395:             *
0396:             * @return String containing reversed DN
0397:             */
0398:            public static String reverseDN(String dn) {
0399:                log.debug(">reverseDN: dn: " + dn);
0400:                String ret = null;
0401:                if (dn != null) {
0402:                    String o;
0403:                    BasicX509NameTokenizer xt = new BasicX509NameTokenizer(dn);
0404:                    StringBuffer buf = new StringBuffer();
0405:                    boolean first = true;
0406:                    while (xt.hasMoreTokens()) {
0407:                        o = xt.nextToken();
0408:                        //log.debug("token: "+o);
0409:                        if (!first) {
0410:                            buf.insert(0, ",");
0411:                        } else {
0412:                            first = false;
0413:                        }
0414:                        buf.insert(0, o);
0415:                    }
0416:                    if (buf.length() > 0) {
0417:                        ret = buf.toString();
0418:                    }
0419:                }
0420:
0421:                log.debug("<reverseDN: resulting dn: " + ret);
0422:                return ret;
0423:            } //reverseDN
0424:
0425:            /**
0426:             * Tries to determine if a DN is in reversed form. It does this by taking the last attribute 
0427:             * and the first attribute. If the last attribute comes before the first in the dNObjects array
0428:             * the DN is assumed to be in reversed order.
0429:             * The check if a DN is revered is relative to the default ordering, so if the default ordering is:
0430:             * "C=SE, O=PrimeKey, CN=Tomas" (dNObjectsReverse ordering in EJBCA) a dn or form "CN=Tomas, O=PrimeKey, C=SE" is reversed.
0431:             * 
0432:             * if the default ordering is:
0433:             * "CN=Tomas, O=PrimeKey, C=SE" (dNObjectsForward ordering in EJBCA) a dn or form "C=SE, O=PrimeKey, CN=Tomas" is reversed.
0434:             * 
0435:             *
0436:             * @param dn String containing DN to be checked, The DN string has the format "C=SE, O=xx, OU=yy, CN=zz".
0437:             *
0438:             * @return true if the DN is believed to be in reversed order, false otherwise
0439:             */
0440:            protected static boolean isDNReversed(String dn) {
0441:                //log.debug(">isDNReversed: dn: " + dn);
0442:                boolean ret = false;
0443:                if (dn != null) {
0444:                    String first = null;
0445:                    String last = null;
0446:                    X509NameTokenizer xt = new X509NameTokenizer(dn);
0447:                    if (xt.hasMoreTokens()) {
0448:                        first = xt.nextToken();
0449:                    }
0450:                    while (xt.hasMoreTokens()) {
0451:                        last = xt.nextToken();
0452:                    }
0453:                    String[] dNObjects = DnComponents.getDnObjects();
0454:                    if ((first != null) && (last != null)) {
0455:                        first = first.substring(0, first.indexOf('='));
0456:                        last = last.substring(0, last.indexOf('='));
0457:                        int firsti = 0, lasti = 0;
0458:                        for (int i = 0; i < dNObjects.length; i++) {
0459:                            if (first.toLowerCase().equals(dNObjects[i])) {
0460:                                firsti = i;
0461:                            }
0462:                            if (last.toLowerCase().equals(dNObjects[i])) {
0463:                                lasti = i;
0464:                            }
0465:                        }
0466:                        if (lasti < firsti) {
0467:                            ret = true;
0468:                        }
0469:
0470:                    }
0471:                }
0472:                //log.debug("<isDNReversed: " + ret);
0473:                return ret;
0474:            } //isDNReversed
0475:
0476:            /**
0477:             * Gets a specified part of a DN. Specifically the first occurrence it the DN contains several
0478:             * instances of a part (i.e. cn=x, cn=y returns x).
0479:             *
0480:             * @param dn String containing DN, The DN string has the format "C=SE, O=xx, OU=yy, CN=zz".
0481:             * @param dnpart String specifying which part of the DN to get, should be "CN" or "OU" etc.
0482:             *
0483:             * @return String containing dnpart or null if dnpart is not present
0484:             */
0485:            public static String getPartFromDN(String dn, String dnpart) {
0486:                log.debug(">getPartFromDN: dn:'" + dn + "', dnpart=" + dnpart);
0487:                String part = null;
0488:                if ((dn != null) && (dnpart != null)) {
0489:                    String o;
0490:                    dnpart += "="; // we search for 'CN=' etc.
0491:                    X509NameTokenizer xt = new X509NameTokenizer(dn);
0492:                    while (xt.hasMoreTokens()) {
0493:                        o = xt.nextToken();
0494:                        //log.debug("checking: "+o.substring(0,dnpart.length()));
0495:                        if ((o.length() > dnpart.length())
0496:                                && o.substring(0, dnpart.length())
0497:                                        .equalsIgnoreCase(dnpart)) {
0498:                            part = o.substring(dnpart.length());
0499:
0500:                            break;
0501:                        }
0502:                    }
0503:                }
0504:                log.debug("<getpartFromDN: resulting DN part=" + part);
0505:                return part;
0506:            } //getPartFromDN
0507:
0508:            /**
0509:             * Gets a specified parts of a DN. Returns all occurences as an ArrayList, also works if DN contains several
0510:             * instances of a part (i.e. cn=x, cn=y returns {x, y, null}).
0511:             *
0512:             * @param dn String containing DN, The DN string has the format "C=SE, O=xx, OU=yy, CN=zz".
0513:             * @param dnpart String specifying which part of the DN to get, should be "CN" or "OU" etc.
0514:             *
0515:             * @return ArrayList containing dnparts or empty list if dnpart is not present
0516:             */
0517:            public static ArrayList getPartsFromDN(String dn, String dnpart) {
0518:                log.debug(">getPartsFromDN: dn:'" + dn + "', dnpart=" + dnpart);
0519:                ArrayList parts = new ArrayList();
0520:                if ((dn != null) && (dnpart != null)) {
0521:                    String o;
0522:                    dnpart += "="; // we search for 'CN=' etc.
0523:                    X509NameTokenizer xt = new X509NameTokenizer(dn);
0524:                    while (xt.hasMoreTokens()) {
0525:                        o = xt.nextToken();
0526:                        if ((o.length() > dnpart.length())
0527:                                && o.substring(0, dnpart.length())
0528:                                        .equalsIgnoreCase(dnpart)) {
0529:                            parts.add(o.substring(dnpart.length()));
0530:                        }
0531:                    }
0532:                }
0533:                log.debug("<getpartsFromDN: resulting DN part="
0534:                        + parts.toString());
0535:                return parts;
0536:            } //getPartFromDN
0537:
0538:            /**
0539:             * Gets a list of all custom OIDs defined in the string. A custom OID is defined as an OID, simply as that. Otherwise, if it is not a custom oid, the DNpart is defined by a name such as CN och rfc822Name.
0540:             *
0541:             * @param dn String containing DN, The DN string has the format "C=SE, O=xx, OU=yy, CN=zz", or "rfc822Name=foo@bar.com", etc.
0542:             * @param dnpart String specifying which part of the DN to get, should be "CN" or "OU" etc.
0543:             *
0544:             * @return ArrayList containing oids or empty list if no custom OIDs are present
0545:             */
0546:            public static ArrayList getCustomOids(String dn) {
0547:                log.debug(">getCustomOids: dn:'" + dn);
0548:                ArrayList parts = new ArrayList();
0549:                if (dn != null) {
0550:                    String o;
0551:                    X509NameTokenizer xt = new X509NameTokenizer(dn);
0552:                    while (xt.hasMoreTokens()) {
0553:                        o = xt.nextToken();
0554:                        // Try to see if it is a valid OID
0555:                        try {
0556:                            int i = o.indexOf('=');
0557:                            // An oid is never shorter than 3 chars and must start with 1.
0558:                            if ((i > 2) && (o.charAt(1) == '.')) {
0559:                                String oid = o.substring(0, i);
0560:                                new DERObjectIdentifier(oid);
0561:                                parts.add(oid);
0562:                            }
0563:                        } catch (IllegalArgumentException e) {
0564:                            // Not a valid oid
0565:                        }
0566:                    }
0567:                }
0568:                log.debug("<getpartsFromDN: resulting DN part="
0569:                        + parts.toString());
0570:                return parts;
0571:            } //getPartFromDN
0572:
0573:            /**
0574:             * Gets subject DN in the format we are sure about (BouncyCastle),supporting UTF8.
0575:             *
0576:             * @param cert X509Certificate
0577:             *
0578:             * @return String containing the subjects DN.
0579:             */
0580:            public static String getSubjectDN(X509Certificate cert) {
0581:                return getDN(cert, 1);
0582:            }
0583:
0584:            /**
0585:             * Gets issuer DN in the format we are sure about (BouncyCastle),supporting UTF8.
0586:             *
0587:             * @param cert X509Certificate
0588:             *
0589:             * @return String containing the issuers DN.
0590:             */
0591:            public static String getIssuerDN(X509Certificate cert) {
0592:                return getDN(cert, 2);
0593:            }
0594:
0595:            /**
0596:             * Gets subject or issuer DN in the format we are sure about (BouncyCastle),supporting UTF8.
0597:             *
0598:             * @param cert X509Certificate
0599:             * @param which 1 = subjectDN, anything else = issuerDN
0600:             *
0601:             * @return String containing the DN.
0602:             */
0603:            private static String getDN(X509Certificate cert, int which) {
0604:                //log.debug(">getDN("+which+")");
0605:                String dn = null;
0606:                if (cert == null) {
0607:                    return dn;
0608:                }
0609:                try {
0610:                    CertificateFactory cf = CertTools.getCertificateFactory();
0611:                    X509Certificate x509cert = (X509Certificate) cf
0612:                            .generateCertificate(new ByteArrayInputStream(cert
0613:                                    .getEncoded()));
0614:                    //log.debug("Created certificate of class: " + x509cert.getClass().getName());
0615:
0616:                    if (which == 1) {
0617:                        dn = x509cert.getSubjectDN().toString();
0618:                    } else {
0619:                        dn = x509cert.getIssuerDN().toString();
0620:                    }
0621:                } catch (CertificateException ce) {
0622:                    log.error("CertificateException: ", ce);
0623:                    return null;
0624:                }
0625:                //log.debug("<getDN("+which+"):"+dn);
0626:                return stringToBCDNString(dn);
0627:            } // getDN
0628:
0629:            /**
0630:             * Gets issuer DN for CRL in the format we are sure about (BouncyCastle),supporting UTF8.
0631:             *
0632:             * @param crl X509RL
0633:             *
0634:             * @return String containing the DN.
0635:             */
0636:            public static String getIssuerDN(X509CRL crl) {
0637:                //log.debug(">getIssuerDN(crl)");
0638:                String dn = null;
0639:                try {
0640:                    CertificateFactory cf = CertTools.getCertificateFactory();
0641:                    X509CRL x509crl = (X509CRL) cf
0642:                            .generateCRL(new ByteArrayInputStream(crl
0643:                                    .getEncoded()));
0644:                    //log.debug("Created certificate of class: " + x509crl.getClass().getName());
0645:                    dn = x509crl.getIssuerDN().toString();
0646:                } catch (CRLException ce) {
0647:                    log.error("CRLException: ", ce);
0648:                    return null;
0649:                }
0650:                //log.debug("<getIssuerDN(crl):"+dn);
0651:                return stringToBCDNString(dn);
0652:            } // getIssuerDN
0653:
0654:            public static CertificateFactory getCertificateFactory() {
0655:                try {
0656:                    return CertificateFactory.getInstance("X.509", "BC");
0657:                } catch (NoSuchProviderException nspe) {
0658:                    log.error("NoSuchProvider: ", nspe);
0659:                } catch (CertificateException ce) {
0660:                    log.error("CertificateException: ", ce);
0661:                }
0662:                return null;
0663:            }
0664:
0665:            public static synchronized void removeBCProvider() {
0666:                Security.removeProvider("BC");
0667:            }
0668:
0669:            public static synchronized void installBCProvider() {
0670:                // A flag that ensures that we install the parameters for implcitlyCA only when we have installed a new provider
0671:                boolean installImplicitlyCA = false;
0672:                if (Security.addProvider(new BouncyCastleProvider()) < 0) {
0673:                    // If already installed, remove so we can handle redeploy
0674:                    // Nope, we ignore re-deploy on this level, because it can happen
0675:                    // that the BC-provider is uninstalled, in just the second another
0676:                    // thread tries to use the provider, and then that request will fail.
0677:                    if (developmentProviderInstallation) {
0678:                        removeBCProvider();
0679:                        if (Security.addProvider(new BouncyCastleProvider()) < 0) {
0680:                            log.error("Cannot even install BC provider again!");
0681:                        } else {
0682:                            installImplicitlyCA = true;
0683:                        }
0684:                    }
0685:                } else {
0686:                    installImplicitlyCA = true;
0687:                }
0688:                if (installImplicitlyCA) {
0689:                    // Install EC parameters for implicitlyCA encoding of EC keys, we have default curve parameters if no new ones have been given.
0690:                    // The parameters are only used if implicitlyCA is used for generating keys, or verifying certs
0691:                    checkImplicitParams();
0692:                    ECCurve curve = new ECCurve.Fp(new BigInteger(
0693:                            IMPLICITLYCA_Q), // q
0694:                            new BigInteger(IMPLICITLYCA_A, 16), // a
0695:                            new BigInteger(IMPLICITLYCA_B, 16)); // b
0696:                    org.bouncycastle.jce.spec.ECParameterSpec implicitSpec = new org.bouncycastle.jce.spec.ECParameterSpec(
0697:                            curve, curve
0698:                                    .decodePoint(Hex.decode(IMPLICITLYCA_G)), // G
0699:                            new BigInteger(IMPLICITLYCA_N)); // n
0700:                    ConfigurableProvider config = (ConfigurableProvider) Security
0701:                            .getProvider("BC");
0702:                    if (config != null) {
0703:                        config.setParameter(
0704:                                ConfigurableProvider.EC_IMPLICITLY_CA,
0705:                                implicitSpec);
0706:                    } else {
0707:                        log
0708:                                .error("Can not get ConfigurableProvider, implicitlyCA EC parameters NOT set!");
0709:                    }
0710:                }
0711:
0712:                // 2007-05-25
0713:                // Finally we must configure SERIALNUMBER behavior in BC >=1.36 to be the same
0714:                // as the behavior in BC 1.35, it changed from SN to SERIALNUMBER in BC 1.36
0715:                // We must be backwards compatible
0716:                X509Name.DefaultSymbols.put(X509Name.SN, "SN");
0717:
0718:                // We hard specify the system security provider in a few cases (see SYSTEM_SECURITY_PROVIDER). 
0719:                // If the SUN provider does not exist, we will always use BC.
0720:                Provider p = Security
0721:                        .getProvider(CertTools.SYSTEM_SECURITY_PROVIDER);
0722:                if (p == null) {
0723:                    log
0724:                            .debug("SUN security provider does not exist, using BC as system default provider.");
0725:                    SYSTEM_SECURITY_PROVIDER = "BC";
0726:                }
0727:
0728:            }
0729:
0730:            /** Check if parameters have been set correctly during pre-process, otherwise log an error and
0731:             * set default values. Mostly used to be able to do JUnit testing
0732:             */
0733:            private static void checkImplicitParams() {
0734:                if (StringUtils
0735:                        .contains(IMPLICITLYCA_Q, "ecdsa.implicitlyca.q")) {
0736:                    log.info("IMPLICITLYCA_Q not set, using default.");
0737:                    IMPLICITLYCA_Q = "883423532389192164791648750360308885314476597252960362792450860609699839";
0738:                }
0739:                if (StringUtils
0740:                        .contains(IMPLICITLYCA_A, "ecdsa.implicitlyca.a")) {
0741:                    log.info("IMPLICITLYCA_A not set, using default.");
0742:                    IMPLICITLYCA_A = "7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc";
0743:                }
0744:                if (StringUtils
0745:                        .contains(IMPLICITLYCA_B, "ecdsa.implicitlyca.b")) {
0746:                    log.info("IMPLICITLYCA_B not set, using default.");
0747:                    IMPLICITLYCA_B = "6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a";
0748:                }
0749:                if (StringUtils
0750:                        .contains(IMPLICITLYCA_G, "ecdsa.implicitlyca.g")) {
0751:                    log.info("IMPLICITLYCA_G not set, using default.");
0752:                    IMPLICITLYCA_G = "020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf";
0753:                }
0754:                if (StringUtils
0755:                        .contains(IMPLICITLYCA_N, "ecdsa.implicitlyca.n")) {
0756:                    log.info("IMPLICITLYCA_N not set, using default.");
0757:                    IMPLICITLYCA_N = "883423532389192164791648750360308884807550341691627752275345424702807307";
0758:                }
0759:            }
0760:
0761:            /**
0762:             * Reads a certificate in PEM-format from a file. The file may contain other things,
0763:             * the first certificate in the file is read.
0764:             *
0765:             * @param certFile the file containing the certificate in PEM-format
0766:             * @return Ordered Collection of X509Certificate, first certificate first, or empty Collection
0767:             * @exception IOException if the filen cannot be read.
0768:             * @exception CertificateException if the filen does not contain a correct certificate.
0769:             */
0770:            public static Collection getCertsFromPEM(String certFile)
0771:                    throws IOException, CertificateException {
0772:                log.debug(">getCertfromPEM: certFile=" + certFile);
0773:                InputStream inStrm = null;
0774:                Collection certs;
0775:                try {
0776:                    inStrm = new FileInputStream(certFile);
0777:                    certs = getCertsFromPEM(inStrm);
0778:                } finally {
0779:                    if (inStrm != null)
0780:                        inStrm.close();
0781:                }
0782:                log.debug("<getCertfromPEM: certFile=" + certFile);
0783:                return certs;
0784:            }
0785:
0786:            /**
0787:             * Reads a certificate in PEM-format from an InputStream. The stream may contain other things,
0788:             * the first certificate in the stream is read.
0789:             *
0790:             * @param certFile the input stream containing the certificate in PEM-format
0791:             * @return Ordered Collection of X509Certificate, first certificate first, or empty Collection
0792:             * @exception IOException if the stream cannot be read.
0793:             * @exception CertificateException if the stream does not contain a correct certificate.
0794:             */
0795:            public static Collection getCertsFromPEM(InputStream certstream)
0796:                    throws IOException, CertificateException {
0797:                log.debug(">getCertfromPEM:");
0798:                ArrayList ret = new ArrayList();
0799:                String beginKey = "-----BEGIN CERTIFICATE-----";
0800:                String endKey = "-----END CERTIFICATE-----";
0801:                BufferedReader bufRdr = null;
0802:                ByteArrayOutputStream ostr = null;
0803:                PrintStream opstr = null;
0804:                try {
0805:                    bufRdr = new BufferedReader(new InputStreamReader(
0806:                            certstream));
0807:                    while (bufRdr.ready()) {
0808:                        ostr = new ByteArrayOutputStream();
0809:                        opstr = new PrintStream(ostr);
0810:                        String temp;
0811:                        while ((temp = bufRdr.readLine()) != null
0812:                                && !temp.equals(beginKey))
0813:                            continue;
0814:                        if (temp == null)
0815:                            throw new IOException("Error in "
0816:                                    + certstream.toString() + ", missing "
0817:                                    + beginKey + " boundary");
0818:                        while ((temp = bufRdr.readLine()) != null
0819:                                && !temp.equals(endKey))
0820:                            opstr.print(temp);
0821:                        if (temp == null)
0822:                            throw new IOException("Error in "
0823:                                    + certstream.toString() + ", missing "
0824:                                    + endKey + " boundary");
0825:                        opstr.close();
0826:
0827:                        byte[] certbuf = Base64.decode(ostr.toByteArray());
0828:                        ostr.close();
0829:                        // Phweeew, were done, now decode the cert from file back to X509Certificate object
0830:                        CertificateFactory cf = CertTools
0831:                                .getCertificateFactory();
0832:                        X509Certificate x509cert = (X509Certificate) cf
0833:                                .generateCertificate(new ByteArrayInputStream(
0834:                                        certbuf));
0835:                        ret.add(x509cert);
0836:                    }
0837:                } finally {
0838:                    if (bufRdr != null)
0839:                        bufRdr.close();
0840:                    if (opstr != null)
0841:                        opstr.close();
0842:                    if (ostr != null)
0843:                        ostr.close();
0844:                }
0845:                log.debug("<getcertfromPEM:" + ret.size());
0846:                return ret;
0847:            } // getCertsFromPEM
0848:
0849:            /** Converts a regular array of certificates into an ArrayList, using the provided provided.
0850:             * 
0851:             * @param certs Certificate[] of certificates to convert
0852:             * @param provider provider for example "SUN" or "BC", use null for the default provider (BC)
0853:             * @return An ArrayList of certificates in the same order as the passed in array
0854:             * @throws NoSuchProviderException 
0855:             * @throws CertificateException 
0856:             */
0857:            public static ArrayList getCertCollectionFromArray(
0858:                    Certificate[] certs, String provider)
0859:                    throws CertificateException, NoSuchProviderException {
0860:                if (log.isDebugEnabled()) {
0861:                    log.debug(">getCertCollectionFromArray: " + provider);
0862:                }
0863:                ArrayList ret = new ArrayList();
0864:                String prov = provider;
0865:                if (prov == null) {
0866:                    prov = "BC";
0867:                }
0868:                for (int i = 0; i < certs.length; i++) {
0869:                    CertificateFactory cf = CertificateFactory.getInstance(
0870:                            "X.509", prov);
0871:                    Certificate cert = certs[i];
0872:                    X509Certificate x509cert = (X509Certificate) cf
0873:                            .generateCertificate(new ByteArrayInputStream(cert
0874:                                    .getEncoded()));
0875:                    ret.add(x509cert);
0876:                }
0877:                if (log.isDebugEnabled()) {
0878:                    log.debug("<getCertCollectionFromArray: " + ret.size());
0879:                }
0880:                return ret;
0881:            }
0882:
0883:            /**
0884:             * Returns a certificate in PEM-format.
0885:             *
0886:             * @param certs Collection of X509Certificate to convert to PEM
0887:             * @return byte array containing PEM certificate
0888:             * @exception CertificateException if the stream does not contain a correct certificate.
0889:             */
0890:            public static byte[] getPEMFromCerts(Collection certs)
0891:                    throws CertificateException {
0892:                String beginKey = "-----BEGIN CERTIFICATE-----";
0893:                String endKey = "-----END CERTIFICATE-----";
0894:                ByteArrayOutputStream ostr = new ByteArrayOutputStream();
0895:                PrintStream opstr = new PrintStream(ostr);
0896:                Iterator iter = certs.iterator();
0897:                while (iter.hasNext()) {
0898:                    X509Certificate cert = (X509Certificate) iter.next();
0899:                    byte[] certbuf = Base64.encode(cert.getEncoded());
0900:                    opstr.println("Subject: " + cert.getSubjectDN());
0901:                    opstr.println("Issuer: " + cert.getIssuerDN());
0902:                    opstr.println(beginKey);
0903:                    opstr.println(new String(certbuf));
0904:                    opstr.println(endKey);
0905:                }
0906:                opstr.close();
0907:                byte[] ret = ostr.toByteArray();
0908:                return ret;
0909:            }
0910:
0911:            /**
0912:             * Returns a CRL in PEM-format.
0913:             *
0914:             * @param crlbytes the der encoded crl bytes to convert to PEM
0915:             * @return byte array containing PEM CRL
0916:             * @exception IOException if the stream cannot be read.
0917:             */
0918:            public static byte[] getPEMFromCrl(byte[] crlbytes) {
0919:                String beginKey = "-----BEGIN X509 CRL-----";
0920:                String endKey = "-----END X509 CRL-----";
0921:                ByteArrayOutputStream ostr = new ByteArrayOutputStream();
0922:                PrintStream opstr = new PrintStream(ostr);
0923:                byte[] crlb64 = Base64.encode(crlbytes);
0924:                opstr.println(beginKey);
0925:                opstr.println(new String(crlb64));
0926:                opstr.println(endKey);
0927:                opstr.close();
0928:                byte[] ret = ostr.toByteArray();
0929:                return ret;
0930:            }
0931:
0932:            /**
0933:             * Creates X509Certificate from byte[].
0934:             *
0935:             * @param cert byte array containing certificate in DER-format
0936:             *
0937:             * @return X509Certificate
0938:             *
0939:             * @throws CertificateException if the byte array does not contain a proper certificate.
0940:             * @throws IOException if the byte array cannot be read.
0941:             */
0942:            public static X509Certificate getCertfromByteArray(byte[] cert)
0943:                    throws CertificateException {
0944:                log.debug(">getCertfromByteArray:");
0945:                CertificateFactory cf = CertTools.getCertificateFactory();
0946:                X509Certificate x509cert = (X509Certificate) cf
0947:                        .generateCertificate(new ByteArrayInputStream(cert));
0948:                log.debug("<getCertfromByteArray:");
0949:                return x509cert;
0950:            } // getCertfromByteArray
0951:
0952:            /**
0953:             * Creates X509CRL from byte[].
0954:             *
0955:             * @param crl byte array containing CRL in DER-format
0956:             *
0957:             * @return X509CRL
0958:             *
0959:             * @throws IOException if the byte array can not be read.
0960:             * @throws CertificateException if the byte arrayen does not contani a correct CRL.
0961:             * @throws CRLException if the byte arrayen does not contani a correct CRL.
0962:             */
0963:            public static X509CRL getCRLfromByteArray(byte[] crl)
0964:                    throws IOException, CRLException {
0965:                log.debug(">getCRLfromByteArray:");
0966:
0967:                if (crl == null) {
0968:                    throw new IOException("Cannot read byte[] that is 'null'!");
0969:                }
0970:
0971:                CertificateFactory cf = CertTools.getCertificateFactory();
0972:                X509CRL x509crl = (X509CRL) cf
0973:                        .generateCRL(new ByteArrayInputStream(crl));
0974:                log.debug("<getCRLfromByteArray:");
0975:
0976:                return x509crl;
0977:            } // getCRLfromByteArray
0978:
0979:            /**
0980:             * Checks if a certificate is self signed by verifying if subject and issuer are the same.
0981:             *
0982:             * @param cert the certificate that skall be checked.
0983:             *
0984:             * @return boolean true if the certificate has the same issuer and subject, false otherwise.
0985:             */
0986:            public static boolean isSelfSigned(X509Certificate cert) {
0987:                log.debug(">isSelfSigned: cert: " + CertTools.getIssuerDN(cert)
0988:                        + "\n" + CertTools.getSubjectDN(cert));
0989:
0990:                boolean ret = CertTools.getSubjectDN(cert).equals(
0991:                        CertTools.getIssuerDN(cert));
0992:                log.debug("<isSelfSigned:" + ret);
0993:
0994:                return ret;
0995:            } // isSelfSigned
0996:
0997:            /**
0998:             * Generate a selfsigned certiicate.
0999:             *
1000:             * @param dn subject and issuer DN
1001:             * @param validity in days
1002:             * @param policyId policy string ('2.5.29.32.0') or null
1003:             * @param privKey private key
1004:             * @param pubKey public key
1005:             * @param sigAlg signature algorithm, you can use one of the contants CATokenInfo.SIGALG_XXX
1006:             * @param isCA boolean true or false
1007:             *
1008:             * @return X509Certificate, self signed
1009:             *
1010:             * @throws NoSuchAlgorithmException DOCUMENT ME!
1011:             * @throws SignatureException DOCUMENT ME!
1012:             * @throws InvalidKeyException DOCUMENT ME!
1013:             * @throws IllegalStateException 
1014:             * @throws CertificateEncodingException 
1015:             */
1016:            public static X509Certificate genSelfCert(String dn, long validity,
1017:                    String policyId, PrivateKey privKey, PublicKey pubKey,
1018:                    String sigAlg, boolean isCA)
1019:                    throws NoSuchAlgorithmException, SignatureException,
1020:                    InvalidKeyException, CertificateEncodingException,
1021:                    IllegalStateException {
1022:
1023:                int keyusage = X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign;
1024:                return genSelfCertForPurpose(dn, validity, policyId, privKey,
1025:                        pubKey, sigAlg, isCA, keyusage);
1026:
1027:            } //genselfCert
1028:
1029:            /**
1030:             * Generate a selfsigned certiicate with possibility to specify key usage.
1031:             *
1032:             * @param dn subject and issuer DN
1033:             * @param validity in days
1034:             * @param policyId policy string ('2.5.29.32.0') or null
1035:             * @param privKey private key
1036:             * @param pubKey public key
1037:             * @param sigAlg signature algorithm, you can use one of the contants CATokenInfo.SIGALG_XXX
1038:             * @param isCA boolean true or false
1039:             * @param keyusage as defined by constants in X509KeyUsage
1040:             *
1041:             * @return X509Certificate, self signed
1042:             *
1043:             * @throws NoSuchAlgorithmException DOCUMENT ME!
1044:             * @throws SignatureException DOCUMENT ME!
1045:             * @throws InvalidKeyException DOCUMENT ME!
1046:             * @throws IllegalStateException 
1047:             * @throws CertificateEncodingException 
1048:             */
1049:            public static X509Certificate genSelfCertForPurpose(String dn,
1050:                    long validity, String policyId, PrivateKey privKey,
1051:                    PublicKey pubKey, String sigAlg, boolean isCA, int keyusage)
1052:                    throws NoSuchAlgorithmException, SignatureException,
1053:                    InvalidKeyException, CertificateEncodingException,
1054:                    IllegalStateException {
1055:                // Create self signed certificate
1056:                Date firstDate = new Date();
1057:
1058:                // Set back startdate ten minutes to avoid some problems with wrongly set clocks.
1059:                firstDate.setTime(firstDate.getTime() - (10 * 60 * 1000));
1060:
1061:                Date lastDate = new Date();
1062:
1063:                // validity in days = validity*24*60*60*1000 milliseconds
1064:                lastDate.setTime(lastDate.getTime()
1065:                        + (validity * (24 * 60 * 60 * 1000)));
1066:
1067:                X509V3CertificateGenerator certgen = new X509V3CertificateGenerator();
1068:
1069:                // Serialnumber is random bits, where random generator is initialized with Date.getTime() when this
1070:                // bean is created.
1071:                byte[] serno = new byte[8];
1072:                SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
1073:                random.setSeed((new Date().getTime()));
1074:                random.nextBytes(serno);
1075:                certgen
1076:                        .setSerialNumber((new java.math.BigInteger(serno))
1077:                                .abs());
1078:                certgen.setNotBefore(firstDate);
1079:                certgen.setNotAfter(lastDate);
1080:                certgen.setSignatureAlgorithm(sigAlg);
1081:                certgen.setSubjectDN(CertTools.stringToBcX509Name(dn));
1082:                certgen.setIssuerDN(CertTools.stringToBcX509Name(dn));
1083:                certgen.setPublicKey(pubKey);
1084:
1085:                // Basic constranits is always critical and MUST be present at-least in CA-certificates.
1086:                BasicConstraints bc = new BasicConstraints(isCA);
1087:                certgen.addExtension(X509Extensions.BasicConstraints.getId(),
1088:                        true, bc);
1089:
1090:                // Put critical KeyUsage in CA-certificates
1091:                if (isCA == true) {
1092:                    X509KeyUsage ku = new X509KeyUsage(keyusage);
1093:                    certgen.addExtension(X509Extensions.KeyUsage.getId(), true,
1094:                            ku);
1095:                }
1096:
1097:                // Subject and Authority key identifier is always non-critical and MUST be present for certificates to verify in Mozilla.
1098:                try {
1099:                    if (isCA == true) {
1100:                        SubjectPublicKeyInfo spki = new SubjectPublicKeyInfo(
1101:                                (ASN1Sequence) new ASN1InputStream(
1102:                                        new ByteArrayInputStream(pubKey
1103:                                                .getEncoded())).readObject());
1104:                        SubjectKeyIdentifier ski = new SubjectKeyIdentifier(
1105:                                spki);
1106:
1107:                        SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo(
1108:                                (ASN1Sequence) new ASN1InputStream(
1109:                                        new ByteArrayInputStream(pubKey
1110:                                                .getEncoded())).readObject());
1111:                        AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(
1112:                                apki);
1113:
1114:                        certgen.addExtension(
1115:                                X509Extensions.SubjectKeyIdentifier.getId(),
1116:                                false, ski);
1117:                        certgen.addExtension(
1118:                                X509Extensions.AuthorityKeyIdentifier.getId(),
1119:                                false, aki);
1120:                    }
1121:                } catch (IOException e) { // do nothing
1122:                }
1123:
1124:                // CertificatePolicies extension if supplied policy ID, always non-critical
1125:                if (policyId != null) {
1126:                    PolicyInformation pi = new PolicyInformation(
1127:                            new DERObjectIdentifier(policyId));
1128:                    DERSequence seq = new DERSequence(pi);
1129:                    certgen.addExtension(X509Extensions.CertificatePolicies
1130:                            .getId(), false, seq);
1131:                }
1132:
1133:                X509Certificate selfcert = certgen.generate(privKey);
1134:
1135:                return selfcert;
1136:            } //genselfCertForPurpose
1137:
1138:            /**
1139:             * Get the authority key identifier from a certificate extensions
1140:             *
1141:             * @param cert certificate containing the extension
1142:             * @return byte[] containing the authority key identifier, or null if it does not exist
1143:             * @throws IOException if extension can not be parsed
1144:             */
1145:            public static byte[] getAuthorityKeyId(X509Certificate cert)
1146:                    throws IOException {
1147:                if (cert == null) {
1148:                    return null;
1149:                }
1150:                byte[] extvalue = cert.getExtensionValue("2.5.29.35");
1151:                if (extvalue == null) {
1152:                    return null;
1153:                }
1154:                DEROctetString oct = (DEROctetString) (new ASN1InputStream(
1155:                        new ByteArrayInputStream(extvalue)).readObject());
1156:                AuthorityKeyIdentifier keyId = new AuthorityKeyIdentifier(
1157:                        (ASN1Sequence) new ASN1InputStream(
1158:                                new ByteArrayInputStream(oct.getOctets()))
1159:                                .readObject());
1160:                return keyId.getKeyIdentifier();
1161:            } // getAuthorityKeyId
1162:
1163:            /**
1164:             * Get the subject key identifier from a certificate extensions
1165:             *
1166:             * @param cert certificate containing the extension
1167:             * @return byte[] containing the subject key identifier, or null if it does not exist
1168:             * @throws IOException if extension can not be parsed
1169:             */
1170:            public static byte[] getSubjectKeyId(X509Certificate cert)
1171:                    throws IOException {
1172:                if (cert == null) {
1173:                    return null;
1174:                }
1175:                byte[] extvalue = cert.getExtensionValue("2.5.29.14");
1176:                if (extvalue == null) {
1177:                    return null;
1178:                }
1179:                ASN1OctetString str = ASN1OctetString
1180:                        .getInstance(new ASN1InputStream(
1181:                                new ByteArrayInputStream(extvalue))
1182:                                .readObject());
1183:                SubjectKeyIdentifier keyId = SubjectKeyIdentifier
1184:                        .getInstance(new ASN1InputStream(
1185:                                new ByteArrayInputStream(str.getOctets()))
1186:                                .readObject());
1187:                return keyId.getKeyIdentifier();
1188:            } // getSubjectKeyId
1189:
1190:            /**
1191:             * Get a certificate policy ID from a certificate policies extension
1192:             *
1193:             * @param cert certificate containing the extension
1194:             * @param pos position of the policy id, if several exist, the first is as pos 0
1195:             * @return String with the certificate policy OID
1196:             * @throws IOException if extension can not be parsed
1197:             */
1198:            public static String getCertificatePolicyId(X509Certificate cert,
1199:                    int pos) throws IOException {
1200:                byte[] extvalue = cert
1201:                        .getExtensionValue(X509Extensions.CertificatePolicies
1202:                                .getId());
1203:                if (extvalue == null) {
1204:                    return null;
1205:                }
1206:                DEROctetString oct = (DEROctetString) (new ASN1InputStream(
1207:                        new ByteArrayInputStream(extvalue)).readObject());
1208:                ASN1Sequence seq = (ASN1Sequence) new ASN1InputStream(
1209:                        new ByteArrayInputStream(oct.getOctets())).readObject();
1210:                // Check the size so we don't ArrayIndexOutOfBounds
1211:                if (seq.size() < pos + 1) {
1212:                    return null;
1213:                }
1214:                PolicyInformation pol = new PolicyInformation(
1215:                        (ASN1Sequence) seq.getObjectAt(pos));
1216:                String id = pol.getPolicyIdentifier().getId();
1217:                return id;
1218:            } // getCertificatePolicyId
1219:
1220:            /**
1221:             * Gets the Microsoft specific UPN altName.
1222:             *
1223:             * @param cert certificate containing the extension
1224:             * @return String with the UPN name or null if the altName does not exist
1225:             */
1226:            public static String getUPNAltName(X509Certificate cert)
1227:                    throws IOException, CertificateParsingException {
1228:                Collection altNames = cert.getSubjectAlternativeNames();
1229:                if (altNames != null) {
1230:                    Iterator i = altNames.iterator();
1231:                    while (i.hasNext()) {
1232:                        ASN1Sequence seq = getAltnameSequence((List) i.next());
1233:                        String ret = getUPNStringFromSequence(seq);
1234:                        if (ret != null) {
1235:                            return ret;
1236:                        }
1237:                    }
1238:                }
1239:                return null;
1240:            } // getUPNAltName
1241:
1242:            /** Helper method for the above method
1243:             */
1244:            private static String getUPNStringFromSequence(ASN1Sequence seq) {
1245:                if (seq != null) {
1246:                    // First in sequence is the object identifier, that we must check
1247:                    DERObjectIdentifier id = DERObjectIdentifier
1248:                            .getInstance(seq.getObjectAt(0));
1249:                    if (id.getId().equals(CertTools.UPN_OBJECTID)) {
1250:                        ASN1TaggedObject obj = (ASN1TaggedObject) seq
1251:                                .getObjectAt(1);
1252:                        DERUTF8String str = DERUTF8String.getInstance(obj
1253:                                .getObject());
1254:                        return str.getString();
1255:                    }
1256:                }
1257:                return null;
1258:            }
1259:
1260:            /**
1261:             * Gets the Microsoft specific GUID altName, that is encoded as an octect string.
1262:             *
1263:             * @param cert certificate containing the extension
1264:             * @return String with the hex-encoded GUID byte array or null if the altName does not exist
1265:             */
1266:            public static String getGuidAltName(X509Certificate cert)
1267:                    throws IOException, CertificateParsingException {
1268:                Collection altNames = cert.getSubjectAlternativeNames();
1269:                if (altNames != null) {
1270:                    Iterator i = altNames.iterator();
1271:                    while (i.hasNext()) {
1272:                        ASN1Sequence seq = getAltnameSequence((List) i.next());
1273:                        if (seq != null) {
1274:                            // First in sequence is the object identifier, that we must check
1275:                            DERObjectIdentifier id = DERObjectIdentifier
1276:                                    .getInstance(seq.getObjectAt(0));
1277:                            if (id.getId().equals(CertTools.GUID_OBJECTID)) {
1278:                                ASN1TaggedObject obj = (ASN1TaggedObject) seq
1279:                                        .getObjectAt(1);
1280:                                ASN1OctetString str = ASN1OctetString
1281:                                        .getInstance(obj.getObject());
1282:                                return new String(Hex.encode(str.getOctets()));
1283:                            }
1284:                        }
1285:                    }
1286:                }
1287:                return null;
1288:            } // getGuidAltName
1289:
1290:            /** Helper for the above methods 
1291:             */
1292:            private static ASN1Sequence getAltnameSequence(List listitem)
1293:                    throws IOException {
1294:                Integer no = (Integer) listitem.get(0);
1295:                if (no.intValue() == 0) {
1296:                    byte[] altName = (byte[]) listitem.get(1);
1297:                    return getAltnameSequence(altName);
1298:                }
1299:                return null;
1300:            }
1301:
1302:            private static ASN1Sequence getAltnameSequence(byte[] value)
1303:                    throws IOException {
1304:                DERObject oct = (new ASN1InputStream(new ByteArrayInputStream(
1305:                        value)).readObject());
1306:                ASN1Sequence seq = ASN1Sequence.getInstance(oct);
1307:                return seq;
1308:            }
1309:
1310:            /** Gets an altName string from an X509Extension
1311:             * 
1312:             * @param ext X509Extension with AlternativeNames
1313:             * @return String as defined in method getSubjectAlternativeName
1314:             */
1315:            public static String getAltNameStringFromExtension(X509Extension ext) {
1316:                String altName = null;
1317:                //GeneralNames
1318:                ASN1OctetString octs = ext.getValue();
1319:                if (octs != null) {
1320:                    ASN1InputStream aIn = new ASN1InputStream(
1321:                            new ByteArrayInputStream(octs.getOctets()));
1322:                    DERObject obj;
1323:                    try {
1324:                        obj = aIn.readObject();
1325:                        GeneralNames gan = GeneralNames.getInstance(obj);
1326:                        GeneralName[] gns = gan.getNames();
1327:                        for (int i = 0; i < gns.length; i++) {
1328:                            GeneralName gn = gns[i];
1329:                            int tag = gn.getTagNo();
1330:                            DEREncodable name = gn.getName();
1331:                            String str = CertTools.getGeneralNameString(tag,
1332:                                    name);
1333:                            if (altName == null) {
1334:                                altName = str;
1335:                            } else {
1336:                                altName += ", " + str;
1337:                            }
1338:                        }
1339:                    } catch (IOException e) {
1340:                        log.error("IOException parsing altNames: ", e);
1341:                        return null;
1342:                    }
1343:                }
1344:                return altName;
1345:            }
1346:
1347:            /**
1348:             * SubjectAltName ::= GeneralNames
1349:             *
1350:             * GeneralNames :: = SEQUENCE SIZE (1..MAX) OF GeneralName
1351:             *
1352:             * GeneralName ::= CHOICE {
1353:             * otherName                       [0]     OtherName,
1354:             * rfc822Name                      [1]     IA5String,
1355:             * dNSName                         [2]     IA5String,
1356:             * x400Address                     [3]     ORAddress,
1357:             * directoryName                   [4]     Name,
1358:             * ediPartyName                    [5]     EDIPartyName,
1359:             * uniformResourceIdentifier       [6]     IA5String,
1360:             * iPAddress                       [7]     OCTET STRING,
1361:             * registeredID                    [8]     OBJECT IDENTIFIER}
1362:             * 
1363:             * SubjectAltName is of form \"rfc822Name=<email>,
1364:             * dNSName=<host name>, uniformResourceIdentifier=<http://host.com/>,
1365:             * iPAddress=<address>, guid=<globally unique id>, directoryName=<CN=testDirName|dir|name>
1366:             * 
1367:             * Supported altNames are upn, rfc822Name, uniformResourceIdentifier, dNSName, iPAddress, directoryName
1368:             *
1369:             * @author Marco Ferrante, (c) 2005 CSITA - University of Genoa (Italy)
1370:             * @author Tomas Gustavsson
1371:             * @param certificate containing alt names
1372:             * @return String containing altNames of form "rfc822Name=email, dNSName=hostname, uniformResourceIdentifier=uri, iPAddress=ip, upn=upn, directoryName=CN=testDirName|dir|name" or null if no altNames exist. Values in returned String is from CertTools constants. AltNames not supported are simply not shown in the resulting string.  
1373:             * @throws java.lang.Exception
1374:             */
1375:            public static String getSubjectAlternativeName(
1376:                    X509Certificate certificate)
1377:                    throws CertificateParsingException, IOException {
1378:                log.debug("Search for SubjectAltName");
1379:                if (certificate.getSubjectAlternativeNames() == null)
1380:                    return null;
1381:
1382:                java.util.Collection altNames = certificate
1383:                        .getSubjectAlternativeNames();
1384:                if (altNames == null) {
1385:                    return null;
1386:                }
1387:                Iterator iter = altNames.iterator();
1388:                String result = "";
1389:                String append = "";
1390:                while (iter.hasNext()) {
1391:                    java.util.List item = (java.util.List) iter.next();
1392:                    Integer type = (Integer) item.get(0);
1393:                    Object value = item.get(1);
1394:                    if (!StringUtils.isEmpty(result)) {
1395:                        // Result already contains one altname, so we have to add comma if there are more altNames
1396:                        append = ", ";
1397:                    }
1398:                    switch (type.intValue()) {
1399:                    case 0:
1400:                        ASN1Sequence seq = getAltnameSequence(item);
1401:                        String upn = getUPNStringFromSequence(seq);
1402:                        // OtherName can be something else besides UPN
1403:                        if (upn != null) {
1404:                            result += append + CertTools.UPN + "=" + upn;
1405:                        }
1406:                        break;
1407:                    case 1:
1408:                        result += append + CertTools.EMAIL + "="
1409:                                + (String) value;
1410:                        break;
1411:                    case 2:
1412:                        result += append + CertTools.DNS + "=" + (String) value;
1413:                        break;
1414:                    case 3: // SubjectAltName of type x400Address not supported
1415:                        break;
1416:                    case 4:
1417:                        result += append + CertTools.DIRECTORYNAME + "="
1418:                                + (String) value;
1419:                        break;
1420:                    case 5: // SubjectAltName of type ediPartyName not supported
1421:                        break;
1422:                    case 6:
1423:                        result += append + CertTools.URI + "=" + (String) value;
1424:                        break;
1425:                    case 7:
1426:                        result += append + CertTools.IPADDR + "="
1427:                                + (String) value;
1428:                        break;
1429:                    default: // SubjectAltName of unknown type
1430:                        break;
1431:                    }
1432:                }
1433:                if (StringUtils.isEmpty(result)) {
1434:                    return null;
1435:                }
1436:                return result;
1437:            }
1438:
1439:            /**
1440:             * From an altName string as defined in getSubjectAlternativeName 
1441:             * @param altName
1442:             * @return ASN.1 GeneralNames
1443:             * @see #getSubjectAlternativeName
1444:             */
1445:            public static GeneralNames getGeneralNamesFromAltName(String altName) {
1446:                log.debug(">getGeneralNamesFromAltName: " + altName);
1447:
1448:                ASN1EncodableVector vec = new ASN1EncodableVector();
1449:
1450:                ArrayList emails = CertTools.getEmailFromDN(altName);
1451:                if (!emails.isEmpty()) {
1452:                    Iterator iter = emails.iterator();
1453:                    while (iter.hasNext()) {
1454:                        GeneralName gn = new GeneralName(1, new DERIA5String(
1455:                                (String) iter.next()));
1456:                        vec.add(gn);
1457:                    }
1458:                }
1459:
1460:                ArrayList dns = CertTools
1461:                        .getPartsFromDN(altName, CertTools.DNS);
1462:                if (!dns.isEmpty()) {
1463:                    Iterator iter = dns.iterator();
1464:                    while (iter.hasNext()) {
1465:                        GeneralName gn = new GeneralName(2, new DERIA5String(
1466:                                (String) iter.next()));
1467:                        vec.add(gn);
1468:                    }
1469:                }
1470:
1471:                String directoryName = getDirectoryStringFromAltName(altName);
1472:                if (directoryName != null) {
1473:                    X509Name x509DirectoryName = new X509Name(directoryName);
1474:                    GeneralName gn = new GeneralName(4, x509DirectoryName);
1475:                    vec.add(gn);
1476:                }
1477:
1478:                ArrayList uri = CertTools
1479:                        .getPartsFromDN(altName, CertTools.URI);
1480:                if (!uri.isEmpty()) {
1481:                    Iterator iter = uri.iterator();
1482:                    while (iter.hasNext()) {
1483:                        GeneralName gn = new GeneralName(6, new DERIA5String(
1484:                                (String) iter.next()));
1485:                        vec.add(gn);
1486:                    }
1487:                }
1488:                uri = CertTools.getPartsFromDN(altName, CertTools.URI1);
1489:                if (!uri.isEmpty()) {
1490:                    Iterator iter = uri.iterator();
1491:                    while (iter.hasNext()) {
1492:                        GeneralName gn = new GeneralName(6, new DERIA5String(
1493:                                (String) iter.next()));
1494:                        vec.add(gn);
1495:                    }
1496:                }
1497:                uri = CertTools.getPartsFromDN(altName, CertTools.URI2);
1498:                if (!uri.isEmpty()) {
1499:                    Iterator iter = uri.iterator();
1500:                    while (iter.hasNext()) {
1501:                        GeneralName gn = new GeneralName(6, new DERIA5String(
1502:                                (String) iter.next()));
1503:                        vec.add(gn);
1504:                    }
1505:                }
1506:
1507:                ArrayList ipstr = CertTools.getPartsFromDN(altName,
1508:                        CertTools.IPADDR);
1509:                if (!ipstr.isEmpty()) {
1510:                    Iterator iter = ipstr.iterator();
1511:                    while (iter.hasNext()) {
1512:                        byte[] ipoctets = StringTools
1513:                                .ipStringToOctets((String) iter.next());
1514:                        GeneralName gn = new GeneralName(7, new DEROctetString(
1515:                                ipoctets));
1516:                        vec.add(gn);
1517:                    }
1518:                }
1519:
1520:                // UPN is an OtherName
1521:                ArrayList upn = CertTools
1522:                        .getPartsFromDN(altName, CertTools.UPN);
1523:                if (!upn.isEmpty()) {
1524:                    Iterator iter = upn.iterator();
1525:                    while (iter.hasNext()) {
1526:                        ASN1EncodableVector v = new ASN1EncodableVector();
1527:                        v.add(new DERObjectIdentifier(CertTools.UPN_OBJECTID));
1528:                        v.add(new DERTaggedObject(true, 0, new DERUTF8String(
1529:                                (String) iter.next())));
1530:                        //GeneralName gn = new GeneralName(new DERSequence(v), 0);
1531:                        DERObject gn = new DERTaggedObject(false, 0,
1532:                                new DERSequence(v));
1533:                        vec.add(gn);
1534:                    }
1535:                }
1536:
1537:                ArrayList guid = CertTools.getPartsFromDN(altName,
1538:                        CertTools.GUID);
1539:                if (!guid.isEmpty()) {
1540:                    Iterator iter = guid.iterator();
1541:                    while (iter.hasNext()) {
1542:                        ASN1EncodableVector v = new ASN1EncodableVector();
1543:                        byte[] guidbytes = Hex.decode((String) iter.next());
1544:                        if (guidbytes != null) {
1545:                            v.add(new DERObjectIdentifier(
1546:                                    CertTools.GUID_OBJECTID));
1547:                            v.add(new DERTaggedObject(true, 0,
1548:                                    new DEROctetString(guidbytes)));
1549:                            DERObject gn = new DERTaggedObject(false, 0,
1550:                                    new DERSequence(v));
1551:                            vec.add(gn);
1552:                        } else {
1553:                            log
1554:                                    .error("Cannot decode hexadecimal guid: "
1555:                                            + guid);
1556:                        }
1557:                    }
1558:                }
1559:
1560:                // To support custom OIDs in altNames, they must be added as an OtherName
1561:                ArrayList customoids = CertTools.getCustomOids(altName);
1562:                if (!customoids.isEmpty()) {
1563:                    Iterator iter = customoids.iterator();
1564:                    while (iter.hasNext()) {
1565:                        String oid = (String) iter.next();
1566:                        ArrayList oidval = CertTools.getPartsFromDN(altName,
1567:                                oid);
1568:                        if (!oidval.isEmpty()) {
1569:                            Iterator valiter = oidval.iterator();
1570:                            while (valiter.hasNext()) {
1571:                                ASN1EncodableVector v = new ASN1EncodableVector();
1572:                                v.add(new DERObjectIdentifier(oid));
1573:                                v.add(new DERTaggedObject(true, 0,
1574:                                        new DERUTF8String((String) valiter
1575:                                                .next())));
1576:                                DERObject gn = new DERTaggedObject(false, 0,
1577:                                        new DERSequence(v));
1578:                                vec.add(gn);
1579:                            }
1580:                        }
1581:                    }
1582:                }
1583:
1584:                GeneralNames ret = null;
1585:                if (vec.size() > 0) {
1586:                    ret = new GeneralNames(new DERSequence(vec));
1587:                }
1588:                return ret;
1589:            }
1590:
1591:            /**
1592:             * GeneralName ::= CHOICE {
1593:             * otherName                       [0]     OtherName,
1594:             * rfc822Name                      [1]     IA5String,
1595:             * dNSName                         [2]     IA5String,
1596:             * x400Address                     [3]     ORAddress,
1597:             * directoryName                   [4]     Name,
1598:             * ediPartyName                    [5]     EDIPartyName,
1599:             * uniformResourceIdentifier       [6]     IA5String,
1600:             * iPAddress                       [7]     OCTET STRING,
1601:             * registeredID                    [8]     OBJECT IDENTIFIER}
1602:             * 
1603:             * @param tag the no tag 0-8
1604:             * @param value the DEREncodable value as returned by GeneralName.getName()
1605:             * @return String in form rfc822Name=<email> or uri=<uri> etc 
1606:             * @throws IOException 
1607:             * @see #getSubjectAlternativeName
1608:             */
1609:            public static String getGeneralNameString(int tag,
1610:                    DEREncodable value) throws IOException {
1611:                String ret = null;
1612:                switch (tag) {
1613:                case 0:
1614:                    ASN1Sequence seq = getAltnameSequence(value.getDERObject()
1615:                            .getEncoded());
1616:                    String upn = getUPNStringFromSequence(seq);
1617:                    // OtherName can be something else besides UPN
1618:                    if (upn != null) {
1619:                        ret = CertTools.UPN + "=" + upn;
1620:                    }
1621:                    break;
1622:                case 1:
1623:                    ret = CertTools.EMAIL + "="
1624:                            + DERIA5String.getInstance(value).getString();
1625:                    break;
1626:                case 2:
1627:                    ret = CertTools.DNS + "="
1628:                            + DERIA5String.getInstance(value).getString();
1629:                    break;
1630:                case 3: // SubjectAltName of type x400Address not supported
1631:                    break;
1632:                case 4: // SubjectAltName of type directoryName not supported
1633:                    break;
1634:                case 5: // SubjectAltName of type ediPartyName not supported
1635:                    break;
1636:                case 6:
1637:                    ret = CertTools.URI + "="
1638:                            + DERIA5String.getInstance(value).getString();
1639:                    break;
1640:                case 7:
1641:                    ASN1OctetString oct = ASN1OctetString.getInstance(value);
1642:                    ret = CertTools.IPADDR + "="
1643:                            + StringTools.ipOctetsToString(oct.getOctets());
1644:                    break;
1645:                default: // SubjectAltName of unknown type
1646:                    break;
1647:                }
1648:                return ret;
1649:            }
1650:
1651:            /**
1652:             * Check the certificate with CA certificate.
1653:             *
1654:             * @param certificate cert to verify
1655:             * @param caCertPath collection of X509Certificate
1656:             * @return true if verified OK, false if not
1657:             */
1658:            public static boolean verify(X509Certificate certificate,
1659:                    Collection caCertPath) throws Exception {
1660:                try {
1661:                    ArrayList certlist = new ArrayList();
1662:                    // Create CertPath
1663:                    certlist.add(certificate);
1664:                    // Add other certs...			
1665:                    CertificateFactory cf = CertificateFactory.getInstance(
1666:                            "X.509", "BC");
1667:                    java.security.cert.CertPath cp = cf
1668:                            .generateCertPath(certlist);
1669:                    // Create TrustAnchor. Since EJBCA use BouncyCastle provider, we assume
1670:                    // certificate already in correct order
1671:                    X509Certificate[] cac = (X509Certificate[]) caCertPath
1672:                            .toArray(new X509Certificate[] {});
1673:                    java.security.cert.TrustAnchor anchor = new java.security.cert.TrustAnchor(
1674:                            cac[0], null);
1675:                    // Set the PKIX parameters
1676:                    java.security.cert.PKIXParameters params = new java.security.cert.PKIXParameters(
1677:                            java.util.Collections.singleton(anchor));
1678:                    params.setRevocationEnabled(false);
1679:                    java.security.cert.CertPathValidator cpv = java.security.cert.CertPathValidator
1680:                            .getInstance("PKIX", "BC");
1681:                    java.security.cert.PKIXCertPathValidatorResult result = (java.security.cert.PKIXCertPathValidatorResult) cpv
1682:                            .validate(cp, params);
1683:                    log
1684:                            .debug("Certificate verify result: "
1685:                                    + result.toString());
1686:                } catch (java.security.cert.CertPathValidatorException cpve) {
1687:                    throw new Exception(
1688:                            "Invalid certificate or certificate not issued by specified CA: "
1689:                                    + cpve.getMessage());
1690:                } catch (Exception e) {
1691:                    throw new Exception("Error checking certificate chain: "
1692:                            + e.getMessage());
1693:                }
1694:                return true;
1695:            }
1696:
1697:            /**
1698:             * Return the CRL distribution point URL form a certificate.
1699:             */
1700:            public static URL getCrlDistributionPoint(
1701:                    X509Certificate certificate)
1702:                    throws CertificateParsingException {
1703:                try {
1704:                    DERObject obj = getExtensionValue(certificate,
1705:                            X509Extensions.CRLDistributionPoints.getId());
1706:                    if (obj == null) {
1707:                        return null;
1708:                    }
1709:                    ASN1Sequence distributionPoints = (ASN1Sequence) obj;
1710:                    for (int i = 0; i < distributionPoints.size(); i++) {
1711:                        ASN1Sequence distrPoint = (ASN1Sequence) distributionPoints
1712:                                .getObjectAt(i);
1713:                        for (int j = 0; j < distrPoint.size(); j++) {
1714:                            ASN1TaggedObject tagged = (ASN1TaggedObject) distrPoint
1715:                                    .getObjectAt(j);
1716:                            if (tagged.getTagNo() == 0) {
1717:                                String url = getStringFromGeneralNames(tagged
1718:                                        .getObject());
1719:                                if (url != null) {
1720:                                    return new URL(url);
1721:                                }
1722:                            }
1723:                        }
1724:                    }
1725:                } catch (Exception e) {
1726:                    log.error("Error parsing CrlDistributionPoint", e);
1727:                    throw new CertificateParsingException(e.toString());
1728:                }
1729:                return null;
1730:            }
1731:
1732:            /** Returns OCSP URL that is inside AuthorithInformationAccess extension, or null.
1733:             * 
1734:             * @param cert
1735:             * @return
1736:             * @throws CertificateParsingException
1737:             */
1738:            public static String getAuthorityInformationAccessOcspUrl(
1739:                    X509Certificate cert) throws CertificateParsingException {
1740:                try {
1741:                    DERObject obj = getExtensionValue(cert,
1742:                            X509Extensions.AuthorityInfoAccess.getId());
1743:                    if (obj == null) {
1744:                        return null;
1745:                    }
1746:                    AuthorityInformationAccess aia = AuthorityInformationAccess
1747:                            .getInstance(obj);
1748:                    AccessDescription[] ad = aia.getAccessDescriptions();
1749:                    if ((ad == null) || (ad.length < 1)) {
1750:                        return null;
1751:                    }
1752:                    if (!ad[0].getAccessMethod().equals(
1753:                            X509ObjectIdentifiers.ocspAccessMethod)) {
1754:                        return null;
1755:                    }
1756:                    GeneralName gn = ad[0].getAccessLocation();
1757:                    if (gn.getTagNo() != 6) {
1758:                        return null;
1759:                    }
1760:                    DERIA5String str = DERIA5String.getInstance(gn
1761:                            .getDERObject());
1762:                    return str.getString();
1763:                } catch (Exception e) {
1764:                    log.error("Error parsing AuthorityInformationAccess", e);
1765:                    throw new CertificateParsingException(e.toString());
1766:                }
1767:            }
1768:
1769:            /**
1770:             * Return an Extension DERObject from a certificate
1771:             */
1772:            protected static DERObject getExtensionValue(X509Certificate cert,
1773:                    String oid) throws IOException {
1774:                if (cert == null) {
1775:                    return null;
1776:                }
1777:                byte[] bytes = cert.getExtensionValue(oid);
1778:                if (bytes == null) {
1779:                    return null;
1780:                }
1781:                ASN1InputStream aIn = new ASN1InputStream(
1782:                        new ByteArrayInputStream(bytes));
1783:                ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
1784:                aIn = new ASN1InputStream(new ByteArrayInputStream(octs
1785:                        .getOctets()));
1786:                return aIn.readObject();
1787:            } //getExtensionValue
1788:
1789:            private static String getStringFromGeneralNames(DERObject names) {
1790:                ASN1Sequence namesSequence = ASN1Sequence.getInstance(
1791:                        (ASN1TaggedObject) names, false);
1792:                if (namesSequence.size() == 0) {
1793:                    return null;
1794:                }
1795:                DERTaggedObject taggedObject = (DERTaggedObject) namesSequence
1796:                        .getObjectAt(0);
1797:                return new String(ASN1OctetString.getInstance(taggedObject,
1798:                        false).getOctets());
1799:            } //getStringFromGeneralNames
1800:
1801:            /**
1802:             * Generate SHA1 fingerprint in string representation.
1803:             *
1804:             * @param ba Byte array containing DER encoded X509Certificate.
1805:             *
1806:             * @return String containing hex format of SHA1 fingerprint.
1807:             */
1808:            public static String getCertFingerprintAsString(byte[] ba) {
1809:                try {
1810:                    X509Certificate cert = getCertfromByteArray(ba);
1811:                    byte[] res = generateSHA1Fingerprint(cert.getEncoded());
1812:
1813:                    return new String(Hex.encode(res));
1814:                } catch (CertificateEncodingException cee) {
1815:                    log.error("Error encoding X509 certificate.", cee);
1816:                } catch (CertificateException cee) {
1817:                    log.error("Error decoding X509 certificate.", cee);
1818:                }
1819:
1820:                return null;
1821:            }
1822:
1823:            /**
1824:             * Generate SHA1 fingerprint of certificate in string representation.
1825:             *
1826:             * @param cert X509Certificate.
1827:             *
1828:             * @return String containing hex format of SHA1 fingerprint, or null if input is null.
1829:             */
1830:            public static String getFingerprintAsString(X509Certificate cert) {
1831:                if (cert == null)
1832:                    return null;
1833:                try {
1834:                    byte[] res = generateSHA1Fingerprint(cert.getEncoded());
1835:
1836:                    return new String(Hex.encode(res));
1837:                } catch (CertificateEncodingException cee) {
1838:                    log.error("Error encoding X509 certificate.", cee);
1839:                }
1840:
1841:                return null;
1842:            }
1843:
1844:            /**
1845:             * Generate SHA1 fingerprint of CRL in string representation.
1846:             *
1847:             * @param crl X509CRL.
1848:             *
1849:             * @return String containing hex format of SHA1 fingerprint.
1850:             */
1851:            public static String getFingerprintAsString(X509CRL crl) {
1852:                try {
1853:                    byte[] res = generateSHA1Fingerprint(crl.getEncoded());
1854:
1855:                    return new String(Hex.encode(res));
1856:                } catch (CRLException ce) {
1857:                    log.error("Error encoding X509 CRL.", ce);
1858:                }
1859:
1860:                return null;
1861:            }
1862:
1863:            /**
1864:             * Generate SHA1 fingerprint of byte array in string representation.
1865:             *
1866:             * @param byte array to fingerprint.
1867:             *
1868:             * @return String containing hex format of SHA1 fingerprint.
1869:             */
1870:            public static String getFingerprintAsString(byte[] in) {
1871:                byte[] res = generateSHA1Fingerprint(in);
1872:                return new String(Hex.encode(res));
1873:            }
1874:
1875:            /**
1876:             * Generate a SHA1 fingerprint from a byte array containing a X.509 certificate
1877:             *
1878:             * @param ba Byte array containing DER encoded X509Certificate.
1879:             *
1880:             * @return Byte array containing SHA1 hash of DER encoded certificate.
1881:             */
1882:            public static byte[] generateSHA1Fingerprint(byte[] ba) {
1883:                log.debug(">generateSHA1Fingerprint");
1884:                try {
1885:                    MessageDigest md = MessageDigest.getInstance("SHA1");
1886:
1887:                    return md.digest(ba);
1888:                } catch (NoSuchAlgorithmException nsae) {
1889:                    log.error("SHA1 algorithm not supported", nsae);
1890:                }
1891:                log.debug("<generateSHA1Fingerprint");
1892:                return null;
1893:            } // generateSHA1Fingerprint
1894:
1895:            /**
1896:             * Generate a MD5 fingerprint from a byte array containing a X.509 certificate
1897:             *
1898:             * @param ba Byte array containing DER encoded X509Certificate.
1899:             *
1900:             * @return Byte array containing MD5 hash of DER encoded certificate.
1901:             */
1902:            public static byte[] generateMD5Fingerprint(byte[] ba) {
1903:                try {
1904:                    MessageDigest md = MessageDigest.getInstance("MD5");
1905:
1906:                    return md.digest(ba);
1907:                } catch (NoSuchAlgorithmException nsae) {
1908:                    log.error("MD5 algorithm not supported", nsae);
1909:                }
1910:
1911:                return null;
1912:            } // generateMD5Fingerprint
1913:
1914:            /** Converts Sun Key usage bits to Bouncy castle key usage kits
1915:             * 
1916:             * @param sku key usage bit fields according to java.security.cert.X509Certificate#getKeyUsage, must be a boolean aray of size 9.
1917:             * @return key usage int according to org.bouncycastle.jce.X509KeyUsage#X509KeyUsage, or -1 if input is null.
1918:             * @see java.security.cert.X509Certificate#getKeyUsage
1919:             * @see org.bouncycastle.jce.X509KeyUsage#X509KeyUsage
1920:             */
1921:            public static int sunKeyUsageToBC(boolean[] sku) {
1922:                if (sku == null) {
1923:                    return -1;
1924:                }
1925:                int bcku = 0;
1926:                if (sku[0] == true)
1927:                    bcku = bcku | X509KeyUsage.digitalSignature;
1928:                if (sku[1] == true)
1929:                    bcku = bcku | X509KeyUsage.nonRepudiation;
1930:                if (sku[2] == true)
1931:                    bcku = bcku | X509KeyUsage.keyEncipherment;
1932:                if (sku[3] == true)
1933:                    bcku = bcku | X509KeyUsage.dataEncipherment;
1934:                if (sku[4] == true)
1935:                    bcku = bcku | X509KeyUsage.keyAgreement;
1936:                if (sku[5] == true)
1937:                    bcku = bcku | X509KeyUsage.keyCertSign;
1938:                if (sku[6] == true)
1939:                    bcku = bcku | X509KeyUsage.cRLSign;
1940:                if (sku[7] == true)
1941:                    bcku = bcku | X509KeyUsage.encipherOnly;
1942:                if (sku[8] == true)
1943:                    bcku = bcku | X509KeyUsage.decipherOnly;
1944:                return bcku;
1945:            }
1946:
1947:            /** Converts DERBitString ResonFlags to a RevokedCertInfo constant 
1948:             * 
1949:             * @param reasonFlags DERBITString received from org.bouncycastle.asn1.x509.ReasonFlags.
1950:             * @return int according to org.ejbca.core.model.ca.crl.RevokedCertInfo
1951:             */
1952:            public static int bitStringToRevokedCertInfo(
1953:                    DERBitString reasonFlags) {
1954:                int ret = RevokedCertInfo.REVOKATION_REASON_UNSPECIFIED;
1955:                if (reasonFlags == null) {
1956:                    return ret;
1957:                }
1958:                int val = reasonFlags.intValue();
1959:                if ((val & ReasonFlags.aACompromise) != 0) {
1960:                    ret = RevokedCertInfo.REVOKATION_REASON_AACOMPROMISE;
1961:                }
1962:                if ((val & ReasonFlags.affiliationChanged) != 0) {
1963:                    ret = RevokedCertInfo.REVOKATION_REASON_AFFILIATIONCHANGED;
1964:                }
1965:                if ((val & ReasonFlags.cACompromise) != 0) {
1966:                    ret = RevokedCertInfo.REVOKATION_REASON_CACOMPROMISE;
1967:                }
1968:                if ((val & ReasonFlags.certificateHold) != 0) {
1969:                    ret = RevokedCertInfo.REVOKATION_REASON_CERTIFICATEHOLD;
1970:                }
1971:                if ((val & ReasonFlags.cessationOfOperation) != 0) {
1972:                    ret = RevokedCertInfo.REVOKATION_REASON_CESSATIONOFOPERATION;
1973:                }
1974:                if ((val & ReasonFlags.keyCompromise) != 0) {
1975:                    ret = RevokedCertInfo.REVOKATION_REASON_KEYCOMPROMISE;
1976:                }
1977:                if ((val & ReasonFlags.privilegeWithdrawn) != 0) {
1978:                    ret = RevokedCertInfo.REVOKATION_REASON_PRIVILEGESWITHDRAWN;
1979:                }
1980:                if ((val & ReasonFlags.super seded) != 0) {
1981:                    ret = RevokedCertInfo.REVOKATION_REASON_SUPERSEDED;
1982:                }
1983:                if ((val & ReasonFlags.unused) != 0) {
1984:                    ret = RevokedCertInfo.REVOKATION_REASON_UNSPECIFIED;
1985:                }
1986:                return ret;
1987:            }
1988:
1989:            /**
1990:             * Method used to insert a CN postfix into DN by extracting the first found CN appending cnpostfix and then replacing the original CN 
1991:             * with the new one in DN.
1992:             * 
1993:             * If no CN could be found in DN then should the given DN be returned untouched
1994:             * 
1995:             * @param dn the DN to manipulate, cannot be null
1996:             * @param cnpostfix the postfix to insert, cannot be null
1997:             * @return the new DN
1998:             */
1999:            public static String insertCNPostfix(String dn, String cnpostfix) {
2000:                String newdn = null;
2001:
2002:                if ((dn != null) && (cnpostfix != null)) {
2003:                    String o;
2004:                    X509NameTokenizer xt = new X509NameTokenizer(dn);
2005:                    boolean alreadyreplaced = false;
2006:                    while (xt.hasMoreTokens()) {
2007:                        o = xt.nextToken();
2008:                        if (!alreadyreplaced && (o.length() > 3)
2009:                                && o.substring(0, 3).equalsIgnoreCase("cn=")) {
2010:                            o += cnpostfix;
2011:                            alreadyreplaced = true;
2012:                        }
2013:                        if (newdn == null) {
2014:                            newdn = o;
2015:                        } else {
2016:                            newdn += "," + o;
2017:                        }
2018:                    }
2019:                }
2020:
2021:                return newdn;
2022:            }
2023:
2024:            /** Simple method that looks at the certificate and determines, from EJBCA's standpoint, which signature algorithm it is
2025:             * 
2026:             * @param cert the cert to examine
2027:             * @return Signature algorithm from CATokenInfo.SIGALG_SHA1_WITH_RSA etc.
2028:             */
2029:            public static String getSignatureAlgorithm(X509Certificate cert) {
2030:                // Assume that the same hash algorithm is used for signing that was used to sign this CA cert
2031:                String certSignatureAlgorithm = cert.getSigAlgName();
2032:                String signatureAlgorithm = null;
2033:                PublicKey publickey = cert.getPublicKey();
2034:                if (publickey instanceof  RSAPublicKey) {
2035:                    if (certSignatureAlgorithm.indexOf("256") == -1) {
2036:                        signatureAlgorithm = CATokenInfo.SIGALG_SHA1_WITH_RSA;
2037:                    } else {
2038:                        signatureAlgorithm = CATokenInfo.SIGALG_SHA256_WITH_RSA;
2039:                    }
2040:                } else {
2041:                    if (certSignatureAlgorithm.indexOf("256") == -1) {
2042:                        signatureAlgorithm = CATokenInfo.SIGALG_SHA1_WITH_ECDSA;
2043:                    } else {
2044:                        signatureAlgorithm = CATokenInfo.SIGALG_SHA256_WITH_ECDSA;
2045:                    }
2046:                }
2047:                log.debug("getSignatureAlgorithm: " + signatureAlgorithm);
2048:                return signatureAlgorithm;
2049:            }
2050:
2051:            /**
2052:             * class for breaking up an X500 Name into it's component tokens, ala
2053:             * java.util.StringTokenizer. Taken from BouncyCastle, but does NOT
2054:             * use or consider escaped characters. Used for reversing DNs without unescaping.
2055:             */
2056:            private static class BasicX509NameTokenizer {
2057:                private String oid;
2058:                private int index;
2059:                private StringBuffer buf = new StringBuffer();
2060:
2061:                public BasicX509NameTokenizer(String oid) {
2062:                    this .oid = oid;
2063:                    this .index = -1;
2064:                }
2065:
2066:                public boolean hasMoreTokens() {
2067:                    return (index != oid.length());
2068:                }
2069:
2070:                public String nextToken() {
2071:                    if (index == oid.length()) {
2072:                        return null;
2073:                    }
2074:
2075:                    int end = index + 1;
2076:                    boolean quoted = false;
2077:                    boolean escaped = false;
2078:
2079:                    buf.setLength(0);
2080:
2081:                    while (end != oid.length()) {
2082:                        char c = oid.charAt(end);
2083:
2084:                        if (c == '"') {
2085:                            if (!escaped) {
2086:                                buf.append(c);
2087:                                quoted = !quoted;
2088:                            } else {
2089:                                buf.append(c);
2090:                            }
2091:                            escaped = false;
2092:                        } else {
2093:                            if (escaped || quoted) {
2094:                                buf.append(c);
2095:                                escaped = false;
2096:                            } else if (c == '\\') {
2097:                                buf.append(c);
2098:                                escaped = true;
2099:                            } else if ((c == ',') && (!escaped)) {
2100:                                break;
2101:                            } else {
2102:                                buf.append(c);
2103:                            }
2104:                        }
2105:                        end++;
2106:                    }
2107:
2108:                    index = end;
2109:                    return buf.toString().trim();
2110:                }
2111:            }
2112:
2113:            /**
2114:             * Obtains a Vector with the DERObjectIdentifiers for 
2115:             * dNObjects names.
2116:             * 
2117:             * @return Vector with DERObjectIdentifiers defining the known order we require
2118:             */
2119:            private static Vector getDefaultX509FieldOrder() {
2120:                Vector fieldOrder = new Vector();
2121:                String[] dNObjects = DnComponents.getDnObjects();
2122:                for (int i = 0; i < dNObjects.length; i++) {
2123:                    fieldOrder.add(DnComponents.getOid(dNObjects[i]));
2124:                }
2125:                return fieldOrder;
2126:            }
2127:
2128:            /**
2129:             * Obtains a Vector with the DERObjectIdentifiers for 
2130:             * dNObjects names, in the specified order
2131:             * 
2132:             * @param ldaporder if true the returned order are as defined in LDAP RFC (CN=foo,O=bar,C=SE), otherwise the order is a defined in X.500 (C=SE,O=bar,CN=foo).
2133:             * @return Vector with DERObjectIdentifiers defining the known order we require
2134:             */
2135:            public static Vector getX509FieldOrder(boolean ldaporder) {
2136:                Vector fieldOrder = new Vector();
2137:                String[] dNObjects = DnComponents.getDnObjects(ldaporder);
2138:                for (int i = 0; i < dNObjects.length; i++) {
2139:                    fieldOrder.add(DnComponents.getOid(dNObjects[i]));
2140:                }
2141:                return fieldOrder;
2142:            }
2143:
2144:            /**
2145:             * Obtain a X509Name reordered, if some fields from original X509Name 
2146:             * doesn't appear in "ordering" parameter, they will be added at end 
2147:             * in the original order.
2148:             *   
2149:             * @param x509Name the X509Name that is unordered 
2150:             * @param ordering Vector of DERObjectIdentifier defining the desired order of components
2151:             * @return X509Name with ordered conmponents according to the orcering vector
2152:             */
2153:            private static X509Name getOrderedX509Name(X509Name x509Name,
2154:                    Vector ordering, X509NameEntryConverter converter) {
2155:
2156:                //-- Null prevent
2157:                if (ordering == null) {
2158:                    ordering = new Vector();
2159:                }
2160:
2161:                //-- New order for the X509 Fields
2162:                Vector newOrdering = new Vector();
2163:                Vector newValues = new Vector();
2164:
2165:                Hashtable ht = new Hashtable();
2166:                Iterator it = ordering.iterator();
2167:
2168:                //-- Add ordered fields
2169:                while (it.hasNext()) {
2170:                    DERObjectIdentifier oid = (DERObjectIdentifier) it.next();
2171:
2172:                    if (!ht.containsKey(oid)) {
2173:                        Vector valueList = getX509NameFields(x509Name, oid);
2174:                        //-- Only add the OID if has not null value
2175:                        if (valueList != null) {
2176:                            Iterator itVals = valueList.iterator();
2177:                            while (itVals.hasNext()) {
2178:                                Object value = itVals.next();
2179:                                ht.put(oid, value);
2180:                                newOrdering.add(oid);
2181:                                newValues.add(value);
2182:                            }
2183:                        }
2184:                    } // if ht.containsKey
2185:                } // while it.hasNext
2186:
2187:                Vector allOids = x509Name.getOIDs();
2188:
2189:                //-- Add unexpected fields to the end
2190:                for (int i = 0; i < allOids.size(); i++) {
2191:
2192:                    DERObjectIdentifier oid = (DERObjectIdentifier) allOids
2193:                            .get(i);
2194:
2195:                    if (!ht.containsKey(oid)) {
2196:                        Vector valueList = getX509NameFields(x509Name, oid);
2197:
2198:                        //-- Only add the OID if has not null value
2199:                        if (valueList != null) {
2200:                            Iterator itVals = valueList.iterator();
2201:
2202:                            while (itVals.hasNext()) {
2203:                                Object value = itVals.next();
2204:                                ht.put(oid, value);
2205:                                newOrdering.add(oid);
2206:                                newValues.add(value);
2207:                                log
2208:                                        .debug("added --> " + oid + " val: "
2209:                                                + value);
2210:                            }
2211:                        }
2212:                    }
2213:                }
2214:
2215:                //-- Create X509Name with the ordered fields
2216:                X509Name orderedName = new X509Name(newOrdering, newValues,
2217:                        converter);
2218:
2219:                return orderedName;
2220:            }
2221:
2222:            /**
2223:             * Obtain the values for a DN field from X509Name, or null in case
2224:             * of the field does not exist.
2225:             * 
2226:             * @param name
2227:             * @param id
2228:             * @return
2229:             */
2230:            private static Vector getX509NameFields(X509Name name,
2231:                    DERObjectIdentifier id) {
2232:
2233:                Vector oids = name.getOIDs();
2234:                Vector values = name.getValues();
2235:                Vector vRet = null;
2236:
2237:                for (int i = 0; i < oids.size(); i++) {
2238:
2239:                    if (id.equals(oids.elementAt(i))) {
2240:                        if (vRet == null) {
2241:                            vRet = new Vector();
2242:                        }
2243:                        vRet.add(values.get(i));
2244:                    }
2245:
2246:                }
2247:
2248:                return vRet;
2249:
2250:            }
2251:
2252:            /**
2253:             * Obtain the directory string for the directoryName generation
2254:             * form the Subject Alternative Name String.
2255:             * 
2256:             * @param altName
2257:             * @return
2258:             */
2259:            private static String getDirectoryStringFromAltName(String altName) {
2260:
2261:                DNFieldExtractor dnfe = new DNFieldExtractor(altName,
2262:                        DNFieldExtractor.TYPE_SUBJECTALTNAME);
2263:                String directoryName = dnfe.getField(
2264:                        DNFieldExtractor.DIRECTORYNAME, 0);
2265:
2266:                /** TODO: Validate or restrict the directoryName Fields? */
2267:
2268:                return ("".equals(directoryName) ? null : directoryName);
2269:            }
2270:
2271:        } // CertTools
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.