    001    /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
    002     *
    003     * Redistribution and use in  source and binary forms, with or without
    004     * modification, are permitted  provided that the following conditions are met:
    005     *
    006     * 1. Redistributions of  source code must retain the above copyright notice,
    007     *    this list of conditions and the following disclaimer.
    008     *
    009     * 2. Redistributions in  binary form must reproduce the above copyright notice,
    010     *    this list of conditions and the following disclaimer in the documentation
    011     *    and/or other materials provided with the distribution.
    012     *
    013     * 3. The end-user documentation included with the redistribution, if any, must
    014     *    include the following acknowledgment:
    015     *
    016     *    "This product includes software developed by IAIK of Graz University of
    017     *     Technology."
    018     *
    019     *    Alternately, this acknowledgment may appear in the software itself, if
    020     *    and wherever such third-party acknowledgments normally appear.
    021     *
    022     * 4. The names "Graz University of Technology" and "IAIK of Graz University of
    023     *    Technology" must not be used to endorse or promote products derived from
    024     *    this software without prior written permission.
    025     *
    026     * 5. Products derived from this software may not be called
    027     *    "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior
    028     *    written permission of Graz University of Technology.
    029     *
    030     *  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
    031     *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    032     *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    033     *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
    034     *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
    035     *  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    036     *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
    037     *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    038     *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    039     *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    040     *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    041     *  POSSIBILITY  OF SUCH DAMAGE.
    042     */
    043
    044    package demo.pkcs.pkcs11;
    045
    046    import java.io.BufferedReader;
    047    import java.io.IOException;
    048    import java.io.PrintWriter;
    049    //import java.util.HashMap;
    050    import java.util.Enumeration;
    051    import java.util.Hashtable;
    052    //import java.util.Iterator;
    053    //import java.util.List;
    054    //import java.util.Map;
    055    import java.util.Vector;
    056
    057    import iaik.pkcs.pkcs11.Module;
    058    import iaik.pkcs.pkcs11.Session;
    059    import iaik.pkcs.pkcs11.Slot;
    060    import iaik.pkcs.pkcs11.Token;
    061    import iaik.pkcs.pkcs11.TokenException;
    062    import iaik.pkcs.pkcs11.TokenInfo;
    063    import iaik.pkcs.pkcs11.objects.Key;
    064    import iaik.pkcs.pkcs11.objects.Object;
    065    import iaik.pkcs.pkcs11.objects.PrivateKey;
    066    import iaik.pkcs.pkcs11.objects.RSAPrivateKey;
    067    import iaik.pkcs.pkcs11.objects.X509PublicKeyCertificate;
    068    import iaik.x509.X509Certificate;
    069
    070
    071
    072    /**
    073     * This class contains only static methods. It is the place for all functions
    074     * that are used by several classes in this package.
    075     *
    076     * @author Karl Scheibelhofer <Karl.Scheibelhofer@iaik.at>
    077     */
    078    public class Util {
    079
    080      /**
    081       * Maps mechanism strings to their codes as Long.
    082       */
    083      protected static Hashtable mechansimCodes_;
    084
    085      /**
    086       * Converts the names of mechanisms to their long value code.
    087       *
    088       * @param mechansimName The name of the mechanism to get the code; e.g.
    089       *                      "CKM_RSA_PKCS".
    090       * @return The code of the mechanism or null, if this name is unknown.
    091       * @preconditions (mechansimName <> null)
    092       * @postconditions
    093       */
    094      public static Long mechanismCodeToString(String mechansimName) {
    095        if (mechansimName == null) {
    096          throw new NullPointerException("Argument \"mechansimName\" must not be null.");
    097        }
    098
    099        Long mechanismCode;
    100
    101        if (mechansimName.startsWith("0x")) {
    102          // we try to parse it as hex encoded long
    103          mechanismCode = new Long(Long.parseLong(mechansimName, 16));
    104        } else {
    105          if (mechansimCodes_ == null) {
    106            mechansimCodes_ = new Hashtable(160);
    107            mechansimCodes_.put("CKM_RSA_PKCS_KEY_PAIR_GEN", new Long(0x00000000));
    108            mechansimCodes_.put("CKM_RSA_PKCS", new Long(0x00000001));
    109            mechansimCodes_.put("CKM_RSA_9796", new Long(0x00000002));
    110            mechansimCodes_.put("CKM_RSA_X_509", new Long(0x00000003));
    111            mechansimCodes_.put("CKM_MD2_RSA_PKCS", new Long(0x00000004));
    112            mechansimCodes_.put("CKM_MD5_RSA_PKCS", new Long(0x00000005));
    113            mechansimCodes_.put("CKM_SHA1_RSA_PKCS", new Long(0x00000006));
    114            mechansimCodes_.put("CKM_RIPEMD128_RSA_PKCS", new Long(0x00000007));
    115            mechansimCodes_.put("CKM_RIPEMD160_RSA_PKCS", new Long(0x00000008));
    116            mechansimCodes_.put("CKM_RSA_PKCS_OAEP", new Long(0x00000009));
    117            mechansimCodes_.put("CKM_DSA_KEY_PAIR_GEN", new Long(0x00000010));
    118            mechansimCodes_.put("CKM_DSA", new Long(0x00000011));
    119            mechansimCodes_.put("CKM_DSA_SHA1", new Long(0x00000012));
    120            mechansimCodes_.put("CKM_DH_PKCS_KEY_PAIR_GEN", new Long(0x00000020));
    121            mechansimCodes_.put("CKM_DH_PKCS_DERIVE", new Long(0x00000021));
    122            mechansimCodes_.put("CKM_RC2_KEY_GEN", new Long(0x00000100));
    123            mechansimCodes_.put("CKM_RC2_ECB", new Long(0x00000101));
    124            mechansimCodes_.put("CKM_RC2_CBC", new Long(0x00000102));
    125            mechansimCodes_.put("CKM_RC2_MAC", new Long(0x00000103));
    126            mechansimCodes_.put("CKM_RC2_MAC_GENERAL", new Long(0x00000104));
    127            mechansimCodes_.put("CKM_RC2_CBC_PAD", new Long(0x00000105));
    128            mechansimCodes_.put("CKM_RC4_KEY_GEN", new Long(0x00000110));
    129            mechansimCodes_.put("CKM_RC4", new Long(0x00000111));
    130            mechansimCodes_.put("CKM_DES_KEY_GEN", new Long(0x00000120));
    131            mechansimCodes_.put("CKM_DES_ECB", new Long(0x00000121));
    132            mechansimCodes_.put("CKM_DES_CBC", new Long(0x00000122));
    133            mechansimCodes_.put("CKM_DES_MAC", new Long(0x00000123));
    134            mechansimCodes_.put("CKM_DES_MAC_GENERAL", new Long(0x00000124));
    135            mechansimCodes_.put("CKM_DES_CBC_PAD", new Long(0x00000125));
    136            mechansimCodes_.put("CKM_DES2_KEY_GEN", new Long(0x00000130));
    137            mechansimCodes_.put("CKM_DES3_KEY_GEN", new Long(0x00000131));
    138            mechansimCodes_.put("CKM_DES3_ECB", new Long(0x00000132));
    139            mechansimCodes_.put("CKM_DES3_CBC", new Long(0x00000133));
    140            mechansimCodes_.put("CKM_DES3_MAC", new Long(0x00000134));
    141            mechansimCodes_.put("CKM_DES3_MAC_GENERAL", new Long(0x00000135));
    142            mechansimCodes_.put("CKM_DES3_CBC_PAD", new Long(0x00000136));
    143            mechansimCodes_.put("CKM_CDMF_KEY_GEN", new Long(0x00000140));
    144            mechansimCodes_.put("CKM_CDMF_ECB", new Long(0x00000141));
    145            mechansimCodes_.put("CKM_CDMF_CBC", new Long(0x00000142));
    146            mechansimCodes_.put("CKM_CDMF_MAC", new Long(0x00000143));
    147            mechansimCodes_.put("CKM_CDMF_MAC_GENERAL", new Long(0x00000144));
    148            mechansimCodes_.put("CKM_CDMF_CBC_PAD", new Long(0x00000145));
    149            mechansimCodes_.put("CKM_MD2", new Long(0x00000200));
    150            mechansimCodes_.put("CKM_MD2_HMAC", new Long(0x00000201));
    151            mechansimCodes_.put("CKM_MD2_HMAC_GENERAL", new Long(0x00000202));
    152            mechansimCodes_.put("CKM_MD5", new Long(0x00000210));
    153            mechansimCodes_.put("CKM_MD5_HMAC", new Long(0x00000211));
    154            mechansimCodes_.put("CKM_MD5_HMAC_GENERAL", new Long(0x00000212));
    155            mechansimCodes_.put("CKM_SHA_1", new Long(0x00000220));
    156            mechansimCodes_.put("CKM_SHA_1_HMAC", new Long(0x00000221));
    157            mechansimCodes_.put("CKM_SHA_1_HMAC_GENERAL", new Long(0x00000222));
    158            mechansimCodes_.put("CKM_RIPEMD128", new Long(0x00000230));
    159            mechansimCodes_.put("CKM_RIPEMD128_HMAC", new Long(0x00000231));
    160            mechansimCodes_.put("CKM_RIPEMD128_HMAC_GENERAL", new Long(0x00000232));
    161            mechansimCodes_.put("CKM_RIPEMD160", new Long(0x00000240));
    162            mechansimCodes_.put("CKM_RIPEMD160_HMAC", new Long(0x00000241));
    163            mechansimCodes_.put("CKM_RIPEMD160_HMAC_GENERAL", new Long(0x00000242));
    164            mechansimCodes_.put("CKM_CAST_KEY_GEN", new Long(0x00000300));
    165            mechansimCodes_.put("CKM_CAST_ECB", new Long(0x00000301));
    166            mechansimCodes_.put("CKM_CAST_CBC", new Long(0x00000302));
    167            mechansimCodes_.put("CKM_CAST_MAC", new Long(0x00000303));
    168            mechansimCodes_.put("CKM_CAST_MAC_GENERAL", new Long(0x00000304));
    169            mechansimCodes_.put("CKM_CAST_CBC_PAD", new Long(0x00000305));
    170            mechansimCodes_.put("CKM_CAST3_KEY_GEN", new Long(0x00000310));
    171            mechansimCodes_.put("CKM_CAST3_ECB", new Long(0x00000311));
    172            mechansimCodes_.put("CKM_CAST3_CBC", new Long(0x00000312));
    173            mechansimCodes_.put("CKM_CAST3_MAC", new Long(0x00000313));
    174            mechansimCodes_.put("CKM_CAST3_MAC_GENERAL", new Long(0x00000314));
    175            mechansimCodes_.put("CKM_CAST3_CBC_PAD", new Long(0x00000315));
    176            mechansimCodes_.put("CKM_CAST5_KEY_GEN", new Long(0x00000320));
    177            mechansimCodes_.put("CKM_CAST128_KEY_GEN", new Long(0x00000320));
    178            mechansimCodes_.put("CKM_CAST5_ECB", new Long(0x00000321));
    179            mechansimCodes_.put("CKM_CAST128_ECB", new Long(0x00000321));
    180            mechansimCodes_.put("CKM_CAST5_CBC", new Long(0x00000322));
    181            mechansimCodes_.put("CKM_CAST128_CBC", new Long(0x00000322));
    182            mechansimCodes_.put("CKM_CAST5_MAC", new Long(0x00000323));
    183            mechansimCodes_.put("CKM_CAST128_MAC", new Long(0x00000323));
    184            mechansimCodes_.put("CKM_CAST5_MAC_GENERAL", new Long(0x00000324));
    185            mechansimCodes_.put("CKM_CAST128_MAC_GENERAL", new Long(0x00000324));
    186            mechansimCodes_.put("CKM_CAST5_CBC_PAD", new Long(0x00000325));
    187            mechansimCodes_.put("CKM_CAST128_CBC_PAD", new Long(0x00000325));
    188            mechansimCodes_.put("CKM_RC5_KEY_GEN", new Long(0x00000330));
    189            mechansimCodes_.put("CKM_RC5_ECB", new Long(0x00000331));
    190            mechansimCodes_.put("CKM_RC5_CBC", new Long(0x00000332));
    191            mechansimCodes_.put("CKM_RC5_MAC", new Long(0x00000333));
    192            mechansimCodes_.put("CKM_RC5_MAC_GENERAL", new Long(0x00000334));
    193            mechansimCodes_.put("CKM_RC5_CBC_PAD", new Long(0x00000335));
    194            mechansimCodes_.put("CKM_IDEA_KEY_GEN", new Long(0x00000340));
    195            mechansimCodes_.put("CKM_IDEA_ECB", new Long(0x00000341));
    196            mechansimCodes_.put("CKM_IDEA_CBC", new Long(0x00000342));
    197            mechansimCodes_.put("CKM_IDEA_MAC", new Long(0x00000343));
    198            mechansimCodes_.put("CKM_IDEA_MAC_GENERAL", new Long(0x00000344));
    199            mechansimCodes_.put("CKM_IDEA_CBC_PAD", new Long(0x00000345));
    200            mechansimCodes_.put("CKM_GENERIC_SECRET_KEY_GEN", new Long(0x00000350));
    201            mechansimCodes_.put("CKM_CONCATENATE_BASE_AND_KEY", new Long(0x00000360));
    202            mechansimCodes_.put("CKM_CONCATENATE_BASE_AND_DATA", new Long(0x00000362));
    203            mechansimCodes_.put("CKM_CONCATENATE_DATA_AND_BASE", new Long(0x00000363));
    204            mechansimCodes_.put("CKM_XOR_BASE_AND_DATA", new Long(0x00000364));
    205            mechansimCodes_.put("CKM_EXTRACT_KEY_FROM_KEY", new Long(0x00000365));
    206            mechansimCodes_.put("CKM_SSL3_PRE_MASTER_KEY_GEN", new Long(0x00000370));
    207            mechansimCodes_.put("CKM_SSL3_MASTER_KEY_DERIVE", new Long(0x00000371));
    208            mechansimCodes_.put("CKM_SSL3_KEY_AND_MAC_DERIVE", new Long(0x00000372));
    209            mechansimCodes_.put("CKM_SSL3_MD5_MAC", new Long(0x00000380));
    210            mechansimCodes_.put("CKM_SSL3_SHA1_MAC", new Long(0x00000381));
    211            mechansimCodes_.put("CKM_MD5_KEY_DERIVATION", new Long(0x00000390));
    212            mechansimCodes_.put("CKM_MD2_KEY_DERIVATION", new Long(0x00000391));
    213            mechansimCodes_.put("CKM_SHA1_KEY_DERIVATION", new Long(0x00000392));
    214            mechansimCodes_.put("CKM_PBE_MD2_DES_CBC", new Long(0x000003A0));
    215            mechansimCodes_.put("CKM_PBE_MD5_DES_CBC", new Long(0x000003A1));
    216            mechansimCodes_.put("CKM_PBE_MD5_CAST_CBC", new Long(0x000003A2));
    217            mechansimCodes_.put("CKM_PBE_MD5_CAST3_CBC", new Long(0x000003A3));
    218            mechansimCodes_.put("CKM_PBE_MD5_CAST5_CBC", new Long(0x000003A4));
    219            mechansimCodes_.put("CKM_PBE_MD5_CAST128_CBC", new Long(0x000003A4));
    220            mechansimCodes_.put("CKM_PBE_SHA1_CAST5_CBC", new Long(0x000003A5));
    221            mechansimCodes_.put("CKM_PBE_SHA1_CAST128_CBC", new Long(0x000003A5));
    222            mechansimCodes_.put("CKM_PBE_SHA1_RC4_128", new Long(0x000003A6));
    223            mechansimCodes_.put("CKM_PBE_SHA1_RC4_40", new Long(0x000003A7));
    224            mechansimCodes_.put("CKM_PBE_SHA1_DES3_EDE_CBC", new Long(0x000003A8));
    225            mechansimCodes_.put("CKM_PBE_SHA1_DES2_EDE_CBC", new Long(0x000003A9));
    226            mechansimCodes_.put("CKM_PBE_SHA1_RC2_128_CBC", new Long(0x000003AA));
    227            mechansimCodes_.put("CKM_PBE_SHA1_RC2_40_CBC", new Long(0x000003AB));
    228            mechansimCodes_.put("CKM_PKCS5_PBKD2", new Long(0x000003B0));
    229            mechansimCodes_.put("CKM_PBA_SHA1_WITH_SHA1_HMAC", new Long(0x000003C0));
    230            mechansimCodes_.put("CKM_KEY_WRAP_LYNKS", new Long(0x00000400));
    231            mechansimCodes_.put("CKM_KEY_WRAP_SET_OAEP", new Long(0x00000401));
    232            mechansimCodes_.put("CKM_SKIPJACK_KEY_GEN", new Long(0x00001000));
    233            mechansimCodes_.put("CKM_SKIPJACK_ECB64", new Long(0x00001001));
    234            mechansimCodes_.put("CKM_SKIPJACK_CBC64", new Long(0x00001002));
    235            mechansimCodes_.put("CKM_SKIPJACK_OFB64", new Long(0x00001003));
    236            mechansimCodes_.put("CKM_SKIPJACK_CFB64", new Long(0x00001004));
    237            mechansimCodes_.put("CKM_SKIPJACK_CFB32", new Long(0x00001005));
    238            mechansimCodes_.put("CKM_SKIPJACK_CFB16", new Long(0x00001006));
    239            mechansimCodes_.put("CKM_SKIPJACK_CFB8", new Long(0x00001007));
    240            mechansimCodes_.put("CKM_SKIPJACK_WRAP", new Long(0x00001008));
    241            mechansimCodes_.put("CKM_SKIPJACK_PRIVATE_WRAP", new Long(0x00001009));
    242            mechansimCodes_.put("CKM_SKIPJACK_RELAYX", new Long(0x0000100a));
    243            mechansimCodes_.put("CKM_KEA_KEY_PAIR_GEN", new Long(0x00001010));
    244            mechansimCodes_.put("CKM_KEA_KEY_DERIVE", new Long(0x00001011));
    245            mechansimCodes_.put("CKM_FORTEZZA_TIMESTAMP", new Long(0x00001020));
    246            mechansimCodes_.put("CKM_BATON_KEY_GEN", new Long(0x00001030));
    247            mechansimCodes_.put("CKM_BATON_ECB128", new Long(0x00001031));
    248            mechansimCodes_.put("CKM_BATON_ECB96", new Long(0x00001032));
    249            mechansimCodes_.put("CKM_BATON_CBC128", new Long(0x00001033));
    250            mechansimCodes_.put("CKM_BATON_COUNTER", new Long(0x00001034));
    251            mechansimCodes_.put("CKM_BATON_SHUFFLE", new Long(0x00001035));
    252            mechansimCodes_.put("CKM_BATON_WRAP", new Long(0x00001036));
    253            mechansimCodes_.put("CKM_ECDSA_KEY_PAIR_GEN", new Long(0x00001040));
    254            mechansimCodes_.put("CKM_ECDSA", new Long(0x00001041));
    255            mechansimCodes_.put("CKM_ECDSA_SHA1", new Long(0x00001042));
    256            mechansimCodes_.put("CKM_JUNIPER_KEY_GEN", new Long(0x00001060));
    257            mechansimCodes_.put("CKM_JUNIPER_ECB128", new Long(0x00001061));
    258            mechansimCodes_.put("CKM_JUNIPER_CBC128", new Long(0x00001062));
    259            mechansimCodes_.put("CKM_JUNIPER_COUNTER", new Long(0x00001063));
    260            mechansimCodes_.put("CKM_JUNIPER_SHUFFLE", new Long(0x00001064));
    261            mechansimCodes_.put("CKM_JUNIPER_WRAP", new Long(0x00001065));
    262            mechansimCodes_.put("CKM_FASTHASH", new Long(0x00001070));
    263            mechansimCodes_.put("CKM_VENDOR_DEFINED", new Long(0x80000000));
    264          }
    265
    266          mechanismCode = (Long) mechansimCodes_.get(mechansimName);
    267        }
    268
    269        return mechanismCode ;
    270      }
    271
    272      /**
    273       * Lists all available tokens of the given module and lets the user select
    274       * one, if there is more than one available.
    275       *
    276       * @param pkcs11Module The PKCS#11 module to use.
    277       * @param output The output stream to write the user prompts to.
    278       * @param input The input stream where to read user input from.
    279       * @return The selected token or null, if no token is available or the user
    280       *         canceled the action.
    281       * @exception TokenException If listing the tokens failed.
    282       * @exception IOException If writing a user prompt faild or if reading user
    283       *                        input failed.
    284       * @preconditions (pkcs11Module <> null)
    285       *                and (output <> null)
    286       *                and (input <> null)
    287       * @postconditions
    288       */
    289      public static Token selectToken(Module pkcs11Module, PrintWriter output, BufferedReader input)
    290          throws TokenException, IOException
    291      {
    292        if (pkcs11Module == null) {
    293          throw new NullPointerException("Argument \"pkcs11Module\" must not be null.");
    294        }
    295        if (output == null) {
    296          throw new NullPointerException("Argument \"output\" must not be null.");
    297        }
    298        if (input == null) {
    299          throw new NullPointerException("Argument \"input\" must not be null.");
    300        }
    301
    302        output.println("################################################################################");
    303        output.println("getting list of all tokens");
    304        Slot[] slotsWithToken = pkcs11Module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
    305        Token[] tokens = new Token[slotsWithToken.length];
    306        Hashtable tokenIDtoToken = new Hashtable(tokens.length);
    307
    308        for (int i = 0; i < slotsWithToken.length; i++) {
    309          output.println("________________________________________________________________________________");
    310          tokens[i] = slotsWithToken[i].getToken();
    311          TokenInfo tokenInfo = tokens[i].getTokenInfo();
    312          long tokenID = tokens[i].getTokenID();
    313          tokenIDtoToken.put(new Long(tokenID), tokens[i]);
    314          output.println("Token ID: " + tokenID);
    315          output.println(tokenInfo);
    316          output.println("________________________________________________________________________________");
    317        }
    318        output.println("################################################################################");
    319
    320        output.println("################################################################################");
    321        Token token = null;
    322        Long selectedTokenID = null;
    323        if (tokens.length == 0) {
    324          output.println("There is no slot with a present token.");
    325        } else if (tokens.length == 1) {
    326          output.println("Taking token with ID: " + tokens[0].getTokenID());
    327          selectedTokenID = new Long(tokens[0].getTokenID());
    328          token = tokens[0];
    329        } else {
    330          boolean gotTokenID = false;
    331          while (!gotTokenID) {
    332            output.print("Enter the ID of the token to use or 'x' to exit: ");
    333            output.flush();
    334            String tokenIDstring = input.readLine();
    335            if (tokenIDstring.equalsIgnoreCase("x")) {
    336              break;
    337            }
    338            try {
    339              selectedTokenID = new Long(tokenIDstring);
    340              token = (Token) tokenIDtoToken.get(selectedTokenID);
    341              if (token != null) {
    342                gotTokenID = true;
    343              } else {
    344                output.println("A token with the entered ID \"" + tokenIDstring + "\" does not exist. Try again.");
    345              }
    346            } catch (NumberFormatException ex) {
    347              output.println("The entered ID \"" + tokenIDstring + "\" is invalid. Try again.");
    348            }
    349          }
    350        }
    351        output.println("################################################################################");
    352
    353        return token ;
    354      }
    355
    356      /**
    357       * Opens an authorized session for the given token. If the token requires the
    358       * user to login for private operations, the method loggs in the user.
    359       *
    360       * @param token The token to open a session for.
    361       * @param rwSession If the session should be a read-write session. This may be
    362       *                  Token.SessionReadWriteBehavior.RO_SESSION or
    363       *                  Token.SessionReadWriteBehavior.RW_SESSION.
    364       * @param output The output stream to write the user prompts to.
    365       * @param input The input stream where to read user input from.
    366       * @return The selected token or null, if no token is available or the user
    367       *         canceled the action.
    368       * @exception TokenException If listing the tokens failed.
    369       * @exception IOException If writing a user prompt faild or if reading user
    370       *                        input failed.
    371       * @preconditions (token <> null)
    372       *                and (output <> null)
    373       *                and (input <> null)
    374       * @postconditions (result <> null)
    375       */
    376      public static Session openAuthorizedSession(Token token, boolean rwSession, PrintWriter output, BufferedReader input)
    377          throws TokenException, IOException
    378      {
    379        if (token == null) {
    380          throw new NullPointerException("Argument \"token\" must not be null.");
    381        }
    382        if (output == null) {
    383          throw new NullPointerException("Argument \"output\" must not be null.");
    384        }
    385        if (input == null) {
    386          throw new NullPointerException("Argument \"input\" must not be null.");
    387        }
    388
    389        output.println("################################################################################");
    390        output.println("opening session");
    391        Session session =
    392            token.openSession(Token.SessionType.SERIAL_SESSION, rwSession, null, null);
    393
    394        TokenInfo tokenInfo = token.getTokenInfo();
    395        if (tokenInfo.isLoginRequired()) {
    396          if (tokenInfo.isProtectedAuthenticationPath()) {
    397            output.print("Please enter the user-PIN at the PIN-pad of your reader.");
    398            output.flush();
    399            session.login(Session.UserType.USER, null); // the token prompts the PIN by other means; e.g. PIN-pad
    400          } else {
    401            output.print("Enter user-PIN and press [return key]: ");
    402            output.flush();
    403            String userPINString = input.readLine();
    404            session.login(Session.UserType.USER, userPINString.toCharArray());
    405          }
    406        }
    407        output.println("################################################################################");
    408
    409        return session ;
    410      }
    411
    412      /**
    413       * Lists all keys that match the given key template and lets the user choose
    414       * one, if there is more than one. If there is a corresponding certificate for
    415       * a key, this method displays the certificate for this key.
    416       *
    417       * @param session The session to use for key and certificate searching.
    418       * @param keyTemplate The template for searching for keys.
    419       * @param output The output stream to write the user prompts to.
    420       * @param input The input stream where to read user input from.
    421       * @return The selected key or null, if there is no matching key or the user
    422       *         canceled the operation. The return object also contains a
    423       *         corresponding certificate, if there is one for the selected key.
    424       * @exception TokenException If searching for keys or certificates failed.
    425       * @exception IOException If writing a user prompt faild or if reading user
    426       *                        input failed.
    427       * @preconditions (session <> null)
    428       *                and (keyTemplate <> keyTemplate)
    429       *                and (output <> null)
    430       *                and (input <> null)
    431       * @postconditions (result <> null)
    432       */
    433      public static KeyAndCertificate selectKeyAndCertificate(Session session, Key keyTemplate,
    434                                                              PrintWriter output, BufferedReader input)
    435          throws TokenException, IOException
    436      {
    437        if (session == null) {
    438          throw new NullPointerException("Argument \"session\" must not be null.");
    439        }
    440        if (keyTemplate == null) {
    441          throw new NullPointerException("Argument \"keyTemplate\" must not be null.");
    442        }
    443        if (output == null) {
    444          throw new NullPointerException("Argument \"output\" must not be null.");
    445        }
    446        if (input == null) {
    447          throw new NullPointerException("Argument \"input\" must not be null.");
    448        }
    449
    450        output.println("################################################################################");
    451        output.println("searching for keys");
    452
    453        Vector keyList = new Vector(4);
    454
    455        session.findObjectsInit(keyTemplate);
    456        Object[] matchingKeys;
    457
    458        while ((matchingKeys = session.findObjects(1)).length > 0) {
    459          keyList.addElement(matchingKeys[0]);
    460        }
    461        session.findObjectsFinal();
    462
    463        // try to find the corresponding certificates for the signature keys
    464        Hashtable keyToCertificateTable = new Hashtable(4);
    465        Enumeration keyListEnumeration = keyList.elements();
    466        while (keyListEnumeration.hasMoreElements()) {
    467          PrivateKey signatureKey = (PrivateKey) keyListEnumeration.nextElement();
    468          byte[] keyID = signatureKey.getId().getByteArrayValue();
    469          X509PublicKeyCertificate certificateTemplate = new X509PublicKeyCertificate();
    470          certificateTemplate.getId().setByteArrayValue(keyID);
    471
    472          session.findObjectsInit(certificateTemplate);
    473          Object[] correspondingCertificates = session.findObjects(1);
    474
    475          if (correspondingCertificates.length > 0) {
    476            keyToCertificateTable.put(signatureKey, correspondingCertificates[0]);
    477          }
    478          session.findObjectsFinal();
    479        }
    480
    481        Key selectedKey = null;
    482        X509PublicKeyCertificate correspondingCertificate = null;
    483        if (keyList.size() == 0) {
    484          output.println("Found NO matching key that can be used.");
    485        } else if (keyList.size() == 1) {
    486          // there is no choice, take this key
    487          selectedKey = (Key) keyList.elementAt(0);
    488          // create a IAIK JCE certificate from the PKCS11 certificate
    489          correspondingCertificate = (X509PublicKeyCertificate) keyToCertificateTable.get(selectedKey);
    490          String correspondingCertificateString = toString(correspondingCertificate);
    491          output.println("Found just one private RSA signing key. This key will be used:");
    492          output.println(selectedKey);
    493          output.println("--------------------------------------------------------------------------------");
    494          output.println("The certificate for this key is:");
    495          output.println((correspondingCertificateString != null)
    496                         ? correspondingCertificateString
    497                         : "<no certificate found>");
    498        } else {
    499          // give the user the choice
    500          output.println("found these private RSA signing keys:");
    501          Hashtable objectHandleToObjectMap = new Hashtable(keyList.size());
    502          Enumeration keyListEnumeration2 = keyList.elements();
    503          while (keyListEnumeration2.hasMoreElements()) {
    504            Object signatureKey = (Object) keyListEnumeration2.nextElement();
    505            long objectHandle = signatureKey.getObjectHandle();
    506            objectHandleToObjectMap.put(new Long(objectHandle), signatureKey);
    507            correspondingCertificate = (X509PublicKeyCertificate) keyToCertificateTable.get(signatureKey);
    508            String correspondingCertificateString = toString(correspondingCertificate);
    509            output.println("________________________________________________________________________________");
    510            output.println("RSA signature key with handle: " + objectHandle);
    511            output.println(signatureKey);
    512            output.println("--------------------------------------------------------------------------------");
    513            output.println("The certificate for this key is: ");
    514            output.println((correspondingCertificateString != null) ? correspondingCertificateString : "<no certificate found>");
    515            output.println("________________________________________________________________________________");
    516          }
    517
    518          boolean gotObjectHandle = false;
    519          Long selectedObjectHandle;
    520          while (!gotObjectHandle) {
    521            output.print("Enter the handle of the key to use for signing or 'x' to exit: ");
    522            output.flush();
    523            String objectHandleString = input.readLine();
    524            if (objectHandleString.equalsIgnoreCase("x")) {
    525              break;
    526            }
    527            try {
    528              selectedObjectHandle = new Long(objectHandleString);
    529              selectedKey = (RSAPrivateKey) objectHandleToObjectMap.get(selectedObjectHandle);
    530              if (selectedKey != null) {
    531                correspondingCertificate = (X509PublicKeyCertificate) keyToCertificateTable.get(selectedKey);
    532                gotObjectHandle = true;
    533              } else {
    534                output.println("An object with the handle \"" + objectHandleString + "\" does not exist. Try again.");
    535              }
    536            } catch (NumberFormatException ex) {
    537              output.println("The entered handle \"" + objectHandleString + "\" is invalid. Try again.");
    538            }
    539          }
    540        }
    541
    542        output.println("################################################################################");
    543
    544        return (selectedKey != null)
    545               ? new KeyAndCertificate(selectedKey, correspondingCertificate)
    546               : null ;
    547      }
    548
    549      /**
    550       * Gets a string representation of the given PKCS#11 certificate.
    551       *
    552       * @param certificate The PKCS#11 certificate.
    553       * @return The string representing the certificate.
    554       * @preconditions
    555       * @postconditions
    556       */
    557      public static String toString(X509PublicKeyCertificate certificate) {
    558        String certificateString = null;
    559
    560        if (certificate != null) {
    561          try {
    562            X509Certificate correspondingCertificate = new X509Certificate(certificate.getValue().getByteArrayValue());
    563            certificateString = correspondingCertificate.toString(true);
    564          } catch (Exception ex) {
    565            certificateString = certificate.toString();
    566          }
    567        }
    568
    569        return certificateString ;
    570      }
    571
    572    }