Search code examples
javacryptographycertificatex509certificatex509certificate2

How to get the Policy Identifier and the Subject Type of Basic Constraints in a X509Certificate of java


I have a X509Certificate in java and I want to get the value of the Policy Identifier which there exists in the Certificate Policies field, as depicted in the following picture:

enter image description here

Also, I want to get the value of the Subject Type in Basic Constraints field, as depicted in the following picture:

enter image description here

My code:

public static void main(String[] args) throws Exception {
    CertificateFactory cf = CertificateFactory.getInstance("X509");
    InputStream in = new FileInputStream(new File("E:\\myCert.crt"));
    X509Certificate cert = (X509Certificate) cf.generateCertificate(in);
    int length = cert.getCertificateExtensionOIDs().size();
    String oid;
    for(int i = 0; i < length; i++){
        oid = cert.getCertificateExtensionOIDs().iterator().next();
        byte[] UID = cert.getExtensionValue(oid);
        DERObject derObject = toDERObject(UID);
        if(derObject instanceof DEROctetString){
            DEROctetString derOctetString = (DEROctetString) derObject;
            derObject = toDERObject(derOctetString.getOctets());
        }
// here I think, I should use derObject to retrieve cert info but I don't know how!?
}
public static DERObject toDERObject(byte[] data) throws IOException {
        ByteArrayInputStream inStream = new ByteArrayInputStream(data);
        ASN1InputStream DIS = new ASN1InputStream(inStream);
        return DIS.readObject();
    }

Solution

  • Look at that code. A little more data validation code may be needed and you have to be careful checking basic constraints, because the condition below may not be enough in some cases.

    import org.bouncycastle.asn1.ASN1InputStream;
    import org.bouncycastle.asn1.ASN1Sequence;
    import org.bouncycastle.asn1.DEROctetString;
    import org.bouncycastle.asn1.x509.CertificatePolicies;
    import org.bouncycastle.asn1.x509.PolicyInformation;
    
    import java.io.ByteArrayInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.InvalidKeyException;
    import java.security.SignatureException;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;
    import java.security.cert.X509Certificate;
    
    /**
     * 2016 krzysiek
     */
    public class App {
        private static final String CERTIFICATE_POLICY_OID = "2.5.29.32";
    
        private static final String FILENAME = "/test.cer";
    
        public static void main(String[] args) {
            try {
                X509Certificate cert = loadCertificate();
                String policyIdentifier = getCertificatePolicyId(cert, 0, 0);
    
                System.out.println("Policy Identifier: " + policyIdentifier);
    
                String subjectType = getSubjectType(cert);
                System.out.println("Subject Type: " + subjectType);
            } catch (Exception e) {
                System.out.println("Problem with certificate: " + e.getMessage());
            }
        }
    
        private static String getSubjectType(X509Certificate cert) {
            int pathLen = cert.getBasicConstraints();
            if (pathLen == -1) {
                if (cert.getKeyUsage()[5] || cert.getKeyUsage()[6]) { //simple check, there my be needed more key usage and extended key usage verification
                    return "Service";
                } else {
                    return "EndEntity";
                }
    
            } else {
                try {
                    cert.verify(cert.getPublicKey());
                    return "RootCA";
                } catch (SignatureException | InvalidKeyException e) {
                    return "SubCA";
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
        private static X509Certificate loadCertificate() {
            try (InputStream in = new FileInputStream(App.class.getResource(FILENAME).getFile())) {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                Certificate certificate = cf.generateCertificate(in);
                X509Certificate cert = (X509Certificate) certificate;
    
                return cert;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public static String getCertificatePolicyId(X509Certificate cert, int certificatePolicyPos, int policyIdentifierPos)
                throws IOException {
            byte[] extPolicyBytes = cert.getExtensionValue(CERTIFICATE_POLICY_OID);
            if (extPolicyBytes == null) {
                return null;
            }
    
            DEROctetString oct = (DEROctetString) (new ASN1InputStream(new ByteArrayInputStream(extPolicyBytes)).readObject());
            ASN1Sequence seq = (ASN1Sequence) new ASN1InputStream(new ByteArrayInputStream(oct.getOctets())).readObject();
    
            if (seq.size() <= (certificatePolicyPos)) {
                return null;
            }
    
            CertificatePolicies certificatePolicies = new CertificatePolicies(PolicyInformation.getInstance(seq.getObjectAt(certificatePolicyPos)));
            if (certificatePolicies.getPolicyInformation().length <= policyIdentifierPos) {
                return null;
            }
    
            PolicyInformation[] policyInformation = certificatePolicies.getPolicyInformation();
            return policyInformation[policyIdentifierPos].getPolicyIdentifier().getId();
        }
    }
    

    pom.xml:

    <properties>
        <bouncycastle.version>1.54</bouncycastle.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>${bouncycastle.version}</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcmail-jdk15on</artifactId>
            <version>${bouncycastle.version}</version>
        </dependency>
    </dependencies>