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

org.bouncycastle.cert.DeltaCertificateTool Maven / Gradle / Ivy

There is a newer version: 6.2.20
Show newest version
package org.bouncycastle.cert;

import java.io.IOException;

import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;

/**
 * General tool for handling the extension described in: https://datatracker.ietf.org/doc/draft-bonnell-lamps-chameleon-certs/
 */
public class DeltaCertificateTool
{
    public static final int signature = 0x01;
    public static final int issuer = 0x02;
    public static final int validity = 0x04;
    public static final int subject = 0x08;
    public static final int extensions = 0x10;

    public static Extension makeDeltaCertificateExtension(boolean isCritical, int includeFlags, X509CertificateHolder deltaCert)
        throws IOException
    {
        ASN1EncodableVector deltaV = new ASN1EncodableVector();

        deltaV.add(new ASN1Integer(deltaCert.getSerialNumber()));
        if ((includeFlags & signature) != 0)
        {
            deltaV.add(new DERTaggedObject(false, 0, deltaCert.getSignatureAlgorithm()));
        }
        if ((includeFlags & issuer) != 0)
        {
            deltaV.add(new DERTaggedObject(false, 1, deltaCert.getIssuer()));
        }

        //
        // before and after dates
        //
        if ((includeFlags & validity) != 0)
        {
            ASN1EncodableVector validity = new ASN1EncodableVector(2);
            validity.add(deltaCert.toASN1Structure().getStartDate());
            validity.add(deltaCert.toASN1Structure().getEndDate());

            deltaV.add(new DERTaggedObject(false, 2, new DERSequence(validity)));
        }
        if ((includeFlags & subject) != 0)
        {
            deltaV.add(new DERTaggedObject(false, 3, deltaCert.getSubject()));
        }
        deltaV.add(deltaCert.getSubjectPublicKeyInfo());
        if ((includeFlags & extensions) != 0)
        {
            if (deltaCert.getExtensions() != null)
            {
                deltaV.add(new DERTaggedObject(false, 4, deltaCert.getExtensions()));
            }
        }
        deltaV.add(new DERBitString(deltaCert.getSignature()));

        return new Extension(new ASN1ObjectIdentifier("2.16.840.1.114027.80.6.1"), isCritical, new DERSequence(deltaV).getEncoded(ASN1Encoding.DER));
    }

    public static X509CertificateHolder extractDeltaCertificate(X509CertificateHolder originCert)
    {
        ASN1ObjectIdentifier deltaExtOid = new ASN1ObjectIdentifier("2.16.840.1.114027.80.6.1");
        Extension deltaExt = originCert.getExtension(deltaExtOid);

        ASN1Sequence seq = ASN1Sequence.getInstance(deltaExt.getParsedValue());
//        *      version          [ 0 ]  Version DEFAULT v1(0),
//        *      serialNumber            CertificateSerialNumber,
//        *      signature               AlgorithmIdentifier,
//        *      issuer                  Name,
//        *      validity                Validity,
//        *      subject                 Name,
//        *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
//        *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
//        *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
//        *      extensions        [ 3 ] Extensions OPTIONAL
        ASN1Sequence originTbs = ASN1Sequence.getInstance(originCert.toASN1Structure().getTBSCertificate().toASN1Primitive());
        int idx = 0;
        ASN1Encodable[] extracted = originTbs.toArray();

        extracted[0] = originTbs.getObjectAt(0);
        extracted[1] = ASN1Integer.getInstance(seq.getObjectAt(idx++));

        ASN1Encodable next = seq.getObjectAt(idx++);
        while (next instanceof ASN1TaggedObject)
        {
            ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(next);
            switch (tagged.getTagNo())
            {
            case 0:
                extracted[2] = ASN1Sequence.getInstance(tagged, false);
                break;
            case 1:
                extracted[3] = ASN1Sequence.getInstance(tagged, true);   // issuer
                break;
            case 2:
                extracted[4] = ASN1Sequence.getInstance(tagged, false);
                break;
            case 3:
                extracted[5] = ASN1Sequence.getInstance((ASN1TaggedObject)next, true);   // subject
                break;
            }
            next = seq.getObjectAt(idx++);
        }

        extracted[6] = next;  // subjectPublicKey

        if (extracted[2] == null)
        {
            extracted[2] = originTbs.getObjectAt(2);
        }

        if (extracted[3] == null)
        {
            extracted[3] = originTbs.getObjectAt(3);
        }

        if (extracted[4] == null)
        {
            extracted[4] = originTbs.getObjectAt(4);
        }

        if (extracted[5] == null)
        {
            extracted[5] = originTbs.getObjectAt(5);
        }

        ExtensionsGenerator extGen = extractExtensions(originTbs);

        if (idx < (seq.size() - 1))  // last element is the signature
        {
            next = seq.getObjectAt(idx++);
            ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(next);
            if (tagged.getTagNo() != 4)
            {
                throw new IllegalArgumentException("malformed delta extension");
            }

            ASN1Sequence deltaExts = ASN1Sequence.getInstance(tagged, false);

            for (int i = 0; i != deltaExts.size(); i++)
            {
                extGen.replaceExtension(Extension.getInstance(deltaExts.getObjectAt(i)));
            }

            extracted[7] = new DERTaggedObject(3, extGen.generate());
        }
        else
        {
            if (!extGen.isEmpty())
            {
                extracted[7] = extGen.generate();
            }
            {
                extracted[7] = null;
            }
        }

        ASN1EncodableVector tbsDeltaCertV = new ASN1EncodableVector(7);
        for (int i = 0; i != extracted.length; i++)
        {
            if (extracted[i] != null)
            {
                tbsDeltaCertV.add(extracted[i]);
            }
        }

        ASN1EncodableVector certV = new ASN1EncodableVector();
        certV.add(new DERSequence(tbsDeltaCertV));
        certV.add(ASN1Sequence.getInstance(extracted[2]));
        certV.add(ASN1BitString.getInstance(seq.getObjectAt(seq.size() - 1)));

        return new X509CertificateHolder(Certificate.getInstance(new DERSequence(certV)));
    }

    private static ExtensionsGenerator extractExtensions(ASN1Sequence originTbs)
    {
        ASN1ObjectIdentifier deltaExtOid = new ASN1ObjectIdentifier("2.16.840.1.114027.80.6.1");
        ASN1Sequence originExt = ASN1Sequence.getInstance(ASN1TaggedObject.getInstance(originTbs.getObjectAt(originTbs.size() - 1)), true);
        ExtensionsGenerator extGen = new ExtensionsGenerator();

        for (int i = 0; i != originExt.size(); i++)
        {
            Extension ext = Extension.getInstance(originExt.getObjectAt(i));
            if (!deltaExtOid.equals(ext.getExtnId()))
            {
                extGen.addExtension(ext);
            }
        }

        return extGen;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy