/*
* Copyright (C) 2014 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.tls.policy.formats;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvParser;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.intel.dcsg.cpg.crypto.CryptographyException;
import com.intel.dcsg.cpg.crypto.RsaUtil;
import com.intel.dcsg.cpg.crypto.Sha256Digest;
import com.intel.dcsg.cpg.x509.X509Util;
import java.io.IOException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author jbuhacoff
*/
public class CertificateTlsPolicyTest {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CertificateTlsPolicyTest.class);
private static List<X509Certificate> certificates = new ArrayList<>();
@BeforeClass
public static void createX509Certificates() throws NoSuchAlgorithmException, CryptographyException, IOException {
for(int i=0; i<3; i++) {
KeyPair keypair = RsaUtil.generateRsaKeyPair(1028);
X509Certificate certificate = RsaUtil.generateX509Certificate(String.format("CN=%d",i), keypair, 10); // valid for 10 days
certificates.add(certificate);
}
}
public static class X509CertificateTlsPolicy {
public List<X509Certificate> certificates;
}
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown=true)
public static class X509CertificateDigest {
public X509CertificateDigest() {
}
public X509CertificateDigest(String algorithm, byte[] digest) {
this.algorithm = algorithm;
this.digest = digest;
}
public String algorithm;
public byte[] digest;
}
public static class X509CertificateDigestTlsPolicy {
public List<X509CertificateDigest> publicKeyDigests;
}
@Test
public void testX509CertificatePem() throws CryptographyException, CertificateEncodingException, CertificateException {
StringBuilder pem = new StringBuilder();
for(X509Certificate certificate : certificates) {
pem.append(X509Util.encodePemCertificate(certificate));
}
String text = pem.toString();
log.debug("PEM:\n{}", text);
List<X509Certificate> decoded = X509Util.decodePemCertificates(text);
int max = certificates.size();
for(int i=0; i<max; i++) {
assertArrayEquals(String.format("record %d", i),certificates.get(i).getEncoded(), decoded.get(i).getEncoded());
}
}
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown=true)
public static class X509CertificateJsonMeta {
public X509CertificateJsonMeta() { }
public int version = 1;
}
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown=true)
public static class X509CertificateDigestJsonMeta {
public X509CertificateDigestJsonMeta() { }
public int version = 1;
public String algorithm = null;
}
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown=true)
public static class X509CertificateJson {
public X509CertificateJson() { }
public X509CertificateJsonMeta meta = null;
public List<String> certificates = new ArrayList<>();
}
@Test
public void testX509CertificateJson() throws CryptographyException, JsonProcessingException, IOException, CertificateEncodingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
X509CertificateJson json = new X509CertificateJson();
json.meta = new X509CertificateJsonMeta();
for(X509Certificate certificate : certificates) {
json.certificates.add(Base64.encodeBase64String(certificate.getEncoded()));
}
String text = mapper.writeValueAsString(json);
log.debug("JSON:\n{}", text);
X509CertificateJson decoded = mapper.readValue(text, X509CertificateJson.class);
int max = certificates.size();
for(int i=0; i<max; i++) {
assertEquals(String.format("record %d", i),Base64.encodeBase64String(certificates.get(i).getEncoded()), decoded.certificates.get(i));
}
}
public static class X509CertificateDigestCsv {
public X509CertificateDigestCsv() { }
public X509CertificateDigestCsv(String algorithm, String digest) {
this.algorithm = algorithm;
this.digest = digest;
}
public String algorithm;
public String digest;
}
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown=true)
public static class X509CertificateDigestJson {
public X509CertificateDigestJson() { }
public X509CertificateDigestJsonMeta meta = null;
public List<X509CertificateDigest> certificateDigests = new ArrayList<>();
}
@Test
public void testX509CertificateDigestCsv() throws JsonProcessingException, IOException, CertificateEncodingException {
CsvSchema schema = CsvSchema.builder()
.addColumn("algorithm", CsvSchema.ColumnType.STRING)
.addColumn("digest", CsvSchema.ColumnType.STRING)
.build();
CsvMapper mapper = new CsvMapper();
ArrayList<X509CertificateDigestCsv> lines = new ArrayList<>();
for(X509Certificate certificate : certificates) {
lines.add(new X509CertificateDigestCsv("sha256", Sha256Digest.digestOf(certificate.getEncoded()).toBase64()));
}
String text = "# inserting a comment here\n"+mapper.writer(schema).writeValueAsString(lines);
log.debug("CSV:\n{}", text);
mapper.enable(CsvParser.Feature.TRIM_SPACES);
// mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); // not needed.
ArrayList<X509CertificateDigestCsv> decoded = new ArrayList<>();
MappingIterator<X509CertificateDigestCsv> it = mapper.reader(X509CertificateDigestCsv.class).with(schema).readValues(text);
while(it.hasNext()) {
X509CertificateDigestCsv csv = it.next();
if( csv.algorithm != null && csv.algorithm.startsWith("#")) {
continue; // ignore comment lines
}
decoded.add(csv);
}
// ArrayList<X509CertificateDigestCsv> decoded = mapper.reader(X509CertificateDigestCsv.class).with(schema).readValue(text); // does not work: cannot cast X509CertificateDigestCsv to ArrayList
int max = certificates.size();
for(int i=0; i<max; i++) {
assertEquals(Sha256Digest.digestOf(certificates.get(i).getEncoded()).toBase64(), decoded.get(i).digest);
}
}
@Test
public void testX509CertificateDigestJson() throws CryptographyException, JsonProcessingException, IOException, CertificateEncodingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
X509CertificateDigestJson json = new X509CertificateDigestJson();
for(X509Certificate certificate : certificates) {
json.certificateDigests.add(new X509CertificateDigest("sha256",Sha256Digest.digestOf(certificate.getEncoded()).toByteArray()));
}
String text = mapper.writeValueAsString(json);
log.debug("JSON:\n{}", text);
X509CertificateDigestJson decoded = mapper.readValue(text, X509CertificateDigestJson.class);
int max = certificates.size();
for(int i=0; i<max; i++) {
assertArrayEquals(String.format("record %d", i),Sha256Digest.digestOf(certificates.get(i).getEncoded()).toByteArray(), decoded.certificateDigests.get(i).digest);
}
}
@Test
public void testX509CertificateDigestJsonWithMeta() throws CryptographyException, JsonProcessingException, IOException, CertificateEncodingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
X509CertificateDigestJson json = new X509CertificateDigestJson();
json.meta = new X509CertificateDigestJsonMeta();
json.meta.algorithm = "sha256"; // can set it here if they are all the same
for(X509Certificate certificate : certificates) {
json.certificateDigests.add(new X509CertificateDigest(null,Sha256Digest.digestOf(certificate.getEncoded()).toByteArray()));
}
String text = mapper.writeValueAsString(json);
log.debug("JSON:\n{}", text);
X509CertificateDigestJson decoded = mapper.readValue(text, X509CertificateDigestJson.class);
int max = certificates.size();
for(int i=0; i<max; i++) {
assertArrayEquals(String.format("record %d", i),Sha256Digest.digestOf(certificates.get(i).getEncoded()).toByteArray(), decoded.certificateDigests.get(i).digest);
}
}
}