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