diff --git a/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java b/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java
index 5ef30e031fad9a2259569e22979c0687b08ae152..942d29070da54ff931ac910d64e7865d81a99ec3 100644
--- a/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java
+++ b/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java
@@ -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;
/**
@@ -80,6 +82,13 @@ public interface ContentSignerParameters {
*/
public X509Certificate[] getSignerCertificateChain();
+ /**
+ * Retrieves the signer's X.509 CRLs.
+ *
+ * @return An unmodifiable set of X.509 CRLs (never null
)
+ */
+ public Set getCRLs();
+
/**
* Retrieves the content that was signed.
* The content is the JAR file's signature file.
diff --git a/src/share/classes/java/security/CodeSigner.java b/src/share/classes/java/security/CodeSigner.java
index a5ef70b7dceae4ef2e0f746cffd2df024660c67a..b7abdf06fb8748c856329f59b2f7fb6fdcdc9346 100644
--- a/src/share/classes/java/security/CodeSigner.java
+++ b/src/share/classes/java/security/CodeSigner.java
@@ -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 @@ public final class CodeSigner implements Serializable {
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();
+ }
+ });
+ }
+
}
diff --git a/src/share/classes/java/util/jar/JarVerifier.java b/src/share/classes/java/util/jar/JarVerifier.java
index a4ceaa790fd8adcedbd6fc1d1360c6223ac24109..1c88d226e284541bd9f8e12ebfd3ac515184cf00 100644
--- a/src/share/classes/java/util/jar/JarVerifier.java
+++ b/src/share/classes/java/util/jar/JarVerifier.java
@@ -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 @@ package java.util.jar;
import java.io.*;
import java.util.*;
-import java.util.zip.*;
import java.security.*;
import java.security.cert.CertificateException;
diff --git a/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java b/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..4543b00da5f5139da92a063cce4b9780f416af6c
--- /dev/null
+++ b/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java
@@ -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);
+}
diff --git a/src/share/classes/sun/misc/SharedSecrets.java b/src/share/classes/sun/misc/SharedSecrets.java
index c9f50728860792fe55e9acfedbc446a158af036e..76ae42f673a08fe2d2163dc0b745522d367c338c 100644
--- a/src/share/classes/sun/misc/SharedSecrets.java
+++ b/src/share/classes/sun/misc/SharedSecrets.java
@@ -27,8 +27,8 @@ package sun.misc;
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 @@ public class SharedSecrets {
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 @@ public class SharedSecrets {
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;
+ }
}
diff --git a/src/share/classes/sun/security/pkcs/PKCS7.java b/src/share/classes/sun/security/pkcs/PKCS7.java
index 1a1bcf41cf22db8567738e056e7faf934d46c5c0..d3342fdb2b546aa4191d90b3f5f53758433f0a42 100644
--- a/src/share/classes/sun/security/pkcs/PKCS7.java
+++ b/src/share/classes/sun/security/pkcs/PKCS7.java
@@ -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 @@ package sun.security.pkcs;
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 @@ public class PKCS7 {
* @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 @@ public class PKCS7 {
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 @@ public class PKCS7 {
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 implCRLs = new HashSet(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);
diff --git a/src/share/classes/sun/security/tools/JarSigner.java b/src/share/classes/sun/security/tools/JarSigner.java
index 0f7324d7c194fca1b854017ed6d96fd5766780a9..f45a2c931571625e5a67905ff959ff5546bd1ef5 100644
--- a/src/share/classes/sun/security/tools/JarSigner.java
+++ b/src/share/classes/sun/security/tools/JarSigner.java
@@ -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.net.URISyntaxException;
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 java.util.Map.Entry;
import sun.security.x509.*;
import sun.security.util.*;
import sun.misc.BASE64Encoder;
+import sun.misc.SharedSecrets;
/**
@@ -114,14 +117,16 @@ public class JarSigner {
static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list
X509Certificate[] certChain; // signer's cert chain (when composing)
+ Set 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 crlfiles = new ArrayList(); // 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 ckaliases = new ArrayList(); // aliases in -verify
char[] storepass; // keystore password
@@ -146,6 +151,7 @@ public class JarSigner {
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 @@ public class JarSigner {
} else {
loadKeyStore(keystore, true);
getAliasInfo(alias);
+ crls = new HashSet();
+ if (crlfiles.size() > 0 || autoCRL) {
+ CertificateFactory fac =
+ CertificateFactory.getInstance("X509");
+ List list = new ArrayList();
+ 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 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 @@ public class JarSigner {
} 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) {
@@ -515,6 +551,9 @@ public class JarSigner {
System.out.println(rb.getString
("[-sigalg ] name of signature algorithm"));
System.out.println();
+ System.out.println(rb.getString
+ ("[-crl[:auto| ] include CRL in signed jar"));
+ System.out.println();
System.out.println(rb.getString
("[-verify] verify a signed JAR file"));
System.out.println();
@@ -654,6 +693,20 @@ public class JarSigner {
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 @@ public class JarSigner {
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 @@ class SignatureFile {
public Block generateBlock(PrivateKey privateKey,
String sigalg,
X509Certificate[] certChain,
+ Set crls,
boolean externalSF, String tsaUrl,
X509Certificate tsaCert,
ContentSigner signingMechanism,
@@ -2204,7 +2258,7 @@ class SignatureFile {
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 @@ class SignatureFile {
* Construct a new signature block.
*/
Block(SignatureFile sfg, PrivateKey privateKey, String sigalg,
- X509Certificate[] certChain, boolean externalSF, String tsaUrl,
+ X509Certificate[] certChain, Set crls,
+ boolean externalSF, String tsaUrl,
X509Certificate tsaCert, ContentSigner signingMechanism,
String[] args, ZipFile zipFile)
throws NoSuchAlgorithmException, InvalidKeyException, IOException,
@@ -2305,7 +2360,7 @@ class SignatureFile {
// 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 @@ class JarSignerParameters implements ContentSignerParameters {
private byte[] signature;
private String signatureAlgorithm;
private X509Certificate[] signerCertificateChain;
+ private Set crls;
private byte[] content;
private ZipFile source;
@@ -2354,7 +2410,8 @@ class JarSignerParameters implements ContentSignerParameters {
*/
JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate,
byte[] signature, String signatureAlgorithm,
- X509Certificate[] signerCertificateChain, byte[] content,
+ X509Certificate[] signerCertificateChain, Set crls,
+ byte[] content,
ZipFile source) {
if (signature == null || signatureAlgorithm == null ||
@@ -2367,6 +2424,7 @@ class JarSignerParameters implements ContentSignerParameters {
this.signature = signature;
this.signatureAlgorithm = signatureAlgorithm;
this.signerCertificateChain = signerCertificateChain;
+ this.crls = crls;
this.content = content;
this.source = source;
}
@@ -2442,4 +2500,13 @@ class JarSignerParameters implements ContentSignerParameters {
public ZipFile getSource() {
return source;
}
+
+ @Override
+ public Set getCRLs() {
+ if (crls == null) {
+ return Collections.emptySet();
+ } else {
+ return Collections.unmodifiableSet(crls);
+ }
+ }
}
diff --git a/src/share/classes/sun/security/tools/JarSignerResources.java b/src/share/classes/sun/security/tools/JarSignerResources.java
index 7e259e8e8fec3731652a223307730197a9fc6c12..16cc6863b432e325f103c66c7a83381a8ca12f11 100644
--- a/src/share/classes/sun/security/tools/JarSignerResources.java
+++ b/src/share/classes/sun/security/tools/JarSignerResources.java
@@ -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 @@ public class JarSignerResources extends java.util.ListResourceBundle {
"[-digestalg ] name of digest algorithm"},
{"[-sigalg ] name of signature algorithm",
"[-sigalg ] name of signature algorithm"},
+ {"[-crl[:auto| ] include CRL in signed jar",
+ "[-crl[:auto| ] 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 @@ public class JarSignerResources extends java.util.ListResourceBundle {
{"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. "},
diff --git a/src/share/classes/sun/security/tools/KeyTool.java b/src/share/classes/sun/security/tools/KeyTool.java
index 2539d43e14b5433b1851d6547dfbbbbd968f8df4..b799bfaa7fca3e6ce694ed283ad5456ee1106aab 100644
--- a/src/share/classes/sun/security/tools/KeyTool.java
+++ b/src/share/classes/sun/security/tools/KeyTool.java
@@ -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.Principal;
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.*;
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 javax.net.ssl.X509TrustManager;
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 @@ public final class KeyTool {
private Set passwords = new HashSet ();
private String startDate = null;
+ private List ids = new ArrayList (); // used in GENCRL
private List v3ext = new ArrayList ();
enum Command {
@@ -180,9 +190,6 @@ public final class KeyTool {
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 @@ public final class KeyTool {
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 @@ public final class KeyTool {
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 @@ public final class KeyTool {
EXT("ext", "", "X.509 extension"),
FILEOUT("file", "", "output file name"),
FILEIN("file", "", "input file name"),
+ ID("id", "", "Serial ID of cert to revoke"),
INFILE("infile", "", "input file name"),
KEYALG("keyalg", "", "key algorithm name"),
KEYPASS("keypass", "", "key password"),
@@ -458,6 +479,8 @@ public final class KeyTool {
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 @@ public final class KeyTool {
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 @@ public final class KeyTool {
&& !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 @@ public final class KeyTool {
// Create a certificate factory
if (command == PRINTCERT || command == IMPORTCERT
- || command == IDENTITYDB) {
+ || command == IDENTITYDB || command == PRINTCRL) {
cf = CertificateFactory.getInstance("X509");
}
@@ -1086,6 +1112,22 @@ public final class KeyTool {
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 @@ public final class KeyTool {
inStream.close();
}
}
+ } else if (command == PRINTCRL) {
+ doPrintCRL(filename, out);
}
// If we need to save the keystore, do so.
@@ -1152,7 +1196,8 @@ public final class KeyTool {
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 @@ public final class KeyTool {
}
}
+ 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= 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 @@ public final class KeyTool {
}
}
+ private static Iterable e2i(final Enumeration e) {
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ @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 readCRLsFromCert(X509Certificate cert)
+ throws Exception {
+ List crls = new ArrayList();
+ CRLDistributionPointsExtension ext =
+ X509CertImpl.toImpl(cert).getCRLDistributionPointsExtension();
+ if (ext == null) return crls;
+ for (DistributionPoint o: (List)
+ 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 @@ public final class KeyTool {
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 @@ public final class KeyTool {
/**
* 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 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();
}
// 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: " +
diff --git a/src/share/classes/sun/security/x509/X509CRLImpl.java b/src/share/classes/sun/security/x509/X509CRLImpl.java
index b1157799663930047d6a976931d1d7d19a6a61c5..f5d159891d9faa512a72309d5e891ee28288494f 100644
--- a/src/share/classes/sun/security/x509/X509CRLImpl.java
+++ b/src/share/classes/sun/security/x509/X509CRLImpl.java
@@ -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 @@ import sun.misc.HexDumpEncoder;
* @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 @@ public class X509CRLImpl extends X509CRL {
}
}
+ @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
*/
diff --git a/test/sun/security/tools/jarsigner/crl.sh b/test/sun/security/tools/jarsigner/crl.sh
new file mode 100644
index 0000000000000000000000000000000000000000..73d0c4eae57c2a2124a96ed1ac0070536773af3a
--- /dev/null
+++ b/test/sun/security/tools/jarsigner/crl.sh
@@ -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
+
+$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