001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014: * License for the specific language governing permissions and limitations under
015: * the License.
016: */
017:
018: package org.apache.harmony.tools.keytool;
019:
020: import java.io.BufferedOutputStream;
021: import java.io.File;
022: import java.io.FileOutputStream;
023: import java.io.IOException;
024: import java.io.OutputStream;
025: import java.security.InvalidKeyException;
026: import java.security.KeyStore;
027: import java.security.KeyStoreException;
028: import java.security.NoSuchAlgorithmException;
029: import java.security.NoSuchProviderException;
030: import java.security.PrivateKey;
031: import java.security.PublicKey;
032: import java.security.Signature;
033: import java.security.SignatureException;
034: import java.security.UnrecoverableKeyException;
035: import java.security.cert.CertificateException;
036: import java.security.cert.X509Certificate;
037: import java.util.Vector;
038:
039: import org.apache.harmony.luni.util.Base64;
040: import org.apache.harmony.security.pkcs10.CertificationRequest;
041: import org.apache.harmony.security.pkcs10.CertificationRequestInfo;
042: import org.apache.harmony.security.x501.Name;
043: import org.apache.harmony.security.x509.AlgorithmIdentifier;
044: import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
045:
046: /**
047: * Class for generating X.509 Certificate Signing Requests (CSRs). The generated
048: * certificate request is printed to a file, if its name is supplied in param,
049: * or otherwise printed to stdout.
050: */
051: public class CSRGenerator {
052: /**
053: * Generates a Certificate Signing Request (CSR). The request is generated
054: * based on data taken from keystore entry associated with alias given in
055: * parameter param. The certificate request is printed to a file, if its
056: * name is supplied in param, or otherwise printed to stdout.
057: *
058: * @param param
059: * @throws KeyStoreException
060: * @throws UnrecoverableKeyException
061: * @throws NoSuchAlgorithmException
062: * @throws IOException
063: * @throws InvalidKeyException
064: * @throws SignatureException
065: * @throws NoSuchProviderException
066: * @throws KeytoolException
067: * @throws CertificateException
068: */
069: static void certReq(KeytoolParameters param)
070: throws KeyStoreException, NoSuchAlgorithmException,
071: UnrecoverableKeyException, IOException,
072: InvalidKeyException, SignatureException,
073: NoSuchProviderException, KeytoolException,
074: CertificateException {
075:
076: KeyStore keyStore = param.getKeyStore();
077: String alias = param.getAlias();
078:
079: if (!keyStore.entryInstanceOf(alias,
080: KeyStore.PrivateKeyEntry.class)) {
081: throw new KeytoolException(
082: "Failed to generate a certificate request. \n"
083: + "Entry <" + alias
084: + "> is not a private key entry. ");
085: }
086:
087: // get the existing certificate and keys associated with the alias
088: X509Certificate cert = (X509Certificate) keyStore
089: .getCertificate(param.getAlias());
090: PrivateKey privateKey;
091: try {
092: privateKey = (PrivateKey) keyStore.getKey(param.getAlias(),
093: param.getKeyPass());
094: } catch (NoSuchAlgorithmException e) {
095: throw new NoSuchAlgorithmException(
096: "Cannot find the algorithm to recover the key. ", e);
097: }
098: PublicKey publicKey = cert.getPublicKey();
099:
100: Name distinguishedName;
101: try {
102: distinguishedName = new Name(cert.getSubjectDN().getName());
103: } catch (IOException e) {
104: throw (IOException) new IOException(
105: "Failed to generate a distinguished name. ")
106: .initCause(e);
107: }
108:
109: SubjectPublicKeyInfo subjectPublicKeyInfo = null;
110: try {
111: subjectPublicKeyInfo = (SubjectPublicKeyInfo) SubjectPublicKeyInfo.ASN1
112: .decode(publicKey.getEncoded());
113: } catch (IOException e) {
114: throw (IOException) new IOException(
115: "Failed to decode SubjectPublicKeyInfo. ")
116: .initCause(e);
117: }
118:
119: // generate CertificationRequestInfo based on data taken from
120: // the existing certificate.
121: CertificationRequestInfo certReqInfo = new CertificationRequestInfo(
122: cert.getVersion(), distinguishedName,
123: subjectPublicKeyInfo,
124: // attributes
125: new Vector());
126: byte[] infoEncoding = certReqInfo.getEncoded();
127:
128: // generate the signature
129: String sigAlgName = (param.getSigAlg() != null) ? param
130: .getSigAlg() : cert.getSigAlgName();
131:
132: Signature sig;
133: String sigProvider = (param.getSigProvider() != null) ? param
134: .getSigProvider() : param.getProvider();
135: try {
136: sig = (sigProvider != null) ? Signature.getInstance(
137: sigAlgName, sigProvider) : Signature
138: .getInstance(sigAlgName);
139: } catch (NoSuchAlgorithmException e) {
140: throw new NoSuchAlgorithmException("The algorithm "
141: + sigAlgName + " is not found in the environment.",
142: e);
143: } catch (NoSuchProviderException e) {
144: throw (NoSuchProviderException) new NoSuchProviderException(
145: "The provider " + sigProvider
146: + " is not found in the environment.")
147: .initCause(e);
148: }
149:
150: try {
151: sig.initSign(privateKey);
152: } catch (InvalidKeyException e) {
153: throw new InvalidKeyException(
154: "The private key used to generate the signature is invalid.",
155: e);
156: }
157:
158: byte[] signatureValue;
159: try {
160: sig.update(infoEncoding, 0, infoEncoding.length);
161: signatureValue = sig.sign();
162: } catch (SignatureException e) {
163: throw new SignatureException(
164: "Failed to sign the certificate. ", e);
165: }
166:
167: // generating the request
168: CertificationRequest certReq = new CertificationRequest(
169: certReqInfo, new AlgorithmIdentifier(cert
170: .getSigAlgOID()), signatureValue);
171: byte[] certReqEncoding = certReq.getEncoded();
172:
173: OutputStream output;
174: // if no file name is given, output to System.out
175: String fileName = param.getFileName();
176: if (fileName == null) {
177: output = System.out;
178: } else { // output to a file if the name is supplied
179: File file = new File(fileName);
180: // the file will be created if it doesn't already exist.
181: // If it already exists and is not a file, then an IOException will
182: // be thrown.
183: file.createNewFile();
184:
185: output = new BufferedOutputStream(
186: new FileOutputStream(file));
187: }
188:
189: output.write("-----BEGIN NEW CERTIFICATE REQUEST-----\n"
190: .getBytes());
191: output.write(Base64.encode(certReqEncoding, "ISO-8859-1")
192: .getBytes());
193: output.write("\n-----END NEW CERTIFICATE REQUEST-----\n"
194: .getBytes());
195: output.flush();
196:
197: if (param.isVerbose() && fileName != null) {
198: System.out
199: .println("The certificate request is stored in file <"
200: + fileName + ">.");
201: }
202: }
203: }
|