1d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com/*
2d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * Copyright (C) 2012 The Android Open Source Project
3d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com *
4d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * Licensed under the Apache License, Version 2.0 (the "License");
5d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * you may not use this file except in compliance with the License.
6d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * You may obtain a copy of the License at
7d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com *
8d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com *      http://www.apache.org/licenses/LICENSE-2.0
9d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com *
10d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * Unless required by applicable law or agreed to in writing, software
11d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * distributed under the License is distributed on an "AS IS" BASIS,
12d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * See the License for the specific language governing permissions and
14d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * limitations under the License.
15d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com */
16a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
17a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.compackage org.conscrypt;
189a6eb0e1e8a8de7371cd9604f34619b8f87de66fsenorblanco@chromium.org
19a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.math.BigInteger;
203f2d45aff69260fcf39d4eea8586387ed44402bbsenorblanco@chromium.orgimport java.security.InvalidAlgorithmParameterException;
21d912ca419927e8548e9e931156bbbc81f26969aesenorblanco@chromium.orgimport java.security.InvalidParameterException;
22a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECField;
23a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECFieldF2m;
24a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECFieldFp;
25a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECParameterSpec;
26392e14eaaf952565e25e11b8e5133507e4e7d0d8senorblanco@chromium.orgimport java.security.spec.ECPoint;
27a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.EllipticCurve;
28a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
291c4c9ef43747b42d2c31b5f17fe5e054fb3fee64commit-bot@chromium.orgpublic final class OpenSSLECGroupContext {
30b3c0f4886e22b6d2041c1049a1f295943959fff1scroggo    private final long groupCtx;
31a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
32a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    public OpenSSLECGroupContext(long groupCtx) {
33a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        this.groupCtx = groupCtx;
34781cc76e0f1ebb06e0796a9237045ae9d4bddd21sugoi@google.com    }
35f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
36a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    public static OpenSSLECGroupContext getCurveByName(String curveName) {
3772ae6bd24eb72be13d5745129c16058e4d54e2f4scroggo@google.com        // Workaround for OpenSSL not supporting SECG names for NIST P-192 and P-256
38a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        // (aka ANSI X9.62 prime192v1 and prime256v1) curve names.
39a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        if ("secp256r1".equals(curveName)) {
405a7c6be72b940dde8ff6ad2485a09aecd56a2660scroggo@google.com            curveName = "prime256v1";
41a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        } else if ("secp192r1".equals(curveName)) {
42a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com            curveName = "prime192v1";
438c6411a603266e94dd87445ac30e0b1abc36b0afreed@google.com        }
440833777df1f05adafd9b70c666a72d80defa4f6bdjsollen@google.com
456c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        final long ctx = NativeCrypto.EC_GROUP_new_by_curve_name(curveName);
4635c5ff0be81f2bbba9a7f31b055124a51e6168f4senorblanco@chromium.org        if (ctx == 0) {
47b4ca9df976951adf632388371f9a8a9219d93014senorblanco@chromium.org            return null;
484a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        }
49a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
504a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org        NativeCrypto.EC_GROUP_set_point_conversion_form(ctx,
51c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org                NativeCrypto.POINT_CONVERSION_UNCOMPRESSED);
52e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com        NativeCrypto.EC_GROUP_set_asn1_flag(ctx, NativeCrypto.OPENSSL_EC_NAMED_CURVE);
539e5f85e89d03a850d435fc951e74e9861a0c1bddcommit-bot@chromium.org
54a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        return new OpenSSLECGroupContext(ctx);
55cf292b7b32732330f7e0a55e6dd323426e466f80commit-bot@chromium.org    }
56a612d4c5134655fe6703c8d2f63be710aa1e2767senorblanco@chromium.org
57088719ecdc89b399dd3a3a65f8cced262e50d951robertphillips@google.com    public static OpenSSLECGroupContext getInstance(int type, BigInteger p, BigInteger a,
58a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com            BigInteger b, BigInteger x, BigInteger y, BigInteger n, BigInteger h) {
59a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        final long ctx = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), a.toByteArray(),
600ac74b2c0d0f740bdf1c0dcba2bef77bc33f77e9sugoi@google.com                b.toByteArray());
61fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        if (ctx == 0) {
6286fc266eda887920e3dd104bee8121ae19729cf5senorblanco@chromium.org            return null;
63a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        }
64c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org
65a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        NativeCrypto.EC_GROUP_set_point_conversion_form(ctx,
663f2d45aff69260fcf39d4eea8586387ed44402bbsenorblanco@chromium.org                NativeCrypto.POINT_CONVERSION_UNCOMPRESSED);
67a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
68d912ca419927e8548e9e931156bbbc81f26969aesenorblanco@chromium.org        OpenSSLECGroupContext group = new OpenSSLECGroupContext(ctx);
69a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
70a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        OpenSSLECPointContext generator = new OpenSSLECPointContext(group,
71a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com                NativeCrypto.EC_POINT_new(ctx));
72a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
73a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        NativeCrypto.EC_POINT_set_affine_coordinates(ctx, generator.getContext(),
74b3c0f4886e22b6d2041c1049a1f295943959fff1scroggo                x.toByteArray(), y.toByteArray());
75a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
76a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        NativeCrypto.EC_GROUP_set_generator(ctx, generator.getContext(), n.toByteArray(),
77a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com                h.toByteArray());
78a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
79781cc76e0f1ebb06e0796a9237045ae9d4bddd21sugoi@google.com        return group;
80f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    }
8172ae6bd24eb72be13d5745129c16058e4d54e2f4scroggo@google.com
82a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    @Override
83a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    protected void finalize() throws Throwable {
84a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        try {
85a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com            if (groupCtx != 0) {
868c6411a603266e94dd87445ac30e0b1abc36b0afreed@google.com                NativeCrypto.EC_GROUP_clear_free(groupCtx);
876c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            }
88a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        } finally {
89d8a6cc814f1a0a8faaddad05ae765ad2f6b11aacscroggo@google.com            super.finalize();
90d8a6cc814f1a0a8faaddad05ae765ad2f6b11aacscroggo@google.com        }
91a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    }
92e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com
939e5f85e89d03a850d435fc951e74e9861a0c1bddcommit-bot@chromium.org    @Override
94a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    public boolean equals(Object o) {
95cf292b7b32732330f7e0a55e6dd323426e466f80commit-bot@chromium.org        if (!(o instanceof OpenSSLECGroupContext)) {
96a612d4c5134655fe6703c8d2f63be710aa1e2767senorblanco@chromium.org            return false;
97941ee9303b62163ae08bbdcd7ad514e1a6389bdarobertphillips@google.com        }
98a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
990ac74b2c0d0f740bdf1c0dcba2bef77bc33f77e9sugoi@google.com        final OpenSSLECGroupContext other = (OpenSSLECGroupContext) o;
100fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return NativeCrypto.EC_GROUP_cmp(groupCtx, other.groupCtx);
10186fc266eda887920e3dd104bee8121ae19729cf5senorblanco@chromium.org    }
10282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
103b4ca9df976951adf632388371f9a8a9219d93014senorblanco@chromium.org    @Override
104a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    public int hashCode() {
105a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        // TODO Auto-generated method stub
106a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        return super.hashCode();
107a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    }
108a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
109a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    public long getContext() {
1105370cd969d8f3957e4306068e6195ac1bca3d6cddjsollen@google.com        return groupCtx;
1115370cd969d8f3957e4306068e6195ac1bca3d6cddjsollen@google.com    }
1129a6eb0e1e8a8de7371cd9604f34619b8f87de66fsenorblanco@chromium.org
113a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    public static OpenSSLECGroupContext getInstance(ECParameterSpec params)
114a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com            throws InvalidAlgorithmParameterException {
115a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        final String curveName = Platform.getCurveName(params);
1165a7c6be72b940dde8ff6ad2485a09aecd56a2660scroggo@google.com        if (curveName != null) {
1170833777df1f05adafd9b70c666a72d80defa4f6bdjsollen@google.com            return OpenSSLECGroupContext.getCurveByName(curveName);
118a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com        }
119a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
120d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com        final EllipticCurve curve = params.getCurve();
121c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        final ECField field = curve.getField();
122c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org
123c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        final int type;
124c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        final BigInteger p;
125c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        if (field instanceof ECFieldFp) {
126c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org            type = NativeCrypto.EC_CURVE_GFP;
127            p = ((ECFieldFp) field).getP();
128        } else if (field instanceof ECFieldF2m) {
129            type = NativeCrypto.EC_CURVE_GF2M;
130            p = ((ECFieldF2m) field).getReductionPolynomial();
131        } else {
132            throw new InvalidParameterException("unhandled field class "
133                    + field.getClass().getName());
134        }
135
136        final ECPoint generator = params.getGenerator();
137        return OpenSSLECGroupContext.getInstance(type, p, curve.getA(), curve.getB(),
138                generator.getAffineX(), generator.getAffineY(), params.getOrder(),
139                BigInteger.valueOf(params.getCofactor()));
140    }
141
142    public ECParameterSpec getECParameterSpec() {
143        final String curveName = NativeCrypto.EC_GROUP_get_curve_name(groupCtx);
144
145        final byte[][] curveParams = NativeCrypto.EC_GROUP_get_curve(groupCtx);
146        final BigInteger p = new BigInteger(curveParams[0]);
147        final BigInteger a = new BigInteger(curveParams[1]);
148        final BigInteger b = new BigInteger(curveParams[2]);
149
150        final ECField field;
151        final int type = NativeCrypto.get_EC_GROUP_type(groupCtx);
152        if (type == NativeCrypto.EC_CURVE_GFP) {
153            field = new ECFieldFp(p);
154        } else if (type == NativeCrypto.EC_CURVE_GF2M) {
155            field = new ECFieldF2m(p.bitLength() - 1, p);
156        } else {
157            throw new RuntimeException("unknown curve type " + type);
158        }
159
160        final EllipticCurve curve = new EllipticCurve(field, a, b);
161
162        final OpenSSLECPointContext generatorCtx = new OpenSSLECPointContext(this,
163                NativeCrypto.EC_GROUP_get_generator(groupCtx));
164        final ECPoint generator = generatorCtx.getECPoint();
165
166        final BigInteger order = new BigInteger(NativeCrypto.EC_GROUP_get_order(groupCtx));
167        final BigInteger cofactor = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(groupCtx));
168
169        ECParameterSpec spec = new ECParameterSpec(curve, generator, order, cofactor.intValue());
170        Platform.setCurveName(spec, curveName);
171        return spec;
172    }
173}
174