Search in sources :

Example 1 with ProtectionVerificationResult

use of org.xipki.security.cmp.ProtectionVerificationResult in project xipki by xipki.

the class CmpAgentUtil method checkProtection.

// method extractXiActionContent
static void checkProtection(VerifiedPkiMessage response) throws PkiErrorException {
    notNull(response, "response");
    if (!response.hasProtection()) {
        return;
    }
    ProtectionVerificationResult protectionVerificationResult = response.getProtectionVerificationResult();
    boolean valid;
    if (protectionVerificationResult == null) {
        valid = false;
    } else {
        ProtectionResult protectionResult = protectionVerificationResult.getProtectionResult();
        valid = protectionResult == ProtectionResult.MAC_VALID || protectionResult == ProtectionResult.SIGNATURE_VALID;
    }
    if (!valid) {
        throw new PkiErrorException(PKISTATUS_RESPONSE_ERROR, PKIFailureInfo.badMessageCheck, "message check of the response failed");
    }
}
Also used : ProtectionResult(org.xipki.security.cmp.ProtectionResult) PkiErrorException(org.xipki.cmpclient.PkiErrorException) ProtectionVerificationResult(org.xipki.security.cmp.ProtectionVerificationResult)

Example 2 with ProtectionVerificationResult

use of org.xipki.security.cmp.ProtectionVerificationResult in project xipki by xipki.

the class BaseCmpResponder method processPkiMessage.

