Skip to content

Commit

Permalink
Add serial number and expiring data info
Browse files Browse the repository at this point in the history
  • Loading branch information
hamadodene committed Aug 8, 2022
1 parent 7826248 commit 2e6e09f
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,43 @@
*/
package org.carapaceproxy.api;

import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.carapaceproxy.configstore.CertificateData;
import org.carapaceproxy.configstore.ConfigurationStoreUtils;
import org.carapaceproxy.core.HttpProxyServer;
import org.carapaceproxy.core.RuntimeServerConfiguration;
import org.carapaceproxy.server.certificates.DynamicCertificateState;
import static org.carapaceproxy.server.certificates.DynamicCertificateState.AVAILABLE;
import static org.carapaceproxy.server.certificates.DynamicCertificateState.WAITING;
import org.carapaceproxy.server.certificates.DynamicCertificatesManager;
import org.carapaceproxy.server.config.SSLCertificateConfiguration;
import org.carapaceproxy.server.config.SSLCertificateConfiguration.CertificateMode;
import static org.carapaceproxy.server.config.SSLCertificateConfiguration.CertificateMode.MANUAL;
import static org.carapaceproxy.server.config.SSLCertificateConfiguration.CertificateMode.STATIC;
import java.util.Set;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.QueryParam;
import org.carapaceproxy.utils.CertificatesUtils;
import static org.carapaceproxy.utils.APIUtils.certificateStateToString;
import static org.carapaceproxy.utils.APIUtils.certificateModeToString;
import static org.carapaceproxy.utils.APIUtils.stringToCertificateMode;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import static org.carapaceproxy.server.certificates.DynamicCertificatesManager.DEFAULT_DAYS_BEFORE_RENEWAL;
import static org.carapaceproxy.utils.CertificatesUtils.loadKeyStoreFromFile;

import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import static org.carapaceproxy.server.certificates.DynamicCertificateState.AVAILABLE;
import static org.carapaceproxy.server.certificates.DynamicCertificateState.WAITING;
import static org.carapaceproxy.server.certificates.DynamicCertificatesManager.DEFAULT_DAYS_BEFORE_RENEWAL;
import static org.carapaceproxy.server.config.SSLCertificateConfiguration.CertificateMode.MANUAL;
import static org.carapaceproxy.server.config.SSLCertificateConfiguration.CertificateMode.STATIC;
import static org.carapaceproxy.utils.APIUtils.*;
import static org.carapaceproxy.utils.CertificatesUtils.createKeystore;
import static org.carapaceproxy.utils.CertificatesUtils.loadKeyStoreFromFile;

/**
* Access to certificates
*
Expand Down Expand Up @@ -287,11 +283,15 @@ public Response uploadCertificate(
String encodedData = "";
DynamicCertificateState state = WAITING;
if (data != null && data.length > 0) {
encodedData = Base64.getEncoder().encodeToString(data);
Certificate[] chain = CertificatesUtils.readChainFromKeystore(data);
PrivateKey key = CertificatesUtils.loadPrivateKey(data, "");
encodedData = Base64.getEncoder().encodeToString(createKeystore(chain, key));
state = AVAILABLE;
}

CertificateData cert = new CertificateData(domain, "", encodedData, state, "", "");
cert.setManual(MANUAL.equals(certType));

cert.setDaysBeforeRenewal(daysbeforerenewal != null ? daysbeforerenewal : DEFAULT_DAYS_BEFORE_RENEWAL);
HttpProxyServer server = (HttpProxyServer) context.getAttribute("server");
server.updateDynamicCertificateForDomain(cert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ public boolean equals(Object obj) {

@Override
public String toString() {
return "CertificateData{" + "domain=" + domain + ", state=" + state + ", manual=" + manual + '}';
return "CertificateData{" + "domain=" + domain + ","
+" state=" + state + ", manual=" + manual
+ ",expiringDate=" + expiringDate + ",serialNumber " + serialNumber + '}';
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,13 @@
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

/**
* Utilitis for Certificates storing as Keystores
Expand All @@ -47,9 +44,8 @@ public final class CertificatesUtils {
private static final long DAY_TO_MILLIS = 24 * 60 * 60 * 1_000;

/**
*
* @param chain to store into a keystore
* @param key private key for the chain
* @param key private key for the chain
* @return keystore data
* @throws GeneralSecurityException
*/
Expand All @@ -76,7 +72,8 @@ public static Certificate[] readChainFromKeystore(byte[] data) throws GeneralSec
try (ByteArrayInputStream is = new ByteArrayInputStream(data)) {
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_FORMAT);
keyStore.load(is, KEYSTORE_PW);
return keyStore.getCertificateChain(KEYSTORE_CERT_ALIAS);
String alias = keyStore.aliases().nextElement();
return keyStore.getCertificateChain(alias);
} catch (IOException ex) {
throw new GeneralSecurityException(ex);
}
Expand All @@ -102,7 +99,6 @@ public static Certificate[] readChainFromKeystore(KeyStore keystore) throws Gene
}

/**
*
* @param data keystore data.
* @return whether a valid keystore can be retrived from data.
*/
Expand Down Expand Up @@ -134,8 +130,8 @@ public static KeyStore loadKeyStoreFromFile(String filename, String password, Fi

public static Map<String, X509Certificate> loadCaCerts(TrustManagerFactory trustManagerFactory) {
final Map<String, X509Certificate> certificateAuthorities = new HashMap<>();
for(TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if(trustManager instanceof X509TrustManager) {
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
for (X509Certificate ca : ((X509TrustManager) trustManager).getAcceptedIssuers()) {
certificateAuthorities.put(ca.getSubjectX500Principal().getName(), ca);
}
Expand All @@ -161,6 +157,21 @@ public static boolean isCertificateExpired(Date expiringDate, int daysBeforeRene
return System.currentTimeMillis() + (daysBeforeRenewal * DAY_TO_MILLIS) >= expiringDate.getTime();
}

public static X509Certificate readCertificateAsX509(byte[] data, String password) throws Exception {
KeyStore ks = KeyStore.getInstance(KEYSTORE_FORMAT);
ks.load(new ByteArrayInputStream(data), password.trim().toCharArray());
String alias = ks.aliases().nextElement();
return (X509Certificate) ks.getCertificate(alias);
}

public static PrivateKey loadPrivateKey(byte[] data, String password) throws Exception {
KeyStore ks = KeyStore.getInstance(KEYSTORE_FORMAT);
ks.load(new ByteArrayInputStream(data), password.trim().toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey key = (PrivateKey) ks.getKey(alias, password.trim().toCharArray());
return key;
}

/**
* Compare two certificates chain.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Base64;
import java.util.Properties;
Expand All @@ -37,6 +38,8 @@
import org.carapaceproxy.server.mapper.requestmatcher.MatchAllRequestMatcher;

import static org.carapaceproxy.utils.CertificatesTestUtils.uploadCertificate;

import org.carapaceproxy.utils.CertificatesUtils;
import org.carapaceproxy.utils.RawHttpClient;
import org.carapaceproxy.utils.TestUtils;
import static org.hamcrest.CoreMatchers.containsString;
Expand Down Expand Up @@ -460,7 +463,8 @@ public void testCertificates() throws Exception {

// Downloading
response = client.get("/api/certificates/" + manualDomain + "/download", credentials);
assertTrue(Arrays.equals(chain1, response.getBody()));
Certificate[] responseChain = CertificatesUtils.readChainFromKeystore(response.getBody());
assertTrue(Arrays.equals(CertificatesUtils.readChainFromKeystore(chain1), responseChain));

// Certificate updating
// Uploading
Expand Down Expand Up @@ -502,7 +506,8 @@ public void testCertificates() throws Exception {

// Downloading
response = client.get("/api/certificates/" + manualDomain + "/download", credentials);
assertTrue(Arrays.equals(chain2, response.getBody()));
Certificate[] responseChain2 = CertificatesUtils.readChainFromKeystore(response.getBody());
assertTrue(Arrays.equals(CertificatesUtils.readChainFromKeystore(chain2), responseChain2));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@
import static org.carapaceproxy.utils.CertificatesTestUtils.uploadCertificate;
import org.carapaceproxy.utils.RawHttpClient;
import org.carapaceproxy.utils.RawHttpClient.HttpResponse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;

import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -75,7 +74,7 @@
import org.shredzone.acme4j.util.KeyPairUtils;
import static org.carapaceproxy.server.certificates.DynamicCertificatesManager.DEFAULT_DAYS_BEFORE_RENEWAL;
import static org.carapaceproxy.utils.CertificatesUtils.createKeystore;
import static org.junit.Assert.assertTrue;

import java.util.Base64;
import org.carapaceproxy.server.config.SSLCertificateConfiguration;
import org.powermock.reflect.Whitebox;
Expand Down Expand Up @@ -542,29 +541,33 @@ public void testWildcardsCertificates() throws Exception {
// upload exact
KeyPair endUserKeyPair = KeyPairUtils.createKeyPair(DEFAULT_KEYPAIRS_SIZE);
Certificate[] chain = generateSampleChain(endUserKeyPair, false);
byte[] chainData = createKeystore(chain, endUserKeyPair.getPrivate());
String chain1 = Base64.getEncoder().encodeToString(chainData);
uploadCertificate("localhost2", null, chainData, client, credentials);
byte[] chainData1 = createKeystore(chain, endUserKeyPair.getPrivate());
uploadCertificate("localhost2", null, chainData1, client, credentials);
CertificateData data = dynCertsMan.getCertificateDataForDomain("localhost2");
byte[] keyStoreData = Base64.getDecoder().decode(data.getChain());
Certificate[] saveChain = CertificatesUtils.readChainFromKeystore(keyStoreData);
assertNotNull(data);
assertEquals(chain1, data.getChain());
assertArrayEquals(CertificatesUtils.readChainFromKeystore(chainData1), saveChain);
assertFalse(data.isWildcard());

// upload wildcard
endUserKeyPair = KeyPairUtils.createKeyPair(DEFAULT_KEYPAIRS_SIZE);
chain = generateSampleChain(endUserKeyPair, false);
chainData = createKeystore(chain, endUserKeyPair.getPrivate());
String chain2 = Base64.getEncoder().encodeToString(chainData);
uploadCertificate("*.localhost2", null, chainData, client, credentials);
byte[] chainData2 = createKeystore(chain, endUserKeyPair.getPrivate());
uploadCertificate("*.localhost2", null, chainData2, client, credentials);
data = dynCertsMan.getCertificateDataForDomain("*.localhost2");
byte[] keyStoreData2 = Base64.getDecoder().decode(data.getChain());
Certificate[] saveChain2 = CertificatesUtils.readChainFromKeystore(keyStoreData2);
assertNotNull(data);
assertEquals(chain2, data.getChain());
assertArrayEquals(CertificatesUtils.readChainFromKeystore(chainData2), saveChain2);
assertTrue(data.isWildcard());

// exact still different from wildcard
data = dynCertsMan.getCertificateDataForDomain("localhost2");
byte[] keyStoreData3 = Base64.getDecoder().decode(data.getChain());
Certificate[] saveChain3 = CertificatesUtils.readChainFromKeystore(keyStoreData3);
assertNotNull(data);
assertEquals(chain1, data.getChain());
assertArrayEquals(CertificatesUtils.readChainFromKeystore(chainData1), saveChain3);
assertFalse(data.isWildcard());
}
}
Expand Down

0 comments on commit 2e6e09f

Please sign in to comment.