1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.conscrypt;
18
19import java.math.BigInteger;
20import java.security.InvalidKeyException;
21import java.security.Key;
22import java.security.KeyFactorySpi;
23import java.security.PrivateKey;
24import java.security.PublicKey;
25import java.security.interfaces.DSAParams;
26import java.security.interfaces.DSAPrivateKey;
27import java.security.interfaces.DSAPublicKey;
28import java.security.spec.DSAPrivateKeySpec;
29import java.security.spec.DSAPublicKeySpec;
30import java.security.spec.InvalidKeySpecException;
31import java.security.spec.KeySpec;
32import java.security.spec.PKCS8EncodedKeySpec;
33import java.security.spec.X509EncodedKeySpec;
34
35public class OpenSSLDSAKeyFactory extends KeyFactorySpi {
36
37    @Override
38    protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
39        if (keySpec == null) {
40            throw new InvalidKeySpecException("keySpec == null");
41        }
42
43        if (keySpec instanceof DSAPublicKeySpec) {
44            return new OpenSSLDSAPublicKey((DSAPublicKeySpec) keySpec);
45        } else if (keySpec instanceof X509EncodedKeySpec) {
46            return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_DSA);
47        }
48        throw new InvalidKeySpecException("Must use DSAPublicKeySpec or X509EncodedKeySpec; was "
49                + keySpec.getClass().getName());
50    }
51
52    @Override
53    protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
54        if (keySpec == null) {
55            throw new InvalidKeySpecException("keySpec == null");
56        }
57
58        if (keySpec instanceof DSAPrivateKeySpec) {
59            return new OpenSSLDSAPrivateKey((DSAPrivateKeySpec) keySpec);
60        } else if (keySpec instanceof PKCS8EncodedKeySpec) {
61            return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
62                    NativeCrypto.EVP_PKEY_DSA);
63        }
64        throw new InvalidKeySpecException("Must use DSAPrivateKeySpec or PKCS8EncodedKeySpec; was "
65                + keySpec.getClass().getName());
66    }
67
68    @Override
69    protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
70            throws InvalidKeySpecException {
71        if (key == null) {
72            throw new InvalidKeySpecException("key == null");
73        }
74
75        if (keySpec == null) {
76            throw new InvalidKeySpecException("keySpec == null");
77        }
78
79        if (!"DSA".equals(key.getAlgorithm())) {
80            throw new InvalidKeySpecException("Key must be a DSA key");
81        }
82
83        if (key instanceof DSAPublicKey && DSAPublicKeySpec.class.isAssignableFrom(keySpec)) {
84            DSAPublicKey dsaKey = (DSAPublicKey) key;
85            DSAParams params = dsaKey.getParams();
86            return (T) new DSAPublicKeySpec(dsaKey.getY(), params.getP(), params.getQ(),
87                    params.getG());
88        } else if (key instanceof PublicKey && DSAPublicKeySpec.class.isAssignableFrom(keySpec)) {
89            final byte[] encoded = key.getEncoded();
90            if (!"X.509".equals(key.getFormat()) || encoded == null) {
91                throw new InvalidKeySpecException("Not a valid X.509 encoding");
92            }
93            DSAPublicKey dsaKey =
94                    (DSAPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
95            DSAParams params = dsaKey.getParams();
96            return (T) new DSAPublicKeySpec(dsaKey.getY(), params.getP(), params.getQ(),
97                    params.getG());
98        } else if (key instanceof DSAPrivateKey
99                && DSAPrivateKeySpec.class.isAssignableFrom(keySpec)) {
100            DSAPrivateKey dsaKey = (DSAPrivateKey) key;
101            DSAParams params = dsaKey.getParams();
102            return (T) new DSAPrivateKeySpec(dsaKey.getX(), params.getP(), params.getQ(),
103                    params.getG());
104        } else if (key instanceof PrivateKey && DSAPrivateKeySpec.class.isAssignableFrom(keySpec)) {
105            final byte[] encoded = key.getEncoded();
106            if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
107                throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
108            }
109            DSAPrivateKey dsaKey =
110                    (DSAPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
111            DSAParams params = dsaKey.getParams();
112            return (T) new DSAPrivateKeySpec(dsaKey.getX(), params.getP(), params.getQ(),
113                    params.getG());
114        } else if (key instanceof PrivateKey
115                && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
116            final byte[] encoded = key.getEncoded();
117            if (!"PKCS#8".equals(key.getFormat())) {
118                throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
119                        + key.getFormat());
120            } else if (encoded == null) {
121                throw new InvalidKeySpecException("Key is not encodable");
122            }
123            return (T) new PKCS8EncodedKeySpec(encoded);
124        } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
125            final byte[] encoded = key.getEncoded();
126            if (!"X.509".equals(key.getFormat())) {
127                throw new InvalidKeySpecException("Encoding type must be X.509; was "
128                        + key.getFormat());
129            } else if (encoded == null) {
130                throw new InvalidKeySpecException("Key is not encodable");
131            }
132            return (T) new X509EncodedKeySpec(encoded);
133        } else {
134            throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
135                    + key.getClass().getName() + ", keySpec=" + keySpec.getName());
136        }
137    }
138
139    @Override
140    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
141        if (key == null) {
142            throw new InvalidKeyException("key == null");
143        }
144        if ((key instanceof OpenSSLDSAPublicKey) || (key instanceof OpenSSLDSAPrivateKey)) {
145            return key;
146        } else if (key instanceof DSAPublicKey) {
147            DSAPublicKey dsaKey = (DSAPublicKey) key;
148
149            BigInteger y = dsaKey.getY();
150
151            DSAParams params = dsaKey.getParams();
152            BigInteger p = params.getP();
153            BigInteger q = params.getQ();
154            BigInteger g = params.getG();
155
156            try {
157                return engineGeneratePublic(new DSAPublicKeySpec(y, p, q, g));
158            } catch (InvalidKeySpecException e) {
159                throw new InvalidKeyException(e);
160            }
161        } else if (key instanceof DSAPrivateKey) {
162            DSAPrivateKey dsaKey = (DSAPrivateKey) key;
163
164            BigInteger x = dsaKey.getX();
165
166            DSAParams params = dsaKey.getParams();
167            BigInteger p = params.getP();
168            BigInteger q = params.getQ();
169            BigInteger g = params.getG();
170
171            try {
172                return engineGeneratePrivate(new DSAPrivateKeySpec(x, p, q, g));
173            } catch (InvalidKeySpecException e) {
174                throw new InvalidKeyException(e);
175            }
176        } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
177            byte[] encoded = key.getEncoded();
178            if (encoded == null) {
179                throw new InvalidKeyException("Key does not support encoding");
180            }
181            try {
182                return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
183            } catch (InvalidKeySpecException e) {
184                throw new InvalidKeyException(e);
185            }
186        } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
187            byte[] encoded = key.getEncoded();
188            if (encoded == null) {
189                throw new InvalidKeyException("Key does not support encoding");
190            }
191            try {
192                return engineGeneratePublic(new X509EncodedKeySpec(encoded));
193            } catch (InvalidKeySpecException e) {
194                throw new InvalidKeyException(e);
195            }
196        } else {
197            throw new InvalidKeyException("Key must be DSA public or private key; was "
198                    + key.getClass().getName());
199        }
200    }
201}
202