151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/* 272a80a636a9356a5920fbefb9a5bc05a78202ca6Przemyslaw Szczepaniak * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it 651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as 751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation. Oracle designates this 851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided 951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code. 1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT 1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that 1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code). 1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version 1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation, 1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any 2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions. 2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.security.x509; 2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.*; 2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Arrays; 3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Properties; 3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.Key; 3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.PublicKey; 3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.KeyFactory; 3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.Security; 3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.Provider; 3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.InvalidKeyException; 3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.NoSuchAlgorithmException; 3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.spec.InvalidKeySpecException; 3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.spec.X509EncodedKeySpec; 4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.misc.HexDumpEncoder; 4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.security.util.*; 4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/** 4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Holds an X.509 key, for example a public key found in an X.509 4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * certificate. Includes a description of the algorithm to be used 4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * with the key; these keys normally are used as 4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * "SubjectPublicKeyInfo". 4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <P>While this class can represent any kind of X.509 key, it may be 5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * desirable to provide subclasses which understand how to parse keying 5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * data. For example, RSA public keys have two members, one for the 5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * public modulus and one for the prime exponent. If such a class is 5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * provided, it is used when parsing X.509 keys. If one is not provided, 5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the key still parses correctly. 5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author David Brownell 5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class X509Key implements PublicKey { 6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** use serialVersionUID from JDK 1.1. for interoperability */ 6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static final long serialVersionUID = -5359250853002055002L; 6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* The algorithm information (name, parameters, etc). */ 6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected AlgorithmId algid; 6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The key bytes, without the algorithm information. 6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @deprecated Use the BitArray form which does not require keys to 7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * be byte aligned. 7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see sun.security.x509.X509Key#setKey(BitArray) 7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see sun.security.x509.X509Key#getKey() 7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski @Deprecated 7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected byte[] key = null; 7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The number of bits unused in the last byte of the key. 7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Added to keep the byte[] key form consistent with the BitArray 8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * form. Can de deleted when byte[] key is deleted. 8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 8272a80a636a9356a5920fbefb9a5bc05a78202ca6Przemyslaw Szczepaniak @Deprecated 8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int unusedBits = 0; 8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* BitArray form of key */ 8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private BitArray bitStringKey = null; 8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* The encoding for the key. */ 8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected byte[] encodedKey; 9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Default constructor. The key constructed must have its key 9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and algorithm initialized before it may be used, for example 9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by using <code>decode</code>. 9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public X509Key() { } 9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Build and initialize as a "default" key. All X.509 key 10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * data is stored and transmitted losslessly, but no knowledge 10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * about this particular algorithm is available. 10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private X509Key(AlgorithmId algid, BitArray key) 10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throws InvalidKeyException { 10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.algid = algid; 10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski setKey(key); 10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski encode(); 10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Sets the key in the BitArray form. 11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected void setKey(BitArray key) { 11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.bitStringKey = (BitArray)key.clone(); 11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Do this to keep the byte array form consistent with 11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * this. Can delete when byte[] key is deleted. 11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.key = key.toByteArray(); 12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int remaining = key.length() % 8; 12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.unusedBits = 12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski ((remaining == 0) ? 0 : 8 - remaining); 12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Gets the key. The key may or may not be byte aligned. 12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return a BitArray containing the key. 12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected BitArray getKey() { 13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Do this for consistency in case a subclass 13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * modifies byte[] key directly. Remove when 13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * byte[] key is deleted. 13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Note: the consistency checks fail when the subclass 13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * modifies a non byte-aligned key (into a byte-aligned key) 13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * using the deprecated byte[] key field. 13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.bitStringKey = new BitArray( 14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.key.length * 8 - this.unusedBits, 14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.key); 14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return (BitArray)bitStringKey.clone(); 14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Construct X.509 subject public key from a DER value. If 14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the runtime environment is configured with a specific class for 14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * this kind of key, a subclass is returned. Otherwise, a generic 15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * X509Key object is returned. 15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <P>This mechanism gurantees that keys (and algorithms) may be 15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * freely manipulated and transferred, without risk of losing 15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * information. Also, when a key (or algorithm) needs some special 15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * handling, that specific need can be accomodated. 15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param in the DER-encoded SubjectPublicKeyInfo value 15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IOException on data format errors 15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public static PublicKey parse(DerValue in) throws IOException 16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski { 16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AlgorithmId algorithm; 16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski PublicKey subjectKey; 16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (in.tag != DerValue.tag_Sequence) 16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IOException("corrupt subject key"); 16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski algorithm = AlgorithmId.parse(in.data.getDerValue()); 16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski subjectKey = buildX509Key(algorithm, 17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski in.data.getUnalignedBitString()); 17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (InvalidKeyException e) { 17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IOException("subject key, " + e.getMessage(), e); 17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (in.data.available() != 0) 17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IOException("excess subject key"); 17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return subjectKey; 18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Parse the key bits. This may be redefined by subclasses to take 18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * advantage of structure within the key. For example, RSA public 18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * keys encapsulate two unsigned integers (modulus and exponent) as 18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DER values within the <code>key</code> bits; Diffie-Hellman and 18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DSS/DSA keys encapsulate a single unsigned integer. 18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <P>This function is called when creating X.509 SubjectPublicKeyInfo 19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * values using the X509Key member functions, such as <code>parse</code> 19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and <code>decode</code>. 19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IOException on parsing errors. 19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception InvalidKeyException on invalid key encodings. 19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected void parseKeyBits() throws IOException, InvalidKeyException { 19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski encode(); 19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Factory interface, building the kind of key associated with this 20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * specific algorithm ID or else returning this generic base class. 20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * See the description above. 20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski static PublicKey buildX509Key(AlgorithmId algid, BitArray key) 20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throws IOException, InvalidKeyException 20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski { 20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Use the algid and key parameters to produce the ASN.1 encoding 21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of the key, which will then be used as the input to the 21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * key factory. 21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski DerOutputStream x509EncodedKeyStream = new DerOutputStream(); 21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski encode(x509EncodedKeyStream, algid, key); 21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski X509EncodedKeySpec x509KeySpec 21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski = new X509EncodedKeySpec(x509EncodedKeyStream.toByteArray()); 21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Instantiate the key factory of the appropriate algorithm 22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski KeyFactory keyFac = KeyFactory.getInstance(algid.getName()); 22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Generate the public key 22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return keyFac.generatePublic(x509KeySpec); 22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (NoSuchAlgorithmException e) { 22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Return generic X509Key with opaque key data (see below) 22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (InvalidKeySpecException e) { 22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InvalidKeyException(e.getMessage(), e); 22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Try again using JDK1.1-style for backwards compatibility. 23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String classname = ""; 23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Properties props; 23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String keytype; 23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Provider sunProvider; 23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski sunProvider = Security.getProvider("SUN"); 24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (sunProvider == null) 24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InstantiationException(); 24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski classname = sunProvider.getProperty("PublicKey.X.509." + 24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski algid.getName()); 24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (classname == null) { 24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InstantiationException(); 24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 24872a80a636a9356a5920fbefb9a5bc05a78202ca6Przemyslaw Szczepaniak Class<?> keyClass = null; 24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski keyClass = Class.forName(classname); 25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (ClassNotFoundException e) { 25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski ClassLoader cl = ClassLoader.getSystemClassLoader(); 25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (cl != null) { 25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski keyClass = cl.loadClass(classname); 25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object inst = null; 25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski X509Key result; 26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (keyClass != null) 26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski inst = keyClass.newInstance(); 26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (inst instanceof X509Key) { 26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski result = (X509Key) inst; 26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski result.algid = algid; 26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski result.setKey(key); 26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski result.parseKeyBits(); 26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return result; 26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (ClassNotFoundException e) { 27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (InstantiationException e) { 27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (IllegalAccessException e) { 27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // this should not happen. 27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IOException (classname + " [internal error]"); 27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski X509Key result = new X509Key(algid, key); 27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return result; 27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the algorithm to be used with this key. 28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String getAlgorithm() { 28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return algid.getName(); 28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the algorithm ID to be used with this key. 29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AlgorithmId getAlgorithmId() { return algid; } 29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Encode SubjectPublicKeyInfo sequence on the DER output stream. 29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IOException on encoding errors. 29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public final void encode(DerOutputStream out) throws IOException 29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski { 30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski encode(out, this.algid, getKey()); 30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the DER-encoded form of the key as a byte array. 30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public byte[] getEncoded() { 30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return getEncodedInternal().clone(); 30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (InvalidKeyException e) { 31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // XXX 31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public byte[] getEncodedInternal() throws InvalidKeyException { 31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski byte[] encoded = encodedKey; 31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (encoded == null) { 31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski DerOutputStream out = new DerOutputStream(); 32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski encode(out); 32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski encoded = out.toByteArray(); 32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (IOException e) { 32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InvalidKeyException("IOException : " + 32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski e.getMessage()); 32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski encodedKey = encoded; 32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return encoded; 32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the format for this key: "X.509" 33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String getFormat() { 33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return "X.509"; 33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the DER-encoded form of the key as a byte array. 34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception InvalidKeyException on encoding errors. 34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public byte[] encode() throws InvalidKeyException { 34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return getEncodedInternal().clone(); 34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns a printable representation of the key 34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String toString() 35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski { 35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski HexDumpEncoder encoder = new HexDumpEncoder(); 35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return "algorithm = " + algid.toString() 35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski + ", unparsed keybits = \n" + encoder.encodeBuffer(key); 35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Initialize an X509Key object from an input stream. The data on that 36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * input stream must be encoded using DER, obeying the X.509 36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>SubjectPublicKeyInfo</code> format. That is, the data is a 36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * sequence consisting of an algorithm ID and a bit string which holds 36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the key. (That bit string is often used to encapsulate another DER 36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * encoded sequence.) 36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <P>Subclasses should not normally redefine this method; they should 36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * instead provide a <code>parseKeyBits</code> method to parse any 36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * fields inside the <code>key</code> member. 36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <P>The exception to this rule is that since private keys need not 37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * be encoded using the X.509 <code>SubjectPublicKeyInfo</code> format, 37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * private keys may override this method, <code>encode</code>, and 37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of course <code>getFormat</code>. 37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param in an input stream with a DER-encoded X.509 37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * SubjectPublicKeyInfo value 37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception InvalidKeyException on parsing errors. 37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void decode(InputStream in) 38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throws InvalidKeyException 38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski { 38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski DerValue val; 38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski val = new DerValue(in); 38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (val.tag != DerValue.tag_Sequence) 38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InvalidKeyException("invalid key format"); 38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski algid = AlgorithmId.parse(val.data.getDerValue()); 39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski setKey(val.data.getUnalignedBitString()); 39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski parseKeyBits(); 39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (val.data.available() != 0) 39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InvalidKeyException ("excess key data"); 39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (IOException e) { 39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // e.printStackTrace (); 39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InvalidKeyException("IOException: " + 39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski e.getMessage()); 39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void decode(byte[] encodedKey) throws InvalidKeyException { 40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski decode(new ByteArrayInputStream(encodedKey)); 40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Serialization write ... X.509 keys serialize as 40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * themselves, and they're parsed when they get read back. 40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private void writeObject(ObjectOutputStream stream) throws IOException { 41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski stream.write(getEncoded()); 41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Serialization read ... X.509 keys serialize as 41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * themselves, and they're parsed when they get read back. 41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private void readObject(ObjectInputStream stream) throws IOException { 41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski decode(stream); 42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (InvalidKeyException e) { 42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski e.printStackTrace(); 42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IOException("deserialized key is invalid: " + 42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski e.getMessage()); 42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean equals(Object obj) { 42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (this == obj) { 43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return true; 43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (obj instanceof Key == false) { 43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski byte[] thisEncoded = this.getEncodedInternal(); 43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski byte[] otherEncoded; 43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (obj instanceof X509Key) { 43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski otherEncoded = ((X509Key)obj).getEncodedInternal(); 44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski otherEncoded = ((Key)obj).getEncoded(); 44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return Arrays.equals(thisEncoded, otherEncoded); 44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (InvalidKeyException e) { 44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Calculates a hash code value for the object. Objects 45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * which are equal will also have the same hashcode. 45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int hashCode() { 45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski byte[] b1 = getEncodedInternal(); 45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int r = b1.length; 45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = 0; i < b1.length; i++) { 45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski r += (b1[i] & 0xff) * 37; 45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return r; 46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (InvalidKeyException e) { 46251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // should not happen 46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return 0; 46451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* 46851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Produce SubjectPublicKey encoding from algorithm id and key material. 46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski static void encode(DerOutputStream out, AlgorithmId algid, BitArray key) 47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throws IOException { 47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski DerOutputStream tmp = new DerOutputStream(); 47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski algid.encode(tmp); 47451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski tmp.putUnalignedBitString(key); 47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski out.write(DerValue.tag_Sequence, tmp); 47651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 478