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 }