use of org.xipki.ca.api.profile.ExtensionSpec in project xipki by xipki.
the class CertprofileValidator method validate.
public static void validate(Certprofile certprofile) throws CertprofileException {
StringBuilder msg = new StringBuilder();
Map<ASN1ObjectIdentifier, ExtensionControl> controls = certprofile.getExtensionControls();
Set<ASN1ObjectIdentifier> types = new HashSet<>(controls.keySet());
CertLevel certLevel = certprofile.getCertLevel();
CertDomain certDomain = certprofile.getCertDomain();
ExtensionSpec spec = ExtensionSpec.getExtensionSpec(certDomain, certLevel);
// make sure that non-request extensions are not permitted in requests
Set<ASN1ObjectIdentifier> set = new HashSet<>();
for (ASN1ObjectIdentifier type : types) {
ExtensionControl control = controls.get(type);
if (control.isRequest() && spec.isNonRequest(type)) {
set.add(type);
}
}
if (CollectionUtil.isNotEmpty(set)) {
msg.append("extensions ").append(toString(set)).append(" must not be contained in request, ");
}
// make sure that non-permitted extensions are not configured
set.clear();
for (ASN1ObjectIdentifier type : types) {
if (spec.isNotPermitted(type)) {
set.add(type);
}
}
if (CollectionUtil.isNotEmpty(set)) {
msg.append("extensions ").append(toString(set)).append(" must not be contained, ");
}
// make sure that critical only extensions are not marked as non-critical.
set.clear();
for (ASN1ObjectIdentifier type : types) {
ExtensionControl control = controls.get(type);
if (control.isCritical() && spec.isNonCriticalOnly(type)) {
set.add(type);
}
}
if (CollectionUtil.isNotEmpty(set)) {
msg.append("critical only extensions are marked as non-critical ").append(toString(set)).append(", ");
}
// make sure that non-critical only extensions are not marked as critical.
set.clear();
for (ASN1ObjectIdentifier type : types) {
ExtensionControl control = controls.get(type);
if (!control.isCritical() && spec.isCriticalOnly(type)) {
set.add(type);
}
}
if (CollectionUtil.isNotEmpty(set)) {
msg.append("non-critical only extensions are marked as critical ").append(toString(set)).append(", ");
}
// make sure that required extensions are present
set.clear();
Set<ASN1ObjectIdentifier> requiredTypes = spec.getRequiredExtensions();
for (ASN1ObjectIdentifier type : requiredTypes) {
ExtensionControl extCtrl = controls.get(type);
if (extCtrl == null || !extCtrl.isRequired()) {
set.add(type);
}
}
if (!set.isEmpty()) {
msg.append("required extensions are not configured or not marked as required ").append(toString(set)).append(", ");
}
// KeyUsage
Set<KeyUsageControl> usages = certprofile.getKeyUsage();
if (certLevel == CertLevel.SubCA || certLevel == CertLevel.RootCA) {
// make sure the CA certificate contains usage keyCertSign and cRLSign
KeyUsage[] requiredUsages = new KeyUsage[] { KeyUsage.keyCertSign, KeyUsage.cRLSign };
for (KeyUsage usage : requiredUsages) {
if (!containsKeyusage(usages, usage)) {
msg.append("CA profile does not contain keyUsage ").append(usage).append(", ");
}
}
} else {
// make sure the EE certificate does not contain CA-only usages
KeyUsage[] caOnlyUsages = { KeyUsage.keyCertSign };
Set<KeyUsage> setUsages = new HashSet<>();
for (KeyUsage caOnlyUsage : caOnlyUsages) {
if (containsKeyusage(usages, caOnlyUsage)) {
setUsages.add(caOnlyUsage);
}
}
if (CollectionUtil.isNotEmpty(setUsages)) {
msg.append("EndEntity profile must not contain CA-only keyUsage ").append(setUsages).append(", ");
}
}
// BasicConstraints
if (certLevel == CertLevel.RootCA) {
Integer pathLen = certprofile.getPathLenBasicConstraint();
if (pathLen != null) {
msg.append("Root CA must not set PathLen, ");
}
}
if (certDomain == CertDomain.CABForumBR) {
validateCABForumBR(certprofile, msg);
}
// Edwards or Montgomery Curves (RFC8410)
Map<ASN1ObjectIdentifier, KeyParametersOption> keyAlgorithms = certprofile.getKeyAlgorithms();
boolean withEdwardsCurves = keyAlgorithms.containsKey(EdECConstants.id_ED25519) || keyAlgorithms.containsKey(EdECConstants.id_ED448);
boolean withMontgomeryCurves = keyAlgorithms.containsKey(EdECConstants.id_X25519) || keyAlgorithms.containsKey(EdECConstants.id_X448);
if (withEdwardsCurves || withMontgomeryCurves) {
Set<KeyUsage> requiredUsages = new HashSet<>();
Set<KeyUsage> optionalUsages = new HashSet<>();
for (KeyUsageControl m : usages) {
if (m.isRequired()) {
requiredUsages.add(m.getKeyUsage());
} else {
optionalUsages.add(m.getKeyUsage());
}
}
List<KeyUsage> allowedUsages;
if (withMontgomeryCurves) {
if (certLevel != CertLevel.EndEntity) {
msg.append("montgomery curves are not permitted in CA certificates, ");
}
if (!requiredUsages.contains(KeyUsage.keyAgreement)) {
msg.append("required KeyUsage KeyAgreement is not marked as 'required', ");
}
allowedUsages = Arrays.asList(KeyUsage.keyAgreement, KeyUsage.encipherOnly, KeyUsage.decipherOnly);
} else {
if (certLevel == CertLevel.EndEntity) {
if (!(requiredUsages.contains(KeyUsage.digitalSignature) || requiredUsages.contains(KeyUsage.contentCommitment))) {
msg.append("required KeyUsage digitalSignature or contentCommitment is not marked " + "as 'required', ");
}
allowedUsages = Arrays.asList(KeyUsage.digitalSignature, KeyUsage.contentCommitment);
} else {
allowedUsages = Arrays.asList(KeyUsage.digitalSignature, KeyUsage.contentCommitment, KeyUsage.keyCertSign, KeyUsage.cRLSign);
}
}
requiredUsages.removeAll(allowedUsages);
optionalUsages.removeAll(allowedUsages);
if (!requiredUsages.isEmpty()) {
msg.append("Required KeyUsage items ").append(requiredUsages).append(" are not permitted, ");
}
if (!optionalUsages.isEmpty()) {
msg.append("Optional KeyUsage items ").append(requiredUsages).append(" are not permitted, ");
}
}
final int len = msg.length();
if (len > 2) {
msg.delete(len - 2, len);
throw new CertprofileException(msg.toString());
}
}
Aggregations