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 }
--- EOF ---