// method processPKIMessage0
public PKIMessage processPkiMessage(PKIMessage pkiMessage, X509Cert tlsClientCert, Map<String, String> parameters, AuditEvent event) {
    notNull(pkiMessage, "pkiMessage");
    notNull(event, "event");
    GeneralPKIMessage message = new GeneralPKIMessage(pkiMessage);
    PKIHeader reqHeader = message.getHeader();
    ASN1OctetString tid = reqHeader.getTransactionID();
    String msgId = RandomUtil.nextHexLong();
    event.addEventData(NAME_mid, msgId);
    if (tid == null) {
        byte[] randomBytes = randomTransactionId();
        tid = new DEROctetString(randomBytes);
    }
    String tidStr = Base64.encodeToString(tid.getOctets());
    event.addEventData(NAME_tid, tidStr);
    int reqPvno = reqHeader.getPvno().getValue().intValue();
    if (reqPvno < PVNO_CMP2000) {
        event.update(AuditLevel.INFO, AuditStatus.FAILED);
        event.addEventData(NAME_message, "unsupported version " + reqPvno);
        return buildErrorPkiMessage(tid, reqHeader, PKIFailureInfo.unsupportedVersion, null);
    }
    CmpControl cmpControl = getCmpControl();
    Integer failureCode = null;
    String statusText = null;
    Date messageTime = null;
    if (reqHeader.getMessageTime() != null) {
        try {
            messageTime = reqHeader.getMessageTime().getDate();
        } catch (ParseException ex) {
            LogUtil.error(LOG, ex, "tid=" + tidStr + ": could not parse messageTime");
        }
    }
    GeneralName recipient = reqHeader.getRecipient();
    boolean intentMe = recipient == null || intendsMe(recipient);
    if (!intentMe) {
        LOG.warn("tid={}: I am not the intended recipient, but '{}'", tid, reqHeader.getRecipient());
        failureCode = PKIFailureInfo.badRequest;
        statusText = "I am not the intended recipient";
    } else if (messageTime == null) {
        if (cmpControl.isMessageTimeRequired()) {
            failureCode = PKIFailureInfo.missingTimeStamp;
            statusText = "missing time-stamp";
        }
    } else {
        long messageTimeBias = cmpControl.getMessageTimeBias();
        if (messageTimeBias < 0) {
            messageTimeBias *= -1;
        }
        long msgTimeMs = messageTime.getTime();
        long currentTimeMs = System.currentTimeMillis();
        long bias = (msgTimeMs - currentTimeMs) / 1000L;
        if (bias > messageTimeBias) {
            failureCode = PKIFailureInfo.badTime;
            statusText = "message time is in the future";
        } else if (bias * -1 > messageTimeBias) {
            failureCode = PKIFailureInfo.badTime;
            statusText = "message too old";
        }
    }
    if (failureCode != null) {
        event.update(AuditLevel.INFO, AuditStatus.FAILED);
        event.addEventData(NAME_message, statusText);
        return buildErrorPkiMessage(tid, reqHeader, failureCode, statusText);
    }
    boolean isProtected = message.hasProtection();
    CmpRequestorInfo requestor;
    String errorStatus;
    if (isProtected) {
        try {
            ProtectionVerificationResult verificationResult = verifyProtection(tidStr, message, cmpControl);
            ProtectionResult pr = verificationResult.getProtectionResult();
            if (pr == ProtectionResult.SIGNATURE_VALID || pr == ProtectionResult.MAC_VALID) {
                errorStatus = null;
            } else if (pr == ProtectionResult.SIGNATURE_INVALID) {
                errorStatus = "request is protected by signature but invalid";
            } else if (pr == ProtectionResult.MAC_INVALID) {
                errorStatus = "request is protected by MAC but invalid";
            } else if (pr == ProtectionResult.SENDER_NOT_AUTHORIZED) {
                errorStatus = "request is protected but the requestor is not authorized";
            } else if (pr == ProtectionResult.SIGNATURE_ALGO_FORBIDDEN) {
                errorStatus = "request is protected by signature but the algorithm is forbidden";
            } else if (pr == ProtectionResult.MAC_ALGO_FORBIDDEN) {
                errorStatus = "request is protected by MAC but the algorithm is forbidden";
            } else {
                throw new IllegalStateException("should not reach here, unknown ProtectionResult " + pr);
            }
            requestor = (CmpRequestorInfo) verificationResult.getRequestor();
        } catch (Exception ex) {
            LogUtil.error(LOG, ex, "tid=" + tidStr + ": could not verify the signature");
            errorStatus = "request has invalid signature based protection";
            requestor = null;
        }
    } else if (tlsClientCert != null) {
        boolean authorized = false;
        X500Name x500Sender = getX500Sender(reqHeader);
        requestor = (x500Sender == null) ? null : getRequestor(x500Sender);
        if (requestor != null) {
            if (tlsClientCert.equals(requestor.getCert().getCert())) {
                authorized = true;
            }
        }
        if (authorized) {
            errorStatus = null;
        } else {
            LOG.warn("tid={}: not authorized requestor (TLS client '{}')", tid, tlsClientCert.getSubjectRfc4519Text());
            errorStatus = "requestor (TLS client certificate) is not authorized";
        }
    } else {
        errorStatus = "request has no protection";
        requestor = null;
    }
    if (errorStatus != null) {
        event.update(AuditLevel.INFO, AuditStatus.FAILED);
        event.addEventData(NAME_message, errorStatus);
        return buildErrorPkiMessage(tid, reqHeader, PKIFailureInfo.badMessageCheck, errorStatus);
    }
    PKIMessage resp = processPkiMessage0(pkiMessage, requestor, tid, message, msgId, parameters, event);
    if (isProtected) {
        resp = addProtection(resp, event, requestor);
    }
    return resp;
}
Also used : ProtectionResult(org.xipki.security.cmp.ProtectionResult) ProtectedPKIMessage(org.bouncycastle.cert.cmp.ProtectedPKIMessage) GeneralPKIMessage(org.bouncycastle.cert.cmp.GeneralPKIMessage) ProtectionVerificationResult(org.xipki.security.cmp.ProtectionVerificationResult) X500Name(org.bouncycastle.asn1.x500.X500Name) CMPException(org.bouncycastle.cert.cmp.CMPException) ParseException(java.text.ParseException) InsufficientPermissionException(org.xipki.ca.api.InsufficientPermissionException) CRMFException(org.bouncycastle.cert.crmf.CRMFException) OperationException(org.xipki.ca.api.OperationException) GeneralPKIMessage(org.bouncycastle.cert.cmp.GeneralPKIMessage) CmpRequestorInfo(org.xipki.ca.api.mgmt.RequestorInfo.CmpRequestorInfo) ParseException(java.text.ParseException) GeneralName(org.bouncycastle.asn1.x509.GeneralName)

