--- /dev/null Fri Oct 17 22:50:35 2014 +++ new/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java Fri Oct 17 22:50:35 2014 @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.security.ucrypto; + +import java.util.Set; +import java.util.Arrays; +import java.util.concurrent.ConcurrentSkipListSet; +import java.lang.ref.*; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.Key; +import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.KeyFactorySpi; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPublicKey; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; + +/** + * Wrapper class for native keys needed for using ucrypto APIs. + * This class currently supports native RSA private/public keys. + * + * @since 1.9 + */ +abstract class NativeKey implements Key { + + private static final long serialVersionUID = 6812507588904302830L; + + private final int numComponents; + + NativeKey(int numComponents) { + this.numComponents = numComponents; + } + + abstract long value(); + + int length() { + return numComponents; + } + + public String getAlgorithm() { return "RSA"; } + public String getFormat() { return "RAW"; } + public byte[] getEncoded() { + // not used; so not generated + return null; + } + + private native static void nativeFree(long id, int numComponents); + + static byte[] getMagnitude(BigInteger bi) { + byte[] b = bi.toByteArray(); + if ((b.length > 1) && (b[0] == 0)) { + int n = b.length - 1; + byte[] newarray = new byte[n]; + System.arraycopy(b, 1, newarray, 0, n); + b = newarray; + } + return b; + } + + static final class RSAPrivateCrt extends NativeKey implements RSAPrivateCrtKey { + + private static final long serialVersionUID = 6812507588904302831L; + + private final RSAPrivateCrtKeySpec keySpec; + private final long keyId; + + RSAPrivateCrt(KeySpec keySpec) throws InvalidKeySpecException { + super(8); + long pKey = 0L; + if (keySpec instanceof RSAPrivateCrtKeySpec) { + RSAPrivateCrtKeySpec ks = (RSAPrivateCrtKeySpec) keySpec; + BigInteger mod = ks.getModulus(); + BigInteger publicExp = ks.getPublicExponent(); + BigInteger privateExp = ks.getPrivateExponent(); + BigInteger primeP = ks.getPrimeP(); + BigInteger primeQ = ks.getPrimeQ(); + BigInteger primeExpP = ks.getPrimeExponentP(); + BigInteger primeExpQ = ks.getPrimeExponentQ(); + BigInteger crtCoeff = ks.getCrtCoefficient(); + pKey = nativeInit(NativeKey.getMagnitude(mod), + NativeKey.getMagnitude(publicExp), + NativeKey.getMagnitude(privateExp), + NativeKey.getMagnitude(primeP), + NativeKey.getMagnitude(primeQ), + NativeKey.getMagnitude(primeExpP), + NativeKey.getMagnitude(primeExpQ), + NativeKey.getMagnitude(crtCoeff)); + } else { + throw new InvalidKeySpecException("Only supports RSAPrivateCrtKeySpec"); + } + if (pKey == 0L) { + throw new UcryptoException("Error constructing RSA PrivateKey"); + } + // track native resource clean up + new KeyRef(this, pKey); + this.keySpec = (RSAPrivateCrtKeySpec) keySpec; + this.keyId = pKey; + } + + long value() { return keyId; } + public BigInteger getModulus() { return keySpec.getModulus(); }; + public BigInteger getPublicExponent() { return keySpec.getPublicExponent(); }; + public BigInteger getPrivateExponent() { return keySpec.getPrivateExponent(); }; + public BigInteger getPrimeP() { return keySpec.getPrimeP(); }; + public BigInteger getPrimeQ() { return keySpec.getPrimeQ(); }; + public BigInteger getPrimeExponentP() { return keySpec.getPrimeExponentP(); }; + public BigInteger getPrimeExponentQ() { return keySpec.getPrimeExponentQ(); }; + public BigInteger getCrtCoefficient() { return keySpec.getCrtCoefficient(); }; + + private native static long nativeInit(byte[] mod, byte[] pubExp, byte[] privExp, + byte[] p, byte[] q, + byte[] expP, byte[] expQ, byte[] crtCoeff); + } + + static final class RSAPublic extends NativeKey implements RSAPublicKey { + + private static final long serialVersionUID = 6812507588904302832L; + + private final RSAPublicKeySpec keySpec; + private final long keyId; + + RSAPublic(KeySpec keySpec) throws InvalidKeySpecException { + super(2); + long pKey = 0L; + if (keySpec instanceof RSAPublicKeySpec) { + RSAPublicKeySpec ks = (RSAPublicKeySpec) keySpec; + BigInteger mod = ks.getModulus(); + BigInteger publicExp = ks.getPublicExponent(); + pKey = nativeInit(NativeKey.getMagnitude(mod), + NativeKey.getMagnitude(publicExp)); + } else { + throw new InvalidKeySpecException("Only supports RSAPublicKeySpec"); + } + if (pKey == 0L) { + throw new UcryptoException("Error constructing RSA PublicKey"); + } + // track native resource clean up + new KeyRef(this, pKey); + this.keySpec = (RSAPublicKeySpec) keySpec; + this.keyId = pKey; + } + + long value() { return keyId; } + public BigInteger getModulus() { return keySpec.getModulus(); }; + public BigInteger getPublicExponent() { return keySpec.getPublicExponent(); }; + + private native static long nativeInit(byte[] mod, byte[] pubExp); + } + + // internal class for native resource cleanup + private static class KeyRef extends PhantomReference + implements Comparable { + + private static ReferenceQueue refQueue = + new ReferenceQueue(); + + // Needed to keep these references from being GC'ed until when their + // referents are GC'ed so we can do post-mortem processing + private static Set refList = + new ConcurrentSkipListSet(); + + private final long id; + private final int length; + + private static void drainRefQueueBounded() { + while (true) { + KeyRef next = (KeyRef) refQueue.poll(); + if (next == null) break; + next.dispose(); + } + } + + KeyRef(NativeKey nk, long id) { + super(nk, refQueue); + this.id = id; + this.length = nk.length(); + refList.add(this); + UcryptoProvider.debug("Resource: track NativeKey " + this.id); + drainRefQueueBounded(); + } + + public int compareTo(KeyRef other) { + if (this.id == other.id) { + return 0; + } else { + return (this.id < other.id) ? -1 : 1; + } + } + + void dispose() { + refList.remove(this); + UcryptoProvider.debug("Resource: free NativeKey " + this.id); + try { + NativeKey.nativeFree(id, length); + } finally { + this.clear(); + } + } + } +}