Class CertificateParser


  • public abstract class CertificateParser
    extends Object
    The CertificateParser class is used to parse certificates and create Certificate instances.

    A parser instance is created for a specific certificate format (e.g. X509)

    The parser can be used in two ways:

    • to parse certificate elements from a provided byte array
    • to allocate a Certificate instance and initialize it with a subset of selected elements copied from the specified byte array

    Certificate Parsing

    The CertificateParser instance can be used to parse certificates from a byte array and to trigger a CertificateParser.ParserHandler for each element found. The handler receives information on each element found including its value.

    Example: parsing and verification

     public class CertExample1 implements FieldHandler, KeyHandler, ExtensionHandler {
    
        private final CertificateParser parser = CertificateParser.getInstance(CertificateParser.TYPE_X509_DER);
        private PublicKey pubKey;
        private final Certificate rootCert;
    
        public CertExample1(Certificate root) {
            this.rootCert = root;
        }
        // parse certificate, verify signature with root cert, extract and return public key
        public PublicKey parse(byte[] data, short offset, short length) throws CertificateException {
            parser.parseCert(data, offset, length, this, rootCert.getPublicKey());
            return pubKey;
        }
    
        // --- FieldHandler ----------------------------------------------------------
        @Override
        public boolean onField(short fieldID, byte[] field) {
            switch (fieldID) {
            case X509Certificate.FIELD_TBS_NOT_AFTER:
                if (expired(field)) {
                    CertificateException.throwIt(EXPIRED);
                }
                break;
            case X509Certificate.FIELD_TBS_PUBLIC_KEY_INFO:
                if (pubKey == null) {
                    // KeyHandler has not been called because type not supported
                    // use proprietary decoder
                    pubKey = decodeKey(value);
                }
                break;
            }
            return false;
        }
    
        // --- ExtensionHandler ------------------------------------------------------
        @Override
        public boolean onExtension(byte[] oid, boolean isCritical, byte[] value) {
            if (Util.arrayCompare(oid, (short) 0, OID_KEY_USAGE, (short) 0, OID_KEY_USAGE.length) == 0) {
                // check usage
            }
        }
    
        // --- KeyHandler ------------------------------------------------------------
        @Override
        public PublicKey onKey(byte keytype, short params) {
            if (keytype == KeyBuilder.TYPE_XEC) {
                pubKey = (PublicKey) KeyBuilder.buildXECKey(
                        NamedParameterSpec.getInstance(params),
                        JCSystem.MEMORY_TYPE_PERSISTENT,
                        false);
            } else {
                pubKey = (PublicKey) KeyBuilder.buildKey(keytype, params, false);
            }
            return pubKey;
        }
    }
     
    Note: The parsing may fail at any time due to an invalid element encoding (fail-fast processing since there is no copy of the source buffer). Consequently, the handler is not called for subsequent elements if an invalid element is found. This could also be the case if the buffer is modified during parsing with invalid data after the ones already parsed (for example if the handler modifies the buffer)

    Parsing and allocating a Certificate instance

    The CertificateParser instance can be used to parse an existing byte array and to create a new Certificate instance. A X509Certificate.FieldHandler is used to specify which certificate fields should be stored to be used to initialize a new Certificate instance.

    Example: Parsing and creation of a new Certificate instance

     public class CertExample2 implements FieldHandler, ExtensionHandler {
    
         private final CertificateParser parser = CertificateParser.getInstance(CertificateParser.TYPE_X509_DER);
    
         public Certificate buildCert(byte[] data, short offset, short length) throws CertificateException {
             return parser.buildCert(data, offset, length, this);
         }
    
         // --- FieldHandler ----------------------------------------------------------
         @Override
         public boolean onField(short fieldID, byte[] field) {
             switch (fieldID) {
             case X509Certificate.FIELD_TBS_ISSUER:    // store issuer name
             case X509Certificate.FIELD_TBS_NOT_AFTER: // store validity date
             case X509Certificate.FIELD_TBS_NOT_BEFORE:// store validity date
             case X509Certificate.FIELD_TBS_SUBJECT:   // store subject
                 return true;
             }
             // skip other fields
             return false;
         }
    
         // --- ExtensionHandler ------------------------------------------------------
         @Override
         public boolean onExtension(byte[] oid, boolean isCritical, byte[] value) {
            // keep critical extensions
            // and Subject Alternative Name (OID: 2.5.29.17)
            return
               isCritical ||
               Util.arrayCompare(oid, (short)0, OID_SUBJECT_ALT_NAME, (short)0, OID_SUBJECT_ALT_NAME.length) == 0);
         }
     }
     

    Since:
    3.1