6890876: jarsigner can add CRL info into signed jar

Reviewed-by: mullan
This commit is contained in:
Weijun Wang 2010-05-06 13:42:52 +08:00
parent a94d06f6b7
commit 7c6813eb7a
14 changed files with 683 additions and 57 deletions

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,9 @@
package com.sun.jarsigner; package com.sun.jarsigner;
import java.net.URI; import java.net.URI;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Set;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
/** /**
@ -80,6 +82,13 @@ public interface ContentSignerParameters {
*/ */
public X509Certificate[] getSignerCertificateChain(); 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. * Retrieves the content that was signed.
* The content is the JAR file's signature file. * The content is the JAR file's signature file.

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,10 @@
package java.security; package java.security;
import java.io.Serializable; import java.io.Serializable;
import java.security.cert.CRL;
import java.security.cert.CertPath; import java.security.cert.CertPath;
import sun.misc.JavaSecurityCodeSignerAccess;
import sun.misc.SharedSecrets;
/** /**
* This class encapsulates information about a code signer. * This class encapsulates information about a code signer.
@ -163,4 +166,43 @@ public final class CodeSigner implements Serializable {
sb.append(")"); sb.append(")");
return sb.toString(); 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();
}
});
}
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.io.*;
import java.util.*; import java.util.*;
import java.util.zip.*;
import java.security.*; import java.security.*;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;

View File

@ -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);
}

View File

@ -27,8 +27,8 @@ package sun.misc;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.io.Console; import java.io.Console;
import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.security.CodeSigner;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
/** A repository of "shared secrets", which are a mechanism for /** A repository of "shared secrets", which are a mechanism for
@ -49,6 +49,7 @@ public class SharedSecrets {
private static JavaNioAccess javaNioAccess; private static JavaNioAccess javaNioAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess; private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess;
private static JavaSecurityCodeSignerAccess javaSecurityCodeSignerAccess;
public static JavaUtilJarAccess javaUtilJarAccess() { public static JavaUtilJarAccess javaUtilJarAccess() {
if (javaUtilJarAccess == null) { if (javaUtilJarAccess == null) {
@ -126,4 +127,16 @@ public class SharedSecrets {
unsafe.ensureClassInitialized(ProtectionDomain.class); unsafe.ensureClassInitialized(ProtectionDomain.class);
return javaSecurityProtectionDomainAccess; return javaSecurityProtectionDomainAccess;
} }
public static void setJavaSecurityCodeSignerAccess
(JavaSecurityCodeSignerAccess jscsa) {
javaSecurityCodeSignerAccess = jscsa;
}
public static JavaSecurityCodeSignerAccess
getJavaSecurityCodeSignerAccess() {
if (javaSecurityCodeSignerAccess == null)
unsafe.ensureClassInitialized(CodeSigner.class);
return javaSecurityCodeSignerAccess;
}
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.io.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.*; import java.util.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509CRL; import java.security.cert.X509CRL;
@ -173,20 +172,30 @@ public class PKCS7 {
* @param digestAlgorithmIds the message digest algorithm identifiers. * @param digestAlgorithmIds the message digest algorithm identifiers.
* @param contentInfo the content information. * @param contentInfo the content information.
* @param certificates an array of X.509 certificates. * @param certificates an array of X.509 certificates.
* @param crls an array of CRLs
* @param signerInfos an array of signer information. * @param signerInfos an array of signer information.
*/ */
public PKCS7(AlgorithmId[] digestAlgorithmIds, public PKCS7(AlgorithmId[] digestAlgorithmIds,
ContentInfo contentInfo, ContentInfo contentInfo,
X509Certificate[] certificates, X509Certificate[] certificates,
X509CRL[] crls,
SignerInfo[] signerInfos) { SignerInfo[] signerInfos) {
version = BigInteger.ONE; version = BigInteger.ONE;
this.digestAlgorithmIds = digestAlgorithmIds; this.digestAlgorithmIds = digestAlgorithmIds;
this.contentInfo = contentInfo; this.contentInfo = contentInfo;
this.certificates = certificates; this.certificates = certificates;
this.crls = crls;
this.signerInfos = signerInfos; this.signerInfos = signerInfos;
} }
public PKCS7(AlgorithmId[] digestAlgorithmIds,
ContentInfo contentInfo,
X509Certificate[] certificates,
SignerInfo[] signerInfos) {
this(digestAlgorithmIds, contentInfo, certificates, null, signerInfos);
}
private void parseNetscapeCertChain(DerValue val) private void parseNetscapeCertChain(DerValue val)
throws ParsingException, IOException { throws ParsingException, IOException {
DerInputStream dis = new DerInputStream(val.toByteArray()); DerInputStream dis = new DerInputStream(val.toByteArray());
@ -312,7 +321,7 @@ public class PKCS7 {
ByteArrayInputStream bais = null; ByteArrayInputStream bais = null;
try { try {
if (certfac == null) if (certfac == null)
crls[i] = (X509CRL) new X509CRLImpl(crlVals[i]); crls[i] = new X509CRLImpl(crlVals[i]);
else { else {
byte[] encoded = crlVals[i].toByteArray(); byte[] encoded = crlVals[i].toByteArray();
bais = new ByteArrayInputStream(encoded); bais = new ByteArrayInputStream(encoded);
@ -480,7 +489,30 @@ public class PKCS7 {
signedData.putOrderedSetOf((byte)0xA0, implCerts); 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 // signerInfos
signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos); signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);

View File

@ -26,6 +26,7 @@
package sun.security.tools; package sun.security.tools;
import java.io.*; import java.io.*;
import java.security.cert.X509CRL;
import java.util.*; import java.util.*;
import java.util.zip.*; import java.util.zip.*;
import java.util.jar.*; import java.util.jar.*;
@ -35,6 +36,7 @@ import java.net.URISyntaxException;
import java.text.Collator; import java.text.Collator;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CRL;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.*; import java.security.*;
@ -56,6 +58,7 @@ import java.util.Map.Entry;
import sun.security.x509.*; import sun.security.x509.*;
import sun.security.util.*; import sun.security.util.*;
import sun.misc.BASE64Encoder; 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 static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list
X509Certificate[] certChain; // signer's cert chain (when composing) X509Certificate[] certChain; // signer's cert chain (when composing)
Set<X509CRL> crls; // signer provided CRLs
PrivateKey privateKey; // private key PrivateKey privateKey; // private key
KeyStore store; // the keystore specified by -keystore KeyStore store; // the keystore specified by -keystore
// or the default keystore, never null // or the default keystore, never null
String keystore; // key store file String keystore; // key store file
List<String> crlfiles = new ArrayList<String>(); // CRL files to add
boolean nullStream = false; // null keystore input stream (NONE) boolean nullStream = false; // null keystore input stream (NONE)
boolean token = false; // token-based keystore 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 String alias; // alias to sign jar with
List<String> ckaliases = new ArrayList<String>(); // aliases in -verify List<String> ckaliases = new ArrayList<String>(); // aliases in -verify
char[] storepass; // keystore password char[] storepass; // keystore password
@ -146,6 +151,7 @@ public class JarSigner {
boolean signManifest = true; // "sign" the whole manifest boolean signManifest = true; // "sign" the whole manifest
boolean externalSF = true; // leave the .SF out of the PKCS7 block boolean externalSF = true; // leave the .SF out of the PKCS7 block
boolean strict = false; // treat warnings as error boolean strict = false; // treat warnings as error
boolean autoCRL = false; // Automatcially add CRL defined in cert
// read zip entry raw bytes // read zip entry raw bytes
private ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); private ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
@ -226,6 +232,29 @@ public class JarSigner {
} else { } else {
loadKeyStore(keystore, true); loadKeyStore(keystore, true);
getAliasInfo(alias); 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 // load the alternative signing mechanism
if (altSignerClass != null) { if (altSignerClass != null) {
@ -367,6 +396,13 @@ public class JarSigner {
} else if (collator.compare(flags, "-digestalg") ==0) { } else if (collator.compare(flags, "-digestalg") ==0) {
if (++n == args.length) usageNoArg(); if (++n == args.length) usageNoArg();
digestalg = args[n]; 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) { } else if (collator.compare(flags, "-certs") ==0) {
showcerts = true; showcerts = true;
} else if (collator.compare(flags, "-strict") ==0) { } else if (collator.compare(flags, "-strict") ==0) {
@ -515,6 +551,9 @@ public class JarSigner {
System.out.println(rb.getString System.out.println(rb.getString
("[-sigalg <algorithm>] name of signature algorithm")); ("[-sigalg <algorithm>] name of signature algorithm"));
System.out.println(); System.out.println();
System.out.println(rb.getString
("[-crl[:auto| <file>] include CRL in signed jar"));
System.out.println();
System.out.println(rb.getString System.out.println(rb.getString
("[-verify] verify a signed JAR file")); ("[-verify] verify a signed JAR file"));
System.out.println(); System.out.println();
@ -654,6 +693,20 @@ public class JarSigner {
if (showcerts) { if (showcerts) {
sb.append(si); sb.append(si);
sb.append('\n'); 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")) { } else if (showcerts && !verbose.equals("all")) {
@ -1233,7 +1286,7 @@ public class JarSigner {
try { try {
block = block =
sf.generateBlock(privateKey, sigalg, certChain, sf.generateBlock(privateKey, sigalg, certChain, crls,
externalSF, tsaUrl, tsaCert, signingMechanism, args, externalSF, tsaUrl, tsaCert, signingMechanism, args,
zipFile); zipFile);
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
@ -2197,6 +2250,7 @@ class SignatureFile {
public Block generateBlock(PrivateKey privateKey, public Block generateBlock(PrivateKey privateKey,
String sigalg, String sigalg,
X509Certificate[] certChain, X509Certificate[] certChain,
Set<X509CRL> crls,
boolean externalSF, String tsaUrl, boolean externalSF, String tsaUrl,
X509Certificate tsaCert, X509Certificate tsaCert,
ContentSigner signingMechanism, ContentSigner signingMechanism,
@ -2204,7 +2258,7 @@ class SignatureFile {
throws NoSuchAlgorithmException, InvalidKeyException, IOException, throws NoSuchAlgorithmException, InvalidKeyException, IOException,
SignatureException, CertificateException SignatureException, CertificateException
{ {
return new Block(this, privateKey, sigalg, certChain, externalSF, return new Block(this, privateKey, sigalg, certChain, crls, externalSF,
tsaUrl, tsaCert, signingMechanism, args, zipFile); tsaUrl, tsaCert, signingMechanism, args, zipFile);
} }
@ -2218,7 +2272,8 @@ class SignatureFile {
* Construct a new signature block. * Construct a new signature block.
*/ */
Block(SignatureFile sfg, PrivateKey privateKey, String sigalg, 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, X509Certificate tsaCert, ContentSigner signingMechanism,
String[] args, ZipFile zipFile) String[] args, ZipFile zipFile)
throws NoSuchAlgorithmException, InvalidKeyException, IOException, throws NoSuchAlgorithmException, InvalidKeyException, IOException,
@ -2305,7 +2360,7 @@ class SignatureFile {
// Assemble parameters for the signing mechanism // Assemble parameters for the signing mechanism
ContentSignerParameters params = ContentSignerParameters params =
new JarSignerParameters(args, tsaUri, tsaCert, signature, new JarSignerParameters(args, tsaUri, tsaCert, signature,
signatureAlgorithm, certChain, content, zipFile); signatureAlgorithm, certChain, crls, content, zipFile);
// Generate the signature block // Generate the signature block
block = signingMechanism.generateSignedData( block = signingMechanism.generateSignedData(
@ -2346,6 +2401,7 @@ class JarSignerParameters implements ContentSignerParameters {
private byte[] signature; private byte[] signature;
private String signatureAlgorithm; private String signatureAlgorithm;
private X509Certificate[] signerCertificateChain; private X509Certificate[] signerCertificateChain;
private Set<X509CRL> crls;
private byte[] content; private byte[] content;
private ZipFile source; private ZipFile source;
@ -2354,7 +2410,8 @@ class JarSignerParameters implements ContentSignerParameters {
*/ */
JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate, JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate,
byte[] signature, String signatureAlgorithm, byte[] signature, String signatureAlgorithm,
X509Certificate[] signerCertificateChain, byte[] content, X509Certificate[] signerCertificateChain, Set<X509CRL> crls,
byte[] content,
ZipFile source) { ZipFile source) {
if (signature == null || signatureAlgorithm == null || if (signature == null || signatureAlgorithm == null ||
@ -2367,6 +2424,7 @@ class JarSignerParameters implements ContentSignerParameters {
this.signature = signature; this.signature = signature;
this.signatureAlgorithm = signatureAlgorithm; this.signatureAlgorithm = signatureAlgorithm;
this.signerCertificateChain = signerCertificateChain; this.signerCertificateChain = signerCertificateChain;
this.crls = crls;
this.content = content; this.content = content;
this.source = source; this.source = source;
} }
@ -2442,4 +2500,13 @@ class JarSignerParameters implements ContentSignerParameters {
public ZipFile getSource() { public ZipFile getSource() {
return source; return source;
} }
@Override
public Set<X509CRL> getCRLs() {
if (crls == null) {
return Collections.emptySet();
} else {
return Collections.unmodifiableSet(crls);
}
}
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 <algorithm>] name of digest algorithm"}, "[-digestalg <algorithm>] name of digest algorithm"},
{"[-sigalg <algorithm>] name of signature algorithm", {"[-sigalg <algorithm>] name of signature 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",
"[-verify] verify a signed JAR file"}, "[-verify] verify a signed JAR file"},
{"[-verbose[:suboptions]] verbose output when signing/verifying.", {"[-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",
"using an alternative signing mechanism"}, "using an alternative signing mechanism"},
{"entry was signed on", "entry was signed on {0}"}, {"entry was signed on", "entry was signed on {0}"},
{"with a CRL including %d entries", "with a CRL including %d entries"},
{"Warning: ", "Warning: "}, {"Warning: ", "Warning: "},
{"This jar contains unsigned entries which have not been integrity-checked. ", {"This jar contains unsigned entries which have not been integrity-checked. ",
"This jar contains unsigned entries which have not been integrity-checked. "}, "This jar contains unsigned entries which have not been integrity-checked. "},

View File

@ -25,6 +25,7 @@
package sun.security.tools; package sun.security.tools;
import sun.misc.SharedSecrets;
import java.io.*; import java.io.*;
import java.security.CodeSigner; import java.security.CodeSigner;
import java.security.KeyStore; import java.security.KeyStore;
@ -42,6 +43,7 @@ import java.security.Principal;
import java.security.Provider; import java.security.Provider;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.CRL;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.text.Collator; import java.text.Collator;
@ -50,14 +52,20 @@ import java.util.*;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; 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.misc.BASE64Encoder;
import sun.security.util.ObjectIdentifier; import sun.security.util.ObjectIdentifier;
import sun.security.pkcs.PKCS10; import sun.security.pkcs.PKCS10;
import sun.security.provider.X509Factory; import sun.security.provider.X509Factory;
import sun.security.util.DerOutputStream;
import sun.security.util.Password; import sun.security.util.Password;
import sun.security.util.PathList; import sun.security.util.PathList;
import javax.crypto.KeyGenerator; import javax.crypto.KeyGenerator;
@ -72,6 +80,7 @@ import javax.net.ssl.X509TrustManager;
import sun.misc.BASE64Decoder; import sun.misc.BASE64Decoder;
import sun.security.pkcs.PKCS10Attribute; import sun.security.pkcs.PKCS10Attribute;
import sun.security.pkcs.PKCS9Attribute; import sun.security.pkcs.PKCS9Attribute;
import sun.security.provider.certpath.ldap.LDAPCertStoreHelper;
import sun.security.util.DerValue; import sun.security.util.DerValue;
import sun.security.x509.*; import sun.security.x509.*;
@ -147,6 +156,7 @@ public final class KeyTool {
private Set<char[]> passwords = new HashSet<char[]> (); private Set<char[]> passwords = new HashSet<char[]> ();
private String startDate = null; private String startDate = null;
private List <String> ids = new ArrayList <String> (); // used in GENCRL
private List <String> v3ext = new ArrayList <String> (); private List <String> v3ext = new ArrayList <String> ();
enum Command { enum Command {
@ -180,9 +190,6 @@ public final class KeyTool {
STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE, STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE,
STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS,
PROVIDERARG, PROVIDERPATH, V, PROTECTED), 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", IMPORTCERT("Imports a certificate or a certificate chain",
NOPROMPT, TRUSTCACERTS, PROTECTED, ALIAS, FILEIN, NOPROMPT, TRUSTCACERTS, PROTECTED, ALIAS, FILEIN,
KEYPASS, KEYSTORE, STOREPASS, STORETYPE, KEYPASS, KEYSTORE, STOREPASS, STORETYPE,
@ -195,10 +202,6 @@ public final class KeyTool {
SRCALIAS, DESTALIAS, SRCKEYPASS, DESTKEYPASS, SRCALIAS, DESTALIAS, SRCKEYPASS, DESTKEYPASS,
NOPROMPT, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, NOPROMPT, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH,
V), 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", KEYPASSWD("Changes the key password of an entry",
ALIAS, KEYPASS, NEW, KEYSTORE, STOREPASS, ALIAS, KEYPASS, NEW, KEYSTORE, STOREPASS,
STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG,
@ -211,12 +214,29 @@ public final class KeyTool {
RFC, FILEIN, SSLSERVER, JARFILE, V), RFC, FILEIN, SSLSERVER, JARFILE, V),
PRINTCERTREQ("Prints the content of a certificate request", PRINTCERTREQ("Prints the content of a certificate request",
FILEIN, V), 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", SELFCERT("Generates a self-signed certificate",
ALIAS, SIGALG, DNAME, STARTDATE, VALIDITY, KEYPASS, ALIAS, SIGALG, DNAME, STARTDATE, VALIDITY, KEYPASS,
STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME,
PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V),
STOREPASSWD("Changes the store password of a keystore", GENCRL("Generates CRL",
NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, 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); PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V);
final String description; final String description;
@ -244,6 +264,7 @@ public final class KeyTool {
EXT("ext", "<value>", "X.509 extension"), EXT("ext", "<value>", "X.509 extension"),
FILEOUT("file", "<filename>", "output file name"), FILEOUT("file", "<filename>", "output file name"),
FILEIN("file", "<filename>", "input file name"), FILEIN("file", "<filename>", "input file name"),
ID("id", "<id:reason>", "Serial ID of cert to revoke"),
INFILE("infile", "<filename>", "input file name"), INFILE("infile", "<filename>", "input file name"),
KEYALG("keyalg", "<keyalg>", "key algorithm name"), KEYALG("keyalg", "<keyalg>", "key algorithm name"),
KEYPASS("keypass", "<arg>", "key password"), KEYPASS("keypass", "<arg>", "key password"),
@ -458,6 +479,8 @@ public final class KeyTool {
validity = Long.parseLong(args[++i]); validity = Long.parseLong(args[++i]);
} else if (collator.compare(flags, "-ext") == 0) { } else if (collator.compare(flags, "-ext") == 0) {
v3ext.add(args[++i]); v3ext.add(args[++i]);
} else if (collator.compare(flags, "-id") == 0) {
ids.add(args[++i]);
} else if (collator.compare(flags, "-file") == 0) { } else if (collator.compare(flags, "-file") == 0) {
filename = args[++i]; filename = args[++i];
} else if (collator.compare(flags, "-infile") == 0) { } else if (collator.compare(flags, "-infile") == 0) {
@ -720,7 +743,8 @@ public final class KeyTool {
command != GENSECKEY && command != GENSECKEY &&
command != IDENTITYDB && command != IDENTITYDB &&
command != IMPORTCERT && command != IMPORTCERT &&
command != IMPORTKEYSTORE) { command != IMPORTKEYSTORE &&
command != PRINTCRL) {
throw new Exception(rb.getString throw new Exception(rb.getString
("Keystore file does not exist: ") + ksfname); ("Keystore file does not exist: ") + ksfname);
} }
@ -855,11 +879,13 @@ public final class KeyTool {
&& !KeyStoreUtil.isWindowsKeyStore(storetype) && !KeyStoreUtil.isWindowsKeyStore(storetype)
&& isKeyStoreRelated(command)) { && isKeyStoreRelated(command)) {
// here we have EXPORTCERT and LIST (info valid until STOREPASSWD) // here we have EXPORTCERT and LIST (info valid until STOREPASSWD)
if (command != PRINTCRL) {
System.err.print(rb.getString("Enter keystore password: ")); System.err.print(rb.getString("Enter keystore password: "));
System.err.flush(); System.err.flush();
storePass = Password.readPassword(System.in); storePass = Password.readPassword(System.in);
passwords.add(storePass); passwords.add(storePass);
} }
}
// Now load a nullStream-based keystore, // Now load a nullStream-based keystore,
// or verify the integrity of an input stream-based keystore // or verify the integrity of an input stream-based keystore
@ -895,7 +921,7 @@ public final class KeyTool {
// Create a certificate factory // Create a certificate factory
if (command == PRINTCERT || command == IMPORTCERT if (command == PRINTCERT || command == IMPORTCERT
|| command == IDENTITYDB) { || command == IDENTITYDB || command == PRINTCRL) {
cf = CertificateFactory.getInstance("X509"); cf = CertificateFactory.getInstance("X509");
} }
@ -1086,6 +1112,22 @@ public final class KeyTool {
ps.close(); 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) { } else if (command == PRINTCERTREQ) {
InputStream inStream = System.in; InputStream inStream = System.in;
if (filename != null) { if (filename != null) {
@ -1098,6 +1140,8 @@ public final class KeyTool {
inStream.close(); inStream.close();
} }
} }
} else if (command == PRINTCRL) {
doPrintCRL(filename, out);
} }
// If we need to save the keystore, do so. // If we need to save the keystore, do so.
@ -1152,7 +1196,8 @@ public final class KeyTool {
CertificateValidity interval = new CertificateValidity(firstDate, CertificateValidity interval = new CertificateValidity(firstDate,
lastDate); lastDate);
PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst; PrivateKey privateKey =
(PrivateKey)recoverKey(alias, storePass, keyPass).fst;
if (sigAlgName == null) { if (sigAlgName == null) {
sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm()); 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<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 * Creates a PKCS#10 cert signing request, corresponding to the
* keys (and name) associated with a given alias. * keys (and name) associated with a given alias.
@ -1925,6 +2020,177 @@ public final class KeyTool {
} }
} }
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) private void doPrintCertReq(InputStream in, PrintStream out)
throws Exception { throws Exception {
@ -2063,6 +2329,16 @@ public final class KeyTool {
out.println(); 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. * Match a command (may be abbreviated) with a command set.
* @param s the command provided * @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 * @return the position of a single match, or -1 if none matched
* @throws Exception if s is ambiguous * @throws Exception if s is ambiguous
*/ */
private static int oneOf(String s, String... list) throws Exception { private static int oneOf(String s, String... list) throws Exception {
int[] match = new int[list.length]; int[] match = new int[list.length];
int nmatch = 0; int nmatch = 0;
int experiment = Integer.MAX_VALUE;
for (int i = 0; i<list.length; i++) { for (int i = 0; i<list.length; i++) {
String one = list[i]; String one = list[i];
if (one == null) {
experiment = i;
continue;
}
if (one.toLowerCase(Locale.ENGLISH) if (one.toLowerCase(Locale.ENGLISH)
.startsWith(s.toLowerCase(Locale.ENGLISH))) { .startsWith(s.toLowerCase(Locale.ENGLISH))) {
match[nmatch++] = i; match[nmatch++] = i;
@ -3360,18 +3643,28 @@ public final class KeyTool {
} }
} }
} }
if (nmatch == 0) return -1; if (nmatch == 0) {
if (nmatch == 1) return match[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(); StringBuffer sb = new StringBuffer();
MessageFormat form = new MessageFormat(rb.getString MessageFormat form = new MessageFormat(rb.getString
("command {0} is ambiguous:")); ("command {0} is ambiguous:"));
Object[] source = {s}; Object[] source = {s};
sb.append(form.format(source) +"\n "); sb.append(form.format(source));
for (int i=0; i<nmatch; i++) { sb.append("\n ");
sb.append(" " + list[match[i]]); 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());
} }
}
/** /**
* Create a GeneralName object from known types * Create a GeneralName object from known types
@ -3405,6 +3698,8 @@ public final class KeyTool {
"IssuerAlternativeName", "IssuerAlternativeName",
"SubjectInfoAccess", "SubjectInfoAccess",
"AuthorityInfoAccess", "AuthorityInfoAccess",
null,
"CRLDistributionPoints",
}; };
private ObjectIdentifier findOidForExtName(String type) private ObjectIdentifier findOidForExtName(String type)
@ -3417,6 +3712,7 @@ public final class KeyTool {
case 4: return PKIXExtensions.IssuerAlternativeName_Id; case 4: return PKIXExtensions.IssuerAlternativeName_Id;
case 5: return PKIXExtensions.SubjectInfoAccess_Id; case 5: return PKIXExtensions.SubjectInfoAccess_Id;
case 6: return PKIXExtensions.AuthInfoAccess_Id; case 6: return PKIXExtensions.AuthInfoAccess_Id;
case 8: return PKIXExtensions.CRLDistributionPoints_Id;
default: return new ObjectIdentifier(type); default: return new ObjectIdentifier(type);
} }
} }
@ -3712,6 +4008,28 @@ public final class KeyTool {
("Illegal value: ") + extstr); ("Illegal value: ") + extstr);
} }
break; 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: case -1:
ObjectIdentifier oid = new ObjectIdentifier(name); ObjectIdentifier oid = new ObjectIdentifier(name);
byte[] data = null; byte[] data = null;
@ -3748,6 +4066,9 @@ public final class KeyTool {
new DerValue(DerValue.tag_OctetString, data) new DerValue(DerValue.tag_OctetString, data)
.toByteArray())); .toByteArray()));
break; break;
default:
throw new Exception(rb.getString(
"Unknown extension type: ") + extstr);
} }
} }
// always non-critical // always non-critical
@ -3810,12 +4131,9 @@ public final class KeyTool {
System.err.println(rb.getString("Commands:")); System.err.println(rb.getString("Commands:"));
System.err.println(); System.err.println();
for (Command c: Command.values()) { for (Command c: Command.values()) {
if (c != IDENTITYDB if (c == KEYCLONE) break;
&& c != KEYCLONE
&& c != SELFCERT) { // Deprecated commands
System.err.printf(" %-20s%s\n", c, rb.getString(c.description)); System.err.printf(" %-20s%s\n", c, rb.getString(c.description));
} }
}
System.err.println(); System.err.println();
System.err.println(rb.getString( System.err.println(rb.getString(
"Use \"keytool -command_name -help\" for usage of command_name")); "Use \"keytool -command_name -help\" for usage of command_name"));

View File

@ -38,6 +38,7 @@ import java.security.cert.X509Certificate;
import java.util.List; import java.util.List;
import com.sun.jarsigner.*; import com.sun.jarsigner.*;
import java.security.cert.X509CRL;
import java.util.Arrays; import java.util.Arrays;
import sun.security.pkcs.*; import sun.security.pkcs.*;
import sun.security.timestamp.*; import sun.security.timestamp.*;
@ -239,7 +240,7 @@ public final class TimestampedSigner extends ContentSigner {
// Create the PKCS #7 signed data message // Create the PKCS #7 signed data message
PKCS7 p7 = PKCS7 p7 =
new PKCS7(algorithms, contentInfo, signerCertificateChain, new PKCS7(algorithms, contentInfo, signerCertificateChain,
signerInfos); parameters.getCRLs().toArray(new X509CRL[parameters.getCRLs().size()]), signerInfos);
ByteArrayOutputStream p7out = new ByteArrayOutputStream(); ByteArrayOutputStream p7out = new ByteArrayOutputStream();
p7.encodeSignedData(p7out); p7.encodeSignedData(p7out);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -71,6 +71,7 @@ public class Resources extends java.util.ListResourceBundle {
"Generates a secret key"}, //-genseckey "Generates a secret key"}, //-genseckey
{"Generates certificate from a certificate request", {"Generates certificate from a certificate request",
"Generates certificate from a certificate request"}, //-gencert "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",
"Imports entries from a JDK 1.1.x-style identity database"}, //-identitydb "Imports entries from a JDK 1.1.x-style identity database"}, //-identitydb
{"Imports a certificate or a certificate chain", {"Imports a certificate or a certificate chain",
@ -87,6 +88,8 @@ public class Resources extends java.util.ListResourceBundle {
"Prints the content of a certificate"}, //-printcert "Prints the content of a certificate"}, //-printcert
{"Prints the content of a certificate request", {"Prints the content of a certificate request",
"Prints the content of a certificate request"}, //-printcertreq "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",
"Generates a self-signed certificate"}, //-selfcert "Generates a self-signed certificate"}, //-selfcert
{"Changes the store password of a keystore", {"Changes the store password of a keystore",
@ -176,6 +179,8 @@ public class Resources extends java.util.ListResourceBundle {
"verbose output"}, //-v "verbose output"}, //-v
{"validity number of days", {"validity number of days",
"validity number of days"}, //-validity "validity number of days"}, //-validity
{"Serial ID of cert to revoke",
"Serial ID of cert to revoke"}, //-id
// keytool: Running part // keytool: Running part
{"keytool error: ", "keytool error: "}, {"keytool error: ", "keytool error: "},
{"Illegal option: ", "Illegal option: "}, {"Illegal option: ", "Illegal option: "},
@ -375,6 +380,7 @@ public class Resources extends java.util.ListResourceBundle {
{"Signer #%d:", "Signer #%d:"}, {"Signer #%d:", "Signer #%d:"},
{"Timestamp:", "Timestamp:"}, {"Timestamp:", "Timestamp:"},
{"Signature:", "Signature:"}, {"Signature:", "Signature:"},
{"CRLs:", "CRLs:"},
{"Certificate owner: ", "Certificate owner: "}, {"Certificate owner: ", "Certificate owner: "},
{"Not a signed jar file", "Not a signed jar file"}, {"Not a signed jar file", "Not a signed jar file"},
{"No certificate from the SSL server", {"No certificate from the SSL server",
@ -433,6 +439,7 @@ public class Resources extends java.util.ListResourceBundle {
{"This extension cannot be marked as critical. ", {"This extension cannot be marked as critical. ",
"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: "}, {"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:"}, {"command {0} is ambiguous:", "command {0} is ambiguous:"},
// policytool // policytool

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,7 +25,6 @@
package sun.security.util; package sun.security.util;
import java.security.CodeSigner;
import java.security.cert.CertPath; import java.security.cert.CertPath;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
@ -34,11 +33,11 @@ import java.security.*;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.jar.*; import java.util.jar.*;
import java.io.ByteArrayOutputStream;
import sun.security.pkcs.*; import sun.security.pkcs.*;
import sun.security.timestamp.TimestampToken; import sun.security.timestamp.TimestampToken;
import sun.misc.BASE64Decoder; import sun.misc.BASE64Decoder;
import sun.misc.SharedSecrets;
import sun.security.jca.Providers; import sun.security.jca.Providers;
@ -479,7 +478,12 @@ public class SignatureFileVerifier {
signers = new ArrayList<CodeSigner>(); signers = new ArrayList<CodeSigner>();
} }
// Append the new code signer // 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) { if (debug != null) {
debug.println("Signature Block Certificate: " + debug.println("Signature Block Certificate: " +

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -89,7 +89,7 @@ import sun.misc.HexDumpEncoder;
* @author Hemma Prafullchandra * @author Hemma Prafullchandra
* @see X509CRL * @see X509CRL
*/ */
public class X509CRLImpl extends X509CRL { public class X509CRLImpl extends X509CRL implements DerEncoder {
// CRL data, and its envelope // CRL data, and its envelope
private byte[] signedCRL = null; // DER encoded crl 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 * Immutable X.509 Certificate Issuer DN and serial number pair
*/ */

View File

@ -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