All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.signatures.CertificateInfo Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2024 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
 */
package com.itextpdf.signatures;

import com.itextpdf.bouncycastleconnector.BouncyCastleFactoryCreator;
import com.itextpdf.commons.bouncycastle.IBouncyCastleFactory;
import com.itextpdf.commons.bouncycastle.asn1.IASN1InputStream;
import com.itextpdf.commons.bouncycastle.asn1.IASN1ObjectIdentifier;
import com.itextpdf.commons.bouncycastle.asn1.IASN1Primitive;
import com.itextpdf.commons.bouncycastle.asn1.IASN1Sequence;
import com.itextpdf.commons.bouncycastle.asn1.IASN1Set;
import com.itextpdf.kernel.exceptions.PdfException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Class containing static methods that allow you to get information from
 * an X509 Certificate: the issuer and the subject.
 */
public class CertificateInfo {

    private static final IBouncyCastleFactory BOUNCY_CASTLE_FACTORY = BouncyCastleFactoryCreator.getFactory();

    // Inner classes

    /**
     * Class that holds an X509 name.
     */
    public static class X500Name {
        /**
         * Country code - StringType(SIZE(2)).
         */
        public static final IASN1ObjectIdentifier C = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.6");

        /**
         * Organization - StringType(SIZE(1..64)).
         */
        public static final IASN1ObjectIdentifier O = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.10");

        /**
         * Organizational unit name - StringType(SIZE(1..64)).
         */
        public static final IASN1ObjectIdentifier OU = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.11");

        /**
         * Title.
         */
        public static final IASN1ObjectIdentifier T = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.12");

        /**
         * Common name - StringType(SIZE(1..64)).
         */
        public static final IASN1ObjectIdentifier CN = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.3");

        /**
         * Device serial number name - StringType(SIZE(1..64)).
         */
        public static final IASN1ObjectIdentifier SN = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.5");

        /**
         * Locality name - StringType(SIZE(1..64)).
         */
        public static final IASN1ObjectIdentifier L = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.7");

        /**
         * State, or province name - StringType(SIZE(1..64)).
         */
        public static final IASN1ObjectIdentifier ST = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.8");

        /**
         * Naming attribute of type X520name.
         */
        public static final IASN1ObjectIdentifier SURNAME = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier("2.5.4.4");

        /**
         * Naming attribute of type X520name.
         */
        public static final IASN1ObjectIdentifier GIVENNAME = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier(
                "2.5.4.42");

        /**
         * Naming attribute of type X520name.
         */
        public static final IASN1ObjectIdentifier INITIALS = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier(
                "2.5.4.43");

        /**
         * Naming attribute of type X520name.
         */
        public static final IASN1ObjectIdentifier GENERATION = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier(
                "2.5.4.44");

        /**
         * Naming attribute of type X520name.
         */
        public static final IASN1ObjectIdentifier UNIQUE_IDENTIFIER = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier(
                "2.5.4.45");

