1 /* 2 * Copyright (c) 2006, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.ec; 27 28 import java.io.IOException; 29 import java.math.BigInteger; 30 31 import java.security.*; 32 import java.security.interfaces.*; 33 import java.security.spec.*; 34 35 import sun.security.util.*; 36 import sun.security.x509.AlgorithmId; 37 import sun.security.pkcs.PKCS8Key; 38 39 /** 40 * Key implementation for EC private keys. 41 * 42 * ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft): 43 * 44 * <pre> 45 * EXPLICIT TAGS 46 * 47 * ECPrivateKey ::= SEQUENCE { 48 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), 49 * privateKey OCTET STRING, 50 * parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, 51 * publicKey [1] BIT STRING OPTIONAL 52 * } 53 * </pre> 54 * 55 * We currently ignore the optional parameters and publicKey fields. We 56 * require that the parameters are encoded as part of the AlgorithmIdentifier, 57 * not in the private key structure. 58 * 59 * @since 1.6 60 * @author Andreas Sterbenz 61 */ 62 public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { 63 64 private static final long serialVersionUID = 88695385615075129L; 65 66 private BigInteger s; // private value 67 private ECParameterSpec params; 68 69 /** 70 * Construct a key from its encoding. Called by the ECKeyFactory and 71 * the SunPKCS11 code. 72 */ 73 public ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException { 74 decode(encoded); 75 } 76 77 /** 78 * Construct a key from its components. Used by the 79 * KeyFactory and the SunPKCS11 code. 80 */ 81 public ECPrivateKeyImpl(BigInteger s, ECParameterSpec params) 82 throws InvalidKeyException { 83 this.s = s; 84 this.params = params; 85 // generate the encoding 86 algid = new AlgorithmId 87 (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params)); 88 try { 89 DerOutputStream out = new DerOutputStream(); 90 out.putInteger(1); // version 1 91 byte[] privBytes = ECParameters.trimZeroes(s.toByteArray()); 92 out.putOctetString(privBytes); 93 DerValue val = 94 new DerValue(DerValue.tag_Sequence, out.toByteArray()); 95 key = val.toByteArray(); 96 } catch (IOException exc) { 97 // should never occur 98 throw new InvalidKeyException(exc); 99 } 100 } 101 102 // see JCA doc 103 public String getAlgorithm() { 104 return "EC"; 105 } 106 107 // see JCA doc 108 public BigInteger getS() { 109 return s; 110 } 111 112 // see JCA doc 113 public ECParameterSpec getParams() { 114 return params; 115 } 116 117 /** 118 * Parse the key. Called by PKCS8Key. 119 */ 120 protected void parseKeyBits() throws InvalidKeyException { 121 try { 122 DerInputStream in = new DerInputStream(key); 123 DerValue derValue = in.getDerValue(); 124 if (derValue.tag != DerValue.tag_Sequence) { 125 throw new IOException("Not a SEQUENCE"); 126 } 127 DerInputStream data = derValue.data; 128 int version = data.getInteger(); 129 if (version != 1) { 130 throw new IOException("Version must be 1"); 131 } 132 byte[] privData = data.getOctetString(); 133 s = new BigInteger(1, privData); 134 while (data.available() != 0) { 135 DerValue value = data.getDerValue(); 136 if (value.isContextSpecific((byte)0)) { 137 // ignore for now 138 } else if (value.isContextSpecific((byte)1)) { 139 // ignore for now 140 } else { 141 throw new InvalidKeyException("Unexpected value: " + value); 142 } 143 } 144 AlgorithmParameters algParams = this.algid.getParameters(); 145 if (algParams == null) { 146 throw new InvalidKeyException("EC domain parameters must be " 147 + "encoded in the algorithm identifier"); 148 } 149 params = algParams.getParameterSpec(ECParameterSpec.class); 150 } catch (IOException e) { 151 throw new InvalidKeyException("Invalid EC private key", e); 152 } catch (InvalidParameterSpecException e) { 153 throw new InvalidKeyException("Invalid EC private key", e); 154 } 155 } 156 157 // return a string representation of this key for debugging 158 public String toString() { 159 return "Sun EC private key, " + params.getCurve().getField().getFieldSize() 160 + " bits\n private value: " 161 + s + "\n parameters: " + params; 162 } 163 164 } 165