From 629224c92a8001bd0f7535f8d4d5fbec96c07940 Mon Sep 17 00:00:00 2001 From: carltietjen Date: Wed, 18 Nov 2015 15:44:30 -0800 Subject: [PATCH] In HttpsServerCertificateManager fixed futureSeconds (code was treating like it was milliseconds rather than seconds) In makeSelfSignedCert, changed the code to reflect the change above. -- Also made code practice changes (using final) --- .../secure/HttpsServerCertificateManager.java | 412 ++++++++++-------- .../pwm/tests/MakeSelfSignedCertTest.java | 26 +- 2 files changed, 233 insertions(+), 205 deletions(-) diff --git a/src/main/java/password/pwm/util/secure/HttpsServerCertificateManager.java b/src/main/java/password/pwm/util/secure/HttpsServerCertificateManager.java index 34771f68e..89ac93f69 100644 --- a/src/main/java/password/pwm/util/secure/HttpsServerCertificateManager.java +++ b/src/main/java/password/pwm/util/secure/HttpsServerCertificateManager.java @@ -56,214 +56,242 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -public class HttpsServerCertificateManager { - private static PwmLogger LOGGER = PwmLogger.forClass(HttpsServerCertificateManager.class); - - private static final String KEYSTORE_ALIAS = "https"; - - private static boolean bouncyCastleInitialized; - - private final PwmApplication pwmApplication; - - public HttpsServerCertificateManager(final PwmApplication pwmApplication) { - this.pwmApplication = pwmApplication; - } - - private static void initBouncyCastleProvider() { - if (!bouncyCastleInitialized) { - Security.addProvider(new BouncyCastleProvider()); - bouncyCastleInitialized = true; - } - } - - public KeyStore configToKeystore() throws PwmUnrecoverableException { - final Configuration configuration = pwmApplication.getConfig(); - final PasswordData keystorePassword = configuration.readSettingAsPassword(PwmSetting.HTTPS_CERT_PASSWORD); - if (keystorePassword == null || keystorePassword.getStringValue().isEmpty()) { - final String errorMsg = "https keystore password is not configured"; - throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR, errorMsg, new String[]{errorMsg})); - } - - Map files = configuration.readSettingAsFile(PwmSetting.HTTPS_CERT_PKCS12); - if (files == null || files.isEmpty()) { - final String errorMsg = "https keystore pkcs12 file is not present"; +/** + * {@link } + */ +public class HttpsServerCertificateManager +{ + private static final PwmLogger LOGGER = PwmLogger.forClass(HttpsServerCertificateManager.class); + + private static final String KEYSTORE_ALIAS = "https"; + + private static boolean bouncyCastleInitialized; + + private final PwmApplication pwmApplication; + + public HttpsServerCertificateManager(final PwmApplication pwmApplication) + { + this.pwmApplication = pwmApplication; + } + + private static void initBouncyCastleProvider() + { + if (!bouncyCastleInitialized) + { + Security.addProvider(new BouncyCastleProvider()); + bouncyCastleInitialized = true; + } + } + + public KeyStore configToKeystore() throws PwmUnrecoverableException + { + final Configuration configuration = pwmApplication.getConfig(); + final PasswordData keystorePassword = configuration.readSettingAsPassword(PwmSetting.HTTPS_CERT_PASSWORD); + if (keystorePassword == null || keystorePassword.getStringValue().isEmpty()) + { + final String errorMsg = "https keystore password is not configured"; + throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR, errorMsg, new String[]{errorMsg})); + } + + Map files = configuration.readSettingAsFile(PwmSetting.HTTPS_CERT_PKCS12); + if (files == null || files.isEmpty()) + { + final String errorMsg = "https keystore pkcs12 file is not present"; + throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR, errorMsg, new String[]{errorMsg})); + } + + final FileValue.FileInformation fileInformation = files.keySet().iterator().next(); + final FileValue.FileContent fileContent = files.get(fileInformation); + + final KeyStore keyStore; + try + { + final InputStream stream = new ByteArrayInputStream(fileContent.getContents()); + keyStore = KeyStore.getInstance("pkcs12", "SunJSSE"); + keyStore.load(stream, keystorePassword.getStringValue().toCharArray()); + + if (!keyStore.containsAlias(KEYSTORE_ALIAS)) + { + final String errorMsg = "pkcs12 store does not does not contain a certificate with \"" + KEYSTORE_ALIAS + "\" alias"; throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR, errorMsg, new String[]{errorMsg})); - } - - final FileValue.FileInformation fileInformation = files.keySet().iterator().next(); - final FileValue.FileContent fileContent = files.get(fileInformation); - - final KeyStore keyStore; - try { - final InputStream stream = new ByteArrayInputStream(fileContent.getContents()); - keyStore = KeyStore.getInstance("pkcs12", "SunJSSE"); - keyStore.load(stream, keystorePassword.getStringValue().toCharArray()); - - if (!keyStore.containsAlias(KEYSTORE_ALIAS)) { - final String errorMsg = "pkcs12 store does not does not contain a certificate with \"" + KEYSTORE_ALIAS + "\" alias"; - throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR, errorMsg, new String[]{errorMsg})); - } - return keyStore; - } catch (IOException | NoSuchAlgorithmException | CertificateException | NoSuchProviderException | KeyStoreException e) { - throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR, "error parsing pkcs12 file: " + e.getMessage())); - } - } - - public KeyStore makeSelfSignedCert(final String password) - throws PwmUnrecoverableException - { - final Configuration configuration = pwmApplication.getConfig(); - - try { - final SelfCertGenerator selfCertGenerator = new SelfCertGenerator(configuration); - return selfCertGenerator.makeSelfSignedCert(pwmApplication, password); - } catch (Exception e) { - throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_CERTIFICATE_ERROR,"unable to generate self signed certificate: " + e.getMessage())); - } - } - - public static class StoredCertData implements Serializable { - private X509Certificate x509Certificate; - private String keypairb64; - - public StoredCertData(X509Certificate x509Certificate, KeyPair keypair) - throws IOException - { - this.x509Certificate = x509Certificate; - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(keypair); - final byte[] ba = baos.toByteArray(); - keypairb64 = StringUtil.base64Encode(ba); - } - - public X509Certificate getX509Certificate() { - return x509Certificate; - } - - public KeyPair getKeypair() - throws IOException, ClassNotFoundException - { - final byte[] ba = StringUtil.base64Decode(keypairb64); - final ByteArrayInputStream bais = new ByteArrayInputStream(ba); - final ObjectInputStream ois = new ObjectInputStream(bais); - return (KeyPair)ois.readObject(); - } - } - - - public static class SelfCertGenerator { - private final Configuration config; - - public SelfCertGenerator(Configuration config) { - this.config = config; - } - - public KeyStore makeSelfSignedCert(final PwmApplication pwmApplication, final String password) - throws Exception - { - final String cnName = makeSubjectName(); - final KeyStore keyStore = KeyStore.getInstance("jks"); - keyStore.load(null, password.toCharArray()); - StoredCertData storedCertData = pwmApplication.readAppAttribute(PwmApplication.AppAttribute.HTTPS_SELF_CERT, StoredCertData.class); - if (storedCertData != null) { - if (!cnName.equals(storedCertData.getX509Certificate().getSubjectDN().getName())) { - LOGGER.info("replacing stored self cert, subject name does not match configured site url"); - storedCertData = null; - } else if (storedCertData.getX509Certificate().getNotBefore().after(new Date())) { - LOGGER.info("replacing stored self cert, not-before date is in the future"); - storedCertData = null; - } else if (storedCertData.getX509Certificate().getNotAfter().before(new Date())) { - LOGGER.info("replacing stored self cert, not-after date is in the past"); - storedCertData = null; - } - } - - if (storedCertData == null) { - storedCertData = makeSelfSignedCert(cnName); - pwmApplication.writeAppAttribute(PwmApplication.AppAttribute.HTTPS_SELF_CERT, storedCertData); + } + return keyStore; + } catch (IOException | NoSuchAlgorithmException | CertificateException | NoSuchProviderException | KeyStoreException e) + { + throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR, "error parsing pkcs12 file: " + e.getMessage())); + } + } + + public KeyStore makeSelfSignedCert(final String password) + throws PwmUnrecoverableException + { + final Configuration configuration = pwmApplication.getConfig(); + + try + { + final SelfCertGenerator selfCertGenerator = new SelfCertGenerator(configuration); + return selfCertGenerator.makeSelfSignedCert(pwmApplication, password); + } catch (Exception e) + { + throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_CERTIFICATE_ERROR, "unable to generate self signed certificate: " + e.getMessage())); + } + } + + public static class StoredCertData implements Serializable + { + private final X509Certificate x509Certificate; + private String keypairb64; + + public StoredCertData(X509Certificate x509Certificate, KeyPair keypair) + throws IOException + { + this.x509Certificate = x509Certificate; + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(keypair); + final byte[] ba = baos.toByteArray(); + keypairb64 = StringUtil.base64Encode(ba); + } + + public X509Certificate getX509Certificate() + { + return x509Certificate; + } + + public KeyPair getKeypair() + throws IOException, ClassNotFoundException + { + final byte[] ba = StringUtil.base64Decode(keypairb64); + final ByteArrayInputStream bais = new ByteArrayInputStream(ba); + final ObjectInputStream ois = new ObjectInputStream(bais); + return (KeyPair) ois.readObject(); + } + } + + + public static class SelfCertGenerator + { + private final Configuration config; + + public SelfCertGenerator(Configuration config) + { + this.config = config; + } + + public KeyStore makeSelfSignedCert(final PwmApplication pwmApplication, final String password) + throws Exception + { + final String cnName = makeSubjectName(); + final KeyStore keyStore = KeyStore.getInstance("jks"); + keyStore.load(null, password.toCharArray()); + StoredCertData storedCertData = pwmApplication.readAppAttribute(PwmApplication.AppAttribute.HTTPS_SELF_CERT, StoredCertData.class); + if (storedCertData != null) + { + if (!cnName.equals(storedCertData.getX509Certificate().getSubjectDN().getName())) + { + LOGGER.info("replacing stored self cert, subject name does not match configured site url"); + storedCertData = null; + } else if (storedCertData.getX509Certificate().getNotBefore().after(new Date())) + { + LOGGER.info("replacing stored self cert, not-before date is in the future"); + storedCertData = null; + } else if (storedCertData.getX509Certificate().getNotAfter().before(new Date())) + { + LOGGER.info("replacing stored self cert, not-after date is in the past"); + storedCertData = null; } - - keyStore.setKeyEntry( - KEYSTORE_ALIAS, - storedCertData.getKeypair().getPrivate(), - password.toCharArray(), - new X509Certificate[]{storedCertData.getX509Certificate()} - ); - return keyStore; - } - - public String makeSubjectName() - throws Exception - { - String cnName = PwmConstants.PWM_APP_NAME.toLowerCase() + ".example.com"; + } + + if (storedCertData == null) + { + storedCertData = makeSelfSignedCert(cnName); + pwmApplication.writeAppAttribute(PwmApplication.AppAttribute.HTTPS_SELF_CERT, storedCertData); + } + + keyStore.setKeyEntry( + KEYSTORE_ALIAS, + storedCertData.getKeypair().getPrivate(), + password.toCharArray(), + new X509Certificate[]{storedCertData.getX509Certificate()} + ); + return keyStore; + } + + public String makeSubjectName() + throws Exception + { + String cnName = PwmConstants.PWM_APP_NAME.toLowerCase() + ".example.com"; + { + final String siteURL = config.readSettingAsString(PwmSetting.PWM_SITE_URL); + if (siteURL != null && !siteURL.isEmpty()) { - final String siteURL = config.readSettingAsString(PwmSetting.PWM_SITE_URL); - if (siteURL != null && !siteURL.isEmpty()) { - try { - URI uri = new URI(siteURL); - if (uri.getHost() != null && !uri.getHost().isEmpty()) { - cnName = uri.getHost(); - } - } catch (URISyntaxException e) { - // disregard - } - } + try + { + final URI uri = new URI(siteURL); + if (uri.getHost() != null && !uri.getHost().isEmpty()) + { + cnName = uri.getHost(); + } + } catch (URISyntaxException e) + { + // disregard + } } - return cnName; - } + } + return cnName; + } - public StoredCertData makeSelfSignedCert(final String cnName) - throws Exception - { - initBouncyCastleProvider(); + public StoredCertData makeSelfSignedCert(final String cnName) + throws Exception + { + initBouncyCastleProvider(); - LOGGER.debug("creating self-signed certificate with cn of " + cnName); - final KeyPair keyPair = generateRSAKeyPair(config); - final long futureSeconds = Long.parseLong(config.readAppProperty(AppProperty.SECURITY_HTTPSSERVER_SELF_FUTURESECONDS)); - final X509Certificate certificate = generateV3Certificate(keyPair, cnName, futureSeconds); - return new StoredCertData(certificate, keyPair); - } + LOGGER.debug("creating self-signed certificate with cn of " + cnName); + final KeyPair keyPair = generateRSAKeyPair(config); + final long futureSeconds = Long.parseLong(config.readAppProperty(AppProperty.SECURITY_HTTPSSERVER_SELF_FUTURESECONDS)); + final X509Certificate certificate = generateV3Certificate(keyPair, cnName, futureSeconds); + return new StoredCertData(certificate, keyPair); + } - public static X509Certificate generateV3Certificate(final KeyPair pair, final String cnValue, final long futureSeconds) - throws Exception - { - X500NameBuilder subjectName = new X500NameBuilder(BCStyle.INSTANCE); - subjectName.addRDN(BCStyle.CN, cnValue); + public static X509Certificate generateV3Certificate(final KeyPair pair, final String cnValue, final long futureSeconds) + throws Exception + { + final X500NameBuilder subjectName = new X500NameBuilder(BCStyle.INSTANCE); + subjectName.addRDN(BCStyle.CN, cnValue); - SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddhhmmss"); - String serNumStr = formatter.format(new Date(System.currentTimeMillis())); - BigInteger serialNumber = new BigInteger(serNumStr); + final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddhhmmss"); + final String serNumStr = formatter.format(new Date(System.currentTimeMillis())); + final BigInteger serialNumber = new BigInteger(serNumStr); - Date notBefore = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2)); // 2 days in the past - Date notAfter = new Date(System.currentTimeMillis() + futureSeconds); + final Date notBefore = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2)); // 2 days in the past + final Date notAfter = new Date(System.currentTimeMillis() + (futureSeconds * 1000)); - X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(subjectName.build(), serialNumber, notBefore, notAfter, subjectName.build(), pair.getPublic()); + final X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(subjectName.build(), serialNumber, notBefore, notAfter, subjectName.build(), pair.getPublic()); - BasicConstraints basic = new BasicConstraints(false); // not a CA - certGen.addExtension(Extension.basicConstraints, true, basic.getEncoded()); // OID, critical, ASN.1 encoded value + final BasicConstraints basic = new BasicConstraints(false); // not a CA + certGen.addExtension(Extension.basicConstraints, true, basic.getEncoded()); // OID, critical, ASN.1 encoded value - KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment); // sign and key encipher - certGen.addExtension(Extension.keyUsage, true, keyUsage.getEncoded()); // OID, critical, ASN.1 encoded value + final KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment); // sign and key encipher + certGen.addExtension(Extension.keyUsage, true, keyUsage.getEncoded()); // OID, critical, ASN.1 encoded value - ExtendedKeyUsage extKeyUsage = new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth); // server authentication - certGen.addExtension(Extension.extendedKeyUsage, true, extKeyUsage.getEncoded()); // OID, critical, ASN.1 encoded value + final ExtendedKeyUsage extKeyUsage = new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth); // server authentication + certGen.addExtension(Extension.extendedKeyUsage, true, extKeyUsage.getEncoded()); // OID, critical, ASN.1 encoded value - ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider("BC").build(pair.getPrivate()); + final ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider("BC").build(pair.getPrivate()); - return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certGen.build(sigGen)); - } + return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certGen.build(sigGen)); + } - static KeyPair generateRSAKeyPair(final Configuration config) - throws Exception - { - final int keySize = Integer.parseInt(config.readAppProperty(AppProperty.SECURITY_HTTPSSERVER_SELF_KEY_SIZE)); - final String keyAlg = config.readAppProperty(AppProperty.SECURITY_HTTPSSERVER_SELF_ALG); - KeyPairGenerator kpGen = KeyPairGenerator.getInstance(keyAlg, "BC"); - kpGen.initialize(keySize, new SecureRandom()); - return kpGen.generateKeyPair(); - } - } + static KeyPair generateRSAKeyPair(final Configuration config) + throws Exception + { + final int keySize = Integer.parseInt(config.readAppProperty(AppProperty.SECURITY_HTTPSSERVER_SELF_KEY_SIZE)); + final String keyAlg = config.readAppProperty(AppProperty.SECURITY_HTTPSSERVER_SELF_ALG); + final KeyPairGenerator kpGen = KeyPairGenerator.getInstance(keyAlg, "BC"); + kpGen.initialize(keySize, new SecureRandom()); + return kpGen.generateKeyPair(); + } + } } diff --git a/src/test/java/password/pwm/tests/MakeSelfSignedCertTest.java b/src/test/java/password/pwm/tests/MakeSelfSignedCertTest.java index fb588c9b6..05c856b86 100644 --- a/src/test/java/password/pwm/tests/MakeSelfSignedCertTest.java +++ b/src/test/java/password/pwm/tests/MakeSelfSignedCertTest.java @@ -33,22 +33,22 @@ public class MakeSelfSignedCertTest extends TestCase { - private static final Provider BC_PROVIDER = new BouncyCastleProvider(); + private static final Provider BC_PROVIDER = new BouncyCastleProvider(); - public void testSelfSignedCert() throws Exception - { - Security.addProvider(BC_PROVIDER); + public void testSelfSignedCert() throws Exception + { + Security.addProvider(BC_PROVIDER); - KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); - kpGen.initialize(2048, new SecureRandom()); - final KeyPair keyPair = kpGen.generateKeyPair(); + final KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + kpGen.initialize(2048, new SecureRandom()); + final KeyPair keyPair = kpGen.generateKeyPair(); - final String cnName = "test.myname.com"; - final long futureSeconds = TimeUnit.DAYS.toMillis(2 * 265); + final String cnName = "test.myname.com"; + final long futureSeconds = (TimeUnit.DAYS.toMillis(2 * 365)) / 1000; - X509Certificate storedCertData = HttpsServerCertificateManager.SelfCertGenerator.generateV3Certificate(keyPair, cnName, futureSeconds); - Assert.assertNotNull(storedCertData); - Assert.assertEquals(storedCertData.getSubjectDN().getName(), storedCertData.getIssuerDN().getName()); - } + final X509Certificate storedCertData = HttpsServerCertificateManager.SelfCertGenerator.generateV3Certificate(keyPair, cnName, futureSeconds); + Assert.assertNotNull(storedCertData); + Assert.assertEquals(storedCertData.getSubjectDN().getName(), storedCertData.getIssuerDN().getName()); + } }