net.ripe.rpki.commons.crypto.rfc3779.ResourceExtensionEncoder.java Source code

Java tutorial

Introduction

Here is the source code for net.ripe.rpki.commons.crypto.rfc3779.ResourceExtensionEncoder.java

Source

/**
 * The BSD License
 *
 * Copyright (c) 2010-2012 RIPE NCC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   - Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *   - Neither the name of the RIPE NCC nor the names of its contributors may be
 *     used to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package net.ripe.rpki.commons.crypto.rfc3779;

import net.ripe.ipresource.Asn;
import net.ripe.ipresource.IpAddress;
import net.ripe.ipresource.IpRange;
import net.ripe.ipresource.IpResource;
import net.ripe.ipresource.IpResourceRange;
import net.ripe.ipresource.IpResourceSet;
import net.ripe.ipresource.IpResourceType;
import net.ripe.rpki.commons.crypto.util.Asn1Util;
import org.apache.commons.lang.Validate;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Encodes the certificate resource extensions as specified in RFC3779. Resource
 * inheritance is not yet supported.
 * <p/>
 * The methods in this class are named after the grammar rules in RFC3779,
 * suffixed with "ToDer".
 */
public class ResourceExtensionEncoder {

    /**
     * id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) dod(6)
     * internet(1) security(5) mechanisms(5) pkix(7) }
     */
    public static final String OID_PKIX = "1.3.6.1.5.5.7";

    /**
     * id-pe OBJECT IDENTIFIER ::= { id-pkix 1 }
     */
    public static final String OID_PE = OID_PKIX + ".1";

    /**
     * id-pe-ipAddrBlocks OBJECT IDENTIFIER ::= { id-pe 7 }
     */
    public static final ASN1ObjectIdentifier OID_IP_ADDRESS_BLOCKS = new ASN1ObjectIdentifier(OID_PE + ".7");

    /**
     * id-pe-autonomousSysIds OBJECT IDENTIFIER ::= { id-pe 8 }
     */
    public static final ASN1ObjectIdentifier OID_AUTONOMOUS_SYS_IDS = new ASN1ObjectIdentifier(OID_PE + ".8");

    /**
     * Encode the IP Address Block extension for Resource Certificates. This
     * extension is identified by {@link #OID_IP_ADDRESS_BLOCKS}.
     *
     * @param inheritIpv4 inherit IPv4 resources from signing certificate.
     * @param inheritIpv6 inherit IPv6 resources from signing certificate.
     * @param resources   the set of IPv4 and IPv6 resources.
     * @return the DER encoding of the IP Address Block Extension.
     */
    public ASN1Object encodeIpAddressBlocks(boolean inheritIpv4, boolean inheritIpv6, IpResourceSet resources) {
        SortedMap<AddressFamily, IpResourceSet> addressBlocks = new TreeMap<AddressFamily, IpResourceSet>();

        if (inheritIpv4) {
            addressBlocks.put(AddressFamily.IPV4, null);
        } else if (resources.containsType(IpResourceType.IPv4)) {
            addressBlocks.put(AddressFamily.IPV4, resources);
        }

        if (inheritIpv6) {
            addressBlocks.put(AddressFamily.IPV6, null);
        } else if (resources.containsType(IpResourceType.IPv6)) {
            addressBlocks.put(AddressFamily.IPV6, resources);
        }

        return addressBlocks.isEmpty() ? null : ipAddressBlocksToDer(addressBlocks);
    }

    /**
     * Encode the AS Identifier extension for resource certificates. Only the
     * "asnum" part is encoded, since we do not use the "rdi" (routing domain
     * identifiers).
     *
     * @param inherit   inherit ASNs from signing certificate.
     * @param resources the set of ASNs.
     * @return the DER encoding of the AS Identifier extension.
     */
    public ASN1Object encodeAsIdentifiers(boolean inherit, IpResourceSet resources) {
        if (inherit || resources.containsType(IpResourceType.ASN)) {
            return asIdentifiersToDer(inherit, resources, false, new IpResourceSet());
        }
        return null;
    }

    /*
     * Internal support code.
     */

    /**
     * ASIdentifiers ::= SEQUENCE { asnum [0] EXPLICIT ASIdentifierChoice
     * OPTIONAL, rdi [1] EXPLICIT ASIdentifierChoice OPTIONAL}
     */
    ASN1Object asIdentifiersToDer(boolean inheritAsn, IpResourceSet asnResources, boolean inheritRdi,
            IpResourceSet rdiResources) {
        List<ASN1Encodable> seq = new ArrayList<ASN1Encodable>(2);
        if (inheritAsn || asnResources.containsType(IpResourceType.ASN)) {
            seq.add(new DERTaggedObject(0, asIdentifierChoiceToDer(inheritAsn, asnResources)));
        }
        if (inheritRdi || rdiResources.containsType(IpResourceType.ASN)) {
            seq.add(new DERTaggedObject(1, asIdentifierChoiceToDer(inheritRdi, rdiResources)));
        }
        return new DERSequence(seq.toArray(new ASN1Encodable[seq.size()]));
    }

    /**
     * ASIdentifierChoice ::= CHOICE { inherit NULL, -- inherit from issuer --
     * asIdsOrRanges SEQUENCE OF ASIdOrRange }
     */
    ASN1Encodable asIdentifierChoiceToDer(boolean inherit, IpResourceSet resources) {
        return inherit ? DERNull.INSTANCE : asIdsOrRangesToDer(resources);
    }

