Source Code Cross Referenced for WIMApplication.java in  » 6.0-JDK-Modules » j2me » com » sun » satsa » pki » 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.satsa.pki 
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.satsa.pki;
0028:
0029:        import com.sun.midp.io.j2me.apdu.APDUManager;
0030:        import com.sun.midp.io.j2me.apdu.Handle;
0031:        import com.sun.midp.security.SecurityToken;
0032:        import com.sun.satsa.acl.ACLPermissions;
0033:        import com.sun.satsa.acl.PINAttributes;
0034:        import com.sun.satsa.acl.PINEntryDialog;
0035:        import com.sun.satsa.util.*;
0036:
0037:        import com.sun.midp.i18n.Resource;
0038:        import com.sun.midp.i18n.ResourceConstants;
0039:
0040:        import javax.microedition.pki.UserCredentialManager;
0041:        import javax.microedition.pki.UserCredentialManagerException;
0042:        import javax.microedition.securityservice.CMSMessageSignatureService;
0043:        import javax.microedition.securityservice.CMSMessageSignatureServiceException;
0044:        import java.io.IOException;
0045:        import java.util.Vector;
0046:        import java.util.Calendar;
0047:        import java.util.TimeZone;
0048:
0049:        /**
0050:         * This class provides interface to WIM card application.
0051:         */
0052:        class WIMApplication {
0053:
0054:            /** Operation result constant (skip this SE and try next). */
0055:            static final int SKIP = 0;
0056:            /** Operation result constant. */
0057:            static final int SUCCESS = 1;
0058:            /** Operation result constant. */
0059:            static final int CANCEL = 2;
0060:            /** Operation result constant. */
0061:            static final int ERROR = 3;
0062:
0063:            /**
0064:             * This class has a different security domain than the MIDlet
0065:             * suite */
0066:            private SecurityToken securityToken;
0067:
0068:            /** INS byte for APDU command. */
0069:            private static final byte INS_VERIFY = (byte) 0x20;
0070:            /** INS byte for APDU command. */
0071:            private static final byte INS_MSE = (byte) 0x22;
0072:            /** INS byte for APDU command. */
0073:            private static final byte INS_PSO = (byte) 0x2a;
0074:            /** INS byte for command APDU. */
0075:            static final byte INS_NEW = (byte) 0xBC;
0076:
0077:            /** PIN status constant. */
0078:            private static final int PIN_BLOCKED = 0;
0079:            /** PIN status constant. */
0080:            private static final int PIN_DISABLED = 1;
0081:            /** PIN status constant. */
0082:            private static final int PIN_REQUIRED = 2;
0083:            /** PIN status constant. */
0084:            private static final int PIN_CANCELLED = 3;
0085:
0086:            /** ODF path. */
0087:            private static final short ODFPath = 0x5031;
0088:            /** EF(TokenInfo) path. */
0089:            private static final short TokenInfoPath = 0x5032;
0090:            /** EF(UnusedSpace) path. */
0091:            private static final short UnusedSpace = 0x5033;
0092:
0093:            /** ODF entry tag. */
0094:            private static final int PRIVATE_KEYS_TAG = 0xa0;
0095:            /** ODF entry tag. */
0096:            private static final int PUBLIC_KEYS1_TAG = 0xa1;
0097:            /** ODF entry tag. */
0098:            private static final int PUBLIC_KEYS2_TAG = 0xa2;
0099:            /** ODF entry tag. */
0100:            private static final int USEFUL_CERTIFICATES_TAG = 0xa4;
0101:            /** ODF entry tag. */
0102:            private static final int TRUSTED_CERTIFICATES_TAG = 0xa5;
0103:            /** ODF entry tag. */
0104:            private static final int USER_CERTIFICATES_TAG = 0xa6;
0105:            /** ODF entry tag. */
0106:            private static final int PINS_TAG = 0xa8;
0107:
0108:            /** APDUs that must be used for WIM application selection. */
0109:            private static final byte[][] selectAPDUs = {
0110:                    { 0, (byte) 0xa4, 4, 0, 12, (byte) 0xA0, 0, 0, 0, 0x63,
0111:                            0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35, 0x7f },
0112:                    { 0, (byte) 0xa4, 4, 0, 12, (byte) 0xA0, 0, 0, 0, 0x63,
0113:                            0x57, 0x41, 0x50, 0x2D, 0x57, 0x49, 0x4D, 0x7f } };
0114:
0115:            /** Binary representation of WIM_GENERIC_RSA SE OID, 2.23.43.1.1.2 */
0116:            private static final byte[] WIM_GENERIC_RSA_OID = { 0x67, 0x2B,
0117:                    0x01, 0x01, 0x02 };
0118:
0119:            /** Binary representation of WAP_WSG_WIMPATH OID, 2.23.43.1.3 */
0120:            private static final byte[] WAP_WSG_WIMPATH = { 0x67, 0x2B, 0x01,
0121:                    0x03 };
0122:
0123:            /** RSA digest header. */
0124:            private static final byte[] DigestInfoHeader = { 0x30, 0x21, // DigestInfo ::= SEQUENCE {
0125:                    0x30, 0x09, // AlgorithmIdentifier ::= SEQUENCE {
0126:                    0x06, 0x05, // id-SHA1 OBJECT IDENTIFIER ::=
0127:                    0x2b, 0x0e, 0x03, 0x02, 0x1a, // { 1 3 14 3 2 26 } ,
0128:                    0x05, 0x00, // parameters NULL } ,
0129:                    0x04, 0x14 }; // digest OCTET STRING
0130:
0131:            /** Connection object. */
0132:            private Connection apdu;
0133:
0134:            /** File system object. */
0135:            private WimFileSystem files;
0136:
0137:            /** Identifier of WIM_GENERIC_RSA SE */
0138:            private int WIM_GENERIC_RSA_ID;
0139:
0140:            /** Identifier of RSA algorithm in EF(TokenInfo) and PrKDFs. */
0141:            private int RSA_ALGORITHM_ID;
0142:
0143:            /** If true this WIM application doesn't allow to modify data. */
0144:            private boolean readOnly;
0145:
0146:            /** Serial number of this WIM card. */
0147:            private String serialNumber;
0148:
0149:            /** This vector contains parsed objects from DF(ODF). */
0150:            private Vector ODF;
0151:
0152:            /** Private keys. */
0153:            private PrivateKey[] PrKeys;
0154:            /** Public keys. */
0155:            private PublicKey[] PuKeys;
0156:            /** PINs. */
0157:            private PINAttributes[] PINs;
0158:            /** Certificates. */
0159:            private Certificate[] Certificates;
0160:            /** Vector contains identifiers of existing certificates. */
0161:            private Vector certificateIDs;
0162:            /** This vector contains objects loaded from directory file. */
0163:            private Vector loaderObjects;
0164:            /** This vector contains locations of loaded objects. */
0165:            private Vector loaderLocations;
0166:            /**
0167:             * This vector contains locations of free space in directory
0168:             * files. */
0169:            private Vector loaderFreeBlocks;
0170:            /** Full path to EF(UnusedSpace) file. */
0171:            private short[] UnusedSpacePath;
0172:
0173:            /**
0174:             * Creates connection with WIM application (WIM spec, 11.3.3) on
0175:             * card in specified slot. Doesn't throw exceptions.
0176:             * @param token security token
0177:             * @param slotNum the slot number
0178:             * @param securityElementID identifies the security element
0179:             * @param readOnly if true WIM data can be protected
0180:             * @return WIMApplication object or null.
0181:             */
0182:            public static WIMApplication getInstance(SecurityToken token,
0183:                    int slotNum, String securityElementID, boolean readOnly) {
0184:
0185:                for (int i = 0; i < selectAPDUs.length; i++) {
0186:
0187:                    Handle h;
0188:                    APDUManager.initACL(slotNum, token);
0189:                    try {
0190:                        h = APDUManager.selectApplication(selectAPDUs[i],
0191:                                (byte) slotNum, token);
0192:                    } catch (IOException e) {
0193:                        continue;
0194:                    }
0195:
0196:                    WIMApplication w = new WIMApplication(h);
0197:                    if (w.init(securityElementID)
0198:                            && (readOnly || (!w.readOnly))) {
0199:                        return w;
0200:                    }
0201:                    w.done();
0202:                }
0203:                return null;
0204:            }
0205:
0206:            /**
0207:             * Constructs a new WIMApplication object.
0208:             * @param h the APDU connection handle
0209:             */
0210:            private WIMApplication(Handle h) {
0211:                this .apdu = new Connection(h);
0212:                files = new WimFileSystem(apdu);
0213:                securityToken = h.token;
0214:            }
0215:
0216:            /**
0217:             * Reads configuration (EF(TokenInfo) file).
0218:             * Doesn't throw exceptions.
0219:             * @param securityElementID identifies the security element
0220:             * @return true if successful
0221:             */
0222:            private boolean init(String securityElementID) {
0223:
0224:                try {
0225:                    if (!readTokenInfo(securityElementID)) {
0226:                        return false;
0227:                    }
0228:
0229:                    readODF();
0230:                    loadPINs();
0231:                    UnusedSpacePath = files
0232:                            .makePath(TLV.createOctetString(Utils
0233:                                    .shortToBytes(UnusedSpace)));
0234:                    return true;
0235:                } catch (IOException te) {
0236:                    done();
0237:                }
0238:
0239:                return false;
0240:            }
0241:
0242:            /**
0243:             * Safely closes the connection.
0244:             */
0245:            public void done() {
0246:                if (apdu != null) {
0247:                    apdu.done();
0248:                }
0249:                apdu = null;
0250:            }
0251:
0252:            /**
0253:             * Reads and parses EF(TokenInfo).
0254:             * @param securityElementID identifies the security element
0255:             * specified by user
0256:             * @return true if successful and WIM application is found
0257:             * @throws IOException if the file is not found or there is some
0258:             * other IO error
0259:             * @throws RuntimeException if there is an error parsing the file
0260:             * (e.g. its non-WIM PKCS#15 application and some mandatory for WIM
0261:             * fields are absent)
0262:             */
0263:            private boolean readTokenInfo(String securityElementID)
0264:                    throws IOException, TLVException {
0265:
0266:                files.select(TokenInfoPath);
0267:                TLV t = new TLV(files.readFile(), 0);
0268:
0269:                /*
0270:                 *  PKCS15TokenInfo ::= SEQUENCE {
0271:                 *      version        INTEGER {v1(0)} (v1,...),
0272:                 *      serialNumber   OCTET STRING,
0273:                 *      -manufacturerID PKCS15Label OPTIONAL,
0274:                 *      +label          [0] PKCS15Label OPTIONAL,
0275:                 *      +tokenflags     PKCS15TokenFlags,
0276:                 *      +seInfo         SEQUENCE OF PKCS15SecurityEnvironmentInfo
0277:                 *                      OPTIONAL,
0278:                 *      -recordInfo     [1] PKCS15RecordInfo OPTIONAL,
0279:                 *      +supportedAlgorithms [2]SEQUENCE OF PKCS15AlgorithmInfo
0280:                 *                      OPTIONAL,
0281:                 *      ... -- For future extensions
0282:                 *  }
0283:                 */
0284:
0285:                t = t.child; // version
0286:
0287:                // it must be integer and it must be 0 (version 1)
0288:                if (t.getInteger() != 0) {
0289:                    return false;
0290:                }
0291:
0292:                t = t.next; // serial number
0293:                if (t.type != TLV.OCTETSTR_TYPE) {
0294:                    return false;
0295:                }
0296:                serialNumber = Utils.hexNumber(t.data, t.valueOffset, t.length);
0297:
0298:                // skip optional manufacturerID
0299:                t = t.next.skipOptional(TLV.UTF8STR_TYPE);
0300:
0301:                // it must be label
0302:                if (t.type != 0x80) {
0303:                    return false;
0304:                }
0305:
0306:                String label = t.getUTF8();
0307:
0308:                if (!(label.startsWith("WIM 1.01") && (label.length() == 8 || label
0309:                        .charAt(8) == ' '))) {
0310:                    return false;
0311:                }
0312:
0313:                if (securityElementID != null
0314:                        && label.indexOf(securityElementID) == -1) {
0315:                    return false;
0316:                }
0317:
0318:                t = t.next; // Token flags. Check if this card is read-only.
0319:                readOnly = t.checkFlag(0);
0320:
0321:                t = t.next; // seInfo
0322:                // check if WIM_GENERIC_RSA SE is supported
0323:                WIM_GENERIC_RSA_ID = -1;
0324:                TLV v = t.child;
0325:                while (v != null) {
0326:                    if (v.child.next.valueEquals(WIM_GENERIC_RSA_OID)) {
0327:                        WIM_GENERIC_RSA_ID = v.child.getInteger();
0328:                        break;
0329:                    }
0330:                    v = v.next;
0331:                }
0332:
0333:                if (WIM_GENERIC_RSA_ID == -1) {
0334:                    return false;
0335:                }
0336:
0337:                // skip otional recordInfo
0338:                t = t.next.skipOptional(0xa1).child;
0339:
0340:                // check if RSA signature is supported
0341:                boolean supportsSignature = false;
0342:                while (t != null) {
0343:                    TLV m = t.child;
0344:                    if (m.next.getInteger() == 0) { // 0 - RSA
0345:                        RSA_ALGORITHM_ID = m.getInteger();
0346:                        supportsSignature = m.next.next.next.checkFlag(1);
0347:                        break;
0348:                    }
0349:                    t = t.next;
0350:                }
0351:
0352:                return supportsSignature;
0353:            }
0354:
0355:            /**
0356:             * Reads ODF and sets WIM root directory if necessary.
0357:             * @throws IOException if I/O error occurs
0358:             */
0359:            private void readODF() throws IOException, TLVException {
0360:
0361:                ODF = new Vector();
0362:                resetLoader(ODF, null, null);
0363:                parseDF(new short[] { ODFPath });
0364:
0365:                for (int i = 0; i < ODF.size(); i++) {
0366:
0367:                    TLV t = (TLV) ODF.elementAt(i);
0368:
0369:                    if (t.type != 0xa7) {
0370:                        continue;
0371:                    }
0372:
0373:                    t = t.child;
0374:                    if (t.type != 0xa0) { // not [0]SEQUENCE OF ObjectType
0375:                        continue;
0376:                    }
0377:
0378:                    t = t.child.child; // 1st of SEQUENCE OF PKCS15Data
0379:
0380:                    while (t != null) {
0381:
0382:                        if (t.type != TLV.SEQUENCE_TYPE) { // not opaqueDO
0383:                            t = t.next;
0384:                            continue;
0385:                        }
0386:
0387:                        TLV m = t.child.next.child
0388:                                .skipOptional(TLV.UTF8STR_TYPE);
0389:                        if (m.type != TLV.OID_TYPE
0390:                                || !m.valueEquals(WAP_WSG_WIMPATH)) {
0391:                            t = t.next;
0392:                            continue;
0393:                        }
0394:
0395:                        m = t.child.next.next.child;
0396:
0397:                        short[] root = new short[m.length / 2];
0398:
0399:                        for (int j = 0; j < root.length; j++) {
0400:                            root[j] = Utils.getShort(m.data, m.valueOffset + j
0401:                                    * 2);
0402:                        }
0403:                        files.setRoot(root);
0404:                        break;
0405:                    }
0406:                }
0407:            }
0408:
0409:            /**
0410:             * Initialises object loader.
0411:             * @param objects vector for loaded objects or null
0412:             * @param locations vector for object locations or null
0413:             * @param freeBlocks vector for unused block locations or null
0414:             */
0415:            private void resetLoader(Vector objects, Vector locations,
0416:                    Vector freeBlocks) {
0417:                loaderObjects = objects;
0418:                loaderLocations = locations;
0419:                loaderFreeBlocks = freeBlocks;
0420:            }
0421:
0422:            /**
0423:             * Finds all the files for specified type, reads and parses them.
0424:             * @param tag tag of ODF entry for this type of objects
0425:             * @throws IOException if IO error occurs
0426:             */
0427:            private void loadObjects(int tag) throws IOException, TLVException {
0428:
0429:                for (int i = 0; i < ODF.size(); i++) {
0430:                    TLV t = (TLV) ODF.elementAt(i);
0431:                    if (t.type == tag) {
0432:                        parseDF(files.makePath(t.child.child));
0433:                    }
0434:                }
0435:            }
0436:
0437:            /**
0438:             * Parses directory file. Places results into vectors specified
0439:             * <code>resetLoader</code> method.
0440:             * @param path path to directory file
0441:             * @throws TLVException if parsing error occurs
0442:             * @throws IOException if I/O error occurs
0443:             */
0444:            private void parseDF(short[] path) throws TLVException, IOException {
0445:                files.select(path);
0446:                doParseDF(files.readFile(), path, loaderObjects,
0447:                        loaderLocations, loaderFreeBlocks);
0448:            }
0449:
0450:            /**
0451:             * Loads all RSA private keys. Keys are stored in
0452:             * <code>PrKeys</code> array.
0453:             * @throws TLVException if parsing error occurs
0454:             * @throws IOException if I/O error occurs
0455:             */
0456:            private void loadPrivateKeys() throws IOException, TLVException {
0457:
0458:                Vector v = new Vector();
0459:                resetLoader(v, null, null);
0460:                loadObjects(PRIVATE_KEYS_TAG);
0461:
0462:                Vector k = new Vector();
0463:
0464:                for (int i = 0; i < v.size(); i++) {
0465:
0466:                    TLV t = (TLV) v.elementAt(i);
0467:
0468:                    if (t.type != TLV.SEQUENCE_TYPE) { // non-RSA key
0469:                        continue;
0470:                    }
0471:
0472:                    PrivateKey key = new PrivateKey();
0473:
0474:                    t = t.child; // commonObjectAttributes
0475:
0476:                    key.label = t.child.getUTF8().trim();
0477:                    key.authId = t.child.next.next.getId();
0478:
0479:                    t = t.next;
0480:
0481:                    TLV m = t.child;
0482:                    key.id = m.getValue();
0483:
0484:                    m = m.next;
0485:                    key.authentication = m.checkFlag(2);
0486:                    key.nonRepudiation = m.checkFlag(9);
0487:
0488:                    m = m.next.skipOptional(TLV.BOOLEAN_TYPE);
0489:                    key.keyReference = m.getInteger() & 0xff;
0490:
0491:                    // skip PKCS15CommonPrivateKeyAttributes
0492:                    t = t.next.skipOptional(0xa0);
0493:
0494:                    t = t.child.child;
0495:                    key.path = files.makePath(t.child);
0496:                    t = t.next;
0497:                    key.modulusLength = t.getInteger();
0498:
0499:                    t = t.next;
0500:                    if (t != null && t.type == TLV.INTEGER_TYPE
0501:                            && t.getInteger() != RSA_ALGORITHM_ID) {
0502:                        continue;
0503:                    }
0504:
0505:                    k.addElement(key);
0506:                }
0507:
0508:                PrKeys = new PrivateKey[k.size()];
0509:                k.copyInto(PrKeys);
0510:            }
0511:
0512:            /**
0513:             * Loads all RSA public keys. Stores keys in <code>PuKeys</code>
0514:             * array.
0515:             * @throws TLVException if parsing error occurs
0516:             * @throws IOException if I/O error occurs
0517:             */
0518:            private void loadPublicKeys() throws IOException, TLVException {
0519:
0520:                Vector v = new Vector();
0521:                resetLoader(v, null, null);
0522:                loadObjects(PUBLIC_KEYS1_TAG);
0523:                loadObjects(PUBLIC_KEYS2_TAG);
0524:
0525:                Vector k = new Vector();
0526:
0527:                for (int i = 0; i < v.size(); i++) {
0528:
0529:                    TLV t = (TLV) v.elementAt(i);
0530:
0531:                    if (t.type != TLV.SEQUENCE_TYPE) { // non-RSA key
0532:                        continue;
0533:                    }
0534:
0535:                    PublicKey key = new PublicKey();
0536:
0537:                    t = t.child; // commonObjectAttributes
0538:                    t = t.next; // CommonKeyAttributes
0539:
0540:                    key.id = t.child.getValue();
0541:                    TLV m = t.child.next.next;
0542:
0543:                    if (m.type != TLV.BOOLEAN_TYPE
0544:                            || m.data[m.valueOffset] != 0) {
0545:                        continue; // native, useless for CSR generation
0546:                    }
0547:
0548:                    // skip PKCS15CommonPublicKeyAttributes
0549:                    t = t.next.skipOptional(0xa0);
0550:
0551:                    key.body = files.pathToLocation(t.child.child);
0552:
0553:                    k.addElement(key);
0554:                }
0555:
0556:                PuKeys = new PublicKey[k.size()];
0557:                k.copyInto(PuKeys);
0558:            }
0559:
0560:            /**
0561:             * Loads PIN objects and places them into <code>PINs</code> array.
0562:             * @throws TLVException if parsing error occurs
0563:             * @throws IOException if I/O error occurs
0564:             */
0565:            private void loadPINs() throws IOException, TLVException {
0566:
0567:                Vector v = new Vector();
0568:                resetLoader(v, null, null);
0569:                loadObjects(PINS_TAG);
0570:
0571:                Vector k = new Vector();
0572:
0573:                for (int i = 0; i < v.size(); i++) {
0574:
0575:                    TLV t = (TLV) v.elementAt(i);
0576:
0577:                    if (t.type != TLV.SEQUENCE_TYPE) { // not a PIN object
0578:                        continue;
0579:                    }
0580:
0581:                    PINAttributes pin = new PINAttributes();
0582:                    k.addElement(pin);
0583:
0584:                    t = t.child; // commonObjectAttributes
0585:                    pin.label = t.child.getUTF8().trim();
0586:
0587:                    t = t.next; // CommonAuthenticationObjectAttributes
0588:                    pin.id = t.child.getId();
0589:
0590:                    t = t.next.child.child; // PinAttributes.pinFlags
0591:
0592:                    if (t.checkFlag(0)) {
0593:                        pin.pinFlags = PINAttributes.FLAG_CASE_SENSITIVE;
0594:                    }
0595:                    if (t.checkFlag(5)) {
0596:                        pin.pinFlags = PINAttributes.FLAG_NEEDS_PADDING;
0597:                    }
0598:
0599:                    t = t.next;
0600:                    pin.pinType = t.getEnumerated();
0601:
0602:                    t = t.next;
0603:                    pin.minLength = t.getInteger();
0604:
0605:                    t = t.next;
0606:                    pin.storedLength = t.getInteger();
0607:
0608:                    t = t.next;
0609:                    if (t.type == TLV.INTEGER_TYPE) {
0610:                        pin.maxLength = t.getInteger();
0611:                        t = t.next;
0612:                    } else {
0613:                        pin.maxLength = pin.storedLength;
0614:                    }
0615:
0616:                    // this entry is optional, default value is 0
0617:                    if (t.type == 0x80) {
0618:                        pin.pinReference = t.getInteger();
0619:                        t = t.next;
0620:                    }
0621:
0622:                    pin.padChar = t.getId();
0623:
0624:                    t = t.next.skipOptional(TLV.GEN_TIME_TYPE);
0625:                    pin.path = files.makePath(t.child);
0626:                }
0627:
0628:                if (k.size() == 0) {
0629:                    throw new IOException("PINs not found");
0630:                }
0631:
0632:                PINs = new PINAttributes[k.size()];
0633:                k.copyInto(PINs);
0634:            }
0635:
0636:            /**
0637:             * Loads attributes of X.509 certificates. Places results into
0638:             * <code>Certificates</code> array. Places identifiers of all
0639:             * certificates into <code>certificateIDs</code> vector.
0640:             * @param loadValues if true loads also the certificates
0641:             * @param loadTrusted if true load trusted certificates
0642:             * @throws TLVException if parsing error occurs
0643:             * @throws IOException if I/O error occurs
0644:             */
0645:            private void loadCertificates(boolean loadValues,
0646:                    boolean loadTrusted) throws IOException, TLVException {
0647:
0648:                Vector objects = new Vector();
0649:                Vector locations = new Vector();
0650:                resetLoader(objects, locations, null);
0651:                if (loadTrusted) {
0652:                    loadObjects(TRUSTED_CERTIFICATES_TAG);
0653:                }
0654:                loadObjects(USEFUL_CERTIFICATES_TAG);
0655:                loadObjects(USER_CERTIFICATES_TAG);
0656:
0657:                Vector k = new Vector();
0658:                certificateIDs = new Vector();
0659:
0660:                for (int i = 0; i < objects.size(); i++) {
0661:
0662:                    TLV t = (TLV) objects.elementAt(i);
0663:
0664:                    // is it x.509 certificate?
0665:                    if (t.type != TLV.SEQUENCE_TYPE) {
0666:                        certificateIDs
0667:                                .addElement(t.child.next.child.getValue());
0668:                        continue;
0669:                    }
0670:
0671:                    Certificate cert = new Certificate();
0672:                    k.addElement(cert);
0673:
0674:                    t = t.child; // commonObjectAttributes
0675:
0676:                    cert.label = t.child.getUTF8().trim();
0677:
0678:                    t = t.next;
0679:
0680:                    cert.id = t.child.getValue();
0681:                    certificateIDs.addElement(cert.id);
0682:
0683:                    TLV v = t.child.next;
0684:                    if (v != null) {
0685:                        v = v.skipOptional(TLV.BOOLEAN_TYPE);
0686:                        if (v != null) {
0687:                            cert.requestId = v.getValue();
0688:                        }
0689:                    }
0690:
0691:                    t = t.next.child.child;
0692:
0693:                    cert.body = files.pathToLocation(t);
0694:
0695:                    if (loadValues) {
0696:                        cert.cert = files.loadObject(cert.body);
0697:                    }
0698:
0699:                    cert.header = (Location) locations.elementAt(i);
0700:                }
0701:
0702:                Certificates = new Certificate[k.size()];
0703:                k.copyInto(Certificates);
0704:            }
0705:
0706:            /**
0707:             * Verifies PIN status.
0708:             * @param pin object containing PIN attributes
0709:             * @return PIN status.
0710:             */
0711:            private int getPINStatus(PINAttributes pin) {
0712:
0713:                try {
0714:                    files.select(pin.path);
0715:                    apdu.resetCommand().sendCommand(INS_VERIFY,
0716:                            pin.pinReference, 0, false);
0717:                } catch (IOException e) {
0718:                    return PIN_BLOCKED;
0719:                }
0720:
0721:                if (apdu.lastSW == 0x9000) {
0722:                    return PIN_DISABLED;
0723:                }
0724:
0725:                if (apdu.lastSW == 0x6983) {
0726:                    return PIN_BLOCKED;
0727:                }
0728:
0729:                return PIN_REQUIRED;
0730:            }
0731:
0732:            /**
0733:             * Verifies the PIN if necessary.
0734:             * @param pin object containing PIN attributes
0735:             * @return PIN_DISABLED - if the PIN is verified or not required;
0736:             * PIN_BLOCKED - if the PIN is blocked; PIN_CANCELLED - if user
0737:             * cancelled PIN entry dialog
0738:             */
0739:            private int checkPIN(PINAttributes pin) {
0740:
0741:                while (true) {
0742:
0743:                    int status = getPINStatus(pin);
0744:
0745:                    if (status == PIN_DISABLED) {
0746:                        return PIN_DISABLED;
0747:                    }
0748:
0749:                    if (status == PIN_BLOCKED) {
0750:                        try {
0751:                            MessageDialog
0752:                                    .showMessage(
0753:                                            securityToken,
0754:                                            Resource
0755:                                                    .getString(ResourceConstants.ERROR),
0756:                                            Resource
0757:                                                    .getString(ResourceConstants.JSR177_WIM_PIN_BLOCKED)
0758:                                                    + ":\n" + pin.label, false);
0759:                        } catch (InterruptedException e) {
0760:                        }
0761:                        return PIN_BLOCKED;
0762:                    }
0763:
0764:                    // verification is required
0765:                    PINEntryDialog dialog;
0766:                    try {
0767:                        dialog = new PINEntryDialog(securityToken,
0768:                                ACLPermissions.CMD_VERIFY, pin, null);
0769:                    } catch (InterruptedException e) {
0770:                        return PIN_CANCELLED;
0771:                    }
0772:
0773:                    dialog.waitForAnswer();
0774:
0775:                    Object[] pins = dialog.getPINs();
0776:
0777:                    if (pins == null) {
0778:                        return PIN_CANCELLED;
0779:                    }
0780:
0781:                    boolean ok = true;
0782:                    try {
0783:                        byte[] tmp = (byte[]) pins[0];
0784:                        apdu.resetCommand().putBytes(tmp, 0, tmp.length)
0785:                                .sendCommand(INS_VERIFY, pin.pinReference, 127,
0786:                                        false);
0787:                    } catch (IOException e) {
0788:                        ok = false;
0789:                    }
0790:
0791:                    if (ok & (apdu.lastSW == 0x9000)) {
0792:                        return PIN_DISABLED;
0793:                    }
0794:
0795:                    try {
0796:                        MessageDialog
0797:                                .showMessage(
0798:                                        securityToken,
0799:                                        Resource
0800:                                                .getString(ResourceConstants.ERROR),
0801:                                        Resource
0802:                                                .getString(ResourceConstants.JSR177_WIM_PIN_NOT_VERIFIED),
0803:                                        false);
0804:                    } catch (InterruptedException e) {
0805:                    }
0806:                }
0807:            }
0808:
0809:            /**
0810:             * Generates CSR. See UserCredentialManager.generateCSR for details.
0811:             * The calling method must load a vector that contains IDs of keys
0812:             * for which CSRs were generated earlier and save it after successful
0813:             * CSR generation.
0814:             * @param nameInfo certificate subject name
0815:             * @param keyLen key length
0816:             * @param keyUsage key usage
0817:             * @param forceKeyGen if set to true a new key must be generated
0818:             * @param keyIDs IDs of keys for which CSRs were generated earlier.
0819:             * If the new CSR is generated, the key ID is added into this vector.
0820:             * @return the new CSR or null if operation cancelled
0821:             * @throws UserCredentialManagerException if key is not found
0822:             * @throws CMSMessageSignatureServiceException if CSR generation
0823:             * failed
0824:             * @throws SecurityException if a PIN is blocked due to an excessive
0825:             * number of incorrect PIN entries
0826:             */
0827:            public byte[] generateCSR(String nameInfo, int keyLen,
0828:                    int keyUsage, boolean forceKeyGen, Vector keyIDs)
0829:                    throws UserCredentialManagerException,
0830:                    CMSMessageSignatureServiceException {
0831:
0832:                // check the name
0833:
0834:                if (nameInfo == null) {
0835:                    nameInfo = "CN=" + serialNumber;
0836:                }
0837:
0838:                TLV name;
0839:
0840:                try {
0841:                    name = new TLV(RFC2253Name.toDER(nameInfo), 0);
0842:                } catch (TLVException e) {
0843:                    throw new IllegalArgumentException("Invalid name");
0844:                }
0845:
0846:                try {
0847:                    if (MessageDialog
0848:                            .showMessage(
0849:                                    securityToken,
0850:                                    Resource
0851:                                            .getString(ResourceConstants.AMS_CONFIRMATION),
0852:                                    Resource
0853:                                            .getString(ResourceConstants.JSR177_CERTIFICATE_GENERATED)
0854:                                            + "\n\n"
0855:                                            +
0856:                                            // "Name: "
0857:                                            Resource
0858:                                                    .getString(ResourceConstants.JSR177_CERTIFICATE_SUBJECT)
0859:                                            + ": "
0860:                                            + nameInfo
0861:                                            + "\n\n"
0862:                                            +
0863:                                            // "Key usage: "
0864:                                            Resource
0865:                                                    .getString(ResourceConstants.JSR177_CERTIFICATE_KEYUSAGE)
0866:                                            + ": "
0867:                                            + ((keyUsage == UserCredentialManager.KEY_USAGE_AUTHENTICATION) ?
0868:                                            // "authentication"
0869:                                            Resource
0870:                                                    .getString(ResourceConstants.JSR177_CERTIFICATE_KEYUSAGE_AUTH)
0871:                                                    :
0872:                                                    // "non-repudiation"
0873:                                                    Resource
0874:                                                            .getString(ResourceConstants.JSR177_CERTIFICATE_KEYUSAGE_NR))
0875:                                            + "\n"
0876:                                            +
0877:                                            // "Algorithm: "
0878:                                            Resource
0879:                                                    .getString(ResourceConstants.JSR177_CERTIFICATE_ALGORITHM)
0880:                                            + ": "
0881:                                            + "RSA"
0882:                                            + "\n"
0883:                                            +
0884:                                            // "Key length: "
0885:                                            Resource
0886:                                                    .getString(ResourceConstants.JSR177_CERTIFICATE_KEYLENGTH)
0887:                                            + ": " + keyLen, true) == Dialog.CANCELLED) {
0888:                        return null;
0889:                    }
0890:                } catch (InterruptedException e) {
0891:                    return null;
0892:                }
0893:
0894:                int keyId = -1;
0895:                if (forceKeyGen) {
0896:                    try {
0897:                        keyId = generateKey(keyLen, keyUsage);
0898:                    } catch (IOException ioe) { // ignored
0899:                    } catch (InterruptedException ie) { // ignored
0900:                    }
0901:
0902:                    if (keyId == -1) {
0903:                        throw new UserCredentialManagerException(
0904:                                UserCredentialManagerException.SE_NO_KEYGEN);
0905:                    }
0906:                    if (keyId == -2) {
0907:                        throw new UserCredentialManagerException(
0908:                                UserCredentialManagerException.SE_NO_KEYS);
0909:                    }
0910:                }
0911:
0912:                // load info about keys
0913:
0914:                try {
0915:                    if (keyId != -1) {
0916:                        loadPINs();
0917:                    }
0918:                    loadCertificates(false, true);
0919:                    loadPrivateKeys();
0920:                    loadPublicKeys();
0921:                } catch (IOException e) {
0922:                    throw new UserCredentialManagerException(
0923:                            UserCredentialManagerException.SE_NO_KEYS);
0924:                }
0925:
0926:                // find the 'best' key
0927:
0928:                PrivateKey key = null;
0929:                int keyType = 3; // 0 - no certificate or CSR
0930:                // 1 - CSR
0931:                // 2 - certificate
0932:                // 3 - empty
0933:                TLV keyValue = null;
0934:
0935:                for (int i = 0; i < PrKeys.length; i++) {
0936:
0937:                    if (keyId != -1) {
0938:                        if (keyId == PrKeys[i].keyReference) {
0939:                            key = PrKeys[i];
0940:                            keyValue = getPublicKey(PrKeys[i].id);
0941:                            break;
0942:                        }
0943:                        continue;
0944:                    }
0945:
0946:                    // check key size
0947:                    if (PrKeys[i].modulusLength != keyLen) {
0948:                        continue;
0949:                    }
0950:
0951:                    // check key usage
0952:                    if (!(keyUsage == UserCredentialManager.KEY_USAGE_AUTHENTICATION ? PrKeys[i].authentication
0953:                            : PrKeys[i].nonRepudiation)) {
0954:                        continue;
0955:                    }
0956:
0957:                    // check if certificate or CSR for this key exists
0958:                    int type = 0;
0959:
0960:                    if (getIDIndex(keyIDs, PrKeys[i].id) != -1) {
0961:                        type = 1;
0962:                    }
0963:
0964:                    if (getIDIndex(certificateIDs, PrKeys[i].id) != -1) {
0965:                        type = 2;
0966:                    }
0967:
0968:                    // is this key is better than the previous?
0969:                    if (type >= keyType) {
0970:                        continue;
0971:                    }
0972:
0973:                    // if PIN doesn't exist or blocked, find another key
0974:                    PINAttributes pin = getPIN(PrKeys[i].authId);
0975:                    if (pin == null || getPINStatus(pin) == PIN_BLOCKED) {
0976:                        continue;
0977:                    }
0978:
0979:                    // if the public key can't be retrieved, find another key
0980:                    TLV t = getPublicKey(PrKeys[i].id);
0981:                    if (t == null) {
0982:                        continue;
0983:                    }
0984:
0985:                    // the best key so far
0986:                    key = PrKeys[i];
0987:                    keyValue = t;
0988:                    keyType = type;
0989:                }
0990:
0991:                if (key == null) {
0992:                    throw new UserCredentialManagerException(
0993:                            UserCredentialManagerException.SE_NO_KEYS);
0994:                }
0995:
0996:                // the key is found and loaded
0997:                // check PIN for signature operation
0998:                int pinStatus = checkPIN(getPIN(key.authId));
0999:
1000:                if (pinStatus == PIN_CANCELLED) {
1001:                    return null;
1002:                }
1003:
1004:                if (pinStatus == PIN_BLOCKED) {
1005:                    throw new SecurityException("PIN blocked");
1006:                }
1007:
1008:                if (pinStatus != PIN_DISABLED) {
1009:                    // IMPL_NOTE: need warning message?
1010:                    throw new CMSMessageSignatureServiceException(
1011:                            CMSMessageSignatureServiceException.SE_CRYPTO_FAILURE);
1012:                }
1013:
1014:                // PIN is verified, create the CSR
1015:
1016:                TLV CRInfo = TLV.createSequence();
1017:
1018:                CRInfo
1019:                        .setChild(TLV.createInteger(0))
1020:                        .setNext(name)
1021:                        .setNext(keyValue)
1022:                        .setNext(new TLV(TLV.SET_TYPE).setTag(0xa0))
1023:                        .setChild(TLV.createSequence())
1024:                        .setChild(TLV.createOID("1.2.840.113549.1.9.14"))
1025:                        .setNext(new TLV(TLV.SET_TYPE))
1026:                        .setChild(TLV.createSequence())
1027:                        .setChild(TLV.createSequence())
1028:                        .setChild(TLV.createOID("2.5.29.15"))
1029:                        .setNext(
1030:                                new TLV(TLV.BOOLEAN_TYPE,
1031:                                        new byte[] { (byte) 255 }))
1032:                        .setNext(
1033:                                new TLV(
1034:                                        TLV.OCTETSTR_TYPE,
1035:                                        keyUsage == UserCredentialManager.KEY_USAGE_AUTHENTICATION ? new byte[] {
1036:                                                3, 2, 7, (byte) 0x80 }
1037:                                                : new byte[] { 3, 2, 6, 0x40 }));
1038:
1039:                byte[] sign;
1040:
1041:                try {
1042:                    sign = signData(key, CRInfo.getDERData());
1043:                } catch (IOException e) {
1044:                    throw new CMSMessageSignatureServiceException(
1045:                            CMSMessageSignatureServiceException.SE_CRYPTO_FAILURE);
1046:                }
1047:
1048:                TLV alg = CRInfo.child.next.next.child.copy();
1049:
1050:                TLV OID = TLV.createOID("1.2.840.113549.1.1.5");
1051:                TLV params = alg.child.next;
1052:
1053:                alg = TLV.createSequence();
1054:                alg.setChild(OID).setNext(params);
1055:
1056:                TLV request = TLV.createSequence();
1057:                request.setChild(CRInfo).setNext(alg).setNext(
1058:                        new TLV(TLV.BITSTRING_TYPE, sign));
1059:
1060:                // add to the vector of IDs of keys for which CSRs are generated
1061:                keyIDs.addElement(key.id);
1062:                return request.getDERData();
1063:            }
1064:
1065:            /**
1066:             * Generates new key.
1067:             * @param keyLen key length
1068:             * @param keyUsage key usage
1069:             * @return key reference or -1 if the key generation is not
1070:             * supported or -2 if key cannot be generated
1071:             * @throws IOException if I/O error occurs
1072:             * @throws InterruptedException if interrupted
1073:             */
1074:            int generateKey(int keyLen, int keyUsage) throws IOException,
1075:                    InterruptedException {
1076:
1077:                boolean nonRepudiation = (keyUsage == UserCredentialManager.KEY_USAGE_NON_REPUDIATION);
1078:
1079:                byte[] tmp = apdu.resetCommand()
1080:                        .putByte(nonRepudiation ? 1 : 0).putShort(keyLen)
1081:                        .sendCommand(INS_NEW, 0x0100, 240, false);
1082:
1083:                if (apdu.lastSW == 0x9001) {
1084:                    return -2;
1085:                }
1086:
1087:                if (tmp.length != 6 || Utils.getShort(tmp, 0) != 0x1234
1088:                        || Utils.getShort(tmp, 2) != 0x4321) {
1089:                    return -1;
1090:                }
1091:
1092:                apdu.resetCommand().putByte(nonRepudiation ? 1 : 0).putShort(
1093:                        keyLen);
1094:
1095:                if (nonRepudiation) {
1096:                    // must create new PIN
1097:                    String[] pinInfo = MessageDialog.enterNewPIN(securityToken);
1098:                    if (pinInfo == null) {
1099:                        return -1;
1100:                    }
1101:
1102:                    tmp = pinInfo[1].getBytes();
1103:                    int len = tmp.length;
1104:                    apdu.putBytes(tmp, 0, len);
1105:                    while (len++ < 8) {
1106:                        apdu.putByte(0xff);
1107:                    }
1108:
1109:                    tmp = Utils.stringToBytes(pinInfo[0]);
1110:                    len = tmp.length < 32 ? tmp.length : 32;
1111:                    apdu.putBytes(tmp, 0, len);
1112:                    while (len++ < 32) {
1113:                        apdu.putByte(0x20);
1114:                    }
1115:                }
1116:
1117:                tmp = apdu.sendCommand(INS_NEW, 0x0000, 240, false);
1118:                return apdu.lastSW == 0x9000 ? tmp[0] & 0xff : -2;
1119:            }
1120:
1121:            /**
1122:             * Sign given data using given key.
1123:             * @param key private key
1124:             * @param data data to be signed
1125:             * @return signature prepended with one zero byte.
1126:             * @throws IOException if I/O or crypto error occurs
1127:             */
1128:            private byte[] signData(PrivateKey key, byte[] data)
1129:                    throws IOException {
1130:
1131:                // calculate SHA-1 digest
1132:                byte[] tmp = Utils.getHash(data, 0, data.length);
1133:
1134:                // MSE - RESTORE
1135:                apdu.resetCommand().sendCommand(INS_MSE,
1136:                        0xf300 | WIM_GENERIC_RSA_ID, 0, true);
1137:
1138:                // MSE - SET
1139:                apdu.resetCommand().putByte(0x84). // key reference tag
1140:                        putByte(0x1). // length
1141:                        putByte(key.keyReference). // value
1142:                        putByte(0x81). // private key path tag
1143:                        putByte(key.path.length * 2); // length
1144:                for (int i = 0; i < key.path.length; i++) { // value
1145:                    apdu.putShort(key.path[i]);
1146:                }
1147:                apdu.sendCommand(INS_MSE, 0x41b6, 0, true);
1148:
1149:                // sign the data
1150:                tmp = apdu.resetCommand().putBytes(DigestInfoHeader, 0,
1151:                        DigestInfoHeader.length).putBytes(tmp, 0, 20)
1152:                        .sendCommand(INS_PSO, 0x9e9a);
1153:
1154:                byte[] sign = new byte[tmp.length - 1];
1155:                System.arraycopy(tmp, 0, sign, 1, tmp.length - 2);
1156:                return sign;
1157:            }
1158:
1159:            /**
1160:             * Returns index of given identifier in the vector or -1 if not
1161:             * found.
1162:             * @param IDs vector containing identifiers
1163:             * @param id identifier
1164:             * @return index of given identifier or -1
1165:             */
1166:            private int getIDIndex(Vector IDs, byte[] id) {
1167:
1168:                for (int j = 0; j < IDs.size(); j++) {
1169:                    if (Utils.byteMatch((byte[]) IDs.elementAt(j), id)) {
1170:                        return j;
1171:                    }
1172:                }
1173:                return -1;
1174:            }
1175:
1176:            /**
1177:             * Returns PIN attributes for given authId.
1178:             * @param authId identifier of PIN
1179:             * @return PIN attributes or null
1180:             */
1181:            private PINAttributes getPIN(int authId) {
1182:
1183:                for (int i = 0; i < PINs.length; i++) {
1184:                    if (PINs[i].id == authId) {
1185:                        return PINs[i];
1186:                    }
1187:                }
1188:                return null;
1189:            }
1190:
1191:            /**
1192:             * Returns TLV that contains SubjectPublicKeyInfo structure for
1193:             * public key.
1194:             * @param id key identifier
1195:             * @return TLV that contains SubjectPublicKeyInfo structure or null
1196:             */
1197:            private TLV getPublicKey(byte[] id) {
1198:
1199:                // try to obtain the key from certificate
1200:
1201:                for (int i = 0; i < Certificates.length; i++) {
1202:                    if (!Utils.byteMatch(Certificates[i].id, id)) {
1203:                        continue;
1204:                    }
1205:                    try {
1206:                        TLV t = files.loadObject(Certificates[i].body);
1207:                        return t.child.child.skipOptional(0xa0).next.next.next.next.next
1208:                                .copy();
1209:                    } catch (IOException e) {
1210:                        continue;
1211:                    }
1212:                }
1213:
1214:                /*
1215:                    there is no certificate for this private key, try to
1216:                    read public key
1217:                 */
1218:                for (int i = 0; i < PuKeys.length; i++) {
1219:                    if (!Utils.byteMatch(PuKeys[i].id, id)) {
1220:                        continue;
1221:                    }
1222:
1223:                    try {
1224:                        files.select(PuKeys[i].body.path);
1225:                        if (PuKeys[i].body.length == -1) {
1226:                            PuKeys[i].body.length = files.getCurrrentFileSize();
1227:                        }
1228:                        byte[] tmp = files.readData(1, PuKeys[i].body.length,
1229:                                PuKeys[i].body.offset);
1230:
1231:                        TLV subjectPKInfo = TLV.createSequence();
1232:
1233:                        TLV alg = TLV.createSequence();
1234:                        subjectPKInfo.setChild(alg);
1235:
1236:                        alg.setChild(TLV.createOID("1.2.840.113549.1.1.1"))
1237:                                .setNext(new TLV(TLV.NULL_TYPE));
1238:
1239:                        alg.setNext(new TLV(TLV.BITSTRING_TYPE, tmp));
1240:                        return subjectPKInfo;
1241:                    } catch (IOException e) {
1242:                        break;
1243:                    }
1244:                }
1245:                return null;
1246:            }
1247:
1248:            /**
1249:             * Adds a user certificate or certificate URI to a certificate store.
1250:             * See UserCredentialManager.addCredential for details. Calling
1251:             * method must remove leading and trailing spaces in label.
1252:             * @param label the user friendly name associated with the
1253:             * certificate
1254:             * @param top chain of certificates from pkiPath
1255:             * @param keyIDs vector that contains identifiers of keys for which
1256:             * certificates are expected
1257:             * @return  operation result
1258:             * @throws IllegalArgumentException if certificate parsing error
1259:             * occurs or label is not unique or user credential exists already
1260:             * @throws SecurityException if a PIN is blocked due to an excessive
1261:             * number of incorrect PIN entries
1262:             */
1263:            public int addCredential(String label, TLV top, Vector keyIDs) {
1264:
1265:                // load existing certificates
1266:                try {
1267:                    loadPrivateKeys();
1268:                    loadCertificates(true, true);
1269:                } catch (IOException e) {
1270:                    return SKIP;
1271:                }
1272:
1273:                // put certificates into array
1274:                Vector u = new Vector();
1275:                while (top != null) {
1276:                    u.addElement(top);
1277:                    top = top.next;
1278:                }
1279:                TLV path[] = new TLV[u.size()];
1280:                u.copyInto(path);
1281:
1282:                // verify certificates encoding and calculate identifier
1283:                // the purpose of the check is to ensure that new certificates
1284:                // will not cause runtime exceptions, not to verify X.509
1285:                // compliance
1286:                byte[][] IDs = new byte[path.length][];
1287:                try {
1288:                    TLV Issuer = null;
1289:                    for (int i = 0; i < path.length; i++) {
1290:                        TLV t = path[i].child.child.skipOptional(0xa0).next.next;
1291:                        RFC2253Name.compare(t, t); // issuer
1292:                        if (Issuer != null && !RFC2253Name.compare(Issuer, t)) {
1293:                            throw new IllegalArgumentException();
1294:                        }
1295:                        t = t.next; // validity
1296:                        t.child.getTime(); // notBefore
1297:                        t.child.next.getTime(); // notAfter
1298:                        t = t.next; // subject
1299:                        RFC2253Name.compare(t, t);
1300:                        Issuer = t;
1301:                        IDs[i] = getKeyHash(path[i]); // subjectPublicKeyInfo
1302:                    }
1303:                } catch (IOException e) {
1304:                    throw new IllegalArgumentException("Invalid pkiPath");
1305:                } catch (NullPointerException npe) {
1306:                    throw new IllegalArgumentException("Invalid pkiPath");
1307:                }
1308:
1309:                // check if this WIM contains corresponding private key
1310:                if (getPrivateKey(IDs[path.length - 1]) == null) {
1311:                    return SKIP;
1312:                }
1313:
1314:                // check that the label is unique for this card
1315:                if (getCertificate(label) != null) {
1316:                    throw new IllegalArgumentException(label);
1317:                }
1318:
1319:                // eliminate certificates that already present on the card
1320:                for (int i = 0; i < path.length; i++) {
1321:                    TLV t = path[i].child.child.skipOptional(0xa0);
1322:                    if (getCertificate(t.next.next, t) != null) {
1323:                        path[i] = null;
1324:                    }
1325:                }
1326:
1327:                if (path[path.length - 1] == null) {
1328:                    throw new IllegalArgumentException("credential exists");
1329:                }
1330:
1331:                // if the 1st certificate is self-signed we don't need to save it
1332:                if (path.length > 1 && path[0] != null) {
1333:                    TLV t = path[0].child.child.skipOptional(0xa0).next.next;
1334:                    if (RFC2253Name.compare(t, t.next.next)) {
1335:                        path[0] = null;
1336:                    }
1337:                }
1338:
1339:                // find place for every certificate and generate CDF records
1340:
1341:                startUpdate();
1342:
1343:                Location[] locations;
1344:                try {
1345:                    locations = putObjects(path);
1346:                } catch (IOException e) {
1347:                    return ERROR;
1348:                }
1349:                if (locations == null) { // if no enough space
1350:                    return ERROR;
1351:                }
1352:
1353:                Vector headers = new Vector();
1354:                int labelNum = 0;
1355:
1356:                for (int i = 0; i < path.length; i++) {
1357:
1358:                    if (path[i] == null) {
1359:                        continue;
1360:                    }
1361:
1362:                    // generate header for certificate
1363:
1364:                    // create unique label if necessary
1365:                    String t_label = label;
1366:                    if (i < path.length - 1) {
1367:                        for (int k = 0; k < 100000; k++) {
1368:                            t_label = "certificate # " + labelNum++;
1369:                            if (!label.equals(t_label)
1370:                                    && getCertificate(t_label) == null) {
1371:                                break;
1372:                            }
1373:                        }
1374:                    }
1375:
1376:                    // find identifier of the previous certificate
1377:                    byte[] prevID;
1378:                    if (i == 0) {
1379:                        TLV t = path[i].child.child.skipOptional(0xa0).next.next;
1380:                        Vector v = getCertsBySubject(t);
1381:                        if (v.size() == 0) {
1382:                            prevID = new byte[20];
1383:                        } else {
1384:                            prevID = ((Certificate) v.elementAt(0)).id;
1385:                        }
1386:                    } else {
1387:                        prevID = IDs[i - 1];
1388:                    }
1389:
1390:                    TLV commonAttrs = TLV.createSequence();
1391:                    commonAttrs.setChild(createLabel(t_label)).setNext(
1392:                            new TLV(TLV.BITSTRING_TYPE, new byte[2]));
1393:
1394:                    TLV commonCertAttrs = TLV.createSequence();
1395:                    commonCertAttrs.setChild(TLV.createOctetString(IDs[i]))
1396:                            .setNext(TLV.createOctetString(prevID));
1397:
1398:                    Location l = locations[i];
1399:
1400:                    TLV x509Attrs = new TLV(0xa1);
1401:                    x509Attrs.setChild(TLV.createSequence()).setChild(
1402:                            createPath(l.path, l.offset, l.length));
1403:
1404:                    TLV cdf = TLV.createSequence();
1405:                    cdf.setChild(commonAttrs).setNext(commonCertAttrs).setNext(
1406:                            x509Attrs);
1407:
1408:                    headers.addElement(cdf);
1409:                }
1410:
1411:                // find free space for headers in CDFs
1412:                if (!putHeaders(headers)) {
1413:                    return ERROR;
1414:                }
1415:
1416:                // check PINs
1417:                for (int i = 0; i < updatePIN.length; i++) {
1418:                    if (updatePIN[i]) {
1419:                        int pinStatus = checkPIN(PINs[i]);
1420:                        if (pinStatus == PIN_CANCELLED) {
1421:                            return CANCEL;
1422:                        }
1423:                        if (pinStatus == PIN_BLOCKED) {
1424:                            throw new SecurityException("PIN blocked");
1425:                        }
1426:                        if (pinStatus != PIN_DISABLED) {
1427:                            return ERROR;
1428:                        }
1429:                    }
1430:                }
1431:
1432:                // update
1433:                try {
1434:                    doUpdate();
1435:                } catch (IOException e) {
1436:                    return ERROR;
1437:                }
1438:
1439:                // remove key identifier from the list of expected certificates
1440:                for (int i = 0; i < keyIDs.size(); i++) {
1441:                    if (Utils.byteMatch(IDs[path.length - 1], (byte[]) keyIDs
1442:                            .elementAt(i))) {
1443:                        keyIDs.removeElementAt(i);
1444:                        break;
1445:                    }
1446:                }
1447:
1448:                //        typeInfo("AddCredential");
1449:                return SUCCESS;
1450:            }
1451:
1452:            /**
1453:             * Finds place for new certificates and registers necessary file
1454:             * updates.
1455:             * @param path array containing certificates
1456:             * @return array that contains locations for new certificates.
1457:             * @throws TLVException if parsing error occurs
1458:             * @throws IOException if I/O error occurs
1459:             */
1460:            private Location[] putObjects(TLV[] path) throws IOException,
1461:                    TLVException {
1462:
1463:                // find the free space where certificates can be stored
1464:                files.select(UnusedSpacePath);
1465:
1466:                Vector freeSpace = new Vector();
1467:                doParseDF(files.readFile(), UnusedSpacePath, freeSpace, null,
1468:                        null);
1469:
1470:                Location[] blocks = new Location[freeSpace.size()];
1471:                TLV[] records = new TLV[freeSpace.size()];
1472:                for (int i = 0; i < freeSpace.size(); i++) {
1473:                    records[i] = (TLV) freeSpace.elementAt(i);
1474:                    blocks[i] = files.pathToLocation(records[i].child);
1475:                }
1476:
1477:                Location[] result = new Location[path.length];
1478:
1479:                for (int j = 0; j < path.length; j++) {
1480:                    if (path[j] == null) {
1481:                        continue;
1482:                    }
1483:
1484:                    byte[] data = path[j].getDERData();
1485:
1486:                    for (int i = 0; i < blocks.length; i++) {
1487:
1488:                        Location block = blocks[i];
1489:                        if (block.length < data.length) {
1490:                            continue;
1491:                        }
1492:
1493:                        block.length -= data.length;
1494:                        result[j] = new Location(block.path, block.offset
1495:                                + block.length, data.length);
1496:
1497:                        update(result[j].path, result[j].offset, data);
1498:
1499:                        // check if PIN is required for this update
1500:                        TLV t = records[i].child.next;
1501:                        if (t != null && t.type == TLV.OCTETSTR_TYPE) {
1502:
1503:                            int id;
1504:                            try {
1505:                                id = t.getId();
1506:                            } catch (TLVException e) {
1507:                                // should never happen
1508:                                return null;
1509:                            }
1510:
1511:                            for (int k = 0; k < PINs.length; k++) {
1512:                                if (PINs[k].id == id) {
1513:                                    updatePIN[k] = true;
1514:                                }
1515:                            }
1516:                        }
1517:
1518:                        // Update length of block
1519:
1520:                        t = records[i].child.child.next.next;
1521:
1522:                        update(UnusedSpacePath, t.valueOffset, Utils
1523:                                .shortToBytes(block.length));
1524:                        break;
1525:                    }
1526:                    if (result[j] == null) {
1527:                        return null;
1528:                    }
1529:                }
1530:                return result;
1531:            }
1532:
1533:            /**
1534:             * Finds place for new certificates directory entries and registers
1535:             * all necessary file updates.
1536:             * @param headers vector containing new CDF entries
1537:             * @return true if successful
1538:             */
1539:            private boolean putHeaders(Vector headers) {
1540:
1541:                Vector holes = null;
1542:
1543:                for (int i = 0; i < headers.size(); i++) {
1544:
1545:                    try {
1546:                        if (i == headers.size() - 1) {
1547:                            holes = new Vector();
1548:                            resetLoader(null, null, holes);
1549:                            loadObjects(USEFUL_CERTIFICATES_TAG);
1550:                        } else if (i == 0) {
1551:                            holes = new Vector();
1552:                            resetLoader(null, null, holes);
1553:                            loadObjects(USER_CERTIFICATES_TAG);
1554:                        }
1555:                    } catch (IOException e) {
1556:                        // should never happen
1557:                        return false;
1558:                    }
1559:
1560:                    TLV header = (TLV) headers.elementAt(i);
1561:                    byte[] data = header.getDERData();
1562:
1563:                    boolean found = false;
1564:                    for (int k = 0; k < holes.size(); k++) {
1565:
1566:                        Location l = (Location) holes.elementAt(k);
1567:                        if (l.length < data.length) {
1568:                            continue;
1569:                        }
1570:
1571:                        l.length -= data.length;
1572:                        update(l.path, l.offset + l.length, data);
1573:
1574:                        // now update the free space after the new record
1575:                        if (l.length != 0) {
1576:                            update(l.path, l.offset,
1577:                                    getEmptySpaceHeader(l.length));
1578:                            found = true;
1579:                        }
1580:                        break;
1581:                    }
1582:                    if (!found) {
1583:                        return false;
1584:                    }
1585:                }
1586:                return true;
1587:            }
1588:
1589:            /**
1590:             * Creates PKCS#15 path.
1591:             * @param path card file path
1592:             * @param offset offset in the file
1593:             * @param length length of data in the file
1594:             * @return TLV object that represents PKCS#15 path
1595:             */
1596:            private TLV createPath(short[] path, int offset, int length) {
1597:
1598:                TLV t = TLV.createSequence();
1599:                t.setChild(TLV.createOctetString(Utils.shortsToBytes(path)))
1600:                        .setNext(TLV.createInteger(Utils.shortToBytes(offset)))
1601:                        .setNext(
1602:                                TLV.createInteger(Utils.shortToBytes(length))
1603:                                        .setTag(0x80));
1604:                return t;
1605:            }
1606:
1607:            /**
1608:             * Removes credential.
1609:             * @param label the user friendly name associated with the
1610:             * certificate.
1611:             * @param isn the DER encoded ASN.1 structure that contains the
1612:             * certificate issuer and serial number
1613:             * @return operation result
1614:             * @throws SecurityException if a PIN is blocked due to an excessive
1615:             * number of incorrect PIN entries
1616:             */
1617:            public int removeCredential(String label, TLV isn) {
1618:
1619:                // load existing certificates (excluding trusted - can't delete
1620:                // them)
1621:                try {
1622:                    loadCertificates(true, false);
1623:                } catch (IOException e) {
1624:                    return SKIP;
1625:                }
1626:
1627:                Certificate cert = getCertificate(isn.child, isn.child.next);
1628:
1629:                if (cert == null) {
1630:                    // there is no such certificate
1631:                    return SKIP;
1632:                }
1633:
1634:                // IMPL_NOTE: should there be a warning?
1635:                // if (! cert.label.trim().equals(label)) {}
1636:
1637:                // find the certificate chain
1638:                Vector chain = getChain(cert, null, false);
1639:
1640:                // this chain can have common certificates with some other
1641:                // chains, in this case only part of the chain should be deleted
1642:                int count = chain.size();
1643:                check: for (int i = 1; i < chain.size(); i++) {
1644:                    for (int k = 0; k < Certificates.length; k++) {
1645:                        if (Certificates[k] != chain.elementAt(i - 1)
1646:                                && Certificates[k]
1647:                                        .isIssuedBy((Certificate) chain
1648:                                                .elementAt(i))) {
1649:                            count = i;
1650:                            break check;
1651:                        }
1652:                    }
1653:                }
1654:
1655:                try {
1656:                    if (MessageDialog
1657:                            .showMessage(
1658:                                    securityToken,
1659:                                    Resource
1660:                                            .getString(ResourceConstants.AMS_CONFIRMATION),
1661:                                    Resource
1662:                                            .getString(ResourceConstants.JSR177_CERTIFICATE_DELETED)
1663:                                            + "\n\n"
1664:                                            +
1665:                                            // "Label: " 
1666:                                            Resource
1667:                                                    .getString(ResourceConstants.JSR177_CERTIFICATE_LABEL)
1668:                                            + ": "
1669:                                            + cert.label
1670:                                            + "\n\n"
1671:                                            + Certificate.getInfo(cert.cert)
1672:                                            + "\n\n", true) == Dialog.CANCELLED) {
1673:                        return CANCEL;
1674:                    }
1675:                } catch (InterruptedException e) {
1676:                    return CANCEL;
1677:                }
1678:
1679:                startUpdate();
1680:                try {
1681:                    doRemove(chain, count);
1682:                    int pinStatus = checkPIN(PINs[0]);
1683:                    if (pinStatus == PIN_CANCELLED) {
1684:                        return CANCEL;
1685:                    }
1686:                    if (pinStatus == PIN_BLOCKED) {
1687:                        throw new SecurityException("PIN blocked");
1688:                    }
1689:                    if (pinStatus != PIN_DISABLED) {
1690:                        return ERROR;
1691:                    }
1692:                    doUpdate();
1693:                } catch (IOException e) {
1694:                    return ERROR;
1695:                }
1696:
1697:                //        typeInfo("RemoveCredential");
1698:                return SUCCESS;
1699:            }
1700:
1701:            /**
1702:             * Register all necessary file updates for certificate removal.
1703:             * @param chain certificate chain to be removed
1704:             * @param count the number of certificates to be removed
1705:             * @throws TLVException if parsing error occurs
1706:             * @throws IOException if I/O error occurs
1707:             */
1708:            private void doRemove(Vector chain, int count) throws IOException,
1709:                    TLVException {
1710:
1711:                // Load and parse UnusedSpace.
1712:                files.select(UnusedSpacePath);
1713:
1714:                Vector v_free = new Vector(); // records in UnusedSpace
1715:                Vector v_location = new Vector(); // their offsets
1716:                Vector v_hole = new Vector(); // empty space in the file
1717:                doParseDF(files.readFile(), UnusedSpacePath, v_free,
1718:                        v_location, v_hole);
1719:
1720:                TLV[] free = new TLV[v_free.size()];
1721:                v_free.copyInto(free);
1722:
1723:                Location[] block = new Location[free.length];
1724:                for (int i = 0; i < free.length; i++) {
1725:                    block[i] = files.pathToLocation(free[i].child);
1726:                }
1727:
1728:                for (int i = 0; i < count; i++) {
1729:
1730:                    Certificate cert = (Certificate) chain.elementAt(i);
1731:
1732:                    // remove the certificate header from CDF
1733:                    update(cert.header.path, cert.header.offset,
1734:                            getEmptySpaceHeader(cert.header.length));
1735:
1736:                    // Now area in data file must be marked as unused.
1737:                    // try to append/prepend the new block to existing blocks
1738:
1739:                    Location hole = cert.body;
1740:
1741:                    int head = -1;
1742:                    int tail = -1;
1743:                    int empty = -1;
1744:
1745:                    for (int k = 0; k < block.length; k++) {
1746:                        if (block[k] == null
1747:                                || !comparePaths(hole.path, block[k].path)) {
1748:                            continue;
1749:                        }
1750:                        if (block[k].length == 0) {
1751:                            empty = k;
1752:                            continue;
1753:                        }
1754:                        if (doesFollow(block[k], hole)) {
1755:                            head = k;
1756:                            continue;
1757:                        }
1758:                        if (doesFollow(hole, block[k])) {
1759:                            tail = k;
1760:                        }
1761:                    }
1762:
1763:                    if (head != -1 && tail != -1) {
1764:                        block[head].length = block[head].length + hole.length
1765:                                + block[tail].length;
1766:                        setBlockLength(free[head], block[head].length);
1767:
1768:                        Location newHole = (Location) v_location
1769:                                .elementAt(tail);
1770:                        deleteBlock(newHole);
1771:                        v_hole.addElement(newHole);
1772:                        block[tail] = null;
1773:                        continue;
1774:                    }
1775:
1776:                    if (head != -1) {
1777:                        block[head].length += hole.length;
1778:                        setBlockLength(free[head], block[head].length);
1779:                        continue;
1780:                    }
1781:
1782:                    if (tail != -1) {
1783:                        block[tail].offset -= hole.length;
1784:                        block[tail].length += hole.length;
1785:                        setBlockOffset(free[tail], block[tail].offset);
1786:                        setBlockLength(free[tail], block[tail].length);
1787:                        continue;
1788:                    }
1789:
1790:                    if (empty != -1) {
1791:                        block[empty].offset = hole.offset;
1792:                        block[empty].length = hole.length;
1793:                        setBlockOffset(free[empty], block[empty].offset);
1794:                        setBlockLength(free[empty], block[empty].length);
1795:                        continue;
1796:                    }
1797:
1798:                    // this is a new block, have to allocate new entry
1799:
1800:                    // generate new record with PIN-G authId
1801:                    TLV n = TLV.createSequence();
1802:                    TLV t = n.setChild(createPath(hole.path, hole.offset,
1803:                            hole.length));
1804:                    t
1805:                            .setNext(TLV
1806:                                    .createOctetString(new byte[] { (byte) PINs[0].id }));
1807:                    byte[] data = n.getDERData();
1808:
1809:                    // find space for new entry
1810:                    Location l = null;
1811:                    for (int k = 0; k < v_hole.size(); k++) {
1812:                        Location loc = (Location) v_hole.elementAt(k);
1813:                        if (loc.length >= data.length) {
1814:                            l = loc;
1815:                            break;
1816:                        }
1817:                    }
1818:
1819:                    if (l == null) {
1820:                        throw new IOException(
1821:                                "Can't allocate new entry in EF(UnusedSpace)");
1822:                    }
1823:
1824:                    // update data
1825:                    update(UnusedSpacePath, l.offset, data);
1826:                    l.offset += data.length;
1827:                    l.length -= data.length;
1828:                    if (l.length != 0) {
1829:                        update(UnusedSpacePath, l.offset,
1830:                                getEmptySpaceHeader(l.length));
1831:                    }
1832:                }
1833:            }
1834:
1835:            /**
1836:             * Modify offset in record of EF(UnusedSpace).
1837:             * @param t TLV object that represents the record
1838:             * @param offset the new offset value
1839:             */
1840:            private void setBlockOffset(TLV t, int offset) {
1841:
1842:                t = t.child.child.next;
1843:                update(UnusedSpacePath, t.valueOffset, Utils
1844:                        .shortToBytes(offset));
1845:            }
1846:
1847:            /**
1848:             * Modify length of block in record of EF(UnusedSpace).
1849:             * @param t TLV object that represents the record
1850:             * @param length the new length value
1851:             */
1852:            private void setBlockLength(TLV t, int length) {
1853:
1854:                t = t.child.child.next.next;
1855:                update(UnusedSpacePath, t.valueOffset, Utils
1856:                        .shortToBytes(length));
1857:            }
1858:
1859:            /**
1860:             * Mark record of EF(UnusedSpace) as unused.
1861:             * @param l location of the record
1862:             */
1863:            private void deleteBlock(Location l) {
1864:                update(UnusedSpacePath, l.offset, getEmptySpaceHeader(l.length));
1865:            }
1866:
1867:            /**
1868:             * Verifies if the second block starts right after the fist.
1869:             * @param a1 location of the first block
1870:             * @param a2 location of the second block
1871:             * @return true if the second block starts right after the fist
1872:             */
1873:            private static boolean doesFollow(Location a1, Location a2) {
1874:                return (a1.offset + a1.length == a2.offset);
1875:            }
1876:
1877:            /**
1878:             * Compares two paths.
1879:             * @param path1 the first path
1880:             * @param path2 the second path
1881:             * @return true if the paths are equal
1882:             */
1883:            private static boolean comparePaths(short[] path1, short[] path2) {
1884:
1885:                if (path1.length != path2.length) {
1886:                    return false;
1887:                }
1888:
1889:                for (int i = 0; i < path1.length; i++) {
1890:                    if (path1[i] != path2[i]) {
1891:                        return false;
1892:                    }
1893:                }
1894:                return true;
1895:            }
1896:
1897:            /** Vector contains locations of blocks that must be updated. */
1898:            private Vector updateLocations;
1899:            /** Vector contains values that must be written. */
1900:            private Vector updateData;
1901:            /**
1902:             * Flags that indicate which PINs must be verified before the
1903:             * update.
1904:             */
1905:            private boolean[] updatePIN;
1906:
1907:            /** Initialises the new update. */
1908:            private void startUpdate() {
1909:                updateLocations = new Vector();
1910:                updateData = new Vector();
1911:                updatePIN = new boolean[PINs.length];
1912:                updatePIN[0] = true;
1913:            }
1914:
1915:            /**
1916:             * Registers file modification.
1917:             * @param path file path
1918:             * @param offset offset in the file
1919:             * @param data data to be written
1920:             */
1921:            private void update(short[] path, int offset, byte[] data) {
1922:                updateLocations.addElement(new Location(path, offset, 0));
1923:                updateData.addElement(data);
1924:            }
1925:
1926:            /**
1927:             * Performs all the registered updates.
1928:             * @throws IOException if I/O error occurs
1929:             */
1930:            private void doUpdate() throws IOException {
1931:
1932:                for (int i = 0; i < updateLocations.size(); i++) {
1933:                    Location l = (Location) updateLocations.elementAt(i);
1934:                    files.select(l.path);
1935:                    byte[] d = (byte[]) updateData.elementAt(i);
1936:                    files.writeData(d, 0, d.length, l.offset);
1937:                }
1938:                updateLocations = null;
1939:                updateData = null;
1940:            }
1941:
1942:            /**
1943:             * Returns private key for given ID.
1944:             * @param id key identifier
1945:             * @return the key or null if not found
1946:             */
1947:            private PrivateKey getPrivateKey(byte[] id) {
1948:
1949:                for (int i = 0; i < PrKeys.length; i++) {
1950:                    if (Utils.byteMatch(id, PrKeys[i].id)) {
1951:                        return PrKeys[i];
1952:                    }
1953:                }
1954:                return null;
1955:            }
1956:
1957:            /**
1958:             * Returns certificates for given subject.
1959:             * @param subject TLV structure that represents RFC 2253 name.
1960:             * @return certificates for given subject
1961:             */
1962:            private Vector getCertsBySubject(TLV subject) {
1963:
1964:                Vector v = new Vector();
1965:                for (int i = 0; i < Certificates.length; i++) {
1966:                    if (RFC2253Name.compare(subject, Certificates[i]
1967:                            .getSubject())) {
1968:                        v.addElement(Certificates[i]);
1969:                    }
1970:                }
1971:                return v;
1972:            }
1973:
1974:            /**
1975:             * Returns certificate for given label.
1976:             * @param label the user friendly certificate label
1977:             * @return the certificate object or null if not found
1978:             */
1979:            private Certificate getCertificate(String label) {
1980:
1981:                for (int i = 0; i < Certificates.length; i++) {
1982:                    if (Certificates[i].label.equals(label)) {
1983:                        return Certificates[i];
1984:                    }
1985:                }
1986:                return null;
1987:            }
1988:
1989:            /**
1990:             * Returns certificate for given issuer and serial number.
1991:             * @param issuer TLV structure that represents RFC 2253 name.
1992:             * @param serialNumber certificate serial number
1993:             * @return the certificate object or null if not found
1994:             */
1995:            private Certificate getCertificate(TLV issuer, TLV serialNumber) {
1996:
1997:                for (int i = 0; i < Certificates.length; i++) {
1998:                    TLV t = Certificates[i].cert.child.child.skipOptional(0xa0);
1999:                    if (t.match(serialNumber) && t.next.next.match(issuer)) {
2000:                        return Certificates[i];
2001:                    }
2002:                }
2003:                return null;
2004:            }
2005:
2006:            /**
2007:             * Calculates public key hash for given X.509 certificate.
2008:             * @param cert TLV structure that represents X.509 certificate
2009:             * @return public key hash
2010:             * @throws TLVException if parsing error occurs
2011:             */
2012:            private static byte[] getKeyHash(TLV cert) throws TLVException {
2013:
2014:                TLV t = cert.child.child.skipOptional(0xa0).next.next.next.next.next.child;
2015:                // t is at subjectPublicKeyInfo.algorithm field
2016:
2017:                byte[] data;
2018:                int offset;
2019:                int length;
2020:
2021:                TLV m = t.child;
2022:                t = t.next;
2023:                if (m.match(TLV.createOID("1.2.840.113549.1.1.1"))) {
2024:                    // RSA
2025:                    data = (new TLV(t.data, t.valueOffset + 1).child)
2026:                            .getValue();
2027:                    offset = 0;
2028:                    length = data.length;
2029:                } else if (m.match(TLV.createOID("1.2.840.10045.2.1"))) {
2030:                    // ECDSA
2031:                    data = t.data;
2032:                    offset = t.valueOffset + 2;
2033:                    if (t.data[t.valueOffset + 1] == 4) {
2034:                        // uncompressed form
2035:                        length = (t.length - 2) / 2;
2036:                    } else {
2037:                        // compressed form
2038:                        length = (t.length - 2);
2039:                    }
2040:                } else {
2041:                    // PKCS#15 doesn't say anything about this case
2042:                    // just calculate the hash of subjectPublicKey data
2043:                    data = t.data;
2044:                    offset = t.valueOffset + 1;
2045:                    length = t.length - 1;
2046:                }
2047:
2048:                return Utils.getHash(data, offset, length);
2049:            }
2050:
2051:            /**
2052:             * Pads the string to 32 bytes as recommended in WIM and returns TLV
2053:             * value that can be used as label.
2054:             * @param label label string
2055:             * @return TLV object for new label
2056:             */
2057:            private static TLV createLabel(String label) {
2058:                int len = Utils.stringToBytes(label).length;
2059:                while (len < 32) {
2060:                    label = label + " ";
2061:                    len++;
2062:                }
2063:                return TLV.createUTF8String(label);
2064:            }
2065:
2066:            /**
2067:             * Creates block header that can be used to mark empty space in
2068:             * directory file.
2069:             * @param length free block length
2070:             * @return block header
2071:             */
2072:            private static byte[] getEmptySpaceHeader(int length) {
2073:
2074:                if (length == 1) {
2075:                    return new byte[] { (byte) 0xff };
2076:                }
2077:
2078:                if (length < 130) {
2079:                    return new byte[] { 0, (byte) (length - 2) };
2080:                }
2081:
2082:                if (length < 259) {
2083:                    return new byte[] { 0, (byte) 0x81, (byte) (length - 3) };
2084:                }
2085:
2086:                length -= 4;
2087:                return new byte[] { 0, (byte) 0x82, (byte) (length >> 8),
2088:                        (byte) length };
2089:            }
2090:
2091:            /**
2092:             * Parses EF(DF).
2093:             * @param data data to be parsed
2094:             * @param path file path
2095:             * @param objects method places objects from file into this vector.
2096:             *        Can be null. Contains values of TLV type
2097:             * @param locations method places location of objects into this
2098:             *        vector. Can be null. Contains values of type Location.
2099:             * @param freeBlocks method places locations of free memory in
2100:             *        EF(DF) into this vector. Can be null. Contains values of
2101:             *        type Location.
2102:             * @throws TLVException if parsing error occurs
2103:             */
2104:            private static void doParseDF(byte[] data, short[] path,
2105:                    Vector objects, Vector locations, Vector freeBlocks)
2106:                    throws TLVException {
2107:
2108:                int start = 0;
2109:
2110:                int current = 0;
2111:                while (current < data.length) {
2112:
2113:                    // free space - skip
2114:                    if (data[current] == (byte) 0xff) {
2115:                        current++;
2116:                        continue;
2117:                    }
2118:
2119:                    // TLV object
2120:                    TLV t = new TLV(data, current);
2121:
2122:                    // empty one - skip
2123:                    if (t.type == 0) {
2124:                        current = t.valueOffset + t.length;
2125:                        continue;
2126:                    }
2127:
2128:                    // real object
2129:
2130:                    if (objects != null) {
2131:                        objects.addElement(t);
2132:                    }
2133:
2134:                    if (locations != null) {
2135:                        locations.addElement(new Location(path, current,
2136:                                t.valueOffset + t.length - current));
2137:                    }
2138:
2139:                    if (freeBlocks != null && start < current) {
2140:                        freeBlocks.addElement(new Location(path, start, current
2141:                                - start));
2142:                    }
2143:
2144:                    current = t.valueOffset + t.length;
2145:                    start = current;
2146:                }
2147:                if (start < current && freeBlocks != null) {
2148:                    freeBlocks.addElement(new Location(path, start, current
2149:                            - start));
2150:                }
2151:            }
2152:
2153:            /**
2154:             * Generates a signature.
2155:             * @param nonRepudiation if true, the non-repudiation key must be
2156:             * used, otherwise - authentication key
2157:             * @param data the data to be signed
2158:             * @param options signature content options
2159:             * @param caNames array that contains parsed names of certificate
2160:             * authorities
2161:             * @return the DER encoded signature, null if the signature
2162:             * generation was cancelled by the user before completion
2163:             * @throws CMSMessageSignatureServiceException if an error occurs
2164:             * during signature generation
2165:             */
2166:            public byte[] generateSignature(boolean nonRepudiation,
2167:                    byte[] data, int options, TLV[] caNames)
2168:                    throws CMSMessageSignatureServiceException {
2169:
2170:                // load existing certificates
2171:                try {
2172:                    loadPrivateKeys();
2173:                    loadCertificates(true, true);
2174:                } catch (IOException e) {
2175:                    throw new CMSMessageSignatureServiceException(
2176:                            CMSMessageSignatureServiceException.SE_FAILURE);
2177:                }
2178:
2179:                // find certificate chains
2180:                Vector chains = getChains(nonRepudiation, caNames);
2181:                if (chains.size() == 0) {
2182:                    throw new CMSMessageSignatureServiceException(
2183:                            CMSMessageSignatureServiceException.CRYPTO_NO_CERTIFICATE);
2184:                }
2185:
2186:                // select certificate
2187:                Vector chain = selectChain(chains);
2188:                if (chain == null) {
2189:                    return null;
2190:                }
2191:
2192:                Certificate cert = (Certificate) chain.elementAt(0);
2193:                PrivateKey key = getPrivateKey(cert.id);
2194:                PINAttributes pin = getPIN(key.authId);
2195:
2196:                int pinStatus = checkPIN(pin);
2197:
2198:                if (pinStatus == PIN_BLOCKED) {
2199:                    throw new SecurityException();
2200:                }
2201:
2202:                if (pinStatus == PIN_CANCELLED) {
2203:                    return null;
2204:                }
2205:
2206:                TLV signedAttrs = new TLV(TLV.SET_TYPE);
2207:                TLV t = signedAttrs.setChild(TLV.createSequence());
2208:                t.setChild(TLV.createOID("1.2.840.113549.1.9.3")). // ContentType
2209:                        setNext(new TLV(TLV.SET_TYPE)).setChild(
2210:                                TLV.createOID("1.2.840.113549.1.7.1")); // data
2211:
2212:                t.next = TLV.createSequence();
2213:                t = t.next;
2214:
2215:                Calendar calendar = Calendar.getInstance();
2216:                calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
2217:
2218:                t.setChild(TLV.createOID("1.2.840.113549.1.9.5")). // signingTime
2219:                        setNext(new TLV(TLV.SET_TYPE)).setChild(
2220:                                TLV.createUTCTime(calendar));
2221:
2222:                t.next = TLV.createSequence();
2223:                t = t.next;
2224:
2225:                t.setChild(TLV.createOID("1.2.840.113549.1.9.4")). // messageDigest
2226:                        setNext(new TLV(TLV.SET_TYPE)).setChild(
2227:                                TLV.createOctetString(Utils.getHash(data, 0,
2228:                                        data.length)));
2229:
2230:                // generate signature
2231:                byte[] signature;
2232:                try {
2233:                    signature = signData(key, signedAttrs.getDERData());
2234:                } catch (IOException e) {
2235:                    throw new CMSMessageSignatureServiceException(
2236:                            CMSMessageSignatureServiceException.CRYPTO_FAILURE);
2237:                }
2238:
2239:                // format the signature
2240:                /*
2241:                 *   ContentInfo ::= SEQUENCE {
2242:                 *      contentType ContentType,
2243:                 *      content [0] EXPLICIT ANY DEFINED BY contentType }
2244:                 *
2245:                 *  ContentType ::= OBJECT IDENTIFIER
2246:                 *
2247:                 *  id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
2248:                 *      us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
2249:                 */
2250:
2251:                TLV ContentInfo = TLV.createSequence();
2252:                t = ContentInfo.setChild(TLV.createOID("1.2.840.113549.1.7.2"))
2253:                        .setNext(new TLV(0xa0)).setChild(TLV.createSequence());
2254:
2255:                /*
2256:                 *   t - SignedData
2257:                 *  SignedData ::= SEQUENCE {
2258:                 *    version CMSVersion,
2259:                 *     digestAlgorithms DigestAlgorithmIdentifiers,
2260:                 *    encapContentInfo EncapsulatedContentInfo,
2261:                 *    certificates [0] IMPLICIT CertificateSet OPTIONAL,
2262:                 *    - crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
2263:                 *    signerInfos SignerInfos }
2264:                 *
2265:                 *    DigestAlgorithmIdentifiers ::= SET OF
2266:                 *                                    DigestAlgorithmIdentifier
2267:                 */
2268:
2269:                t = t.setChild(TLV.createInteger(1)). // version
2270:                        setNext(new TLV(TLV.SET_TYPE)); // digestAlgorithms
2271:
2272:                TLV SHAAlgId = TLV.createSequence();
2273:                SHAAlgId.setChild(TLV.createOID("1.3.14.3.2.26")); // SHA-1
2274:
2275:                t.setChild(SHAAlgId.copy());
2276:
2277:                /*
2278:                 *   EncapsulatedContentInfo ::= SEQUENCE {
2279:                 *    eContentType ContentType,
2280:                 *    eContent [0] EXPLICIT OCTET STRING OPTIONAL }
2281:                 *
2282:                 *    ContentType ::= OBJECT IDENTIFIER
2283:                 *
2284:                 *    id-data OBJECT IDENTIFIER ::= { iso(1) member-body(2)
2285:                 *        us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 }
2286:                 */
2287:
2288:                t = t.setNext(TLV.createSequence());
2289:
2290:                TLV m = t.setChild(TLV.createOID("1.2.840.113549.1.7.1"));
2291:
2292:                if ((options & CMSMessageSignatureService.SIG_INCLUDE_CONTENT) != 0) {
2293:                    m.setNext(new TLV(0xa0)).setChild(
2294:                            TLV.createOctetString(data));
2295:                }
2296:
2297:                /*
2298:                 *   certificates [0] IMPLICIT CertificateSet OPTIONAL,
2299:                 *
2300:                 *  CertificateSet ::= SET OF CertificateChoices
2301:                 *
2302:                 * CertificateChoices ::= CHOICE {
2303:                 *   certificate Certificate,                 -- See X.509
2304:                 *  extendedCertificate [0] IMPLICIT ExtendedCertificate,
2305:                 *                                           -- Obsolete
2306:                 *  attrCert [1] IMPLICIT AttributeCertificate }
2307:                 *
2308:                 */
2309:
2310:                if ((options & CMSMessageSignatureService.SIG_INCLUDE_CERTIFICATE) != 0) {
2311:                    t = t.setNext(new TLV(0xa0));
2312:                    TLV n = t.setChild(cert.cert);
2313:                    for (int i = 1; i < chain.size(); i++) {
2314:                        n = n.setNext(((Certificate) chain.elementAt(i)).cert);
2315:                    }
2316:                }
2317:
2318:                /*
2319:                 *   signerInfos SignerInfos }
2320:                 *  SignerInfos ::= SET OF SignerInfo
2321:                 *
2322:                 *  SignerInfo ::= SEQUENCE {
2323:                 *    version CMSVersion,
2324:                 *    sid SignerIdentifier,
2325:                 *    digestAlgorithm DigestAlgorithmIdentifier,
2326:                 *    signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
2327:                 *    signatureAlgorithm SignatureAlgorithmIdentifier,
2328:                 *    signature SignatureValue,
2329:                 *    - unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }
2330:                 *
2331:                 *    SignerIdentifier ::= CHOICE {
2332:                 *      issuerAndSerialNumber IssuerAndSerialNumber,
2333:                 *      - subjectKeyIdentifier [0] SubjectKeyIdentifier }
2334:                 *
2335:                 *      IssuerAndSerialNumber ::= SEQUENCE {
2336:                 *        issuer Name,
2337:                 *        serialNumber CertificateSerialNumber }
2338:                 *
2339:                 */
2340:
2341:                t = t.setNext(new TLV(TLV.SET_TYPE)).setChild(
2342:                        TLV.createSequence()).setChild(TLV.createInteger(1))
2343:                        .setNext(cert.getIssuerAndSerialNumber()).setNext(
2344:                                SHAAlgId). // SHA-1
2345:                        setNext(signedAttrs).setTag(0xa0).setNext(
2346:                                cert.getKeyAlgorithmID()).setNext(
2347:                                new TLV(TLV.OCTETSTR_TYPE, signature, 1));
2348:
2349:                return ContentInfo.getDERData();
2350:            }
2351:
2352:            /**
2353:             * Finds certificate chains for specified operation.
2354:             * @param nonRepudiation if true, the non-repudiation key must be
2355:             * used, otherwise - authentication key
2356:             * @param caNames array that contains parsed names of certificate
2357:             * authorities
2358:             * @return vector of certificate chains
2359:             */
2360:            private Vector getChains(boolean nonRepudiation, TLV[] caNames) {
2361:
2362:                // find the chains
2363:                Vector chains = new Vector();
2364:                for (int i = 0; i < Certificates.length; i++) {
2365:                    PrivateKey key = getPrivateKey(Certificates[i].id);
2366:                    if ((key != null)
2367:                            && (nonRepudiation ? key.nonRepudiation
2368:                                    : key.authentication)) {
2369:                        Vector chain = getChain(Certificates[i], caNames, true);
2370:                        if (chain != null) {
2371:                            chains.addElement(chain);
2372:                        }
2373:                    }
2374:                }
2375:                return chains;
2376:            }
2377:
2378:            /**
2379:             * Builds certificate chain for given certificate.
2380:             * @param cert user certificate
2381:             * @param caNames array that contains parsed names of certificate
2382:             * authorities
2383:             * @param checkValidity check validity of certificates
2384:             * @return vector containing certificate chain or null
2385:             */
2386:            private Vector getChain(Certificate cert, TLV[] caNames,
2387:                    boolean checkValidity) {
2388:
2389:                Vector chain = new Vector();
2390:
2391:                while (true) {
2392:
2393:                    if (checkValidity && cert.isExpired()) {
2394:                        // the certificate is expired, can't build the chain
2395:                        return null;
2396:                    }
2397:
2398:                    chain.addElement(cert);
2399:                    TLV issuer = cert.getIssuer();
2400:
2401:                    // if this is the certificate issued by one of the CAs in
2402:                    // the list then the chain is complete
2403:                    if (caNames != null) {
2404:                        // check if we need any additional certificates
2405:                        for (int i = 0; i < caNames.length; i++) {
2406:                            if (RFC2253Name.compare(issuer, caNames[i])) {
2407:                                return chain;
2408:                            }
2409:                        }
2410:                    }
2411:
2412:                    // search for the issuer certificate
2413:                    boolean found = false;
2414:                    for (int i = 0; i < Certificates.length; i++) {
2415:                        Certificate next = Certificates[i];
2416:                        found = cert.isIssuedBy(next) && !chain.contains(next);
2417:                        if (found) {
2418:                            cert = next;
2419:                            break;
2420:                        }
2421:                    }
2422:
2423:                    if (!found) {
2424:                        // issuer certificate was not found
2425:                        // if caNames is null, the chain is good enough,
2426:                        // otherwise the chain is not found
2427:                        return caNames == null ? chain : null;
2428:                    }
2429:                }
2430:            }
2431:
2432:            /**
2433:             * Allows user to select certificate or cancel signature operation.
2434:             * @param chains array of certifcate chains
2435:             * @return user selected certificate chain
2436:             */
2437:            private Vector selectChain(Vector chains) {
2438:
2439:                String[] labels = new String[chains.size()];
2440:                for (int i = 0; i < chains.size(); i++) {
2441:                    labels[i] = ((Certificate) ((Vector) chains.elementAt(i))
2442:                            .elementAt(0)).label;
2443:                }
2444:
2445:                int chainIndex = -1;
2446:                try {
2447:                    if (chains.size() == 1) {
2448:                        // if only one chain is found show certificate label to
2449:                        // the user
2450:
2451:                        if (MessageDialog
2452:                                .showMessage(
2453:                                        securityToken,
2454:                                        Resource
2455:                                                .getString(ResourceConstants.AMS_CONFIRMATION),
2456:                                        Resource
2457:                                                .getString(ResourceConstants.JSR177_CERTIFICATE_USED)
2458:                                                + labels[0], true) != Dialog.CANCELLED) {
2459:                            chainIndex = 0;
2460:                        }
2461:                    } else {
2462:                        // if more than one chain is found ask user to choose
2463:                        // one of them
2464:                        chainIndex = MessageDialog
2465:                                .chooseItem(
2466:                                        securityToken,
2467:                                        Resource
2468:                                                .getString(ResourceConstants.JSR177_SELECT_CERTIFICATE),
2469:                                        Resource
2470:                                                .getString(ResourceConstants.JSR177_CERTIFICATES_AVAILABLE),
2471:                                        labels);
2472:                    }
2473:                } catch (InterruptedException e) {
2474:                }
2475:
2476:                return (chainIndex == -1) ? null : (Vector) chains
2477:                        .elementAt(chainIndex);
2478:            }
2479:
2480:            // IMPL_NOTE: delete after debugging
2481:            /**
2482:             * Debug output.
2483:             * @param Title title text
2484:             * /
2485:            private void typeInfo(String Title) {
2486:
2487:                System.out.println("***********************************");
2488:                System.out.println("debug " + Title);
2489:                System.out.println("***********************************");
2490:
2491:                try {
2492:                    files.select(UnusedSpacePath);
2493:
2494:                    Vector v_free = new Vector();     // records in UnusedSpace
2495:                    Vector v_location = new Vector(); // their offsets
2496:                    Vector v_hole = new Vector();     // empty space in the file
2497:                    doParseDF(files.readFile(), UnusedSpacePath,
2498:                                 v_free, v_location, v_hole);
2499:
2500:                    System.out.println("-------------------------------------");
2501:                    System.out.println("Unused space entries " + v_free.size());
2502:                    System.out.println();
2503:
2504:                    for (int i = 0; i < v_free.size(); i++) {
2505:
2506:                        ((Location) v_location.elementAt(i)).print();
2507:                        ((TLV) v_free.elementAt(i)).print();
2508:                        System.out.println();
2509:                    }
2510:
2511:                    System.out.println("-------------------------------------");
2512:                    System.out.println("Holes in UnusedSpace " + v_hole.size());
2513:                    System.out.println();
2514:
2515:                    for (int i = 0; i < v_hole.size(); i++) {
2516:                        ((Location) v_hole.elementAt(i)).print();
2517:                        System.out.println();
2518:                    }
2519:
2520:                    loadCertificates(true, true);
2521:
2522:                    System.out.println("-------------------------------------");
2523:                    System.out.println("Certificates " + Certificates.length);
2524:                    for (int i = 0; i < Certificates.length; i++) {
2525:                        Certificates[i].print();
2526:                    }
2527:
2528:                } catch (Exception e) {
2529:                    System.out.println("Exception in typeInfo " + e);
2530:                }
2531:            }
2532:             */
2533:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.