Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libjava / classpath / gnu / java / security / key / rsa / RSAKeyPairPKCS8Codec.java
1 /* RSAKeyPairPKCS8Codec.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.rsa;
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
51 import java.io.ByteArrayOutputStream;
52 import java.io.IOException;
53 import java.math.BigInteger;
54 import java.security.InvalidParameterException;
55 import java.security.PrivateKey;
56 import java.security.PublicKey;
57 import java.util.ArrayList;
58 import java.util.logging.Logger;
59
60 /**
61  * An implementation of an {@link IKeyPairCodec} that knows how to encode /
62  * decode PKCS#8 ASN.1 external representation of RSA private keys.
63  */
64 public class RSAKeyPairPKCS8Codec
65     implements IKeyPairCodec
66 {
67   private static final Logger log = Configuration.DEBUG ?
68                 Logger.getLogger(RSAKeyPairPKCS8Codec.class.getName()) : null;
69
70   private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING);
71
72   // implicit 0-arguments constructor
73
74   public int getFormatID()
75   {
76     return PKCS8_FORMAT;
77   }
78
79   /**
80    * @throws InvalidParameterException ALWAYS.
81    */
82   public byte[] encodePublicKey(PublicKey key)
83   {
84     throw new InvalidParameterException("Wrong format for public keys");
85   }
86
87   /**
88    * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of an RSA
89    * private key. The ASN.1 specification is as follows:
90    * <pre>
91    *   PrivateKeyInfo ::= SEQUENCE {
92    *     version              INTEGER, -- MUST be 0
93    *     privateKeyAlgorithm  AlgorithmIdentifier,
94    *     privateKey           OCTET STRING
95    *   }
96    *
97    *   AlgorithmIdentifier ::= SEQUENCE {
98    *     algorithm   OBJECT IDENTIFIER,
99    *     parameters  ANY DEFINED BY algorithm OPTIONAL
100    *   }
101    * </pre>
102    * <p>
103    * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL
104    * for this algorithm identifier.".
105    * <p>
106    * The <i>privateKey</i> field, which is an OCTET STRING, contains the
107    * DER-encoded form of the RSA private key defined as:
108    * <pre>
109    *   RSAPrivateKey ::= SEQUENCE {
110    *     version                 INTEGER, -- MUST be 0
111    *     modulus                 INTEGER, -- n
112    *     publicExponent          INTEGER, -- e
113    *     privateExponent         INTEGER, -- d
114    *     prime1                  INTEGER, -- p
115    *     prime2                  INTEGER, -- q
116    *     exponent1               INTEGER, -- d mod (p-1)
117    *     exponent2               INTEGER, -- d mod (q-1)
118    *     coefficient             INTEGER, -- (inverse of q) mod p
119    *   }
120    * </pre>
121    *
122    * @return the DER encoded form of the ASN.1 representation of the
123    *         <i>PrivateKeyInfo</i> field for an RSA {@link PrivateKey}..
124    * @throw InvalidParameterException if an error occurs during the marshalling
125    *        process.
126    */
127   public byte[] encodePrivateKey(PrivateKey key)
128   {
129     if (Configuration.DEBUG)
130       log.entering(this.getClass().getName(), "encodePrivateKey()", key);
131     if (! (key instanceof GnuRSAPrivateKey))
132       throw new InvalidParameterException("Wrong key type");
133
134     GnuRSAPrivateKey pk = (GnuRSAPrivateKey) key;
135     BigInteger n = pk.getN();
136     BigInteger e = pk.getE();
137     BigInteger d = pk.getPrivateExponent();
138     BigInteger p = pk.getPrimeP();
139     BigInteger q = pk.getPrimeQ();
140     BigInteger dP = pk.getPrimeExponentP();
141     BigInteger dQ = pk.getPrimeExponentQ();
142     BigInteger qInv = pk.getCrtCoefficient();
143
144     DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
145
146     DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID);
147
148     ArrayList algorithmID = new ArrayList(2);
149     algorithmID.add(derOID);
150     algorithmID.add(new DERValue(DER.NULL, null));
151     DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
152                                            algorithmID);
153
154     DERValue derRSAVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
155     DERValue derN = new DERValue(DER.INTEGER, n);
156     DERValue derE = new DERValue(DER.INTEGER, e);
157     DERValue derD = new DERValue(DER.INTEGER, d);
158     DERValue derP = new DERValue(DER.INTEGER, p);
159     DERValue derQ = new DERValue(DER.INTEGER, q);
160     DERValue derDP = new DERValue(DER.INTEGER, dP);
161     DERValue derDQ = new DERValue(DER.INTEGER, dQ);
162     DERValue derQInv = new DERValue(DER.INTEGER, qInv);
163
164     ArrayList rsaPrivateKey = new ArrayList();
165     rsaPrivateKey.add(derRSAVersion);
166     rsaPrivateKey.add(derN);
167     rsaPrivateKey.add(derE);
168     rsaPrivateKey.add(derD);
169     rsaPrivateKey.add(derP);
170     rsaPrivateKey.add(derQ);
171     rsaPrivateKey.add(derDP);
172     rsaPrivateKey.add(derDQ);
173     rsaPrivateKey.add(derQInv);
174     DERValue derRSAPrivateKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
175                                              rsaPrivateKey);
176     byte[] pkBytes = derRSAPrivateKey.getEncoded();
177     DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, pkBytes);
178
179     ArrayList pki = new ArrayList(3);
180     pki.add(derVersion);
181     pki.add(derAlgorithmID);
182     pki.add(derPrivateKey);
183     DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
184
185     byte[] result;
186     ByteArrayOutputStream baos = new ByteArrayOutputStream();
187     try
188       {
189         DERWriter.write(baos, derPKI);
190         result = baos.toByteArray();
191       }
192     catch (IOException x)
193       {
194         InvalidParameterException y = new InvalidParameterException();
195         y.initCause(x);
196         throw y;
197       }
198     if (Configuration.DEBUG)
199       log.exiting(this.getClass().getName(), "encodePrivateKey()", result);
200     return result;
201   }
202
203   /**
204    * @throws InvalidParameterException ALWAYS.
205    */
206   public PublicKey decodePublicKey(byte[] input)
207   {
208     throw new InvalidParameterException("Wrong format for public keys");
209   }
210
211   /**
212    * @param input the byte array to unmarshall into a valid RSA
213    *          {@link PrivateKey} instance. MUST NOT be null.
214    * @return a new instance of a {@link GnuRSAPrivateKey} decoded from the
215    *         <i>PrivateKeyInfo</i> material fed as <code>input</code>.
216    * @throw InvalidParameterException if an exception occurs during the
217    *        unmarshalling process.
218    */
219   public PrivateKey decodePrivateKey(byte[] input)
220   {
221     if (Configuration.DEBUG)
222       log.entering(this.getClass().getName(), "decodePrivateKey()", input);
223     if (input == null)
224       throw new InvalidParameterException("Input bytes MUST NOT be null");
225
226     BigInteger version, n, e, d, p, q, dP, dQ, qInv;
227     DERReader der = new DERReader(input);
228     try
229       {
230         DERValue derPKI = der.read();
231         DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
232
233         DERValue derVersion = der.read();
234         DerUtil.checkIsBigInteger(derVersion, "Wrong Version field");
235         version = (BigInteger) derVersion.getValue();
236         if (version.compareTo(BigInteger.ZERO) != 0)
237           throw new InvalidParameterException("Unexpected Version: " + version);
238
239         DERValue derAlgoritmID = der.read();
240         DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
241
242         DERValue derOID = der.read();
243         OID algOID = (OID) derOID.getValue();
244         if (! algOID.equals(RSA_ALG_OID))
245           throw new InvalidParameterException("Unexpected OID: " + algOID);
246
247         // rfc-2459 states that this field is OPTIONAL but NULL if/when present
248         DERValue val = der.read();
249         if (val.getTag() == DER.NULL)
250           val = der.read();
251
252         byte[] pkBytes = (byte[]) val.getValue();
253         der = new DERReader(pkBytes);
254         DERValue derRSAPrivateKey = der.read();
255         DerUtil.checkIsConstructed(derRSAPrivateKey, "Wrong RSAPrivateKey field");
256
257         val = der.read();
258         DerUtil.checkIsBigInteger(val, "Wrong RSAPrivateKey Version field");
259         version = (BigInteger) val.getValue();
260         if (version.compareTo(BigInteger.ZERO) != 0)
261           throw new InvalidParameterException("Unexpected RSAPrivateKey Version: "
262                                               + version);
263
264         val = der.read();
265         DerUtil.checkIsBigInteger(val, "Wrong modulus field");
266         n = (BigInteger) val.getValue();
267         val = der.read();
268         DerUtil.checkIsBigInteger(val, "Wrong publicExponent field");
269         e = (BigInteger) val.getValue();
270         val = der.read();
271         DerUtil.checkIsBigInteger(val, "Wrong privateExponent field");
272         d = (BigInteger) val.getValue();
273         val = der.read();
274         DerUtil.checkIsBigInteger(val, "Wrong prime1 field");
275         p = (BigInteger) val.getValue();
276         val = der.read();
277         DerUtil.checkIsBigInteger(val, "Wrong prime2 field");
278         q = (BigInteger) val.getValue();
279         val = der.read();
280         DerUtil.checkIsBigInteger(val, "Wrong exponent1 field");
281         dP = (BigInteger) val.getValue();
282         val = der.read();
283         DerUtil.checkIsBigInteger(val, "Wrong exponent2 field");
284         dQ = (BigInteger) val.getValue();
285         val = der.read();
286         DerUtil.checkIsBigInteger(val, "Wrong coefficient field");
287         qInv = (BigInteger) val.getValue();
288       }
289     catch (IOException x)
290       {
291         InvalidParameterException y = new InvalidParameterException();
292         y.initCause(x);
293         throw y;
294       }
295     PrivateKey result = new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID,
296                                              n, e, d, p, q, dP, dQ, qInv);
297     if (Configuration.DEBUG)
298       log.exiting(this.getClass().getName(), "decodePrivateKey()", result);
299     return result;
300   }
301 }