/**
   * Creates a test signature and verifies it.
   *
   * @param privateKey Private key to sign with
   * @param publicKey Public key to verify with
   * @param signatureProvider Name of provider to sign with
   * @throws NoSuchAlgorithmException In case the key or signature algorithm is unknown
   * @throws NoSuchProviderException In case the supplied provider name is unknown or BC is not
   *     installed
   * @throws InvalidKeyException If signature verification failed or the key was invalid
   * @throws SignatureException If the signature could not be made or verified correctly
   */
  public static void testSignAndVerify(
      PrivateKey privateKey, PublicKey publicKey, String signatureProvider)
      throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException,
          SignatureException {
    final byte input[] = "Lillan gick pa vagen ut, motte dar en katt...".getBytes();
    final String sigAlg = suggestSigAlg(publicKey);
    if (sigAlg == null) {
      throw new NoSuchAlgorithmException("Unknown key algorithm: " + publicKey.getAlgorithm());
    }
    if (LOG.isDebugEnabled()) {
      LOG.debug("Testing keys with algorithm: " + publicKey.getAlgorithm());
      LOG.debug("testSigAlg: " + sigAlg);
      LOG.debug("provider: " + signatureProvider);
      LOG.trace("privateKey: " + privateKey);
      LOG.trace("privateKey class: " + privateKey.getClass().getName());
      LOG.trace("publicKey: " + publicKey);
      LOG.trace("publicKey class: " + publicKey.getClass().getName());
    }
    final Signature signSignature = Signature.getInstance(sigAlg, signatureProvider);
    signSignature.initSign(privateKey);
    signSignature.update(input);
    byte[] signBA = signSignature.sign();
    if (LOG.isTraceEnabled()) {
      LOG.trace("Created signature of size: " + signBA.length);
      LOG.trace("Created signature: " + new String(Hex.encode(signBA)));
    }

    final Signature verifySignature = Signature.getInstance(sigAlg, "BC");
    verifySignature.initVerify(publicKey);
    verifySignature.update(input);
    if (!verifySignature.verify(signBA)) {
      throw new InvalidKeyException("Test signature inconsistent");
    }
  }
