001package org.apache.commons.ssl.org.bouncycastle.asn1.x509;
002
003import java.util.Enumeration;
004
005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
010import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
011import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
012
013/**
014 * This class helps to support crossCerfificatePairs in a LDAP directory
015 * according RFC 2587
016 * 
017 * <pre>
018 *     crossCertificatePairATTRIBUTE::={
019 *       WITH SYNTAX   CertificatePair
020 *       EQUALITY MATCHING RULE certificatePairExactMatch
021 *       ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)}
022 * </pre>
023 * 
024 * <blockquote> The forward elements of the crossCertificatePair attribute of a
025 * CA's directory entry shall be used to store all, except self-issued
026 * certificates issued to this CA. Optionally, the reverse elements of the
027 * crossCertificatePair attribute, of a CA's directory entry may contain a
028 * subset of certificates issued by this CA to other CAs. When both the forward
029 * and the reverse elements are present in a single attribute value, issuer name
030 * in one certificate shall match the subject name in the other and vice versa,
031 * and the subject public key in one certificate shall be capable of verifying
032 * the digital signature on the other certificate and vice versa.
033 * 
034 * When a reverse element is present, the forward element value and the reverse
035 * element value need not be stored in the same attribute value; in other words,
036 * they can be stored in either a single attribute value or two attribute
037 * values. </blockquote>
038 * 
039 * <pre>
040 *       CertificatePair ::= SEQUENCE {
041 *         forward        [0]    Certificate OPTIONAL,
042 *         reverse        [1]    Certificate OPTIONAL,
043 *         -- at least one of the pair shall be present -- } 
044 * </pre>
045 */
046public class CertificatePair
047    extends ASN1Object
048{
049    private Certificate forward;
050
051    private Certificate reverse;
052
053    public static CertificatePair getInstance(Object obj)
054    {
055        if (obj == null || obj instanceof CertificatePair)
056        {
057            return (CertificatePair)obj;
058        }
059
060        if (obj instanceof ASN1Sequence)
061        {
062            return new CertificatePair((ASN1Sequence)obj);
063        }
064
065        throw new IllegalArgumentException("illegal object in getInstance: "
066            + obj.getClass().getName());
067    }
068
069    /**
070     * Constructor from ASN1Sequence.
071     * <p>
072     * The sequence is of type CertificatePair:
073     * <pre>
074     *       CertificatePair ::= SEQUENCE {
075     *         forward        [0]    Certificate OPTIONAL,
076     *         reverse        [1]    Certificate OPTIONAL,
077     *         -- at least one of the pair shall be present -- }
078     * </pre>
079     * </p>
080     * @param seq The ASN.1 sequence.
081     */
082    private CertificatePair(ASN1Sequence seq)
083    {
084        if (seq.size() != 1 && seq.size() != 2)
085        {
086            throw new IllegalArgumentException("Bad sequence size: "
087                + seq.size());
088        }
089
090        Enumeration e = seq.getObjects();
091
092        while (e.hasMoreElements())
093        {
094            ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement());
095            if (o.getTagNo() == 0)
096            {
097                forward = Certificate.getInstance(o, true);
098            }
099            else if (o.getTagNo() == 1)
100            {
101                reverse = Certificate.getInstance(o, true);
102            }
103            else
104            {
105                throw new IllegalArgumentException("Bad tag number: "
106                    + o.getTagNo());
107            }
108        }
109    }
110
111    /**
112     * Constructor from a given details.
113     *
114     * @param forward Certificates issued to this CA.
115     * @param reverse Certificates issued by this CA to other CAs.
116     */
117    public CertificatePair(Certificate forward, Certificate reverse)
118    {
119        this.forward = forward;
120        this.reverse = reverse;
121    }
122
123    /**
124     * Produce an object suitable for an ASN1OutputStream.
125     * <p>
126     * Returns:
127     * <pre>
128     *       CertificatePair ::= SEQUENCE {
129     *         forward        [0]    Certificate OPTIONAL,
130     *         reverse        [1]    Certificate OPTIONAL,
131     *         -- at least one of the pair shall be present -- }
132     * </pre>
133     *
134     * @return a ASN1Primitive
135     */
136    public ASN1Primitive toASN1Primitive()
137    {
138        ASN1EncodableVector vec = new ASN1EncodableVector();
139
140        if (forward != null)
141        {
142            vec.add(new DERTaggedObject(0, forward));
143        }
144        if (reverse != null)
145        {
146            vec.add(new DERTaggedObject(1, reverse));
147        }
148
149        return new DERSequence(vec);
150    }
151
152    /**
153     * @return Returns the forward.
154     */
155    public Certificate getForward()
156    {
157        return forward;
158    }
159
160    /**
161     * @return Returns the reverse.
162     */
163    public Certificate getReverse()
164    {
165        return reverse;
166    }
167}