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