Frames | No Frames |
1: /* DSSKeyPairX509Codec.java -- X.509 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.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; 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: 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. 62: */ 63: public class DSSKeyPairX509Codec 64: implements IKeyPairCodec 65: { 66: private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING); 67: 68: // implicit 0-arguments constructor 69: 70: public int getFormatID() 71: { 72: return X509_FORMAT; 73: } 74: 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: 79: * 80: * <pre> 81: * SubjectPublicKeyInfo ::= SEQUENCE { 82: * algorithm AlgorithmIdentifier, 83: * subjectPublicKey BIT STRING 84: * } 85: * 86: * AlgorithmIdentifier ::= SEQUENCE { 87: * algorithm OBJECT IDENTIFIER, 88: * parameters ANY DEFINED BY algorithm OPTIONAL 89: * } 90: * 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. 106: * 107: * <pre> 108: * DSAPublicKey ::= INTEGER -- public key, Y 109: * </pre> 110: * 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. 118: */ 119: public byte[] encodePublicKey(PublicKey key) 120: { 121: if (! (key instanceof DSSPublicKey)) 122: throw new InvalidParameterException("key"); 123: 124: DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID); 125: 126: DSSPublicKey dssKey = (DSSPublicKey) key; 127: DERValue derParams; 128: if (dssKey.hasInheritedParameters()) 129: derParams = new DERValue(DER.NULL, null); 130: else 131: { 132: BigInteger p = dssKey.getParams().getP(); 133: BigInteger q = dssKey.getParams().getQ(); 134: BigInteger g = dssKey.getParams().getG(); 135: 136: DERValue derP = new DERValue(DER.INTEGER, p); 137: DERValue derQ = new DERValue(DER.INTEGER, q); 138: DERValue derG = new DERValue(DER.INTEGER, g); 139: 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); 145: } 146: 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); 152: 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)); 157: 158: ArrayList spki = new ArrayList(2); 159: spki.add(derAlgorithmID); 160: spki.add(derSPK); 161: DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); 162: 163: byte[] result; 164: ByteArrayOutputStream baos = new ByteArrayOutputStream(); 165: try 166: { 167: DERWriter.write(baos, derSPKI); 168: result = baos.toByteArray(); 169: } 170: catch (IOException x) 171: { 172: InvalidParameterException e = new InvalidParameterException(x.getMessage()); 173: e.initCause(x); 174: throw e; 175: } 176: return result; 177: } 178: 179: /** 180: * @throws InvalidParameterException ALWAYS. 181: */ 182: public byte[] encodePrivateKey(PrivateKey key) 183: { 184: throw new InvalidParameterException("Wrong format for private keys"); 185: } 186: 187: /** 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. 194: */ 195: public PublicKey decodePublicKey(byte[] input) 196: { 197: if (input == null) 198: throw new InvalidParameterException("Input bytes MUST NOT be null"); 199: 200: BigInteger p = null; 201: BigInteger g = null; 202: BigInteger q = null; 203: BigInteger y; 204: DERReader der = new DERReader(input); 205: try 206: { 207: DERValue derSPKI = der.read(); 208: DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); 209: 210: DERValue derAlgorithmID = der.read(); 211: DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); 212: 213: DERValue derOID = der.read(); 214: if (! (derOID.getValue() instanceof OID)) 215: throw new InvalidParameterException("Wrong Algorithm field"); 216: 217: OID algOID = (OID) derOID.getValue(); 218: if (! algOID.equals(DSA_ALG_OID)) 219: throw new InvalidParameterException("Unexpected OID: " + algOID); 220: 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()) 236: { 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(); 246: 247: val = der.read(); 248: } 249: 250: if (! (val.getValue() instanceof BitString)) 251: throw new InvalidParameterException("Wrong SubjectPublicKey field"); 252: 253: byte[] yBytes = ((BitString) val.getValue()).toByteArray(); 254: 255: DERReader dsaPub = new DERReader(yBytes); 256: val = dsaPub.read(); 257: DerUtil.checkIsBigInteger(val, "Wrong Y field"); 258: y = (BigInteger) val.getValue(); 259: } 260: catch (IOException x) 261: { 262: InvalidParameterException e = new InvalidParameterException(x.getMessage()); 263: e.initCause(x); 264: throw e; 265: } 266: return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); 267: } 268: 269: /** 270: * @throws InvalidParameterException ALWAYS. 271: */ 272: public PrivateKey decodePrivateKey(byte[] input) 273: { 274: throw new InvalidParameterException("Wrong format for private keys"); 275: } 276: }