Java – Bouncy Castle – “Extended Key Usages”de um certificado X.509

Estou compartilhando o que aprendi. Então você provavelmente já viu isso no Stack Overflow ou encontrou numa pesquisa no Google.

De acordo com o RFC 5280 o Extended Key Usage “indica uma ou mais finalidades para as quais a chave pública de um certificado pode ser usada, em conjunto ou no lugar das finalidades básicas indicadas na extensão ‘key usage'”. Se um certificado possui essa extensão, ele deve ser usado apenas para um dos propósitos indicados.

Um certificado que possui as extensões “key usages” e “extended key usages” deve ser usado apenas para um propósito consistente com o definido para ambas as extensões.

O “EU Digital COVID Certificate” é um bom exemplo do uso de “extended key usages”. Eles utilizam essa extensão para definir qual tipo de documento pode ser assinado por um certificado X.509. Uma aplicação que verifica a validade de um documento “EU DCC” vai entender como inválido um documento assinado por um certificado que não possua o “extended key usages” apropriado.

A seção “4.2.1.12. Extended Key Usage” da RFC 5280 contém a documentação oficial da extensão.

O código neste post, foi elaborado utilizado a biblioteca Bouncy Castle na versão 1.72. Se você estiver usando uma versão anterior, o código pode não compilar.

Eu uso Gradle então, as dependências estão no formato dele:

implementation "org.bouncycastle:bcprov-jdk18on:1.72"
implementation "org.bouncycastle:bcpkix-jdk18on:1.72"
implementation "org.slf4j:slf4j-api:2.0.7"

The code I use for retrieve key usages is:

import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.cert.X509CertificateHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static final Logger LOG = LoggerFactory.getLogger("example");
	
public static List<String> extendKeyUsages(final X509Certificate x509) 
{
	if (x509 == null) 
	{
		return Collections.emptyList();
	} 
	else 
	{
		final List<String> rtn = new ArrayList<>();
		try
		{
			final X509CertificateHolder certHolder = new X509CertificateHolder(x509.getEncoded());
			final ExtendedKeyUsage extKeyUsage = ExtendedKeyUsage.fromExtensions(certHolder.getExtensions());
			
			if (extKeyUsage != null && extKeyUsage.getUsages() != null)
			{
				final KeyPurposeId[] kpi = extKeyUsage.getUsages();
				Arrays.stream(kpi).forEach(item -> rtn.add(item.getId()));
			}
		}
		catch (Exception e)
		{
			LOG.warn("{} :: {}", e.getClass().getName(), e.getMessage());
		}
		return rtn;
	}
}

O método retorna um “List<String>” que contém o “id” de cada “extended key usages” definido para um certificado X.509. Em caso de qualquer exceção, retorna uma lista vazia.

Você pode usar o código “como está” ou alterar para atender seus requisitos.