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.wrapper;
045    
046    import java.io.File;
047    import java.io.FileInputStream;
048    import java.io.FileOutputStream;
049    import java.io.IOException;
050    import java.io.InputStream;
051    import java.security.MessageDigest;
052    import java.util.Arrays;
053    
054    import iaik.pkcs.pkcs11.wrapper.CK_ATTRIBUTE;
055    import iaik.pkcs.pkcs11.wrapper.CK_INFO;
056    import iaik.pkcs.pkcs11.wrapper.CK_MECHANISM;
057    import iaik.pkcs.pkcs11.wrapper.CK_MECHANISM_INFO;
058    import iaik.pkcs.pkcs11.wrapper.CK_SESSION_INFO;
059    import iaik.pkcs.pkcs11.wrapper.CK_SLOT_INFO;
060    import iaik.pkcs.pkcs11.wrapper.CK_TOKEN_INFO;
061    import iaik.pkcs.pkcs11.wrapper.Functions;
062    import iaik.pkcs.pkcs11.wrapper.PKCS11;
063    import iaik.pkcs.pkcs11.wrapper.PKCS11Connector;
064    import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
065    import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;
066    
067    
068    
069    /**
070     * This is a simple class for testing the implementation.
071     * Notice that this is an sample that may not run as is with many tokens.
072     * It may be required to exclude some test methods in the main method.
073     */
074    public class SimpleTest {
075    
076      protected static final String CERTIFICATE_FILE = "tokenCertificate.der";
077    
078      protected static final String SIGNATURE_FILE = "signature.bin";
079    
080      protected static final String DIGEST_FILE = "digest.dat";
081    
082      protected PKCS11 myPKCS11Module_;
083    
084      protected String userPin_;
085    
086      protected long token_ = -1L;
087    
088      protected long session_;
089    
090      protected long[] objects_;
091    
092      protected long signatureKeyHandle_;
093    
094      protected long certificateHandle_;
095    
096      protected byte[] derEncodedCertificate_;
097    
098      protected File file_;
099    
100      protected CK_MECHANISM signatureMechanism_;
101    
102      protected CK_MECHANISM digestMechanism_;
103    
104      protected MessageDigest messageDigest_;
105    
106      protected byte[] signature_;
107    
108      protected byte[] digest_;
109    
110      public SimpleTest(String pkcs11Module, String userPin, File file)
111        throws IOException, PKCS11Exception
112      {
113        System.out.print("trying to connect to PKCS#11 module: " + pkcs11Module);
114        myPKCS11Module_ = PKCS11Connector.connectToPKCS11Module(pkcs11Module);
115        userPin_ = userPin;
116        file_ = file;
117        signatureMechanism_ = new CK_MECHANISM();
118        signatureMechanism_.mechanism = PKCS11Constants.CKM_SHA1_RSA_PKCS;
119        signatureMechanism_.pParameter = null;
120        digestMechanism_ = new CK_MECHANISM();
121        digestMechanism_.mechanism = PKCS11Constants.CKM_SHA_1;
122        digestMechanism_.pParameter = null;
123        System.out.println(" FINISHED");
124      }
125    
126      public static void main(String[] args) {
127        if (args.length != 3) {
128          printUsage();
129          System.exit(1);
130        }
131    
132        try {
133          SimpleTest test = new SimpleTest(args[0], args[1], new File(args[2]));
134    
135          test.initialize();
136          test.getInfo();
137          test.getSlotInfo();
138          test.getTokenInfo();
139          test.getMechanismInfo();
140          //test.initToken();
141          test.openROSession();
142          test.getSessionInfo();
143          test.findAllObjects();
144          test.printAllObjects();
145          test.loginUser();
146          test.getSessionInfo();
147          test.findAllObjects();
148          test.printAllObjects();
149          test.findSignatureKey();
150          test.findCertificate();
151          test.readCertificate();
152          test.writeCertificateToFile();
153          test.signData();
154          test.writeSignatureToFile();
155          test.digestData();
156          test.writeDigestToFile();
157          test.logout();
158          test.closeSession();
159    
160        } catch (Throwable thr) {
161          thr.printStackTrace();
162        }
163      }
164    
165      public static void printUsage() {
166        System.out.println("Usage: SimepleTest <PKCS#11 module> <userPIN> <file to be signed>");
167        System.out.println(" e.g.: SimpleTest pk2priv.dll password data.dat");
168        System.out.println("The given DLL must be in the search path of the system.");
169      }
170    
171      public void initialize()
172          throws PKCS11Exception
173      {
174        System.out.print("initializing... ");
175        myPKCS11Module_.C_Initialize(null);
176        System.out.println("FINISHED\n");
177      }
178    
179      public void getInfo()
180          throws PKCS11Exception
181      {
182        System.out.println("getting info");
183        CK_INFO moduleInfo = myPKCS11Module_.C_GetInfo();
184        System.out.println("Module Info: ");
185        System.out.println(moduleInfo);
186        System.out.println("FINISHED\n");
187      }
188    
189      public void getSlotInfo()
190          throws PKCS11Exception
191      {
192        System.out.println("getting slot list");
193        long[] slotIDs = myPKCS11Module_.C_GetSlotList(false);
194        CK_SLOT_INFO slotInfo;
195        for (int i=0; i < slotIDs.length; i++) {
196          System.out.println("Slot Info: ");
197          slotInfo = myPKCS11Module_.C_GetSlotInfo(slotIDs[i]);
198          System.out.println(slotInfo);
199        }
200        System.out.println("FINISHED\n");
201      }
202    
203      public void getTokenInfo()
204          throws PKCS11Exception
205      {
206        System.out.println("getting token list");
207        long[] tokenIDs = myPKCS11Module_.C_GetSlotList(true);
208        CK_TOKEN_INFO tokenInfo;
209        for (int i=0; i < tokenIDs.length; i++) {
210          System.out.println("Token Info: ");
211          tokenInfo = myPKCS11Module_.C_GetTokenInfo(tokenIDs[i]);
212          System.out.println(tokenInfo);
213          if (token_ == -1L) {
214            token_ = tokenIDs[i];
215          }
216        }
217        System.out.println("FINISHED\n");
218      }
219    
220      public void getMechanismInfo()
221          throws PKCS11Exception
222      {
223        CK_MECHANISM_INFO mechanismInfo;
224    
225        System.out.println("getting mechanism list");
226        System.out.println("getting slot list");
227        long[] slotIDs = myPKCS11Module_.C_GetSlotList(true);
228        for (int i=0; i < slotIDs.length; i++) {
229          System.out.println("getting mechanism list for slot " + slotIDs[i]);
230          long[] mechanismIDs = myPKCS11Module_.C_GetMechanismList(slotIDs[i]);
231          for (int j=0; j < mechanismIDs.length; j++) {
232            System.out.println("mechanism info for mechanism " + Functions.mechanismCodeToString(mechanismIDs[j]) +
233             ": ");
234            mechanismInfo = myPKCS11Module_.C_GetMechanismInfo(slotIDs[i],
235                     mechanismIDs[j]);
236            System.out.println(mechanismInfo);
237          }
238        }
239        System.out.println("FINISHED\n");
240      }
241    
242      public void initToken()
243          throws PKCS11Exception
244      {
245        String label = "The Label!                      ";
246        String pin = "password";
247    
248        System.out.println("init token");
249        long[] slotIDs = myPKCS11Module_.C_GetSlotList(false);
250        myPKCS11Module_.C_InitToken(slotIDs[0], pin.toCharArray(), label.toCharArray());
251        System.out.println("FINISHED");
252      }
253    
254      public void openROSession()
255          throws PKCS11Exception
256      {
257        System.out.println("open RO session");
258        session_ = myPKCS11Module_.C_OpenSession(token_, PKCS11Constants.CKF_SERIAL_SESSION, null, null);
259        System.out.println("FINISHED\n");
260      }
261    
262      public void getSessionInfo()
263          throws PKCS11Exception
264      {
265        System.out.println("get session info");
266        CK_SESSION_INFO sessionInfo;
267        System.out.println("Session Info: ");
268        sessionInfo = myPKCS11Module_.C_GetSessionInfo(session_);
269        System.out.println(sessionInfo);
270        System.out.println("FINISHED\n");
271      }
272    
273      public void findAllObjects()
274          throws PKCS11Exception
275      {
276        System.out.println("find all objects");
277        myPKCS11Module_.C_FindObjectsInit(session_, null);
278        objects_ = myPKCS11Module_.C_FindObjects(session_, 100); //maximum of 100 at once
279        if (objects_ == null) {
280          System.out.println("null returned - no objects found");
281        } else {
282          System.out.println("found " + objects_.length + " objects");
283        }
284        myPKCS11Module_.C_FindObjectsFinal(session_);
285        System.out.println("FINISHED\n");
286      }
287    
288      public void printAllObjects()
289          throws PKCS11Exception
290      {
291        System.out.println("print all objects");
292    
293        for (int i = 0; i < objects_.length; i++) {
294          System.out.println("object No. " + i);
295          CK_ATTRIBUTE[] template = new CK_ATTRIBUTE[1];
296          template[0] = new CK_ATTRIBUTE();
297          template[0].type = PKCS11Constants.CKA_CLASS;
298          myPKCS11Module_.C_GetAttributeValue(session_, objects_[i], template);
299          System.out.println("CKA_CLASS: " + Functions.classTypeToString(((Long) template[0].pValue).longValue()));
300        }
301    
302        System.out.println("FINISHED\n");
303      }
304    
305      public void loginUser()
306          throws PKCS11Exception
307      {
308        System.out.println("login user to session with password \"" + userPin_ + "\"");
309        myPKCS11Module_.C_Login(session_, PKCS11Constants.CKU_USER, userPin_.toCharArray());
310        System.out.println("FINISHED\n");
311      }
312    
313      public void findSignatureKey()
314          throws PKCS11Exception
315      {
316        System.out.println("find signature key");
317        CK_ATTRIBUTE[] attributeTemplateList = new CK_ATTRIBUTE[2];
318    
319        attributeTemplateList[0] = new CK_ATTRIBUTE();
320        attributeTemplateList[0].type = PKCS11Constants.CKA_CLASS;
321        attributeTemplateList[0].pValue = new Long(PKCS11Constants.CKO_PRIVATE_KEY);
322        attributeTemplateList[1] = new CK_ATTRIBUTE();
323        attributeTemplateList[1].type = PKCS11Constants.CKA_SIGN;
324        attributeTemplateList[1].pValue = new Boolean(PKCS11Constants.TRUE);
325    
326        myPKCS11Module_.C_FindObjectsInit(session_, attributeTemplateList);
327        long[] availableSignatureKeys = myPKCS11Module_.C_FindObjects(session_, 100); //maximum of 100 at once
328        if (availableSignatureKeys == null) {
329          System.out.println("null returned - no signature key found");
330        } else {
331          System.out.println("found " + availableSignatureKeys.length + " signature keys");
332          for (int i=0; i < availableSignatureKeys.length; i++) {
333            if (i == 0) { // the first we find, we take as our signature key
334              signatureKeyHandle_ = availableSignatureKeys[i];
335              System.out.print("for signing we use ");
336            }
337            System.out.println("signature key " + i);
338          }
339        }
340        myPKCS11Module_.C_FindObjectsFinal(session_);
341        System.out.println("FINISHED\n");
342      }
343    
344      public void findCertificate()
345          throws PKCS11Exception
346      {
347        System.out.println("find certificate");
348    
349        // first get the ID of the signature key
350        CK_ATTRIBUTE[] attributeTemplateList = new CK_ATTRIBUTE[1];
351        attributeTemplateList[0] = new CK_ATTRIBUTE();
352        attributeTemplateList[0].type = PKCS11Constants.CKA_ID;
353    
354        myPKCS11Module_.C_GetAttributeValue(session_, signatureKeyHandle_ , attributeTemplateList);
355        byte[] keyAndCertificateID = (byte[]) attributeTemplateList[0].pValue;
356        System.out.println("ID of siganture key: " + Functions.toHexString(keyAndCertificateID));
357    
358        // now get the certificate with the same ID as the signature key
359        attributeTemplateList = new CK_ATTRIBUTE[2];
360    
361        attributeTemplateList[0] = new CK_ATTRIBUTE();
362        attributeTemplateList[0].type = PKCS11Constants.CKA_CLASS;
363        attributeTemplateList[0].pValue = new Long(PKCS11Constants.CKO_CERTIFICATE);
364        attributeTemplateList[1] = new CK_ATTRIBUTE();
365        attributeTemplateList[1].type = PKCS11Constants.CKA_ID;
366        attributeTemplateList[1].pValue = keyAndCertificateID;
367    
368        myPKCS11Module_.C_FindObjectsInit(session_, attributeTemplateList);
369        long[] availableCertificates = myPKCS11Module_.C_FindObjects(session_, 100); //maximum of 100 at once
370        if (availableCertificates == null) {
371          System.out.println("null returned - no certificate found");
372        } else {
373          System.out.println("found " + availableCertificates.length + " certificates with matching ID");
374          for (int i=0; i < availableCertificates.length; i++) {
375            if (i == 0) { // the first we find, we take as our certificate
376              certificateHandle_ = availableCertificates[i];
377              System.out.print("for verification we use ");
378            }
379            System.out.println("certificate " + i);
380          }
381        }
382        myPKCS11Module_.C_FindObjectsFinal(session_);
383        System.out.println("FINISHED\n");
384      }
385    
386      public void readCertificate()
387          throws PKCS11Exception
388      {
389        System.out.println("read certificate");
390    
391        CK_ATTRIBUTE[] template = new CK_ATTRIBUTE[1];
392        template[0] = new CK_ATTRIBUTE();
393        template[0].type = PKCS11Constants.CKA_VALUE;
394        myPKCS11Module_.C_GetAttributeValue(session_, certificateHandle_ , template);
395        derEncodedCertificate_ = (byte[]) template[0].pValue;
396        System.out.println("DER encoded certificate (" + derEncodedCertificate_.length + " bytes):");
397        System.out.println(Functions.toHexString(derEncodedCertificate_));
398    
399        System.out.println("FINISHED\n");
400      }
401    
402      public void writeCertificateToFile()
403          throws IOException, PKCS11Exception
404      {
405        System.out.println("write certificate to file: " + CERTIFICATE_FILE);
406    
407        FileOutputStream fos = new FileOutputStream(CERTIFICATE_FILE);
408        fos.write(derEncodedCertificate_);
409        fos.flush();
410        fos.close();
411    
412        System.out.println("FINISHED\n");
413      }
414    
415      public void signData()
416          throws IOException, PKCS11Exception
417      {
418        byte[] buffer = new byte[1024];
419        byte[] helpBuffer;
420        int bytesRead;
421    
422        InputStream dataInput = new FileInputStream(file_);
423        myPKCS11Module_.C_SignInit(session_, signatureMechanism_, signatureKeyHandle_);
424        while ((bytesRead = dataInput.read(buffer, 0, buffer.length)) >= 0) {
425          helpBuffer = new byte[bytesRead]; // we need a buffer that only holds what to send for signing
426          System.arraycopy(buffer, 0, helpBuffer, 0, bytesRead);
427          myPKCS11Module_.C_SignUpdate(session_, helpBuffer);
428          Arrays.fill(helpBuffer, (byte) 0);
429        }
430        Arrays.fill(buffer, (byte) 0);
431        signature_ = myPKCS11Module_.C_SignFinal(session_);
432      }
433    
434      public void writeSignatureToFile()
435          throws IOException, PKCS11Exception
436      {
437        System.out.println("write signature to file: " + SIGNATURE_FILE);
438    
439        FileOutputStream fos = new FileOutputStream(SIGNATURE_FILE);
440        fos.write(signature_);
441        fos.flush();
442        fos.close();
443    
444        System.out.println("FINISHED");
445      }
446    
447      public void digestData()
448          throws IOException, PKCS11Exception
449      {
450        byte[] buffer = new byte[1024];
451        byte[] helpBuffer, testDigest;
452        int bytesRead;
453    
454        System.out.println("Digest Data");
455        myPKCS11Module_.C_DigestInit(session_, digestMechanism_);
456        try { 
457          messageDigest_ = MessageDigest.getInstance("SHA-1"); 
458        } catch (Exception e) { 
459          System.out.println(e); 
460        }
461        InputStream dataInput = new FileInputStream(file_);
462       while ((bytesRead = dataInput.read(buffer, 0, buffer.length)) >= 0) {
463          helpBuffer = new byte[bytesRead]; // we need a buffer that only holds what to send for digesting
464          System.arraycopy(buffer, 0, helpBuffer, 0, bytesRead);
465          myPKCS11Module_.C_DigestUpdate(session_, helpBuffer);
466          messageDigest_.update(helpBuffer);
467          Arrays.fill(helpBuffer, (byte) 0);
468        }
469        Arrays.fill(buffer, (byte) 0);
470        digest_ = myPKCS11Module_.C_DigestFinal(session_);
471        testDigest = messageDigest_.digest();
472        System.out.println("PKCS11digest:"+Functions.toHexString(digest_));
473        System.out.println("TestDigest  :"+Functions.toHexString(testDigest));
474        System.out.println("FINISHED\n");
475      }
476    
477      public void writeDigestToFile()
478          throws IOException, PKCS11Exception
479      {
480        System.out.println("write digest to file: " + DIGEST_FILE);
481    
482        FileOutputStream fos = new FileOutputStream(DIGEST_FILE);
483        fos.write(digest_);
484        fos.flush();
485        fos.close();
486    
487        System.out.println("FINISHED\n");
488      }
489    
490      public void logout()
491          throws PKCS11Exception
492      {
493        System.out.println("logout session");
494        myPKCS11Module_.C_Logout(session_);
495        System.out.println("FINISHED\n");
496      }
497    
498      public void closeSession()
499          throws PKCS11Exception
500      {
501        System.out.println("close session");
502        myPKCS11Module_.C_CloseSession(session_);
503        System.out.println("FINISHED\n");
504      }
505    
506    
507    }