    /**
     * asIdsOrRanges ::= SEQUENCE OF ASIdOrRange
     */
    DERSequence asIdsOrRangesToDer(IpResourceSet resources) {
        List<ASN1Encodable> seq = new ArrayList<ASN1Encodable>();
        for (IpResource resource : resources) {
            if (IpResourceType.ASN == resource.getType()) {
                seq.add(asIdOrRangeToDer(IpResourceRange.range(resource.getStart(), resource.getEnd())));
            }
        }
        return new DERSequence(seq.toArray(new ASN1Encodable[seq.size()]));
    }

    /**
     * ASIdOrRange ::= CHOICE { id ASId, range ASRange }
     */
    ASN1Encodable asIdOrRangeToDer(IpResourceRange range) {
        return range.isUnique() ? asIdToDer((Asn) range.getStart()) : asRangeToDer(range);
    }

    /**
     * ASRange ::= SEQUENCE { min ASId, max ASId }
     */
    DERSequence asRangeToDer(IpResourceRange range) {
        ASN1Encodable[] seq = { asIdToDer((Asn) range.getStart()), asIdToDer((Asn) range.getEnd()) };
        return new DERSequence(seq);
    }

    /**
     * ASId ::= INTEGER
     */
    ASN1Integer asIdToDer(Asn asn) {
        return new ASN1Integer(asn.getValue());
    }

    /**
     * IPAddrBlocks ::= SEQUENCE OF IPAddressFamily
     */
    ASN1Object ipAddressBlocksToDer(SortedMap<AddressFamily, IpResourceSet> resources) {
        List<ASN1Encodable> seq = new ArrayList<ASN1Encodable>(2);
        for (AddressFamily addressFamily : resources.keySet()) {
            seq.add(ipAddressFamilyToDer(addressFamily, resources.get(addressFamily)));
        }
        return new DERSequence(seq.toArray(new ASN1Encodable[seq.size()]));
    }

    /**
     * IPAddressFamily ::= SEQUENCE { -- AFI & opt SAFI -- addressFamily OCTET
     * STRING (SIZE (2..3)), ipAddressChoice IPAddressChoice }
     */
    ASN1Object ipAddressFamilyToDer(AddressFamily addressFamily, IpResourceSet resources) {
        IpResourceType type = addressFamily.toIpResourceType();
        ASN1Encodable[] seq = new ASN1Encodable[2];
        seq[0] = addressFamily.toDer();
        seq[1] = ipAddressChoiceToDer(type, resources);
        return new DERSequence(seq);
    }

    /**
     * IPAddressChoice ::= CHOICE { inherit NULL, -- inherit from issuer --
     * addressesOrRanges SEQUENCE OF IPAddressOrRange }
     */
    ASN1Encodable ipAddressChoiceToDer(IpResourceType type, IpResourceSet resources) {
        if (resources == null) {
            return DERNull.INSTANCE;
        }

        List<ASN1Encodable> addressesOrRanges = new ArrayList<ASN1Encodable>();
        for (IpResource resource : resources) {
            if (resource.getType() == type) {
                addressesOrRanges.add(ipAddressOrRangeToDer(asRange(resource)));
            }
        }
        Validate.notEmpty(addressesOrRanges, "no resources of type " + type + " in set");
        return new DERSequence(addressesOrRanges.toArray(new ASN1Encodable[addressesOrRanges.size()]));
    }

    private IpRange asRange(IpResource resource) {
        return IpRange.range((IpAddress) resource.getStart(), (IpAddress) resource.getEnd());
    }

    /**
     * IPAddressOrRange ::= CHOICE { addressPrefix IPAddress, addressRange
     * IPAddressRange }
     */
    ASN1Encodable ipAddressOrRangeToDer(IpRange range) {
        return range.isLegalPrefix() ? Asn1Util.encodeIpAddress(range) : ipRangeToDer(range);
    }

    /**
     * IPAddressRange ::= SEQUENCE { min IPAddress, max IPAddress }
     */
    DERSequence ipRangeToDer(IpRange range) {
        ASN1Encodable[] encodables = { startIpAddressToDer((IpAddress) range.getStart()),
                endIpAddressToDer((IpAddress) range.getEnd()) };
        return new DERSequence(encodables);
    }

    /**
     * get the {DERBitString} for the ending IPv4 address; i.e. strip the least
     * significant ZERO values as described by rfc3779
     */
    private static DERBitString startIpAddressToDer(IpAddress address) {
        // Just keep track of the index of the last ONE bit
        int lastOne = address.getLeastSignificantOne();
        return Asn1Util.resourceToBitString(address, address.getType().getBitSize() - lastOne);
    }

    /**
     * get the {DERBitString} for the ending IPv4 address; i.e. strip the least
     * significant ONE values as described by rfc3779
     */
    private static DERBitString endIpAddressToDer(IpAddress address) {
        // Just keep track of the index of the last Zero bit
        int lastOne = address.getLeastSignificantZero();
        return Asn1Util.resourceToBitString(address.stripLeastSignificantOnes(),
                address.getType().getBitSize() - lastOne);
    }

}