Search in sources :

Example 1 with ExtensionSpec

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());
    }
}
Also used : KeyParametersOption(org.xipki.ca.api.profile.KeyParametersOption) CertprofileException(org.xipki.ca.api.profile.CertprofileException) ExtensionSpec(org.xipki.ca.api.profile.ExtensionSpec) ASN1ObjectIdentifier(org.bouncycastle.asn1.ASN1ObjectIdentifier)

Aggregations

ASN1ObjectIdentifier (org.bouncycastle.asn1.ASN1ObjectIdentifier)1 CertprofileException (org.xipki.ca.api.profile.CertprofileException)1 ExtensionSpec (org.xipki.ca.api.profile.ExtensionSpec)1 KeyParametersOption (org.xipki.ca.api.profile.KeyParametersOption)1