2445 lines · 92.7 KB · Java
RawDownload
            // The entry name to be written into attrs            String name = null;            try {                // Find if the digest already exists                AlgorithmId aid = AlgorithmId.get(digests[i].getAlgorithm());                for (Object key: attrs.keySet()) {                    if (key instanceof Attributes.Name) {                        String n = ((Attributes.Name)key).toString();                        if (n.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) {                            String tmp = n.substring(0, n.length() - 7);                            if (AlgorithmId.get(tmp).equals(aid)) {                                name = n;                                break;                            }                        }                    }                }            } catch (NoSuchAlgorithmException nsae) {                // Ignored. Writing new digest entry.            }             if (name == null) {                name = digests[i].getAlgorithm()+"-Digest";                attrs.putValue(name, base64Digests[i]);                update=true;            } else {                // compare digests, and replace the one in the manifest                // if they are different                String mfDigest = attrs.getValue(name);                if (!mfDigest.equalsIgnoreCase(base64Digests[i])) {                    attrs.putValue(name, base64Digests[i]);                    update=true;                }            }        }        return update;    }     /*     * Try to load the specified signing mechanism.     * The URL class loader is used.     */    private ContentSigner loadSigningMechanism(String signerClassName,        String signerClassPath) throws Exception {         // construct class loader        String cpString = null;   // make sure env.class.path defaults to dot         // do prepends to get correct ordering        cpString = PathList.appendPath(System.getProperty("env.class.path"), cpString);        cpString = PathList.appendPath(System.getProperty("java.class.path"), cpString);        cpString = PathList.appendPath(signerClassPath, cpString);        URL[] urls = PathList.pathToURLs(cpString);        ClassLoader appClassLoader = new URLClassLoader(urls);         // attempt to find signer        Class signerClass = appClassLoader.loadClass(signerClassName);         // Check that it implements ContentSigner        Object signer = signerClass.newInstance();        if (!(signer instanceof ContentSigner)) {            MessageFormat form = new MessageFormat(                rb.getString("signerClass.is.not.a.signing.mechanism"));            Object[] source = {signerClass.getName()};            throw new IllegalArgumentException(form.format(source));        }        return (ContentSigner)signer;    }} /** * This is a BASE64Encoder that does not insert a default newline at the end of * every output line. This is necessary because java.util.jar does its own * line management (see Manifest.make72Safe()). Inserting additional new lines * can cause line-wrapping problems (see CR 6219522). */class JarBASE64Encoder extends BASE64Encoder {    /**     * Encode the suffix that ends every output line.     */    protected void encodeLineSuffix(OutputStream aStream) throws IOException { }} class SignatureFile {     /** SignatureFile */    Manifest sf;     /** .SF base name */    String baseName;     public SignatureFile(MessageDigest digests[],                         Manifest mf,                         ManifestDigester md,                         String baseName,                         boolean signManifest)     {        this.baseName = baseName;         String version = System.getProperty("java.version");        String javaVendor = System.getProperty("java.vendor");         sf = new Manifest();        Attributes mattr = sf.getMainAttributes();        BASE64Encoder encoder = new JarBASE64Encoder();         mattr.putValue(Attributes.Name.SIGNATURE_VERSION.toString(), "1.0");        mattr.putValue("Created-By", version + " (" + javaVendor + ")");         if (signManifest) {            // sign the whole manifest            for (int i=0; i < digests.length; i++) {                mattr.putValue(digests[i].getAlgorithm()+"-Digest-Manifest",                               encoder.encode(md.manifestDigest(digests[i])));            }        }         // create digest of the manifest main attributes        ManifestDigester.Entry mde =                md.get(ManifestDigester.MF_MAIN_ATTRS, false);        if (mde != null) {            for (int i=0; i < digests.length; i++) {                mattr.putValue(digests[i].getAlgorithm() +                        "-Digest-" + ManifestDigester.MF_MAIN_ATTRS,                        encoder.encode(mde.digest(digests[i])));            }        } else {            throw new IllegalStateException                ("ManifestDigester failed to create " +                "Manifest-Main-Attribute entry");        }         /* go through the manifest entries and create the digests */         Map<String,Attributes> entries = sf.getEntries();        Iterator<Map.Entry<String,Attributes>> mit =                                mf.getEntries().entrySet().iterator();        while(mit.hasNext()) {            Map.Entry<String,Attributes> e = mit.next();            String name = e.getKey();            mde = md.get(name, false);            if (mde != null) {                Attributes attr = new Attributes();                for (int i=0; i < digests.length; i++) {                    attr.putValue(digests[i].getAlgorithm()+"-Digest",                                  encoder.encode(mde.digest(digests[i])));                }                entries.put(name, attr);            }        }    }     /**     * Writes the SignatureFile to the specified OutputStream.     *     * @param out the output stream     * @exception IOException if an I/O error has occurred     */     public void write(OutputStream out) throws IOException    {        sf.write(out);    }     /**     * get .SF file name     */    public String getMetaName()    {        return "META-INF/"+ baseName + ".SF";    }     /**     * get base file name     */    public String getBaseName()    {        return baseName;    }     /*     * Generate a signed data block.     * If a URL or a certificate (containing a URL) for a Timestamping     * Authority is supplied then a signature timestamp is generated and     * inserted into the signed data block.     *     * @param sigalg signature algorithm to use, or null to use default     * @param tsaUrl The location of the Timestamping Authority. If null     *               then no timestamp is requested.     * @param tsaCert The certificate for the Timestamping Authority. If null     *               then no timestamp is requested.     * @param signingMechanism The signing mechanism to use.     * @param args The command-line arguments to jarsigner.     * @param zipFile The original source Zip file.     */    public Block generateBlock(PrivateKey privateKey,                               String sigalg,                               X509Certificate[] certChain,                               boolean externalSF, String tsaUrl,                               X509Certificate tsaCert,                               ContentSigner signingMechanism,                               String[] args, ZipFile zipFile)        throws NoSuchAlgorithmException, InvalidKeyException, IOException,            SignatureException, CertificateException    {        return new Block(this, privateKey, sigalg, certChain, externalSF,                tsaUrl, tsaCert, signingMechanism, args, zipFile);    }      public static class Block {         private byte[] block;        private String blockFileName;         /*         * Construct a new signature block.         */        Block(SignatureFile sfg, PrivateKey privateKey, String sigalg,            X509Certificate[] certChain, boolean externalSF, String tsaUrl,            X509Certificate tsaCert, ContentSigner signingMechanism,            String[] args, ZipFile zipFile)            throws NoSuchAlgorithmException, InvalidKeyException, IOException,            SignatureException, CertificateException {             Principal issuerName = certChain[0].getIssuerDN();            if (!(issuerName instanceof X500Name)) {                // must extract the original encoded form of DN for subsequent                // name comparison checks (converting to a String and back to                // an encoded DN could cause the types of String attribute                // values to be changed)                X509CertInfo tbsCert = new                    X509CertInfo(certChain[0].getTBSCertificate());                issuerName = (Principal)                    tbsCert.get(CertificateIssuerName.NAME + "." +                                CertificateIssuerName.DN_NAME);            }            BigInteger serial = certChain[0].getSerialNumber();             String signatureAlgorithm;            String keyAlgorithm = privateKey.getAlgorithm();            /*             * If no signature algorithm was specified, we choose a             * default that is compatible with the private key algorithm.             */            if (sigalg == null) {                 if (keyAlgorithm.equalsIgnoreCase("DSA"))                    signatureAlgorithm = "SHA1withDSA";                else if (keyAlgorithm.equalsIgnoreCase("RSA"))                    signatureAlgorithm = "SHA256withRSA";                else if (keyAlgorithm.equalsIgnoreCase("EC"))                    signatureAlgorithm = "SHA256withECDSA";                else                    throw new RuntimeException("private key is not a DSA or "                                               + "RSA key");            } else {                signatureAlgorithm = sigalg;            }             // check common invalid key/signature algorithm combinations            String sigAlgUpperCase = signatureAlgorithm.toUpperCase(Locale.ENGLISH);            if ((sigAlgUpperCase.endsWith("WITHRSA") &&                !keyAlgorithm.equalsIgnoreCase("RSA")) ||                (sigAlgUpperCase.endsWith("WITHECDSA") &&                !keyAlgorithm.equalsIgnoreCase("EC")) ||                (sigAlgUpperCase.endsWith("WITHDSA") &&                !keyAlgorithm.equalsIgnoreCase("DSA"))) {                throw new SignatureException                    ("private key algorithm is not compatible with signature algorithm");            }             blockFileName = "META-INF/"+sfg.getBaseName()+"."+keyAlgorithm;             AlgorithmId sigAlg = AlgorithmId.get(signatureAlgorithm);            AlgorithmId digEncrAlg = AlgorithmId.get(keyAlgorithm);             Signature sig = Signature.getInstance(signatureAlgorithm);            sig.initSign(privateKey);             ByteArrayOutputStream baos = new ByteArrayOutputStream();            sfg.write(baos);             byte[] content = baos.toByteArray();             sig.update(content);            byte[] signature = sig.sign();             // Timestamp the signature and generate the signature block file            if (signingMechanism == null) {                signingMechanism = new TimestampedSigner();            }            URI tsaUri = null;            try {                if (tsaUrl != null) {                    tsaUri = new URI(tsaUrl);                }            } catch (URISyntaxException e) {                IOException ioe = new IOException();                ioe.initCause(e);                throw ioe;            }             // Assemble parameters for the signing mechanism            ContentSignerParameters params =                new JarSignerParameters(args, tsaUri, tsaCert, signature,                    signatureAlgorithm, certChain, content, zipFile);             // Generate the signature block            block = signingMechanism.generateSignedData(                    params, externalSF, (tsaUrl != null || tsaCert != null));        }         /*         * get block file name.         */        public String getMetaName()        {            return blockFileName;        }         /**         * Writes the block file to the specified OutputStream.         *         * @param out the output stream         * @exception IOException if an I/O error has occurred         */         public void write(OutputStream out) throws IOException        {            out.write(block);        }    }}  /* * This object encapsulates the parameters used to perform content signing. */class JarSignerParameters implements ContentSignerParameters {     private String[] args;    private URI tsa;    private X509Certificate tsaCertificate;    private byte[] signature;    private String signatureAlgorithm;    private X509Certificate[] signerCertificateChain;    private byte[] content;    private ZipFile source;     /**     * Create a new object.     */    JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate,        byte[] signature, String signatureAlgorithm,        X509Certificate[] signerCertificateChain, byte[] content,        ZipFile source) {         if (signature == null || signatureAlgorithm == null ||            signerCertificateChain == null) {            throw new NullPointerException();        }        this.args = args;        this.tsa = tsa;        this.tsaCertificate = tsaCertificate;        this.signature = signature;        this.signatureAlgorithm = signatureAlgorithm;        this.signerCertificateChain = signerCertificateChain;        this.content = content;        this.source = source;    }     /**     * Retrieves the command-line arguments.     *     * @return The command-line arguments. May be null.     */    public String[] getCommandLine() {        return args;    }     /**     * Retrieves the identifier for a Timestamping Authority (TSA).     *     * @return The TSA identifier. May be null.     */    public URI getTimestampingAuthority() {        return tsa;    }     /**     * Retrieves the certificate for a Timestamping Authority (TSA).     *     * @return The TSA certificate. May be null.     */    public X509Certificate getTimestampingAuthorityCertificate() {        return tsaCertificate;    }     /**     * Retrieves the signature.     *     * @return The non-null signature bytes.     */    public byte[] getSignature() {        return signature;    }     /**     * Retrieves the name of the signature algorithm.     *     * @return The non-null string name of the signature algorithm.     */    public String getSignatureAlgorithm() {        return signatureAlgorithm;    }     /**     * Retrieves the signer's X.509 certificate chain.     *     * @return The non-null array of X.509 public-key certificates.     */    public X509Certificate[] getSignerCertificateChain() {        return signerCertificateChain;    }     /**     * Retrieves the content that was signed.     *     * @return The content bytes. May be null.     */    public byte[] getContent() {        return content;    }     /**     * Retrieves the original source ZIP file before it was signed.     *     * @return The original ZIP file. May be null.     */    public ZipFile getSource() {        return source;    }}

Lines 2001–2445 of 2445. Previous lines