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 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 1.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 @SuppressWarnings("deprecation") 180 protected Object engineGetParameter(String param) throws InvalidParameterException { 181 throw new UnsupportedOperationException("getParameter() not supported"); 182 } 183 184 @Override 185 protected synchronized void engineInitSign(PrivateKey privateKey) 186 throws InvalidKeyException { 187 if (privateKey == null) { 188 throw new InvalidKeyException("Key must not be null"); 189 } 190 NativeKey newKey = key; 191 int newSigLength = sigLength; 192 // Need to check RSA key length whenever a new private key is set 193 if (privateKey != key) { 194 if (!(privateKey instanceof RSAPrivateKey)) { 195 throw new InvalidKeyException("RSAPrivateKey required. " + 196 "Received: " + privateKey.getClass().getName()); 197 } 198 RSAPrivateKey rsaPrivKey = (RSAPrivateKey) privateKey; 199 BigInteger mod = rsaPrivKey.getModulus(); 200 newSigLength = checkRSAKeyLength(mod); 201 BigInteger pe = rsaPrivKey.getPrivateExponent(); 202 try { 203 if (rsaPrivKey instanceof RSAPrivateCrtKey) { 204 RSAPrivateCrtKey rsaPrivCrtKey = (RSAPrivateCrtKey) rsaPrivKey; 205 newKey = (NativeKey) keyFactory.engineGeneratePrivate 206 (new RSAPrivateCrtKeySpec(mod, 207 rsaPrivCrtKey.getPublicExponent(), 208 pe, 209 rsaPrivCrtKey.getPrimeP(), 210 rsaPrivCrtKey.getPrimeQ(), 211 rsaPrivCrtKey.getPrimeExponentP(), 212 rsaPrivCrtKey.getPrimeExponentQ(), 213 rsaPrivCrtKey.getCrtCoefficient())); 214 } else { 215 newKey = (NativeKey) keyFactory.engineGeneratePrivate 216 (new RSAPrivateKeySpec(mod, pe)); 217 } 218 } catch (InvalidKeySpecException ikse) { 219 throw new InvalidKeyException(ikse); 220 } 221 } 222 init(true, newKey, newSigLength); 223 } 224 225 226 @Override 227 protected synchronized void engineInitVerify(PublicKey publicKey) 228 throws InvalidKeyException { 229 if (publicKey == null) { 230 throw new InvalidKeyException("Key must not be null"); 231 } 232 NativeKey newKey = key; 233 int newSigLength = sigLength; 234 // Need to check RSA key length whenever a new public key is set 235 if (publicKey != key) { 236 if (publicKey instanceof RSAPublicKey) { 237 BigInteger mod = ((RSAPublicKey) publicKey).getModulus(); 238 newSigLength = checkRSAKeyLength(mod); 239 try { 240 newKey = (NativeKey) keyFactory.engineGeneratePublic 241 (new RSAPublicKeySpec(mod, ((RSAPublicKey) publicKey).getPublicExponent())); 242 } catch (InvalidKeySpecException ikse) { 243 throw new InvalidKeyException(ikse); 244 } 245 } else { 246 throw new InvalidKeyException("RSAPublicKey required. " + 247 "Received: " + publicKey.getClass().getName()); 248 } 249 } 250 init(false, newKey, newSigLength); 251 } 252 253 // deprecated but abstract 254 @SuppressWarnings("deprecation") 255 protected void engineSetParameter(String param, Object value) throws InvalidParameterException { 256 throw new UnsupportedOperationException("setParameter() not supported"); 257 } 258 259 @Override 260 protected synchronized byte[] engineSign() throws SignatureException { 261 byte[] sig = new byte[sigLength]; 262 int rv = doFinal(sig, 0, sigLength); 263 if (rv < 0) { 264 throw new SignatureException(new UcryptoException(-rv)); 265 } 266 return sig; 267 } 268 269 @Override 270 protected synchronized int engineSign(byte[] outbuf, int offset, int len) 271 throws SignatureException { 272 if (outbuf == null || (offset < 0) || (outbuf.length < (offset + sigLength)) 273 || (len < sigLength)) { 274 throw new SignatureException("Invalid output buffer. offset: " + 275 offset + ". len: " + len + ". sigLength: " + sigLength); 276 } 277 int rv = doFinal(outbuf, offset, sigLength); 278 if (rv < 0) { 279 throw new SignatureException(new UcryptoException(-rv)); 280 } 281 return sigLength; 282 } 283 284 @Override 285 protected synchronized void engineUpdate(byte b) throws SignatureException { 286 byte[] in = { b }; 287 int rv = update(in, 0, 1); 288 if (rv < 0) { 289 throw new SignatureException(new UcryptoException(-rv)); 290 } 291 } 292 293 @Override 294 protected synchronized void engineUpdate(byte[] in, int inOfs, int inLen) 295 throws SignatureException { 296 if (in == null || inOfs < 0 || inLen == 0) return; 297 298 int rv = update(in, inOfs, inLen); 299 if (rv < 0) { 300 throw new SignatureException(new UcryptoException(-rv)); 301 } 302 } 303 304 @Override 305 protected synchronized void engineUpdate(ByteBuffer in) { 306 if (in == null || in.remaining() == 0) return; 307 308 if (in instanceof DirectBuffer == false) { 309 // cannot do better than default impl 310 super.engineUpdate(in); 311 return; 312 } 313 long inAddr = ((DirectBuffer)in).address(); 314 int inOfs = in.position(); 315 int inLen = in.remaining(); 316 317 int rv = update((inAddr + inOfs), inLen); 318 if (rv < 0) { 319 throw new UcryptoException(-rv); 320 } 321 in.position(inOfs + inLen); 322 } 323 324 @Override 325 protected synchronized boolean engineVerify(byte[] sigBytes) throws SignatureException { 326 return engineVerify(sigBytes, 0, sigBytes.length); 327 } 328 329 @Override 330 protected synchronized boolean engineVerify(byte[] sigBytes, int sigOfs, int sigLen) 331 throws SignatureException { 332 if (sigBytes == null || (sigOfs < 0) || (sigBytes.length < (sigOfs + this.sigLength)) 333 || (sigLen < this.sigLength)) { 334 throw new SignatureException("Invalid signature buffer. sigOfs: " + 335 sigOfs + ". sigLen: " + sigLen + ". this.sigLength: " + this.sigLength); 336 } 337 338 int rv = doFinal(sigBytes, sigOfs, sigLen); 339 if (rv == 0) { 340 return true; 341 } else { 342 UcryptoProvider.debug("Signature: " + mech + " verification error " + 343 new UcryptoException(-rv).getMessage()); 344 return false; 345 } 346 } 347 348 void reset(boolean doCancel) { 349 initialized = false; 350 if (pCtxt != null) { 351 pCtxt.dispose(doCancel); 352 pCtxt = null; 353 } 354 } 355 356 /** 357 * calls ucrypto_sign_init(...) or ucrypto_verify_init(...) 358 * @return pointer to the context 359 */ 360 private native static long nativeInit(int mech, boolean sign, 361 long keyValue, int keyLength); 362 363 /** 364 * calls ucrypto_sign_update(...) or ucrypto_verify_update(...) 365 * @return an error status code (0 means SUCCESS) 366 */ 367 private native static int nativeUpdate(long pContext, boolean sign, 368 byte[] in, int inOfs, int inLen); 369 /** 370 * calls ucrypto_sign_update(...) or ucrypto_verify_update(...) 371 * @return an error status code (0 means SUCCESS) 372 */ 373 private native static int nativeUpdate(long pContext, boolean sign, 374 long pIn, int inLen); 375 376 /** 377 * calls ucrypto_sign_final(...) or ucrypto_verify_final(...) 378 * @return the length of signature bytes or verification status. 379 * If negative, it indicates an error status code 380 */ 381 private native static int nativeFinal(long pContext, boolean sign, 382 byte[] sig, int sigOfs, int sigLen); 383 384 // actual init() implementation - caller should clone key if needed 385 private void init(boolean sign, NativeKey key, int sigLength) { 386 reset(true); 387 this.sign = sign; 388 this.sigLength = sigLength; 389 this.key = key; 390 long pCtxtVal = nativeInit(mech.value(), sign, key.value(), 391 key.length()); 392 initialized = (pCtxtVal != 0L); 393 if (initialized) { 394 pCtxt = new SignatureContextRef(this, pCtxtVal, sign); 395 } else { 396 throw new UcryptoException("Cannot initialize Signature"); 397 } 398 } 399 400 private void ensureInitialized() { 401 if (!initialized) { 402 init(sign, key, sigLength); 403 if (!initialized) { 404 throw new UcryptoException("Cannot initialize Signature"); 405 } 406 } 407 } 408 409 // returns 0 (success) or negative (ucrypto error occurred) 410 private int update(byte[] in, int inOfs, int inLen) { 411 if (inOfs < 0 || inOfs + inLen > in.length) { 412 throw new ArrayIndexOutOfBoundsException("inOfs :" + inOfs + 413 ". inLen: " + inLen + ". in.length: " + in.length); 414 } 415 ensureInitialized(); 416 int k = nativeUpdate(pCtxt.id, sign, in, inOfs, inLen); 417 if (k < 0) { 418 reset(false); 419 } 420 return k; 421 } 422 423 // returns 0 (success) or negative (ucrypto error occurred) 424 private int update(long pIn, int inLen) { 425 ensureInitialized(); 426 int k = nativeUpdate(pCtxt.id, sign, pIn, inLen); 427 if (k < 0) { 428 reset(false); 429 } 430 return k; 431 } 432 433 // returns 0 (success) or negative (ucrypto error occurred) 434 private int doFinal(byte[] sigBytes, int sigOfs, int sigLen) { 435 try { 436 ensureInitialized(); 437 int k = nativeFinal(pCtxt.id, sign, sigBytes, sigOfs, sigLen); 438 return k; 439 } finally { 440 reset(false); 441 } 442 } 443 444 // check and return RSA key size in number of bytes 445 private int checkRSAKeyLength(BigInteger mod) throws InvalidKeyException { 446 int keySize = (mod.bitLength() + 7) >> 3; 447 int maxDataSize = keySize - PKCS1PADDING_LEN; 448 if (maxDataSize < encodedLen) { 449 throw new InvalidKeyException 450 ("Key is too short for this signature algorithm. maxDataSize: " + 451 maxDataSize + ". encodedLen: " + encodedLen); 452 } 453 return keySize; 454 } 455 }