es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Verifique el estado del certificado con una llamada OCSP a través de http – Spring Boot.

Mi requisito es comprobar el certificado de usuario devuelto por la Autoridad Nacional con el punto final de OCSP a través de http.

Los DSAP deben utilizar el Protocolo de Estado de Certificado en Línea (OCSP) para realizar la verificación de estado contra la Autoridad.

curl –cert ABCDSAP……pem –key ABCDSAP…. clave privada.key.pem –cacert ABCManagementCAStaging.cer.txt https://ocsp.staging.abc.gov.cs –data-binary @request.der –header "Content-Type:application/ocsp-requests" –header "ocsp.staging.abc.gov.cs" –output stgnca-ocsp-resp.der –insecure -v >> _STG_CDNS.txt 2>&1

Puedo hacer una llamada de API REST para enviar el certificado obtenido en formato DER a OCSP.

No estoy seguro de cómo obtener la respuesta y analizarla para verificar el estado del certificado.

No puedo encontrar ninguna pista correcta para implementar en Spring Boot. Por favor, guíame sobre cómo proceder.

El siguiente código es lo que se me ocurrió

public OcspResponse validateUserCert(String userCert) {
try {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.add(HttpHeaders.HOST, "ocsp.staging.abc.gov.ab");

    OcspRequest request = new OcspRequest(userCert.getBytes(StandardCharsets.UTF_8));

    return singpassRestTemplate
            .exchange(
                    ocspProperties.getUrl(),
                    HttpMethod.POST,
                    new HttpEntity<>(request, headers),
                    OcspResponse.class)
            .getBody();
} catch (Exception e) {
    log.error(e.getMessage(), e);
    throw new DigitalSigningWebhookServerError(
        DigitalSigningErrorCode.OCSP_EXCEPTION,
        DigitalSigningErrorCode.OCSP_EXCEPTION.getDescription());
}

}

