2006-08-14 Mark Wielaard <mark@klomp.org>
[official-gcc.git] / libjava / classpath / gnu / java / security / key / dss / DSSKeyPairX509Codec.java
bloba5e8e9d47eb6984e789ab5ce6ed21b67c1e92bd8
1 /* DSSKeyPairX509Codec.java -- X.509 Encoding/Decoding handler
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
39 package gnu.java.security.key.dss;
41 import gnu.java.security.OID;
42 import gnu.java.security.Registry;
43 import gnu.java.security.der.BitString;
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;
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;
59 /**
60 * An implementation of an {@link IKeyPairCodec} that knows how to encode /
61 * decode X.509 ASN.1 external representation of DSS public keys.
63 public class DSSKeyPairX509Codec
64 implements IKeyPairCodec
66 private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
68 // implicit 0-arguments constructor
70 public int getFormatID()
72 return X509_FORMAT;
75 /**
76 * Returns the X.509 ASN.1 <i>SubjectPublicKeyInfo</i> representation of a
77 * DSA public key. The ASN.1 specification, as defined in RFC-3280, and
78 * RFC-2459, is as follows:
80 * <pre>
81 * SubjectPublicKeyInfo ::= SEQUENCE {
82 * algorithm AlgorithmIdentifier,
83 * subjectPublicKey BIT STRING
84 * }
86 * AlgorithmIdentifier ::= SEQUENCE {
87 * algorithm OBJECT IDENTIFIER,
88 * parameters ANY DEFINED BY algorithm OPTIONAL
89 * }
91 * DssParams ::= SEQUENCE {
92 * p INTEGER,
93 * q INTEGER,
94 * g INTEGER
95 * }
96 * </pre>
97 * <p>
98 * Note that RFC-3280 (page 79) implies that some certificates MAY have an
99 * absent, or NULL, parameters field in their AlgorithmIdentifier element,
100 * implying that those parameters MUST be <i>inherited</i> from another
101 * certificate. This implementation, encodes a <i>NULL</i> element as the DER
102 * value of the parameters field when such is the case.
103 * <p>
104 * The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
105 * DER-encoded form of the DSA public key as an INTEGER.
107 * <pre>
108 * DSAPublicKey ::= INTEGER -- public key, Y
109 * </pre>
111 * @param key the {@link PublicKey} instance to encode. MUST be an instance of
112 * {@link DSSPublicKey}.
113 * @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
114 * X.509 certificate.
115 * @throw InvalidParameterException if <code>key</code> is not an instance
116 * of {@link DSSPublicKey} or if an exception occurs during the
117 * marshalling process.
119 public byte[] encodePublicKey(PublicKey key)
121 if (! (key instanceof DSSPublicKey))
122 throw new InvalidParameterException("key");
124 DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
126 DSSPublicKey dssKey = (DSSPublicKey) key;
127 DERValue derParams;
128 if (dssKey.hasInheritedParameters())
129 derParams = new DERValue(DER.NULL, null);
130 else
132 BigInteger p = dssKey.getParams().getP();
133 BigInteger q = dssKey.getParams().getQ();
134 BigInteger g = dssKey.getParams().getG();
136 DERValue derP = new DERValue(DER.INTEGER, p);
137 DERValue derQ = new DERValue(DER.INTEGER, q);
138 DERValue derG = new DERValue(DER.INTEGER, g);
140 ArrayList params = new ArrayList(3);
141 params.add(derP);
142 params.add(derQ);
143 params.add(derG);
144 derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
147 ArrayList algorithmID = new ArrayList(2);
148 algorithmID.add(derOID);
149 algorithmID.add(derParams);
150 DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
151 algorithmID);
153 BigInteger y = dssKey.getY();
154 DERValue derDSAPublicKey = new DERValue(DER.INTEGER, y);
155 byte[] yBytes = derDSAPublicKey.getEncoded();
156 DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes));
158 ArrayList spki = new ArrayList(2);
159 spki.add(derAlgorithmID);
160 spki.add(derSPK);
161 DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
163 byte[] result;
164 ByteArrayOutputStream baos = new ByteArrayOutputStream();
167 DERWriter.write(baos, derSPKI);
168 result = baos.toByteArray();
170 catch (IOException x)
172 InvalidParameterException e = new InvalidParameterException(x.getMessage());
173 e.initCause(x);
174 throw e;
176 return result;
180 * @throws InvalidParameterException ALWAYS.
182 public byte[] encodePrivateKey(PrivateKey key)
184 throw new InvalidParameterException("Wrong format for private keys");
188 * @param input the byte array to unmarshall into a valid DSS
189 * {@link PublicKey} instance. MUST NOT be null.
190 * @return a new instance of a {@link DSSPublicKey} decoded from the
191 * <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
192 * @throw InvalidParameterException if an exception occurs during the
193 * unmarshalling process.
195 public PublicKey decodePublicKey(byte[] input)
197 if (input == null)
198 throw new InvalidParameterException("Input bytes MUST NOT be null");
200 BigInteger p = null;
201 BigInteger g = null;
202 BigInteger q = null;
203 BigInteger y;
204 DERReader der = new DERReader(input);
207 DERValue derSPKI = der.read();
208 DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
210 DERValue derAlgorithmID = der.read();
211 DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field");
213 DERValue derOID = der.read();
214 if (! (derOID.getValue() instanceof OID))
215 throw new InvalidParameterException("Wrong Algorithm field");
217 OID algOID = (OID) derOID.getValue();
218 if (! algOID.equals(DSA_ALG_OID))
219 throw new InvalidParameterException("Unexpected OID: " + algOID);
221 DERValue val = der.read();
222 // RFC-3280, page 79 states: "If the subjectPublicKeyInfo field of the
223 // certificate contains an algorithm field with null parameters or
224 // parameters are omitted, compare the certificate subjectPublicKey
225 // algorithm to the working_public_key_algorithm. If the certificate
226 // subjectPublicKey algorithm and the working_public_key_algorithm are
227 // different, set the working_public_key_parameters to null."
228 // in other words, the parameters field of an AlgorithmIdentifier
229 // element MAY NOT be present at all, or if present MAY be NULL!
230 // the Mauve test ValidDSAParameterInheritenceTest5, in
231 // gnu.testlet.java.security.cert.pkix.pkits, is/was failing because
232 // of this.
233 if (val.getTag() == DER.NULL)
234 val = der.read();
235 else if (val.isConstructed())
237 val = der.read();
238 DerUtil.checkIsBigInteger(val, "Wrong P field");
239 p = (BigInteger) val.getValue();
240 val = der.read();
241 DerUtil.checkIsBigInteger(val, "Wrong Q field");
242 q = (BigInteger) val.getValue();
243 val = der.read();
244 DerUtil.checkIsBigInteger(val, "Wrong G field");
245 g = (BigInteger) val.getValue();
247 val = der.read();
250 if (! (val.getValue() instanceof BitString))
251 throw new InvalidParameterException("Wrong SubjectPublicKey field");
253 byte[] yBytes = ((BitString) val.getValue()).toByteArray();
255 DERReader dsaPub = new DERReader(yBytes);
256 val = dsaPub.read();
257 DerUtil.checkIsBigInteger(val, "Wrong Y field");
258 y = (BigInteger) val.getValue();
260 catch (IOException x)
262 InvalidParameterException e = new InvalidParameterException(x.getMessage());
263 e.initCause(x);
264 throw e;
266 return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y);
270 * @throws InvalidParameterException ALWAYS.
272 public PrivateKey decodePrivateKey(byte[] input)
274 throw new InvalidParameterException("Wrong format for private keys");