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: }
|