Java tutorial
/** * Copyright 2010 Roman Kisilenko * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package me.it_result.ca.bouncycastle; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import me.it_result.ca.AlreadyInitializedException; import me.it_result.ca.CAClient; import me.it_result.ca.CAException; import me.it_result.ca.CertificateParameters; import me.it_result.ca.DuplicateSubjectException; import me.it_result.ca.InvalidCAException; import me.it_result.ca.InvalidCertificateKeyException; import me.it_result.ca.NotInitializedException; import me.it_result.ca.db.Database; import org.bouncycastle.jce.PKCS10CertificationRequest; /** * @author roman * */ public class BouncyCAClient extends BouncyCABase implements CAClient { private int selfSignedCertificateValidityDays; public BouncyCAClient(Database database, String keyAlgorithm, int keyBits, int selfSignedCertificateValidityDays, String keystorePassword, String signatureAlgorithm, ProfileRegistry profiles) { super(database, keyAlgorithm, keyBits, keystorePassword, signatureAlgorithm, profiles); this.selfSignedCertificateValidityDays = selfSignedCertificateValidityDays; } /* (non-Javadoc) * @see me.it_result.ca.CAClient#initialize(java.security.cert.X509Certificate) */ @Override public synchronized void initialize(X509Certificate caCertificate) throws CAException { ensureNotInitialized(); try { KeyStore keyStore = loadKeystore(); keyStore.setCertificateEntry(CA_ALIAS, caCertificate); saveKeystore(keyStore); } catch (Exception e) { throw new CAException(e); } } private void ensureNotInitialized() throws CAException { if (isInitialized()) throw new AlreadyInitializedException("CA already initialized"); } /* (non-Javadoc) * @see me.it_result.ca.CAClient#isInitialized() */ @Override public synchronized boolean isInitialized() { try { KeyStore keyStore = loadKeystore(); return keyStore.containsAlias(CA_ALIAS) && keyStore.isCertificateEntry(CA_ALIAS); } catch (Exception e) { return false; } } /* (non-Javadoc) * @see me.it_result.ca.CA#generateCSR() */ @Override public synchronized byte[] generateCSR(CertificateParameters certificateParameters) throws CAException { try { KeyPair keyPair; KeyStore keyStore = loadKeystore(); String subjectDN = certificateParameters.getSubjectDN(); String alias = Utils.generateAlias(subjectDN); boolean containsAlias = keyStore.containsAlias(alias); if (!containsAlias) keyPair = generateKeyPair(); else keyPair = getKeypair(subjectDN); X509Certificate cert = assembleCertificate(keyPair.getPublic(), keyPair.getPublic(), subjectDN, subjectDN, new BigInteger("1"), false, selfSignedCertificateValidityDays) .generate(keyPair.getPrivate()); Profile profile = selectProfile(certificateParameters); PKCS10CertificationRequest csr = profile.generateCsr(keyPair, certificateParameters, signatureAlgorithm); byte[] csrBytes = csr.getEncoded(); if (!containsAlias) { keyStore.setKeyEntry(alias, keyPair.getPrivate(), keystorePassword.toCharArray(), new X509Certificate[] { cert }); saveKeystore(keyStore); } return csrBytes; } catch (DuplicateSubjectException e) { throw new DuplicateSubjectException(e); } catch (Exception e) { throw new CAException(e); } finally { certGen.reset(); } } private Profile selectProfile(CertificateParameters certificateParameters) throws CAException { Profile profile = profiles.getProfile(certificateParameters); if (profile == null) throw new CAException( "Certificate profile for " + certificateParameters.getClass() + " is not registered"); return profile; } @Override public synchronized KeyPair getKeypair(String subjectDN) throws CAException { try { KeyStore keystore = loadKeystore(); String alias = Utils.generateAlias(subjectDN); if (keystore.containsAlias(alias)) { PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, keystorePassword.toCharArray()); X509Certificate selfSignedCertificate = (X509Certificate) keystore.getCertificate(alias); KeyPair keyPair = new KeyPair(selfSignedCertificate.getPublicKey(), privateKey); return keyPair; } } catch (Exception e) { throw new CAException(e); } return null; } @Override public synchronized X509Certificate getCertificate(String subjectDN) throws CAException { try { KeyStore keystore = loadKeystore(); String alias = Utils.generateAlias(subjectDN); if (keystore.containsAlias(alias)) { X509Certificate certificate = (X509Certificate) keystore.getCertificate(alias); return certificate; } } catch (Exception e) { throw new CAException(e); } return null; } /* (non-Javadoc) * @see me.it_result.ca.CA#storeCertificate() */ @Override public synchronized void storeCertificate(X509Certificate certificate) throws CAException { ensureInitialized(); try { KeyStore keyStore = loadKeystore(); String alias = Utils.generateAlias(certificate.getSubjectX500Principal()); X509Certificate existingCertificate = (X509Certificate) keyStore.getCertificate(alias); if (!existingCertificate.getPublicKey().equals(certificate.getPublicKey())) throw new InvalidCertificateKeyException("Signed certificate public key does not match expected"); X509Certificate caCertificate = (X509Certificate) keyStore.getCertificate(CA_ALIAS); try { certificate.verify(caCertificate.getPublicKey()); } catch (Exception e) { throw new InvalidCAException("The certificate was signed by a different CA", e); } PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, keystorePassword.toCharArray()); keyStore.setKeyEntry(alias, privateKey, keystorePassword.toCharArray(), new Certificate[] { certificate }); saveKeystore(keyStore); } catch (InvalidCertificateKeyException e) { throw new InvalidCertificateKeyException(e); } catch (InvalidCAException e) { throw new InvalidCAException(e); } catch (Exception e) { throw new CAException(e); } } private void ensureInitialized() throws CAException { if (!isInitialized()) throw new NotInitializedException("CA is not initialized yet."); } @Override public synchronized X509Certificate getCaCertificate() throws CAException, CAException { ensureInitialized(); try { KeyStore keyStore = loadKeystore(); return (X509Certificate) keyStore.getCertificate(CA_ALIAS); } catch (Exception e) { throw new CAException(e); } } @Override public KeyStore getKeyStore() throws CAException { try { return loadKeystore(); } catch (Exception e) { throw new CAException(e); } } @Override public KeyStore getTrustStore() throws NotInitializedException, CAException { ensureInitialized(); try { return loadKeystore(); } catch (Exception e) { throw new CAException(e); } } }