Example 3 with ProtectionVerificationResult

use of org.xipki.security.cmp.ProtectionVerificationResult in project xipki by xipki.

the class BaseCmpResponder method verifyProtection.

// method randomBytes
private ProtectionVerificationResult verifyProtection(String tid, GeneralPKIMessage pkiMessage, CmpControl cmpControl) throws CMPException, InvalidKeyException {
    ProtectedPKIMessage protectedMsg = new ProtectedPKIMessage(pkiMessage);
    PKIHeader header = protectedMsg.getHeader();
    X500Name sender = getX500Sender(header);
    if (sender == null) {
        LOG.warn("tid={}: not authorized requestor 'null'", tid);
        return new ProtectionVerificationResult(null, ProtectionResult.SENDER_NOT_AUTHORIZED);
    }
    AlgorithmIdentifier protectionAlg = header.getProtectionAlg();
    if (protectedMsg.hasPasswordBasedMacProtection()) {
        PBMParameter parameter = PBMParameter.getInstance(pkiMessage.getHeader().getProtectionAlg().getParameters());
        HashAlgo owfAlg;
        try {
            owfAlg = HashAlgo.getInstance(parameter.getOwf());
        } catch (NoSuchAlgorithmException ex) {
            LogUtil.warn(LOG, ex);
            return new ProtectionVerificationResult(null, ProtectionResult.MAC_ALGO_FORBIDDEN);
        }
        if (!cmpControl.isRequestPbmOwfPermitted(owfAlg)) {
            LOG.warn("MAC_ALGO_FORBIDDEN (PBMParameter.owf: {})", owfAlg.getJceName());
            return new ProtectionVerificationResult(null, ProtectionResult.MAC_ALGO_FORBIDDEN);
        }
        SignAlgo macAlg;
        try {
            macAlg = SignAlgo.getInstance(parameter.getMac());
        } catch (NoSuchAlgorithmException ex) {
            LogUtil.warn(LOG, ex);
            return new ProtectionVerificationResult(null, ProtectionResult.MAC_ALGO_FORBIDDEN);
        }
        if (!cmpControl.isRequestPbmMacPermitted(macAlg)) {
            LOG.warn("MAC_ALGO_FORBIDDEN (PBMParameter.mac: {})", macAlg.getJceName());
            return new ProtectionVerificationResult(null, ProtectionResult.MAC_ALGO_FORBIDDEN);
        }
        int iterationCount = parameter.getIterationCount().getValue().intValue();
        if (iterationCount < 1000) {
            LOG.warn("MAC_ALGO_FORBIDDEN (PBMParameter.iterationCount: {} < 1000)", iterationCount);
            return new ProtectionVerificationResult(null, ProtectionResult.MAC_ALGO_FORBIDDEN);
        }
        ASN1OctetString asn1 = header.getSenderKID();
        // CHECKSTYLE:SKIP
        byte[] senderKID = (asn1 == null) ? null : asn1.getOctets();
        PKMACBuilder pkMacBuilder = new PKMACBuilder(new JcePKMACValuesCalculator());
        CmpRequestorInfo requestor = getMacRequestor(senderKID);
        if (requestor == null) {
            LOG.warn("tid={}: not authorized requestor with senderKID '{}", tid, (senderKID == null) ? "null" : Hex.toHexString(senderKID));
            return new ProtectionVerificationResult(null, ProtectionResult.SENDER_NOT_AUTHORIZED);
        }
        boolean macValid = protectedMsg.verify(pkMacBuilder, requestor.getPassword());
        return new ProtectionVerificationResult(requestor, macValid ? ProtectionResult.MAC_VALID : ProtectionResult.MAC_INVALID);
    } else {
        if (!cmpControl.getSigAlgoValidator().isAlgorithmPermitted(protectionAlg)) {
            LOG.warn("SIG_ALGO_FORBIDDEN: {}", pkiMessage.getHeader().getProtectionAlg().getAlgorithm().getId());
            return new ProtectionVerificationResult(null, ProtectionResult.SIGNATURE_ALGO_FORBIDDEN);
        }
        X500Name x500Sender = getX500Sender(header);
        CmpRequestorInfo requestor = (x500Sender == null) ? null : getRequestor(x500Sender);
        if (requestor == null) {
            LOG.warn("tid={}: not authorized requestor '{}'", tid, header.getSender());
            return new ProtectionVerificationResult(null, ProtectionResult.SENDER_NOT_AUTHORIZED);
        }
        ContentVerifierProvider verifierProvider = securityFactory.getContentVerifierProvider(requestor.getCert().getCert());
        if (verifierProvider == null) {
            LOG.warn("tid={}: not authorized requestor '{}'", tid, sender);
            return new ProtectionVerificationResult(requestor, ProtectionResult.SENDER_NOT_AUTHORIZED);
        }
        boolean signatureValid = protectedMsg.verify(verifierProvider);
        return new ProtectionVerificationResult(requestor, signatureValid ? ProtectionResult.SIGNATURE_VALID : ProtectionResult.SIGNATURE_INVALID);
    }
}
Also used : PKMACBuilder(org.bouncycastle.cert.crmf.PKMACBuilder) ProtectedPKIMessage(org.bouncycastle.cert.cmp.ProtectedPKIMessage) ProtectionVerificationResult(org.xipki.security.cmp.ProtectionVerificationResult) X500Name(org.bouncycastle.asn1.x500.X500Name) AlgorithmIdentifier(org.bouncycastle.asn1.x509.AlgorithmIdentifier) JcePKMACValuesCalculator(org.bouncycastle.cert.crmf.jcajce.JcePKMACValuesCalculator) CmpRequestorInfo(org.xipki.ca.api.mgmt.RequestorInfo.CmpRequestorInfo) ContentVerifierProvider(org.bouncycastle.operator.ContentVerifierProvider)

