    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    }