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 iaik.asn1.ObjectID; 047 import iaik.asn1.structures.Name; 048 import iaik.pkcs.pkcs11.Module; 049 import iaik.pkcs.pkcs11.Session; 050 import iaik.pkcs.pkcs11.Token; 051 import iaik.pkcs.pkcs11.TokenInfo; 052 import iaik.pkcs.pkcs11.objects.DHPrivateKey; 053 import iaik.pkcs.pkcs11.objects.DSAPrivateKey; 054 import iaik.pkcs.pkcs11.objects.Key; 055 import iaik.pkcs.pkcs11.objects.Object; 056 import iaik.pkcs.pkcs11.objects.RSAPrivateKey; 057 import iaik.pkcs.pkcs11.objects.X509PublicKeyCertificate; 058 import iaik.security.provider.IAIK; 059 060 import java.io.BufferedReader; 061 import java.io.FileInputStream; 062 import java.io.InputStreamReader; 063 import java.io.PrintWriter; 064 import java.security.MessageDigest; 065 import java.security.Provider; 066 import java.security.PublicKey; 067 import java.security.Security; 068 import java.security.cert.CertificateFactory; 069 import java.security.interfaces.DSAParams; 070 import java.util.Collection; 071 072 import javax.crypto.spec.DHParameterSpec; 073 074 075 /** 076 * This demo program imports a given X.509 certificate onto a PKCS#11 token. 077 * 078 * @author <a href="mailto:Karl.Scheibelhofer@iaik.at"> Karl Scheibelhofer </a> 079 * @version 0.1 080 * @invariants 081 */ 082 public class ImportCertificate { 083 084 static BufferedReader input_; 085 086 static PrintWriter output_; 087 088 static { 089 try { 090 //output_ = new PrintWriter(new FileWriter("SignAndVerify_output.txt"), true); 091 output_ = new PrintWriter(System.out, true); 092 input_ = new BufferedReader(new InputStreamReader(System.in)); 093 } catch (Throwable thr) { 094 thr.printStackTrace(); 095 output_ = new PrintWriter(System.out, true); 096 input_ = new BufferedReader(new InputStreamReader(System.in)); 097 } 098 } 099 100 public static void main(String[] args) { 101 if (args.length != 2) { 102 printUsage(); 103 System.exit(1); 104 } 105 106 try { 107 108 Security.addProvider(new IAIK()); 109 110 // try if we have the ECC provider available, if yes, add it 111 try { 112 Class eccProviderClass = Class.forName("iaik.security.ecc.provider.ECCProvider"); 113 Provider eccProvider = (Provider) eccProviderClass.newInstance(); 114 Security.addProvider(eccProvider); 115 } catch (Exception ex) { 116 // ignore, we only need it for pkcs#12 files containing ECC keys 117 } 118 119 Module pkcs11Module = Module.getInstance(args[0]); 120 pkcs11Module.initialize(null); 121 122 Token token = Util.selectToken(pkcs11Module, output_, input_); 123 if (token == null) { 124 output_.println("We have no token to proceed. Finished."); 125 output_.flush(); 126 System.exit(0); 127 } 128 TokenInfo tokenInfo = token.getTokenInfo(); 129 130 output_.println("################################################################################"); 131 output_.println("Information of Token:"); 132 output_.println(tokenInfo); 133 output_.println("################################################################################"); 134 135 output_.println("################################################################################"); 136 output_.println("Reading certificate from file: " + args[1]); 137 138 Session session = Util.openAuthorizedSession(token, Token.SessionReadWriteBehavior.RW_SESSION, output_, input_); 139 140 // parse certificate 141 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "IAIK"); 142 FileInputStream fileInputStream = new FileInputStream(args[1]); 143 Collection certificateChain = certificateFactory.generateCertificates(fileInputStream); 144 if (certificateChain.size() < 1) { 145 output_.println("Did not find any certificate in the given input file. Finished."); 146 output_.flush(); 147 System.exit(0); 148 } 149 iaik.x509.X509Certificate x509Certificate = 150 (iaik.x509.X509Certificate) certificateChain.iterator().next(); 151 certificateChain.remove(x509Certificate); 152 153 output_.println("################################################################################"); 154 155 output_.println("################################################################################"); 156 output_.println("Searching for corresponding private key on token."); 157 158 PublicKey publicKey = x509Certificate.getPublicKey(); 159 160 Object searchTemplate = null; 161 if (publicKey.getAlgorithm().equalsIgnoreCase("RSA")) { 162 java.security.interfaces.RSAPublicKey rsaPublicKey = (java.security.interfaces.RSAPublicKey) publicKey; 163 RSAPrivateKey rsaPrivateKeySearchTemplate = new RSAPrivateKey(); 164 byte[] modulus = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(rsaPublicKey.getModulus()); 165 rsaPrivateKeySearchTemplate.getModulus().setByteArrayValue(modulus); 166 searchTemplate = rsaPrivateKeySearchTemplate; 167 } else if (publicKey.getAlgorithm().equalsIgnoreCase("DSA")) { 168 java.security.interfaces.DSAPublicKey dsaPublicKey = (java.security.interfaces.DSAPublicKey) publicKey; 169 DSAParams dsaParams = dsaPublicKey.getParams(); 170 DSAPrivateKey dsaPrivateKeySearchTemplate = new DSAPrivateKey(); 171 byte[] g = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dsaParams.getG()); 172 byte[] p = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dsaParams.getP()); 173 byte[] q = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dsaParams.getQ()); 174 dsaPrivateKeySearchTemplate.getBase().setByteArrayValue(g); 175 dsaPrivateKeySearchTemplate.getPrime().setByteArrayValue(p); 176 dsaPrivateKeySearchTemplate.getSubprime().setByteArrayValue(q); 177 searchTemplate = dsaPrivateKeySearchTemplate; 178 } else if (publicKey.getAlgorithm().equalsIgnoreCase("DH") 179 || publicKey.getAlgorithm().equalsIgnoreCase("DiffieHellman")) { 180 javax.crypto.interfaces.DHPublicKey dhPublicKey = (javax.crypto.interfaces.DHPublicKey) publicKey; 181 DHParameterSpec dhParams = dhPublicKey.getParams(); 182 DHPrivateKey dhPrivateKeySearchTemplate = new DHPrivateKey(); 183 byte[] g = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dhParams.getG()); 184 byte[] p = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dhParams.getP()); 185 dhPrivateKeySearchTemplate.getBase().setByteArrayValue(g); 186 dhPrivateKeySearchTemplate.getPrime().setByteArrayValue(p); 187 searchTemplate = dhPrivateKeySearchTemplate; 188 } 189 190 byte[] objectID = null; 191 if (searchTemplate != null) { 192 session.findObjectsInit(searchTemplate); 193 Object[] foundKeyObjects = session.findObjects(1); 194 if (foundKeyObjects.length > 0) { 195 Key foundKey = (Key) foundKeyObjects[0]; 196 objectID = foundKey.getId().getByteArrayValue(); 197 output_.println("found a correponding key on the token: "); 198 output_.println(foundKey); 199 } else { 200 output_.println("found no correponding key on the token."); 201 } 202 session.findObjectsFinal(); 203 } else { 204 output_.println("public key is neither RSA, DSA nor DH."); 205 } 206 207 output_.println("################################################################################"); 208 209 210 output_.println("################################################################################"); 211 output_.println("Create certificate object(s) on token."); 212 213 iaik.x509.X509Certificate currentCertificate = x509Certificate; // start with user cert 214 boolean importedCompleteChain = false; 215 while (!importedCompleteChain) { 216 // create certificate object template 217 X509PublicKeyCertificate pkcs11X509PublicKeyCertificate = new X509PublicKeyCertificate(); 218 Name subjectName = (Name) currentCertificate.getSubjectDN(); 219 Name issuerName = (Name) currentCertificate.getIssuerDN(); 220 String subjectCommonName = subjectName.getRDN(ObjectID.commonName); 221 String issuerCommonName = issuerName.getRDN(ObjectID.commonName); 222 char[] label = (subjectCommonName + "'s " + 223 ((issuerCommonName != null) ? issuerCommonName + " " : "") + "Certificate").toCharArray(); 224 byte[] newObjectID; 225 // if we need a new object ID, create one 226 if (objectID == null) { 227 if (publicKey instanceof java.security.interfaces.RSAPublicKey) { 228 newObjectID = ((java.security.interfaces.RSAPublicKey) publicKey).getModulus().toByteArray(); 229 MessageDigest digest = MessageDigest.getInstance("SHA-1"); 230 newObjectID = digest.digest(newObjectID); 231 } else if (publicKey instanceof java.security.interfaces.DSAPublicKey) { 232 newObjectID = ((java.security.interfaces.DSAPublicKey) publicKey).getY().toByteArray(); 233 MessageDigest digest = MessageDigest.getInstance("SHA-1"); 234 newObjectID = digest.digest(newObjectID); 235 } else { 236 newObjectID = currentCertificate.getFingerprint("SHA-1"); 237 } 238 } else { 239 // we already got one from a corresponding private key before 240 newObjectID = objectID; 241 } 242 243 byte[] encodedSubject = ((Name) currentCertificate.getSubjectDN()).getEncoded(); 244 byte[] encodedIssuer = ((Name) currentCertificate.getIssuerDN()).getEncoded(); 245 246 // serial number should be an DER encoded ASN.1 integer 247 /* 248 INTEGER asn1Integer = new INTEGER(userCertificate.getSerialNumber()); 249 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 250 DerCoder.encodeTo(asn1Integer, buffer); 251 pkcs11X509PublicKeyCertificate.getSerialNumber().setByteArrayValue(buffer.toByteArray()); 252 */ 253 // Netscape deviates from the standard here, for use with Netscape rather use 254 byte[] serialNumber = currentCertificate.getSerialNumber().toByteArray(); 255 256 pkcs11X509PublicKeyCertificate.getToken().setBooleanValue(Boolean.TRUE); 257 pkcs11X509PublicKeyCertificate.getPrivate().setBooleanValue(Boolean.FALSE); 258 pkcs11X509PublicKeyCertificate.getLabel().setCharArrayValue(label); 259 pkcs11X509PublicKeyCertificate.getId().setByteArrayValue(newObjectID); 260 pkcs11X509PublicKeyCertificate.getSubject().setByteArrayValue(encodedSubject); 261 pkcs11X509PublicKeyCertificate.getIssuer().setByteArrayValue(encodedIssuer); 262 pkcs11X509PublicKeyCertificate.getSerialNumber().setByteArrayValue(serialNumber); 263 pkcs11X509PublicKeyCertificate.getValue().setByteArrayValue(currentCertificate.getEncoded()); 264 265 output_.println(pkcs11X509PublicKeyCertificate); 266 output_.println("________________________________________________________________________________"); 267 session.createObject(pkcs11X509PublicKeyCertificate); 268 269 if (certificateChain.size() > 0) { 270 currentCertificate = (iaik.x509.X509Certificate) certificateChain.iterator().next(); 271 certificateChain.remove(currentCertificate); 272 objectID = null; // do not use the same ID for other certificates 273 } else { 274 importedCompleteChain = true; 275 } 276 } 277 278 output_.println("################################################################################"); 279 280 session.closeSession(); 281 pkcs11Module.finalize(null); 282 283 } catch (Throwable thr) { 284 thr.printStackTrace(); 285 } 286 } 287 288 public static void printUsage() { 289 output_.println("Usage: ImportCertificate <PKCS#11 module> " + 290 "<DER encoded X.509 certificate, certificate chain, or PKCS#7 certificate chain>"); 291 output_.println(" e.g.: ImportCertificate pk2priv.dll myCertificate.der"); 292 output_.println("The given DLL must be in the search path of the system."); 293 } 294 295 }