Source Code Cross Referenced for MEKeyTool.java in  » 6.0-JDK-Modules » j2me » com » sun » midp » mekeytool » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /*
0002:         *   
0003:         *
0004:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006:         * 
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License version
0009:         * 2 only, as published by the Free Software Foundation.
0010:         * 
0011:         * This program is distributed in the hope that it will be useful, but
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014:         * General Public License version 2 for more details (a copy is
0015:         * included at /legal/license.txt).
0016:         * 
0017:         * You should have received a copy of the GNU General Public License
0018:         * version 2 along with this work; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA
0021:         * 
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional
0024:         * information or have any questions.
0025:         */
0026:
0027:        package com.sun.midp.mekeytool;
0028:
0029:        import java.util.*;
0030:        import java.io.*;
0031:
0032:        import java.security.*;
0033:        import java.security.cert.*;
0034:        import java.security.interfaces.RSAPublicKey;
0035:        import java.math.BigInteger;
0036:
0037:        import com.sun.midp.publickeystore.*;
0038:
0039:        /**
0040:         * Manages the initial public keystore needed to bootstrap this MIDP
0041:         * security implementation. It provides both a Java and a command line interface.
0042:         * <p>
0043:         * The anchor of trust on an ME (mobile equipment) are the public keys
0044:         * loaded on it by the manufacturer, in MIDP implementation this is known
0045:         * as the <i>ME keystore</i>. This tool does for the MIDP implementation 
0046:         * what the manufacturer must do for the ME so that trusted MIDP 
0047:         * applications can be authenticated.
0048:         * @see #main(String[])
0049:         */
0050:        public class MEKeyTool {
0051:            /** default MIDP application directory, see Utility.c getStorageRoot() */
0052:            private final static String defaultAppDir = "appdb";
0053:
0054:            /** default ME keystore filename, see com.sun.midp.Main.java */
0055:            private final static String defaultKeystoreFilename = "_main.ks";
0056:
0057:            /**
0058:             * Maps byte codes that follow id-at (0x55 0x04) to corresponding name
0059:             * component tags (e.g. Common Name, or CN, is 0x55, 0x04, 0x03 and
0060:             * Country, or C, is 0x55, 0x04, 0x06). See getName. See X.520 for
0061:             * the OIDs and RFC 1779 for the printable labels. Place holders for
0062:             * unknown labels have a -1 as the first byte.
0063:             */
0064:            private static final String[] AttrLabel = { null, null, null, "CN", // Common name: id-at 3
0065:                    "SN", // Surname: id-at 4
0066:                    null, "C", // Country: id-at 6
0067:                    "L", // Locality: id-at 7
0068:                    "ST", // State or province: id-at 8
0069:                    "STREET", // Street address: id-at 9
0070:                    "O", // Organization: id-at 10
0071:                    "OU", // Organization unit: id-at 11
0072:            };
0073:
0074:            /** Email attribute label. */
0075:            private static final String EMAIL_ATTR_LABEL = "EmailAddress";
0076:
0077:            /** Email attribute object identifier. */
0078:            private static final byte[] EMAIL_ATTR_OID = { (byte) 0x2a,
0079:                    (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7,
0080:                    (byte) 0x0d, (byte) 0x01, (byte) 0x09, (byte) 0x01 };
0081:
0082:            /** read-writable ME keystore that does not depend on SSL */
0083:            private PublicKeyStoreBuilderBase keystore;
0084:
0085:            /** the state for getFirstKey and getNextKey */
0086:            private int nextKeyToGet;
0087:
0088:            /**
0089:             * Performs the command specified in the first argument.
0090:             * <p>
0091:             * Exits with a 0 status if the command was successful.
0092:             * Exits and prints out an error message with a -1 status if the command
0093:             * failed.</p>
0094:             * <p><pre>
0095:             *MEKeyTool supports the following commands:
0096:             *
0097:             *  no args  - same has -help
0098:             *  -import  - import a public key from a JCE keystore
0099:             *              into a ME keystore
0100:             *  -delete  - delete a key from a ME keystore
0101:             *  -help    - print a usage summary
0102:             *  -list    - list the owner and validity period of each
0103:             *              key in a ME keystore
0104:             *
0105:             *Parameters for (commands):
0106:             *
0107:             *  -MEkeystore &lt;filename of the ME keystore&gt; (optional for all)
0108:             *  -keystore   &lt;filename of the JCA keystore&gt; (optional import)
0109:             *  -storepass  &lt;password for the JCA keystore&gt; (optional import)
0110:             *  -alias      &lt;short string ID of a key in a JCA keystore&gt; (import)
0111:             *  -domain     &lt;security domain of the ME key&gt; (optional import)
0112:             *  -owner      &lt;name of the owner of a ME key&gt; (delete)
0113:             *  -number     &lt;key number starting a 1 of a ME key&gt; (delete)
0114:             *
0115:             *Defaults:
0116:             *
0117:             *  -MEkeystore appdir/main.ks
0118:             *  -keystore   &lt;user's home dir&gt;/.keystore
0119:             *  -domain     untrusted
0120:             * </pre>
0121:             * @param args command line arguments
0122:             */
0123:            public static void main(String[] args) {
0124:                File meKeystoreFile = null;
0125:
0126:                if (args.length == 0) {
0127:                    System.out.println("\n  Error: No command given");
0128:                    displayUsage();
0129:                    System.exit(-1);
0130:                }
0131:
0132:                if (args[0].equals("-help")) {
0133:                    // user just needs help with the arguments
0134:                    displayUsage();
0135:                    System.exit(0);
0136:                }
0137:
0138:                // start with the default keystore file
0139:                meKeystoreFile = new File(defaultAppDir,
0140:                        defaultKeystoreFilename);
0141:
0142:                try {
0143:                    if (args[0].equals("-import")) {
0144:                        importCommand(meKeystoreFile, args);
0145:                        System.exit(0);
0146:                    }
0147:
0148:                    if (args[0].equals("-delete")) {
0149:                        deleteCommand(meKeystoreFile, args);
0150:                        System.exit(0);
0151:                    }
0152:
0153:                    if (args[0].equals("-list")) {
0154:                        listCommand(meKeystoreFile, args);
0155:                        System.exit(0);
0156:                    }
0157:
0158:                    throw new UsageException("  Invalid command: " + args[0]);
0159:                } catch (Exception e) {
0160:                    System.out.println("\n  Error: " + e.getMessage());
0161:
0162:                    if (e instanceof  UsageException) {
0163:                        displayUsage();
0164:                    }
0165:
0166:                    System.exit(-1);
0167:                }
0168:            }
0169:
0170:            /**
0171:             * Display the usage text to standard output.
0172:             */
0173:            private static void displayUsage() {
0174:                System.out
0175:                        .println("\n  MEKeyTool argument combinations:\n\n"
0176:                                + "    -help\n"
0177:                                + "    -import [-MEkeystore <filename>] "
0178:                                + "[-keystore <filename>]\n"
0179:                                + "            [-storepass <password>] -alias <key alias> "
0180:                                + "[-domain <domain>]\n"
0181:                                + "    -list [-MEkeystore <filename>]\n"
0182:                                + "    -delete [-MEkeystore <filename>]\n"
0183:                                + "            (-owner <owner name> | -number <key number>)\n"
0184:                                + "\n"
0185:                                + "  The default for -MEkeystore is \"appdb/_main.ks\".\n"
0186:                                + "  The default for -keystore is \"$HOME/.keystore\".\n");
0187:            }
0188:
0189:            /**
0190:             * Process the command line arguments for the import command and
0191:             * then imports a public key from a JCA keystore to ME keystore.
0192:             * This method assumes the first argument is the import command
0193:             * and skips it.
0194:             * @param meKeystoreFile ME keystore abstract file name
0195:             * @param args command line arguments
0196:             * @exception Exception if an unrecoverable error occurs
0197:             */
0198:            private static void importCommand(File meKeystoreFile, String[] args)
0199:                    throws Exception {
0200:                String jcaKeystoreFilename = null;
0201:                String keystorePassword = null;
0202:                String alias = null;
0203:                String domain = "identified";
0204:                MEKeyTool keyTool;
0205:
0206:                for (int i = 1; i < args.length; i++) {
0207:                    try {
0208:                        if (args[i].equals("-MEkeystore")) {
0209:                            i++;
0210:                            meKeystoreFile = new File(args[i]);
0211:                        } else if (args[i].equals("-keystore")) {
0212:                            i++;
0213:                            jcaKeystoreFilename = args[i];
0214:                        } else if (args[i].equals("-storepass")) {
0215:                            i++;
0216:                            keystorePassword = args[i];
0217:                        } else if (args[i].equals("-alias")) {
0218:                            i++;
0219:                            alias = args[i];
0220:                        } else if (args[i].equals("-domain")) {
0221:                            i++;
0222:                            domain = args[i];
0223:                        } else {
0224:                            throw new UsageException(
0225:                                    "Invalid argument for import command: "
0226:                                            + args[i]);
0227:                        }
0228:                    } catch (ArrayIndexOutOfBoundsException e) {
0229:                        throw new UsageException("Missing value for "
0230:                                + args[--i]);
0231:                    }
0232:                }
0233:
0234:                if (jcaKeystoreFilename == null) {
0235:                    jcaKeystoreFilename = System.getProperty("user.home")
0236:                            + File.separator + ".keystore";
0237:                }
0238:
0239:                if (alias == null) {
0240:                    throw new Exception("J2SE key alias was not given");
0241:                }
0242:
0243:                try {
0244:                    keyTool = new MEKeyTool(meKeystoreFile);
0245:                } catch (FileNotFoundException fnfe) {
0246:                    keyTool = new MEKeyTool();
0247:                }
0248:
0249:                keyTool.importKeyFromJcaKeystore(jcaKeystoreFilename,
0250:                        keystorePassword, alias, domain);
0251:                keyTool.saveKeystore(meKeystoreFile);
0252:            }
0253:
0254:            /**
0255:             * Process the command line arguments for the delete command and
0256:             * then delete a public key from a ME keystore.
0257:             * This method assumes the first argument is the delete command
0258:             * and skips it.
0259:             * @param meKeystoreFile ME keystore abstract file name
0260:             * @param args command line arguments
0261:             * @exception Exception if an unrecoverable error occurs
0262:             */
0263:            private static void deleteCommand(File meKeystoreFile, String[] args)
0264:                    throws Exception {
0265:                String owner = null;
0266:                int keyNumber = -1;
0267:                boolean keyNumberGiven = false;
0268:                MEKeyTool keyTool;
0269:
0270:                for (int i = 1; i < args.length; i++) {
0271:                    try {
0272:                        if (args[i].equals("-MEkeystore")) {
0273:                            i++;
0274:                            meKeystoreFile = new File(args[i]);
0275:                        } else if (args[i].equals("-owner")) {
0276:                            i++;
0277:                            owner = args[i];
0278:                        } else if (args[i].equals("-number")) {
0279:                            keyNumberGiven = true;
0280:                            i++;
0281:                            try {
0282:                                keyNumber = Integer.parseInt(args[i]);
0283:                            } catch (NumberFormatException e) {
0284:                                throw new UsageException(
0285:                                        "Invalid number for the -number argument: "
0286:                                                + args[i]);
0287:                            }
0288:                        } else {
0289:                            throw new UsageException(
0290:                                    "Invalid argument for the delete command: "
0291:                                            + args[i]);
0292:                        }
0293:                    } catch (ArrayIndexOutOfBoundsException e) {
0294:                        throw new UsageException("Missing value for "
0295:                                + args[--i]);
0296:                    }
0297:                }
0298:
0299:                if (owner == null && !keyNumberGiven) {
0300:                    throw new UsageException(
0301:                            "Neither key -owner or -number was not given");
0302:                }
0303:
0304:                if (owner != null && keyNumberGiven) {
0305:                    throw new UsageException(
0306:                            "-owner and -number cannot be used " + "together");
0307:                }
0308:
0309:                keyTool = new MEKeyTool(meKeystoreFile);
0310:
0311:                if (owner != null) {
0312:                    if (!keyTool.deleteKey(owner)) {
0313:                        throw new UsageException("Key not found for: " + owner);
0314:                    }
0315:                } else {
0316:                    try {
0317:                        keyTool.deleteKey(keyNumber - 1);
0318:                    } catch (ArrayIndexOutOfBoundsException e) {
0319:                        throw new UsageException(
0320:                                "Invalid number for the -number "
0321:                                        + "delete option: " + keyNumber);
0322:                    }
0323:                }
0324:
0325:                keyTool.saveKeystore(meKeystoreFile);
0326:            }
0327:
0328:            /**
0329:             * Process the command line arguments for the list command and
0330:             * then list the public keys of a ME keystore.
0331:             * This method assumes the first argument is the list command
0332:             * and skips it.
0333:             * @param meKeystoreFile ME keystore abstract file name
0334:             * @param args command line arguments
0335:             * @exception Exception if an unrecoverable error occurs
0336:             */
0337:            private static void listCommand(File meKeystoreFile, String[] args)
0338:                    throws Exception {
0339:                MEKeyTool keyTool;
0340:                PublicKeyInfo key;
0341:
0342:                for (int i = 1; i < args.length; i++) {
0343:                    try {
0344:                        if (args[i].equals("-MEkeystore")) {
0345:                            i++;
0346:                            meKeystoreFile = new File(args[i]);
0347:                        } else {
0348:                            throw new UsageException(
0349:                                    "Invalid argument for the list "
0350:                                            + "command: " + args[i]);
0351:                        }
0352:                    } catch (ArrayIndexOutOfBoundsException e) {
0353:                        throw new UsageException("Missing value for "
0354:                                + args[--i]);
0355:                    }
0356:                }
0357:
0358:                keyTool = new MEKeyTool(meKeystoreFile);
0359:                key = keyTool.getFirstKey();
0360:                for (int i = 1; key != null; i++) {
0361:                    System.out.println("Key " + Integer.toString(i));
0362:                    System.out.println(formatKeyInfo(key));
0363:                    key = keyTool.getNextKey();
0364:                }
0365:
0366:                System.out.println("");
0367:            }
0368:
0369:            /**
0370:             * Constructs a MEKeyTool with an empty keystore.
0371:             */
0372:            public MEKeyTool() {
0373:                keystore = new PublicKeyStoreBuilderBase();
0374:            }
0375:
0376:            /**
0377:             * Constructs a MEKeyTool and loads its keystore using a filename.
0378:             * @param meKeystoreFilename serialized keystore file
0379:             * @exception FileNotFoundException if the file does not exist, is a
0380:             * directory rather than a regular file, or for some other reason
0381:             * cannot be opened for reading.
0382:             * @exception IOException if the key storage was corrupted
0383:             */
0384:            public MEKeyTool(String meKeystoreFilename)
0385:                    throws FileNotFoundException, IOException {
0386:
0387:                FileInputStream input;
0388:
0389:                input = new FileInputStream(new File(meKeystoreFilename));
0390:
0391:                try {
0392:                    keystore = new PublicKeyStoreBuilderBase(input);
0393:                } finally {
0394:                    input.close();
0395:                }
0396:            };
0397:
0398:            /**
0399:             * Constructs a MEKeyTool and loads its keystore from a file.
0400:             * @param meKeystoreFile serialized keystore file
0401:             * @exception FileNotFoundException if the file does not exist, is a
0402:             * directory rather than a regular file, or for some other reason
0403:             * cannot be opened for reading.
0404:             * @exception IOException if the key storage was corrupted
0405:             */
0406:            public MEKeyTool(File meKeystoreFile) throws FileNotFoundException,
0407:                    IOException {
0408:
0409:                FileInputStream input;
0410:
0411:                input = new FileInputStream(meKeystoreFile);
0412:
0413:                try {
0414:                    keystore = new PublicKeyStoreBuilderBase(input);
0415:                } finally {
0416:                    input.close();
0417:                }
0418:            };
0419:
0420:            /**
0421:             * Constructs a MEKeyTool and loads its keystore from a stream.
0422:             * @param meKeystoreStream serialized keystore stream
0423:             * @exception IOException if the key storage was corrupted
0424:             */
0425:            public MEKeyTool(InputStream meKeystoreStream) throws IOException {
0426:                keystore = new PublicKeyStoreBuilderBase(meKeystoreStream);
0427:            };
0428:
0429:            /**
0430:             * Copies a key from a Standard Edition keystore into the ME keystore.
0431:             * @param jcakeystoreFilename name of the serialized keystore
0432:             * @param keystorePassword password to unlock the keystore
0433:             * @param alias the ID of the key in the SE keystore
0434:             * @param domain security domain of any application authorized
0435:             *               with the corresponding private key
0436:             */
0437:            public void importKeyFromJcaKeystore(String jcakeystoreFilename,
0438:                    String keystorePassword, String alias, String domain)
0439:                    throws IOException, GeneralSecurityException {
0440:                FileInputStream keystoreStream;
0441:                KeyStore jcaKeystore;
0442:
0443:                // Load the keystore
0444:                keystoreStream = new FileInputStream(new File(
0445:                        jcakeystoreFilename));
0446:
0447:                try {
0448:                    jcaKeystore = KeyStore.getInstance(KeyStore
0449:                            .getDefaultType());
0450:
0451:                    if (keystorePassword == null) {
0452:                        jcaKeystore.load(keystoreStream, null);
0453:                    } else {
0454:                        jcaKeystore.load(keystoreStream, keystorePassword
0455:                                .toCharArray());
0456:                    }
0457:                } finally {
0458:                    keystoreStream.close();
0459:                }
0460:
0461:                importKeyFromJcaKeystore(jcaKeystore, alias, domain);
0462:            }
0463:
0464:            /**
0465:             * Copies a key from a Standard Edition keystore into the ME keystore.
0466:             * @param jcaKeystore loaded JCA keystore
0467:             * @param alias the ID of the key in the SE keystore
0468:             * @param domain security domain of any application authorized
0469:             *               with the corresponding private key
0470:             */
0471:            public void importKeyFromJcaKeystore(KeyStore jcaKeystore,
0472:                    String alias, String domain) throws IOException,
0473:                    GeneralSecurityException {
0474:                X509Certificate cert;
0475:                byte[] der;
0476:                TLV tbsCert;
0477:                TLV subjectName;
0478:                RSAPublicKey rsaKey;
0479:                String owner;
0480:                long notBefore;
0481:                long notAfter;
0482:                byte[] rawModulus;
0483:                int i;
0484:                int keyLen;
0485:                byte[] modulus;
0486:                byte[] exponent;
0487:                Vector keys;
0488:
0489:                // get the cert from the keystore
0490:                try {
0491:                    cert = (X509Certificate) jcaKeystore.getCertificate(alias);
0492:                } catch (ClassCastException cce) {
0493:                    throw new CertificateException("Certificate not X.509 type");
0494:                }
0495:
0496:                if (cert == null) {
0497:                    throw new CertificateException("Certificate not found");
0498:                }
0499:
0500:                /*
0501:                 * J2SE reorders the attributes when building a printable name
0502:                 * so we must build a printable name on our own.
0503:                 */
0504:
0505:                /*
0506:                 * TBSCertificate  ::=  SEQUENCE  {
0507:                 *   version         [0]  EXPLICIT Version DEFAULT v1,
0508:                 *   serialNumber         CertificateSerialNumber,
0509:                 *   signature            AlgorithmIdentifier,
0510:                 *   issuer               Name,
0511:                 *   validity             Validity,
0512:                 *   subject              Name,
0513:                 *   subjectPublicKeyInfo SubjectPublicKeyInfo,
0514:                 *   issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
0515:                 *                        -- If present, version shall be v2 or v3
0516:                 *   subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
0517:                 *                        -- If present, version shall be v2 or v3
0518:                 *   extensions      [3]  EXPLICIT Extensions OPTIONAL
0519:                 *                        -- If present, version shall be v3
0520:                 * }
0521:                 */
0522:                der = cert.getTBSCertificate();
0523:                tbsCert = new TLV(der, 0);
0524:
0525:                // walk down the tree of TLVs to find the subject name
0526:                try {
0527:                    // Top level a is Sequence, drop down to the first child
0528:                    subjectName = tbsCert.child;
0529:
0530:                    // skip the version if present.
0531:                    if (subjectName.type == TLV.VERSION_TYPE) {
0532:                        subjectName = subjectName.next;
0533:                    }
0534:
0535:                    // skip the serial number
0536:                    subjectName = subjectName.next;
0537:
0538:                    // skip the signature alg. id.
0539:                    subjectName = subjectName.next;
0540:
0541:                    // skip the issuer
0542:                    subjectName = subjectName.next;
0543:
0544:                    // skip the validity
0545:                    subjectName = subjectName.next;
0546:
0547:                    owner = parseDN(der, subjectName);
0548:                } catch (NullPointerException e) {
0549:                    throw new CertificateException("TBSCertificate corrupt 1");
0550:                } catch (IndexOutOfBoundsException e) {
0551:                    throw new CertificateException("TBSCertificate corrupt 2");
0552:                }
0553:
0554:                notBefore = cert.getNotBefore().getTime();
0555:                notAfter = cert.getNotAfter().getTime();
0556:
0557:                // get the key from the cert
0558:                try {
0559:                    rsaKey = (RSAPublicKey) cert.getPublicKey();
0560:                } catch (ClassCastException cce) {
0561:                    throw new RuntimeException(
0562:                            "Key in certificate is not an RSA key");
0563:                }
0564:
0565:                // get the key parameters from the key
0566:                rawModulus = rsaKey.getModulus().toByteArray();
0567:
0568:                /*
0569:                 * the modulus is given as the minimum positive integer,
0570:                 * will not padded to the bit size of the key, or may have a extra
0571:                 * pad to make it positive. SSL expects the key to be signature
0572:                 * bit size. but we cannot get that from the key, so we should
0573:                 * remove any zero pad bytes and then pad out to a multiple of 8 bytes
0574:                 */
0575:                for (i = 0; i < rawModulus.length && rawModulus[i] == 0; i++)
0576:                    ;
0577:
0578:                keyLen = rawModulus.length - i;
0579:                keyLen = (keyLen + 7) / 8 * 8;
0580:                modulus = new byte[keyLen];
0581:
0582:                int k, j;
0583:                for (k = rawModulus.length - 1, j = keyLen - 1; k >= 0
0584:                        && j >= 0; k--, j--) {
0585:                    modulus[j] = rawModulus[k];
0586:                }
0587:
0588:                exponent = rsaKey.getPublicExponent().toByteArray();
0589:
0590:                // add the key
0591:                keys = keystore.findKeys(owner);
0592:                if (keys != null) {
0593:                    boolean duplicateKey = false;
0594:
0595:                    for (int n = 0; !duplicateKey && n < keys.size(); n++) {
0596:                        PublicKeyInfo key = (PublicKeyInfo) keys.elementAt(n);
0597:
0598:                        if (key.getOwner().equals(owner)) {
0599:                            byte[] temp = key.getModulus();
0600:
0601:                            if (modulus.length == temp.length) {
0602:                                duplicateKey = true;
0603:                                for (int m = 0; j < modulus.length
0604:                                        && m < temp.length; m++) {
0605:                                    if (modulus[m] != temp[m]) {
0606:                                        duplicateKey = false;
0607:                                        break;
0608:                                    }
0609:                                }
0610:                            }
0611:                        }
0612:                    }
0613:
0614:                    if (duplicateKey) {
0615:                        throw new CertificateException(
0616:                                "Owner already has this key in the ME keystore");
0617:                    }
0618:                }
0619:
0620:                keystore.addKey(new PublicKeyInfo(owner, notBefore, notAfter,
0621:                        modulus, exponent, domain));
0622:            }
0623:
0624:            /**
0625:             * Deletes the first public key matching the owner's distinguished name.
0626:             * @param owner name of the key's owner
0627:             * @return true, if the key was deleted, else false
0628:             */
0629:            public boolean deleteKey(String owner) {
0630:                PublicKeyInfo key;
0631:
0632:                for (int i = 0; i < keystore.numberOfKeys(); i++) {
0633:                    key = keystore.getKey(i);
0634:                    if (key.getOwner().equals(owner)) {
0635:                        keystore.deleteKey(i);
0636:                        return true;
0637:                    }
0638:                }
0639:
0640:                return false;
0641:            };
0642:
0643:            /**
0644:             * Deletes a key by key number, 0 being the first public key.
0645:             *
0646:             * @param number number of the key
0647:             *
0648:             * @exception  ArrayIndexOutOfBoundsException  if an invalid number was
0649:             *             given.
0650:             */
0651:            public void deleteKey(int number) {
0652:                keystore.deleteKey(number);
0653:            };
0654:
0655:            /**
0656:             * Gets the first key in the keystore.
0657:             * @return all the information related to the first key
0658:             */
0659:            protected PublicKeyInfo getFirstKey() {
0660:                nextKeyToGet = 0;
0661:                return getNextKey();
0662:            };
0663:
0664:            /**
0665:             * Gets the next key after the previous one returned by
0666:             * {@link #getFirstKey} or this method. If getFirstKey is not called
0667:             * before the first call to this method, null will be returned.
0668:             * @return all the information related to the next key, or null if
0669:             *        there are no more keys
0670:             */
0671:            protected PublicKeyInfo getNextKey() {
0672:                PublicKeyInfo key;
0673:
0674:                try {
0675:                    key = keystore.getKey(nextKeyToGet);
0676:                } catch (ArrayIndexOutOfBoundsException e) {
0677:                    return null;
0678:                }
0679:
0680:                nextKeyToGet++;
0681:
0682:                return key;
0683:            };
0684:
0685:            /**
0686:             * Saves the keystore to a file.
0687:             * @param meKeystoreFile serialized keystore file
0688:             */
0689:            public void saveKeystore(File meKeystoreFile) throws IOException {
0690:                FileOutputStream output;
0691:
0692:                output = new FileOutputStream(meKeystoreFile);
0693:
0694:                keystore.serialize(output);
0695:                output.close();
0696:            }
0697:
0698:            /**
0699:             * Gets the read-write keystore this tool is manipulating.
0700:             * For advanced users.
0701:             * @return read-write keystore 
0702:             */
0703:            public PublicKeyStoreBuilderBase getKeystore() {
0704:                return keystore;
0705:            }
0706:
0707:            /**
0708:             * Creates a string representation of a key that is displayed to a
0709:             * user during a list command. The string does not include the modulus
0710:             * and exponent.
0711:             * @param keyInfo key to display
0712:             * @return printable representation of the key
0713:             */
0714:            public static String formatKeyInfo(PublicKeyInfo keyInfo) {
0715:                return "  Owner: " + keyInfo.getOwner() + "\n  Valid from "
0716:                        + (new Date(keyInfo.getNotBefore())).toString()
0717:                        + " to " + (new Date(keyInfo.getNotAfter())).toString()
0718:                        + "\n  Security Domain: " + keyInfo.getDomain()
0719:                        + "\n  Enabled: " + keyInfo.isEnabled();
0720:            };
0721:
0722:            /**
0723:             * Parses a DER TLV tree into a printable distinguished name.
0724:             *
0725:             * @param buffer DER buffer
0726:             * @param dn sequence of TLV nodes.
0727:             *
0728:             * @return printable name.
0729:             *
0730:             * @exception NullPointerException if the name is corrupt
0731:             * @exception IndexOutOfBoundsException if the name is corrupt
0732:             */
0733:            private String parseDN(byte[] buffer, TLV dn) {
0734:                TLV attribute;
0735:                TLV type;
0736:                TLV value;
0737:                StringBuffer name = new StringBuffer(256);
0738:
0739:                /*
0740:                 * Name ::= CHOICE { RDNSequence } # CHOICE does not encoded
0741:                 *
0742:                 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
0743:                 *
0744:                 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
0745:                 *
0746:                 *   AttributeTypeAndValue ::= SEQUENCE {
0747:                 *     type     AttributeType,
0748:                 *     value    AttributeValue }
0749:                 *
0750:                 * AttributeType ::= OBJECT IDENTIFIER
0751:                 *
0752:                 * AttributeValue ::= ANY DEFINED BY AttributeType
0753:                 *
0754:                 * basically this means that each attribute value is 3 levels down
0755:                 */
0756:
0757:                // sequence drop down a level
0758:                attribute = dn.child;
0759:
0760:                while (attribute != null) {
0761:                    if (attribute != dn.child) {
0762:                        name.append(";");
0763:                    }
0764:
0765:                    /*
0766:                     * we do not handle relative distinguished names yet
0767:                     * which should not be used by CAs anyway
0768:                     * so only take the first element of the sequence
0769:                     */
0770:
0771:                    type = attribute.child.child;
0772:
0773:                    /*
0774:                     * At this point we tag the name component, e.g. C= or hex
0775:                     * if unknown.
0776:                     */
0777:                    if ((type.length == 3)
0778:                            && (buffer[type.valueOffset] == 0x55)
0779:                            && (buffer[type.valueOffset + 1] == 0x04)) {
0780:                        // begins with id-at, so try to see if we have a label
0781:                        int temp = buffer[type.valueOffset + 2] & 0xFF;
0782:                        if ((temp < AttrLabel.length)
0783:                                && (AttrLabel[temp] != null)) {
0784:                            name.append(AttrLabel[temp]);
0785:                        } else {
0786:                            name.append(TLV.hexEncode(buffer, type.valueOffset,
0787:                                    type.length, -1));
0788:                        }
0789:                    } else if (TLV.byteMatch(buffer, type.valueOffset,
0790:                            type.length, EMAIL_ATTR_OID, 0,
0791:                            EMAIL_ATTR_OID.length)) {
0792:                        name.append(EMAIL_ATTR_LABEL);
0793:                    } else {
0794:                        name.append(TLV.hexEncode(buffer, type.valueOffset,
0795:                                type.length, -1));
0796:                    }
0797:
0798:                    name.append("=");
0799:
0800:                    value = attribute.child.child.next;
0801:                    if (value.type == TLV.PRINTSTR_TYPE
0802:                            || value.type == TLV.TELETEXSTR_TYPE
0803:                            || value.type == TLV.UTF8STR_TYPE
0804:                            || value.type == TLV.IA5STR_TYPE
0805:                            || value.type == TLV.UNIVSTR_TYPE) {
0806:                        try {
0807:                            name.append(new String(buffer, value.valueOffset,
0808:                                    value.length, "UTF-8"));
0809:                        } catch (UnsupportedEncodingException e) {
0810:                            throw new RuntimeException(e.toString());
0811:                        }
0812:                    } else {
0813:                        name.append(TLV.hexEncode(buffer, value.valueOffset,
0814:                                value.length, -1));
0815:                    }
0816:
0817:                    attribute = attribute.next;
0818:                }
0819:
0820:                return name.toString();
0821:            }
0822:        }
0823:
0824:        /**
0825:         * Used to represent each Type, Length, Value structure in a DER buffer.
0826:         */
0827:        class TLV {
0828:            /** ASN context specific flag used in types (0x80). */
0829:            static final int CONTEXT = 0x80;
0830:            /** ASN constructed flag used in types (0x20). */
0831:            static final int CONSTRUCTED = 0x20;
0832:            /** ASN constructed flag used in types (0x20). */
0833:            static final int EXPLICIT = CONSTRUCTED;
0834:
0835:            /** ANY_STRING type used as a place holder. [UNIVERSAL 0] */
0836:            static final int ANY_STRING_TYPE = 0x00; // our own impl
0837:
0838:            /** ASN BOOLEAN type used in certificate parsing. [UNIVERSAL 1] */
0839:            static final int BOOLEAN_TYPE = 1;
0840:            /** ASN INTEGER type used in certificate parsing. [UNIVERSAL 2] */
0841:            static final int INTEGER_TYPE = 2;
0842:            /** ASN BIT STRING type used in certificate parsing. [UNIVERSAL 3] */
0843:            static final int BITSTRING_TYPE = 3;
0844:            /** ASN OCTET STRING type used in certificate parsing. [UNIVERSAL 4] */
0845:            static final int OCTETSTR_TYPE = 4;
0846:            /** ASN NULL type used in certificate parsing. [UNIVERSAL 5] */
0847:            static final int NULL_TYPE = 5;
0848:            /** ASN OBJECT ID type used in certificate parsing. [UNIVERSAL 6] */
0849:            static final int OID_TYPE = 6;
0850:            /** ASN UTF8String type used in certificate parsing. [UNIVERSAL 12] */
0851:            static final int UTF8STR_TYPE = 12;
0852:            /**
0853:             * ASN SEQUENCE type used in certificate parsing.
0854:             * [UNIVERSAL CONSTRUCTED 16]
0855:             */
0856:            static final int SEQUENCE_TYPE = CONSTRUCTED + 16;
0857:            /**
0858:             * ASN SET type used in certificate parsing.
0859:             * [UNIVERSAL CONSTRUCTED 17]
0860:             */
0861:            static final int SET_TYPE = CONSTRUCTED + 17;
0862:            /** ASN PrintableString type used in certificate parsing. [UNIVERSAL 19] */
0863:            static final int PRINTSTR_TYPE = 19;
0864:            /** ASN TELETEX STRING type used in certificate parsing. [UNIVERSAL 20] */
0865:            static final int TELETEXSTR_TYPE = 20;
0866:            /** ASN IA5 STRING type used in certificate parsing. [UNIVERSAL 22] */
0867:            static final int IA5STR_TYPE = 22; // Used for EmailAddress
0868:            /** ASN UCT time type used in certificate parsing [UNIVERSAL 23] */
0869:            static final int UCT_TIME_TYPE = 23;
0870:            /**
0871:             * ASN Generalized time type used in certificate parsing.
0872:             * [UNIVERSAL 24]
0873:             */
0874:            static final int GEN_TIME_TYPE = 24;
0875:            /**
0876:             * ASN UniversalString type used in certificate parsing.
0877:             * [UNIVERSAL 28].
0878:             */
0879:            static final int UNIVSTR_TYPE = 28;
0880:            /** ASN BIT STRING type used in certificate parsing. [UNIVERSAL 30] */
0881:            static final int BMPSTR_TYPE = 30;
0882:
0883:            /**
0884:             * Context specific explicit type for certificate version. 
0885:             * [CONTEXT EXPLICIT 0]
0886:             */
0887:            static final int VERSION_TYPE = CONTEXT + EXPLICIT + 0;
0888:            /**
0889:             * Context specific explicit type for certificate extensions.
0890:             * [CONTEXT EXPLICIT 3]
0891:             */
0892:            static final int EXTENSIONS_TYPE = CONTEXT + EXPLICIT + 3;
0893:
0894:            /**
0895:             * Checks if two byte arrays match.
0896:             * <P />
0897:             * @param a first byte array
0898:             * @param aOff starting offset for comparison within a
0899:             * @param aLen number of bytes of a to be compared
0900:             * @param b second byte array
0901:             * @param bOff starting offset for comparison within b
0902:             * @param bLen number of bytes of b to be compared
0903:             * @return true if aLen == bLen and the sequence of aLen bytes in a
0904:             * starting at
0905:             * aOff matches those in b starting at bOff, false otherwise
0906:             */
0907:            static boolean byteMatch(byte[] a, int aOff, int aLen, byte[] b,
0908:                    int bOff, int bLen) {
0909:                if ((aLen != bLen) || (a.length < aOff + aLen)
0910:                        || (b.length < bOff + bLen)) {
0911:                    return false;
0912:                }
0913:
0914:                for (int i = 0; i < aLen; i++) {
0915:                    if (a[i + aOff] != b[i + bOff]) {
0916:                        return false;
0917:                    }
0918:                }
0919:
0920:                return true;
0921:            }
0922:
0923:            /**
0924:             * Converts a subsequence of bytes into a printable OID,
0925:             * a string of decimal digits, each separated by a ".". 
0926:             *
0927:             * @param buffer byte array containing the bytes to be converted
0928:             * @param offset starting offset of the byte subsequence inside b
0929:             * @param length number of bytes to be converted
0930:             *
0931:             * @return printable OID
0932:             */
0933:            static String OIDtoString(byte[] buffer, int offset, int length) {
0934:                StringBuffer result;
0935:                int end;
0936:                int t;
0937:                int x;
0938:                int y;
0939:
0940:                if (length == 0) {
0941:                    return "";
0942:                }
0943:
0944:                result = new StringBuffer(40);
0945:
0946:                end = offset + length;
0947:
0948:                /*
0949:                 * first byte (t) always represents the first 2 values (x, y).
0950:                 * t = (x * 40) + y;
0951:                 */
0952:                t = buffer[offset++] & 0xff;
0953:                x = t / 40;
0954:                y = t - (x * 40);
0955:
0956:                result.append(x);
0957:                result.append('.');
0958:                result.append(y);
0959:
0960:                x = 0;
0961:                while (offset < end) {
0962:                    // 7 bit per byte, bit 8 = 0 means the end of a value
0963:                    x = x << 7;
0964:
0965:                    t = buffer[offset++];
0966:                    if (t >= 0) {
0967:                        x += t;
0968:                        result.append('.');
0969:                        result.append(x);
0970:                        x = 0;
0971:                    } else {
0972:                        x += t & 0x7f;
0973:                    }
0974:                }
0975:
0976:                return result.toString();
0977:            }
0978:
0979:            /** Hexadecimal digits. */
0980:            static char[] hc = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
0981:                    '9', 'A', 'B', 'C', 'D', 'E', 'F' };
0982:
0983:            /**
0984:             * Converts a subsequence of bytes in a byte array into a 
0985:             * corresponding string of hexadecimal digits, each separated by a ":". 
0986:             *
0987:             * @param b byte array containing the bytes to be converted
0988:             * @param off starting offset of the byte subsequence inside b
0989:             * @param len number of bytes to be converted
0990:             * @param max print a single "+" instead of the bytes after max,
0991:             *        -1 for no max.
0992:             * @return a string of corresponding hexadecimal digits or
0993:             * an error string
0994:             */
0995:            static String hexEncode(byte[] b, int off, int len, int max) {
0996:                char[] r;
0997:                int v;
0998:                int i;
0999:                int j;
1000:
1001:                if ((b == null) || (len == 0)) {
1002:                    return "";
1003:                }
1004:
1005:                if ((off < 0) || (len < 0)) {
1006:                    throw new ArrayIndexOutOfBoundsException();
1007:                }
1008:
1009:                r = new char[len * 3];
1010:
1011:                for (i = 0, j = 0;;) {
1012:                    v = b[off + i] & 0xff;
1013:                    r[j++] = hc[v >>> 4];
1014:                    r[j++] = hc[v & 0x0f];
1015:
1016:                    i++;
1017:                    if (i >= len) {
1018:                        break;
1019:                    }
1020:
1021:                    if (i == max) {
1022:                        r[j++] = ' ';
1023:                        r[j++] = '+';
1024:                        break;
1025:                    }
1026:
1027:                    r[j++] = ':';
1028:                }
1029:
1030:                return (new String(r, 0, j));
1031:            }
1032:
1033:            /** Raw DER type. */
1034:            int type;
1035:            /** Number of bytes that make up the value. */
1036:            int length;
1037:            /** Offset of the value. */
1038:            int valueOffset;
1039:            /** Non-null for constructed types, the first child TLV. */
1040:            TLV child;
1041:            /** The next TLV in the parent sequence. */
1042:            TLV next;
1043:
1044:            /**
1045:             * Construct a TLV structure, recursing down for constructed types.
1046:             *
1047:             * @param buffer DER buffer
1048:             * @param offset where to start parsing
1049:             *
1050:             * @exception IndexOutOfBoundException if the DER is corrupt
1051:             */
1052:            TLV(byte[] buffer, int offset) {
1053:                boolean constructed;
1054:                int size;
1055:
1056:                type = buffer[offset++] & 0xff;
1057:
1058:                // recurse for constructed types, bit 6 = 1
1059:                constructed = (type & 0x20) == 0x20;
1060:
1061:                if ((type & 0x1f) == 0x1f) {
1062:                    // multi byte type, 7 bits per byte, only last byte bit 8 as zero
1063:                    type = 0;
1064:                    for (;;) {
1065:                        int temp = buffer[offset++];
1066:                        type = type << 7;
1067:                        if (temp >= 0) {
1068:                            type += temp;
1069:                            break;
1070:                        }
1071:
1072:                        // strip off bit 8
1073:                        temp = temp & 0x7f;
1074:                        type += temp;
1075:                    }
1076:
1077:                }
1078:
1079:                size = buffer[offset++] & 0xff;
1080:                if (size >= 128) {
1081:                    int sizeLen = size - 128;
1082:
1083:                    // NOTE: for now, all sizes must fit int two bytes
1084:                    if (sizeLen > 2) {
1085:                        throw new RuntimeException("TLV size to large");
1086:                    }
1087:
1088:                    size = 0;
1089:                    while (sizeLen > 0) {
1090:                        size = (size << 8) + (buffer[offset++] & 0xff);
1091:                        sizeLen--;
1092:                    }
1093:                }
1094:
1095:                length = size;
1096:                valueOffset = offset;
1097:
1098:                if (constructed) {
1099:                    int end;
1100:                    TLV temp;
1101:
1102:                    end = offset + length;
1103:
1104:                    child = new TLV(buffer, offset);
1105:                    temp = child;
1106:                    for (;;) {
1107:                        offset = temp.valueOffset + temp.length;
1108:                        if (offset >= end) {
1109:                            break;
1110:                        }
1111:
1112:                        temp.next = new TLV(buffer, offset);
1113:                        temp = temp.next;
1114:                    }
1115:                }
1116:            }
1117:
1118:            /**
1119:             * Print the a TLV structure, recursing down for constructed types.
1120:             *
1121:             * @param buffer DER buffer
1122:             */
1123:            void print(byte[] buffer) {
1124:                print(buffer, 0);
1125:            }
1126:
1127:            /**
1128:             * Print the a TLV structure, recursing down for constructed types.
1129:             *
1130:             * @param buffer DER buffer
1131:             * @param level what level this TLV is at
1132:             */
1133:            private void print(byte[] buffer, int level) {
1134:                for (int i = 0; i < level; i++) {
1135:                    System.out.print(' ');
1136:                }
1137:
1138:                if (child == null) {
1139:                    System.out.print("Type: 0x" + Integer.toHexString(type)
1140:                            + " length: " + length + " value: ");
1141:                    if (type == PRINTSTR_TYPE || type == TELETEXSTR_TYPE
1142:                            || type == UTF8STR_TYPE || type == IA5STR_TYPE
1143:                            || type == UNIVSTR_TYPE) {
1144:                        try {
1145:                            System.out.print(new String(buffer, valueOffset,
1146:                                    length, "UTF-8"));
1147:                        } catch (UnsupportedEncodingException e) {
1148:                            // ignore
1149:                        }
1150:                    } else if (type == OID_TYPE) {
1151:                        System.out.print(OIDtoString(buffer, valueOffset,
1152:                                length));
1153:                    } else {
1154:                        System.out.print(hexEncode(buffer, valueOffset, length,
1155:                                14));
1156:                    }
1157:
1158:                    System.out.println("");
1159:                } else {
1160:                    if (type == SET_TYPE) {
1161:                        System.out.println("Set:");
1162:                    } else if (type == VERSION_TYPE) {
1163:                        System.out.println("Version (explicit):");
1164:                    } else if (type == EXTENSIONS_TYPE) {
1165:                        System.out.println("Extensions (explicit):");
1166:                    } else {
1167:                        System.out.println("Sequence:");
1168:                    }
1169:
1170:                    child.print(buffer, level + 1);
1171:                }
1172:
1173:                if (next != null) {
1174:                    next.print(buffer, level);
1175:                }
1176:            }
1177:        }
1178:
1179:        /**
1180:         * This exception is used to signal a usage error.
1181:         */
1182:        class UsageException extends Exception {
1183:
1184:            /**
1185:             * Constructs a UsageException.
1186:             */
1187:            UsageException() {
1188:            }
1189:
1190:            /**
1191:             * Constructs a UsageException.
1192:             *
1193:             * @param message exception message
1194:             */
1195:            UsageException(String message) {
1196:                super(message);
1197:            }
1198:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.