        /**
         * Email address (RSA PKCS#9 extension) - IA5String.
         * 

* Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. */ public static final IASN1ObjectIdentifier EmailAddress = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier( "1.2.840.113549.1.9.1"); /** * Email address in Verisign certificates. */ public static final IASN1ObjectIdentifier E = EmailAddress; /** * Object identifier. */ public static final IASN1ObjectIdentifier DC = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier( "0.9.2342.19200300.100.1.25"); /** * LDAP User id. */ public static final IASN1ObjectIdentifier UID = BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier( "0.9.2342.19200300.100.1.1"); /** * A Map with default symbols. */ public static final Map DefaultSymbols = new HashMap<>(); static { DefaultSymbols.put(C, "C"); DefaultSymbols.put(O, "O"); DefaultSymbols.put(T, "T"); DefaultSymbols.put(OU, "OU"); DefaultSymbols.put(CN, "CN"); DefaultSymbols.put(L, "L"); DefaultSymbols.put(ST, "ST"); DefaultSymbols.put(SN, "SN"); DefaultSymbols.put(EmailAddress, "E"); DefaultSymbols.put(DC, "DC"); DefaultSymbols.put(UID, "UID"); DefaultSymbols.put(SURNAME, "SURNAME"); DefaultSymbols.put(GIVENNAME, "GIVENNAME"); DefaultSymbols.put(INITIALS, "INITIALS"); DefaultSymbols.put(GENERATION, "GENERATION"); } /** * A Map with values. */ public Map> values = new HashMap<>(); /** * Constructs an X509 name. * * @param seq an ASN1 Sequence */ public X500Name(IASN1Sequence seq) { @SuppressWarnings("unchecked") Enumeration e = seq.getObjects(); while (e.hasMoreElements()) { IASN1Set set = BOUNCY_CASTLE_FACTORY.createASN1Set(e.nextElement()); for (int i = 0; i < set.size(); i++) { IASN1Sequence s = BOUNCY_CASTLE_FACTORY.createASN1Sequence(set.getObjectAt(i)); String id = DefaultSymbols.get(BOUNCY_CASTLE_FACTORY.createASN1ObjectIdentifier(s.getObjectAt(0))); if (id != null) { List vs = values.get(id); if (vs == null) { vs = new ArrayList<>(); values.put(id, vs); } vs.add((BOUNCY_CASTLE_FACTORY.createASN1String(s.getObjectAt(1))).getString()); } } } } /** * Constructs an X509 name. * * @param dirName a directory name */ public X500Name(String dirName) { CertificateInfo.X509NameTokenizer nTok = new CertificateInfo.X509NameTokenizer(dirName); while (nTok.hasMoreTokens()) { String token = nTok.nextToken(); int index = token.indexOf('='); if (index == -1) { throw new IllegalArgumentException(/*MessageLocalization.getComposedMessage("badly.formated .directory.string")*/); } String id = token.substring(0, index).toUpperCase(); String value = token.substring(index + 1); List vs = values.get(id); if (vs == null) { vs = new ArrayList<>(); values.put(id, vs); } vs.add(value); } } /** * Gets the first entry from the field array retrieved from the values Map. * * @param name the field name * * @return the (first) field value */ public String getField(String name) { List vs = values.get(name); return vs == null ? null : (String) vs.get(0); } /** * Gets a field array from the values Map. * * @param name The field name * * @return List */ public List getFieldArray(String name) { return values.get(name); } /** * Getter for values. * * @return Map with the fields of the X509 name */ public Map> getFields() { return values; } @Override public String toString() { return values.toString(); } } /** * Class for breaking up an X500 Name into it's component tokens, similar to {@link java.util.StringTokenizer}. * We need this class as some of the lightweight Java environments don't support classes such as StringTokenizer. */ public static class X509NameTokenizer { private String oid; private int index; private StringBuffer buf = new StringBuffer(); /** * Creates an X509NameTokenizer. * * @param oid the oid that needs to be parsed */ public X509NameTokenizer(String oid) { this.oid = oid; this.index = -1; } /** * Checks if the tokenizer has any tokens left. * * @return true if there are any tokens left, false if there aren't */ public boolean hasMoreTokens() { return index != oid.length(); } /** * Returns the next token. * * @return the next token */ public String nextToken() { if (index == oid.length()) { return null; } int end = index + 1; boolean quoted = false; boolean escaped = false; buf.setLength(0); while (end != oid.length()) { char c = oid.charAt(end); if (c == '"') { if (escaped) { buf.append(c); } else { quoted = !quoted; } escaped = false; } else { if (escaped || quoted) { buf.append(c); escaped = false; } else if (c == '\\') { escaped = true; } else if (c == ',') { break; } else { buf.append(c); } } end++; } index = end; return buf.toString().trim(); } } // Certificate issuer /** * Get the issuer fields from an X509 Certificate. * * @param cert an X509Certificate * * @return an X500Name */ public static X500Name getIssuerFields(X509Certificate cert) { try { return new X500Name( BOUNCY_CASTLE_FACTORY.createASN1Sequence(CertificateInfo.getIssuer(cert.getTBSCertificate()))); } catch (Exception e) { throw new PdfException(e); } } /** * Get the "issuer" from the TBSCertificate bytes that are passed in. * * @param enc a TBSCertificate in a byte array * * @return an IASN1Primitive */ public static IASN1Primitive getIssuer(byte[] enc) { try { IASN1Sequence seq; try (IASN1InputStream in = BOUNCY_CASTLE_FACTORY.createASN1InputStream(new ByteArrayInputStream(enc))) { seq = BOUNCY_CASTLE_FACTORY.createASN1Sequence(in.readObject()); } return BOUNCY_CASTLE_FACTORY.createASN1Primitive( seq.getObjectAt(BOUNCY_CASTLE_FACTORY.createASN1TaggedObject(seq.getObjectAt(0)) == null ? 2 : 3)); } catch (IOException e) { throw new PdfException(e); } } // Certificate Subject /** * Get the subject fields from an X509 Certificate. * * @param cert an X509Certificate * * @return an X500Name */ public static X500Name getSubjectFields(X509Certificate cert) { try { if (cert != null) { return new X500Name( BOUNCY_CASTLE_FACTORY.createASN1Sequence(CertificateInfo.getSubject(cert.getTBSCertificate()))); } } catch (Exception e) { throw new PdfException(e); } return null; } /** * Get the "subject" from the TBSCertificate bytes that are passed in. * * @param enc A TBSCertificate in a byte array * * @return a IASN1Primitive */ public static IASN1Primitive getSubject(byte[] enc) { try { IASN1Sequence seq; try (IASN1InputStream in = BOUNCY_CASTLE_FACTORY.createASN1InputStream(new ByteArrayInputStream(enc))) { seq = BOUNCY_CASTLE_FACTORY.createASN1Sequence(in.readObject()); } return BOUNCY_CASTLE_FACTORY.createASN1Primitive( seq.getObjectAt(BOUNCY_CASTLE_FACTORY.createASN1TaggedObject(seq.getObjectAt(0)) == null ? 4 : 5)); } catch (IOException e) { throw new PdfException(e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy