/*
* Copyright (C) 2014 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.tls.policy.creator.impl;
import com.intel.dcsg.cpg.codec.Base64Codec;
import com.intel.dcsg.cpg.codec.Base64Util;
import com.intel.dcsg.cpg.codec.ByteArrayCodec;
import com.intel.dcsg.cpg.codec.HexCodec;
import com.intel.dcsg.cpg.crypto.CryptographyException;
import com.intel.dcsg.cpg.crypto.digest.Digest;
import com.intel.dcsg.cpg.crypto.digest.DigestUtil;
import com.intel.dcsg.cpg.crypto.digest.UnsupportedAlgorithmException;
import com.intel.dcsg.cpg.codec.HexUtil;
import com.intel.dcsg.cpg.tls.policy.impl.CertificateDigestTlsPolicy;
import com.intel.dcsg.cpg.x509.repository.DigestRepository;
import com.intel.dcsg.cpg.x509.repository.HashSetMutableDigestRepository;
import com.intel.mtwilson.tls.policy.TlsPolicyDescriptor;
import com.intel.mtwilson.tls.policy.factory.TlsPolicyCreator;
import com.intel.mtwilson.tls.policy.factory.TlsPolicyFactoryUtil;
import java.util.Collection;
import java.util.Iterator;
import org.apache.commons.codec.binary.Base64;
/**
*
* @author jbuhacoff
*/
public class CertificateDigestTlsPolicyCreator implements TlsPolicyCreator{
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CertificateDigestTlsPolicyCreator.class);
@Override
public CertificateDigestTlsPolicy createTlsPolicy(TlsPolicyDescriptor tlsPolicyDescriptor) {
if( "certificate-digest".equalsIgnoreCase(tlsPolicyDescriptor.getPolicyType()) ) {
try {
DigestRepository repository = getCertificateDigestRepository(tlsPolicyDescriptor);
return new CertificateDigestTlsPolicy(repository);
}
catch(CryptographyException e) {
throw new IllegalArgumentException("Cannot create certificate digest policy from given repository", e);
}
}
return null; // IAW TlsPolicyCreator interface, returning null means the given policy type is not supported so caller can try a different creator
}
private DigestRepository getCertificateDigestRepository(TlsPolicyDescriptor tlsPolicyDescriptor) throws CryptographyException {
HashSetMutableDigestRepository repository = new HashSetMutableDigestRepository();
if( "certificate-digest".equals(tlsPolicyDescriptor.getPolicyType()) ) {
if( tlsPolicyDescriptor.getData() == null || tlsPolicyDescriptor.getData().isEmpty() ) {
throw new IllegalArgumentException("TLS policy descriptor does not contain any certificate digests");
}
ByteArrayCodec codec;
CertificateDigestMetadata meta = getCertificateDigestMetadata(tlsPolicyDescriptor);
if( meta.digestEncoding == null ) {
// attempt auto-detection based on first digest
String sample = TlsPolicyFactoryUtil.getFirst(tlsPolicyDescriptor.getData());
meta.digestEncoding = TlsPolicyFactoryUtil.guessEncodingForData(sample);
log.debug("Guessing codec {} for sample data {}", meta.digestEncoding, sample);
}
codec = TlsPolicyFactoryUtil.getCodecByName(meta.digestEncoding); // safe because if input is null return value will be null
if( codec == null ) {
throw new IllegalArgumentException("TlsPolicyDescriptor indicates certificate digests but does not declare digest encoding");
}
log.debug("Codec {} for digest encoding {}", codec.getClass().getName(), meta.digestEncoding);
String alg;
if( meta.digestAlgorithm == null || meta.digestAlgorithm.isEmpty() ) {
log.debug("Guessing algorithm for sample data");
// attempt auto-detection based on first digest
String sample = TlsPolicyFactoryUtil.getFirst(tlsPolicyDescriptor.getData());
byte[] hash = codec.decode(sample);
alg = TlsPolicyFactoryUtil.guessAlgorithmForDigest(hash);
log.debug("Algorithm {} for sample data {} decoded length {}", alg, sample, hash.length);
}
else {
log.debug("Using specified algorithm for sample data {}", meta.digestAlgorithm);
alg = meta.digestAlgorithm;
}
if( alg == null ) {
throw new IllegalArgumentException("TlsPolicyDescriptor indicates certificate digests but does not declare digest algorithm");
}
alg = DigestUtil.getJavaAlgorithmName(alg);
if( alg == null ) {
throw new UnsupportedAlgorithmException(alg);
}
for(String certificateDigest : tlsPolicyDescriptor.getData()) {
Digest digest = new Digest(alg, codec.decode(certificateDigest));
repository.addDigest(digest);
}
return repository;
}
throw new UnsupportedOperationException("TLS policy type must be 'certificate-digest'");
}
public static class CertificateDigestMetadata {
public String digestAlgorithm;
public String digestEncoding;
}
/**
*
* @param tlsPolicyDescriptor
* @return an instance of CertificateDigestMetadata, but some fields may be null if they were not included in the descriptor's meta section
*/
public static CertificateDigestMetadata getCertificateDigestMetadata(TlsPolicyDescriptor tlsPolicyDescriptor) {
CertificateDigestMetadata metadata = new CertificateDigestMetadata();
if( tlsPolicyDescriptor.getMeta() == null ) {
return metadata;
}
if(tlsPolicyDescriptor.getMeta() == null) {
throw new IllegalArgumentException("TLS policy descriptor metadata cannot be null.");
}
if( tlsPolicyDescriptor.getMeta().get("digestEncoding") != null && !tlsPolicyDescriptor.getMeta().get("digestEncoding").isEmpty() ) {
metadata.digestEncoding = tlsPolicyDescriptor.getMeta().get("digestEncoding");
}
if( tlsPolicyDescriptor.getMeta().get("digestAlgorithm") != null && !tlsPolicyDescriptor.getMeta().get("digestAlgorithm").isEmpty() ) {
metadata.digestAlgorithm = tlsPolicyDescriptor.getMeta().get("digestAlgorithm");
}
return metadata;
}
}