1 /*
2  * Copyright (c) 2005, 2020, 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.mscapi;
27 
28 import java.math.BigInteger;
29 import java.security.AlgorithmParameters;
30 import java.security.KeyException;
31 import java.security.KeyFactory;
32 import java.security.KeyRep;
33 import java.security.ProviderException;
34 import java.security.PublicKey;
35 import java.security.interfaces.ECPublicKey;
36 import java.security.interfaces.RSAPublicKey;
37 import java.security.spec.ECParameterSpec;
38 import java.security.spec.ECPoint;
39 import java.security.spec.ECPublicKeySpec;
40 import java.util.Arrays;
41 
42 import sun.security.rsa.RSAUtil.KeyType;
43 import sun.security.rsa.RSAPublicKeyImpl;
44 import sun.security.util.ECKeySizeParameterSpec;
45 
46 /**
47  * The handle for an RSA public key using the Microsoft Crypto API.
48  *
49  * @since 1.6
50  */
51 public abstract class CPublicKey extends CKey implements PublicKey {
52 
53     private static final long serialVersionUID = -2289561342425825391L;
54 
55     protected byte[] encoding = null;
56 
57     public static class CECPublicKey extends CPublicKey implements ECPublicKey {
58 
59         private ECPoint w = null;
60         private static final long serialVersionUID = 12L;
61 
CECPublicKey(NativeHandles handles, int keyLength)62         CECPublicKey(NativeHandles handles, int keyLength) {
63             super("EC", handles, keyLength);
64         }
65 
66         @Override
getW()67         public ECPoint getW() {
68             if (w == null) {
69                 // See CKey::generateECBlob.
70                 try {
71                     byte[] blob = getPublicKeyBlob(
72                             handles.hCryptProv, handles.hCryptKey);
73                     int len = blob[8] & 0xff;
74                     byte[] x = Arrays.copyOfRange(blob, 8, 8 + len);
75                     byte[] y = Arrays.copyOfRange(blob, 8 + len, 8 + len + len);
76                     w = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
77                 } catch (KeyException e) {
78                     throw new ProviderException(e);
79                 }
80             }
81             return w;
82         }
83 
84         @Override
getEncoded()85         public byte[] getEncoded() {
86             if (encoding == null) {
87                 try {
88                     encoding = KeyFactory.getInstance("EC").generatePublic(
89                                 new ECPublicKeySpec(getW(), getParams()))
90                             .getEncoded();
91                 } catch (Exception e) {
92                     // ignore
93                 }
94             }
95             return encoding;
96         }
97 
98         @Override
getParams()99         public ECParameterSpec getParams() {
100             try {
101                 AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
102                 ap.init(new ECKeySizeParameterSpec(keyLength));
103                 return ap.getParameterSpec(ECParameterSpec.class);
104             } catch (Exception e) {
105                 throw new ProviderException(e);
106             }
107         }
108 
toString()109         public String toString() {
110             StringBuffer sb = new StringBuffer();
111             sb.append(algorithm + "PublicKey [size=").append(keyLength)
112                     .append("]\n  ECPoint: ").append(getW())
113                     .append("\n  params: ").append(getParams());
114             return sb.toString();
115         }
116     }
117 
118     public static class CRSAPublicKey extends CPublicKey implements RSAPublicKey {
119 
120         private BigInteger modulus = null;
121         private BigInteger exponent = null;
122         private static final long serialVersionUID = 12L;
123 
CRSAPublicKey(NativeHandles handles, int keyLength)124         CRSAPublicKey(NativeHandles handles, int keyLength) {
125             super("RSA", handles, keyLength);
126         }
127 
toString()128         public String toString() {
129             StringBuffer sb = new StringBuffer();
130             sb.append(algorithm + "PublicKey [size=").append(keyLength)
131                     .append(" bits, type=");
132             if (handles.hCryptKey != 0) {
133                 sb.append(getKeyType(handles.hCryptKey))
134                         .append(", container=").append(getContainerName(handles.hCryptProv));
135             } else {
136                 sb.append("CNG");
137             }
138             sb.append("]\n  modulus: ").append(getModulus())
139                     .append("\n  public exponent: ").append(getPublicExponent());
140             return sb.toString();
141         }
142 
143         @Override
getPublicExponent()144         public BigInteger getPublicExponent() {
145             if (exponent == null) {
146                 try {
147                     byte[] publicKeyBlob = getPublicKeyBlob(
148                             handles.hCryptProv, handles.hCryptKey);
149                     exponent = new BigInteger(1, getExponent(publicKeyBlob));
150                 } catch (KeyException e) {
151                     throw new ProviderException(e);
152                 }
153             }
154             return exponent;
155         }
156 
157         @Override
getModulus()158         public BigInteger getModulus() {
159             if (modulus == null) {
160                 try {
161                     byte[] publicKeyBlob = getPublicKeyBlob(
162                             handles.hCryptProv, handles.hCryptKey);
163                     modulus = new BigInteger(1, getModulus(publicKeyBlob));
164                 } catch (KeyException e) {
165                     throw new ProviderException(e);
166                 }
167             }
168             return modulus;
169         }
170 
171         @Override
getEncoded()172         public byte[] getEncoded() {
173             if (encoding == null) {
174                 try {
175                     encoding = RSAPublicKeyImpl.newKey(KeyType.RSA, null,
176                             getModulus(), getPublicExponent()).getEncoded();
177                 } catch (KeyException e) {
178                     // ignore
179                 }
180             }
181             return encoding;
182         }
183 
getExponent(byte[] keyBlob)184         private native byte[] getExponent(byte[] keyBlob) throws KeyException;
185 
getModulus(byte[] keyBlob)186         private native byte[] getModulus(byte[] keyBlob) throws KeyException;
187     }
188 
189     // Called by native code inside security.cpp
of( String alg, long hCryptProv, long hCryptKey, int keyLength)190     static CPublicKey of(
191             String alg, long hCryptProv, long hCryptKey, int keyLength) {
192         return of(alg, new NativeHandles(hCryptProv, hCryptKey), keyLength);
193     }
194 
of( String alg, NativeHandles handles, int keyLength)195     public static CPublicKey of(
196             String alg, NativeHandles handles, int keyLength) {
197         switch (alg) {
198             case "RSA":
199                 return new CRSAPublicKey(handles, keyLength);
200             case "EC":
201                 return new CECPublicKey(handles, keyLength);
202             default:
203                 throw new AssertionError("Unsupported algorithm: " + alg);
204         }
205     }
206 
CPublicKey( String alg, NativeHandles handles, int keyLength)207     protected CPublicKey(
208             String alg, NativeHandles handles, int keyLength) {
209         super(alg, handles, keyLength);
210     }
211 
212     @Override
getFormat()213     public String getFormat() {
214         return "X.509";
215     }
216 
writeReplace()217     protected Object writeReplace() throws java.io.ObjectStreamException {
218         return new KeyRep(KeyRep.Type.PUBLIC,
219                         getAlgorithm(),
220                         getFormat(),
221                         getEncoded());
222     }
223 
224     // Returns the CAPI or CNG representation of the key.
getPublicKeyBlob(long hCryptProv, long hCryptKey)225     native byte[] getPublicKeyBlob(long hCryptProv, long hCryptKey)
226             throws KeyException;
227 }
228