提交 707c32d6 编写于 作者: W weijun

6780416: New keytool commands/options: -gencert, -printcertreq, -ext

Reviewed-by: xuelei, mullan
上级 35c32b60
/* /*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1997-2009 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
...@@ -69,6 +69,10 @@ import javax.net.ssl.SSLContext; ...@@ -69,6 +69,10 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import sun.misc.BASE64Decoder;
import sun.security.pkcs.PKCS10Attribute;
import sun.security.pkcs.PKCS9Attribute;
import sun.security.util.DerValue;
import sun.security.x509.*; import sun.security.x509.*;
import static java.security.KeyStore.*; import static java.security.KeyStore.*;
...@@ -85,7 +89,6 @@ import static java.security.KeyStore.*; ...@@ -85,7 +89,6 @@ import static java.security.KeyStore.*;
* *
* @since 1.2 * @since 1.2
*/ */
public final class KeyTool { public final class KeyTool {
private boolean debug = false; private boolean debug = false;
...@@ -100,6 +103,8 @@ public final class KeyTool { ...@@ -100,6 +103,8 @@ public final class KeyTool {
private String dname = null; private String dname = null;
private String dest = null; private String dest = null;
private String filename = null; private String filename = null;
private String infilename = null;
private String outfilename = null;
private String srcksfname = null; private String srcksfname = null;
// User-specified providers are added before any command is called. // User-specified providers are added before any command is called.
...@@ -117,7 +122,6 @@ public final class KeyTool { ...@@ -117,7 +122,6 @@ public final class KeyTool {
private char[] storePassNew = null; private char[] storePassNew = null;
private char[] keyPass = null; private char[] keyPass = null;
private char[] keyPassNew = null; private char[] keyPassNew = null;
private char[] oldPass = null;
private char[] newPass = null; private char[] newPass = null;
private char[] destKeyPass = null; private char[] destKeyPass = null;
private char[] srckeyPass = null; private char[] srckeyPass = null;
...@@ -140,6 +144,8 @@ public final class KeyTool { ...@@ -140,6 +144,8 @@ 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> v3ext = new ArrayList <String> ();
private static final int CERTREQ = 1; private static final int CERTREQ = 1;
private static final int CHANGEALIAS = 2; private static final int CHANGEALIAS = 2;
private static final int DELETE = 3; private static final int DELETE = 3;
...@@ -156,6 +162,8 @@ public final class KeyTool { ...@@ -156,6 +162,8 @@ public final class KeyTool {
private static final int PRINTCERT = 13; private static final int PRINTCERT = 13;
private static final int SELFCERT = 14; private static final int SELFCERT = 14;
private static final int STOREPASSWD = 15; private static final int STOREPASSWD = 15;
private static final int GENCERT = 16;
private static final int PRINTCERTREQ = 17;
private static final Class[] PARAM_STRING = { String.class }; private static final Class[] PARAM_STRING = { String.class };
...@@ -184,7 +192,9 @@ public final class KeyTool { ...@@ -184,7 +192,9 @@ public final class KeyTool {
private void run(String[] args, PrintStream out) throws Exception { private void run(String[] args, PrintStream out) throws Exception {
try { try {
parseArgs(args); parseArgs(args);
doCommands(out); if (command != -1) {
doCommands(out);
}
} catch (Exception e) { } catch (Exception e) {
System.out.println(rb.getString("keytool error: ") + e); System.out.println(rb.getString("keytool error: ") + e);
if (verbose) { if (verbose) {
...@@ -214,7 +224,10 @@ public final class KeyTool { ...@@ -214,7 +224,10 @@ public final class KeyTool {
*/ */
void parseArgs(String[] args) { void parseArgs(String[] args) {
if (args.length == 0) usage(); if (args.length == 0) {
usage();
return;
}
int i=0; int i=0;
...@@ -260,6 +273,10 @@ public final class KeyTool { ...@@ -260,6 +273,10 @@ public final class KeyTool {
command = IMPORTKEYSTORE; command = IMPORTKEYSTORE;
} else if (collator.compare(flags, "-genseckey") == 0) { } else if (collator.compare(flags, "-genseckey") == 0) {
command = GENSECKEY; command = GENSECKEY;
} else if (collator.compare(flags, "-gencert") == 0) {
command = GENCERT;
} else if (collator.compare(flags, "-printcertreq") == 0) {
command = PRINTCERTREQ;
} }
/* /*
...@@ -337,9 +354,18 @@ public final class KeyTool { ...@@ -337,9 +354,18 @@ public final class KeyTool {
} else if (collator.compare(flags, "-validity") == 0) { } else if (collator.compare(flags, "-validity") == 0) {
if (++i == args.length) errorNeedArgument(flags); if (++i == args.length) errorNeedArgument(flags);
validity = Long.parseLong(args[i]); validity = Long.parseLong(args[i]);
} else if (collator.compare(flags, "-ext") == 0) {
if (++i == args.length) errorNeedArgument(flags);
v3ext.add(args[i]);
} else if (collator.compare(flags, "-file") == 0) { } else if (collator.compare(flags, "-file") == 0) {
if (++i == args.length) errorNeedArgument(flags); if (++i == args.length) errorNeedArgument(flags);
filename = args[i]; filename = args[i];
} else if (collator.compare(flags, "-infile") == 0) {
if (++i == args.length) errorNeedArgument(flags);
infilename = args[i];
} else if (collator.compare(flags, "-outfile") == 0) {
if (++i == args.length) errorNeedArgument(flags);
outfilename = args[i];
} else if (collator.compare(flags, "-sslserver") == 0) { } else if (collator.compare(flags, "-sslserver") == 0) {
if (++i == args.length) errorNeedArgument(flags); if (++i == args.length) errorNeedArgument(flags);
sslserver = args[i]; sslserver = args[i];
...@@ -364,7 +390,7 @@ public final class KeyTool { ...@@ -364,7 +390,7 @@ public final class KeyTool {
} }
} }
providers.add( providers.add(
new Pair<String, String>(providerClass, providerArg)); Pair.of(providerClass, providerArg));
} }
/* /*
...@@ -404,6 +430,10 @@ public final class KeyTool { ...@@ -404,6 +430,10 @@ public final class KeyTool {
} }
} }
boolean isKeyStoreRelated(int cmd) {
return cmd != PRINTCERT && cmd != PRINTCERTREQ;
}
/** /**
* Execute the commands. * Execute the commands.
*/ */
...@@ -568,7 +598,7 @@ public final class KeyTool { ...@@ -568,7 +598,7 @@ public final class KeyTool {
// the default, which is located in $HOME/.keystore. // the default, which is located in $HOME/.keystore.
// If the command is "genkey", "identitydb", "import", or "printcert", // If the command is "genkey", "identitydb", "import", or "printcert",
// it is OK not to have a keystore. // it is OK not to have a keystore.
if (command != PRINTCERT) { if (isKeyStoreRelated(command)) {
if (ksfname == null) { if (ksfname == null) {
ksfname = System.getProperty("user.home") + File.separator ksfname = System.getProperty("user.home") + File.separator
+ ".keystore"; + ".keystore";
...@@ -721,7 +751,7 @@ public final class KeyTool { ...@@ -721,7 +751,7 @@ public final class KeyTool {
} }
} else if (!protectedPath } else if (!protectedPath
&& !KeyStoreUtil.isWindowsKeyStore(storetype) && !KeyStoreUtil.isWindowsKeyStore(storetype)
&& !(command == PRINTCERT)) { && isKeyStoreRelated(command)) {
// here we have EXPORTCERT and LIST (info valid until STOREPASSWD) // here we have EXPORTCERT and LIST (info valid until STOREPASSWD)
System.err.print(rb.getString("Enter keystore password: ")); System.err.print(rb.getString("Enter keystore password: "));
System.err.flush(); System.err.flush();
...@@ -763,7 +793,7 @@ public final class KeyTool { ...@@ -763,7 +793,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) {
cf = CertificateFactory.getInstance("X509"); cf = CertificateFactory.getInstance("X509");
} }
...@@ -930,6 +960,41 @@ public final class KeyTool { ...@@ -930,6 +960,41 @@ public final class KeyTool {
storePassNew = getNewPasswd("keystore password", storePass); storePassNew = getNewPasswd("keystore password", storePass);
} }
kssave = true; kssave = true;
} else if (command == GENCERT) {
if (alias == null) {
alias = keyAlias;
}
InputStream inStream = System.in;
if (infilename != null) {
inStream = new FileInputStream(infilename);
}
PrintStream ps = null;
if (outfilename != null) {
ps = new PrintStream(new FileOutputStream(outfilename));
out = ps;
}
try {
doGenCert(alias, sigAlgName, inStream, out);
} finally {
if (inStream != System.in) {
inStream.close();
}
if (ps != null) {
ps.close();
}
}
} else if (command == PRINTCERTREQ) {
InputStream inStream = System.in;
if (filename != null) {
inStream = new FileInputStream(filename);
}
try {
doPrintCertReq(inStream, out);
} finally {
if (inStream != System.in) {
inStream.close();
}
}
} }
// If we need to save the keystore, do so. // If we need to save the keystore, do so.
...@@ -961,6 +1026,91 @@ public final class KeyTool { ...@@ -961,6 +1026,91 @@ public final class KeyTool {
} }
} }
/**
* Generate a certificate: Read PKCS10 request from in, and print
* certificate to out. Use alias as CA, sigAlgName as the signature
* type.
*/
private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStream out)
throws Exception {
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 = new Date();
lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L);
CertificateValidity interval = new CertificateValidity(firstDate,
lastDate);
PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
if (sigAlgName == null) {
sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm());
}
Signature signature = Signature.getInstance(sigAlgName);
signature.initSign(privateKey);
X500Signer signer = new X500Signer(signature, owner);
X509CertInfo info = new X509CertInfo();
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber
((int)(firstDate.getTime()/1000)));
info.set(X509CertInfo.VERSION,
new CertificateVersion(CertificateVersion.V3));
info.set(X509CertInfo.ALGORITHM_ID,
new CertificateAlgorithmId(signer.getAlgorithmId()));
info.set(X509CertInfo.ISSUER,
new CertificateIssuerName(signer.getSigner()));
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
boolean canRead = false;
StringBuffer sb = new StringBuffer();
while (true) {
String s = reader.readLine();
if (s == null) break;
// OpenSSL does not use NEW
//if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) {
if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) {
canRead = true;
//} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) {
} else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) {
break;
} else if (canRead) {
sb.append(s);
}
}
byte[] rawReq = new BASE64Decoder().decodeBuffer(new String(sb));
PKCS10 req = new PKCS10(rawReq);
info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo()));
info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(req.getSubjectName()));
CertificateExtensions reqex = null;
Iterator<PKCS10Attribute> attrs = req.getAttributes().getAttributes().iterator();
while (attrs.hasNext()) {
PKCS10Attribute attr = attrs.next();
if (attr.getAttributeId().equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) {
reqex = (CertificateExtensions)attr.getAttributeValue();
}
}
CertificateExtensions ext = createV3Extensions(
reqex,
null,
v3ext,
req.getSubjectPublicKeyInfo(),
signerCert.getPublicKey());
info.set(X509CertInfo.EXTENSIONS, ext);
X509CertImpl cert = new X509CertImpl(info);
cert.sign(privateKey, sigAlgName);
dumpCert(cert, out);
}
/** /**
* 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.
...@@ -972,10 +1122,10 @@ public final class KeyTool { ...@@ -972,10 +1122,10 @@ public final class KeyTool {
alias = keyAlias; alias = keyAlias;
} }
Object[] objs = recoverKey(alias, storePass, keyPass); Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
PrivateKey privKey = (PrivateKey)objs[0]; PrivateKey privKey = (PrivateKey)objs.fst;
if (keyPass == null) { if (keyPass == null) {
keyPass = (char[])objs[1]; keyPass = objs.snd;
} }
Certificate cert = keyStore.getCertificate(alias); Certificate cert = keyStore.getCertificate(alias);
...@@ -986,21 +1136,14 @@ public final class KeyTool { ...@@ -986,21 +1136,14 @@ public final class KeyTool {
throw new Exception(form.format(source)); throw new Exception(form.format(source));
} }
PKCS10 request = new PKCS10(cert.getPublicKey()); PKCS10 request = new PKCS10(cert.getPublicKey());
CertificateExtensions ext = createV3Extensions(null, null, v3ext, cert.getPublicKey(), null);
// Attribute name is not significant
request.getAttributes().setAttribute(X509CertInfo.EXTENSIONS,
new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, ext));
// Construct an X500Signer object, so that we can sign the request // Construct an X500Signer object, so that we can sign the request
if (sigAlgName == null) { if (sigAlgName == null) {
// If no signature algorithm was specified at the command line, sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm());
// we choose one that is compatible with the selected private key
String keyAlgName = privKey.getAlgorithm();
if ("DSA".equalsIgnoreCase(keyAlgName)
|| "DSS".equalsIgnoreCase(keyAlgName)) {
sigAlgName = "SHA1WithDSA";
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
sigAlgName = "SHA1WithRSA";
} else {
throw new Exception(rb.getString
("Cannot derive signature algorithm"));
}
} }
Signature signature = Signature.getInstance(sigAlgName); Signature signature = Signature.getInstance(sigAlgName);
...@@ -1152,6 +1295,23 @@ public final class KeyTool { ...@@ -1152,6 +1295,23 @@ public final class KeyTool {
keyStore.setKeyEntry(alias, secKey, keyPass, null); keyStore.setKeyEntry(alias, secKey, keyPass, null);
} }
/**
* If no signature algorithm was specified at the command line,
* we choose one that is compatible with the selected private key
*/
private static String getCompatibleSigAlgName(String keyAlgName)
throws Exception {
if ("DSA".equalsIgnoreCase(keyAlgName)) {
return "SHA1WithDSA";
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
return "SHA1WithRSA";
} else if ("EC".equalsIgnoreCase(keyAlgName)) {
return "SHA1withECDSA";
} else {
throw new Exception(rb.getString
("Cannot derive signature algorithm"));
}
}
/** /**
* Creates a new key pair and self-signed certificate. * Creates a new key pair and self-signed certificate.
*/ */
...@@ -1179,16 +1339,7 @@ public final class KeyTool { ...@@ -1179,16 +1339,7 @@ public final class KeyTool {
} }
if (sigAlgName == null) { if (sigAlgName == null) {
if ("DSA".equalsIgnoreCase(keyAlgName)) { sigAlgName = getCompatibleSigAlgName(keyAlgName);
sigAlgName = "SHA1WithDSA";
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
sigAlgName = "SHA1WithRSA";
} else if ("EC".equalsIgnoreCase(keyAlgName)) {
sigAlgName = "SHA1withECDSA";
} else {
throw new Exception(rb.getString
("Cannot derive signature algorithm"));
}
} }
CertAndKeyGen keypair = CertAndKeyGen keypair =
new CertAndKeyGen(keyAlgName, sigAlgName, providerName); new CertAndKeyGen(keyAlgName, sigAlgName, providerName);
...@@ -1225,6 +1376,9 @@ public final class KeyTool { ...@@ -1225,6 +1376,9 @@ public final class KeyTool {
keyPass = promptForKeyPass(alias, null, storePass); keyPass = promptForKeyPass(alias, null, storePass);
} }
keyStore.setKeyEntry(alias, privKey, keyPass, chain); keyStore.setKeyEntry(alias, privKey, keyPass, chain);
// resign so that -ext are applied.
doSelfCert(alias, null, sigAlgName);
} }
/** /**
...@@ -1247,9 +1401,9 @@ public final class KeyTool { ...@@ -1247,9 +1401,9 @@ public final class KeyTool {
throw new Exception(form.format(source)); throw new Exception(form.format(source));
} }
Object[] objs = recoverEntry(keyStore, orig, storePass, keyPass); Pair<Entry,char[]> objs = recoverEntry(keyStore, orig, storePass, keyPass);
Entry entry = (Entry)objs[0]; Entry entry = objs.fst;
keyPass = (char[])objs[1]; keyPass = objs.snd;
PasswordProtection pp = null; PasswordProtection pp = null;
...@@ -1275,10 +1429,10 @@ public final class KeyTool { ...@@ -1275,10 +1429,10 @@ public final class KeyTool {
if (alias == null) { if (alias == null) {
alias = keyAlias; alias = keyAlias;
} }
Object[] objs = recoverKey(alias, storePass, keyPass); Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
Key privKey = (Key)objs[0]; Key privKey = objs.fst;
if (keyPass == null) { if (keyPass == null) {
keyPass = (char[])objs[1]; keyPass = objs.snd;
} }
if (keyPassNew == null) { if (keyPassNew == null) {
...@@ -1629,8 +1783,8 @@ public final class KeyTool { ...@@ -1629,8 +1783,8 @@ public final class KeyTool {
} }
} }
Object[] objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass); Pair<Entry,char[]> objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass);
Entry entry = (Entry)objs[0]; Entry entry = objs.fst;
PasswordProtection pp = null; PasswordProtection pp = null;
...@@ -1640,8 +1794,8 @@ public final class KeyTool { ...@@ -1640,8 +1794,8 @@ public final class KeyTool {
// so always try to protect with destKeyPass. // so always try to protect with destKeyPass.
if (destKeyPass != null) { if (destKeyPass != null) {
pp = new PasswordProtection(destKeyPass); pp = new PasswordProtection(destKeyPass);
} else if (objs[1] != null) { } else if (objs.snd != null) {
pp = new PasswordProtection((char[])objs[1]); pp = new PasswordProtection(objs.snd);
} }
try { try {
...@@ -1726,9 +1880,50 @@ public final class KeyTool { ...@@ -1726,9 +1880,50 @@ public final class KeyTool {
} }
} }
private void doPrintCertReq(InputStream in, PrintStream out)
throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuffer sb = new StringBuffer();
boolean started = false;
while (true) {
String s = reader.readLine();
if (s == null) break;
if (!started) {
if (s.startsWith("-----")) {
started = true;
}
} else {
if (s.startsWith("-----")) {
break;
}
sb.append(s);
}
}
PKCS10 req = new PKCS10(new BASE64Decoder().decodeBuffer(new String(sb)));
PublicKey pkey = req.getSubjectPublicKeyInfo();
out.printf(rb.getString("PKCS #10 Certificate Request (Version 1.0)\n" +
"Subject: %s\nPublic Key: %s format %s key\n"),
req.getSubjectName(), pkey.getFormat(), pkey.getAlgorithm());
for (PKCS10Attribute attr: req.getAttributes().getAttributes()) {
ObjectIdentifier oid = attr.getAttributeId();
if (oid.equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) {
CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue();
printExtensions(rb.getString("Extension Request:"), exts, out);
} else {
out.println(attr.getAttributeId());
out.println(attr.getAttributeValue());
}
}
if (debug) {
out.println(req); // Just to see more, say, public key length...
}
}
/** /**
* Reads a certificate (or certificate chain) and prints its contents in * Reads a certificate (or certificate chain) and prints its contents in
* a human readbable format. * a human readable format.
*/ */
private void printCertFromStream(InputStream in, PrintStream out) private void printCertFromStream(InputStream in, PrintStream out)
throws Exception throws Exception
...@@ -1840,7 +2035,18 @@ public final class KeyTool { ...@@ -1840,7 +2035,18 @@ public final class KeyTool {
inStream = new FileInputStream(filename); inStream = new FileInputStream(filename);
} }
try { try {
printCertFromStream(inStream, out); // Read the full stream before feeding to X509Factory,
// otherwise, keytool -gencert | keytool -printcert
// might not work properly, since -gencert 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 = inStream.read(b);
if (len < 0) break;
bout.write(b, 0, len);
}
printCertFromStream(new ByteArrayInputStream(bout.toByteArray()), out);
} finally { } finally {
if (inStream != System.in) { if (inStream != System.in) {
inStream.close(); inStream.close();
...@@ -1859,27 +2065,14 @@ public final class KeyTool { ...@@ -1859,27 +2065,14 @@ public final class KeyTool {
alias = keyAlias; alias = keyAlias;
} }
Object[] objs = recoverKey(alias, storePass, keyPass); Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
PrivateKey privKey = (PrivateKey)objs[0]; PrivateKey privKey = (PrivateKey)objs.fst;
if (keyPass == null) if (keyPass == null)
keyPass = (char[])objs[1]; keyPass = objs.snd;
// Determine the signature algorithm // Determine the signature algorithm
if (sigAlgName == null) { if (sigAlgName == null) {
// If no signature algorithm was specified at the command line, sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm());
// we choose one that is compatible with the selected private key
String keyAlgName = privKey.getAlgorithm();
if ("DSA".equalsIgnoreCase(keyAlgName)
|| "DSS".equalsIgnoreCase(keyAlgName)) {
sigAlgName = "SHA1WithDSA";
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
sigAlgName = "SHA1WithRSA";
} else if ("EC".equalsIgnoreCase(keyAlgName)) {
sigAlgName = "SHA1withECDSA";
} else {
throw new Exception
(rb.getString("Cannot derive signature algorithm"));
}
} }
// Get the old certificate // Get the old certificate
...@@ -1943,11 +2136,16 @@ public final class KeyTool { ...@@ -1943,11 +2136,16 @@ public final class KeyTool {
certInfo.set(CertificateAlgorithmId.NAME + "." + certInfo.set(CertificateAlgorithmId.NAME + "." +
CertificateAlgorithmId.ALGORITHM, sigAlgid); CertificateAlgorithmId.ALGORITHM, sigAlgid);
// first upgrade to version 3
certInfo.set(X509CertInfo.VERSION, certInfo.set(X509CertInfo.VERSION,
new CertificateVersion(CertificateVersion.V3)); new CertificateVersion(CertificateVersion.V3));
CertificateExtensions ext = createV3Extensions(
null,
(CertificateExtensions)certInfo.get(X509CertInfo.EXTENSIONS),
v3ext,
oldCert.getPublicKey(),
null);
certInfo.set(X509CertInfo.EXTENSIONS, ext);
// Sign the new certificate // Sign the new certificate
newCert = new X509CertImpl(certInfo); newCert = new X509CertImpl(certInfo);
newCert.sign(privKey, sigAlgName); newCert.sign(privKey, sigAlgName);
...@@ -1985,10 +2183,10 @@ public final class KeyTool { ...@@ -1985,10 +2183,10 @@ public final class KeyTool {
alias = keyAlias; alias = keyAlias;
} }
Object[] objs = recoverKey(alias, storePass, keyPass); Pair<Key,char[]> objs = recoverKey(alias, storePass, keyPass);
PrivateKey privKey = (PrivateKey)objs[0]; PrivateKey privKey = (PrivateKey)objs.fst;
if (keyPass == null) { if (keyPass == null) {
keyPass = (char[])objs[1]; keyPass = objs.snd;
} }
Certificate userCert = keyStore.getCertificate(alias); Certificate userCert = keyStore.getCertificate(alias);
...@@ -2290,36 +2488,40 @@ public final class KeyTool { ...@@ -2290,36 +2488,40 @@ public final class KeyTool {
}; };
out.println(form.format(source)); out.println(form.format(source));
int extnum = 0;
if (cert instanceof X509CertImpl) { if (cert instanceof X509CertImpl) {
X509CertImpl impl = (X509CertImpl)cert; X509CertImpl impl = (X509CertImpl)cert;
if (cert.getCriticalExtensionOIDs() != null) { X509CertInfo certInfo = (X509CertInfo)impl.get(X509CertImpl.NAME
for (String extOID : cert.getCriticalExtensionOIDs()) { + "." +
if (extnum == 0) { X509CertImpl.INFO);
out.println(); CertificateExtensions exts = (CertificateExtensions)
out.println(rb.getString("Extensions: ")); certInfo.get(X509CertInfo.EXTENSIONS);
out.println(); printExtensions(rb.getString("Extensions: "), exts, out);
} }
out.println("#"+(++extnum)+": "+ }
impl.getExtension(new ObjectIdentifier(extOID)));
} private static void printExtensions(String title, CertificateExtensions exts, PrintStream out)
throws Exception {
int extnum = 0;
Iterator<Extension> i1 = exts.getAllExtensions().iterator();
Iterator<Extension> i2 = exts.getUnparseableExtensions().values().iterator();
while (i1.hasNext() || i2.hasNext()) {
Extension ext = i1.hasNext()?i1.next():i2.next();
if (extnum == 0) {
out.println();
out.println(title);
out.println();
} }
if (cert.getNonCriticalExtensionOIDs() != null) { out.print("#"+(++extnum)+": "+ ext);
for (String extOID : cert.getNonCriticalExtensionOIDs()) { if (ext.getClass() == Extension.class) {
if (extnum == 0) { byte[] v = ext.getExtensionValue();
out.println(); if (v.length == 0) {
out.println(rb.getString("Extensions: ")); out.println(rb.getString("(Empty value)"));
out.println(); } else {
} new sun.misc.HexDumpEncoder().encode(ext.getExtensionValue(), out);
Extension ext = impl.getExtension(new ObjectIdentifier(extOID)); out.println();
if (ext != null) {
out.println("#"+(++extnum)+": "+ ext);
} else {
out.println("#"+(++extnum)+": "+
impl.getUnparseableExtension(new ObjectIdentifier(extOID)));
}
} }
} }
out.println();
} }
} }
...@@ -2470,7 +2672,7 @@ public final class KeyTool { ...@@ -2470,7 +2672,7 @@ public final class KeyTool {
* recovered private key, and the 2nd element is the password used to * recovered private key, and the 2nd element is the password used to
* recover it. * recover it.
*/ */
private Object[] recoverKey(String alias, char[] storePass, private Pair<Key,char[]> recoverKey(String alias, char[] storePass,
char[] keyPass) char[] keyPass)
throws Exception throws Exception
{ {
...@@ -2510,7 +2712,7 @@ public final class KeyTool { ...@@ -2510,7 +2712,7 @@ public final class KeyTool {
key = keyStore.getKey(alias, keyPass); key = keyStore.getKey(alias, keyPass);
} }
return new Object[] {key, keyPass}; return Pair.of(key, keyPass);
} }
/** /**
...@@ -2520,7 +2722,7 @@ public final class KeyTool { ...@@ -2520,7 +2722,7 @@ public final class KeyTool {
* recovered entry, and the 2nd element is the password used to * recovered entry, and the 2nd element is the password used to
* recover it (null if no password). * recover it (null if no password).
*/ */
private Object[] recoverEntry(KeyStore ks, private Pair<Entry,char[]> recoverEntry(KeyStore ks,
String alias, String alias,
char[] pstore, char[] pstore,
char[] pkey) throws Exception { char[] pkey) throws Exception {
...@@ -2585,7 +2787,7 @@ public final class KeyTool { ...@@ -2585,7 +2787,7 @@ public final class KeyTool {
} }
} }
return new Object[] {entry, pkey}; return Pair.of(entry, pkey);
} }
/** /**
* Gets the requested finger print of the certificate. * Gets the requested finger print of the certificate.
...@@ -3026,6 +3228,443 @@ public final class KeyTool { ...@@ -3026,6 +3228,443 @@ public final class KeyTool {
return c.getTime(); return c.getTime();
} }
/**
* Match a command (may be abbreviated) with a command set.
* @param s the command provided
* @param list the legal command set
* @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;
for (int i = 0; i<list.length; i++) {
String one = list[i];
if (one.toLowerCase().startsWith(s.toLowerCase())) {
match[nmatch++] = i;
} else {
StringBuffer sb = new StringBuffer();
boolean first = true;
for (char c: one.toCharArray()) {
if (first) {
sb.append(c);
first = false;
} else {
if (!Character.isLowerCase(c)) {
sb.append(c);
}
}
}
if (sb.toString().equalsIgnoreCase(s)) {
match[nmatch++] = i;
}
}
}
if (nmatch == 0) return -1;
if (nmatch == 1) return match[0];
StringBuffer sb = new StringBuffer();
MessageFormat form = new MessageFormat(rb.getString
("command {0} is ambiguous:"));
Object[] source = {s};
sb.append(form.format(source) +"\n ");
for (int i=0; i<nmatch; i++) {
sb.append(" " + list[match[i]]);
}
throw new Exception(sb.toString());
}
/**
* Create a GeneralName object from known types
* @param t one of 5 known types
* @param v value
* @return which one
*/
private GeneralName createGeneralName(String t, String v)
throws Exception {
GeneralNameInterface gn;
int p = oneOf(t, "EMAIL", "URI", "DNS", "IP", "OID");
if (p < 0) {
throw new Exception(rb.getString(
"Unrecognized GeneralName type: ") + t);
}
switch (p) {
case 0: gn = new RFC822Name(v); break;
case 1: gn = new URIName(v); break;
case 2: gn = new DNSName(v); break;
case 3: gn = new IPAddressName(v); break;
default: gn = new OIDName(v); break; //4
}
return new GeneralName(gn);
}
private static final String[] extSupported = {
"BasicConstraints",
"KeyUsage",
"ExtendedKeyUsage",
"SubjectAlternativeName",
"IssuerAlternativeName",
"SubjectInfoAccess",
"AuthorityInfoAccess",
};
private ObjectIdentifier findOidForExtName(String type)
throws Exception {
switch (oneOf(type, extSupported)) {
case 0: return PKIXExtensions.BasicConstraints_Id;
case 1: return PKIXExtensions.KeyUsage_Id;
case 2: return PKIXExtensions.ExtendedKeyUsage_Id;
case 3: return PKIXExtensions.SubjectAlternativeName_Id;
case 4: return PKIXExtensions.IssuerAlternativeName_Id;
case 5: return PKIXExtensions.SubjectInfoAccess_Id;
case 6: return PKIXExtensions.AuthInfoAccess_Id;
default: return new ObjectIdentifier(type);
}
}
/**
* Create X509v3 extensions from a string representation. Note that the
* SubjectKeyIdentifierExtension will always be created non-critical besides
* the extension requested in the <code>extstr</code> argument.
*
* @param reqex the requested extensions, can be null, used for -gencert
* @param ext the original extensions, can be null, used for -selfcert
* @param extstrs -ext values, Read keytool doc
* @param pkey the public key for the certificate
* @param akey the public key for the authority (issuer)
* @return the created CertificateExtensions
*/
private CertificateExtensions createV3Extensions(
CertificateExtensions reqex,
CertificateExtensions ext,
List <String> extstrs,
PublicKey pkey,
PublicKey akey) throws Exception {
if (ext != null && reqex != null) {
// This should not happen
throw new Exception("One of request and original should be null.");
}
if (ext == null) ext = new CertificateExtensions();
try {
// name{:critical}{=value}
// Honoring requested extensions
if (reqex != null) {
for(String extstr: extstrs) {
if (extstr.toLowerCase().startsWith("honored=")) {
List<String> list = Arrays.asList(
extstr.toLowerCase().substring(8).split(","));
// First check existence of "all"
if (list.contains("all")) {
ext = reqex; // we know ext was null
}
// one by one for others
for (String item: list) {
if (item.equals("all")) continue;
// add or remove
boolean add = true;
// -1, unchanged, 0 crtical, 1 non-critical
int action = -1;
String type = null;
if (item.startsWith("-")) {
add = false;
type = item.substring(1);
} else {
int colonpos = item.indexOf(':');
if (colonpos >= 0) {
type = item.substring(0, colonpos);
action = oneOf(item.substring(colonpos+1),
"critical", "non-critical");
if (action == -1) {
throw new Exception(rb.getString
("Illegal value: ") + item);
}
}
}
String n = reqex.getNameByOid(findOidForExtName(type));
if (add) {
Extension e = (Extension)reqex.get(n);
if (!e.isCritical() && action == 0
|| e.isCritical() && action == 1) {
e = Extension.newExtension(
e.getExtensionId(),
!e.isCritical(),
e.getExtensionValue());
ext.set(n, e);
}
} else {
ext.delete(n);
}
}
break;
}
}
}
for(String extstr: extstrs) {
String name, value;
boolean isCritical = false;
int eqpos = extstr.indexOf('=');
if (eqpos >= 0) {
name = extstr.substring(0, eqpos);
value = extstr.substring(eqpos+1);
} else {
name = extstr;
value = null;
}
int colonpos = name.indexOf(':');
if (colonpos >= 0) {
if (name.substring(colonpos+1).equalsIgnoreCase("critical")) {
isCritical = true;
}
name = name.substring(0, colonpos);
}
if (name.equalsIgnoreCase("honored")) {
continue;
}
int exttype = oneOf(name, extSupported);
switch (exttype) {
case 0: // BC
int pathLen = -1;
boolean isCA = false;
if (value == null) {
isCA = true;
} else {
try { // the abbr format
pathLen = Integer.parseInt(value);
isCA = true;
} catch (NumberFormatException ufe) {
// ca:true,pathlen:1
for (String part: value.split(",")) {
String[] nv = part.split(":");
if (nv.length != 2) {
throw new Exception(rb.getString
("Illegal value: ") + extstr);
} else {
if (nv[0].equalsIgnoreCase("ca")) {
isCA = Boolean.parseBoolean(nv[1]);
} else if (nv[0].equalsIgnoreCase("pathlen")) {
pathLen = Integer.parseInt(nv[1]);
} else {
throw new Exception(rb.getString
("Illegal value: ") + extstr);
}
}
}
}
}
ext.set(BasicConstraintsExtension.NAME,
new BasicConstraintsExtension(isCritical, isCA,
pathLen));
break;
case 1: // KU
if(value != null) {
boolean[] ok = new boolean[9];
for (String s: value.split(",")) {
int p = oneOf(s,
"digitalSignature", // (0),
"nonRepudiation", // (1)
"keyEncipherment", // (2),
"dataEncipherment", // (3),
"keyAgreement", // (4),
"keyCertSign", // (5),
"cRLSign", // (6),
"encipherOnly", // (7),
"decipherOnly", // (8)
"contentCommitment" // also (1)
);
if (p < 0) {
throw new Exception(rb.getString("Unknown keyUsage type: ") + s);
}
if (p == 9) p = 1;
ok[p] = true;
}
KeyUsageExtension kue = new KeyUsageExtension(ok);
// The above KeyUsageExtension constructor does not
// allow isCritical value, so...
ext.set(KeyUsageExtension.NAME, Extension.newExtension(
kue.getExtensionId(),
isCritical,
kue.getExtensionValue()));
} else {
throw new Exception(rb.getString
("Illegal value: ") + extstr);
}
break;
case 2: // EKU
if(value != null) {
Vector <ObjectIdentifier> v =
new Vector <ObjectIdentifier>();
for (String s: value.split(",")) {
int p = oneOf(s,
"anyExtendedKeyUsage",
"serverAuth", //1
"clientAuth", //2
"codeSigning", //3
"emailProtection", //4
"", //5
"", //6
"", //7
"timeStamping", //8
"OCSPSigning" //9
);
if (p < 0) {
try {
v.add(new ObjectIdentifier(s));
} catch (Exception e) {
throw new Exception(rb.getString(
"Unknown extendedkeyUsage type: ") + s);
}
} else if (p == 0) {
v.add(new ObjectIdentifier("2.5.29.37.0"));
} else {
v.add(new ObjectIdentifier("1.3.6.1.5.5.7.3." + p));
}
}
ext.set(ExtendedKeyUsageExtension.NAME,
new ExtendedKeyUsageExtension(isCritical, v));
} else {
throw new Exception(rb.getString
("Illegal value: ") + extstr);
}
break;
case 3: // SAN
case 4: // IAN
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));
}
if (exttype == 3) {
ext.set(SubjectAlternativeNameExtension.NAME,
new SubjectAlternativeNameExtension(
isCritical, gnames));
} else {
ext.set(IssuerAlternativeNameExtension.NAME,
new IssuerAlternativeNameExtension(
isCritical, gnames));
}
} else {
throw new Exception(rb.getString
("Illegal value: ") + extstr);
}
break;
case 5: // SIA, always non-critical
case 6: // AIA, always non-critical
if (isCritical) {
throw new Exception(rb.getString(
"This extension cannot be marked as critical. ") + extstr);
}
if(value != null) {
List<AccessDescription> accessDescriptions =
new ArrayList<AccessDescription>();
String[] ps = value.split(",");
for(String item: ps) {
colonpos = item.indexOf(':');
int colonpos2 = item.indexOf(':', colonpos+1);
if (colonpos < 0 || colonpos2 < 0) {
throw new Exception(rb.getString
("Illegal value: ") + extstr);
}
String m = item.substring(0, colonpos);
String t = item.substring(colonpos+1, colonpos2);
String v = item.substring(colonpos2+1);
int p = oneOf(m,
"",
"ocsp", //1
"caIssuers", //2
"timeStamping", //3
"",
"caRepository" //5
);
ObjectIdentifier oid;
if (p < 0) {
try {
oid = new ObjectIdentifier(m);
} catch (Exception e) {
throw new Exception(rb.getString(
"Unknown AccessDescription type: ") + m);
}
} else {
oid = new ObjectIdentifier("1.3.6.1.5.5.7.48." + p);
}
accessDescriptions.add(new AccessDescription(
oid, createGeneralName(t, v)));
}
if (exttype == 5) {
ext.set(SubjectInfoAccessExtension.NAME,
new SubjectInfoAccessExtension(accessDescriptions));
} else {
ext.set(AuthorityInfoAccessExtension.NAME,
new AuthorityInfoAccessExtension(accessDescriptions));
}
} else {
throw new Exception(rb.getString
("Illegal value: ") + extstr);
}
break;
case -1:
ObjectIdentifier oid = new ObjectIdentifier(name);
byte[] data = null;
if (value != null) {
data = new byte[value.length() / 2 + 1];
int pos = 0;
for (char c: value.toCharArray()) {
int hex;
if (c >= '0' && c <= '9') {
hex = c - '0' ;
} else if (c >= 'A' && c <= 'F') {
hex = c - 'A' + 10;
} else if (c >= 'a' && c <= 'f') {
hex = c - 'a' + 10;
} else {
continue;
}
if (pos % 2 == 0) {
data[pos/2] = (byte)(hex << 4);
} else {
data[pos/2] += hex;
}
pos++;
}
if (pos % 2 != 0) {
throw new Exception(rb.getString(
"Odd number of hex digits found: ") + extstr);
}
data = Arrays.copyOf(data, pos/2);
} else {
data = new byte[0];
}
ext.set(oid.toString(), new Extension(oid, isCritical,
new DerValue(DerValue.tag_OctetString, data)
.toByteArray()));
break;
}
}
// always non-critical
ext.set(SubjectKeyIdentifierExtension.NAME,
new SubjectKeyIdentifierExtension(
new KeyIdentifier(pkey).getIdentifier()));
if (akey != null && !pkey.equals(akey)) {
ext.set(AuthorityKeyIdentifierExtension.NAME,
new AuthorityKeyIdentifierExtension(
new KeyIdentifier(akey), null, null));
}
} catch(IOException e) {
throw new RuntimeException(e);
}
return ext;
}
/** /**
* Prints the usage of this tool. * Prints the usage of this tool.
*/ */
...@@ -3098,6 +3737,32 @@ public final class KeyTool { ...@@ -3098,6 +3737,32 @@ public final class KeyTool {
("\t [-sigalg <sigalg>] [-dname <dname>]")); ("\t [-sigalg <sigalg>] [-dname <dname>]"));
System.err.println(rb.getString System.err.println(rb.getString
("\t [-startdate <startdate>]")); ("\t [-startdate <startdate>]"));
System.err.println(rb.getString
("\t [-ext <key>[:critical][=<value>]]..."));
System.err.println(rb.getString
("\t [-validity <valDays>] [-keypass <keypass>]"));
System.err.println(rb.getString
("\t [-keystore <keystore>] [-storepass <storepass>]"));
System.err.println(rb.getString
("\t [-storetype <storetype>] [-providername <name>]"));
System.err.println(rb.getString
("\t [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
System.err.println(rb.getString
("\t [-providerpath <pathlist>]"));
System.err.println();
System.err.println(rb.getString
("-gencert [-v] [-rfc] [-protected]"));
System.err.println(rb.getString
("\t [-infile <infile>] [-outfile <outfile>]"));
System.err.println(rb.getString
("\t [-alias <alias>]"));
System.err.println(rb.getString
("\t [-sigalg <sigalg>]"));
System.err.println(rb.getString
("\t [-startdate <startdate>]"));
System.err.println(rb.getString
("\t [-ext <key>[:critical][=<value>]]..."));
System.err.println(rb.getString System.err.println(rb.getString
("\t [-validity <valDays>] [-keypass <keypass>]")); ("\t [-validity <valDays>] [-keypass <keypass>]"));
System.err.println(rb.getString System.err.println(rb.getString
...@@ -3201,6 +3866,10 @@ public final class KeyTool { ...@@ -3201,6 +3866,10 @@ public final class KeyTool {
("-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]")); ("-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]"));
System.err.println(); System.err.println();
System.err.println(rb.getString
("-printcertreq [-v] [-file <cert_file>]"));
System.err.println();
System.err.println(rb.getString System.err.println(rb.getString
("-storepasswd [-v] [-new <new_storepass>]")); ("-storepasswd [-v] [-new <new_storepass>]"));
System.err.println(rb.getString System.err.println(rb.getString
...@@ -3211,12 +3880,6 @@ public final class KeyTool { ...@@ -3211,12 +3880,6 @@ public final class KeyTool {
("\t [-providerclass <provider_class_name> [-providerarg <arg>]] ...")); ("\t [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
System.err.println(rb.getString System.err.println(rb.getString
("\t [-providerpath <pathlist>]")); ("\t [-providerpath <pathlist>]"));
if (debug) {
throw new RuntimeException("NO ERROR, SORRY");
} else {
System.exit(1);
}
} }
private void tinyHelp() { private void tinyHelp() {
...@@ -3270,4 +3933,8 @@ class Pair<A, B> { ...@@ -3270,4 +3933,8 @@ class Pair<A, B> {
else if (snd == null) return fst.hashCode() + 2; else if (snd == null) return fst.hashCode() + 2;
else return fst.hashCode() * 17 + snd.hashCode(); else return fst.hashCode() * 17 + snd.hashCode();
} }
public static <A,B> Pair<A,B> of(A a, B b) {
return new Pair<A,B>(a,b);
}
} }
/* /*
* Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2009 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
...@@ -49,6 +49,7 @@ public class Resources extends java.util.ListResourceBundle { ...@@ -49,6 +49,7 @@ public class Resources extends java.util.ListResourceBundle {
// keytool // keytool
{"keytool error: ", "keytool error: "}, {"keytool error: ", "keytool error: "},
{"Illegal option: ", "Illegal option: "}, {"Illegal option: ", "Illegal option: "},
{"Illegal value: ", "Illegal value: "},
{"Try keytool -help","Try keytool -help"}, {"Try keytool -help","Try keytool -help"},
{"Command option <flag> needs an argument.", "Command option {0} needs an argument."}, {"Command option <flag> needs an argument.", "Command option {0} needs an argument."},
{"Warning: Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified <command> value.", {"Warning: Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified <command> value.",
...@@ -281,6 +282,20 @@ public class Resources extends java.util.ListResourceBundle { ...@@ -281,6 +282,20 @@ public class Resources extends java.util.ListResourceBundle {
{"keytool usage:\n", "keytool usage:\n"}, {"keytool usage:\n", "keytool usage:\n"},
{"Extensions: ", "Extensions: "}, {"Extensions: ", "Extensions: "},
{"(Empty value)", "(Empty value)"},
{"Extension Request:", "Extension Request:"},
{"PKCS #10 Certificate Request (Version 1.0)\n" +
"Subject: %s\nPublic Key: %s format %s key\n",
"PKCS #10 Certificate Request (Version 1.0)\n" +
"Subject: %s\nPublic Key: %s format %s key\n"},
{"Unknown keyUsage type: ", "Unknown keyUsage type: "},
{"Unknown extendedkeyUsage type: ", "Unknown extendedkeyUsage type: "},
{"Unknown AccessDescription type: ", "Unknown AccessDescription type: "},
{"Unrecognized GeneralName type: ", "Unrecognized GeneralName type: "},
{"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: "},
{"command {0} is ambiguous:", "command {0} is ambiguous:"},
{"-certreq [-v] [-protected]", {"-certreq [-v] [-protected]",
"-certreq [-v] [-protected]"}, "-certreq [-v] [-protected]"},
...@@ -322,6 +337,14 @@ public class Resources extends java.util.ListResourceBundle { ...@@ -322,6 +337,14 @@ public class Resources extends java.util.ListResourceBundle {
{"\t [-validity <valDays>] [-keypass <keypass>]", {"\t [-validity <valDays>] [-keypass <keypass>]",
"\t [-validity <valDays>] [-keypass <keypass>]"}, "\t [-validity <valDays>] [-keypass <keypass>]"},
/** rest is same as -certreq starting from -keystore **/ /** rest is same as -certreq starting from -keystore **/
{"-gencert [-v] [-rfc] [-protected]",
"-gencert [-v] [-rfc] [-protected]"},
{"\t [-infile <infile>] [-outfile <outfile>]",
"\t [-infile <infile>] [-outfile <outfile>]"},
{"\t [-sigalg <sigalg>]",
"\t [-sigalg <sigalg>]"},
{"\t [-ext <key>[:critical][=<value>]]...",
"\t [-ext <key>[:critical][=<value>]]..."},
{"-genseckey [-v] [-protected]", {"-genseckey [-v] [-protected]",
"-genseckey [-v] [-protected]"}, "-genseckey [-v] [-protected]"},
...@@ -388,6 +411,8 @@ public class Resources extends java.util.ListResourceBundle { ...@@ -388,6 +411,8 @@ public class Resources extends java.util.ListResourceBundle {
{"-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]", {"-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]",
"-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]"}, "-printcert [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]"},
{"-printcertreq [-v] [-file <cert_file>]",
"-printcertreq [-v] [-file <cert_file>]"},
{"No certificate from the SSL server", {"No certificate from the SSL server",
"No certificate from the SSL server"}, "No certificate from the SSL server"},
......
/* /*
* Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2009 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
...@@ -48,6 +48,17 @@ public final class AccessDescription { ...@@ -48,6 +48,17 @@ public final class AccessDescription {
public static final ObjectIdentifier Ad_CAISSUERS_Id = public static final ObjectIdentifier Ad_CAISSUERS_Id =
ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 2}); ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 2});
public static final ObjectIdentifier Ad_TIMESTAMPING_Id =
ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 3});
public static final ObjectIdentifier Ad_CAREPOSITORY_Id =
ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 5});
public AccessDescription(ObjectIdentifier accessMethod, GeneralName accessLocation) {
this.accessMethod = accessMethod;
this.accessLocation = accessLocation;
}
public AccessDescription(DerValue derValue) throws IOException { public AccessDescription(DerValue derValue) throws IOException {
DerInputStream derIn = derValue.getData(); DerInputStream derIn = derValue.getData();
accessMethod = derIn.getOID(); accessMethod = derIn.getOID();
...@@ -90,7 +101,19 @@ public final class AccessDescription { ...@@ -90,7 +101,19 @@ public final class AccessDescription {
} }
public String toString() { public String toString() {
return ("accessMethod: " + accessMethod.toString() + String method = null;
"\n accessLocation: " + accessLocation.toString()); if (accessMethod.equals(Ad_CAISSUERS_Id)) {
method = "caIssuers";
} else if (accessMethod.equals(Ad_CAREPOSITORY_Id)) {
method = "caRepository";
} else if (accessMethod.equals(Ad_TIMESTAMPING_Id)) {
method = "timeStamping";
} else if (accessMethod.equals(Ad_OCSP_Id)) {
method = "ocsp";
} else {
method = accessMethod.toString();
}
return ("accessMethod: " + method +
"\n accessLocation: " + accessLocation.toString() + "\n");
} }
} }
...@@ -43,8 +43,9 @@ import sun.security.util.DerValue; ...@@ -43,8 +43,9 @@ import sun.security.util.DerValue;
* certificate that identifies the specific OCSP Responder to use when * certificate that identifies the specific OCSP Responder to use when
* performing on-line validation of that certificate. * performing on-line validation of that certificate.
* <p> * <p>
* This extension is defined in * This extension is defined in <a href="http://www.ietf.org/rfc/rfc3280.txt">
* <a href="http://www.ietf.org/rfc/rfc3280.txt">Internet X.509 PKI Certificate and Certificate Revocation List (CRL) Profile</a>. The profile permits * Internet X.509 PKI Certificate and Certificate Revocation List
* (CRL) Profile</a>. The profile permits
* the extension to be included in end-entity or CA certificates, * the extension to be included in end-entity or CA certificates,
* and it must be marked as non-critical. Its ASN.1 definition is as follows: * and it must be marked as non-critical. Its ASN.1 definition is as follows:
* <pre> * <pre>
......
/* /*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1997-2009 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
...@@ -198,7 +198,7 @@ implements CertAttrSet<String> { ...@@ -198,7 +198,7 @@ implements CertAttrSet<String> {
public String toString() { public String toString() {
String s = super.toString() + "AuthorityKeyIdentifier [\n"; String s = super.toString() + "AuthorityKeyIdentifier [\n";
if (id != null) { if (id != null) {
s += id.toString() + "\n"; s += id.toString(); // id already has a newline
} }
if (names != null) { if (names != null) {
s += names.toString() + "\n"; s += names.toString() + "\n";
......
/* /*
* Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1996-2009 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
...@@ -276,12 +276,6 @@ public final class CertAndKeyGen { ...@@ -276,12 +276,6 @@ public final class CertAndKeyGen {
info.set(X509CertInfo.ISSUER, info.set(X509CertInfo.ISSUER,
new CertificateIssuerName(issuer.getSigner())); new CertificateIssuerName(issuer.getSigner()));
CertificateExtensions ext = new CertificateExtensions();
ext.set(SubjectKeyIdentifierExtension.NAME,
new SubjectKeyIdentifierExtension(
new KeyIdentifier(publicKey).getIdentifier()));
info.set(X509CertInfo.EXTENSIONS, ext);
cert = new X509CertImpl(info); cert = new X509CertImpl(info);
cert.sign(privateKey, this.sigAlg); cert.sign(privateKey, this.sigAlg);
......
/* /*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1997-2009 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
...@@ -231,6 +231,15 @@ public class CertificateExtensions implements CertAttrSet<Extension> { ...@@ -231,6 +231,15 @@ public class CertificateExtensions implements CertAttrSet<Extension> {
map.remove(name); map.remove(name);
} }
public String getNameByOid(ObjectIdentifier oid) throws IOException {
for (String name: map.keySet()) {
if (map.get(name).getExtensionId().equals(oid)) {
return name;
}
}
return null;
}
/** /**
* Return an enumeration of names of attributes existing within this * Return an enumeration of names of attributes existing within this
* attribute. * attribute.
......
/* /*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1997-2009 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,6 +89,22 @@ extends Extension implements CertAttrSet<String> { ...@@ -89,6 +89,22 @@ extends Extension implements CertAttrSet<String> {
encodeThis(); encodeThis();
} }
/**
* Create a IssuerAlternativeNameExtension with the passed criticality
* and GeneralNames.
*
* @param critical true if the extension is to be treated as critical.
* @param names the GeneralNames for the issuer.
* @exception IOException on error.
*/
public IssuerAlternativeNameExtension(Boolean critical, GeneralNames names)
throws IOException {
this.names = names;
this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
this.critical = critical.booleanValue();
encodeThis();
}
/** /**
* Create a default IssuerAlternativeNameExtension. * Create a default IssuerAlternativeNameExtension.
*/ */
......
/* /*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1997-2009 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
...@@ -90,6 +90,8 @@ public class OIDMap { ...@@ -90,6 +90,8 @@ public class OIDMap {
private static final String CERT_ISSUER = ROOT + "." + private static final String CERT_ISSUER = ROOT + "." +
CertificateIssuerExtension.NAME; CertificateIssuerExtension.NAME;
private static final String SUBJECT_INFO_ACCESS = ROOT + "." +
SubjectInfoAccessExtension.NAME;
private static final String AUTH_INFO_ACCESS = ROOT + "." + private static final String AUTH_INFO_ACCESS = ROOT + "." +
AuthorityInfoAccessExtension.NAME; AuthorityInfoAccessExtension.NAME;
private static final String ISSUING_DIST_POINT = ROOT + "." + private static final String ISSUING_DIST_POINT = ROOT + "." +
...@@ -148,6 +150,8 @@ public class OIDMap { ...@@ -148,6 +150,8 @@ public class OIDMap {
"sun.security.x509.CRLDistributionPointsExtension"); "sun.security.x509.CRLDistributionPointsExtension");
addInternal(CERT_ISSUER, PKIXExtensions.CertificateIssuer_Id, addInternal(CERT_ISSUER, PKIXExtensions.CertificateIssuer_Id,
"sun.security.x509.CertificateIssuerExtension"); "sun.security.x509.CertificateIssuerExtension");
addInternal(SUBJECT_INFO_ACCESS, PKIXExtensions.SubjectInfoAccess_Id,
"sun.security.x509.SubjectInfoAccessExtension");
addInternal(AUTH_INFO_ACCESS, PKIXExtensions.AuthInfoAccess_Id, addInternal(AUTH_INFO_ACCESS, PKIXExtensions.AuthInfoAccess_Id,
"sun.security.x509.AuthorityInfoAccessExtension"); "sun.security.x509.AuthorityInfoAccessExtension");
addInternal(ISSUING_DIST_POINT, addInternal(ISSUING_DIST_POINT,
......
/*
* Copyright 2009 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.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* The Subject Information Access Extension (OID = 1.3.6.1.5.5.7.1.11).
* <p>
* The subject information access extension indicates how to access
* information and services for the subject of the certificate in which
* the extension appears. When the subject is a CA, information and
* services may include certificate validation services and CA policy
* data. When the subject is an end entity, the information describes
* the type of services offered and how to access them. In this case,
* the contents of this extension are defined in the protocol
* specifications for the supported services. This extension may be
* included in end entity or CA certificates. Conforming CAs MUST mark
* this extension as non-critical.
* <p>
* This extension is defined in <a href="http://www.ietf.org/rfc/rfc3280.txt">
* Internet X.509 PKI Certificate and Certificate Revocation List
* (CRL) Profile</a>. The profile permits
* the extension to be included in end-entity or CA certificates,
* and it must be marked as non-critical. Its ASN.1 definition is as follows:
* <pre>
* id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 }
*
* SubjectInfoAccessSyntax ::=
* SEQUENCE SIZE (1..MAX) OF AccessDescription
*
* AccessDescription ::= SEQUENCE {
* accessMethod OBJECT IDENTIFIER,
* accessLocation GeneralName }
* </pre>
* <p>
* @see Extension
* @see CertAttrSet
*/
public class SubjectInfoAccessExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.SubjectInfoAccess";
/**
* Attribute name.
*/
public static final String NAME = "SubjectInfoAccess";
public static final String DESCRIPTIONS = "descriptions";
/**
* The List of AccessDescription objects.
*/
private List<AccessDescription> accessDescriptions;
/**
* Create an SubjectInfoAccessExtension from a List of
* AccessDescription; the criticality is set to false.
*
* @param accessDescriptions the List of AccessDescription
* @throws IOException on error
*/
public SubjectInfoAccessExtension(
List<AccessDescription> accessDescriptions) throws IOException {
this.extensionId = PKIXExtensions.SubjectInfoAccess_Id;
this.critical = false;
this.accessDescriptions = accessDescriptions;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value Array of DER encoded bytes of the actual value.
* @exception IOException on error.
*/
public SubjectInfoAccessExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.SubjectInfoAccess_Id;
this.critical = critical.booleanValue();
if (!(value instanceof byte[])) {
throw new IOException("Illegal argument type");
}
extensionValue = (byte[])value;
DerValue val = new DerValue(extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"SubjectInfoAccessExtension.");
}
accessDescriptions = new ArrayList<AccessDescription>();
while (val.data.available() != 0) {
DerValue seq = val.data.getDerValue();
AccessDescription accessDescription = new AccessDescription(seq);
accessDescriptions.add(accessDescription);
}
}
/**
* Return the list of AccessDescription objects.
*/
public List<AccessDescription> getAccessDescriptions() {
return accessDescriptions;
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.SubjectInfoAccess_Id;
this.critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
if (!(obj instanceof List)) {
throw new IOException("Attribute value should be of type List.");
}
accessDescriptions = (List<AccessDescription>)obj;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:SubjectInfoAccessExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
return accessDescriptions;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:SubjectInfoAccessExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
accessDescriptions = new ArrayList<AccessDescription>();
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:SubjectInfoAccessExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(DESCRIPTIONS);
return elements.elements();
}
// Encode this extension value
private void encodeThis() throws IOException {
if (accessDescriptions.isEmpty()) {
this.extensionValue = null;
} else {
DerOutputStream ads = new DerOutputStream();
for (AccessDescription accessDescription : accessDescriptions) {
accessDescription.encode(ads);
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, ads);
this.extensionValue = seq.toByteArray();
}
}
/**
* Return the extension as user readable string.
*/
public String toString() {
return super.toString() + "SubjectInfoAccess [\n "
+ accessDescriptions + "\n]\n";
}
}
/* /*
* Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2005-2009 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
...@@ -56,11 +56,14 @@ ...@@ -56,11 +56,14 @@
*/ */
import java.security.KeyStore; import java.security.KeyStore;
import java.util.Locale;
import java.util.MissingResourceException;
import sun.security.tools.KeyTool; import sun.security.tools.KeyTool;
import sun.security.x509.*; import sun.security.x509.*;
import java.io.*; import java.io.*;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.security.cert.X509Certificate;
import sun.security.util.ObjectIdentifier;
public class KeyToolTest { public class KeyToolTest {
...@@ -118,7 +121,7 @@ public class KeyToolTest { ...@@ -118,7 +121,7 @@ public class KeyToolTest {
lastInput = input; lastInput = input;
lastCommand = cmd; lastCommand = cmd;
// "X" is appened so that we can precisely test how input is consumed // "X" is appended so that we can precisely test how input is consumed
HumanInputStream in = new HumanInputStream(input+"X"); HumanInputStream in = new HumanInputStream(input+"X");
test(in, cmd); test(in, cmd);
// make sure the input string is no more no less // make sure the input string is no more no less
...@@ -264,12 +267,21 @@ public class KeyToolTest { ...@@ -264,12 +267,21 @@ public class KeyToolTest {
} }
void assertTrue(boolean bool, String msg) { void assertTrue(boolean bool, String msg) {
if (debug) {
System.err.println("If not " + bool + ", " + msg);
} else {
System.err.print("v");
}
if(!bool) { if(!bool) {
afterFail(lastInput, lastCommand, "TRUE"); afterFail(lastInput, lastCommand, "TRUE");
System.err.println(msg);
throw new RuntimeException(msg); throw new RuntimeException(msg);
} }
} }
void assertTrue(boolean bool) {
assertTrue(bool, "well...");
}
/** /**
* Helper method, load a keystore * Helper method, load a keystore
* @param file file for keystore, null or "NONE" for PKCS11 * @param file file for keystore, null or "NONE" for PKCS11
...@@ -827,32 +839,363 @@ public class KeyToolTest { ...@@ -827,32 +839,363 @@ public class KeyToolTest {
remove("mykey.cert"); remove("mykey.cert");
} }
void v3extTest(String keyAlg) throws Exception {
KeyStore ks;
remove("x.jks");
String simple = "-keystore x.jks -storepass changeit -keypass changeit -noprompt -keyalg " + keyAlg + " ";
String pre = simple + "-genkeypair -dname CN=Olala -alias ";
// Version and SKID
testOK("", pre + "o1");
ks = loadStore("x.jks", "changeit", "JKS");
assertTrue(((X509Certificate)ks.getCertificate("o1")).getVersion() == 3);
assertTrue(((X509CertImpl)ks.getCertificate("o1")).getSubjectKeyIdentifierExtension() != null);
// BC
testOK("", pre + "b1 -ext BC:critical");
testOK("", pre + "b2 -ext BC");
testOK("", pre + "b3 -ext bc");
testOK("", pre + "b4 -ext BasicConstraints");
testOK("", pre + "b5 -ext basicconstraints");
testOK("", pre + "b6 -ext BC=ca:true,pathlen:12");
testOK("", pre + "b7 -ext BC=ca:false");
testOK("", pre + "b8 -ext BC:critical=ca:false");
testOK("", pre + "b9 -ext BC=12");
ks = loadStore("x.jks", "changeit", "JKS");
assertTrue(((X509CertImpl)ks.getCertificate("b1")).getBasicConstraintsExtension().isCritical());
assertTrue(!((X509CertImpl)ks.getCertificate("b2")).getBasicConstraintsExtension().isCritical());
assertTrue(((X509CertImpl)ks.getCertificate("b8")).getBasicConstraintsExtension().isCritical());
assertTrue(((X509Certificate)ks.getCertificate("b1")).getBasicConstraints() == Integer.MAX_VALUE);
assertTrue(((X509Certificate)ks.getCertificate("b2")).getBasicConstraints() == Integer.MAX_VALUE);
assertTrue(((X509Certificate)ks.getCertificate("b3")).getBasicConstraints() == Integer.MAX_VALUE);
assertTrue(((X509Certificate)ks.getCertificate("b4")).getBasicConstraints() == Integer.MAX_VALUE);
assertTrue(((X509Certificate)ks.getCertificate("b5")).getBasicConstraints() == Integer.MAX_VALUE);
assertTrue(((X509Certificate)ks.getCertificate("b6")).getBasicConstraints() == 12);
assertTrue(((X509Certificate)ks.getCertificate("b7")).getBasicConstraints() == -1);
assertTrue(((X509Certificate)ks.getCertificate("b9")).getBasicConstraints() == 12);
// KU
testOK("", pre + "ku1 -ext KeyUsage:critical=digitalsignature");
testOK("", pre + "ku2 -ext KU=digitalSignature");
testOK("", pre + "ku3 -ext KU=ds");
testOK("", pre + "ku4 -ext KU=dig");
testFail("", pre + "ku5 -ext KU=d"); // ambigous value
testFail("", pre + "ku6 -ext KU=cs"); // cRLSign cannot be cs
testOK("", pre + "ku11 -ext KU=nr");
testFail("", pre + "ku12 -ext KU=ke"); // ke also means keyAgreement
testOK("", pre + "ku12 -ext KU=keyE");
testFail("", pre + "ku13 -ext KU=de"); // de also means decipherOnly
testOK("", pre + "ku13 -ext KU=dataE");
testOK("", pre + "ku14 -ext KU=ka");
testOK("", pre + "ku15 -ext KU=kcs");
testOK("", pre + "ku16 -ext KU=crls");
testOK("", pre + "ku17 -ext KU=eo");
testOK("", pre + "ku18 -ext KU=do");
testOK("", pre + "ku19 -ext KU=cc");
testOK("", pre + "ku017 -ext KU=ds,cc,eo");
testOK("", pre + "ku135 -ext KU=nr,dataEncipherment,keyCertSign");
testOK("", pre + "ku246 -ext KU=keyEnc,cRL,keyA");
testOK("", pre + "ku1234 -ext KU=ka,da,keyE,nonR");
ks = loadStore("x.jks", "changeit", "JKS");
class CheckKU {
void check(KeyStore ks, String alias, int... pos) throws Exception {
System.err.print("x");
boolean[] bs = ((X509Certificate)ks.getCertificate(alias)).getKeyUsage();
bs = Arrays.copyOf(bs, 9);
for (int i=0; i<bs.length; i++) {
boolean found = false;
for (int p: pos) {
if (p == i) found = true;
}
if (!found ^ bs[i]) {
// OK
} else {
throw new RuntimeException("KU not match at " + i +
": " + found + " vs " + bs[i]);
}
}
}
}
CheckKU c = new CheckKU();
assertTrue(((X509CertImpl)ks.getCertificate("ku1")).getExtension(PKIXExtensions.KeyUsage_Id).isCritical());
assertTrue(!((X509CertImpl)ks.getCertificate("ku2")).getExtension(PKIXExtensions.KeyUsage_Id).isCritical());
c.check(ks, "ku1", 0);
c.check(ks, "ku2", 0);
c.check(ks, "ku3", 0);
c.check(ks, "ku4", 0);
c.check(ks, "ku11", 1);
c.check(ks, "ku12", 2);
c.check(ks, "ku13", 3);
c.check(ks, "ku14", 4);
c.check(ks, "ku15", 5);
c.check(ks, "ku16", 6);
c.check(ks, "ku17", 7);
c.check(ks, "ku18", 8);
c.check(ks, "ku19", 1);
c.check(ks, "ku11", 1);
c.check(ks, "ku11", 1);
c.check(ks, "ku11", 1);
c.check(ks, "ku017", 0, 1, 7);
c.check(ks, "ku135", 1, 3, 5);
c.check(ks, "ku246", 6, 2, 4);
c.check(ks, "ku1234", 1, 2, 3, 4);
// EKU
testOK("", pre + "eku1 -ext EKU:critical=sa");
testOK("", pre + "eku2 -ext ExtendedKeyUsage=ca");
testOK("", pre + "eku3 -ext EKU=cs");
testOK("", pre + "eku4 -ext EKU=ep");
testOK("", pre + "eku8 -ext EKU=ts");
testFail("", pre + "eku9 -ext EKU=os");
testOK("", pre + "eku9 -ext EKU=ocsps");
testOK("", pre + "eku10 -ext EKU=any");
testOK("", pre + "eku11 -ext EKU=1.2.3.4,1.3.5.7,ep");
testFail("", pre + "eku12 -ext EKU=c");
testFail("", pre + "eku12 -ext EKU=nothing");
ks = loadStore("x.jks", "changeit", "JKS");
class CheckEKU {
void check(KeyStore ks, String alias, String... pos) throws Exception {
System.err.print("x");
List<String> bs = ((X509Certificate)ks.getCertificate(alias)).getExtendedKeyUsage();
int found = 0;
for (String p: pos) {
if (bs.contains(p)) {
found++;
} else {
throw new RuntimeException("EKU: not included " + p);
}
}
if (found != bs.size()) {
throw new RuntimeException("EKU: more items than expected");
}
}
}
CheckEKU cx = new CheckEKU();
assertTrue(((X509CertImpl)ks.getCertificate("eku1")).getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical());
assertTrue(!((X509CertImpl)ks.getCertificate("eku2")).getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical());
cx.check(ks, "eku1", "1.3.6.1.5.5.7.3.1");
cx.check(ks, "eku2", "1.3.6.1.5.5.7.3.2");
cx.check(ks, "eku3", "1.3.6.1.5.5.7.3.3");
cx.check(ks, "eku4", "1.3.6.1.5.5.7.3.4");
cx.check(ks, "eku8", "1.3.6.1.5.5.7.3.8");
cx.check(ks, "eku9", "1.3.6.1.5.5.7.3.9");
cx.check(ks, "eku10", "2.5.29.37.0");
cx.check(ks, "eku11", "1.3.6.1.5.5.7.3.4", "1.2.3.4", "1.3.5.7");
// SAN
testOK("", pre+"san1 -ext san:critical=email:me@me.org");
testOK("", pre+"san2 -ext san=uri:http://me.org");
testOK("", pre+"san3 -ext san=dns:me.org");
testOK("", pre+"san4 -ext san=ip:192.168.0.1");
testOK("", pre+"san5 -ext san=oid:1.2.3.4");
testOK("", pre+"san235 -ext san=uri:http://me.org,dns:me.org,oid:1.2.3.4");
ks = loadStore("x.jks", "changeit", "JKS");
class CheckSAN {
// Please sort items with name type
void check(KeyStore ks, String alias, int type, Object... items) throws Exception {
int pos = 0;
System.err.print("x");
Object[] names = null;
if (type == 0) names = ((X509Certificate)ks.getCertificate(alias)).getSubjectAlternativeNames().toArray();
else names = ((X509Certificate)ks.getCertificate(alias)).getIssuerAlternativeNames().toArray();
Arrays.sort(names, new Comparator() {
public int compare(Object o1, Object o2) {
int i1 = (Integer)((List)o1).get(0);
int i2 = (Integer)((List)o2).get(0);
return i1 - i2;
}
});
for (Object o: names) {
List l = (List)o;
for (Object o2: l) {
if (!items[pos++].equals(o2)) {
throw new RuntimeException("Not equals at " + pos
+ ": " + items[pos-1] + " vs " + o2);
}
}
}
if (pos != items.length) {
throw new RuntimeException("Extra items, pos is " + pos);
}
}
}
CheckSAN csan = new CheckSAN();
assertTrue(((X509CertImpl)ks.getCertificate("san1")).getSubjectAlternativeNameExtension().isCritical());
assertTrue(!((X509CertImpl)ks.getCertificate("san2")).getSubjectAlternativeNameExtension().isCritical());
csan.check(ks, "san1", 0, 1, "me@me.org");
csan.check(ks, "san2", 0, 6, "http://me.org");
csan.check(ks, "san3", 0, 2, "me.org");
csan.check(ks, "san4", 0, 7, "192.168.0.1");
csan.check(ks, "san5", 0, 8, "1.2.3.4");
csan.check(ks, "san235", 0, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4");
// IAN
testOK("", pre+"ian1 -ext ian:critical=email:me@me.org");
testOK("", pre+"ian2 -ext ian=uri:http://me.org");
testOK("", pre+"ian3 -ext ian=dns:me.org");
testOK("", pre+"ian4 -ext ian=ip:192.168.0.1");
testOK("", pre+"ian5 -ext ian=oid:1.2.3.4");
testOK("", pre+"ian235 -ext ian=uri:http://me.org,dns:me.org,oid:1.2.3.4");
ks = loadStore("x.jks", "changeit", "JKS");
assertTrue(((X509CertImpl)ks.getCertificate("ian1")).getIssuerAlternativeNameExtension().isCritical());
assertTrue(!((X509CertImpl)ks.getCertificate("ian2")).getIssuerAlternativeNameExtension().isCritical());
csan.check(ks, "ian1", 1, 1, "me@me.org");
csan.check(ks, "ian2", 1, 6, "http://me.org");
csan.check(ks, "ian3", 1, 2, "me.org");
csan.check(ks, "ian4", 1, 7, "192.168.0.1");
csan.check(ks, "ian5", 1, 8, "1.2.3.4");
csan.check(ks, "ian235", 1, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4");
// SIA
testOK("", pre+"sia1 -ext sia=care:uri:ldap://ca.com/cn=CA");
testOK("", pre+"sia2 -ext sia=ts:email:ts@ca.com");
testFail("SIA never critical", pre+"sia3 -ext sia:critical=ts:email:ts@ca.com");
ks = loadStore("x.jks", "changeit", "JKS");
class CheckSia {
void check(KeyStore ks, String alias, int type, Object... items) throws Exception {
int pos = 0;
System.err.print("x");
AccessDescription[] ads = null;
if (type == 0) {
SubjectInfoAccessExtension siae = (SubjectInfoAccessExtension)((X509CertImpl)ks.getCertificate(alias)).getExtension(PKIXExtensions.SubjectInfoAccess_Id);
ads = siae.getAccessDescriptions().toArray(new AccessDescription[0]);
} else {
AuthorityInfoAccessExtension aiae = (AuthorityInfoAccessExtension)((X509CertImpl)ks.getCertificate(alias)).getExtension(PKIXExtensions.AuthInfoAccess_Id);
ads = aiae.getAccessDescriptions().toArray(new AccessDescription[0]);
}
Arrays.sort(ads, new Comparator<AccessDescription>() {
@Override
public int compare(AccessDescription o1, AccessDescription o2) {
return o1.getAccessMethod().toString().compareTo(o2.getAccessMethod().toString());
}
});
for (AccessDescription ad: ads) {
if (!ad.getAccessMethod().equals(items[pos++]) ||
!new Integer(ad.getAccessLocation().getType()).equals(items[pos++])) {
throw new RuntimeException("Not same type at " + pos);
}
String name = null;
switch (ad.getAccessLocation().getType()) {
case 1:
name = ((RFC822Name)ad.getAccessLocation().getName()).getName();
break;
case 6:
name = ((URIName)ad.getAccessLocation().getName()).getURI().toString();
break;
default:
throw new RuntimeException("Not implemented: " + ad);
}
if (!name.equals(items[pos++])) {
throw new Exception("Name not same for " + ad + " at pos " + pos);
}
}
}
}
CheckSia csia = new CheckSia();
assertTrue(!((X509CertImpl)ks.getCertificate("sia1")).getExtension(PKIXExtensions.SubjectInfoAccess_Id).isCritical());
csia.check(ks, "sia1", 0, AccessDescription.Ad_CAREPOSITORY_Id, 6, "ldap://ca.com/cn=CA");
csia.check(ks, "sia2", 0, AccessDescription.Ad_TIMESTAMPING_Id, 1, "ts@ca.com");
// AIA
testOK("", pre+"aia1 -ext aia=cai:uri:ldap://ca.com/cn=CA");
testOK("", pre+"aia2 -ext aia=ocsp:email:ocsp@ca.com");
testFail("AIA never critical", pre+"aia3 -ext aia:critical=ts:email:ts@ca.com");
ks = loadStore("x.jks", "changeit", "JKS");
assertTrue(!((X509CertImpl)ks.getCertificate("aia1")).getExtension(PKIXExtensions.AuthInfoAccess_Id).isCritical());
csia.check(ks, "aia1", 1, AccessDescription.Ad_CAISSUERS_Id, 6, "ldap://ca.com/cn=CA");
csia.check(ks, "aia2", 1, AccessDescription.Ad_OCSP_Id, 1, "ocsp@ca.com");
// OID
testOK("", pre+"oid1 -ext 1.2.3:critical=0102");
testOK("", pre+"oid2 -ext 1.2.3");
testOK("", pre+"oid12 -ext 1.2.3 -ext 1.2.4=01:02:03");
ks = loadStore("x.jks", "changeit", "JKS");
class CheckOid {
void check(KeyStore ks, String alias, String oid, byte[] value) throws Exception {
int pos = 0;
System.err.print("x");
Extension ex = ((X509CertImpl)ks.getCertificate(alias)).getExtension(new ObjectIdentifier(oid));
if (!Arrays.equals(value, ex.getValue())) {
throw new RuntimeException("Not same content in " + alias + " for " + oid);
}
}
}
CheckOid coid = new CheckOid();
assertTrue(((X509CertImpl)ks.getCertificate("oid1")).getExtension(new ObjectIdentifier("1.2.3")).isCritical());
assertTrue(!((X509CertImpl)ks.getCertificate("oid2")).getExtension(new ObjectIdentifier("1.2.3")).isCritical());
coid.check(ks, "oid1", "1.2.3", new byte[]{1,2});
coid.check(ks, "oid2", "1.2.3", new byte[]{});
coid.check(ks, "oid12", "1.2.3", new byte[]{});
coid.check(ks, "oid12", "1.2.4", new byte[]{1,2,3});
// honored
testOK("", pre+"ca");
testOK("", pre+"a");
// request: BC,KU,1.2.3,1.2.4,1.2.5
testOK("", simple+"-alias a -certreq " +
"-ext BC=1 -ext KU=crl " +
"-ext 1.2.3=01 -ext 1.2.4:critical=0102 -ext 1.2.5=010203 " +
"-rfc -file test.req");
// printcertreq
testOK("", "-printcertreq -file test.req");
// issue: deny KU, change criticality of 1.2.3 and 1.2.4, change content of BC, add 2.3.4
testOK("", simple+"-gencert -alias ca -infile test.req -ext " +
"honored=all,-KU,1.2.3:critical,1.2.4:non-critical " +
"-ext BC=2 -ext 2.3.4=01020304 " +
"-debug -rfc -outfile test.cert");
testOK("", simple+"-importcert -file test.cert -alias a");
ks = loadStore("x.jks", "changeit", "JKS");
X509CertImpl a = (X509CertImpl)ks.getCertificate("a");
assertTrue(a.getAuthorityKeyIdentifierExtension() != null);
assertTrue(a.getSubjectKeyIdentifierExtension() != null);
assertTrue(a.getKeyUsage() == null);
assertTrue(a.getExtension(new ObjectIdentifier("1.2.3")).isCritical());
assertTrue(!a.getExtension(new ObjectIdentifier("1.2.4")).isCritical());
assertTrue(!a.getExtension(new ObjectIdentifier("1.2.5")).isCritical());
assertTrue(a.getExtensionValue("1.2.3").length == 3);
assertTrue(a.getExtensionValue("1.2.4").length == 4);
assertTrue(a.getExtensionValue("1.2.5").length == 5);
assertTrue(a.getBasicConstraints() == 2);
assertTrue(!a.getExtension(new ObjectIdentifier("2.3.4")).isCritical());
assertTrue(a.getExtensionValue("2.3.4").length == 6);
remove("x.jks");
remove("test.req");
remove("test.cert");
}
void i18nTest() throws Exception { void i18nTest() throws Exception {
// 1. keytool -help // 1. keytool -help
remove("x.jks"); remove("x.jks");
try { testOK("", "-help");
test("", "-help");
assertTrue(false, "Cannot come here");
} catch(RuntimeException e) {
assertTrue(e.getMessage().indexOf("NO ERROR, SORRY") != -1, "No error");
}
// 2. keytool -genkey -v -keysize 512 Enter "a" for the keystore password. Check error (password too short). Enter "password" for the keystore password. Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password. // 2. keytool -genkey -v -keysize 512 Enter "a" for the keystore password. Check error (password too short). Enter "password" for the keystore password. Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password.
testOK("a\npassword\npassword\nMe\nHere\nNow\nPlace\nPlace\nUS\nyes\n\n", "-genkey -v -keysize 512 -keystore x.jks"); testOK("a\npassword\npassword\nMe\nHere\nNow\nPlace\nPlace\nUS\nyes\n\n", "-genkey -v -keysize 512 -keystore x.jks");
// 3. keytool -list -v -storepass password // 3. keytool -list -v -storepass password
testOK("", "-list -v -storepass password -keystore x.jks"); testOK("", "-list -v -storepass password -keystore x.jks");
// 4. keytool -list -v Type "a" for the keystore password. Check error (wrong keystore password). // 4. keytool -list -v Type "a" for the keystore password. Check error (wrong keystore password).
testFail("a\n", "-list -v -keystore x.jks"); testFail("a\n", "-list -v -keystore x.jks");
assertTrue(ex.indexOf("password was incorrect") != -1, ""); assertTrue(ex.indexOf("password was incorrect") != -1);
// 5. keytool -genkey -v -keysize 512 Enter "password" as the password. Check error (alias 'mykey' already exists). // 5. keytool -genkey -v -keysize 512 Enter "password" as the password. Check error (alias 'mykey' already exists).
testFail("password\n", "-genkey -v -keysize 512 -keystore x.jks"); testFail("password\n", "-genkey -v -keysize 512 -keystore x.jks");
assertTrue(ex.indexOf("alias <mykey> already exists") != -1, ""); assertTrue(ex.indexOf("alias <mykey> already exists") != -1);
// 6. keytool -genkey -v -keysize 512 -alias mykey2 -storepass password Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password. // 6. keytool -genkey -v -keysize 512 -alias mykey2 -storepass password Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password.
testOK("\n\n\n\n\n\nyes\n\n", "-genkey -v -keysize 512 -alias mykey2 -storepass password -keystore x.jks"); testOK("\n\n\n\n\n\nyes\n\n", "-genkey -v -keysize 512 -alias mykey2 -storepass password -keystore x.jks");
// 7. keytool -list -v Type 'password' for the store password. // 7. keytool -list -v Type 'password' for the store password.
testOK("password\n", "-list -v -keystore x.jks"); testOK("password\n", "-list -v -keystore x.jks");
// 8. keytool -keypasswd -v -alias mykey2 -storepass password Type "a" for the new key password. Type "aaaaaa" for the new key password. Type "bbbbbb" when re-entering the new key password. Type "a" for the new key password. Check Error (too many failures). // 8. keytool -keypasswd -v -alias mykey2 -storepass password Type "a" for the new key password. Type "aaaaaa" for the new key password. Type "bbbbbb" when re-entering the new key password. Type "a" for the new key password. Check Error (too many failures).
testFail("a\naaaaaa\nbbbbbb\na\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks"); testFail("a\naaaaaa\nbbbbbb\na\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks");
assertTrue(ex.indexOf("Too many failures - try later") != -1, ""); assertTrue(ex.indexOf("Too many failures - try later") != -1);
// 9. keytool -keypasswd -v -alias mykey2 -storepass password Type "aaaaaa" for the new key password. Type "aaaaaa" when re-entering the new key password. // 9. keytool -keypasswd -v -alias mykey2 -storepass password Type "aaaaaa" for the new key password. Type "aaaaaa" when re-entering the new key password.
testOK("aaaaaa\naaaaaa\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks"); testOK("aaaaaa\naaaaaa\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks");
// 10. keytool -selfcert -v -alias mykey -storepass password // 10. keytool -selfcert -v -alias mykey -storepass password
...@@ -864,7 +1207,7 @@ public class KeyToolTest { ...@@ -864,7 +1207,7 @@ public class KeyToolTest {
testOK("", "-export -v -alias mykey -file cert -storepass password -keystore x.jks"); testOK("", "-export -v -alias mykey -file cert -storepass password -keystore x.jks");
// 13. keytool -import -v -file cert -storepass password Check error (Certificate reply and cert are the same) // 13. keytool -import -v -file cert -storepass password Check error (Certificate reply and cert are the same)
testFail("", "-import -v -file cert -storepass password -keystore x.jks"); testFail("", "-import -v -file cert -storepass password -keystore x.jks");
assertTrue(ex.indexOf("Certificate reply and certificate in keystore are identical") != -1, ""); assertTrue(ex.indexOf("Certificate reply and certificate in keystore are identical") != -1);
// 14. keytool -printcert -file cert // 14. keytool -printcert -file cert
testOK("", "-printcert -file cert -keystore x.jks"); testOK("", "-printcert -file cert -keystore x.jks");
remove("cert"); remove("cert");
...@@ -875,26 +1218,26 @@ public class KeyToolTest { ...@@ -875,26 +1218,26 @@ public class KeyToolTest {
// 1. keytool -storepasswd -storepass password -new abc Check error (password too short) // 1. keytool -storepasswd -storepass password -new abc Check error (password too short)
testFail("", "-storepasswd -storepass password -new abc"); testFail("", "-storepasswd -storepass password -new abc");
assertTrue(ex.indexOf("New password must be at least 6 characters") != -1, ""); assertTrue(ex.indexOf("New password must be at least 6 characters") != -1);
// Changed, no NONE needed now // Changed, no NONE needed now
// 2. keytool -list -storetype PKCS11 Check error (-keystore must be NONE) // 2. keytool -list -storetype PKCS11 Check error (-keystore must be NONE)
//testFail("", "-list -storetype PKCS11"); //testFail("", "-list -storetype PKCS11");
//assertTrue(err.indexOf("keystore must be NONE") != -1, ""); //assertTrue(err.indexOf("keystore must be NONE") != -1);
// 3. keytool -storepasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation) // 3. keytool -storepasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation)
testFail("", "-storepasswd -storetype PKCS11 -keystore NONE"); testFail("", "-storepasswd -storetype PKCS11 -keystore NONE");
assertTrue(ex.indexOf("UnsupportedOperationException") != -1, ""); assertTrue(ex.indexOf("UnsupportedOperationException") != -1);
// 4. keytool -keypasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation) // 4. keytool -keypasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation)
testFail("", "-keypasswd -storetype PKCS11 -keystore NONE"); testFail("", "-keypasswd -storetype PKCS11 -keystore NONE");
assertTrue(ex.indexOf("UnsupportedOperationException") != -1, ""); assertTrue(ex.indexOf("UnsupportedOperationException") != -1);
// 5. keytool -list -protected -storepass password Check error (password can not be specified with -protected) // 5. keytool -list -protected -storepass password Check error (password can not be specified with -protected)
testFail("", "-list -protected -storepass password -keystore x.jks"); testFail("", "-list -protected -storepass password -keystore x.jks");
assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); assertTrue(ex.indexOf("if -protected is specified, then") != -1);
// 6. keytool -keypasswd -protected -keypass password Check error (password can not be specified with -protected) // 6. keytool -keypasswd -protected -keypass password Check error (password can not be specified with -protected)
testFail("", "-keypasswd -protected -keypass password -keystore x.jks"); testFail("", "-keypasswd -protected -keypass password -keystore x.jks");
assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); assertTrue(ex.indexOf("if -protected is specified, then") != -1);
// 7. keytool -keypasswd -protected -new password Check error (password can not be specified with -protected) // 7. keytool -keypasswd -protected -new password Check error (password can not be specified with -protected)
testFail("", "-keypasswd -protected -new password -keystore x.jks"); testFail("", "-keypasswd -protected -new password -keystore x.jks");
assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); assertTrue(ex.indexOf("if -protected is specified, then") != -1);
remove("x.jks"); remove("x.jks");
} }
...@@ -911,11 +1254,11 @@ public class KeyToolTest { ...@@ -911,11 +1254,11 @@ public class KeyToolTest {
testOK("", "-printcert -file genkey.cert"); testOK("", "-printcert -file genkey.cert");
testOK("", p11Arg + "-storepass test12 -selfcert -alias genkey -dname cn=selfCert"); testOK("", p11Arg + "-storepass test12 -selfcert -alias genkey -dname cn=selfCert");
testOK("", p11Arg + "-storepass test12 -list -alias genkey -v"); testOK("", p11Arg + "-storepass test12 -list -alias genkey -v");
assertTrue(out.indexOf("Owner: CN=selfCert") != -1, ""); assertTrue(out.indexOf("Owner: CN=selfCert") != -1);
//(check that cert subject DN is [cn=selfCert]) //(check that cert subject DN is [cn=selfCert])
testOK("", p11Arg + "-storepass test12 -delete -alias genkey"); testOK("", p11Arg + "-storepass test12 -delete -alias genkey");
testOK("", p11Arg + "-storepass test12 -list"); testOK("", p11Arg + "-storepass test12 -list");
assertTrue(out.indexOf("Your keystore contains 0 entries") != -1, ""); assertTrue(out.indexOf("Your keystore contains 0 entries") != -1);
//(check for empty database listing) //(check for empty database listing)
//Runtime.getRuntime().exec("/usr/ccs/bin/sccs unedit cert8.db key3.db"); //Runtime.getRuntime().exec("/usr/ccs/bin/sccs unedit cert8.db key3.db");
remove("genkey.cert"); remove("genkey.cert");
...@@ -943,6 +1286,15 @@ public class KeyToolTest { ...@@ -943,6 +1286,15 @@ public class KeyToolTest {
t.sqeTest(); t.sqeTest();
t.testAll(); t.testAll();
t.i18nTest(); t.i18nTest();
t.v3extTest("RSA");
t.v3extTest("DSA");
boolean testEC = true;
try {
KeyPairGenerator.getInstance("EC");
} catch (NoSuchAlgorithmException nae) {
testEC = false;
}
if (testEC) t.v3extTest("EC");
} }
if (System.getProperty("nss") != null) { if (System.getProperty("nss") != null) {
......
# #
# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. # Copyright 2006-2009 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,6 +25,8 @@ ...@@ -25,6 +25,8 @@
# @summary (almost) all keytool behaviors # @summary (almost) all keytool behaviors
# @author Weijun Wang # @author Weijun Wang
# #
# This test is only executed on several platforms
#
# set a few environment variables so that the shell-script can run stand-alone # set a few environment variables so that the shell-script can run stand-alone
# in the source directory # in the source directory
if [ "${TESTSRC}" = "" ] ; then if [ "${TESTSRC}" = "" ] ; then
...@@ -88,7 +90,7 @@ cp ${NSS}${FS}db${FS}secmod.db . ...@@ -88,7 +90,7 @@ cp ${NSS}${FS}db${FS}secmod.db .
chmod u+w key3.db chmod u+w key3.db
chmod u+w cert8.db chmod u+w cert8.db
echo | ${TESTJAVA}${FS}bin${FS}java -Dfile -Dnss \ echo | ${TESTJAVA}${FS}bin${FS}java -Dnss \
-Dnss.lib=${NSS}${FS}lib${FS}${PF}${FS}${LIBNAME} \ -Dnss.lib=${NSS}${FS}lib${FS}${PF}${FS}${LIBNAME} \
KeyToolTest KeyToolTest
status=$? status=$?
...@@ -99,8 +101,8 @@ rm -f key3.db ...@@ -99,8 +101,8 @@ rm -f key3.db
rm -f secmod.db rm -f secmod.db
rm HumanInputStream*.class rm HumanInputStream*.class
rm KeyToolTest.class rm KeyToolTest*.class
rm TestException.class rm TestException.class
exit $status exit $status
#
# Copyright 2009 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
# @summary (almost) all keytool behaviors
# @author Weijun Wang
#
# This test is always excecuted.
#
# set a few environment variables so that the shell-script can run stand-alone
# in the source directory
if [ "${TESTSRC}" = "" ] ; then
TESTSRC="."
fi
if [ "${TESTCLASSES}" = "" ] ; then
TESTCLASSES="."
fi
if [ "${TESTJAVA}" = "" ] ; then
JAVAC_CMD=`which javac`
TESTJAVA=`dirname $JAVAC_CMD`/..
fi
# set platform-dependent variables
OS=`uname -s`
case "$OS" in
Windows_* )
FS="\\"
;;
* )
FS="/"
;;
esac
${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}KeyToolTest.java || exit 10
echo | ${TESTJAVA}${FS}bin${FS}java -Dfile KeyToolTest
status=$?
rm HumanInputStream*.class
rm KeyToolTest*.class
rm TestException.class
exit $status
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册