Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / tools / gnu / classpath / tools / keytool / CertReqCmd.java
blob0c64246e8c99af6007e474dbe0eb5667ae0cda7b
1 /* CertReqCmd.java -- The certreq command handler of the keytool
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.classpath.tools.keytool;
41 import gnu.java.security.OID;
42 import gnu.java.security.der.BitString;
43 import gnu.java.security.der.DER;
44 import gnu.java.security.der.DERReader;
45 import gnu.java.security.der.DERValue;
46 import gnu.java.security.der.DERWriter;
47 import gnu.java.security.util.Base64;
49 import java.io.ByteArrayOutputStream;
50 import java.io.IOException;
51 import java.io.PrintWriter;
52 import java.math.BigInteger;
53 import java.security.InvalidKeyException;
54 import java.security.Key;
55 import java.security.KeyStoreException;
56 import java.security.NoSuchAlgorithmException;
57 import java.security.PrivateKey;
58 import java.security.PublicKey;
59 import java.security.SignatureException;
60 import java.security.UnrecoverableKeyException;
61 import java.security.cert.Certificate;
62 import java.security.cert.X509Certificate;
63 import java.util.ArrayList;
64 import java.util.logging.Logger;
66 import javax.security.auth.callback.UnsupportedCallbackException;
67 import javax.security.auth.x500.X500Principal;
69 /**
70 * The <b>-certreq</b> keytool command handler is used to generate a Certificate
71 * Signing Request (CSR) in PKCS#10 format.
72 * <p>
73 * The ASN.1 specification of a CSR, as stated in RFC-2986 is as follows:
74 * <p>
75 * <pre>
76 * CertificationRequest ::= SEQUENCE {
77 * certificationRequestInfo CertificationRequestInfo,
78 * signatureAlgorithm AlgorithmIdentifier,
79 * signature BIT STRING
80 * }
82 * CertificationRequestInfo ::= SEQUENCE {
83 * version INTEGER -- v1(0)
84 * subject Name,
85 * subjectPKInfo SubjectPublicKeyInfo,
86 * attributes [0] IMPLICIT Attributes -- see note later
87 * }
89 * SubjectPublicKeyInfo ::= SEQUENCE {
90 * algorithm AlgorithmIdentifier,
91 * subjectPublicKey BIT STRING
92 * }
93 * </pre>
94 * <b>IMPORTANT</b>: Some documentation (e.g. RSA examples) claims that the
95 * <code>attributes</code> field is <i>OPTIONAL</i> while <i>RFC-2986</i>
96 * implies the opposite. This implementation considers this field, by default,
97 * as <i>OPTIONAL</i>, unless the option <code>-attributes</code> is included
98 * on the command line.
99 * <p>
100 * Possible options for this command are:
101 * <p>
102 * <dl>
103 * <dt>-alias ALIAS</dt>
104 * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
105 * Certificate</i>, in a key store is uniquely identified by a user-defined
106 * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
107 * when referring to an entry in the key store. Unless specified otherwise,
108 * a default value of <code>mykey</code> shall be used when this option is
109 * omitted from the command line.
110 * <p></dd>
112 * <dt>-sigalg ALGORITHM</dt>
113 * <dd>The canonical name of the digital signature algorithm to use for
114 * signing the certificate. If this option is omitted, a default value will
115 * be chosen based on the type of the private key associated with the
116 * designated <i>Alias</i>. If the private key is a <code>DSA</code> one,
117 * the value for the signature algorithm will be <code>SHA1withDSA</code>.
118 * If on the other hand the private key is an <code>RSA</code> one, then
119 * the tool will use <code>MD5withRSA</code> as the signature algorithm.
120 * <p></dd>
122 * <dt>-file FILE_NAME</dt>
124 * <dt>-keypass PASSWORD</dt>
126 * <dt>-storetype STORE_TYP}</dt>
127 * <dd>Use this option to specify the type of the key store to use. The
128 * default value, if this option is omitted, is that of the property
129 * <code>keystore.type</code> in the security properties file, which is
130 * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
131 * static method.
132 * <p></dd>
134 * <dt>-keystore URL</dt>
135 * <dd>Use this option to specify the location of the key store to use.
136 * The default value is a file {@link java.net.URL} referencing the file
137 * named <code>.keystore</code> located in the path returned by the call to
138 * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
139 * as argument.
140 * <p>
141 * If a URL was specified, but was found to be malformed --e.g. missing
142 * protocol element-- the tool will attempt to use the URL value as a file-
143 * name (with absolute or relative path-name) of a key store --as if the
144 * protocol was <code>file:</code>.
145 * <p></dd>
147 * <dt>-storepass PASSWORD</dt>
148 * <dd>Use this option to specify the password protecting the key store. If
149 * this option is omitted from the command line, you will be prompted to
150 * provide a password.
151 * <p></dd>
153 * <dt>-provider PROVIDER_CLASS_NAME</dt>
154 * <dd>A fully qualified class name of a Security Provider to add to the
155 * current list of Security Providers already installed in the JVM in-use.
156 * If a provider class is specified with this option, and was successfully
157 * added to the runtime --i.e. it was not already installed-- then the tool
158 * will attempt to removed this Security Provider before exiting.
159 * <p></dd>
161 * <dt>-v</dt>
162 * <dd>Use this option to enable more verbose output.
163 * <p></dd>
165 * <dt>-attributes</dt>
166 * <dd>Use this option to force the tool to encode a NULL DER value in the
167 * CSR as the value of the Attributes field.</dd>
168 * </dl>
170 class CertReqCmd extends Command
172 private static final Logger log = Logger.getLogger(CertReqCmd.class.getName());
173 private String _alias;
174 private String _sigAlgorithm;
175 private String _certReqFileName;
176 private String _password;
177 private String _ksType;
178 private String _ksURL;
179 private String _ksPassword;
180 private String _providerClassName;
181 private boolean nullAttributes;
183 // default 0-arguments constructor
185 // public setters -----------------------------------------------------------
187 /** @param alias the alias to use. */
188 public void setAlias(String alias)
190 this._alias = alias;
194 * @param algorithm the canonical name of the digital signature algorithm to
195 * use.
197 public void setSigalg(String algorithm)
199 this._sigAlgorithm = algorithm;
202 /** @param pathName the fully qualified path name of the file to process. */
203 public void setFile(String pathName)
205 this._certReqFileName = pathName;
208 /** @param password the (private) key password to use. */
209 public void setKeypass(String password)
211 this._password = password;
214 /** @param type the key-store type to use. */
215 public void setStoretype(String type)
217 this._ksType = type;
220 /** @param url the key-store URL to use. */
221 public void setKeystore(String url)
223 this._ksURL = url;
226 /** @param password the key-store password to use. */
227 public void setStorepass(String password)
229 this._ksPassword = password;
232 /** @param className a security provider fully qualified class name to use. */
233 public void setProvider(String className)
235 this._providerClassName = className;
239 * @param flag whether to use, or not, a <code>NULL</code> DER value for
240 * the certificate's Attributes field.
242 public void setAttributes(String flag)
244 this.nullAttributes = Boolean.valueOf(flag).booleanValue();
247 // life-cycle methods -------------------------------------------------------
249 int processArgs(String[] args, int i)
251 int limit = args.length;
252 String opt;
253 while (++i < limit)
255 opt = args[i];
256 log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
257 if (opt == null || opt.length() == 0)
258 continue;
260 if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
261 _alias = args[++i];
262 else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM //$NON-NLS-1$
263 _sigAlgorithm = args[++i];
264 else if ("-file".equals(opt)) // -file FILE_NAME //$NON-NLS-1$
265 _certReqFileName = args[++i];
266 else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
267 _password = args[++i];
268 else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
269 _ksType = args[++i];
270 else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
271 _ksURL = args[++i];
272 else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
273 _ksPassword = args[++i];
274 else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
275 _providerClassName = args[++i];
276 else if ("-v".equals(opt)) //$NON-NLS-1$
277 verbose = true;
278 else if ("-attributes".equals(opt)) //$NON-NLS-1$
279 nullAttributes = true;
280 else
281 break;
284 return i;
287 void setup() throws Exception
289 setOutputStreamParam(_certReqFileName);
290 setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
291 setAliasParam(_alias);
292 setKeyPasswordNoPrompt(_password);
293 // setSignatureAlgorithm(_sigAlgorithm);
295 log.finer("-certreq handler will use the following options:"); //$NON-NLS-1$
296 log.finer(" -alias=" + alias); //$NON-NLS-1$
297 log.finer(" -sigalg=" + _sigAlgorithm); //$NON-NLS-1$
298 log.finer(" -file=" + _certReqFileName); //$NON-NLS-1$
299 log.finer(" -keypass=" + _password); //$NON-NLS-1$
300 log.finer(" -storetype=" + storeType); //$NON-NLS-1$
301 log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
302 log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
303 log.finer(" -provider=" + provider); //$NON-NLS-1$
304 log.finer(" -v=" + verbose); //$NON-NLS-1$
305 log.finer(" -attributes=" + nullAttributes); //$NON-NLS-1$
308 void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
309 UnsupportedCallbackException, UnrecoverableKeyException,
310 InvalidKeyException, SignatureException
312 log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
314 // 1. get the key entry and certificate chain associated to alias
315 Key privateKey = getAliasPrivateKey();
316 Certificate[] chain = store.getCertificateChain(alias);
318 // 2. get alias's DN and public key to use in the CSR
319 X509Certificate bottomCertificate = (X509Certificate) chain[0];
320 X500Principal aliasName = bottomCertificate.getIssuerX500Principal();
321 PublicKey publicKey = bottomCertificate.getPublicKey();
323 // 3. generate the CSR
324 setSignatureAlgorithmParam(_sigAlgorithm, privateKey);
325 byte[] derBytes = getCSR(aliasName, publicKey, (PrivateKey) privateKey);
327 // 4. encode it in base-64 and write it to outStream
328 String encoded = Base64.encode(derBytes, 0, derBytes.length, true);
329 PrintWriter writer = new PrintWriter(outStream, true);
330 writer.println("-----BEGIN NEW CERTIFICATE REQUEST-----"); //$NON-NLS-1$
331 writer.println(encoded);
332 writer.println("-----END NEW CERTIFICATE REQUEST-----"); //$NON-NLS-1$
334 if (verbose)
336 if (! systemOut)
337 System.out.println(Messages.getFormattedString("CertReqCmd.27", //$NON-NLS-1$
338 _certReqFileName));
339 System.out.println(Messages.getString("CertReqCmd.28")); //$NON-NLS-1$
342 writer.close();
344 log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
347 // own methods --------------------------------------------------------------
350 * @param aliasName
351 * @param publicKey
352 * @param privateKey
353 * @return the DER encoded Certificate Signing Request.
354 * @throws IOException
355 * @throws InvalidKeyException
356 * @throws SignatureException
358 private byte[] getCSR(X500Principal aliasName, PublicKey publicKey,
359 PrivateKey privateKey)
360 throws IOException, InvalidKeyException, SignatureException
362 DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
363 DERValue derSubject = new DERReader(aliasName.getEncoded()).read();
364 DERValue derSubjectPKInfo = new DERReader(publicKey.getEncoded()).read();
365 byte[] b = nullAttributes ? new byte[] { 0x05, 0x00 } : new byte[0];
366 DERValue derAttributes = new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0,
367 b.length, b, null);
368 ArrayList certRequestInfo = new ArrayList(4);
369 certRequestInfo.add(derVersion);
370 certRequestInfo.add(derSubject);
371 certRequestInfo.add(derSubjectPKInfo);
372 certRequestInfo.add(derAttributes);
373 DERValue derCertRequestInfo = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
374 certRequestInfo);
376 OID sigAlgorithmID = getSignatureAlgorithmOID();
377 DERValue derSigAlgorithmID = new DERValue(DER.OBJECT_IDENTIFIER,
378 sigAlgorithmID);
379 ArrayList sigAlgorithm = new ArrayList(2);
380 sigAlgorithm.add(derSigAlgorithmID);
381 if (! sigAlgorithmID.equals(Command.SHA1_WITH_DSA)) // it's an RSA-based
382 sigAlgorithm.add(new DERValue(DER.NULL, null));
384 sigAlgorithm.trimToSize();
385 DERValue derSignatureAlgorithm = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
386 sigAlgorithm);
388 signatureAlgorithm.initSign(privateKey);
389 signatureAlgorithm.update(derCertRequestInfo.getEncoded());
390 byte[] sigBytes = signatureAlgorithm.sign();
391 DERValue derSignature = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
393 ArrayList csr = new ArrayList(3);
394 csr.add(derCertRequestInfo);
395 csr.add(derSignatureAlgorithm);
396 csr.add(derSignature);
397 DERValue derCSR = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, csr);
399 ByteArrayOutputStream baos = new ByteArrayOutputStream();
400 DERWriter.write(baos, derCSR);
401 byte[] result = baos.toByteArray();
403 return result;