blob: 9bd888206778edeecc2752afecdee899d8d293e1 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25/*
26 * $Id: DOMKeyValue.java,v 1.18 2005/05/10 18:15:33 mullan Exp $
27 */
28package org.jcp.xml.dsig.internal.dom;
29
30import javax.xml.crypto.*;
31import javax.xml.crypto.dom.DOMCryptoContext;
32import javax.xml.crypto.dsig.*;
33import javax.xml.crypto.dsig.keyinfo.KeyValue;
34
35import java.security.KeyException;
36import java.security.KeyFactory;
37import java.security.NoSuchAlgorithmException;
38import java.security.PublicKey;
39import java.security.interfaces.DSAParams;
40import java.security.interfaces.DSAPublicKey;
41import java.security.interfaces.RSAPublicKey;
42import java.security.spec.DSAPublicKeySpec;
43import java.security.spec.InvalidKeySpecException;
44import java.security.spec.KeySpec;
45import java.security.spec.RSAPublicKeySpec;
46import org.w3c.dom.Document;
47import org.w3c.dom.Element;
48import org.w3c.dom.Node;
49
50/**
51 * DOM-based implementation of KeyValue.
52 *
53 * @author Sean Mullan
54 */
55public final class DOMKeyValue extends DOMStructure implements KeyValue {
56
57 private KeyFactory rsakf, dsakf;
58 private PublicKey publicKey;
59 private javax.xml.crypto.dom.DOMStructure externalPublicKey;
60
61 // DSAKeyValue CryptoBinaries
62 private DOMCryptoBinary p, q, g, y, j, seed, pgen;
63
64 // RSAKeyValue CryptoBinaries
65 private DOMCryptoBinary modulus, exponent;
66
67 public DOMKeyValue(PublicKey key) throws KeyException {
68 if (key == null) {
69 throw new NullPointerException("key cannot be null");
70 }
71 this.publicKey = key;
72 if (key instanceof DSAPublicKey) {
73 DSAPublicKey dkey = (DSAPublicKey) key;
74 DSAParams params = dkey.getParams();
75 p = new DOMCryptoBinary(params.getP());
76 q = new DOMCryptoBinary(params.getQ());
77 g = new DOMCryptoBinary(params.getG());
78 y = new DOMCryptoBinary(dkey.getY());
79 } else if (key instanceof RSAPublicKey) {
80 RSAPublicKey rkey = (RSAPublicKey) key;
81 exponent = new DOMCryptoBinary(rkey.getPublicExponent());
82 modulus = new DOMCryptoBinary(rkey.getModulus());
83 } else {
84 throw new KeyException("unsupported key algorithm: " +
85 key.getAlgorithm());
86 }
87 }
88
89 /**
90 * Creates a <code>DOMKeyValue</code> from an element.
91 *
92 * @param kvElem a KeyValue element
93 */
94 public DOMKeyValue(Element kvElem) throws MarshalException {
95 Element kvtElem = DOMUtils.getFirstChildElement(kvElem);
96 if (kvtElem.getLocalName().equals("DSAKeyValue")) {
97 publicKey = unmarshalDSAKeyValue(kvtElem);
98 } else if (kvtElem.getLocalName().equals("RSAKeyValue")) {
99 publicKey = unmarshalRSAKeyValue(kvtElem);
100 } else {
101 publicKey = null;
102 externalPublicKey = new javax.xml.crypto.dom.DOMStructure(kvtElem);
103 }
104 }
105
106 public PublicKey getPublicKey() throws KeyException {
107 if (publicKey == null) {
108 throw new KeyException("can't convert KeyValue to PublicKey");
109 } else {
110 return publicKey;
111 }
112 }
113
114 public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
115 throws MarshalException {
116 Document ownerDoc = DOMUtils.getOwnerDocument(parent);
117
118 // create KeyValue element
119 Element kvElem = DOMUtils.createElement
120 (ownerDoc, "KeyValue", XMLSignature.XMLNS, dsPrefix);
121 marshalPublicKey(kvElem, ownerDoc, dsPrefix, context);
122
123 parent.appendChild(kvElem);
124 }
125
126 private void marshalPublicKey(Node parent, Document doc, String dsPrefix,
127 DOMCryptoContext context) throws MarshalException {
128 if (publicKey != null) {
129 if (publicKey instanceof DSAPublicKey) {
130 // create and append DSAKeyValue element
131 marshalDSAPublicKey(parent, doc, dsPrefix, context);
132 } else if (publicKey instanceof RSAPublicKey) {
133 // create and append RSAKeyValue element
134 marshalRSAPublicKey(parent, doc, dsPrefix, context);
135 } else {
136 throw new MarshalException(publicKey.getAlgorithm() +
137 " public key algorithm not supported");
138 }
139 } else {
140 parent.appendChild(externalPublicKey.getNode());
141 }
142 }
143
144 private void marshalDSAPublicKey(Node parent, Document doc,
145 String dsPrefix, DOMCryptoContext context) throws MarshalException {
146 Element dsaElem = DOMUtils.createElement
147 (doc, "DSAKeyValue", XMLSignature.XMLNS, dsPrefix);
148 // parameters J, Seed & PgenCounter are not included
149 Element pElem = DOMUtils.createElement
150 (doc, "P", XMLSignature.XMLNS, dsPrefix);
151 Element qElem = DOMUtils.createElement
152 (doc, "Q", XMLSignature.XMLNS, dsPrefix);
153 Element gElem = DOMUtils.createElement
154 (doc, "G", XMLSignature.XMLNS, dsPrefix);
155 Element yElem = DOMUtils.createElement
156 (doc, "Y", XMLSignature.XMLNS, dsPrefix);
157 p.marshal(pElem, dsPrefix, context);
158 q.marshal(qElem, dsPrefix, context);
159 g.marshal(gElem, dsPrefix, context);
160 y.marshal(yElem, dsPrefix, context);
161 dsaElem.appendChild(pElem);
162 dsaElem.appendChild(qElem);
163 dsaElem.appendChild(gElem);
164 dsaElem.appendChild(yElem);
165 parent.appendChild(dsaElem);
166 }
167
168 private void marshalRSAPublicKey(Node parent, Document doc,
169 String dsPrefix, DOMCryptoContext context) throws MarshalException {
170 Element rsaElem = DOMUtils.createElement
171 (doc, "RSAKeyValue", XMLSignature.XMLNS, dsPrefix);
172 Element modulusElem = DOMUtils.createElement
173 (doc, "Modulus", XMLSignature.XMLNS, dsPrefix);
174 Element exponentElem = DOMUtils.createElement
175 (doc, "Exponent", XMLSignature.XMLNS, dsPrefix);
176 modulus.marshal(modulusElem, dsPrefix, context);
177 exponent.marshal(exponentElem, dsPrefix, context);
178 rsaElem.appendChild(modulusElem);
179 rsaElem.appendChild(exponentElem);
180 parent.appendChild(rsaElem);
181 }
182
183 private DSAPublicKey unmarshalDSAKeyValue(Element kvtElem)
184 throws MarshalException {
185 if (dsakf == null) {
186 try {
187 dsakf = KeyFactory.getInstance("DSA");
188 } catch (NoSuchAlgorithmException e) {
189 throw new RuntimeException("unable to create DSA KeyFactory: " +
190 e.getMessage());
191 }
192 }
193 Element curElem = DOMUtils.getFirstChildElement(kvtElem);
194 // check for P and Q
195 if (curElem.getLocalName().equals("P")) {
196 p = new DOMCryptoBinary(curElem.getFirstChild());
197 curElem = DOMUtils.getNextSiblingElement(curElem);
198 q = new DOMCryptoBinary(curElem.getFirstChild());
199 curElem = DOMUtils.getNextSiblingElement(curElem);
200 }
201 if (curElem.getLocalName().equals("G")) {
202 g = new DOMCryptoBinary(curElem.getFirstChild());
203 curElem = DOMUtils.getNextSiblingElement(curElem);
204 }
205 y = new DOMCryptoBinary(curElem.getFirstChild());
206 curElem = DOMUtils.getNextSiblingElement(curElem);
207 if (curElem != null && curElem.getLocalName().equals("J")) {
208 j = new DOMCryptoBinary(curElem.getFirstChild());
209 curElem = DOMUtils.getNextSiblingElement(curElem);
210 }
211 if (curElem != null) {
212 seed = new DOMCryptoBinary(curElem.getFirstChild());
213 curElem = DOMUtils.getNextSiblingElement(curElem);
214 pgen = new DOMCryptoBinary(curElem.getFirstChild());
215 }
216 //@@@ do we care about j, pgenCounter or seed?
217 DSAPublicKeySpec spec = new DSAPublicKeySpec
218 (y.getBigNum(), p.getBigNum(), q.getBigNum(), g.getBigNum());
219 return (DSAPublicKey) generatePublicKey(dsakf, spec);
220 }
221
222 private RSAPublicKey unmarshalRSAKeyValue(Element kvtElem)
223 throws MarshalException {
224 if (rsakf == null) {
225 try {
226 rsakf = KeyFactory.getInstance("RSA");
227 } catch (NoSuchAlgorithmException e) {
228 throw new RuntimeException("unable to create RSA KeyFactory: " +
229 e.getMessage());
230 }
231 }
232 Element modulusElem = DOMUtils.getFirstChildElement(kvtElem);
233 modulus = new DOMCryptoBinary(modulusElem.getFirstChild());
234 Element exponentElem = DOMUtils.getNextSiblingElement(modulusElem);
235 exponent = new DOMCryptoBinary(exponentElem.getFirstChild());
236 RSAPublicKeySpec spec = new RSAPublicKeySpec
237 (modulus.getBigNum(), exponent.getBigNum());
238 return (RSAPublicKey) generatePublicKey(rsakf, spec);
239 }
240
241 private PublicKey generatePublicKey(KeyFactory kf, KeySpec keyspec) {
242 try {
243 return kf.generatePublic(keyspec);
244 } catch (InvalidKeySpecException e) {
245 //@@@ should dump exception to log
246 return null;
247 }
248 }
249
250 public boolean equals(Object obj) {
251 if (this == obj) {
252 return true;
253 }
254 if (!(obj instanceof KeyValue)) {
255 return false;
256 }
257 try {
258 KeyValue kv = (KeyValue) obj;
259 if (publicKey == null ) {
260 if (kv.getPublicKey() != null) {
261 return false;
262 }
263 } else if (!publicKey.equals(kv.getPublicKey())) {
264 return false;
265 }
266 } catch (KeyException ke) {
267 // no practical way to determine if the keys are equal
268 return false;
269 }
270
271 return true;
272 }
273}