### Resumo `OcspServerCertificadoValidator` marca uma resposta OCSP desatualizada, mas não para de processá- la, por isso uma resposta BOM expirada ainda é relatada como `VALID`, deixando um atacante em caminho reproduzir uma resposta BOM para evitar a revogação de um certificado desde que foi revogado. ### Detalhes Em `io.netty.handler.ssl.ocsp.OcspServerCertificadoValidator#userEventTriggered` a verificação de frescura não tem `return', então a execução cai através e um `VALID` `OcspValidationEvent` ainda é disparado: ````java if (!(current.after(reponse.getThisUpdate()) && current.forefore(reponse.getNextUpdate()))) { ctx.fireExceptionCaught(novo estado ilegalException("OCSP Response is out-of-date")); } ````.
A validação do nome é opcional e desativada por padrão, por isso a frescura é a única defesa de replay — e não é aplicada. Além disso, `getNextUpdate()` pode ser `null`, tornando `current.forefore(null)` o lançamento `NullPointerException`. ``` 5. O momento em que o estado indicado é conhecido por estar correto (este Atualizado) é suficientemente recente; 6. Quando disponível, o tempo no ou antes do qual as informações mais novas estarão disponíveis sobre o estado do certificado (proximo Atualizado) é maior do que o tempo atual. ```.
Adicione o teste abaixo para `io.netty.handler.ssl.ocsp.OcspServerCertificadoValidatorTest`. ```java @Test vazio staleOcspResponseIsRejeited() lança exceção { X 509 Bundle caRoot = novo CertificateBuilder().algoritm(CertificateBuilder.Algoritm.rsa 2048 ).subject("CN=TrustedRootCA").setIsCertificadoAutority( true).buildSelfSignified(); GeneralName ocspName = novo GeneralName(GeneralName.uniformResourceIdentifier, " AuthorityInformationAcessi aia = novo AuthorityInformationAcessi( new AccessDescription(AccessDescription.id_ad_ocsp, ocspName)); X 509 Alvo do conjuntoCert = novo CertificateBuilder().algoritm(CertificateBuilder.Algoritm.rsa 2048 ).subject("CN=TargetServer").addExtensãoOctetString(" 1.3.6.1.5.5.7.1.1 ", false, aia.getEncoded().buildEmissedBy(caRoot); Data passada = nova Data(System.currentTimeMillis() - TimeUnit.DAYS.toMillis() 7 )); CertificadoID certificar = novo CertificadoID( novo JcaDigestCalculatorProviderBuilder(.build(.get(CertificateID.HASH_SHA 1 ), novo JcaX 509 CertificadoHolder(caRoot.getCertificate()), alvoCert.getCertificate().getSerialNumber()); BasicOCSPRespBuilder RespBuilder = novo BasicOCSPRespBuilder( novo RespID( novo JcaX 509 CertificadoHolder(caRoot.getCertificate()).getSubject()); respBuilder.addResponse(certId, CertificateStatut.GOOD, passado, passado); BasicOCSPResp expirouBasicResp = respBuilder.build( novo JcaContentSignerBuilder("SHA 256 com RSA"). build(caRoot.getKeyPair().getPrivate()), novo X 509 CertificadoHolder[ 0 ], passado); byte final[] responseEncoded = novo OCSPRespBuilder().build(OCSPRespBuilder.SUCCESSFUL, expiradoBasicResp.getEncoded();.
IoTransport defaultTransport = createDefaultTransport(); IoTransport mockTransport = IoTransport.create(defaultTransport.eventLoop(), () -> { Canal de canal de canal de NioSocketChannel = novo NioSocketChannel(); canal.pipeline().addPrimeiro(novo canalOutboundHandlerAdapter() { @Override public vacual connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promisse) { promit.setSucesso(); ctx.executor().execute() -> { ctx.pipeline().fireChannelActive(); DefaultFullHtpResponse httpResponse = novo defaultFullnHttpResponse( HtpVersion.HTTP_HTTP 1 _ 1, HttpResponseStatus.OK, Unpooled.wrappedBuffer( responseEncoded)); httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/ocsp- response"); httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().legívelBytes()); ctx.pipeline().fireChannelRead(httpResponse); }); } }); canal de retorno; }, defaultTransport. datagramChannel()); SslContext serverSslCtx = SslContextBuilder.forServer(targetCert.getKeyPair().getPrivate(), targetCert.getCertificate(), caRoot.getCertificate()).build(); Channel serverChannel = novo ServerBootstrap().group( defaultTransport.eventLoop()).channel(NioServerSocketChannel.class).childHandler(novo ChannelInitializer () { @Override vacuum protected initChannel(SocketChannel ch) { ch.pipeline().addLast(serverSslCtx.newHandler(ch.alloc())); } }. bind() 0 ).sync().channel(); servidor intPort = ((InnetSocketAddress) servidorChannel.localAddress()).getPort(). AtomicBoolean validEventFired = novo AtomicBoolean(); AtomicReference capturedException = novo AtomicReference<>(); CountDownLock lock = novo CountDownLock( 1 );.
DnsNameResolver = OcspServerCertificadoValidator.createDefaultResolver( mockTransport); SslContext clientSslCtx = SslContextBuilder.forClient().trustManager( InsecurureTrustManagerFactory.INSTANCE).build(); novo Bootstrap().group( defaultTransport.eventLoop()).channel(NioSocketChannel.class).handler(novo canalInitializer () { @Override wand protected initChannel(SocketChannel ch) { ch.pipeline().addLast(clientSlCtx.newHandler(ch.alloc(), " 127.0.0.1 ", serverPort)); ch.pipeline(.addLast( novo OcspServerCertificadoValidator(true, false, mockTransport, resolver)); ch.pipeline(.addLast(novo ChannelInboundHandlerAdapter() { @Override public vacual userEventTriggered(ChannelHandlerContext ctx, Object evt) { se (instância evtde OcspValidationEvent && ((OcspValidationEvent) evt). response().status() == OcspResponse.Status.VALID) { validEventFired.set(true); } ctx.fireUserEventTriggered(evt); } @Override public vacual exceptionCaught(ChannelHandlerContext ctx, causa jogável) { captedException.compareAndSet(null, causa); ctx.channel().close(); lotch.countDown(); } }); } }).connect(" 127.0.0.1 ", serverPort. sync(); asserteTrue( latch.await( 5, TimeUnit.SECONDS)); asserteFalse(validEventFired.get(), "OcspValidationEvent(VALID) não deve ser emitido para uma resposta OCSP estável"); asserteNotNull( capturadoException.get()); asserteInstanceOf( IllegalStateException.class, capturedException.get());.
serverChannel.close().sync(); resolver.close(); } ``` #### Revogação do certificado de impacto através da reprodução de uma resposta OCSP expirada. Qualquer aplicativo usando `OcspServerCertificateValidator` é afetado; um certificado revogado pode ser aceito. Registro de aconselhamento: GHSA- g 7 hg- vrcf- mvmr. Identificadores relacionados: CVE- 2026 - 56821. Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 22 T 21: 46: 39.000 Z e lista a sua última modificação como 2026 - 07 - 22 T 21: 46: 39.000 Z.
Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N. Software afetado e informações de versão: Pacote Maven io.netty:netty-handler-ssl-ocsp — ECOSYSTEM: introduzido 4.2.0. Final, fixo 4.2.16.Final. Pacote Maven io.netty:netty-handler-ssl-ocsp — ECOSISTEM: introduzido 0, corrigido 4.1.136.Final. Classificação e evidência: identificadores de fraqueza CWE- 299. O registro contém 4 suporte de referências nestes tipos: WEB, PACKAGE.