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