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.FileInputStream; 048 import java.io.InputStream; 049 import java.io.InputStreamReader; 050 import java.io.PrintWriter; 051 import java.security.Security; 052 import java.util.Arrays; 053 import java.util.HashSet; 054 055 import iaik.asn1.ObjectID; 056 import iaik.asn1.structures.Name; 057 import iaik.pkcs.pkcs11.Mechanism; 058 import iaik.pkcs.pkcs11.MechanismInfo; 059 import iaik.pkcs.pkcs11.Module; 060 import iaik.pkcs.pkcs11.Session; 061 import iaik.pkcs.pkcs11.Token; 062 import iaik.pkcs.pkcs11.TokenInfo; 063 import iaik.pkcs.pkcs11.objects.RSAPrivateKey; 064 import iaik.pkcs.pkcs11.objects.X509PublicKeyCertificate; 065 import iaik.pkcs.pkcs12.CertificateBag; 066 import iaik.pkcs.pkcs12.KeyBag; 067 import iaik.pkcs.pkcs12.PKCS12; 068 import iaik.security.provider.IAIK; 069 import iaik.x509.X509Certificate; 070 import iaik.x509.extensions.KeyUsage; 071 import iaik.x509.extensions.SubjectKeyIdentifier; 072 073 074 075 /** 076 * This demo program can be used to personalize a card. It downloads a private 077 * RSA key and the corresponding certificate. The key and the certificate are 078 * given as a file in PKCS#12 format. The usage flags of the key object are 079 * taken from the key usage flags of the certificate. 080 * 081 * @author <a href="mailto:Karl.Scheibelhofer@iaik.at"> Karl Scheibelhofer </a> 082 * @version 0.1 083 * @invariants 084 */ 085 public class DownloadPrivateKey { 086 087 static BufferedReader input_; 088 089 static PrintWriter output_; 090 091 static { 092 try { 093 //output_ = new PrintWriter(new FileWriter("SignAndVerify_output.txt"), true); 094 output_ = new PrintWriter(System.out, true); 095 input_ = new BufferedReader(new InputStreamReader(System.in)); 096 } catch (Throwable thr) { 097 thr.printStackTrace(); 098 output_ = new PrintWriter(System.out, true); 099 input_ = new BufferedReader(new InputStreamReader(System.in)); 100 } 101 } 102 103 public static void main(String[] args) { 104 if (args.length != 3) { 105 printUsage(); 106 System.exit(1); 107 } 108 109 try { 110 111 Security.addProvider(new IAIK()); 112 113 Module pkcs11Module = Module.getInstance(args[0]); 114 pkcs11Module.initialize(null); 115 116 Token token = Util.selectToken(pkcs11Module, output_, input_); 117 if (token == null) { 118 output_.println("We have no token to proceed. Finished."); 119 output_.flush(); 120 System.exit(0); 121 } 122 TokenInfo tokenInfo = token.getTokenInfo(); 123 124 output_.println("################################################################################"); 125 output_.println("Information of Token:"); 126 output_.println(tokenInfo); 127 output_.println("################################################################################"); 128 129 output_.println("################################################################################"); 130 output_.println("Reading private key and certifiacte from: " + args[1]); 131 InputStream dataInputStream = new FileInputStream(args[1]); 132 PKCS12 pkcs12Object = new PKCS12(dataInputStream); 133 char[] filePassword = args[2].toCharArray(); 134 pkcs12Object.decrypt(filePassword); 135 KeyBag keyBag = pkcs12Object.getKeyBag(); 136 java.security.PrivateKey jcaPrivateKey = keyBag.getPrivateKey(); 137 138 if (!jcaPrivateKey.getAlgorithm().equals("RSA")) { 139 output_.println("Private Key in the PKCS#12 file is not a RSA key."); 140 System.exit(1); 141 } 142 143 java.security.interfaces.RSAPrivateKey jcaRsaPrivateKey = 144 (java.security.interfaces.RSAPrivateKey) jcaPrivateKey; 145 146 output_.println("got private key"); 147 148 CertificateBag[] certificateBags = pkcs12Object.getCertificateBags(); 149 X509Certificate[] certificateChain = CertificateBag.getCertificates(certificateBags); 150 certificateChain = iaik.utils.Util.arrangeCertificateChain(certificateChain, false); 151 152 X509Certificate userCertificate = certificateChain[0]; 153 String userCommonName = ((Name) userCertificate.getSubjectDN()).getRDN(ObjectID.commonName).toString(); 154 byte[] certificateFingerprint = userCertificate.getFingerprint("SHA-1"); 155 KeyUsage keyUsage = (KeyUsage) userCertificate.getExtension(KeyUsage.oid); 156 SubjectKeyIdentifier subjectKeyIdentifier = (SubjectKeyIdentifier) 157 userCertificate.getExtension(SubjectKeyIdentifier.oid); 158 159 output_.println("got user certifiate"); 160 output_.println("################################################################################"); 161 162 Session session = Util.openAuthorizedSession(token, Token.SessionReadWriteBehavior.RW_SESSION, output_, input_); 163 164 output_.println("################################################################################"); 165 output_.println("creating private key object on the card... "); 166 output_.flush(); 167 168 // check out what attributes of the keys we may set using the mechanism info 169 HashSet supportedMechanisms = new HashSet(Arrays.asList(token.getMechanismList())); 170 171 MechanismInfo signatureMechanismInfo; 172 if (supportedMechanisms.contains(Mechanism.RSA_PKCS)) { 173 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_PKCS); 174 } else if (supportedMechanisms.contains(Mechanism.RSA_X_509)) { 175 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_X_509); 176 } else if (supportedMechanisms.contains(Mechanism.RSA_9796)) { 177 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_9796); 178 } else if (supportedMechanisms.contains(Mechanism.RSA_PKCS_OAEP)) { 179 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_PKCS_OAEP); 180 } else { 181 signatureMechanismInfo = null; 182 } 183 184 // create private key object template 185 RSAPrivateKey pkcs11RsaPrivateKey = new RSAPrivateKey(); 186 187 pkcs11RsaPrivateKey.getSensitive().setBooleanValue(Boolean.TRUE); 188 //pkcs11RsaPrivateKey.getExtractable().setBooleanValue(Boolean.FALSE); 189 pkcs11RsaPrivateKey.getToken().setBooleanValue(Boolean.TRUE); 190 pkcs11RsaPrivateKey.getPrivate().setBooleanValue(Boolean.TRUE); 191 String keyLabel = userCommonName + "'s " + ((Name) userCertificate.getIssuerDN()).getRDN(ObjectID.organization); 192 pkcs11RsaPrivateKey.getLabel().setCharArrayValue(keyLabel.toCharArray()); 193 194 byte[] newObjectID; 195 if (subjectKeyIdentifier != null) { 196 // we take the key identifier from the certificate 197 newObjectID = subjectKeyIdentifier.get(); 198 } else { 199 // then we simply take the fingerprint of the certificate 200 newObjectID = certificateFingerprint; 201 } 202 203 pkcs11RsaPrivateKey.getId().setByteArrayValue(newObjectID); 204 205 //pkcs11RsaPrivateKey.getStartDate().setDateValue(userCertificate.getNotBefore()); 206 //pkcs11RsaPrivateKey.getEndDate().setDateValue(userCertificate.getNotAfter()); 207 208 pkcs11RsaPrivateKey.getSubject().setByteArrayValue(((Name) userCertificate.getSubjectDN()).getEncoded()); 209 210 if (keyUsage != null) { 211 // set usage flags acording to key usage flags of certificate 212 int keyUsageFlags = keyUsage.get(); 213 214 215 // set the attributes in a way netscape does, this should work with most tokens 216 if (signatureMechanismInfo != null) { 217 pkcs11RsaPrivateKey.getDecrypt().setBooleanValue( 218 new Boolean((((keyUsageFlags & KeyUsage.dataEncipherment) != 0) 219 || ((keyUsageFlags & KeyUsage.keyCertSign) != 0)) 220 && signatureMechanismInfo.isDecrypt())); 221 pkcs11RsaPrivateKey.getSign().setBooleanValue( 222 new Boolean((((keyUsageFlags & KeyUsage.digitalSignature) != 0) 223 || ((keyUsageFlags & KeyUsage.keyCertSign) != 0) 224 || ((keyUsageFlags & KeyUsage.cRLSign) != 0) 225 || ((keyUsageFlags & KeyUsage.nonRepudiation) != 0)) 226 && signatureMechanismInfo.isSign())); 227 pkcs11RsaPrivateKey.getSignRecover().setBooleanValue( 228 new Boolean((((keyUsageFlags & KeyUsage.digitalSignature) != 0) 229 || ((keyUsageFlags & KeyUsage.keyCertSign) != 0) 230 || ((keyUsageFlags & KeyUsage.cRLSign) != 0) 231 || ((keyUsageFlags & KeyUsage.nonRepudiation) != 0)) 232 && signatureMechanismInfo.isSignRecover())); 233 pkcs11RsaPrivateKey.getDerive().setBooleanValue( 234 new Boolean(((keyUsageFlags & KeyUsage.keyAgreement) != 0) 235 && signatureMechanismInfo.isDerive())); 236 pkcs11RsaPrivateKey.getUnwrap().setBooleanValue( 237 new Boolean(((keyUsageFlags & KeyUsage.keyEncipherment) != 0) 238 && signatureMechanismInfo.isUnwrap())); 239 } else { 240 // if we have no mechanism information, we try to set the flags according to the key usage only 241 pkcs11RsaPrivateKey.getDecrypt().setBooleanValue( 242 new Boolean( ((keyUsageFlags & KeyUsage.dataEncipherment) != 0) 243 || ((keyUsageFlags & KeyUsage.keyCertSign) != 0))); 244 pkcs11RsaPrivateKey.getSign().setBooleanValue( 245 new Boolean( ((keyUsageFlags & KeyUsage.digitalSignature) != 0) 246 || ((keyUsageFlags & KeyUsage.keyCertSign) != 0) 247 || ((keyUsageFlags & KeyUsage.cRLSign) != 0) 248 || ((keyUsageFlags & KeyUsage.nonRepudiation) != 0))); 249 pkcs11RsaPrivateKey.getSignRecover().setBooleanValue( 250 new Boolean( ((keyUsageFlags & KeyUsage.digitalSignature) != 0) 251 || ((keyUsageFlags & KeyUsage.keyCertSign) != 0) 252 || ((keyUsageFlags & KeyUsage.cRLSign) != 0) 253 || ((keyUsageFlags & KeyUsage.nonRepudiation) != 0))); 254 pkcs11RsaPrivateKey.getDerive().setBooleanValue( 255 new Boolean((keyUsageFlags & KeyUsage.keyAgreement) != 0)); 256 pkcs11RsaPrivateKey.getUnwrap().setBooleanValue( 257 new Boolean((keyUsageFlags & KeyUsage.keyEncipherment) != 0)); 258 } 259 } else { 260 // if there is no keyusage extension in the certificate, try to set all flags according to the mechanism info 261 if (signatureMechanismInfo != null) { 262 pkcs11RsaPrivateKey.getSign().setBooleanValue(new Boolean(signatureMechanismInfo.isSign())); 263 pkcs11RsaPrivateKey.getSignRecover().setBooleanValue(new Boolean(signatureMechanismInfo.isSignRecover())); 264 pkcs11RsaPrivateKey.getDecrypt().setBooleanValue(new Boolean(signatureMechanismInfo.isDecrypt())); 265 pkcs11RsaPrivateKey.getDerive().setBooleanValue(new Boolean(signatureMechanismInfo.isDerive())); 266 pkcs11RsaPrivateKey.getUnwrap().setBooleanValue(new Boolean(signatureMechanismInfo.isUnwrap())); 267 } else { 268 // if we have neither mechanism info nor key usage we just try all 269 pkcs11RsaPrivateKey.getSign().setBooleanValue(Boolean.TRUE); 270 pkcs11RsaPrivateKey.getSignRecover().setBooleanValue(Boolean.TRUE); 271 pkcs11RsaPrivateKey.getDecrypt().setBooleanValue(Boolean.TRUE); 272 pkcs11RsaPrivateKey.getDerive().setBooleanValue(Boolean.TRUE); 273 pkcs11RsaPrivateKey.getUnwrap().setBooleanValue(Boolean.TRUE); 274 } 275 } 276 277 pkcs11RsaPrivateKey.getModulus().setByteArrayValue( 278 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(jcaRsaPrivateKey.getModulus())); 279 pkcs11RsaPrivateKey.getPrivateExponent().setByteArrayValue( 280 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(jcaRsaPrivateKey.getPrivateExponent())); 281 pkcs11RsaPrivateKey.getPublicExponent().setByteArrayValue( 282 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray( 283 ((java.security.interfaces.RSAPublicKey) userCertificate.getPublicKey()).getPublicExponent())); 284 285 if (jcaRsaPrivateKey instanceof java.security.interfaces.RSAPrivateCrtKey) { 286 // if we have the CRT field, we write it to the card 287 // e.g. gemsafe seems to need it 288 java.security.interfaces.RSAPrivateCrtKey crtKey = 289 (java.security.interfaces.RSAPrivateCrtKey)jcaRsaPrivateKey; 290 pkcs11RsaPrivateKey.getPrime1().setByteArrayValue( 291 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(crtKey.getPrimeP())); 292 pkcs11RsaPrivateKey.getPrime2().setByteArrayValue( 293 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(crtKey.getPrimeQ())); 294 pkcs11RsaPrivateKey.getExponent1().setByteArrayValue( 295 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(crtKey.getPrimeExponentP())); 296 pkcs11RsaPrivateKey.getExponent2().setByteArrayValue( 297 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(crtKey.getPrimeExponentQ())); 298 pkcs11RsaPrivateKey.getCoefficient().setByteArrayValue( 299 iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(crtKey.getCrtCoefficient())); 300 } 301 302 output_.println(pkcs11RsaPrivateKey); 303 session.createObject(pkcs11RsaPrivateKey); 304 305 output_.println("################################################################################"); 306 307 308 output_.println("################################################################################"); 309 output_.println("creating certificate object on the card... "); 310 output_.flush(); 311 312 // create certificate object template 313 X509PublicKeyCertificate pkcs11X509PublicKeyCertificate = new X509PublicKeyCertificate(); 314 315 pkcs11X509PublicKeyCertificate.getToken().setBooleanValue(Boolean.TRUE); 316 pkcs11X509PublicKeyCertificate.getPrivate().setBooleanValue(Boolean.FALSE); 317 pkcs11X509PublicKeyCertificate.getLabel().setCharArrayValue(keyLabel.toCharArray()); 318 pkcs11X509PublicKeyCertificate.getSubject().setByteArrayValue( 319 ((Name) userCertificate.getSubjectDN()).getEncoded()); 320 pkcs11X509PublicKeyCertificate.getId().setByteArrayValue(newObjectID); 321 pkcs11X509PublicKeyCertificate.getIssuer().setByteArrayValue( 322 ((Name) userCertificate.getIssuerDN()).getEncoded()); 323 // serial number should be an DER encoded ASN.1 integer 324 /* 325 INTEGER asn1Integer = new INTEGER(userCertificate.getSerialNumber()); 326 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 327 DerCoder.encodeTo(asn1Integer, buffer); 328 pkcs11X509PublicKeyCertificate.getSerialNumber().setByteArrayValue(buffer.toByteArray()); 329 */ 330 // Netscape deviates from the standard here, for use with Netscape rather use 331 pkcs11X509PublicKeyCertificate.getSerialNumber().setByteArrayValue( 332 userCertificate.getSerialNumber().toByteArray()); 333 pkcs11X509PublicKeyCertificate.getValue().setByteArrayValue(userCertificate.getEncoded()); 334 335 output_.println(pkcs11X509PublicKeyCertificate); 336 session.createObject(pkcs11X509PublicKeyCertificate); 337 338 output_.println("################################################################################"); 339 340 session.closeSession(); 341 pkcs11Module.finalize(null); 342 343 } catch (Throwable thr) { 344 thr.printStackTrace(); 345 } 346 } 347 348 public static void printUsage() { 349 output_.println("Usage: DownloadPrivateKey <PKCS#11 module> <PKCS#12 encoded private key and certificate> <PKCS#12 password>"); 350 output_.println(" e.g.: DownloadPrivateKey pk2priv.dll privatekeyAndCert.p12 filepassword"); 351 output_.println("The given DLL must be in the search path of the system."); 352 } 353 354 }