Source Code Cross Referenced for PKIApplet.java in  » 6.0-JDK-Modules » j2me » com » sun » satsa » pkiapplet » 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.pkiapplet 
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.pkiapplet;
0028:
0029:        import javacard.framework.*;
0030:        import javacard.security.*;
0031:        import javacardx.crypto.Cipher;
0032:
0033:        /**
0034:         * Card side application for PKI implementation. Supports subset of
0035:         * WIM functionality.
0036:         */
0037:        public class PKIApplet extends Applet {
0038:
0039:            /** Constant that is used to avoid '(short) x' notation. */
0040:            static final byte x0 = 0;
0041:            /** Constant that is used to avoid '(short) x' notation. */
0042:            static final byte x1 = 1;
0043:            /** Constant that is used to avoid '(short) x' notation. */
0044:            static final byte x2 = 2;
0045:            /** Constant that is used to avoid '(short) x' notation. */
0046:            static final byte x3 = 3;
0047:            /** Constant that is used to avoid '(short) x' notation. */
0048:            static final byte x4 = 4;
0049:            /** Constant that is used to avoid '(short) x' notation. */
0050:            static final byte x5 = 5;
0051:            /** Constant that is used to avoid '(short) x' notation. */
0052:            static final byte x6 = 6;
0053:            /** Constant that is used to avoid '(short) x' notation. */
0054:            static final byte x8 = 8;
0055:
0056:            /** INS byte for command APDU. */
0057:            static final byte INS_VERIFY = (byte) 0x20;
0058:            /** INS byte for command APDU. */
0059:            static final byte INS_SELECT = (byte) 0xa4;
0060:            /** INS byte for command APDU. */
0061:            static final byte INS_READ = (byte) 0xb0;
0062:            /** INS byte for command APDU. */
0063:            static final byte INS_UPDATE = (byte) 0xd6;
0064:            /** INS byte for command APDU. */
0065:            static final byte INS_MSE = (byte) 0x22;
0066:            /** INS byte for command APDU. */
0067:            static final byte INS_PSO = (byte) 0x2a;
0068:
0069:            /** INS byte for command APDU. */
0070:            static final byte INS_NEW = (byte) 0xBC;
0071:
0072:            /** DigestInfo structure size for RSA signature. */
0073:            static final short digestLength = 35;
0074:            /** Temporaru buffer for RSA signature. */
0075:            static byte[] signBuffer = new byte[digestLength];
0076:
0077:            /** If false, applet always report that PINs are validated. */
0078:            static boolean verifyPINs = true;
0079:
0080:            /** If false, key generation is disabled. */
0081:            static boolean supportKeyGeneration = true;
0082:
0083:            /** PIN identifiers. */
0084:            byte[] PIN_REFs;
0085:            /** PIN objects. */
0086:            OwnerPIN[] PINs;
0087:            /** Private keys. */
0088:            PrivateKey[] keys;
0089:            /** Root DF for entire file structure. */
0090:            DFile top;
0091:            /**
0092:             * Root DF for WIM application. All relative paths start from
0093:             * here. */
0094:            DFile base;
0095:            /** Currently selected file. */
0096:            File current;
0097:            /** Flag that indicates that SE is restored. */
0098:            boolean isSERestored;
0099:            /** Flag that indicates that private key path was set properly. */
0100:            boolean isKeyFileSet;
0101:            /** Private key number for signature generation. */
0102:            short keyNum;
0103:            /** Cipher object. */
0104:            Cipher cipher;
0105:            /** MessageDigest object for key hash calculation. */
0106:            MessageDigest digest;
0107:            /** Number of unused keys. */
0108:            static short unusedKeys = 0;
0109:
0110:            /** Constructor. */
0111:            PKIApplet() {
0112:
0113:                if (Data.PINs == null) {
0114:                    CardRuntimeException.throwIt(x0);
0115:                }
0116:                cipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
0117:                if (supportKeyGeneration) {
0118:                    digest = MessageDigest.getInstance(MessageDigest.ALG_SHA,
0119:                            false);
0120:                }
0121:                register();
0122:            }
0123:
0124:            /**
0125:             * To create an instance of the Applet subclass, the JCRE will call
0126:             * this static method first.
0127:             * @param bArray the array containing installation parameters
0128:             * @param bOffset the starting offset in bArray
0129:             * @param bLength the length in bytes of the parameter data in bArray
0130:             */
0131:            public static void install(byte[] bArray, short bOffset,
0132:                    byte bLength) {
0133:                new PKIApplet();
0134:            }
0135:
0136:            /**
0137:             * Called by the JCRE to inform this applet that it has been
0138:             * selected. When invoked first time initialises the file system.
0139:             * @return true
0140:             */
0141:            public boolean select() {
0142:
0143:                if (Data.PINs != null) {
0144:                    init();
0145:                }
0146:                current = base;
0147:                isSERestored = false;
0148:                return true;
0149:            }
0150:
0151:            /**
0152:             * Called by the JCRE to inform this applet that it has been
0153:             * deselected. When invoked PIN-G should be reset.
0154:             */
0155:            public void deselect() {
0156:                if (PINs != null) {
0157:                    PINs[0].reset();
0158:                }
0159:            }
0160:
0161:            /**
0162:             * Initialises the WIM data structures.
0163:             */
0164:            void init() {
0165:
0166:                Parser.init(Data.PINs);
0167:                short cnt = Parser.getByte();
0168:
0169:                PIN_REFs = new byte[(short) (cnt + Data.freePINSlots)];
0170:                PINs = new OwnerPIN[(short) (cnt + Data.freePINSlots)];
0171:
0172:                for (short i = 0; i < cnt; i++) {
0173:
0174:                    PIN_REFs[i] = Parser.getByte();
0175:                    byte len = Parser.getByte();
0176:                    PINs[i] = new OwnerPIN(x3, x8);
0177:                    PINs[i].update(Data.PINs, Parser.offset, len);
0178:                    Parser.skip(len);
0179:                }
0180:
0181:                Parser.init(Data.PrivateKeys);
0182:                cnt = Parser.getByte();
0183:                keys = new PrivateKey[(short) (cnt + Data.freeKeySlots)];
0184:                short keyPos = 0;
0185:                // calculate start of first key in a file
0186:                short privKeyStart = (short) (Data.PrKDFOffset
0187:                        + Data.newPrivKeyOffset - Data.privKeyRecordSize * cnt);
0188:                short pubKeyStart = (short) (Data.PuKDFOffset
0189:                        + Data.newPubKeyOffset - Data.pubKeyRecordSize * cnt);
0190:                for (short i = 0; i < cnt; i++) {
0191:                    PrivateKey key = new PrivateKey(this );
0192:                    if (key.value != null) {
0193:                        keys[keyPos++] = key;
0194:                    } else {
0195:                        // This key is not supported by card
0196:                        byte[] files = Data.Files;
0197:                        short tail = (short) (cnt + Data.freeKeySlots - keyPos - 1);
0198:                        if (tail > 0) {
0199:                            // Shift up private keys
0200:                            short privOffset = (short) (privKeyStart + Data.privKeyRecordSize
0201:                                    * keyPos);
0202:                            Util
0203:                                    .arrayCopyNonAtomic(
0204:                                            files,
0205:                                            (short) (privOffset + Data.privKeyRecordSize),
0206:                                            files,
0207:                                            privOffset,
0208:                                            (short) (Data.privKeyRecordSize * tail));
0209:                            privOffset = (short) ((privKeyStart + Data.privKeyRecordSize
0210:                                    * (keyPos + tail)));
0211:
0212:                            // Shift up public keys
0213:                            short pubOffset = (short) (pubKeyStart + Data.pubKeyRecordSize
0214:                                    * keyPos);
0215:                            Util
0216:                                    .arrayCopyNonAtomic(
0217:                                            files,
0218:                                            (short) (pubOffset + Data.pubKeyRecordSize),
0219:                                            files,
0220:                                            pubOffset,
0221:                                            (short) (Data.pubKeyRecordSize * tail));
0222:                            pubOffset = (short) ((pubKeyStart + Data.pubKeyRecordSize
0223:                                    * (keyPos + tail)));
0224:                        }
0225:                    }
0226:                }
0227:                Data.newPrivKeyOffset = (short) (privKeyStart
0228:                        - Data.PrKDFOffset + keyPos * Data.privKeyRecordSize);
0229:                Data.newPubKeyOffset = (short) (pubKeyStart - Data.PuKDFOffset + keyPos
0230:                        * Data.pubKeyRecordSize);
0231:
0232:                unusedKeys = (short) (keys.length - Data.freeKeySlots - keyPos);
0233:                Parser.init(Data.Files);
0234:                top = (DFile) readFile(null);
0235:
0236:                if (base == null) {
0237:                    ISOException.throwIt((short) 0x9001);
0238:                }
0239:
0240:                Data.PINs = null;
0241:                Data.PrivateKeys = null;
0242:
0243:                // IMPL_NOTE: debug check - remove
0244:                if (Parser.offset != Data.Files.length) {
0245:                    ISOException.throwIt((short) 0x9001);
0246:                }
0247:            }
0248:
0249:            /**
0250:             * Creates new file object.
0251:             * @param parent parent DF for this file
0252:             * @return the new file object
0253:             */
0254:            File readFile(DFile parent) {
0255:
0256:                short id = Parser.getShort();
0257:                short type = Parser.getByte();
0258:                short length = Parser.getShort();
0259:
0260:                if ((type & File.DIR) == 0) {
0261:
0262:                    EFile f;
0263:                    if ((type & File.EMPTY) == 0) {
0264:                        f = new EFile(parent, id, type, Parser.offset, length,
0265:                                Data.Files);
0266:                        Parser.skip(length);
0267:                    } else {
0268:                        type &= ~File.EMPTY;
0269:                        byte[] data = new byte[length];
0270:                        short dlen = Parser.getShort();
0271:                        Util.arrayCopyNonAtomic(Data.Files, Parser.offset,
0272:                                data, (short) 0, dlen);
0273:                        f = new EFile(parent, id, type, (short) 0, length, data);
0274:                        Parser.skip(dlen);
0275:                    }
0276:                    return f;
0277:                }
0278:
0279:                DFile f = new DFile(parent, id, type);
0280:
0281:                File[] files = new File[length];
0282:                for (short i = 0; i < length; i++) {
0283:                    files[i] = readFile(f);
0284:                }
0285:
0286:                f.files = files;
0287:
0288:                if (type == File.WIM) {
0289:                    base = f;
0290:                }
0291:
0292:                return f;
0293:            }
0294:
0295:            /**
0296:             * Main entry point.
0297:             * @param apdu command APDU
0298:             */
0299:            public void process(APDU apdu) {
0300:
0301:                byte[] data = apdu.getBuffer();
0302:                byte CLA = (byte) (data[ISO7816.OFFSET_CLA] & 0xF0);
0303:                byte INS = data[ISO7816.OFFSET_INS];
0304:
0305:                if (CLA == 0 && INS == (byte) (0xA4)
0306:                        && data[ISO7816.OFFSET_P1] == 4) {
0307:                    return;
0308:                }
0309:
0310:                if (CLA != (byte) 0x80) {
0311:                    ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
0312:                }
0313:                switch (INS) {
0314:
0315:                case INS_SELECT:
0316:                    selectFile(apdu);
0317:                    return;
0318:
0319:                case INS_READ:
0320:                    read(apdu);
0321:                    return;
0322:
0323:                case INS_UPDATE:
0324:                    update(apdu);
0325:                    return;
0326:
0327:                case INS_VERIFY:
0328:                    verify(apdu);
0329:                    return;
0330:
0331:                case INS_MSE:
0332:                    manageSE(apdu);
0333:                    return;
0334:
0335:                case INS_PSO:
0336:                    sign(apdu);
0337:                    return;
0338:
0339:                case INS_NEW:
0340:                    if (supportKeyGeneration) {
0341:                        newKey(apdu);
0342:                        return;
0343:                    }
0344:                    break;
0345:                }
0346:
0347:                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
0348:            }
0349:
0350:            /**
0351:             * Handles SELECT FILE APDU.
0352:             * @param apdu command APDU
0353:             */
0354:            void selectFile(APDU apdu) {
0355:
0356:                byte[] data = apdu.getBuffer();
0357:
0358:                if (Util.getShort(data, x2) != 0) {
0359:                    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
0360:                }
0361:
0362:                checkDataSize(x2, apdu);
0363:
0364:                File f = select(Util.getShort(data, x5));
0365:
0366:                if (f == null) {
0367:                    ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
0368:                }
0369:
0370:                current = f;
0371:
0372:                if (current.isDF()) {
0373:
0374:                    Util.setShort(data, x0, (short) 0x6f00);
0375:                    apdu.setOutgoingAndSend(x0, x2);
0376:                } else {
0377:
0378:                    Util.setShort(data, x0, (short) 0x6f04);
0379:                    Util.setShort(data, x2, (short) 0x8002);
0380:                    Util.setShort(data, x4, ((EFile) current).length);
0381:                    apdu.setOutgoingAndSend(x0, x6);
0382:                }
0383:            }
0384:
0385:            /**
0386:             * Selects the file specified by file identifier.
0387:             * @param id file identifier
0388:             * @return selected file
0389:             */
0390:            File select(short id) {
0391:
0392:                DFile f;
0393:                if (current.isDF()) {
0394:                    f = (DFile) current;
0395:                } else {
0396:                    f = current.parent;
0397:                }
0398:
0399:                File x = f.getFile(id);
0400:                if (x != null) {
0401:                    return x;
0402:                }
0403:
0404:                f = f.parent;
0405:
0406:                if (f == null) {
0407:                    return null;
0408:                }
0409:
0410:                return f.getFile(id);
0411:            }
0412:
0413:            /**
0414:             * Handles READ BINARY APDU.
0415:             * @param apdu command APDU
0416:             */
0417:            void read(APDU apdu) {
0418:
0419:                if (current.isDF()) {
0420:                    ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
0421:                }
0422:
0423:                EFile f = (EFile) current;
0424:
0425:                byte[] data = apdu.getBuffer();
0426:
0427:                short offset = Util.getShort(data, x2);
0428:                if (offset < 0 || offset > f.length) {
0429:                    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
0430:                }
0431:
0432:                short len = (short) (data[x4] & 0xff);
0433:                if ((short) (offset + len) > f.length) {
0434:                    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
0435:                }
0436:
0437:                apdu.setOutgoing();
0438:                apdu.setOutgoingLength(len);
0439:                apdu.sendBytesLong(f.data, (short) (f.offset + offset), len);
0440:            }
0441:
0442:            /**
0443:             * Handles UPDATE BINARY apdu.
0444:             * @param apdu command APDU
0445:             */
0446:            void update(APDU apdu) {
0447:
0448:                if (current.isDF()) {
0449:                    ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
0450:                }
0451:
0452:                EFile f = (EFile) current;
0453:
0454:                if (!(f.type == File.UPDATE && isValidated(PINs[0]))) {
0455:                    ISOException
0456:                            .throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
0457:                }
0458:
0459:                byte[] data = apdu.getBuffer();
0460:
0461:                short offset = Util.getShort(data, x2);
0462:                if (offset < 0) {
0463:                    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
0464:                }
0465:
0466:                short len = (short) (data[x4] & 0xff);
0467:
0468:                if ((short) (offset + len) > f.length) {
0469:                    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
0470:                }
0471:
0472:                short l = apdu.setIncomingAndReceive();
0473:                short off = 5;
0474:
0475:                while (l > 0) {
0476:                    Util.arrayCopyNonAtomic(data, off, f.data,
0477:                            (short) (f.offset + offset), l);
0478:                    offset += l;
0479:                    l = apdu.receiveBytes(x0);
0480:                    off = 0;
0481:                }
0482:            }
0483:
0484:            /**
0485:             * Handles PIN related APDUs.
0486:             * @param apdu command APDU
0487:             */
0488:            void verify(APDU apdu) {
0489:
0490:                if (current.type != File.PIN) {
0491:                    ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
0492:                }
0493:
0494:                byte[] data = apdu.getBuffer();
0495:
0496:                short pin_num = -1;
0497:                for (short i = 0; i < (short) (PIN_REFs.length - Data.freePINSlots); i++) {
0498:                    if (PIN_REFs[i] == data[x3]) {
0499:                        pin_num = i;
0500:                        break;
0501:                    }
0502:                }
0503:
0504:                if (pin_num == -1 || data[x2] != 0) {
0505:                    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
0506:                }
0507:
0508:                OwnerPIN pin = PINs[pin_num];
0509:
0510:                if (data[x4] == 0) {
0511:
0512:                    if (isValidated(pin)) {
0513:                        return; // SW = 0x9000
0514:                    }
0515:
0516:                    if (pin.getTriesRemaining() == 0) {
0517:                        ISOException.throwIt(ISO7816.SW_FILE_INVALID);
0518:                    }
0519:
0520:                    ISOException.throwIt((short) (0x6300 | pin
0521:                            .getTriesRemaining()));
0522:                }
0523:
0524:                short len = apdu.setIncomingAndReceive();
0525:                if (len > 8) { // too long, set to 0 to update PIN
0526:                    len = 0;
0527:                }
0528:                pin.check(data, x5, (byte) len);
0529:
0530:                if (isValidated(pin)) {
0531:                    return; // SW = 0x9000
0532:                }
0533:
0534:                ISOException.throwIt((short) 0x6300);
0535:            }
0536:
0537:            /**
0538:             * Hanldes MANAGE SECURITY ENVIRONMENT APDUs.
0539:             * @param apdu command APDU
0540:             */
0541:            void manageSE(APDU apdu) {
0542:
0543:                byte[] data = apdu.getBuffer();
0544:
0545:                if (data[x2] == (byte) 0xf3) {
0546:
0547:                    if (data[x3] != Data.WIM_GENERIC_RSA_ID) {
0548:                        ISOException.throwIt((short) 0x6600);
0549:                    }
0550:
0551:                    isSERestored = true;
0552:                    isKeyFileSet = false;
0553:                    keyNum = -1;
0554:                    return;
0555:                }
0556:
0557:                if (!isSERestored || Util.getShort(data, x2) != (short) 0x41b6) {
0558:                    ISOException.throwIt((short) 0x6600);
0559:                }
0560:
0561:                File keyFile = current;
0562:
0563:                short len = apdu.setIncomingAndReceive();
0564:                short index = 5;
0565:                len += index;
0566:
0567:                try {
0568:                    while (index < len) {
0569:
0570:                        byte tag = data[index++];
0571:                        byte l = data[index++];
0572:
0573:                        if (l <= 0 || l > 32) {
0574:                            ISOException.throwIt((short) 0x6600);
0575:                        }
0576:
0577:                        if (tag == (byte) 0x84) { // private key reference
0578:
0579:                            if (l != 1) {
0580:                                ISOException.throwIt((short) 0x6600);
0581:                            }
0582:
0583:                            for (short i = 0; i < (short) (keys.length
0584:                                    - Data.freeKeySlots - unusedKeys); i++) {
0585:
0586:                                if (data[index] == keys[i].id) {
0587:                                    keyNum = i;
0588:                                    break;
0589:                                }
0590:                            }
0591:                        } else if (tag == (byte) 0x81) { // private key DF path
0592:                            keyFile = getFile(data, index, l);
0593:                        } else {
0594:                            ISOException.throwIt((short) 0x6A80); // invalid tag
0595:                        }
0596:
0597:                        // path (id, relative or complete)
0598:                        index += l;
0599:                    }
0600:                } catch (ArrayIndexOutOfBoundsException e) {
0601:                    keyNum = -1;
0602:                }
0603:
0604:                if (keyNum == -1 || keyFile == null
0605:                        || keyFile.type != File.PrivateKeyFile) {
0606:                    ISOException.throwIt((short) 0x6600);
0607:                }
0608:
0609:                EFile f = (EFile) keyFile;
0610:                isKeyFileSet = (f.data[f.offset] == keys[keyNum].id);
0611:
0612:                if (!isKeyFileSet) {
0613:                    ISOException.throwIt((short) 0x6600);
0614:                }
0615:            }
0616:
0617:            /**
0618:             * Allocates new key and, if necessary, PIN.
0619:             * @param apdu the command APDU. APDU data contains key type
0620:             * (byte, 0 - authenticatiuon, 1 - non-repudiation), key lenght in
0621:             * bits (2 byte value). For non-repudiation key after that goes
0622:             * initial PIN value (8 bytes) and label (32 bytes). If p1 = 1
0623:             * the command just verifies that a new key can be generated.
0624:             */
0625:            void newKey(APDU apdu) {
0626:
0627:                apdu.setIncomingAndReceive();
0628:                byte[] data = apdu.getBuffer();
0629:
0630:                boolean nonRepudiation = (data[x5] == 1);
0631:
0632:                if (Data.freeKeySlots == 0
0633:                        || (nonRepudiation && Data.freePINSlots == 0)) {
0634:                    ISOException.throwIt((short) 0x9001);
0635:                }
0636:
0637:                short keyLen = Util.getShort(data, x6);
0638:
0639:                if (keyLen > (short) ((data.length - 1) * 8)) {
0640:                    ISOException.throwIt((short) 0x9001);
0641:                }
0642:
0643:                // check if keyLen & RSA algorithm are supported by card 
0644:                if (!Pairs.tryKeyPair(keyLen)) {
0645:                    ISOException.throwIt((short) 0x9001);
0646:                }
0647:
0648:                if (data[x2] == 1) {
0649:                    Util.setShort(data, x0, (short) 0x1234);
0650:                    Util.setShort(data, x2, (short) 0x4321);
0651:                    apdu.setOutgoingAndSend(x0, x4);
0652:                    return;
0653:                }
0654:
0655:                /*
0656:                 * IMPL_NOTE: For testing purposes return existing key instead of new one
0657:                 for (short i = 0; i < (short)(keys.length - Data.freeKeySlots - unusedKeys); i++) {
0658:                 if (keys[i].keyLen == keyLen 
0659:                 && keys[i].nonRepudiation == nonRepudiation) {
0660:                 data[0] = (byte)keys[i].id;
0661:                 apdu.setOutgoingAndSend(x0, x1);
0662:                 return;
0663:                 }
0664:                 }
0665:                 */
0666:
0667:                try {
0668:                    short pinIndex = 0;
0669:
0670:                    if (nonRepudiation) {
0671:                        // new PIN must be allocated
0672:                        pinIndex = (short) (PINs.length - Data.freePINSlots);
0673:
0674:                        OwnerPIN pin = new OwnerPIN((byte) 3, (byte) 8);
0675:                        pin.update(data, x8, (byte) 8);
0676:                        pin.check(data, x8, (byte) 8);
0677:                        PINs[pinIndex] = pin;
0678:                        PIN_REFs[pinIndex] = Data.newPINRef;
0679:
0680:                        Util
0681:                                .arrayCopy(
0682:                                        data,
0683:                                        (short) 16,
0684:                                        Data.Files,
0685:                                        (short) (Data.AODFOffset
0686:                                                + Data.newPINOffset + Data.PINLabelOffset),
0687:                                        (short) 32);
0688:                    }
0689:
0690:                    KeyPair p = Pairs.getKeyPair(keyLen);
0691:                    p.genKeyPair();
0692:
0693:                    PrivateKey key = new PrivateKey(this , Data.newKeyID,
0694:                            PINs[pinIndex], nonRepudiation, keyLen,
0695:                            (RSAPrivateKey) p.getPrivate());
0696:
0697:                    RSAPublicKey pk = (RSAPublicKey) p.getPublic();
0698:
0699:                    EFile f = (EFile) base.getFile(Data.newFileID);
0700:                    f.data = encodePublicKey(pk, data);
0701:                    f.offset = 0;
0702:                    f.length = (short) (f.data.length);
0703:
0704:                    byte[] hash = getKeyHash(pk, data);
0705:                    byte[] files = Data.Files;
0706:
0707:                    short offset = (short) (Data.PuKDFOffset + Data.newPubKeyOffset);
0708:                    Util.arrayCopy(hash, x0, files,
0709:                            (short) (offset + Data.pubHashOffset), (short) 20);
0710:
0711:                    Util.setShort(files,
0712:                            (short) (offset + Data.pubKeyLengthOffset), keyLen);
0713:
0714:                    offset = (short) (Data.PrKDFOffset + Data.newPrivKeyOffset);
0715:
0716:                    files[(short) (offset + Data.privPINIDOffset)] = nonRepudiation ? Data.newPINID
0717:                            : Data.PIN_G_ID;
0718:
0719:                    Util.arrayCopy(hash, x0, files,
0720:                            (short) (offset + Data.privHashOffset), (short) 20);
0721:
0722:                    Util
0723:                            .setShort(
0724:                                    files,
0725:                                    (short) (offset + Data.privKeyLengthOffset),
0726:                                    keyLen);
0727:                    offset += Data.privUsageOffset;
0728:                    if (nonRepudiation) {
0729:                        files[offset++] = 6;
0730:                        files[offset++] = 0;
0731:                        files[offset++] = 0x40;
0732:                    } else {
0733:                        files[offset++] = 7;
0734:                        files[offset++] = 0x20;
0735:                        files[offset++] = 0;
0736:                    }
0737:
0738:                    data[0] = Data.newKeyID;
0739:                    apdu.setOutgoingAndSend(x0, x1);
0740:
0741:                    JCSystem.beginTransaction();
0742:
0743:                    if (nonRepudiation) {
0744:                        Data.freePINSlots--;
0745:                        Data.newPINID++;
0746:                        Data.newPINRef++;
0747:                        files[(short) (Data.AODFOffset + Data.newPINOffset)] = 0x30;
0748:                        Data.newPINOffset += Data.PINRecordSize;
0749:                    }
0750:
0751:                    keys[(short) (keys.length - Data.freeKeySlots - unusedKeys)] = key;
0752:                    Data.freeKeySlots--;
0753:                    Data.newFileID += 2;
0754:                    Data.newKeyID++;
0755:                    files[(short) (Data.PrKDFOffset + Data.newPrivKeyOffset)] = 0x30;
0756:                    files[(short) (Data.PuKDFOffset + Data.newPubKeyOffset)] = 0x30;
0757:                    Data.newPrivKeyOffset += Data.privKeyRecordSize;
0758:                    Data.newPubKeyOffset += Data.pubKeyRecordSize;
0759:
0760:                    JCSystem.commitTransaction();
0761:                } catch (ISOException ie) {
0762:                    throw ie;
0763:                } catch (Exception e) {
0764:                    ISOException.throwIt((short) 0x9001);
0765:                }
0766:            }
0767:
0768:            /**
0769:             * Generates DER encoded RSA public key.
0770:             * @param pk the key
0771:             * @param data temporary data buffer
0772:             * @return DER encoded RSA public key
0773:             */
0774:            static byte[] encodePublicKey(RSAPublicKey pk, byte[] data) {
0775:
0776:                short modulusLength = pk.getModulus(data, (short) 0);
0777:                boolean padModulus = ((data[0] & 0x80) != 0);
0778:
0779:                if (padModulus) {
0780:                    modulusLength++;
0781:                }
0782:
0783:                short size = getDERSize(modulusLength);
0784:
0785:                short exponentLength = pk.getExponent(data, (short) 0);
0786:                boolean padExponent = ((data[0] & 0x80) != 0);
0787:
0788:                if (padExponent) {
0789:                    exponentLength++;
0790:                }
0791:
0792:                size += getDERSize(exponentLength);
0793:
0794:                byte[] der = new byte[getDERSize(size)];
0795:
0796:                // generate public key record
0797:
0798:                short offset = 0;
0799:                der[offset++] = 0x30;
0800:                offset = putLength(der, offset, size);
0801:                der[offset++] = 2;
0802:                offset = putLength(der, offset, modulusLength);
0803:                if (padModulus) {
0804:                    offset++;
0805:                }
0806:                offset += pk.getModulus(der, offset);
0807:
0808:                der[offset++] = 2;
0809:                offset = putLength(der, offset, exponentLength);
0810:                if (padExponent) {
0811:                    offset++;
0812:                }
0813:                pk.getExponent(der, offset);
0814:
0815:                return der;
0816:            }
0817:
0818:            /**
0819:             * Calculates identifier for public RSA key.
0820:             * @param pk the key
0821:             * @param data temporary data buffer
0822:             * @return the identifier
0823:             */
0824:            byte[] getKeyHash(RSAPublicKey pk, byte[] data) {
0825:
0826:                short offset = 1;
0827:                short len = pk.getModulus(data, offset);
0828:
0829:                if ((data[1] & 0x80) != 0) {
0830:                    offset--;
0831:                    len++;
0832:                    data[offset] = 0;
0833:                }
0834:                byte[] hash = new byte[(short) 20];
0835:                digest.doFinal(data, offset, len, hash, x0);
0836:                return hash;
0837:            }
0838:
0839:            /**
0840:             * Returns the size of DER object for given value size.
0841:             * @param i the value size
0842:             * @return the size of DER object
0843:             */
0844:            static short getDERSize(short i) {
0845:
0846:                if (i < 128) {
0847:                    return (short) (i + 2);
0848:                }
0849:                return (short) (i + 3);
0850:            }
0851:
0852:            /**
0853:             * Places encoded length of DER object into the buffer.
0854:             * @param data the buffer
0855:             * @param offset offset in the buffer where the length must be
0856:             * placed
0857:             * @param length the length to be placed
0858:             * @return the new offset
0859:             */
0860:            static short putLength(byte[] data, short offset, short length) {
0861:                if (length >= 128) {
0862:                    data[offset++] = (byte) 0x81;
0863:                }
0864:                data[offset++] = (byte) length;
0865:                return offset;
0866:            }
0867:
0868:            /**
0869:             * Returns file object specified by path in the buffer.
0870:             * @param data the buffer
0871:             * @param index path offset
0872:             * @param l path length
0873:             * @return file object or null if not found
0874:             */
0875:            File getFile(byte[] data, short index, short l) {
0876:
0877:                // path must contain even number of bytes
0878:                if (l < 2 || l % 2 != 0) {
0879:                    return null;
0880:                }
0881:                l = (short) (l / 2);
0882:
0883:                short id = Util.getShort(data, index);
0884:
0885:                File x = null;
0886:
0887:                if (l == 1) {
0888:                    x = base;
0889:                } else {
0890:
0891:                    if (id == top.id) {
0892:                        x = top;
0893:                    } else {
0894:                        if (id == (short) 0x3fff) {
0895:                            x = base;
0896:                        } else {
0897:                            return null;
0898:                        }
0899:                    }
0900:                    index += 2;
0901:                    l--;
0902:                }
0903:
0904:                while (l != 0) {
0905:
0906:                    if (!x.isDF()) {
0907:                        return null;
0908:                    }
0909:                    File f = ((DFile) x).getFile(Util.getShort(data, index));
0910:                    if (f == null || f.parent != x) {
0911:                        return null;
0912:                    }
0913:                    x = f;
0914:                    index += 2;
0915:                    l--;
0916:                }
0917:
0918:                return x;
0919:            }
0920:
0921:            /**
0922:             * Handles PSO-CDS APDU command.
0923:             * @param apdu command APDU
0924:             */
0925:            void sign(APDU apdu) {
0926:
0927:                byte[] data = apdu.getBuffer();
0928:
0929:                if (Util.getShort(data, x2) != (short) 0x9e9a) {
0930:                    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
0931:                }
0932:
0933:                if (!isSERestored || keyNum == -1 || !isKeyFileSet) {
0934:                    ISOException.throwIt((short) 0x6600);
0935:                }
0936:
0937:                checkDataSize(digestLength, apdu);
0938:
0939:                if (!keys[keyNum].checkAccess()) {
0940:                    ISOException
0941:                            .throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
0942:                }
0943:
0944:                cipher.init(keys[keyNum].value, Cipher.MODE_ENCRYPT);
0945:                Util.arrayCopyNonAtomic(data, x5, signBuffer, x0, digestLength);
0946:                short len = cipher.doFinal(signBuffer, x0, digestLength, data,
0947:                        x0);
0948:
0949:                short expected = (short) (keys[keyNum].value.getSize() >> 3);
0950:                if (len != expected) {
0951:                    Util.arrayFillNonAtomic(data, x0, (short) (expected - len),
0952:                            x0);
0953:                    cipher.doFinal(signBuffer, x0, digestLength, data,
0954:                            (short) (expected - len));
0955:                }
0956:
0957:                apdu.setOutgoingAndSend(x0, expected);
0958:            }
0959:
0960:            /**
0961:             * Verifies that APDU contains correct number of data bytes.
0962:             * @param expectedSize expected data size
0963:             * @param apdu APDU object
0964:             */
0965:            private void checkDataSize(short expectedSize, APDU apdu) {
0966:                if (expectedSize != apdu.setIncomingAndReceive()) {
0967:                    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
0968:                }
0969:            }
0970:
0971:            /**
0972:             * Verifies that PIN is validated.
0973:             * @param pin the PIN
0974:             * @return true if the PIN is validated or PIN verification is disabled.
0975:             */
0976:            public boolean isValidated(OwnerPIN pin) {
0977:                return verifyPINs ? pin.isValidated() : true;
0978:            }
0979:        }
0980:
0981:        /**
0982:         * This class represents private key.
0983:         */
0984:        class PrivateKey {
0985:            /** Owner applet. */
0986:            PKIApplet applet;
0987:            /** Key identifier. */
0988:            short id;
0989:            /** PIN object that protects this key. */
0990:            OwnerPIN PIN;
0991:            /** True if its non-repudiation key. */
0992:            boolean nonRepudiation;
0993:            /** Length of the key. */
0994:            short keyLen;
0995:            /** The key object. */
0996:            RSAPrivateKey value;
0997:
0998:            /**
0999:             * Constructs new key object using hardcoded data.
1000:             * @param app The applet object
1001:             */
1002:            PrivateKey(PKIApplet app) {
1003:                applet = app;
1004:                id = Parser.getByte();
1005:                PIN = applet.PINs[Parser.getByte()];
1006:                nonRepudiation = (Parser.getByte() == 0);
1007:                keyLen = Parser.getShort();
1008:                boolean notSupported = false;
1009:                try {
1010:                    value = (RSAPrivateKey) KeyBuilder.buildKey(
1011:                            KeyBuilder.TYPE_RSA_PRIVATE, keyLen, false);
1012:                } catch (CryptoException e) {
1013:                    notSupported = true;
1014:                }
1015:                if (value == null) {
1016:                    notSupported = true;
1017:                }
1018:                if (notSupported) {
1019:                    value = null;
1020:                    short len = Parser.getShort();
1021:                    Parser.skip(len);
1022:                    len = Parser.getShort();
1023:                    Parser.skip(len);
1024:                } else {
1025:                    short len = Parser.getShort();
1026:                    value.setModulus(Data.PrivateKeys, Parser.offset, len);
1027:                    Parser.skip(len);
1028:                    len = Parser.getShort();
1029:                    value.setExponent(Data.PrivateKeys, Parser.offset, len);
1030:                    Parser.skip(len);
1031:                }
1032:            }
1033:
1034:            /**
1035:             * Constructs new key object.
1036:             * @param app the applet object
1037:             * @param id key identifier
1038:             * @param PIN PIN object that protects this key
1039:             * @param nonRepudiation is it non-repudiation key?
1040:             * @param keyLen length of key
1041:             * @param value the key object
1042:             */
1043:            PrivateKey(PKIApplet app, short id, OwnerPIN PIN,
1044:                    boolean nonRepudiation, short keyLen, RSAPrivateKey value) {
1045:                this .applet = app;
1046:                this .id = id;
1047:                this .PIN = PIN;
1048:                this .nonRepudiation = nonRepudiation;
1049:                this .keyLen = keyLen;
1050:                this .value = value;
1051:            }
1052:
1053:            /**
1054:             * Verifies that user has access to this key.
1055:             * @return true if PIN is validated
1056:             */
1057:            boolean checkAccess() {
1058:
1059:                boolean result = applet.isValidated(PIN);
1060:                if (nonRepudiation) {
1061:                    PIN.reset();
1062:                }
1063:                return result;
1064:            }
1065:        }
1066:
1067:        /**
1068:         * This class represents private/public key pairs pool.
1069:         */
1070:        class Pairs {
1071:            /** 
1072:             * Singleton instance reference. 
1073:             */
1074:            private static Pairs instance = null;
1075:            /** 
1076:             * Pairs in the pool. 
1077:             */
1078:            private KeyPair[] pairs;
1079:            /** 
1080:             * Key lengths of pairs stored in pool. 
1081:             * Initial value is -1. 
1082:             */
1083:            private short[] lengths;
1084:            /** 
1085:             * Default number of slots in the pool.
1086:             */
1087:            private static final short defaultSize = 10;
1088:            /** 
1089:             * Number of slots in the pool.
1090:             */
1091:            private short poolSize;
1092:
1093:            /**
1094:             * Constructs new pool using given size.
1095:             * @param poolSize Number of slots in the pool
1096:             */
1097:            private Pairs(short poolSize) {
1098:                this .poolSize = poolSize;
1099:                pairs = new KeyPair[poolSize];
1100:                lengths = new short[poolSize];
1101:                for (short i = 0; i < poolSize; i++) {
1102:                    lengths[i] = (short) -1;
1103:                }
1104:            }
1105:
1106:            /**
1107:             * Constructs new pool using default size.
1108:             */
1109:            private Pairs() {
1110:                this (defaultSize);
1111:            }
1112:
1113:            /**
1114:             * Finds a KeyPair object with keys of given length.
1115:             * If needed object does not exists in the pool the method 
1116:             * tries to create it.
1117:             *
1118:             * @param length Length of keys.
1119:             * @return Found KeyPair object or null in case of error.
1120:             */
1121:            private KeyPair findPair(short length) {
1122:                for (short i = 0; i < poolSize; i++) {
1123:                    if (lengths[i] == length) {
1124:                        return pairs[i];
1125:                    }
1126:                }
1127:                for (short i = 0; i < instance.poolSize; i++) {
1128:                    if (lengths[i] == (short) -1) {
1129:                        try {
1130:                            pairs[i] = new KeyPair(KeyPair.ALG_RSA, length);
1131:                        } catch (CryptoException e) {
1132:                            return null;
1133:                        }
1134:                        lengths[i] = length;
1135:                        return pairs[i];
1136:                    }
1137:                }
1138:                return null;
1139:            }
1140:
1141:            /**
1142:             * Gets a KeyPair object with keys of given length.
1143:             * @param length Length of keys.
1144:             * @return Found KeyPair object.
1145:             * @exception ISOException if no suitable pairs found or 
1146:             *                         algorithm or length not valid.
1147:             */
1148:            public static KeyPair getKeyPair(short length) {
1149:                if (instance == null) {
1150:                    instance = new Pairs();
1151:                }
1152:                KeyPair pair = instance.findPair(length);
1153:                if (pair == null) {
1154:                    ISOException.throwIt((short) 0x9001);
1155:                }
1156:                return pair;
1157:            }
1158:
1159:            /**
1160:             * Checks if a suitable KeyPair object can be received from the pool.
1161:             * @param length Length of keys.
1162:             * @return true if a KeyPair object is available,
1163:             *         false in other case.
1164:             * @exception ISOException if no suitable pairs found or 
1165:             *                         algorithm or length are not valid.
1166:             */
1167:            public static boolean tryKeyPair(short length) {
1168:                if (instance == null) {
1169:                    instance = new Pairs();
1170:                }
1171:                return instance.findPair(length) != null;
1172:            }
1173:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.