a59ca3cee7a2246677d99065acec6994c058a959
[platform/upstream/gcc48.git] / libjava / classpath / gnu / java / security / key / dss / DSSKeyPairPKCS8Codec.java
1 /* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler
2    Copyright (C) 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.java.security.key.dss;
40
41 import gnu.java.security.Configuration;
42 import gnu.java.security.OID;
43 import gnu.java.security.Registry;
44 import gnu.java.security.der.DER;
45 import gnu.java.security.der.DERReader;
46 import gnu.java.security.der.DERValue;
47 import gnu.java.security.der.DERWriter;
48 import gnu.java.security.key.IKeyPairCodec;
49 import gnu.java.security.util.DerUtil;
50 import gnu.java.security.util.Util;
51
52 import java.io.ByteArrayOutputStream;
53 import java.io.IOException;
54 import java.math.BigInteger;
55 import java.security.InvalidParameterException;
56 import java.security.PrivateKey;
57 import java.security.PublicKey;
58 import java.util.ArrayList;
59 import java.util.logging.Logger;
60
61 /**
62  * An implementation of an {@link IKeyPairCodec} that knows how to encode /
63  * decode PKCS#8 ASN.1 external representation of DSS private keys.
64  *
65  * @author Casey Marshall (rsdio@metastatic.org)
66  */
67 public class DSSKeyPairPKCS8Codec
68     implements IKeyPairCodec
69 {
70   private static final Logger log = Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName());
71   private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
72
73   // implicit 0-arguments constructor
74
75   public int getFormatID()
76   {
77     return PKCS8_FORMAT;
78   }
79
80   /**
81    * @throws InvalidParameterException ALWAYS.
82    */
83   public byte[] encodePublicKey(PublicKey key)
84   {
85     throw new InvalidParameterException("Wrong format for public keys");
86   }
87
88   /**
89    * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of a DSA
90    * private key. The ASN.1 specification is as follows:
91    *
92    * <pre>
93    *   PrivateKeyInfo ::= SEQUENCE {
94    *     version              INTEGER, -- MUST be 0
95    *     privateKeyAlgorithm  AlgorithmIdentifier,
96    *     privateKey           OCTET STRING
97    *   }
98    *
99    *   AlgorithmIdentifier ::= SEQUENCE {
100    *     algorithm   OBJECT IDENTIFIER,
101    *     parameters  ANY DEFINED BY algorithm OPTIONAL
102    *   }
103    *
104    *   DssParams ::= SEQUENCE {
105    *     p   INTEGER,
106    *     q   INTEGER,
107    *     g   INTEGER
108    *   }
109    * </pre>
110    *
111    * @return the DER encoded form of the ASN.1 representation of the
112    *         <i>PrivateKeyInfo</i> field in an X.509 certificate.
113    * @throw InvalidParameterException if an error occurs during the marshalling
114    *        process.
115    */
116   public byte[] encodePrivateKey(PrivateKey key)
117   {
118     if (! (key instanceof DSSPrivateKey))
119       throw new InvalidParameterException("Wrong key type");
120
121     DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
122
123     DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
124
125     DSSPrivateKey pk = (DSSPrivateKey) key;
126     BigInteger p = pk.getParams().getP();
127     BigInteger q = pk.getParams().getQ();
128     BigInteger g = pk.getParams().getG();
129     BigInteger x = pk.getX();
130
131     ArrayList params = new ArrayList(3);
132     params.add(new DERValue(DER.INTEGER, p));
133     params.add(new DERValue(DER.INTEGER, q));
134     params.add(new DERValue(DER.INTEGER, g));
135     DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
136
137     ArrayList algorithmID = new ArrayList(2);
138     algorithmID.add(derOID);
139     algorithmID.add(derParams);
140     DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
141                                            algorithmID);
142
143     // The OCTET STRING is the DER encoding of an INTEGER.
144     DERValue derX = new DERValue(DER.INTEGER, x);
145     DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded());
146
147     ArrayList pki = new ArrayList(3);
148     pki.add(derVersion);
149     pki.add(derAlgorithmID);
150     pki.add(derPrivateKey);
151     DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
152
153     byte[] result;
154     ByteArrayOutputStream baos = new ByteArrayOutputStream();
155     try
156       {
157         DERWriter.write(baos, derPKI);
158         result = baos.toByteArray();
159       }
160     catch (IOException e)
161       {
162         InvalidParameterException y = new InvalidParameterException(e.getMessage());
163         y.initCause(e);
164         throw y;
165       }
166     return result;
167   }
168
169   /**
170    * @throws InvalidParameterException ALWAYS.
171    */
172   public PublicKey decodePublicKey(byte[] input)
173   {
174     throw new InvalidParameterException("Wrong format for public keys");
175   }
176
177   /**
178    * @param input the byte array to unmarshall into a valid DSS
179    *          {@link PrivateKey} instance. MUST NOT be null.
180    * @return a new instance of a {@link DSSPrivateKey} decoded from the
181    *         <i>PrivateKeyInfo</i> material fed as <code>input</code>.
182    * @throw InvalidParameterException if an exception occurs during the
183    *        unmarshalling process.
184    */
185   public PrivateKey decodePrivateKey(byte[] input)
186   {
187     if (Configuration.DEBUG)
188       log.entering(this.getClass().getName(), "decodePrivateKey");
189     if (input == null)
190       throw new InvalidParameterException("Input bytes MUST NOT be null");
191
192     BigInteger version, p, q, g, x;
193     DERReader der = new DERReader(input);
194     try
195       {
196         DERValue derPKI = der.read();
197         DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
198
199         DERValue derVersion = der.read();
200         if (! (derVersion.getValue() instanceof BigInteger))
201           throw new InvalidParameterException("Wrong Version field");
202
203         version = (BigInteger) derVersion.getValue();
204         if (version.compareTo(BigInteger.ZERO) != 0)
205           throw new InvalidParameterException("Unexpected Version: " + version);
206
207         DERValue derAlgoritmID = der.read();
208         DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
209
210         DERValue derOID = der.read();
211         OID algOID = (OID) derOID.getValue();
212         if (! algOID.equals(DSA_ALG_OID))
213           throw new InvalidParameterException("Unexpected OID: " + algOID);
214
215         DERValue derParams = der.read();
216         DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
217
218         DERValue val = der.read();
219         DerUtil.checkIsBigInteger(val, "Wrong P field");
220         p = (BigInteger) val.getValue();
221         val = der.read();
222         DerUtil.checkIsBigInteger(val, "Wrong Q field");
223         q = (BigInteger) val.getValue();
224         val = der.read();
225         DerUtil.checkIsBigInteger(val, "Wrong G field");
226         g = (BigInteger) val.getValue();
227
228         val = der.read();
229         if (Configuration.DEBUG)
230           log.fine("val = " + val);
231         byte[] xBytes = (byte[]) val.getValue();
232         if (Configuration.DEBUG)
233           log.fine(Util.dumpString(xBytes, "xBytes: "));
234         DERReader der2 = new DERReader(xBytes);
235         val = der2.read();
236         DerUtil.checkIsBigInteger(val, "Wrong X field");
237         x = (BigInteger) val.getValue();
238       }
239     catch (IOException e)
240       {
241         InvalidParameterException y = new InvalidParameterException(e.getMessage());
242         y.initCause(e);
243         throw y;
244       }
245     if (Configuration.DEBUG)
246       log.exiting(this.getClass().getName(), "decodePrivateKey");
247     return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
248   }
249 }