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
26package sun.security.ec;
27
28import java.io.IOException;
29import java.math.BigInteger;
30
31import java.security.*;
32import java.security.interfaces.*;
33import java.security.spec.*;
34
35import sun.security.util.DerInputStream;
36import sun.security.util.DerOutputStream;
37import sun.security.util.DerValue;
38import sun.security.util.ECParameters;
39import sun.security.util.ECUtil;
40import sun.security.x509.AlgorithmId;
41import 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 */
66public 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}
160