Vi algunas implementaciones con Bouncy Castle: ¿alguien puede indicarme hacia la implementación correcta?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Si estás buscando una implementación de validación OCSP utilizando Bouncy Castle en Spring Boot, puedes intentar los siguientes pasos:

    1. Agrega la dependencia de Bouncy Castle a tu proyecto:
    <dependency>
        <groupid>org.bouncycastle</groupid>
        <artifactid>bcprov-jdk15on</artifactid>
        <version>1.65</version>
    </dependency>
    
    1. Crea una clase para manejar la validación OCSP utilizando Bouncy Castle, como la siguiente:
    import org.bouncycastle.cert.ocsp.BasicOCSPResp;
    import org.bouncycastle.cert.ocsp.CertificateID;
    import org.bouncycastle.cert.ocsp.CertificateStatus;
    import org.bouncycastle.cert.ocsp.OCSPException;
    import org.bouncycastle.cert.ocsp.OCSPReq;
    import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
    import org.bouncycastle.cert.ocsp.OCSPResp;
    import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
    import org.bouncycastle.cert.ocsp.RevocationStatus;
    import org.bouncycastle.cert.ocsp.SingleResp;
    import org.bouncycastle.operator.ContentVerifierProvider;
    import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
    import org.bouncycastle.operator.DigestCalculator;
    import org.bouncycastle.operator.DigestCalculatorProvider;
    import org.bouncycastle.operator.OperatorCreationException;
    import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
    import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
    import org.springframework.http.HttpStatus;
    
    import java.io.IOException;
    import java.net.URL;
    import java.security.Security;
    import java.security.cert.X509Certificate;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Optional;
    import java.util.function.Supplier;
    
    public class OcspValidator {
    
        static {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        }
    
        private final String ocspUrl;
    
        public OcspValidator(String ocspUrl) {
            this.ocspUrl = ocspUrl;
        }
    
        public void validate(X509Certificate certificate) {
            try {
                CertificateID id = new CertificateID(new JcaDigestCalculatorProviderBuilder()
                        .build().get(CertificateID.HASH_SHA1), new JcaX509CertificateHolder(certificate).toASN1Structure(),
                        new JcaX509CertificateHolder(certificate.getIssuerX500Principal().getName()).toASN1Structure()
                );
    
                OCSPReq request = new OCSPReqBuilder().addRequest(id).build();
                byte[] req = request.getEncoded();
    
                URL url = new URL(ocspUrl);
                OCSPResp response = new OCSPResp(url.openConnection().getInputStream());
                BasicOCSPResp basicResponse = (BasicOCSPResp) response.getResponseObject();
    
                DigestCalculatorProvider digestCalculatorProvider = new JcaDigestCalculatorProviderBuilder().build();
                DigestCalculator calculator = digestCalculatorProvider.get(CertificateID.HASH_SHA1);
    
                ContentVerifierProvider verifierProvider = new JcaContentVerifierProviderBuilder()
                        .build(basicResponse.getCerts()[0]);
    
                if (basicResponse
                        .getResponses()
                        .length > 1) {
                    throw new RuntimeException("La respuesta OCSP contiene múltiples respuestas");
                }
    
                SingleResp singleResponse = basicResponse.getResponses()[0];
                RevocationStatus status = singleResponse.getCertStatus();
    
                if (status == RevocationStatus.REVOKED) {
                    throw new RuntimeException("El certificado está revocado");
                } else if (status == RevocationStatus.UNKNOWN) {
                    throw new RuntimeException("El estado del certificado es desconocido");
                } else {
                    CertificateStatus certificateStatus = singleResponse.getCertStatus();
                    Supplier<boolean> isGood = () -> {
                        // Si tenemos una verificación previa del ID del respondedor, debemos examinar el certificado utilizado para firmar
                        // esta respuesta en lugar del certificado original del solicitante. Esto es lo mismo
                        // que el certificado respondedor en casos básicos.
                        X509CertificateHolder responderCertHolder = new JcaX509CertificateHolder(basicResponse.getCerts()[0]);
                        if (singleResponse.hasExtensions()) {
                            for (ASN1ObjectIdentifier ocspExtensionOid : OcspExtensions.SINGLE_REQUEST_EXTENSION_OIDS) {
                                Extension extension = singleResponse
                                        .getSingleExtensions()
                                        .getExtension(ocspExtensionOid);
                                if (extension != null) {
                                    OcspExtension ocspExtension = OcspExtensions.getExtension(ocspExtensionOid);
                                    if (ocspExtension != null) {
                                        ocspExtension
                                                .validate(
                                                        extension,
                                                        singleResponse.getCertID(),
                                                        responderCertHolder,
                                                        calculator
                                                );
                                    }
                                }
                            }
                        }
                        return true;
                    };
                    Optional<throwable> exception = Arrays
                            .stream(basicResponse.getCerts())
                            .anyMatch(cert -> {
                                try {
                                    cert.checkValidity();
                                    cert.verify(verifierProvider);
                                    return false;
                                } catch (Exception e) {
                                    return true;
                                }
                            }) ? Optional.of(new Exception("Certificado de firma inválido")) : Optional.empty();
                    if (exception.isPresent()) {
                        throw exception.get();
                    }
                    if (!isGood.get()) {
                        throw new RuntimeException("La verificación del certificado ha fallado");
                    }
                }
            } catch (OCSPException | OperatorCreationException | IOException e) {
                throw new DigitalSigningWebhookServerError(
                    DigitalSigningErrorCode.OCSP_EXCEPTION,
                    DigitalSigningErrorCode.OCSP_EXCEPTION.getDescription(),
                    HttpStatus.INTERNAL_SERVER_ERROR);
            } catch (Exception e) {
                throw new DigitalSigningWebhookServerError(
                    DigitalSigningErrorCode.OCSP_EXCEPTION,
                    DigitalSigningErrorCode.OCSP_EXCEPTION.getDescription(),
                    HttpStatus.INTERNAL_SERVER_ERROR);
            }
        }
    
    }
    
    1. Usa la clase OcspValidator en tu código principal:

    “`java
    @Autowired
    private OcspValidator validator;

    public void validateUserCert(String userCert) {
    X509Certificate certificate = extractCertificateFromUserCert(userCert);
    validator.validate(certificate);
    }
    “`

Comments are closed.