1 /*
2  * Copyright (c) 2003, 2021, 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.pkcs11;
27 
28 import java.math.BigInteger;
29 
30 import java.security.*;
31 import java.security.spec.*;
32 
33 import javax.crypto.interfaces.*;
34 import javax.crypto.spec.*;
35 
36 import static sun.security.pkcs11.TemplateManager.*;
37 import sun.security.pkcs11.wrapper.*;
38 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
39 
40 /**
41  * DH KeyFactory implementation.
42  *
43  * @author  Andreas Sterbenz
44  * @since   1.5
45  */
46 final class P11DHKeyFactory extends P11KeyFactory {
47 
P11DHKeyFactory(Token token, String algorithm)48     P11DHKeyFactory(Token token, String algorithm) {
49         super(token, algorithm);
50     }
51 
implTranslatePublicKey(PublicKey key)52     PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException {
53         try {
54             if (key instanceof DHPublicKey) {
55                 DHPublicKey dhKey = (DHPublicKey)key;
56                 DHParameterSpec params = dhKey.getParams();
57                 return generatePublic(
58                     dhKey.getY(),
59                     params.getP(),
60                     params.getG()
61                 );
62             } else if ("X.509".equals(key.getFormat())) {
63                 // let SunJCE provider parse for us, then recurse
64                 try {
65                     KeyFactory factory = implGetSoftwareFactory();
66                     key = (PublicKey)factory.translateKey(key);
67                     return implTranslatePublicKey(key);
68                 } catch (GeneralSecurityException e) {
69                     throw new InvalidKeyException("Could not translate key", e);
70                 }
71             } else {
72                 throw new InvalidKeyException("PublicKey must be instance "
73                         + "of DHPublicKey or have X.509 encoding");
74             }
75         } catch (PKCS11Exception e) {
76             throw new InvalidKeyException("Could not create DH public key", e);
77         }
78     }
79 
implTranslatePrivateKey(PrivateKey key)80     PrivateKey implTranslatePrivateKey(PrivateKey key)
81             throws InvalidKeyException {
82         try {
83             if (key instanceof DHPrivateKey) {
84                 DHPrivateKey dhKey = (DHPrivateKey)key;
85                 DHParameterSpec params = dhKey.getParams();
86                 return generatePrivate(
87                     dhKey.getX(),
88                     params.getP(),
89                     params.getG()
90                 );
91             } else if ("PKCS#8".equals(key.getFormat())) {
92                 // let SunJCE provider parse for us, then recurse
93                 try {
94                     KeyFactory factory = implGetSoftwareFactory();
95                     key = (PrivateKey)factory.translateKey(key);
96                     return implTranslatePrivateKey(key);
97                 } catch (GeneralSecurityException e) {
98                     throw new InvalidKeyException("Could not translate key", e);
99                 }
100             } else {
101                 throw new InvalidKeyException("PrivateKey must be instance "
102                         + "of DHPrivateKey or have PKCS#8 encoding");
103             }
104         } catch (PKCS11Exception e) {
105             throw new InvalidKeyException("Could not create DH private key", e);
106         }
107     }
108 
109     // see JCA spec
engineGeneratePublic(KeySpec keySpec)110     protected PublicKey engineGeneratePublic(KeySpec keySpec)
111             throws InvalidKeySpecException {
112         token.ensureValid();
113         if (keySpec instanceof X509EncodedKeySpec) {
114             try {
115                 KeyFactory factory = implGetSoftwareFactory();
116                 PublicKey key = factory.generatePublic(keySpec);
117                 return implTranslatePublicKey(key);
118             } catch (GeneralSecurityException e) {
119                 throw new InvalidKeySpecException
120                         ("Could not create DH public key", e);
121             }
122         }
123         if (keySpec instanceof DHPublicKeySpec == false) {
124             throw new InvalidKeySpecException("Only DHPublicKeySpec and "
125                 + "X509EncodedKeySpec supported for DH public keys");
126         }
127         try {
128             DHPublicKeySpec ds = (DHPublicKeySpec)keySpec;
129             return generatePublic(
130                 ds.getY(),
131                 ds.getP(),
132                 ds.getG()
133             );
134         } catch (PKCS11Exception e) {
135             throw new InvalidKeySpecException
136                 ("Could not create DH public key", e);
137         }
138     }
139 
140     // see JCA spec
engineGeneratePrivate(KeySpec keySpec)141     protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
142             throws InvalidKeySpecException {
143         token.ensureValid();
144         if (keySpec instanceof PKCS8EncodedKeySpec) {
145             try {
146                 KeyFactory factory = implGetSoftwareFactory();
147                 PrivateKey key = factory.generatePrivate(keySpec);
148                 return implTranslatePrivateKey(key);
149             } catch (GeneralSecurityException e) {
150                 throw new InvalidKeySpecException
151                         ("Could not create DH private key", e);
152             }
153         }
154         if (keySpec instanceof DHPrivateKeySpec == false) {
155             throw new InvalidKeySpecException("Only DHPrivateKeySpec and "
156                 + "PKCS8EncodedKeySpec supported for DH private keys");
157         }
158         try {
159             DHPrivateKeySpec ds = (DHPrivateKeySpec)keySpec;
160             return generatePrivate(
161                 ds.getX(),
162                 ds.getP(),
163                 ds.getG()
164             );
165         } catch (PKCS11Exception e) {
166             throw new InvalidKeySpecException
167                 ("Could not create DH private key", e);
168         }
169     }
170 
generatePublic(BigInteger y, BigInteger p, BigInteger g)171     private PublicKey generatePublic(BigInteger y, BigInteger p, BigInteger g)
172             throws PKCS11Exception {
173         CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
174             new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY),
175             new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH),
176             new CK_ATTRIBUTE(CKA_VALUE, y),
177             new CK_ATTRIBUTE(CKA_PRIME, p),
178             new CK_ATTRIBUTE(CKA_BASE, g),
179         };
180         attributes = token.getAttributes
181                 (O_IMPORT, CKO_PUBLIC_KEY, CKK_DH, attributes);
182         Session session = null;
183         try {
184             session = token.getObjSession();
185             long keyID = token.p11.C_CreateObject(session.id(), attributes);
186             return P11Key.publicKey
187                 (session, keyID, "DH", p.bitLength(), attributes);
188         } finally {
189             token.releaseSession(session);
190         }
191     }
192 
generatePrivate(BigInteger x, BigInteger p, BigInteger g)193     private PrivateKey generatePrivate(BigInteger x, BigInteger p,
194             BigInteger g) throws PKCS11Exception {
195         CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
196             new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
197             new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH),
198             new CK_ATTRIBUTE(CKA_VALUE, x),
199             new CK_ATTRIBUTE(CKA_PRIME, p),
200             new CK_ATTRIBUTE(CKA_BASE, g),
201         };
202         attributes = token.getAttributes
203                 (O_IMPORT, CKO_PRIVATE_KEY, CKK_DH, attributes);
204         Session session = null;
205         try {
206             session = token.getObjSession();
207             long keyID = token.p11.C_CreateObject(session.id(), attributes);
208             return P11Key.privateKey
209                 (session, keyID, "DH", p.bitLength(), attributes);
210         } finally {
211             token.releaseSession(session);
212         }
213     }
214 
implGetPublicKeySpec(P11Key key, Class<T> keySpec, Session[] session)215     <T extends KeySpec> T implGetPublicKeySpec(P11Key key, Class<T> keySpec,
216             Session[] session) throws PKCS11Exception, InvalidKeySpecException {
217         if (keySpec.isAssignableFrom(DHPublicKeySpec.class)) {
218             session[0] = token.getObjSession();
219             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
220                 new CK_ATTRIBUTE(CKA_VALUE),
221                 new CK_ATTRIBUTE(CKA_PRIME),
222                 new CK_ATTRIBUTE(CKA_BASE),
223             };
224             long keyID = key.getKeyID();
225             try {
226                 token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);
227             } finally {
228                 key.releaseKeyID();
229             }
230             KeySpec spec = new DHPublicKeySpec(
231                 attributes[0].getBigInteger(),
232                 attributes[1].getBigInteger(),
233                 attributes[2].getBigInteger()
234             );
235             return keySpec.cast(spec);
236         } else { // X.509 handled in superclass
237             throw new InvalidKeySpecException("Only DHPublicKeySpec and "
238                 + "X509EncodedKeySpec supported for DH public keys");
239         }
240     }
241 
implGetPrivateKeySpec(P11Key key, Class<T> keySpec, Session[] session)242     <T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec,
243             Session[] session) throws PKCS11Exception, InvalidKeySpecException {
244         if (keySpec.isAssignableFrom(DHPrivateKeySpec.class)) {
245             session[0] = token.getObjSession();
246             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
247                 new CK_ATTRIBUTE(CKA_VALUE),
248                 new CK_ATTRIBUTE(CKA_PRIME),
249                 new CK_ATTRIBUTE(CKA_BASE),
250             };
251             long keyID = key.getKeyID();
252             try {
253                 token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);
254             } finally {
255                 key.releaseKeyID();
256             }
257             KeySpec spec = new DHPrivateKeySpec(
258                 attributes[0].getBigInteger(),
259                 attributes[1].getBigInteger(),
260                 attributes[2].getBigInteger()
261             );
262             return keySpec.cast(spec);
263         } else { // PKCS#8 handled in superclass
264             throw new InvalidKeySpecException("Only DHPrivateKeySpec "
265                 + "and PKCS8EncodedKeySpec supported for DH private keys");
266         }
267     }
268 
implGetSoftwareFactory()269     KeyFactory implGetSoftwareFactory() throws GeneralSecurityException {
270         return KeyFactory.getInstance("DH", P11Util.getSunJceProvider());
271     }
272 
273 }
274