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 import java.math.BigInteger; 33 import java.nio.ByteBuffer; 34 35 import java.security.SignatureSpi; 36 import java.security.NoSuchAlgorithmException; 37 import java.security.InvalidParameterException; 38 import java.security.InvalidKeyException; 39 import java.security.SignatureException; 40 import java.security.Key; 41 import java.security.PrivateKey; 42 import java.security.PublicKey; 43 44 import java.security.*; 45 import java.security.interfaces.*; 46 import java.security.spec.RSAPrivateCrtKeySpec; 47 import java.security.spec.RSAPublicKeySpec; 48 import java.security.spec.InvalidKeySpecException; 49 import sun.nio.ch.DirectBuffer; 50 import java.nio.ByteBuffer; 51 import sun.security.rsa.RSAPadding; 52 53 /** 54 * Signature implementation class. This class currently supports the 55 * following algorithms: 56 * 57 * . RSA: 58 * . MD5withRSA 59 * . SHA1withRSA 60 * . SHA256withRSA 61 * . SHA384withRSA 62 * . SHA512withRSA 63 * 64 * @since 1.9 65 */ 66 class NativeRSASignature extends SignatureSpi { 67 68 private static final int PKCS1PADDING_LEN = 11; 69 70 // fields set in constructor 71 private final UcryptoMech mech; 72 private final int encodedLen; 73 74 // field for ensuring native memory is freed 75 private SignatureContextRef pCtxt = null; 76 77 // 78 // fields (re)set in every init() 79 // 80 private boolean initialized = false; 81 private boolean sign = true; 82 private int sigLength; 83 private NativeKey key; 84 private NativeRSAKeyFactory keyFactory; // may need a more generic type later 85 86 // public implementation classes 87 public static final class MD5 extends NativeRSASignature { 88 public MD5() throws NoSuchAlgorithmException { 89 super(UcryptoMech.CRYPTO_MD5_RSA_PKCS, 34); 90 } 91 } 92 93 public static final class SHA1 extends NativeRSASignature { 94 public SHA1() throws NoSuchAlgorithmException { 95 super(UcryptoMech.CRYPTO_SHA1_RSA_PKCS, 35); 96 } 97 } 98 99 public static final class SHA256 extends NativeRSASignature { 100 public SHA256() throws NoSuchAlgorithmException { 101 super(UcryptoMech.CRYPTO_SHA256_RSA_PKCS, 51); 102 } 103 } 104 105 public static final class SHA384 extends NativeRSASignature { 106 public SHA384() throws NoSuchAlgorithmException { 107 super(UcryptoMech.CRYPTO_SHA384_RSA_PKCS, 67); 108 } 109 } 110 111 public static final class SHA512 extends NativeRSASignature { 112 public SHA512() throws NoSuchAlgorithmException { 113 super(UcryptoMech.CRYPTO_SHA512_RSA_PKCS, 83); 114 } 115 } 116 117 // internal class for native resource cleanup 118 private static class SignatureContextRef extends PhantomReference<NativeRSASignature> 119 implements Comparable<SignatureContextRef> { 120 121 private static ReferenceQueue<NativeRSASignature> refQueue = 122 new ReferenceQueue<NativeRSASignature>(); 123 124 // Needed to keep these references from being GC'ed until when their 125 // referents are GC'ed so we can do post-mortem processing 126 private static Set<SignatureContextRef> refList = 127 new ConcurrentSkipListSet<SignatureContextRef>(); 128 // Collections.synchronizedSortedSet(new TreeSet<SignatureContextRef>()); 129 130 private final long id; 131 private final boolean sign; 132 133 private static void drainRefQueueBounded() { 134 while (true) { 135 SignatureContextRef next = (SignatureContextRef) refQueue.poll(); 136 if (next == null) break; 137 next.dispose(true); 138 } 139 } 140 141 SignatureContextRef(NativeRSASignature ns, long id, boolean sign) { 142 super(ns, refQueue); 143 this.id = id; 144 this.sign = sign; 145 refList.add(this); 146 UcryptoProvider.debug("Resource: track Signature Ctxt " + this.id); 147 drainRefQueueBounded(); 148 } 149 150 public int compareTo(SignatureContextRef other) { 151 if (this.id == other.id) { 152 return 0; 153 } else { 154 return (this.id < other.id) ? -1 : 1; 155 } 156 } 157 158 void dispose(boolean doCancel) { 159 refList.remove(this); 160 try { 161 if (doCancel) { 162 UcryptoProvider.debug("Resource: free Signature Ctxt " + this.id); 163 NativeRSASignature.nativeFinal(id, sign, null, 0, 0); 164 } else { 165 UcryptoProvider.debug("Resource: stop tracking Signature Ctxt " + this.id); 166 } 167 } finally { 168 this.clear(); 169 } 170 } 171 } 172 173 NativeRSASignature(UcryptoMech mech, int encodedLen) 174 throws NoSuchAlgorithmException { 175 this.mech = mech; 176 this.encodedLen = encodedLen; 177 this.keyFactory = new NativeRSAKeyFactory(); 178 } 179 180 // deprecated but abstract 181 @SuppressWarnings("deprecation") 182 protected Object engineGetParameter(String param) throws InvalidParameterException { 183 throw new UnsupportedOperationException("getParameter() not supported"); 184 } 185 186 @Override 187 protected synchronized void engineInitSign(PrivateKey privateKey) 188 throws InvalidKeyException { 189 if (privateKey == null) { 190 throw new InvalidKeyException("Key must not be null"); 191 } 192 NativeKey newKey = key; 193 int newSigLength = sigLength; 194 // Need to check RSA key length whenever a new private key is set 195 if (privateKey != key) { 196 if (privateKey instanceof RSAPrivateCrtKey) { 197 RSAPrivateCrtKey rsaPrivKey = (RSAPrivateCrtKey) privateKey; 198 BigInteger mod = rsaPrivKey.getModulus(); 199 newSigLength = checkRSAKeyLength(mod); 200 try { 201 newKey = (NativeKey) keyFactory.engineGeneratePrivate 202 (new RSAPrivateCrtKeySpec(mod, 203 rsaPrivKey.getPublicExponent(), 204 rsaPrivKey.getPrivateExponent(), 205 rsaPrivKey.getPrimeP(), 206 rsaPrivKey.getPrimeQ(), 207 rsaPrivKey.getPrimeExponentP(), 208 rsaPrivKey.getPrimeExponentQ(), 209 rsaPrivKey.getCrtCoefficient())); 210 } catch (InvalidKeySpecException ikse) { 211 throw new InvalidKeyException(ikse); 212 } 213 } else { 214 throw new InvalidKeyException("RSAPrivateCrtKey required"); 215 } 216 } 217 init(true, newKey, newSigLength); 218 } 219 220 221 @Override 222 protected synchronized void engineInitVerify(PublicKey publicKey) 223 throws InvalidKeyException { 224 if (publicKey == null) { 225 throw new InvalidKeyException("Key must not be null"); 226 } 227 NativeKey newKey = key; 228 int newSigLength = sigLength; 229 // Need to check RSA key length whenever a new public key is set 230 if (publicKey != key) { 231 if (publicKey instanceof RSAPublicKey) { 232 BigInteger mod = ((RSAPublicKey) publicKey).getModulus(); 233 newSigLength = checkRSAKeyLength(mod); 234 try { 235 newKey = (NativeKey) keyFactory.engineGeneratePublic 236 (new RSAPublicKeySpec(mod, ((RSAPublicKey) publicKey).getPublicExponent())); 237 } catch (InvalidKeySpecException ikse) { 238 throw new InvalidKeyException(ikse); 239 } 240 } else { 241 throw new InvalidKeyException("RSAPublicKey required"); 242 } 243 } 244 init(false, newKey, newSigLength); 245 } 246 247 // deprecated but abstract 248 @SuppressWarnings("deprecation") 249 protected void engineSetParameter(String param, Object value) throws InvalidParameterException { 250 throw new UnsupportedOperationException("setParameter() not supported"); 251 } 252 253 @Override 254 protected synchronized byte[] engineSign() throws SignatureException { 255 byte[] sig = new byte[sigLength]; 256 int rv = doFinal(sig, 0, sigLength); 257 if (rv < 0) { 258 throw new SignatureException(new UcryptoException(-rv)); 259 } 260 return sig; 261 } 262 263 @Override 264 protected synchronized int engineSign(byte[] outbuf, int offset, int len) 265 throws SignatureException { 266 if (outbuf == null || (offset < 0) || (outbuf.length < (offset + sigLength)) 267 || (len < sigLength)) { 268 throw new SignatureException("Invalid output buffer"); 269 } 270 int rv = doFinal(outbuf, offset, sigLength); 271 if (rv < 0) { 272 throw new SignatureException(new UcryptoException(-rv)); 273 } 274 return sigLength; 275 } 276 277 @Override 278 protected synchronized void engineUpdate(byte b) throws SignatureException { 279 byte[] in = { b }; 280 int rv = update(in, 0, 1); 281 if (rv < 0) { 282 throw new SignatureException(new UcryptoException(-rv)); 283 } 284 } 285 286 @Override 287 protected synchronized void engineUpdate(byte[] in, int inOfs, int inLen) 288 throws SignatureException { 289 if (in == null || inOfs < 0 || inLen == 0) return; 290 291 int rv = update(in, inOfs, inLen); 292 if (rv < 0) { 293 throw new SignatureException(new UcryptoException(-rv)); 294 } 295 } 296 297 @Override 298 protected synchronized void engineUpdate(ByteBuffer in) { 299 if (in == null || in.remaining() == 0) return; 300 301 if (in instanceof DirectBuffer == false) { 302 // cannot do better than default impl 303 super.engineUpdate(in); 304 return; 305 } 306 long inAddr = ((DirectBuffer)in).address(); 307 int inOfs = in.position(); 308 int inLen = in.remaining(); 309 310 int rv = update((inAddr + inOfs), inLen); 311 if (rv < 0) { 312 throw new UcryptoException(-rv); 313 } 314 in.position(inOfs + inLen); 315 } 316 317 @Override 318 protected synchronized boolean engineVerify(byte[] sigBytes) throws SignatureException { 319 return engineVerify(sigBytes, 0, sigBytes.length); 320 } 321 322 @Override 323 protected synchronized boolean engineVerify(byte[] sigBytes, int sigOfs, int sigLen) 324 throws SignatureException { 325 if (sigBytes == null || (sigOfs < 0) || (sigBytes.length < (sigOfs + this.sigLength)) 326 || (sigLen < this.sigLength)) { 327 throw new SignatureException("Invalid signature buffer"); 328 } 329 330 int rv = doFinal(sigBytes, sigOfs, sigLen); 331 if (rv == 0) { 332 return true; 333 } else { 334 UcryptoProvider.debug("Signature: " + mech + " verification error " + 335 new UcryptoException(-rv).getMessage()); 336 return false; 337 } 338 } 339 340 void reset(boolean doCancel) { 341 initialized = false; 342 if (pCtxt != null) { 343 pCtxt.dispose(doCancel); 344 pCtxt = null; 345 } 346 } 347 348 /** 349 * calls ucrypto_sign_init(...) or ucrypto_verify_init(...) 350 * @return pointer to the context 351 */ 352 private native static long nativeInit(int mech, boolean sign, 353 long keyValue, int keyLength); 354 355 /** 356 * calls ucrypto_sign_update(...) or ucrypto_verify_update(...) 357 * @returns an error status code (0 means SUCCESS) 358 */ 359 private native static int nativeUpdate(long pContext, boolean sign, 360 byte[] in, int inOfs, int inLen); 361 /** 362 * calls ucrypto_sign_update(...) or ucrypto_verify_update(...) 363 * @returns an error status code (0 means SUCCESS) 364 */ 365 private native static int nativeUpdate(long pContext, boolean sign, 366 long pIn, int inLen); 367 368 /** 369 * calls ucrypto_sign_final(...) or ucrypto_verify_final(...) 370 * @returns the length of signature bytes or verification status. 371 * If negative, it indicates an error status code 372 */ 373 private native static int nativeFinal(long pContext, boolean sign, 374 byte[] sig, int sigOfs, int sigLen); 375 376 // actual init() implementation - caller should clone key if needed 377 private void init(boolean sign, NativeKey key, int sigLength) { 378 reset(true); 379 this.sign = sign; 380 this.sigLength = sigLength; 381 this.key = key; 382 long pCtxtVal = nativeInit(mech.value(), sign, key.value(), 383 key.length()); 384 initialized = (pCtxtVal != 0L); 385 if (initialized) { 386 pCtxt = new SignatureContextRef(this, pCtxtVal, sign); 387 } else { 388 throw new UcryptoException("Cannot initialize Signature"); 389 } 390 } 391 392 private void ensureInitialized() { 393 if (!initialized) { 394 init(sign, key, sigLength); 395 if (!initialized) { 396 throw new UcryptoException("Cannot initialize Signature"); 397 } 398 } 399 } 400 401 // returns 0 (success) or negative (ucrypto error occurred) 402 private int update(byte[] in, int inOfs, int inLen) { 403 if (inOfs < 0 || inOfs + inLen > in.length) { 404 throw new ArrayIndexOutOfBoundsException(); 405 } 406 ensureInitialized(); 407 int k = nativeUpdate(pCtxt.id, sign, in, inOfs, inLen); 408 if (k < 0) { 409 reset(false); 410 } 411 return k; 412 } 413 414 // returns 0 (success) or negative (ucrypto error occurred) 415 private int update(long pIn, int inLen) { 416 ensureInitialized(); 417 int k = nativeUpdate(pCtxt.id, sign, pIn, inLen); 418 if (k < 0) { 419 reset(false); 420 } 421 return k; 422 } 423 424 // returns 0 (success) or negative (ucrypto error occurred) 425 private int doFinal(byte[] sigBytes, int sigOfs, int sigLen) { 426 try { 427 ensureInitialized(); 428 int k = nativeFinal(pCtxt.id, sign, sigBytes, sigOfs, sigLen); 429 return k; 430 } finally { 431 reset(false); 432 } 433 } 434 435 // check and return RSA key size in number of bytes 436 private int checkRSAKeyLength(BigInteger mod) throws InvalidKeyException { 437 int keySize = (mod.bitLength() + 7) >> 3; 438 int maxDataSize = keySize - PKCS1PADDING_LEN; 439 if (maxDataSize < encodedLen) { 440 throw new InvalidKeyException 441 ("Key is too short for this signature algorithm"); 442 } 443 return keySize; 444 } 445 }