001package org.apache.commons.ssl.org.bouncycastle.asn1.eac;
002
003import java.math.BigInteger;
004import java.util.Enumeration;
005
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1ObjectIdentifier;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
012import org.apache.commons.ssl.org.bouncycastle.asn1.DEROctetString;
013import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
014import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
015
016/**
017 * an Iso7816ECDSAPublicKeyStructure structure.
018 * <pre>
019 *  Certificate Holder Authorization ::= SEQUENCE {
020 *      ASN1TaggedObject primeModulusP;        // OPTIONAL
021 *      ASN1TaggedObject firstCoefA;            // OPTIONAL
022 *      ASN1TaggedObject secondCoefB;        // OPTIONAL
023 *      ASN1TaggedObject basePointG;            // OPTIONAL
024 *      ASN1TaggedObject orderOfBasePointR;    // OPTIONAL
025 *      ASN1TaggedObject publicPointY;        //REQUIRED
026 *      ASN1TaggedObject    cofactorF;            // OPTIONAL
027 *  }
028 * </pre>
029 */
030public class ECDSAPublicKey
031    extends PublicKeyDataObject
032{
033    private ASN1ObjectIdentifier usage;
034    private BigInteger primeModulusP;        // OPTIONAL
035    private BigInteger firstCoefA;            // OPTIONAL
036    private BigInteger secondCoefB;        // OPTIONAL
037    private byte[]     basePointG;            // OPTIONAL
038    private BigInteger orderOfBasePointR;    // OPTIONAL
039    private byte[]     publicPointY;        //REQUIRED
040    private BigInteger cofactorF;            // OPTIONAL
041    private int options;
042    private static final int P = 0x01;
043    private static final int A = 0x02;
044    private static final int B = 0x04;
045    private static final int G = 0x08;
046    private static final int R = 0x10;
047    private static final int Y = 0x20;
048    private static final int F = 0x40;
049
050    ECDSAPublicKey(ASN1Sequence seq)
051        throws IllegalArgumentException
052    {
053        Enumeration en = seq.getObjects();
054
055        this.usage = ASN1ObjectIdentifier.getInstance(en.nextElement());
056
057        options = 0;
058        while (en.hasMoreElements())
059        {
060            Object obj = en.nextElement();
061            
062            if (obj instanceof ASN1TaggedObject)
063            {
064                ASN1TaggedObject to = (ASN1TaggedObject)obj;
065                switch (to.getTagNo())
066                {
067                case 0x1:
068                    setPrimeModulusP(UnsignedInteger.getInstance(to).getValue());
069                    break;
070                case 0x2:
071                    setFirstCoefA(UnsignedInteger.getInstance(to).getValue());
072                    break;
073                case 0x3:
074                    setSecondCoefB(UnsignedInteger.getInstance(to).getValue());
075                    break;
076                case 0x4:
077                    setBasePointG(ASN1OctetString.getInstance(to, false));
078                    break;
079                case 0x5:
080                    setOrderOfBasePointR(UnsignedInteger.getInstance(to).getValue());
081                    break;
082                case 0x6:
083                    setPublicPointY(ASN1OctetString.getInstance(to, false));
084                    break;
085                case 0x7:
086                    setCofactorF(UnsignedInteger.getInstance(to).getValue());
087                    break;
088                default:
089                    options = 0;
090                    throw new IllegalArgumentException("Unknown Object Identifier!");
091                }
092            }
093            else
094            {
095                throw new IllegalArgumentException("Unknown Object Identifier!");
096            }
097        }
098        if (options != 0x20 && options != 0x7F)
099        {
100            throw new IllegalArgumentException("All options must be either present or absent!");
101        }
102    }
103
104    public ECDSAPublicKey(ASN1ObjectIdentifier usage, byte[] ppY)
105        throws IllegalArgumentException
106    {
107        this.usage = usage;
108        setPublicPointY(new DEROctetString(ppY));
109    }
110
111    public ECDSAPublicKey(ASN1ObjectIdentifier usage, BigInteger p, BigInteger a, BigInteger b, byte[] basePoint, BigInteger order, byte[] publicPoint, int cofactor)
112    {
113        this.usage = usage;
114        setPrimeModulusP(p);
115        setFirstCoefA(a);
116        setSecondCoefB(b);
117        setBasePointG(new DEROctetString(basePoint));
118        setOrderOfBasePointR(order);
119        setPublicPointY(new DEROctetString(publicPoint));
120        setCofactorF(BigInteger.valueOf(cofactor));
121    }
122
123    public ASN1ObjectIdentifier getUsage()
124    {
125        return usage;
126    }
127
128    public byte[] getBasePointG()
129    {
130        if ((options & G) != 0)
131        {
132            return basePointG;
133        }
134        else
135        {
136            return null;
137        }
138    }
139
140    private void setBasePointG(ASN1OctetString basePointG)
141        throws IllegalArgumentException
142    {
143        if ((options & G) == 0)
144        {
145            options |= G;
146            this.basePointG = basePointG.getOctets();
147        }
148        else
149        {
150            throw new IllegalArgumentException("Base Point G already set");
151        }
152    }
153
154    public BigInteger getCofactorF()
155    {
156        if ((options & F) != 0)
157        {
158            return cofactorF;
159        }
160        else
161        {
162            return null;
163        }
164    }
165
166    private void setCofactorF(BigInteger cofactorF)
167        throws IllegalArgumentException
168    {
169        if ((options & F) == 0)
170        {
171            options |= F;
172            this.cofactorF = cofactorF;
173        }
174        else
175        {
176            throw new IllegalArgumentException("Cofactor F already set");
177        }
178    }
179
180    public BigInteger getFirstCoefA()
181    {
182        if ((options & A) != 0)
183        {
184            return firstCoefA;
185        }
186        else
187        {
188            return null;
189        }
190    }
191
192    private void setFirstCoefA(BigInteger firstCoefA)
193        throws IllegalArgumentException
194    {
195        if ((options & A) == 0)
196        {
197            options |= A;
198            this.firstCoefA = firstCoefA;
199        }
200        else
201        {
202            throw new IllegalArgumentException("First Coef A already set");
203        }
204    }
205
206    public BigInteger getOrderOfBasePointR()
207    {
208        if ((options & R) != 0)
209        {
210            return orderOfBasePointR;
211        }
212        else
213        {
214            return null;
215        }
216    }
217
218    private void setOrderOfBasePointR(BigInteger orderOfBasePointR)
219        throws IllegalArgumentException
220    {
221        if ((options & R) == 0)
222        {
223            options |= R;
224            this.orderOfBasePointR = orderOfBasePointR;
225        }
226        else
227        {
228            throw new IllegalArgumentException("Order of base point R already set");
229        }
230    }
231
232    public BigInteger getPrimeModulusP()
233    {
234        if ((options & P) != 0)
235        {
236            return primeModulusP;
237        }
238        else
239        {
240            return null;
241        }
242    }
243
244    private void setPrimeModulusP(BigInteger primeModulusP)
245    {
246        if ((options & P) == 0)
247        {
248            options |= P;
249            this.primeModulusP = primeModulusP;
250        }
251        else
252        {
253            throw new IllegalArgumentException("Prime Modulus P already set");
254        }
255    }
256
257    public byte[] getPublicPointY()
258    {
259        if ((options & Y) != 0)
260        {
261            return publicPointY;
262        }
263        else
264        {
265            return null;
266        }
267    }
268
269    private void setPublicPointY(ASN1OctetString publicPointY)
270        throws IllegalArgumentException
271    {
272        if ((options & Y) == 0)
273        {
274            options |= Y;
275            this.publicPointY = publicPointY.getOctets();
276        }
277        else
278        {
279            throw new IllegalArgumentException("Public Point Y already set");
280        }
281    }
282
283    public BigInteger getSecondCoefB()
284    {
285        if ((options & B) != 0)
286        {
287            return secondCoefB;
288        }
289        else
290        {
291            return null;
292        }
293    }
294
295    private void setSecondCoefB(BigInteger secondCoefB)
296        throws IllegalArgumentException
297    {
298        if ((options & B) == 0)
299        {
300            options |= B;
301            this.secondCoefB = secondCoefB;
302        }
303        else
304        {
305            throw new IllegalArgumentException("Second Coef B already set");
306        }
307    }
308
309    public boolean hasParameters()
310    {
311        return primeModulusP != null;
312    }
313
314    public ASN1EncodableVector getASN1EncodableVector(ASN1ObjectIdentifier oid, boolean publicPointOnly)
315    {
316        ASN1EncodableVector v = new ASN1EncodableVector();
317        v.add(oid);
318
319        if (!publicPointOnly)
320        {
321            v.add(new UnsignedInteger(0x01, getPrimeModulusP()));
322            v.add(new UnsignedInteger(0x02, getFirstCoefA()));
323            v.add(new UnsignedInteger(0x03, getSecondCoefB()));
324            v.add(new DERTaggedObject(false, 0x04, new DEROctetString(getBasePointG())));
325            v.add(new UnsignedInteger(0x05, getOrderOfBasePointR()));
326        }
327        v.add(new DERTaggedObject(false, 0x06, new DEROctetString(getPublicPointY())));
328        if (!publicPointOnly)
329        {
330            v.add(new UnsignedInteger(0x07, getCofactorF()));
331        }
332
333        return v;
334    }
335
336    public ASN1Primitive toASN1Primitive()
337    {
338        return new DERSequence(getASN1EncodableVector(usage, false));
339    }
340}