Beispiel #2
0
  private static Object getOpenSSLKeyForPrivateKey(PrivateKey privateKey) {
    // Sanity checks
    if (privateKey == null) {
      Log.e(TAG, "privateKey == null");
      return null;
    }
    if (!(privateKey instanceof RSAPrivateKey)) {
      Log.e(TAG, "does not implement RSAPrivateKey");
      return null;
    }
    // First, check that this is a proper instance of OpenSSLRSAPrivateKey
    // or one of its sub-classes.
    Class<?> superClass;
    try {
      superClass = Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey");
    } catch (Exception e) {
      // This may happen if the target device has a completely different
      // implementation of the java.security APIs, compared to vanilla
      // Android. Highly unlikely, but still possible.
      Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e);
      return null;
    }
    if (!superClass.isInstance(privateKey)) {
      // This may happen if the PrivateKey was not created by the "AndroidOpenSSL"
      // provider, which should be the default. That could happen if an OEM decided
      // to implement a different default provider. Also highly unlikely.
      Log.e(
          TAG,
          "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:"
              + privateKey.getClass().getCanonicalName());
      return null;
    }

    try {
      // Use reflection to invoke the 'getOpenSSLKey()' method on the
      // private key. This returns another Java object that wraps a native
      // EVP_PKEY and OpenSSLEngine. Note that the method is final in Android
      // 4.1, so calling the superclass implementation is ok.
      Method getKey = superClass.getDeclaredMethod("getOpenSSLKey");
      getKey.setAccessible(true);
      Object opensslKey = null;
      try {
        opensslKey = getKey.invoke(privateKey);
      } finally {
        getKey.setAccessible(false);
      }
      if (opensslKey == null) {
        // Bail when detecting OEM "enhancement".
        Log.e(TAG, "getOpenSSLKey() returned null");
        return null;
      }
      return opensslKey;
    } catch (Exception e) {
      Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handle: " + e);
      return null;
    }
  }
  /**
   * Return the system EVP_PKEY handle corresponding to a given PrivateKey object, obtained through
   * reflection.
   *
   * <p>This shall only be used when the "NONEwithRSA" signature is not available, as described in
   * rawSignDigestWithPrivateKey(). I.e. never use this on Android 4.2 or higher.
   *
   * <p>This can only work in Android 4.0.4 and higher, for older versions of the platform (e.g.
   * 4.0.3), there is no system OpenSSL EVP_PKEY, but the private key contents can be retrieved
   * directly with the getEncoded() method.
   *
   * <p>This assumes that the target device uses a vanilla AOSP implementation of its java.security
   * classes, which is also based on OpenSSL (fortunately, no OEM has apperently changed to a
   * different implementation, according to the Android team).
   *
   * <p>Note that the object returned was created with the platform version of OpenSSL, and _not_
   * the one that comes with Chromium. Whether the object can be used safely with the Chromium
   * OpenSSL library depends on differences between their actual ABI / implementation details.
   *
   * <p>To better understand what's going on below, please refer to the following source files in
   * the Android 4.0.4 and 4.1 source trees:
   * libcore/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
   * libcore/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
   *
   * @param privateKey The PrivateKey handle.
   * @return The EVP_PKEY handle, as a 32-bit integer (0 if not available)
   */
  @CalledByNative
  public static int getOpenSSLHandleForPrivateKey(PrivateKey privateKey) {
    // Sanity checks
    if (privateKey == null) {
      Log.e(TAG, "privateKey == null");
      return 0;
    }
    if (!(privateKey instanceof RSAPrivateKey)) {
      Log.e(TAG, "does not implement RSAPrivateKey");
      return 0;
    }
    // First, check that this is a proper instance of OpenSSLRSAPrivateKey
    // or one of its sub-classes.
    Class<?> superClass;
    try {
      superClass = Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey");
    } catch (Exception e) {
      // This may happen if the target device has a completely different
      // implementation of the java.security APIs, compared to vanilla
      // Android. Highly unlikely, but still possible.
      Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e);
      return 0;
    }
    if (!superClass.isInstance(privateKey)) {
      // This may happen if the PrivateKey was not created by the "AndroidOpenSSL"
      // provider, which should be the default. That could happen if an OEM decided
      // to implement a different default provider. Also highly unlikely.
      Log.e(
          TAG,
          "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:"
              + privateKey.getClass().getCanonicalName());
      return 0;
    }

    try {
      // Use reflection to invoke the 'getOpenSSLKey()' method on
      // the private key. This returns another Java object that wraps
      // a native EVP_PKEY. Note that the method is final, so calling
      // the superclass implementation is ok.
      Method getKey = superClass.getDeclaredMethod("getOpenSSLKey");
      getKey.setAccessible(true);
      Object opensslKey = null;
      try {
        opensslKey = getKey.invoke(privateKey);
      } finally {
        getKey.setAccessible(false);
      }
      if (opensslKey == null) {
        // Bail when detecting OEM "enhancement".
        Log.e(TAG, "getOpenSSLKey() returned null");
        return 0;
      }

      // Use reflection to invoke the 'getPkeyContext' method on the
      // result of the getOpenSSLKey(). This is an 32-bit integer
      // which is the address of an EVP_PKEY object.
      Method getPkeyContext;
      try {
        getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPkeyContext");
      } catch (Exception e) {
        // Bail here too, something really not working as expected.
        Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e);
        return 0;
      }
      getPkeyContext.setAccessible(true);
      int evp_pkey = 0;
      try {
        evp_pkey = (Integer) getPkeyContext.invoke(opensslKey);
      } finally {
        getPkeyContext.setAccessible(false);
      }
      if (evp_pkey == 0) {
        // The PrivateKey is probably rotten for some reason.
        Log.e(TAG, "getPkeyContext() returned null");
      }
      return evp_pkey;

    } catch (Exception e) {
      Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handle: " + e);
      return 0;
    }
  }