Imported Upstream version 4.8.1
[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, 2010  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 = Configuration.DEBUG ?
71                 Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName()) : null;
72
73   private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
74
75   // implicit 0-arguments constructor
76
77   public int getFormatID()
78   {
79     return PKCS8_FORMAT;
80   }
81
82   /**
83    * @throws InvalidParameterException ALWAYS.
84    */
85   public byte[] encodePublicKey(PublicKey key)
86   {
87     throw new InvalidParameterException("Wrong format for public keys");
88   }
89
90   /**
91    * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of a DSA
92    * private key. The ASN.1 specification is as follows:
93    *
94    * <pre>
95    *   PrivateKeyInfo ::= SEQUENCE {
96    *     version              INTEGER, -- MUST be 0
97    *     privateKeyAlgorithm  AlgorithmIdentifier,
98    *     privateKey           OCTET STRING
99    *   }
100    *
101    *   AlgorithmIdentifier ::= SEQUENCE {
102    *     algorithm   OBJECT IDENTIFIER,
103    *     parameters  ANY DEFINED BY algorithm OPTIONAL
104    *   }
105    *
106    *   DssParams ::= SEQUENCE {
107    *     p   INTEGER,
108    *     q   INTEGER,
109    *     g   INTEGER
110    *   }
111    * </pre>
112    *
113    * @return the DER encoded form of the ASN.1 representation of the
114    *         <i>PrivateKeyInfo</i> field in an X.509 certificate.
115    * @throw InvalidParameterException if an error occurs during the marshalling
116    *        process.
117    */
118   public byte[] encodePrivateKey(PrivateKey key)
119   {
120     if (! (key instanceof DSSPrivateKey))
121       throw new InvalidParameterException("Wrong key type");
122
123     DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
124
125     DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
126
127     DSSPrivateKey pk = (DSSPrivateKey) key;
128     BigInteger p = pk.getParams().getP();
129     BigInteger q = pk.getParams().getQ();
130     BigInteger g = pk.getParams().getG();
131     BigInteger x = pk.getX();
132
133     ArrayList params = new ArrayList(3);
134     params.add(new DERValue(DER.INTEGER, p));
135     params.add(new DERValue(DER.INTEGER, q));
136     params.add(new DERValue(DER.INTEGER, g));
137     DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
138
139     ArrayList algorithmID = new ArrayList(2);
140     algorithmID.add(derOID);
141     algorithmID.add(derParams);
142     DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
143                                            algorithmID);
144
145     // The OCTET STRING is the DER encoding of an INTEGER.
146     DERValue derX = new DERValue(DER.INTEGER, x);
147     DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded());
148
149     ArrayList pki = new ArrayList(3);
150     pki.add(derVersion);
151     pki.add(derAlgorithmID);
152     pki.add(derPrivateKey);
153     DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
154
155     byte[] result;
156     ByteArrayOutputStream baos = new ByteArrayOutputStream();
157     try
158       {
159         DERWriter.write(baos, derPKI);
160         result = baos.toByteArray();
161       }
162     catch (IOException e)
163       {
164         InvalidParameterException y = new InvalidParameterException(e.getMessage());
165         y.initCause(e);
166         throw y;
167       }
168     return result;
169   }
170
171   /**
172    * @throws InvalidParameterException ALWAYS.
173    */
174   public PublicKey decodePublicKey(byte[] input)
175   {
176     throw new InvalidParameterException("Wrong format for public keys");
177   }
178
179   /**
180    * @param input the byte array to unmarshall into a valid DSS
181    *          {@link PrivateKey} instance. MUST NOT be null.
182    * @return a new instance of a {@link DSSPrivateKey} decoded from the
183    *         <i>PrivateKeyInfo</i> material fed as <code>input</code>.
184    * @throw InvalidParameterException if an exception occurs during the
185    *        unmarshalling process.
186    */
187   public PrivateKey decodePrivateKey(byte[] input)
188   {
189     if (Configuration.DEBUG)
190       log.entering(this.getClass().getName(), "decodePrivateKey");
191     if (input == null)
192       throw new InvalidParameterException("Input bytes MUST NOT be null");
193
194     BigInteger version, p, q, g, x;
195     DERReader der = new DERReader(input);
196     try
197       {
198         DERValue derPKI = der.read();
199         DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
200
201         DERValue derVersion = der.read();
202         if (! (derVersion.getValue() instanceof BigInteger))
203           throw new InvalidParameterException("Wrong Version field");
204
205         version = (BigInteger) derVersion.getValue();
206         if (version.compareTo(BigInteger.ZERO) != 0)
207           throw new InvalidParameterException("Unexpected Version: " + version);
208
209         DERValue derAlgoritmID = der.read();
210         DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
211
212         DERValue derOID = der.read();
213         OID algOID = (OID) derOID.getValue();
214         if (! algOID.equals(DSA_ALG_OID))
215           throw new InvalidParameterException("Unexpected OID: " + algOID);
216
217         DERValue derParams = der.read();
218         DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
219
220         DERValue val = der.read();
221         DerUtil.checkIsBigInteger(val, "Wrong P field");
222         p = (BigInteger) val.getValue();
223         val = der.read();
224         DerUtil.checkIsBigInteger(val, "Wrong Q field");
225         q = (BigInteger) val.getValue();
226         val = der.read();
227         DerUtil.checkIsBigInteger(val, "Wrong G field");
228         g = (BigInteger) val.getValue();
229
230         val = der.read();
231         if (Configuration.DEBUG)
232           log.fine("val = " + val);
233         byte[] xBytes = (byte[]) val.getValue();
234         if (Configuration.DEBUG)
235           log.fine(Util.dumpString(xBytes, "xBytes: "));
236         DERReader der2 = new DERReader(xBytes);
237         val = der2.read();
238         DerUtil.checkIsBigInteger(val, "Wrong X field");
239         x = (BigInteger) val.getValue();
240       }
241     catch (IOException e)
242       {
243         InvalidParameterException y = new InvalidParameterException(e.getMessage());
244         y.initCause(e);
245         throw y;
246       }
247     if (Configuration.DEBUG)
248       log.exiting(this.getClass().getName(), "decodePrivateKey");
249     return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
250   }
251 }