/*
* This file is part of rockframework.
*
* rockframework is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* rockframework 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>;.
*/
package br.net.woodstock.rockframework.security.cert.impl;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import br.net.woodstock.rockframework.security.cert.CertificateException;
import br.net.woodstock.rockframework.security.cert.CertificateValidator;
import br.net.woodstock.rockframework.security.cert.ValidationError;
import br.net.woodstock.rockframework.security.config.SecurityLog;
import br.net.woodstock.rockframework.security.util.BouncyCastleProviderHelper;
import br.net.woodstock.rockframework.util.Assert;
import br.net.woodstock.rockframework.utils.CollectionUtils;
import br.net.woodstock.rockframework.utils.ConditionUtils;
public class HierarchyCertificateValidator implements CertificateValidator {
public static final String VALIDATOR_NAME = "Hierarchy Validator";
private Certificate[] certificates;
public HierarchyCertificateValidator() {
super();
}
public HierarchyCertificateValidator(final Certificate certificate) {
super();
Assert.notNull(certificate, "certificate");
this.certificates = new Certificate[] { certificate };
}
public HierarchyCertificateValidator(final Certificate[] certificates) {
super();
Assert.notEmpty(certificates, "certificates");
this.certificates = certificates;
}
@Override
public ValidationError[] validate(final Certificate[] chain) {
Assert.notEmpty(chain, "chain");
if (chain.length < 2) {
return new ValidationError[] { new ValidationError(HierarchyCertificateValidator.VALIDATOR_NAME, "Certificate chain must be greater than 1(certificate and issuer certificate") };
}
List<ValidationError> list = new ArrayList<ValidationError>();
for (int i = 0; i < chain.length - 1; i++) {
X509Certificate certificate = (X509Certificate) chain[i];
X509Certificate issuer = (X509Certificate) chain[i + 1];
try {
certificate.verify(issuer.getPublicKey());
int pathLen = issuer.getBasicConstraints();
if (pathLen == -1) {
list.add(new ValidationError(HierarchyCertificateValidator.VALIDATOR_NAME, "Certificate issuer '" + BouncyCastleProviderHelper.toString(issuer.getSubjectX500Principal()) + "' is not a CA"));
}
} catch (SignatureException e) {
list.add(new ValidationError(HierarchyCertificateValidator.VALIDATOR_NAME, "Certificate '" + BouncyCastleProviderHelper.toString(certificate.getSubjectX500Principal()) + "' not signed by '" + BouncyCastleProviderHelper.toString(issuer.getSubjectX500Principal()) + "'"));
} catch (Exception e) {
throw new CertificateException(e);
}
}
try {
if (ConditionUtils.isNotEmpty(this.certificates)) {
boolean requiredOk = false;
outer: for (int i = 1; i < chain.length; i++) {
X509Certificate issuer = (X509Certificate) chain[i];
for (Certificate required : this.certificates) {
X509Certificate x509Required = (X509Certificate) required;
if (Arrays.equals(issuer.getEncoded(), x509Required.getEncoded())) {
SecurityLog.getInstance().getLogger().info("Matches " + BouncyCastleProviderHelper.toString(x509Required.getSubjectX500Principal()));
requiredOk = true;
break outer;
}
}
}
if (!requiredOk) {
list.add(new ValidationError(HierarchyCertificateValidator.VALIDATOR_NAME, "Certificate chain is invalid, a required certificate could not be found"));
}
}
} catch (CertificateEncodingException e) {
throw new CertificateException(e);
}
return CollectionUtils.toArray(list, ValidationError.class);
}
}