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,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.console.core.keystore;
019    
020    import java.io.ByteArrayInputStream;
021    import java.io.ByteArrayOutputStream;
022    import java.io.File;
023    import java.io.FileInputStream;
024    import java.io.FileOutputStream;
025    import java.io.IOException;
026    import java.io.InputStream;
027    import java.math.BigInteger;
028    import java.security.KeyPair;
029    import java.security.KeyPairGenerator;
030    import java.security.KeyStore;
031    import java.security.KeyStoreException;
032    import java.security.NoSuchAlgorithmException;
033    import java.security.PrivateKey;
034    import java.security.PublicKey;
035    import java.security.cert.Certificate;
036    import java.security.cert.CertificateException;
037    import java.security.cert.CertificateFactory;
038    import java.security.cert.X509Certificate;
039    import java.util.ArrayList;
040    import java.util.Collection;
041    import java.util.Date;
042    import java.util.Enumeration;
043    import java.util.Hashtable;
044    import java.util.Iterator;
045    import java.util.List;
046    import java.util.Vector;
047    
048    import org.apache.commons.logging.Log;
049    import org.apache.commons.logging.LogFactory;
050    import org.apache.geronimo.gbean.GBeanInfo;
051    import org.apache.geronimo.gbean.GBeanInfoBuilder;
052    import org.apache.geronimo.gbean.GBeanLifecycle;
053    import org.apache.geronimo.gbean.WaitingException;
054    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
055    import org.apache.geronimo.system.serverinfo.ServerInfo;
056    import org.apache.geronimo.crypto.asn1.ASN1Set;
057    import org.apache.geronimo.crypto.asn1.DEROutputStream;
058    import org.apache.geronimo.crypto.asn1.x509.X509Name;
059    import org.apache.geronimo.crypto.encoders.Base64;
060    import org.apache.geronimo.crypto.jce.PKCS10CertificationRequest;
061    import org.apache.geronimo.crypto.jce.X509Principal;
062    import org.apache.geronimo.crypto.jce.X509V1CertificateGenerator;
063    
064    public class KeyStoreGBean implements GBeanLifecycle {
065    
066        private static Log log = LogFactory.getLog(KeyStoreGBean.class);
067    
068        private String keyStoreType;
069    
070        private String keyStoreProvider;
071    
072        private String keyStoreLocation;
073    
074        private String keyStorePassword;
075    
076        private String keyPassword;
077    
078        private KeyStore keystore;
079    
080        // Used to resolve keystore path.
081        private ServerInfo serverInfo;
082    
083        public KeyStoreGBean() {
084        }
085    
086        public void doStart() throws WaitingException, Exception {
087    
088            //Security.addProvider(new BouncyCastleProvider());
089    
090            this.keystore = KeyStore.getInstance(keyStoreType);
091    
092            boolean keystoreExistsFlag = true;
093            InputStream is = null;
094    
095            try {
096                File keyStore = serverInfo.resolveServer(this.keyStoreLocation);
097                log.debug("loading keystore from " + keyStore);
098                is = new java.io.FileInputStream(keyStore);
099                this.keystore.load(is, this.keyStorePassword.toCharArray());
100            } catch (java.io.FileNotFoundException e) {
101                keystoreExistsFlag = false;
102            } finally {
103                try {
104                    if (is != null) {
105                        is.close();
106                    }
107                } catch (Exception e) {
108                }
109            }
110    
111            if (keystoreExistsFlag == false) {
112                keystore.load(null, keyStorePassword.toCharArray());
113            }
114        }
115    
116        public void doStop() throws WaitingException, Exception {
117        }
118    
119        public void doFail() {
120        }
121    
122        public void setKeyStoreType(String keyStoreType) {
123            this.keyStoreType = keyStoreType;
124        }
125    
126        public String getKeyStoreType() {
127            return this.keyStoreType;
128        }
129    
130        public void setKeyStoreProvider(String keyStoreProvider) {
131            this.keyStoreProvider = keyStoreProvider;
132        }
133    
134        public String getKeyStoreProvider() {
135            return this.keyStoreProvider;
136        }
137    
138        public void setKeyStoreLocation(String keyStoreLocation) {
139            this.keyStoreLocation = keyStoreLocation;
140        }
141    
142        public ServerInfo getServerInfo() {
143            return serverInfo;
144        }
145    
146        public void setServerInfo(ServerInfo serverInfo) {
147            this.serverInfo = serverInfo;
148        }
149    
150        public String getKeyStoreLocation() {
151            return this.keyStoreLocation;
152        }
153    
154        public void setKeyStorePassword(String keyStorePassword) {
155            this.keyStorePassword = keyStorePassword;
156        }
157    
158        public String getKeyStorePassword() {
159            return this.keyStorePassword;
160        }
161    
162        public void setKeyPassword(String keyPassword) {
163            this.keyPassword = keyPassword;
164        }
165    
166        public String getKeyPassword() {
167            return this.keyPassword;
168        }
169    
170        public int getKeyStoreSize() throws KeyStoreException {
171            return this.keystore.size();
172        }
173    
174        public KeyEntryInfo getKeyEntryInfo(String alias) throws KeyStoreException {
175            KeyEntryInfo info = null;
176    
177            if (this.keystore.isCertificateEntry(alias)) {
178                // certificate entry
179                info = new KeyEntryInfo(alias, "trusted certificate", keystore
180                        .getCreationDate(alias));
181            } else if (this.keystore.isKeyEntry(alias)) {
182                // private key entry
183                info = new KeyEntryInfo(alias, "private key", keystore
184                        .getCreationDate(alias));
185            } else {
186                throw new KeyStoreException("invalid key entry type");
187            }
188            return info;
189        }
190    
191        public List getKeyStoreEntries() throws KeyStoreException {
192            List list = new ArrayList();
193    
194            Enumeration aliases = this.keystore.aliases();
195    
196            while (aliases.hasMoreElements()) {
197                String alias = (String) aliases.nextElement();
198                list.add(getKeyEntryInfo(alias));
199            }
200            return list;
201        }
202    
203        public Certificate[] getCertificateChain(String alias)
204                throws KeyStoreException {
205            Certificate[] certs = null;
206    
207            if (keystore.isCertificateEntry(alias)) {
208                Certificate cert = keystore.getCertificate(alias);
209                certs = new Certificate[1];
210                certs[0] = cert;
211            } else if (keystore.isKeyEntry(alias)) {
212                certs = keystore.getCertificateChain(alias);
213            } else if (keystore.containsAlias(alias)) {
214                throw new KeyStoreException("Unsupported key-store-entry, alias = "
215                        + alias);
216            } else {
217                throw new KeyStoreException(
218                        "Key-store-entry alias not found, alias = " + alias);
219            }
220    
221            return certs;
222        }
223    
224        public String generateCSR(String alias) throws Exception {
225    
226            // find certificate by alias
227            X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
228    
229            // find private key by alias
230            PrivateKey key = (PrivateKey) keystore.getKey(alias, keyPassword.toCharArray());
231    
232            // generate csr
233            String csr = generateCSR(cert, key);
234            return csr;
235        }
236    
237        public String generateCSR(X509Certificate cert, PrivateKey signingKey)
238                throws Exception {
239    
240            String sigalg = cert.getSigAlgName();
241            X509Name subject = new X509Name(cert.getSubjectDN().toString());
242            PublicKey publicKey = cert.getPublicKey();
243            ASN1Set attributes = null;
244    
245            PKCS10CertificationRequest csr = new PKCS10CertificationRequest(sigalg,
246                    subject, publicKey, attributes, signingKey);
247    
248            if (!csr.verify()) {
249                throw new KeyStoreException("CSR verification failed");
250            }
251    
252            ByteArrayOutputStream os = new ByteArrayOutputStream();
253            DEROutputStream deros = new DEROutputStream(os);
254            deros.writeObject(csr.getDERObject());
255            String b64 = new String(Base64.encode(os.toByteArray()));
256    
257            final String BEGIN_CERT_REQ = "-----BEGIN CERTIFICATE REQUEST-----";
258            final String END_CERT_REQ = "-----END CERTIFICATE REQUEST-----";
259            final int CERT_REQ_LINE_LENGTH = 70;
260    
261            StringBuffer sbuf = new StringBuffer(BEGIN_CERT_REQ).append('\n');
262    
263            int idx = 0;
264            while (idx < b64.length()) {
265    
266                int len = (idx + CERT_REQ_LINE_LENGTH > b64.length()) ? b64
267                        .length()
268                        - idx : CERT_REQ_LINE_LENGTH;
269    
270                String chunk = b64.substring(idx, idx + len);
271    
272                sbuf.append(chunk).append('\n');
273                idx += len;
274            }
275    
276            sbuf.append(END_CERT_REQ);
277            return sbuf.toString();
278        }
279    
280        public void generateKeyPair(String alias, String keyalg, Integer keysize,
281                String sigalg, Integer validity, String cn, String ou, String o,
282                String l, String st, String c)
283                throws java.security.NoSuchAlgorithmException,
284                java.security.KeyStoreException, java.security.SignatureException,
285                java.security.InvalidKeyException,
286                java.security.cert.CertificateException, java.io.IOException {
287    
288            KeyPairGenerator kpgen = KeyPairGenerator.getInstance(keyalg);
289    
290            kpgen.initialize(keysize.intValue());
291    
292            KeyPair keyPair = kpgen.generateKeyPair();
293    
294            X509Certificate cert = generateCert(keyPair.getPublic(), keyPair
295                    .getPrivate(), sigalg, validity.intValue(), cn, ou, o, l, st, c);
296    
297            keystore.setKeyEntry(alias, keyPair.getPrivate(), keyPassword.toCharArray(), new Certificate[] { cert });
298    
299            saveKeyStore();
300        }
301    
302        public void saveKeyStore() throws java.io.IOException,
303                java.security.KeyStoreException,
304                java.security.cert.CertificateException,
305                java.security.NoSuchAlgorithmException {
306    
307            FileOutputStream os = null;
308    
309            try {
310                File keyStore = serverInfo.resolveServer(this.keyStoreLocation);
311                os = new FileOutputStream(keyStore);
312    
313                keystore.store(os, keyStorePassword.toCharArray());
314            } finally {
315                if (os != null) {
316                    try {
317                        os.close();
318                    } catch (Exception ex) {
319                    }
320                }
321            }
322        }
323    
324        public X509Certificate generateCert(PublicKey publicKey,
325                PrivateKey privateKey, String sigalg, int validity, String cn,
326                String ou, String o, String l, String st, String c)
327                throws java.security.SignatureException,
328                java.security.InvalidKeyException {
329            X509V1CertificateGenerator certgen = new X509V1CertificateGenerator();
330    
331            // issuer dn
332            Vector order = new Vector();
333            Hashtable attrmap = new Hashtable();
334    
335            if (cn != null) {
336                attrmap.put(X509Principal.CN, cn);
337                order.add(X509Principal.CN);
338            }
339    
340            if (ou != null) {
341                attrmap.put(X509Principal.OU, ou);
342                order.add(X509Principal.OU);
343            }
344    
345            if (o != null) {
346                attrmap.put(X509Principal.O, o);
347                order.add(X509Principal.O);
348            }
349    
350            if (l != null) {
351                attrmap.put(X509Principal.L, l);
352                order.add(X509Principal.L);
353            }
354    
355            if (st != null) {
356                attrmap.put(X509Principal.ST, st);
357                order.add(X509Principal.ST);
358            }
359    
360            if (c != null) {
361                attrmap.put(X509Principal.C, c);
362                order.add(X509Principal.C);
363            }
364    
365            X509Principal issuerDN = new X509Principal(order, attrmap);
366            certgen.setIssuerDN(issuerDN);
367    
368            // validity
369            long curr = System.currentTimeMillis();
370            long untill = curr + (long) validity * 24 * 60 * 60 * 1000;
371    
372            certgen.setNotBefore(new Date(curr));
373            certgen.setNotAfter(new Date(untill));
374    
375            // subject dn
376            certgen.setSubjectDN(issuerDN);
377    
378            // public key
379            certgen.setPublicKey(publicKey);
380    
381            // signature alg
382            certgen.setSignatureAlgorithm(sigalg);
383    
384            // serial number
385            certgen.setSerialNumber(new BigInteger(String.valueOf(curr)));
386    
387            // make certificate
388            X509Certificate cert = certgen.generateX509Certificate(privateKey);
389            return cert;
390        }
391    
392        public void importTrustedX509Certificate(String alias, String certfile)
393                throws java.io.FileNotFoundException,
394                java.security.cert.CertificateException,
395                java.security.KeyStoreException, java.io.IOException,
396                java.security.NoSuchAlgorithmException,
397                java.security.NoSuchProviderException {
398            InputStream is = null;
399    
400            try {
401                if (keyStoreProvider.equalsIgnoreCase("Default"))
402                {
403                    keyStoreProvider = new String(System.getProperty("java.security.Provider"));
404                }
405                CertificateFactory cf = CertificateFactory.getInstance("X.509", keyStoreProvider);
406    
407                is = new FileInputStream(certfile);
408                Certificate cert = cf.generateCertificate(is);
409    
410                if(alias == null || alias.equals("")) {
411                    // Generate an alias for this certificate
412                    X509Certificate xcert = (X509Certificate)cert;
413                    alias = xcert.getIssuerDN().toString()+":"+xcert.getSerialNumber();
414                }
415    
416                keystore.setCertificateEntry(alias, cert);
417    
418                saveKeyStore();
419            } finally {
420                if (is != null) {
421                    try {
422                        is.close();
423                    } catch (Exception e) {
424                    }
425                }
426            }
427        }
428    
429        public void importPKCS7Certificate(String alias, String certbuf)
430                throws java.security.cert.CertificateException,
431                java.security.NoSuchProviderException,
432                java.security.KeyStoreException,
433                java.security.NoSuchAlgorithmException,
434                java.security.UnrecoverableKeyException, java.io.IOException {
435    
436            InputStream is = null;
437    
438            try {
439                is = new ByteArrayInputStream(certbuf.getBytes());
440                importPKCS7Certificate(alias, is);
441            } finally {
442                if (is != null) {
443                    try {
444                        is.close();
445                    } catch (Exception e) {
446                    }
447                }
448            }
449        }
450    
451        public void importPKCS7Certificate(String alias, InputStream is)
452                throws java.security.cert.CertificateException,
453                java.security.NoSuchProviderException,
454                java.security.KeyStoreException,
455                java.security.NoSuchAlgorithmException,
456                java.security.UnrecoverableKeyException, java.io.IOException {
457    
458            if (keyStoreProvider.equalsIgnoreCase("Default"))
459            {
460                keyStoreProvider = new String(System.getProperty("java.security.Provider"));
461            }
462            CertificateFactory cf = CertificateFactory.getInstance("X.509",keyStoreProvider);
463            Collection certcoll = cf.generateCertificates(is);
464    
465            Certificate[] chain = new Certificate[certcoll.size()];
466    
467            Iterator iter = certcoll.iterator();
468            for (int i = 0; iter.hasNext(); i++) {
469                chain[i] = (Certificate) iter.next();
470            }
471    
472            char[] password = keyPassword.toCharArray();
473            keystore.setKeyEntry(alias, keystore.getKey(alias, password), password,
474                    chain);
475    
476            saveKeyStore();
477        }
478    
479        public void deleteEntry(String alias)
480                throws KeyStoreException,
481                CertificateException,
482                NoSuchAlgorithmException, IOException {
483    
484            keystore.deleteEntry(alias);
485    
486            saveKeyStore();
487        }
488    
489    
490        public static final GBeanInfo GBEAN_INFO;
491    
492        static {
493            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(KeyStoreGBean.class);
494    
495            infoFactory.addAttribute("keyStoreType", String.class, true);
496            infoFactory.addAttribute("keyStoreProvider", String.class, true);
497            infoFactory.addAttribute("keyStoreLocation", String.class, true);
498            infoFactory.addAttribute("keyStorePassword", String.class, true);
499            infoFactory.addAttribute("keyPassword", String.class, true);
500    
501            infoFactory.addReference("serverInfo", ServerInfo.class, NameFactory.GERONIMO_SERVICE);
502    
503            infoFactory.addOperation("getKeyEntryInfo",
504                    new Class[] { String.class });
505            infoFactory.addOperation("getKeyStoreSize");
506            infoFactory.addOperation("getKeyStoreEntries");
507            infoFactory.addOperation("getCertificateChain",
508                    new Class[] { String.class });
509            infoFactory.addOperation("generateCSR", new Class[] { String.class });
510    
511            infoFactory.addOperation("generateKeyPair", new Class[] { String.class,
512                    String.class, Integer.class, String.class, Integer.class,
513                    String.class, String.class, String.class, String.class,
514                    String.class, String.class });
515    
516            infoFactory.addOperation("importTrustedX509Certificate", new Class[] {
517                    String.class, String.class });
518            infoFactory.addOperation("importPKCS7Certificate", new Class[] {
519                    String.class, String.class });
520            infoFactory.addOperation("deleteEntry", new Class[] {String.class });
521    
522            GBEAN_INFO = infoFactory.getBeanInfo();
523        }
524    
525        public static GBeanInfo getGBeanInfo() {
526            return GBEAN_INFO;
527        }
528    
529    }