001package org.apache.commons.ssl.org.bouncycastle.asn1.eac;
002
003
004import java.io.IOException;
005
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1InputStream;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1ObjectIdentifier;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1ParsingException;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
012import org.apache.commons.ssl.org.bouncycastle.asn1.DERApplicationSpecific;
013import org.apache.commons.ssl.org.bouncycastle.asn1.DEROctetString;
014
015
016/**
017 * an iso7816Certificate structure.
018 * <pre>
019 *  Certificate ::= SEQUENCE {
020 *      CertificateBody         Iso7816CertificateBody,
021 *      signature               DER Application specific
022 *  }
023 * </pre>
024 */
025public class CVCertificate
026    extends ASN1Object
027{
028    private CertificateBody certificateBody;
029    private byte[] signature;
030    private int valid;
031    private static int bodyValid = 0x01;
032    private static int signValid = 0x02;
033    public static final byte version_1 = 0x0;
034
035    public static String ReferenceEncoding = "ISO-8859-1";
036
037    /**
038     * Sets the values of the certificate (body and signature).
039     *
040     * @param appSpe is a DERApplicationSpecific object containing body and signature.
041     * @throws IOException if tags or value are incorrect.
042     */
043    private void setPrivateData(DERApplicationSpecific appSpe)
044        throws IOException
045    {
046        valid = 0;
047        if (appSpe.getApplicationTag() == EACTags.CARDHOLDER_CERTIFICATE)
048        {
049            ASN1InputStream content = new ASN1InputStream(appSpe.getContents());
050            ASN1Primitive tmpObj;
051            while ((tmpObj = content.readObject()) != null)
052            {
053                DERApplicationSpecific aSpe;
054                if (tmpObj instanceof DERApplicationSpecific)
055                {
056                    aSpe = (DERApplicationSpecific)tmpObj;
057                    switch (aSpe.getApplicationTag())
058                    {
059                    case EACTags.CERTIFICATE_CONTENT_TEMPLATE:
060                        certificateBody = CertificateBody.getInstance(aSpe);
061                        valid |= bodyValid;
062                        break;
063                    case EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP:
064                        signature = aSpe.getContents();
065                        valid |= signValid;
066                        break;
067                    default:
068                        throw new IOException("Invalid tag, not an Iso7816CertificateStructure :" + aSpe.getApplicationTag());
069                    }
070                }
071                else
072                {
073                    throw new IOException("Invalid Object, not an Iso7816CertificateStructure");
074                }
075            }
076        }
077        else
078        {
079            throw new IOException("not a CARDHOLDER_CERTIFICATE :" + appSpe.getApplicationTag());
080        }
081    }
082
083    /**
084     * Create an iso7816Certificate structure from an ASN1InputStream.
085     *
086     * @param aIS the byte stream to parse.
087     * @throws IOException if there is a problem parsing the data.
088     */
089    public CVCertificate(ASN1InputStream aIS)
090        throws IOException
091    {
092        initFrom(aIS);
093    }
094
095    private void initFrom(ASN1InputStream aIS)
096        throws IOException
097    {
098        ASN1Primitive obj;
099        while ((obj = aIS.readObject()) != null)
100        {
101            if (obj instanceof DERApplicationSpecific)
102            {
103                setPrivateData((DERApplicationSpecific)obj);
104            }
105            else
106            {
107                throw new IOException("Invalid Input Stream for creating an Iso7816CertificateStructure");
108            }
109        }
110    }
111
112    /**
113     * Create an iso7816Certificate structure from a DERApplicationSpecific.
114     *
115     * @param appSpe the DERApplicationSpecific object.
116     * @return the Iso7816CertificateStructure represented by the DERApplicationSpecific object.
117     * @throws IOException if there is a problem parsing the data.
118     */
119    private CVCertificate(DERApplicationSpecific appSpe)
120        throws IOException
121    {
122        setPrivateData(appSpe);
123    }
124
125    /**
126     * Create an iso7816Certificate structure from a body and its signature.
127     *
128     * @param body the Iso7816CertificateBody object containing the body.
129     * @param signature   the byte array containing the signature
130     * @throws IOException if there is a problem parsing the data.
131     */
132    public CVCertificate(CertificateBody body, byte[] signature)
133        throws IOException
134    {
135        certificateBody = body;
136        this.signature = signature;
137        // patch remi
138        valid |= bodyValid;
139        valid |= signValid;
140    }
141
142    /**
143     * Create an iso7816Certificate structure from an object.
144     *
145     * @param obj the Object to extract the certificate from.
146     * @return the Iso7816CertificateStructure represented by the byte stream.
147     */
148    public static CVCertificate getInstance(Object obj)
149    {
150        if (obj instanceof CVCertificate)
151        {
152            return (CVCertificate)obj;
153        }
154        else if (obj != null)
155        {
156            try
157            {
158                return new CVCertificate(DERApplicationSpecific.getInstance(obj));
159            }
160            catch (IOException e)
161            {
162                throw new ASN1ParsingException("unable to parse data: " + e.getMessage(), e);
163            }
164        }
165
166        return null;
167    }
168
169    /**
170     * Gives the signature of the whole body. Type of signature is given in
171     * the Iso7816CertificateBody.Iso7816PublicKey.ASN1ObjectIdentifier
172     *
173     * @return the signature of the body.
174     */
175    public byte[] getSignature()
176    {
177        return signature;
178    }
179
180    /**
181     * Gives the body of the certificate.
182     *
183     * @return the body.
184     */
185    public CertificateBody getBody()
186    {
187        return certificateBody;
188    }
189
190    /**
191     * @see org.bouncycastle.asn1.ASN1Object#toASN1Primitive()
192     */
193    public ASN1Primitive toASN1Primitive()
194    {
195        ASN1EncodableVector v = new ASN1EncodableVector();
196
197        if (valid != (signValid | bodyValid))
198        {
199            return null;
200        }
201        v.add(certificateBody);
202
203        try
204        {
205            v.add(new DERApplicationSpecific(false, EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP, new DEROctetString(signature)));
206        }
207        catch (IOException e)
208        {
209            throw new IllegalStateException("unable to convert signature!");
210        }
211
212        return new DERApplicationSpecific(EACTags.CARDHOLDER_CERTIFICATE, v);
213    }
214
215    /**
216     * @return the Holder authorization and role (CVCA, DV, IS).
217     */
218    public ASN1ObjectIdentifier getHolderAuthorization()
219        throws IOException
220    {
221        CertificateHolderAuthorization cha = certificateBody.getCertificateHolderAuthorization();
222        return cha.getOid();
223    }
224
225    /**
226     * @return the date of the certificate generation
227     */
228    public PackedDate getEffectiveDate()
229        throws IOException
230    {
231        return certificateBody.getCertificateEffectiveDate();
232    }
233
234
235    /**
236     * @return the type of certificate (request or profile)
237     *         value is either Iso7816CertificateBody.profileType
238     *         or Iso7816CertificateBody.requestType. Any other value
239     *         is not valid.
240     */
241    public int getCertificateType()
242    {
243        return this.certificateBody.getCertificateType();
244    }
245
246    /**
247     * @return the date of the certificate generation
248     */
249    public PackedDate getExpirationDate()
250        throws IOException
251    {
252        return certificateBody.getCertificateExpirationDate();
253    }
254
255
256    /**
257     * return a bits field coded on one byte. For signification of the
258     * several bit see Iso7816CertificateHolderAuthorization
259     *
260     * @return role and access rigth
261     * @throws IOException
262     * @see CertificateHolderAuthorization
263     */
264    public int getRole()
265        throws IOException
266    {
267        CertificateHolderAuthorization cha = certificateBody.getCertificateHolderAuthorization();
268        return cha.getAccessRights();
269    }
270
271    /**
272     * @return the Authority Reference field of the certificate
273     * @throws IOException
274     */
275    public CertificationAuthorityReference getAuthorityReference()
276        throws IOException
277    {
278        return certificateBody.getCertificationAuthorityReference();
279    }
280
281    /**
282     * @return the Holder Reference Field of the certificate
283     * @throws IOException
284     */
285    public CertificateHolderReference getHolderReference()
286        throws IOException
287    {
288        return certificateBody.getCertificateHolderReference();
289    }
290
291    /**
292     * @return the bits corresponding to the role intented for the certificate
293     *         See Iso7816CertificateHolderAuthorization static int for values
294     * @throws IOException
295     */
296    public int getHolderAuthorizationRole()
297        throws IOException
298    {
299        int rights = certificateBody.getCertificateHolderAuthorization().getAccessRights();
300        return rights & 0xC0;
301    }
302
303    /**
304     * @return the bits corresponding the authorizations contained in the certificate
305     *         See Iso7816CertificateHolderAuthorization static int for values
306     * @throws IOException
307     */
308    public Flags getHolderAuthorizationRights()
309        throws IOException
310    {
311        return new Flags(certificateBody.getCertificateHolderAuthorization().getAccessRights() & 0x1F);
312    }
313}