Home | History | Annotate | Download | only in ec
      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