--- a/jdk/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,9 @@
package com.sun.jarsigner;
import java.net.URI;
+import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
+import java.util.Set;
import java.util.zip.ZipFile;
/**
@@ -81,6 +83,13 @@
public X509Certificate[] getSignerCertificateChain();
/**
+ * Retrieves the signer's X.509 CRLs.
+ *
+ * @return An unmodifiable set of X.509 CRLs (never <code>null</code>)
+ */
+ public Set<X509CRL> getCRLs();
+
+ /**
* Retrieves the content that was signed.
* The content is the JAR file's signature file.
*
--- a/jdk/src/share/classes/java/security/CodeSigner.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/java/security/CodeSigner.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,10 @@
package java.security;
import java.io.Serializable;
+import java.security.cert.CRL;
import java.security.cert.CertPath;
+import sun.misc.JavaSecurityCodeSignerAccess;
+import sun.misc.SharedSecrets;
/**
* This class encapsulates information about a code signer.
@@ -163,4 +166,43 @@
sb.append(")");
return sb.toString();
}
+
+ // A private attribute attached to this CodeSigner object. Can be accessed
+ // through SharedSecrets.getJavaSecurityCodeSignerAccess().[g|s]etCRLs
+ //
+ // Currently called in SignatureFileVerifier.getSigners
+ private transient CRL[] crls;
+
+ /**
+ * Sets the CRLs attached
+ * @param crls, null to clear
+ */
+ void setCRLs(CRL[] crls) {
+ this.crls = crls;
+ }
+
+ /**
+ * Returns the CRLs attached
+ * @return the crls, initially null
+ */
+ CRL[] getCRLs() {
+ return crls;
+ }
+
+ // Set up JavaSecurityCodeSignerAccess in SharedSecrets
+ static {
+ SharedSecrets.setJavaSecurityCodeSignerAccess(
+ new JavaSecurityCodeSignerAccess() {
+ @Override
+ public void setCRLs(CodeSigner signer, CRL[] crls) {
+ signer.setCRLs(crls);
+ }
+
+ @Override
+ public CRL[] getCRLs(CodeSigner signer) {
+ return signer.getCRLs();
+ }
+ });
+ }
+
}
--- a/jdk/src/share/classes/java/util/jar/JarVerifier.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@
import java.io.*;
import java.util.*;
-import java.util.zip.*;
import java.security.*;
import java.security.cert.CertificateException;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java Thu May 06 13:42:52 2010 +0800
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.misc;
+
+import java.security.CodeSigner;
+import java.security.cert.CRL;
+
+public interface JavaSecurityCodeSignerAccess {
+ void setCRLs(CodeSigner signer, CRL[] crls);
+ CRL[] getCRLs(CodeSigner signer);
+}
--- a/jdk/src/share/classes/sun/misc/SharedSecrets.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java Thu May 06 13:42:52 2010 +0800
@@ -27,8 +27,8 @@
import java.util.jar.JarFile;
import java.io.Console;
-import java.io.File;
import java.io.FileDescriptor;
+import java.security.CodeSigner;
import java.security.ProtectionDomain;
/** A repository of "shared secrets", which are a mechanism for
@@ -49,6 +49,7 @@
private static JavaNioAccess javaNioAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess;
+ private static JavaSecurityCodeSignerAccess javaSecurityCodeSignerAccess;
public static JavaUtilJarAccess javaUtilJarAccess() {
if (javaUtilJarAccess == null) {
@@ -126,4 +127,16 @@
unsafe.ensureClassInitialized(ProtectionDomain.class);
return javaSecurityProtectionDomainAccess;
}
+
+ public static void setJavaSecurityCodeSignerAccess
+ (JavaSecurityCodeSignerAccess jscsa) {
+ javaSecurityCodeSignerAccess = jscsa;
+ }
+
+ public static JavaSecurityCodeSignerAccess
+ getJavaSecurityCodeSignerAccess() {
+ if (javaSecurityCodeSignerAccess == null)
+ unsafe.ensureClassInitialized(CodeSigner.class);
+ return javaSecurityCodeSignerAccess;
+ }
}
--- a/jdk/src/share/classes/sun/security/pkcs/PKCS7.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/pkcs/PKCS7.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@
import java.io.*;
import java.math.BigInteger;
import java.util.*;
-import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509CRL;
@@ -173,20 +172,30 @@
* @param digestAlgorithmIds the message digest algorithm identifiers.
* @param contentInfo the content information.
* @param certificates an array of X.509 certificates.
+ * @param crls an array of CRLs
* @param signerInfos an array of signer information.
*/
public PKCS7(AlgorithmId[] digestAlgorithmIds,
ContentInfo contentInfo,
X509Certificate[] certificates,
+ X509CRL[] crls,
SignerInfo[] signerInfos) {
version = BigInteger.ONE;
this.digestAlgorithmIds = digestAlgorithmIds;
this.contentInfo = contentInfo;
this.certificates = certificates;
+ this.crls = crls;
this.signerInfos = signerInfos;
}
+ public PKCS7(AlgorithmId[] digestAlgorithmIds,
+ ContentInfo contentInfo,
+ X509Certificate[] certificates,
+ SignerInfo[] signerInfos) {
+ this(digestAlgorithmIds, contentInfo, certificates, null, signerInfos);
+ }
+
private void parseNetscapeCertChain(DerValue val)
throws ParsingException, IOException {
DerInputStream dis = new DerInputStream(val.toByteArray());
@@ -312,7 +321,7 @@
ByteArrayInputStream bais = null;
try {
if (certfac == null)
- crls[i] = (X509CRL) new X509CRLImpl(crlVals[i]);
+ crls[i] = new X509CRLImpl(crlVals[i]);
else {
byte[] encoded = crlVals[i].toByteArray();
bais = new ByteArrayInputStream(encoded);
@@ -480,7 +489,30 @@
signedData.putOrderedSetOf((byte)0xA0, implCerts);
}
- // no crls (OPTIONAL field)
+ // CRLs (optional)
+ if (crls != null && crls.length != 0) {
+ // cast to X509CRLImpl[] since X509CRLImpl implements DerEncoder
+ Set<X509CRLImpl> implCRLs = new HashSet<X509CRLImpl>(crls.length);
+ for (X509CRL crl: crls) {
+ if (crl instanceof X509CRLImpl)
+ implCRLs.add((X509CRLImpl) crl);
+ else {
+ try {
+ byte[] encoded = crl.getEncoded();
+ implCRLs.add(new X509CRLImpl(encoded));
+ } catch (CRLException ce) {
+ IOException ie = new IOException(ce.getMessage());
+ ie.initCause(ce);
+ throw ie;
+ }
+ }
+ }
+
+ // Add the CRL set (tagged with [1] IMPLICIT)
+ // to the signed data
+ signedData.putOrderedSetOf((byte)0xA1,
+ implCRLs.toArray(new X509CRLImpl[implCRLs.size()]));
+ }
// signerInfos
signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);
--- a/jdk/src/share/classes/sun/security/tools/JarSigner.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java Thu May 06 13:42:52 2010 +0800
@@ -26,6 +26,7 @@
package sun.security.tools;
import java.io.*;
+import java.security.cert.X509CRL;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;
@@ -35,6 +36,7 @@
import java.text.Collator;
import java.text.MessageFormat;
import java.security.cert.Certificate;
+import java.security.cert.CRL;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.*;
@@ -56,6 +58,7 @@
import sun.security.x509.*;
import sun.security.util.*;
import sun.misc.BASE64Encoder;
+import sun.misc.SharedSecrets;
/**
@@ -114,14 +117,16 @@
static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list
X509Certificate[] certChain; // signer's cert chain (when composing)
+ Set<X509CRL> crls; // signer provided CRLs
PrivateKey privateKey; // private key
KeyStore store; // the keystore specified by -keystore
// or the default keystore, never null
String keystore; // key store file
+ List<String> crlfiles = new ArrayList<String>(); // CRL files to add
boolean nullStream = false; // null keystore input stream (NONE)
boolean token = false; // token-based keystore
- String jarfile; // jar file to sign or verify
+ String jarfile; // jar files to sign or verify
String alias; // alias to sign jar with
List<String> ckaliases = new ArrayList<String>(); // aliases in -verify
char[] storepass; // keystore password
@@ -146,6 +151,7 @@
boolean signManifest = true; // "sign" the whole manifest
boolean externalSF = true; // leave the .SF out of the PKCS7 block
boolean strict = false; // treat warnings as error
+ boolean autoCRL = false; // Automatcially add CRL defined in cert
// read zip entry raw bytes
private ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
@@ -226,6 +232,29 @@
} else {
loadKeyStore(keystore, true);
getAliasInfo(alias);
+ crls = new HashSet<X509CRL>();
+ if (crlfiles.size() > 0 || autoCRL) {
+ CertificateFactory fac =
+ CertificateFactory.getInstance("X509");
+ List<CRL> list = new ArrayList<CRL>();
+ for (String file: crlfiles) {
+ Collection<? extends CRL> tmp = KeyTool.loadCRLs(file);
+ for (CRL crl: tmp) {
+ if (crl instanceof X509CRL) {
+ crls.add((X509CRL)crl);
+ }
+ }
+ }
+ if (autoCRL) {
+ List<CRL> crlsFromCert =
+ KeyTool.readCRLsFromCert(certChain[0]);
+ for (CRL crl: crlsFromCert) {
+ if (crl instanceof X509CRL) {
+ crls.add((X509CRL)crl);
+ }
+ }
+ }
+ }
// load the alternative signing mechanism
if (altSignerClass != null) {
@@ -367,6 +396,13 @@
} else if (collator.compare(flags, "-digestalg") ==0) {
if (++n == args.length) usageNoArg();
digestalg = args[n];
+ } else if (collator.compare(flags, "-crl") ==0) {
+ if ("auto".equals(modifier)) {
+ autoCRL = true;
+ } else {
+ if (++n == args.length) usageNoArg();
+ crlfiles.add(args[n]);
+ }
} else if (collator.compare(flags, "-certs") ==0) {
showcerts = true;
} else if (collator.compare(flags, "-strict") ==0) {
@@ -516,6 +552,9 @@
("[-sigalg <algorithm>] name of signature algorithm"));
System.out.println();
System.out.println(rb.getString
+ ("[-crl[:auto| <file>] include CRL in signed jar"));
+ System.out.println();
+ System.out.println(rb.getString
("[-verify] verify a signed JAR file"));
System.out.println();
System.out.println(rb.getString
@@ -654,6 +693,20 @@
if (showcerts) {
sb.append(si);
sb.append('\n');
+ CRL[] crls = SharedSecrets
+ .getJavaSecurityCodeSignerAccess()
+ .getCRLs(signer);
+ if (crls != null) {
+ for (CRL crl: crls) {
+ if (crl instanceof X509CRLImpl) {
+ sb.append(tab).append("[");
+ sb.append(String.format(
+ rb.getString("with a CRL including %d entries"),
+ ((X509CRLImpl)crl).getRevokedCertificates().size()))
+ .append("]\n");
+ }
+ }
+ }
}
}
} else if (showcerts && !verbose.equals("all")) {
@@ -1233,7 +1286,7 @@
try {
block =
- sf.generateBlock(privateKey, sigalg, certChain,
+ sf.generateBlock(privateKey, sigalg, certChain, crls,
externalSF, tsaUrl, tsaCert, signingMechanism, args,
zipFile);
} catch (SocketTimeoutException e) {
@@ -2197,6 +2250,7 @@
public Block generateBlock(PrivateKey privateKey,
String sigalg,
X509Certificate[] certChain,
+ Set<X509CRL> crls,
boolean externalSF, String tsaUrl,
X509Certificate tsaCert,
ContentSigner signingMechanism,
@@ -2204,7 +2258,7 @@
throws NoSuchAlgorithmException, InvalidKeyException, IOException,
SignatureException, CertificateException
{
- return new Block(this, privateKey, sigalg, certChain, externalSF,
+ return new Block(this, privateKey, sigalg, certChain, crls, externalSF,
tsaUrl, tsaCert, signingMechanism, args, zipFile);
}
@@ -2218,7 +2272,8 @@
* Construct a new signature block.
*/
Block(SignatureFile sfg, PrivateKey privateKey, String sigalg,
- X509Certificate[] certChain, boolean externalSF, String tsaUrl,
+ X509Certificate[] certChain, Set<X509CRL> crls,
+ boolean externalSF, String tsaUrl,
X509Certificate tsaCert, ContentSigner signingMechanism,
String[] args, ZipFile zipFile)
throws NoSuchAlgorithmException, InvalidKeyException, IOException,
@@ -2305,7 +2360,7 @@
// Assemble parameters for the signing mechanism
ContentSignerParameters params =
new JarSignerParameters(args, tsaUri, tsaCert, signature,
- signatureAlgorithm, certChain, content, zipFile);
+ signatureAlgorithm, certChain, crls, content, zipFile);
// Generate the signature block
block = signingMechanism.generateSignedData(
@@ -2346,6 +2401,7 @@
private byte[] signature;
private String signatureAlgorithm;
private X509Certificate[] signerCertificateChain;
+ private Set<X509CRL> crls;
private byte[] content;
private ZipFile source;
@@ -2354,7 +2410,8 @@
*/
JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate,
byte[] signature, String signatureAlgorithm,
- X509Certificate[] signerCertificateChain, byte[] content,
+ X509Certificate[] signerCertificateChain, Set<X509CRL> crls,
+ byte[] content,
ZipFile source) {
if (signature == null || signatureAlgorithm == null ||
@@ -2367,6 +2424,7 @@
this.signature = signature;
this.signatureAlgorithm = signatureAlgorithm;
this.signerCertificateChain = signerCertificateChain;
+ this.crls = crls;
this.content = content;
this.source = source;
}
@@ -2442,4 +2500,13 @@
public ZipFile getSource() {
return source;
}
+
+ @Override
+ public Set<X509CRL> getCRLs() {
+ if (crls == null) {
+ return Collections.emptySet();
+ } else {
+ return Collections.unmodifiableSet(crls);
+ }
+ }
}
--- a/jdk/src/share/classes/sun/security/tools/JarSignerResources.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/tools/JarSignerResources.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,8 @@
"[-digestalg <algorithm>] name of digest algorithm"},
{"[-sigalg <algorithm>] name of signature algorithm",
"[-sigalg <algorithm>] name of signature algorithm"},
+ {"[-crl[:auto| <file>] include CRL in signed jar",
+ "[-crl[:auto| <file>] include CRL in signed jar"},
{"[-verify] verify a signed JAR file",
"[-verify] verify a signed JAR file"},
{"[-verbose[:suboptions]] verbose output when signing/verifying.",
@@ -191,6 +193,7 @@
{"using an alternative signing mechanism",
"using an alternative signing mechanism"},
{"entry was signed on", "entry was signed on {0}"},
+ {"with a CRL including %d entries", "with a CRL including %d entries"},
{"Warning: ", "Warning: "},
{"This jar contains unsigned entries which have not been integrity-checked. ",
"This jar contains unsigned entries which have not been integrity-checked. "},
--- a/jdk/src/share/classes/sun/security/tools/KeyTool.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java Thu May 06 13:42:52 2010 +0800
@@ -25,6 +25,7 @@
package sun.security.tools;
+import sun.misc.SharedSecrets;
import java.io.*;
import java.security.CodeSigner;
import java.security.KeyStore;
@@ -42,6 +43,7 @@
import java.security.Provider;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
+import java.security.cert.CRL;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.text.Collator;
@@ -50,14 +52,20 @@
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.lang.reflect.Constructor;
+import java.math.BigInteger;
+import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
-
+import java.security.cert.CertStore;
+
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import javax.security.auth.x500.X500Principal;
import sun.misc.BASE64Encoder;
import sun.security.util.ObjectIdentifier;
import sun.security.pkcs.PKCS10;
import sun.security.provider.X509Factory;
-import sun.security.util.DerOutputStream;
import sun.security.util.Password;
import sun.security.util.PathList;
import javax.crypto.KeyGenerator;
@@ -72,6 +80,7 @@
import sun.misc.BASE64Decoder;
import sun.security.pkcs.PKCS10Attribute;
import sun.security.pkcs.PKCS9Attribute;
+import sun.security.provider.certpath.ldap.LDAPCertStoreHelper;
import sun.security.util.DerValue;
import sun.security.x509.*;
@@ -147,6 +156,7 @@
private Set<char[]> passwords = new HashSet<char[]> ();
private String startDate = null;
+ private List <String> ids = new ArrayList <String> (); // used in GENCRL
private List <String> v3ext = new ArrayList <String> ();
enum Command {
@@ -180,9 +190,6 @@
STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE,
STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS,
PROVIDERARG, PROVIDERPATH, V, PROTECTED),
- IDENTITYDB("Imports entries from a JDK 1.1.x-style identity database",
- FILEIN, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME,
- PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V),
IMPORTCERT("Imports a certificate or a certificate chain",
NOPROMPT, TRUSTCACERTS, PROTECTED, ALIAS, FILEIN,
KEYPASS, KEYSTORE, STOREPASS, STORETYPE,
@@ -195,10 +202,6 @@
SRCALIAS, DESTALIAS, SRCKEYPASS, DESTKEYPASS,
NOPROMPT, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH,
V),
- KEYCLONE("Clones a key entry",
- ALIAS, DESTALIAS, KEYPASS, NEW, STORETYPE,
- KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS,
- PROVIDERARG, PROVIDERPATH, V),
KEYPASSWD("Changes the key password of an entry",
ALIAS, KEYPASS, NEW, KEYSTORE, STOREPASS,
STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
@@ -211,12 +214,29 @@
RFC, FILEIN, SSLSERVER, JARFILE, V),
PRINTCERTREQ("Prints the content of a certificate request",
FILEIN, V),
+ PRINTCRL("Prints the content of a CRL file",
+ FILEIN, V),
+ STOREPASSWD("Changes the store password of a keystore",
+ NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME,
+ PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V),
+
+ // Undocumented start here, KEYCLONE is used a marker in -help;
+
+ KEYCLONE("Clones a key entry",
+ ALIAS, DESTALIAS, KEYPASS, NEW, STORETYPE,
+ KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS,
+ PROVIDERARG, PROVIDERPATH, V),
SELFCERT("Generates a self-signed certificate",
ALIAS, SIGALG, DNAME, STARTDATE, VALIDITY, KEYPASS,
STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME,
PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V),
- STOREPASSWD("Changes the store password of a keystore",
- NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME,
+ GENCRL("Generates CRL",
+ RFC, FILEOUT, ID,
+ ALIAS, SIGALG, EXT, KEYPASS, KEYSTORE,
+ STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS,
+ PROVIDERARG, PROVIDERPATH, V, PROTECTED),
+ IDENTITYDB("Imports entries from a JDK 1.1.x-style identity database",
+ FILEIN, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME,
PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V);
final String description;
@@ -244,6 +264,7 @@
EXT("ext", "<value>", "X.509 extension"),
FILEOUT("file", "<filename>", "output file name"),
FILEIN("file", "<filename>", "input file name"),
+ ID("id", "<id:reason>", "Serial ID of cert to revoke"),
INFILE("infile", "<filename>", "input file name"),
KEYALG("keyalg", "<keyalg>", "key algorithm name"),
KEYPASS("keypass", "<arg>", "key password"),
@@ -458,6 +479,8 @@
validity = Long.parseLong(args[++i]);
} else if (collator.compare(flags, "-ext") == 0) {
v3ext.add(args[++i]);
+ } else if (collator.compare(flags, "-id") == 0) {
+ ids.add(args[++i]);
} else if (collator.compare(flags, "-file") == 0) {
filename = args[++i];
} else if (collator.compare(flags, "-infile") == 0) {
@@ -720,7 +743,8 @@
command != GENSECKEY &&
command != IDENTITYDB &&
command != IMPORTCERT &&
- command != IMPORTKEYSTORE) {
+ command != IMPORTKEYSTORE &&
+ command != PRINTCRL) {
throw new Exception(rb.getString
("Keystore file does not exist: ") + ksfname);
}
@@ -855,10 +879,12 @@
&& !KeyStoreUtil.isWindowsKeyStore(storetype)
&& isKeyStoreRelated(command)) {
// here we have EXPORTCERT and LIST (info valid until STOREPASSWD)
- System.err.print(rb.getString("Enter keystore password: "));
- System.err.flush();
- storePass = Password.readPassword(System.in);
- passwords.add(storePass);
+ if (command != PRINTCRL) {
+ System.err.print(rb.getString("Enter keystore password: "));
+ System.err.flush();
+ storePass = Password.readPassword(System.in);
+ passwords.add(storePass);
+ }
}
// Now load a nullStream-based keystore,
@@ -895,7 +921,7 @@
// Create a certificate factory
if (command == PRINTCERT || command == IMPORTCERT
- || command == IDENTITYDB) {
+ || command == IDENTITYDB || command == PRINTCRL) {
cf = CertificateFactory.getInstance("X509");
}
@@ -1086,6 +1112,22 @@
ps.close();
}
}
+ } else if (command == GENCRL) {
+ if (alias == null) {
+ alias = keyAlias;
+ }
+ PrintStream ps = null;
+ if (filename != null) {
+ ps = new PrintStream(new FileOutputStream(filename));
+ out = ps;
+ }
+ try {
+ doGenCRL(out);
+ } finally {
+ if (ps != null) {
+ ps.close();
+ }
+ }
} else if (command == PRINTCERTREQ) {
InputStream inStream = System.in;
if (filename != null) {
@@ -1098,6 +1140,8 @@
inStream.close();
}
}
+ } else if (command == PRINTCRL) {
+ doPrintCRL(filename, out);
}
// If we need to save the keystore, do so.
@@ -1152,7 +1196,8 @@
CertificateValidity interval = new CertificateValidity(firstDate,
lastDate);
- PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
+ PrivateKey privateKey =
+ (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
if (sigAlgName == null) {
sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm());
}
@@ -1221,6 +1266,56 @@
}
}
+ private void doGenCRL(PrintStream out)
+ throws Exception {
+ if (ids == null) {
+ throw new Exception("Must provide -id when -gencrl");
+ }
+ Certificate signerCert = keyStore.getCertificate(alias);
+ byte[] encoded = signerCert.getEncoded();
+ X509CertImpl signerCertImpl = new X509CertImpl(encoded);
+ X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get(
+ X509CertImpl.NAME + "." + X509CertImpl.INFO);
+ X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." +
+ CertificateSubjectName.DN_NAME);
+
+ Date firstDate = getStartDate(startDate);
+ Date lastDate = (Date) firstDate.clone();
+ lastDate.setTime(lastDate.getTime() + (long)validity*1000*24*60*60);
+ CertificateValidity interval = new CertificateValidity(firstDate,
+ lastDate);
+
+
+ PrivateKey privateKey =
+ (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
+ if (sigAlgName == null) {
+ sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm());
+ }
+
+ X509CRLEntry[] badCerts = new X509CRLEntry[ids.size()];
+ for (int i=0; i<ids.size(); i++) {
+ String id = ids.get(i);
+ int d = id.indexOf(':');
+ if (d >= 0) {
+ CRLExtensions ext = new CRLExtensions();
+ ext.set("Reason", new CRLReasonCodeExtension(Integer.parseInt(id.substring(d+1))));
+ badCerts[i] = new X509CRLEntryImpl(new BigInteger(id.substring(0, d)),
+ firstDate, ext);
+ } else {
+ badCerts[i] = new X509CRLEntryImpl(new BigInteger(ids.get(i)), firstDate);
+ }
+ }
+ X509CRLImpl crl = new X509CRLImpl(owner, firstDate, lastDate, badCerts);
+ crl.sign(privateKey, sigAlgName);
+ if (rfc) {
+ out.println("-----BEGIN X509 CRL-----");
+ new BASE64Encoder().encodeBuffer(crl.getEncodedInternal(), out);
+ out.println("-----END X509 CRL-----");
+ } else {
+ out.write(crl.getEncodedInternal());
+ }
+ }
+
/**
* Creates a PKCS#10 cert signing request, corresponding to the
* keys (and name) associated with a given alias.
@@ -1925,6 +2020,177 @@
}
}
+ private static <T> Iterable<T> e2i(final Enumeration<T> e) {
+ return new Iterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return new Iterator<T>() {
+ @Override
+ public boolean hasNext() {
+ return e.hasMoreElements();
+ }
+ @Override
+ public T next() {
+ return e.nextElement();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Loads CRLs from a source. This method is also called in JarSigner.
+ * @param src the source, which means System.in if null, or a URI,
+ * or a bare file path name
+ */
+ public static Collection<? extends CRL> loadCRLs(String src) throws Exception {
+ InputStream in = null;
+ URI uri = null;
+ if (src == null) {
+ in = System.in;
+ } else {
+ try {
+ uri = new URI(src);
+ if (uri.getScheme().equals("ldap")) {
+ // No input stream for LDAP
+ } else {
+ in = uri.toURL().openStream();
+ }
+ } catch (Exception e) {
+ try {
+ in = new FileInputStream(src);
+ } catch (Exception e2) {
+ if (uri == null || uri.getScheme() == null) {
+ throw e2; // More likely a bare file path
+ } else {
+ throw e; // More likely a protocol or network problem
+ }
+ }
+ }
+ }
+ if (in != null) {
+ try {
+ // Read the full stream before feeding to X509Factory,
+ // otherwise, keytool -gencrl | keytool -printcrl
+ // might not work properly, since -gencrl is slow
+ // and there's no data in the pipe at the beginning.
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ byte[] b = new byte[4096];
+ while (true) {
+ int len = in.read(b);
+ if (len < 0) break;
+ bout.write(b, 0, len);
+ }
+ return CertificateFactory.getInstance("X509").generateCRLs(
+ new ByteArrayInputStream(bout.toByteArray()));
+ } finally {
+ if (in != System.in) {
+ in.close();
+ }
+ }
+ } else { // must be LDAP, and uri is not null
+ String path = uri.getPath();
+ if (path.charAt(0) == '/') path = path.substring(1);
+ LDAPCertStoreHelper h = new LDAPCertStoreHelper();
+ CertStore s = h.getCertStore(uri);
+ X509CRLSelector sel =
+ h.wrap(new X509CRLSelector(), null, path);
+ return s.getCRLs(sel);
+ }
+ }
+
+ /**
+ * Returns CRLs described in a X509Certificate's CRLDistributionPoints
+ * Extension. Only those containing a general name of type URI are read.
+ */
+ public static List<CRL> readCRLsFromCert(X509Certificate cert)
+ throws Exception {
+ List<CRL> crls = new ArrayList<CRL>();
+ CRLDistributionPointsExtension ext =
+ X509CertImpl.toImpl(cert).getCRLDistributionPointsExtension();
+ if (ext == null) return crls;
+ for (DistributionPoint o: (List<DistributionPoint>)
+ ext.get(CRLDistributionPointsExtension.POINTS)) {
+ GeneralNames names = o.getFullName();
+ if (names != null) {
+ for (GeneralName name: names.names()) {
+ if (name.getType() == GeneralNameInterface.NAME_URI) {
+ URIName uriName = (URIName)name.getName();
+ for (CRL crl: KeyTool.loadCRLs(uriName.getName())) {
+ if (crl instanceof X509CRL) {
+ crls.add((X509CRL)crl);
+ }
+ }
+ break; // Different name should point to same CRL
+ }
+ }
+ }
+ }
+ return crls;
+ }
+
+ private static String verifyCRL(KeyStore ks, CRL crl)
+ throws Exception {
+ X509CRLImpl xcrl = (X509CRLImpl)crl;
+ X500Principal issuer = xcrl.getIssuerX500Principal();
+ for (String s: e2i(ks.aliases())) {
+ Certificate cert = ks.getCertificate(s);
+ if (cert instanceof X509Certificate) {
+ X509Certificate xcert = (X509Certificate)cert;
+ if (xcert.getSubjectX500Principal().equals(issuer)) {
+ try {
+ ((X509CRLImpl)crl).verify(cert.getPublicKey());
+ return s;
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private void doPrintCRL(String src, PrintStream out)
+ throws Exception {
+ for (CRL crl: loadCRLs(src)) {
+ printCRL(crl, out);
+ String issuer = null;
+ if (caks != null) {
+ issuer = verifyCRL(caks, crl);
+ if (issuer != null) {
+ System.out.println("Verified by " + issuer + " in cacerts");
+ }
+ }
+ if (issuer == null && keyStore != null) {
+ issuer = verifyCRL(keyStore, crl);
+ if (issuer != null) {
+ System.out.println("Verified by " + issuer + " in keystore");
+ }
+ }
+ if (issuer == null) {
+ out.println(rb.getString
+ ("*******************************************"));
+ out.println("WARNING: not verified. Make sure -keystore and -alias are correct.");
+ out.println(rb.getString
+ ("*******************************************\n\n"));
+ }
+ }
+ }
+
+ private void printCRL(CRL crl, PrintStream out)
+ throws Exception {
+ if (rfc) {
+ X509CRL xcrl = (X509CRL)crl;
+ out.println("-----BEGIN X509 CRL-----");
+ new BASE64Encoder().encodeBuffer(xcrl.getEncoded(), out);
+ out.println("-----END X509 CRL-----");
+ } else {
+ out.println(crl.toString());
+ }
+ }
+
private void doPrintCertReq(InputStream in, PrintStream out)
throws Exception {
@@ -2063,6 +2329,16 @@
out.println();
}
}
+ CRL[] crls = SharedSecrets
+ .getJavaSecurityCodeSignerAccess()
+ .getCRLs(signer);
+ if (crls != null) {
+ out.println(rb.getString("CRLs:"));
+ out.println();
+ for (CRL crl: crls) {
+ printCRL(crl, out);
+ }
+ }
}
}
}
@@ -3330,15 +3606,22 @@
/**
* Match a command (may be abbreviated) with a command set.
* @param s the command provided
- * @param list the legal command set
+ * @param list the legal command set. If there is a null, commands after it
+ * are regarded experimental, which means they are supported but their
+ * existence should not be revealed to user.
* @return the position of a single match, or -1 if none matched
* @throws Exception if s is ambiguous
*/
private static int oneOf(String s, String... list) throws Exception {
int[] match = new int[list.length];
int nmatch = 0;
+ int experiment = Integer.MAX_VALUE;
for (int i = 0; i<list.length; i++) {
String one = list[i];
+ if (one == null) {
+ experiment = i;
+ continue;
+ }
if (one.toLowerCase(Locale.ENGLISH)
.startsWith(s.toLowerCase(Locale.ENGLISH))) {
match[nmatch++] = i;
@@ -3360,17 +3643,27 @@
}
}
}
- if (nmatch == 0) return -1;
- if (nmatch == 1) return match[0];
- StringBuffer sb = new StringBuffer();
- MessageFormat form = new MessageFormat(rb.getString
- ("command {0} is ambiguous:"));
- Object[] source = {s};
- sb.append(form.format(source) +"\n ");
- for (int i=0; i<nmatch; i++) {
- sb.append(" " + list[match[i]]);
+ if (nmatch == 0) {
+ return -1;
+ } else if (nmatch == 1) {
+ return match[0];
+ } else {
+ // If multiple matches is in experimental commands, ignore them
+ if (match[1] > experiment) {
+ return match[0];
+ }
+ StringBuffer sb = new StringBuffer();
+ MessageFormat form = new MessageFormat(rb.getString
+ ("command {0} is ambiguous:"));
+ Object[] source = {s};
+ sb.append(form.format(source));
+ sb.append("\n ");
+ for (int i=0; i<nmatch && match[i]<experiment; i++) {
+ sb.append(' ');
+ sb.append(list[match[i]]);
+ }
+ throw new Exception(sb.toString());
}
- throw new Exception(sb.toString());
}
/**
@@ -3405,6 +3698,8 @@
"IssuerAlternativeName",
"SubjectInfoAccess",
"AuthorityInfoAccess",
+ null,
+ "CRLDistributionPoints",
};
private ObjectIdentifier findOidForExtName(String type)
@@ -3417,6 +3712,7 @@
case 4: return PKIXExtensions.IssuerAlternativeName_Id;
case 5: return PKIXExtensions.SubjectInfoAccess_Id;
case 6: return PKIXExtensions.AuthInfoAccess_Id;
+ case 8: return PKIXExtensions.CRLDistributionPoints_Id;
default: return new ObjectIdentifier(type);
}
}
@@ -3712,6 +4008,28 @@
("Illegal value: ") + extstr);
}
break;
+ case 8: // CRL, experimental, only support 1 distributionpoint
+ if(value != null) {
+ String[] ps = value.split(",");
+ GeneralNames gnames = new GeneralNames();
+ for(String item: ps) {
+ colonpos = item.indexOf(':');
+ if (colonpos < 0) {
+ throw new Exception("Illegal item " + item + " in " + extstr);
+ }
+ String t = item.substring(0, colonpos);
+ String v = item.substring(colonpos+1);
+ gnames.add(createGeneralName(t, v));
+ }
+ ext.set(CRLDistributionPointsExtension.NAME,
+ new CRLDistributionPointsExtension(
+ isCritical, Collections.singletonList(
+ new DistributionPoint(gnames, null, null))));
+ } else {
+ throw new Exception(rb.getString
+ ("Illegal value: ") + extstr);
+ }
+ break;
case -1:
ObjectIdentifier oid = new ObjectIdentifier(name);
byte[] data = null;
@@ -3748,6 +4066,9 @@
new DerValue(DerValue.tag_OctetString, data)
.toByteArray()));
break;
+ default:
+ throw new Exception(rb.getString(
+ "Unknown extension type: ") + extstr);
}
}
// always non-critical
@@ -3810,11 +4131,8 @@
System.err.println(rb.getString("Commands:"));
System.err.println();
for (Command c: Command.values()) {
- if (c != IDENTITYDB
- && c != KEYCLONE
- && c != SELFCERT) { // Deprecated commands
- System.err.printf(" %-20s%s\n", c, rb.getString(c.description));
- }
+ if (c == KEYCLONE) break;
+ System.err.printf(" %-20s%s\n", c, rb.getString(c.description));
}
System.err.println();
System.err.println(rb.getString(
--- a/jdk/src/share/classes/sun/security/tools/TimestampedSigner.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/tools/TimestampedSigner.java Thu May 06 13:42:52 2010 +0800
@@ -38,6 +38,7 @@
import java.util.List;
import com.sun.jarsigner.*;
+import java.security.cert.X509CRL;
import java.util.Arrays;
import sun.security.pkcs.*;
import sun.security.timestamp.*;
@@ -239,7 +240,7 @@
// Create the PKCS #7 signed data message
PKCS7 p7 =
new PKCS7(algorithms, contentInfo, signerCertificateChain,
- signerInfos);
+ parameters.getCRLs().toArray(new X509CRL[parameters.getCRLs().size()]), signerInfos);
ByteArrayOutputStream p7out = new ByteArrayOutputStream();
p7.encodeSignedData(p7out);
--- a/jdk/src/share/classes/sun/security/util/Resources.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/util/Resources.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -71,6 +71,7 @@
"Generates a secret key"}, //-genseckey
{"Generates certificate from a certificate request",
"Generates certificate from a certificate request"}, //-gencert
+ {"Generates CRL", "Generates CRL"}, //-gencrl
{"Imports entries from a JDK 1.1.x-style identity database",
"Imports entries from a JDK 1.1.x-style identity database"}, //-identitydb
{"Imports a certificate or a certificate chain",
@@ -87,6 +88,8 @@
"Prints the content of a certificate"}, //-printcert
{"Prints the content of a certificate request",
"Prints the content of a certificate request"}, //-printcertreq
+ {"Prints the content of a CRL file",
+ "Prints the content of a CRL file"}, //-printcrl
{"Generates a self-signed certificate",
"Generates a self-signed certificate"}, //-selfcert
{"Changes the store password of a keystore",
@@ -176,6 +179,8 @@
"verbose output"}, //-v
{"validity number of days",
"validity number of days"}, //-validity
+ {"Serial ID of cert to revoke",
+ "Serial ID of cert to revoke"}, //-id
// keytool: Running part
{"keytool error: ", "keytool error: "},
{"Illegal option: ", "Illegal option: "},
@@ -375,6 +380,7 @@
{"Signer #%d:", "Signer #%d:"},
{"Timestamp:", "Timestamp:"},
{"Signature:", "Signature:"},
+ {"CRLs:", "CRLs:"},
{"Certificate owner: ", "Certificate owner: "},
{"Not a signed jar file", "Not a signed jar file"},
{"No certificate from the SSL server",
@@ -433,6 +439,7 @@
{"This extension cannot be marked as critical. ",
"This extension cannot be marked as critical. "},
{"Odd number of hex digits found: ", "Odd number of hex digits found: "},
+ {"Unknown extension type: ", "Unknown extension type: "},
{"command {0} is ambiguous:", "command {0} is ambiguous:"},
// policytool
--- a/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
package sun.security.util;
-import java.security.CodeSigner;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
@@ -34,11 +33,11 @@
import java.io.*;
import java.util.*;
import java.util.jar.*;
-import java.io.ByteArrayOutputStream;
import sun.security.pkcs.*;
import sun.security.timestamp.TimestampToken;
import sun.misc.BASE64Decoder;
+import sun.misc.SharedSecrets;
import sun.security.jca.Providers;
@@ -479,7 +478,12 @@
signers = new ArrayList<CodeSigner>();
}
// Append the new code signer
- signers.add(new CodeSigner(certChain, getTimestamp(info)));
+ CodeSigner signer = new CodeSigner(certChain, getTimestamp(info));
+ if (block.getCRLs() != null) {
+ SharedSecrets.getJavaSecurityCodeSignerAccess().setCRLs(
+ signer, block.getCRLs());
+ }
+ signers.add(signer);
if (debug != null) {
debug.println("Signature Block Certificate: " +
--- a/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java Thu May 06 11:26:16 2010 +0800
+++ b/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java Thu May 06 13:42:52 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -89,7 +89,7 @@
* @author Hemma Prafullchandra
* @see X509CRL
*/
-public class X509CRLImpl extends X509CRL {
+public class X509CRLImpl extends X509CRL implements DerEncoder {
// CRL data, and its envelope
private byte[] signedCRL = null; // DER encoded crl
@@ -1189,6 +1189,13 @@
}
}
+ @Override
+ public void derEncode(OutputStream out) throws IOException {
+ if (signedCRL == null)
+ throw new IOException("Null CRL to encode");
+ out.write(signedCRL.clone());
+ }
+
/**
* Immutable X.509 Certificate Issuer DN and serial number pair
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/jarsigner/crl.sh Thu May 06 13:42:52 2010 +0800
@@ -0,0 +1,91 @@
+#
+# Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 6890876
+# @summary jarsigner can add CRL info into signed jar
+#
+
+if [ "${TESTJAVA}" = "" ] ; then
+ JAVAC_CMD=`which javac`
+ TESTJAVA=`dirname $JAVAC_CMD`/..
+fi
+
+# set platform-dependent variables
+# PF: platform name, say, solaris-sparc
+
+PF=""
+
+OS=`uname -s`
+case "$OS" in
+ Windows* )
+ FS="\\"
+ ;;
+ * )
+ FS="/"
+ ;;
+esac
+
+KS=crl.jks
+JFILE=crl.jar
+
+KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS"
+JAR=$TESTJAVA${FS}bin${FS}jar
+JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner
+
+rm $KS $JFILE
+
+# Generates some crl files, each containing two entries
+
+$KT -alias a -dname CN=a -keyalg rsa -genkey -validity 300
+$KT -alias a -gencrl -id 1:1 -id 2:2 -file crl1
+$KT -alias a -gencrl -id 3:3 -id 4:4 -file crl2
+$KT -alias b -dname CN=b -keyalg rsa -genkey -validity 300
+$KT -alias b -gencrl -id 5:1 -id 6:2 -file crl3
+
+$KT -alias c -dname CN=c -keyalg rsa -genkey -validity 300 \
+ -ext crl=uri:file://`pwd`/crl1
+
+echo A > A
+
+# Test -crl:auto, cRLDistributionPoints is a local file
+
+$JAR cvf $JFILE A
+$JARSIGNER -keystore $KS -storepass changeit $JFILE c \
+ -crl:auto || exit 1
+$JARSIGNER -keystore $KS -verify -debug -strict $JFILE || exit 6
+$KT -printcert -jarfile $JFILE | grep CRLs || exit 7
+
+# Test -crl <file>
+
+$JAR cvf $JFILE A
+$JARSIGNER -keystore $KS -storepass changeit $JFILE a \
+ -crl crl1 -crl crl2 || exit 1
+$JARSIGNER -keystore $KS -storepass changeit $JFILE b \
+ -crl crl3 -crl crl2 || exit 1
+$JARSIGNER -keystore $KS -verify -debug -strict $JFILE || exit 3
+$KT -printcert -jarfile $JFILE | grep CRLs || exit 4
+CRLCOUNT=`$KT -printcert -jarfile $JFILE | grep SerialNumber | wc -l`
+if [ $CRLCOUNT != 8 ]; then exit 5; fi
+
+exit 0