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