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