FileDocCategorySizeDatePackage
SignCert.javaAPI DocphoneME MR2 API (J2ME)11212Wed May 02 18:00:26 BST 2007com.sun.midp.jadtool

SignCert

public class SignCert extends Object
SignCert is a utility class used by the AppDescriptor Class to modify a self-signed certificate in a KeyStore. These methods do not modify an AppDescriptor at all, but only modify the contents of a Java KeyStore.

Given the alias of a self-signed certificate and the alias of a "signing" certificate...the alias of another certificate that is paired with a private key...the static method SignACert will replace the self-signed certificate with the same certificate signed by the owner of the "signing" certificate.

PORTABILITY WARNING! -------------------- This class uses Sun implementation specific classes in the sun.security.x509.* namespace imported here. This is NOT portable to Java runtime environments provided by other vendors. It may not even be supported in future releases of the Sun JDK. This code works under Sun's JDK1.3.

We were forced to use Sun's X509 certificate implementation classes directly because the public X509 certificate methods in java.security.cert.* do not provide ways to programmatically modify fields within a X509 certificate object.

For more information about the sun.* classes, see:
http://java.sun.com/products/jdk/faq/faq-sun-packages.html

Fields Summary
Constructors Summary
Methods Summary
private static java.lang.Object[]recoverPrivateKey(java.lang.String alias, char[] storePass, char[] keyPass, java.security.KeyStore keyStore)
Recovers (private) key associated with given alias.

return
an array of objects, where the 1st element in the array is the recovered private key, and the 2nd element is the password used to recover it.

        Key key = null;
        
        if (keyStore.containsAlias(alias) == false) {
            throw new Exception("Alias <" + alias + "> does not exist");
        }
        if (keyStore.isKeyEntry(alias) == false) {
            throw new Exception("Alias <" + alias + "> has no (private) key");
        }

        if (keyPass == null) {
            // Try to recover the key using the keystore password
            try {
                key = keyStore.getKey(alias, storePass);
                keyPass = storePass;
            } catch (UnrecoverableKeyException e) {
                throw new Exception("Invalid Key password entered");
                // Did not work out, so prompt user for key password
                // keyPass = getKeyPasswd(alias, null, null);
                // key = keyStore.getKey(alias, keyPass);
            }
        } else {
            key = keyStore.getKey(alias, keyPass);
        }
        if (!(key instanceof PrivateKey)) {
            throw new Exception("Recovered key is not a private key");
        }
        return new Object[] {(PrivateKey)key, keyPass};
    
public static voidsignACert(java.lang.String signee_alias, java.lang.String signing_alias, char[] keyPass, java.security.KeyStore keyStore, char[] storePass)
Signs a certificate signee_alias using the signing (private) key associated with signing_alias. keyPass unlocks the signing key.

Creates a signed certificate and stores it as a single-element certificate chain associated with signee_alias.


        String sigAlgName;

        if (signee_alias == null || signing_alias == null || 
            keyPass == null || keyStore == null) {
            throw new AppDescriptorException("signACert got a null argument",
                                             4);
        }
        
        Object[] objs = recoverPrivateKey(signing_alias, storePass, 
                                          keyPass, keyStore);
        PrivateKey privKey = (PrivateKey)objs[0];
        if (keyPass == null)
            keyPass = (char[])objs[1];
        
        // Determine the signature algorithm
        // If no signature algorithm was specified at the command line,
        // we choose one that is compatible with the selected private key
        String keyAlgName = privKey.getAlgorithm();
        if (keyAlgName.equalsIgnoreCase("DSA")
            || keyAlgName.equalsIgnoreCase("DSS")) {
            sigAlgName = "SHA1WithDSA";
        } else if (keyAlgName.equalsIgnoreCase("RSA")) {
            sigAlgName = "SHA1WithRSA";
        } else {
            throw new
                AppDescriptorException("Cannot derive signature algorithm", 5);
        }

        // Get the old certificate
        Certificate oldCert = keyStore.getCertificate(signee_alias);
        if (oldCert == null) {
            throw new
                AppDescriptorException(signee_alias + " has no public key", 4);
        }

        if (!(oldCert instanceof X509Certificate)) {
            throw new AppDescriptorException(signee_alias +
                " has no X.509 certificate", 6);
        }
        
        // Get the "signing" certificate
        Certificate signingCert = keyStore.getCertificate(signing_alias);
        if (signingCert == null) {
            throw new
                AppDescriptorException(signee_alias + " has no public key", 7);
        }

        if (!(signingCert instanceof X509Certificate)) {
            throw new AppDescriptorException(signee_alias +
                " has no X.509 certificate", 8);
        }       

        // convert to X509CertImpl, so that we can modify selected fields
        // (no public APIs available yet)
        byte[] encoded = oldCert.getEncoded();
        X509CertImpl certImpl = new X509CertImpl(encoded);
        X509CertInfo certInfo = (X509CertInfo)certImpl.get(X509CertImpl.NAME +
                                "." + X509CertImpl.INFO);       
        
        // get an X509Certificate from the signing_alias
        encoded = signingCert.getEncoded();
        X509CertImpl signingCertImpl = new X509CertImpl(encoded);
        X509CertInfo signingCertInfo = (X509CertInfo) 
            signingCertImpl.get(X509CertImpl.NAME
                                + "." + X509CertImpl.INFO);     
        
        // Extend its validity
        int validity = 180;  // 180 days default
        Date firstDate = new Date();
        Date lastDate = new Date();
        lastDate.setTime(firstDate.getTime() + validity*1000*24*60*60L);
        CertificateValidity interval = new CertificateValidity(firstDate,
                                                               lastDate);
        certInfo.set(X509CertInfo.VALIDITY, interval);
        
        // Make new serial number
        certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber
            ((int)(firstDate.getTime()/1000)));

        // Set owner and issuer fields
        X500Name owner;
        // Get the owner name from the certificate
        owner = (X500Name)certInfo.get(X509CertInfo.SUBJECT + "." +
                                       CertificateSubjectName.DN_NAME);

        // Get the issuer name - the owner of the signing certificate
        X500Name issuer;
        issuer = (X500Name)signingCertInfo.get(X509CertInfo.SUBJECT + "." +
                                           CertificateSubjectName.DN_NAME);
        
        certInfo.set(X509CertInfo.ISSUER + "." +
                     CertificateIssuerName.DN_NAME, issuer);
        
        // The inner and outer signature algorithms have to match.
        // The way we achieve that is really ugly, but there seems to be no
        // other solution: We first sign the cert, then retrieve the
        // outer sigalg and use it to set the inner sigalg

        X509CertImpl newCert = new X509CertImpl(certInfo);
        newCert.sign(privKey, sigAlgName);
        AlgorithmId sigAlgid = (AlgorithmId)newCert.get(X509CertImpl.SIG_ALG);
        certInfo.set(CertificateAlgorithmId.NAME + "." +
                     CertificateAlgorithmId.ALGORITHM, sigAlgid);

        // Sign the new certificate
        newCert = new X509CertImpl(certInfo);
        newCert.sign(privKey, sigAlgName);

        // Store the new certificate as a single-element certificate chain
        keyStore.setKeyEntry(signee_alias, privKey,
                             (keyPass != null) ? keyPass : storePass,
                             new Certificate[] { newCert });


        System.err.println("New certificate signed & inserted into KeyStore!");
        System.err.print(newCert.toString());
        System.err.println();