1 /* 2 * Copyright (c) 2014, 2015, 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 com.oracle.security.ucrypto; 27 28 import java.util.Set; 29 import java.util.Arrays; 30 import java.util.concurrent.ConcurrentSkipListSet; 31 import java.lang.ref.*; 32 33 import java.math.BigInteger; 34 import java.security.*; 35 import java.security.interfaces.*; 36 import java.security.spec.*; 37 38 /** 39 * Wrapper class for native keys needed for using ucrypto APIs. 40 * This class currently supports native RSA private/public keys. 41 * 42 * @since 9 43 */ 44 abstract class NativeKey implements Key { 45 46 private static final long serialVersionUID = 6812507588904302830L; 47 48 private final int numComponents; 49 50 NativeKey(int numComponents) { 51 this.numComponents = numComponents; 52 } 53 54 abstract long value(); 55 56 int length() { 57 return numComponents; 58 } 59 60 public String getAlgorithm() { return "RSA"; } 61 public String getFormat() { return "RAW"; } 62 public byte[] getEncoded() { 63 // not used; so not generated 64 return null; 65 } 66 67 private native static void nativeFree(long id, int numComponents); 68 69 static byte[] getMagnitude(BigInteger bi) { 70 byte[] b = bi.toByteArray(); 71 if ((b.length > 1) && (b[0] == 0)) { 72 int n = b.length - 1; 73 byte[] newarray = new byte[n]; 74 System.arraycopy(b, 1, newarray, 0, n); 75 b = newarray; 76 } 77 return b; 78 } 79 80 static final class RSAPrivate extends NativeKey implements RSAPrivateKey { 81 82 private static final long serialVersionUID = 1622705588904302831L; 83 84 private final RSAPrivateKeySpec keySpec; 85 private final long keyId; 86 87 RSAPrivate(KeySpec keySpec) throws InvalidKeySpecException { 88 super(2); 89 long pKey = 0L; 90 if (keySpec instanceof RSAPrivateKeySpec) { 91 RSAPrivateKeySpec ks = (RSAPrivateKeySpec) keySpec; 92 BigInteger mod = ks.getModulus(); 93 BigInteger privateExp = ks.getPrivateExponent(); 94 pKey = nativeInit(NativeKey.getMagnitude(mod), 95 NativeKey.getMagnitude(privateExp)); 96 } else { 97 throw new InvalidKeySpecException("Only supports RSAPrivateKeySpec." + 98 " Received: " + keySpec.getClass().getName()); 99 } 100 if (pKey == 0L) { 101 throw new UcryptoException("Error constructing RSA PrivateKey"); 102 } 103 // track native resource clean up 104 new KeyRef(this, pKey); 105 this.keySpec = (RSAPrivateKeySpec) keySpec; 106 this.keyId = pKey; 107 } 108 109 long value() { return keyId; } 110 public BigInteger getModulus() { return keySpec.getModulus(); }; 111 public BigInteger getPrivateExponent() { return keySpec.getPrivateExponent(); }; 112 113 private native static long nativeInit(byte[] mod, byte[] privExp); 114 } 115 116 static final class RSAPrivateCrt extends NativeKey implements RSAPrivateCrtKey { 117 118 private static final long serialVersionUID = 6812507588904302831L; 119 120 private final RSAPrivateCrtKeySpec keySpec; 121 private final long keyId; 122 123 RSAPrivateCrt(KeySpec keySpec) throws InvalidKeySpecException { 124 super(8); 125 long pKey = 0L; 126 if (keySpec instanceof RSAPrivateCrtKeySpec) { 127 RSAPrivateCrtKeySpec ks = (RSAPrivateCrtKeySpec) keySpec; 128 BigInteger mod = ks.getModulus(); 129 BigInteger publicExp = ks.getPublicExponent(); 130 BigInteger privateExp = ks.getPrivateExponent(); 131 BigInteger primeP = ks.getPrimeP(); 132 BigInteger primeQ = ks.getPrimeQ(); 133 BigInteger primeExpP = ks.getPrimeExponentP(); 134 BigInteger primeExpQ = ks.getPrimeExponentQ(); 135 BigInteger crtCoeff = ks.getCrtCoefficient(); 136 pKey = nativeInit(NativeKey.getMagnitude(mod), 137 NativeKey.getMagnitude(publicExp), 138 NativeKey.getMagnitude(privateExp), 139 NativeKey.getMagnitude(primeP), 140 NativeKey.getMagnitude(primeQ), 141 NativeKey.getMagnitude(primeExpP), 142 NativeKey.getMagnitude(primeExpQ), 143 NativeKey.getMagnitude(crtCoeff)); 144 } else { 145 throw new InvalidKeySpecException("Only supports RSAPrivateCrtKeySpec." 146 + " Received: " + keySpec.getClass().getName()); 147 } 148 if (pKey == 0L) { 149 throw new UcryptoException("Error constructing RSA PrivateCrtKey"); 150 } 151 // track native resource clean up 152 new KeyRef(this, pKey); 153 this.keySpec = (RSAPrivateCrtKeySpec) keySpec; 154 this.keyId = pKey; 155 } 156 157 long value() { return keyId; } 158 public BigInteger getModulus() { return keySpec.getModulus(); }; 159 public BigInteger getPublicExponent() { return keySpec.getPublicExponent(); }; 160 public BigInteger getPrivateExponent() { return keySpec.getPrivateExponent(); }; 161 public BigInteger getPrimeP() { return keySpec.getPrimeP(); }; 162 public BigInteger getPrimeQ() { return keySpec.getPrimeQ(); }; 163 public BigInteger getPrimeExponentP() { return keySpec.getPrimeExponentP(); }; 164 public BigInteger getPrimeExponentQ() { return keySpec.getPrimeExponentQ(); }; 165 public BigInteger getCrtCoefficient() { return keySpec.getCrtCoefficient(); }; 166 167 private native static long nativeInit(byte[] mod, byte[] pubExp, byte[] privExp, 168 byte[] p, byte[] q, 169 byte[] expP, byte[] expQ, byte[] crtCoeff); 170 } 171 172 static final class RSAPublic extends NativeKey implements RSAPublicKey { 173 174 private static final long serialVersionUID = 6812507588904302832L; 175 176 private final RSAPublicKeySpec keySpec; 177 private final long keyId; 178 179 RSAPublic(KeySpec keySpec) throws InvalidKeySpecException { 180 super(2); 181 long pKey = 0L; 182 if (keySpec instanceof RSAPublicKeySpec) { 183 RSAPublicKeySpec ks = (RSAPublicKeySpec) keySpec; 184 BigInteger mod = ks.getModulus(); 185 BigInteger publicExp = ks.getPublicExponent(); 186 pKey = nativeInit(NativeKey.getMagnitude(mod), 187 NativeKey.getMagnitude(publicExp)); 188 } else { 189 throw new InvalidKeySpecException("Only supports RSAPublicKeySpec." + 190 " Received: " + keySpec.getClass().getName()); 191 } 192 if (pKey == 0L) { 193 throw new UcryptoException("Error constructing RSA PublicKey"); 194 } 195 // track native resource clean up 196 new KeyRef(this, pKey); 197 this.keySpec = (RSAPublicKeySpec) keySpec; 198 this.keyId = pKey; 199 } 200 201 long value() { return keyId; } 202 public BigInteger getModulus() { return keySpec.getModulus(); }; 203 public BigInteger getPublicExponent() { return keySpec.getPublicExponent(); }; 204 205 private native static long nativeInit(byte[] mod, byte[] pubExp); 206 } 207 208 // internal class for native resource cleanup 209 private static class KeyRef extends PhantomReference<NativeKey> 210 implements Comparable<KeyRef> { 211 212 private static ReferenceQueue<NativeKey> refQueue = 213 new ReferenceQueue<NativeKey>(); 214 215 // Needed to keep these references from being GC'ed until when their 216 // referents are GC'ed so we can do post-mortem processing 217 private static Set<KeyRef> refList = 218 new ConcurrentSkipListSet<KeyRef>(); 219 220 private final long id; 221 private final int length; 222 223 private static void drainRefQueueBounded() { 224 while (true) { 225 KeyRef next = (KeyRef) refQueue.poll(); 226 if (next == null) break; 227 next.dispose(); 228 } 229 } 230 231 KeyRef(NativeKey nk, long id) { 232 super(nk, refQueue); 233 this.id = id; 234 this.length = nk.length(); 235 refList.add(this); 236 UcryptoProvider.debug("Resource: track NativeKey " + this.id); 237 drainRefQueueBounded(); 238 } 239 240 public int compareTo(KeyRef other) { 241 if (this.id == other.id) { 242 return 0; 243 } else { 244 return (this.id < other.id) ? -1 : 1; 245 } 246 } 247 248 void dispose() { 249 refList.remove(this); 250 UcryptoProvider.debug("Resource: free NativeKey " + this.id); 251 try { 252 NativeKey.nativeFree(id, length); 253 } finally { 254 this.clear(); 255 } 256 } 257 } 258 }