Aggregations

ProtectionVerificationResult (org.xipki.security.cmp.ProtectionVerificationResult)3 X500Name (org.bouncycastle.asn1.x500.X500Name)2 ProtectedPKIMessage (org.bouncycastle.cert.cmp.ProtectedPKIMessage)2 CmpRequestorInfo (org.xipki.ca.api.mgmt.RequestorInfo.CmpRequestorInfo)2 ProtectionResult (org.xipki.security.cmp.ProtectionResult)2 ParseException (java.text.ParseException)1 AlgorithmIdentifier (org.bouncycastle.asn1.x509.AlgorithmIdentifier)1 GeneralName (org.bouncycastle.asn1.x509.GeneralName)1 CMPException (org.bouncycastle.cert.cmp.CMPException)1 GeneralPKIMessage (org.bouncycastle.cert.cmp.GeneralPKIMessage)1 CRMFException (org.bouncycastle.cert.crmf.CRMFException)1 PKMACBuilder (org.bouncycastle.cert.crmf.PKMACBuilder)1 JcePKMACValuesCalculator (org.bouncycastle.cert.crmf.jcajce.JcePKMACValuesCalculator)1 ContentVerifierProvider (org.bouncycastle.operator.ContentVerifierProvider)1 InsufficientPermissionException (org.xipki.ca.api.InsufficientPermissionException)1 OperationException (org.xipki.ca.api.OperationException)1 PkiErrorException (org.xipki.cmpclient.PkiErrorException)1