Home » Newcomers » Newcomers » Combined Java and C++ code compilation
Combined Java and C++ code compilation [message #1768272] |
Sun, 16 July 2017 13:39 |
Inessa Aksenova Messages: 1 Registered: July 2017 |
Junior Member |
|
|
I need to compile Combined Java and C++ code.
Can you tell me how can build them all together in my Eclipse project?
Here is Java and C++ code.
NativeCrypto.java
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.harmony.xnet.provider.jsse;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLException;
import javax.security.auth.x500.X500Principal;
import libcore.io.Memory;
/**
* Provides the Java side of our JNI glue for OpenSSL.
*/
public final class NativeCrypto {
// --- OpenSSL library initialization --------------------------------------
static {
clinit();
}
private native static void clinit();
// --- DSA/RSA public/private key handling functions -----------------------
public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g,
byte[] priv_key, byte[] pub_key);
public static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q);
public static native void EVP_PKEY_free(int pkey);
// --- Message digest functions --------------
public static native int EVP_get_digestbyname(String name);
public static native int EVP_MD_size(int evp_md);
public static native int EVP_MD_block_size(int evp_md);
// --- Message digest context functions --------------
public static native void EVP_MD_CTX_destroy(int ctx);
public static native int EVP_MD_CTX_copy(int ctx);
// --- Digest handling functions -------------------------------------------
public static native int EVP_DigestInit(int evp_md);
public static native void EVP_DigestUpdate(int ctx, byte[] buffer, int offset, int length);
public static native int EVP_DigestFinal(int ctx, byte[] hash, int offset);
// --- Signature handling functions ----------------------------------------
public static native int EVP_VerifyInit(String algorithm);
public static native void EVP_VerifyUpdate(int ctx, byte[] buffer,
int offset, int length);
public static native int EVP_VerifyFinal(int ctx, byte[] signature,
int offset, int length, int key);
// --- RAND seeding --------------------------------------------------------
public static final int RAND_SEED_LENGTH_IN_BYTES = 1024;
public static native void RAND_seed(byte[] seed);
public static native int RAND_load_file(String filename, long max_bytes);
// --- X509_NAME -----------------------------------------------------------
public static int X509_NAME_hash(X500Principal principal) {
return X509_NAME_hash(principal, "SHA1");
}
public static int X509_NAME_hash_old(X500Principal principal) {
return X509_NAME_hash(principal, "MD5");
}
private static int X509_NAME_hash(X500Principal principal, String algorithm) {
try {
byte[] digest = MessageDigest.getInstance(algorithm).digest(principal.getEncoded());
return Memory.peekInt(digest, 0, ByteOrder.LITTLE_ENDIAN);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
// --- SSL handling --------------------------------------------------------
private static final String SUPPORTED_PROTOCOL_SSLV3 = "SSLv3";
private static final String SUPPORTED_PROTOCOL_TLSV1 = "TLSv1";
public static final Map<String, String> OPENSSL_TO_STANDARD_CIPHER_SUITES
= new HashMap<String, String>();
public static final Map<String, String> STANDARD_TO_OPENSSL_CIPHER_SUITES
= new LinkedHashMap<String, String>();
private static void add(String standard, String openssl) {
OPENSSL_TO_STANDARD_CIPHER_SUITES.put(openssl, standard);
STANDARD_TO_OPENSSL_CIPHER_SUITES.put(standard, openssl);
}
/**
* TLS_EMPTY_RENEGOTIATION_INFO_SCSV is RFC 5746's renegotiation
* indication signaling cipher suite value. It is not a real
* cipher suite. It is just an indication in the default and
* supported cipher suite lists indicates that the implementation
* supports secure renegotiation.
*
* In the RI, its presence means that the SCSV is sent in the
* cipher suite list to indicate secure renegotiation support and
* its absense means to send an empty TLS renegotiation info
* extension instead.
*
* However, OpenSSL doesn't provide an API to give this level of
* control, instead always sending the SCSV and always including
* the empty renegotiation info if TLS is used (as opposed to
* SSL). So we simply allow TLS_EMPTY_RENEGOTIATION_INFO_SCSV to
* be passed for compatibility as to provide the hint that we
* support secure renegotiation.
*/
public static final String TLS_EMPTY_RENEGOTIATION_INFO_SCSV
= "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
static {
// Note these are added in priority order
add("SSL_RSA_WITH_RC4_128_MD5", "RC4-MD5");
add("SSL_RSA_WITH_RC4_128_SHA", "RC4-SHA");
add("TLS_RSA_WITH_AES_128_CBC_SHA", "AES128-SHA");
add("TLS_RSA_WITH_AES_256_CBC_SHA", "AES256-SHA");
add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "ECDH-ECDSA-RC4-SHA");
add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "ECDH-ECDSA-AES128-SHA");
add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "ECDH-ECDSA-AES256-SHA");
add("TLS_ECDH_RSA_WITH_RC4_128_SHA", "ECDH-RSA-RC4-SHA");
add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "ECDH-RSA-AES128-SHA");
add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "ECDH-RSA-AES256-SHA");
add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "ECDHE-ECDSA-RC4-SHA");
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDHE-ECDSA-AES128-SHA");
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDHE-ECDSA-AES256-SHA");
add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", "ECDHE-RSA-RC4-SHA");
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "ECDHE-RSA-AES128-SHA");
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "ECDHE-RSA-AES256-SHA");
add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DHE-RSA-AES128-SHA");
add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DHE-RSA-AES256-SHA");
add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DHE-DSS-AES128-SHA");
add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DHE-DSS-AES256-SHA");
add("SSL_RSA_WITH_3DES_EDE_CBC_SHA", "DES-CBC3-SHA");
add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDH-ECDSA-DES-CBC3-SHA");
add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "ECDH-RSA-DES-CBC3-SHA");
add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-ECDSA-DES-CBC3-SHA");
add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-RSA-DES-CBC3-SHA");
add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "EDH-RSA-DES-CBC3-SHA");
add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "EDH-DSS-DES-CBC3-SHA");
add("SSL_RSA_WITH_DES_CBC_SHA", "DES-CBC-SHA");
add("SSL_DHE_RSA_WITH_DES_CBC_SHA", "EDH-RSA-DES-CBC-SHA");
add("SSL_DHE_DSS_WITH_DES_CBC_SHA", "EDH-DSS-DES-CBC-SHA");
add("SSL_RSA_EXPORT_WITH_RC4_40_MD5", "EXP-RC4-MD5");
add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "EXP-DES-CBC-SHA");
add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "EXP-EDH-RSA-DES-CBC-SHA");
add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "EXP-EDH-DSS-DES-CBC-SHA");
add("SSL_RSA_WITH_NULL_MD5", "NULL-MD5");
add("SSL_RSA_WITH_NULL_SHA", "NULL-SHA");
add("TLS_ECDH_ECDSA_WITH_NULL_SHA", "ECDH-ECDSA-NULL-SHA");
add("TLS_ECDH_RSA_WITH_NULL_SHA", "ECDH-RSA-NULL-SHA");
add("TLS_ECDHE_ECDSA_WITH_NULL_SHA", "ECDHE-ECDSA-NULL-SHA");
add("TLS_ECDHE_RSA_WITH_NULL_SHA", "ECDHE-RSA-NULL-SHA");
add("SSL_DH_anon_WITH_RC4_128_MD5", "ADH-RC4-MD5");
add("TLS_DH_anon_WITH_AES_128_CBC_SHA", "ADH-AES128-SHA");
add("TLS_DH_anon_WITH_AES_256_CBC_SHA", "ADH-AES256-SHA");
add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", "ADH-DES-CBC3-SHA");
add("SSL_DH_anon_WITH_DES_CBC_SHA", "ADH-DES-CBC-SHA");
add("TLS_ECDH_anon_WITH_RC4_128_SHA", "AECDH-RC4-SHA");
add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "AECDH-AES128-SHA");
add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "AECDH-AES256-SHA");
add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "AECDH-DES-CBC3-SHA");
add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", "EXP-ADH-RC4-MD5");
add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", "EXP-ADH-DES-CBC-SHA");
add("TLS_ECDH_anon_WITH_NULL_SHA", "AECDH-NULL-SHA");
// No Kerberos in Android
// add("TLS_KRB5_WITH_RC4_128_SHA", "KRB5-RC4-SHA");
// add("TLS_KRB5_WITH_RC4_128_MD5", "KRB5-RC4-MD5");
// add("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", "KRB5-DES-CBC3-SHA");
// add("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", "KRB5-DES-CBC3-MD5");
// add("TLS_KRB5_WITH_DES_CBC_SHA", "KRB5-DES-CBC-SHA");
// add("TLS_KRB5_WITH_DES_CBC_MD5", "KRB5-DES-CBC-MD5");
// add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", "EXP-KRB5-RC4-SHA");
// add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "EXP-KRB5-RC4-MD5");
// add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", "EXP-KRB5-DES-CBC-SHA");
// add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", "EXP-KRB5-DES-CBC-MD5");
// not implemented by either RI or OpenSSL
// add("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", null);
// add("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", null);
// EXPORT1024 suites were never standardized but were widely implemented.
// OpenSSL 0.9.8c and later have disabled TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES
// add("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA", "EXP1024-DES-CBC-SHA");
// add("SSL_RSA_EXPORT1024_WITH_RC4_56_SHA", "EXP1024-RC4-SHA");
// No RC2
// add("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-RC2-CBC-MD5");
// add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", "EXP-KRB5-RC2-CBC-SHA");
// add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-KRB5-RC2-CBC-MD5");
// PSK is Private Shared Key - didn't exist in Froyo's openssl - no JSSE equivalent
// add(null, "PSK-3DES-EDE-CBC-SHA");
// add(null, "PSK-AES128-CBC-SHA");
// add(null, "PSK-AES256-CBC-SHA");
// add(null, "PSK-RC4-SHA");
// Signaling Cipher Suite Value for secure renegotiation handled as special case.
// add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", null);
}
private static final String[] SUPPORTED_CIPHER_SUITES;
static {
int size = STANDARD_TO_OPENSSL_CIPHER_SUITES.size();
SUPPORTED_CIPHER_SUITES = new String[size + 1];
STANDARD_TO_OPENSSL_CIPHER_SUITES.keySet().toArray(SUPPORTED_CIPHER_SUITES);
SUPPORTED_CIPHER_SUITES[size] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
}
// SSL mode from ssl.h
public static final long SSL_MODE_HANDSHAKE_CUTTHROUGH = 0x00000040L;
// SSL options from ssl.h
public static final long SSL_OP_NO_TICKET = 0x00004000L;
public static final long SSL_OP_NO_COMPRESSION = 0x00020000L;
public static final long SSL_OP_NO_SSLv3 = 0x02000000L;
public static final long SSL_OP_NO_TLSv1 = 0x04000000L;
public static native int SSL_CTX_new();
public static String[] getDefaultCipherSuites() {
return new String[] {
"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_RSA_WITH_RC4_128_SHA",
"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
};
}
public static String[] getSupportedCipherSuites() {
return SUPPORTED_CIPHER_SUITES.clone();
}
public static native void SSL_CTX_free(int ssl_ctx);
public static native int SSL_new(int ssl_ctx) throws SSLException;
public static byte[][] encodeCertificates(Certificate[] certificates)
throws CertificateEncodingException {
byte[][] certificateBytes = new byte[certificates.length][];
for (int i = 0; i < certificates.length; i++) {
certificateBytes[i] = certificates[i].getEncoded();
}
return certificateBytes;
}
public static native void SSL_use_certificate(int ssl, byte[][] asn1DerEncodedCertificateChain);
public static native void SSL_use_PrivateKey(int ssl, byte[] pkcs8EncodedPrivateKey);
public static native void SSL_check_private_key(int ssl) throws SSLException;
public static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
throws CertificateEncodingException {
byte[][] principalBytes = new byte[certificates.length][];
for (int i = 0; i < certificates.length; i++) {
principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
}
return principalBytes;
}
public static native void SSL_set_client_CA_list(int ssl, byte[][] asn1DerEncodedX500Principals);
public static native long SSL_get_mode(int ssl);
public static native long SSL_set_mode(int ssl, long mode);
public static native long SSL_clear_mode(int ssl, long mode);
public static native long SSL_get_options(int ssl);
public static native long SSL_set_options(int ssl, long options);
public static native long SSL_clear_options(int ssl, long options);
public static String[] getSupportedProtocols() {
return new String[] { SUPPORTED_PROTOCOL_SSLV3, SUPPORTED_PROTOCOL_TLSV1 };
}
public static void setEnabledProtocols(int ssl, String[] protocols) {
checkEnabledProtocols(protocols);
// openssl uses negative logic letting you disable protocols.
// so first, assume we need to set all (disable all) and clear none (enable none).
// in the loop, selectively move bits from set to clear (from disable to enable)
long optionsToSet = (SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
long optionsToClear = 0;
for (int i = 0; i < protocols.length; i++) {
String protocol = protocols[i];
if (protocol.equals(SUPPORTED_PROTOCOL_SSLV3)) {
optionsToSet &= ~SSL_OP_NO_SSLv3;
optionsToClear |= SSL_OP_NO_SSLv3;
} else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1)) {
optionsToSet &= ~SSL_OP_NO_TLSv1;
optionsToClear |= SSL_OP_NO_TLSv1;
} else {
// error checked by checkEnabledProtocols
throw new IllegalStateException();
}
}
SSL_set_options(ssl, optionsToSet);
SSL_clear_options(ssl, optionsToClear);
}
public static String[] checkEnabledProtocols(String[] protocols) {
if (protocols == null) {
throw new IllegalArgumentException("protocols == null");
}
for (int i = 0; i < protocols.length; i++) {
String protocol = protocols[i];
if (protocol == null) {
throw new IllegalArgumentException("protocols[" + i + "] == null");
}
if ((!protocol.equals(SUPPORTED_PROTOCOL_SSLV3))
&& (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1))) {
throw new IllegalArgumentException("protocol " + protocol
+ " is not supported");
}
}
return protocols;
}
public static native void SSL_set_cipher_lists(int ssl, String[] ciphers);
public static void setEnabledCipherSuites(int ssl, String[] cipherSuites) {
checkEnabledCipherSuites(cipherSuites);
List<String> opensslSuites = new ArrayList<String>();
for (int i = 0; i < cipherSuites.length; i++) {
String cipherSuite = cipherSuites[i];
if (cipherSuite.equals(TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
continue;
}
String openssl = STANDARD_TO_OPENSSL_CIPHER_SUITES.get(cipherSuite);
String cs = (openssl == null) ? cipherSuite : openssl;
opensslSuites.add(cs);
}
SSL_set_cipher_lists(ssl, opensslSuites.toArray(new String[opensslSuites.size()]));
}
public static String[] checkEnabledCipherSuites(String[] cipherSuites) {
if (cipherSuites == null) {
throw new IllegalArgumentException("cipherSuites == null");
}
// makes sure all suites are valid, throwing on error
for (int i = 0; i < cipherSuites.length; i++) {
String cipherSuite = cipherSuites[i];
if (cipherSuite == null) {
throw new IllegalArgumentException("cipherSuites[" + i + "] == null");
}
if (cipherSuite.equals(TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
continue;
}
if (STANDARD_TO_OPENSSL_CIPHER_SUITES.containsKey(cipherSuite)) {
continue;
}
if (OPENSSL_TO_STANDARD_CIPHER_SUITES.containsKey(cipherSuite)) {
// TODO log warning about using backward compatability
continue;
}
throw new IllegalArgumentException("cipherSuite " + cipherSuite + " is not supported.");
}
return cipherSuites;
}
private static final String SUPPORTED_COMPRESSION_METHOD_ZLIB = "ZLIB";
private static final String SUPPORTED_COMPRESSION_METHOD_NULL = "NULL";
private static final String[] SUPPORTED_COMPRESSION_METHODS
= { SUPPORTED_COMPRESSION_METHOD_ZLIB, SUPPORTED_COMPRESSION_METHOD_NULL };
public static String[] getSupportedCompressionMethods() {
return SUPPORTED_COMPRESSION_METHODS.clone();
}
public static final String[] getDefaultCompressionMethods() {
return new String[] { SUPPORTED_COMPRESSION_METHOD_NULL };
}
public static String[] checkEnabledCompressionMethods(String[] methods) {
if (methods == null) {
throw new IllegalArgumentException("methods == null");
}
if (methods.length < 1
&& !methods[methods.length-1].equals(SUPPORTED_COMPRESSION_METHOD_NULL)) {
throw new IllegalArgumentException("last method must be NULL");
}
for (int i = 0; i < methods.length; i++) {
String method = methods[i];
if (method == null) {
throw new IllegalArgumentException("methods[" + i + "] == null");
}
if (!method.equals(SUPPORTED_COMPRESSION_METHOD_ZLIB)
&& !method.equals(SUPPORTED_COMPRESSION_METHOD_NULL)) {
throw new IllegalArgumentException("method " + method
+ " is not supported");
}
}
return methods;
}
public static void setEnabledCompressionMethods(int ssl, String[] methods) {
checkEnabledCompressionMethods(methods);
// openssl uses negative logic letting you disable compression.
// so first, assume we need to set all (disable all) and clear none (enable none).
// in the loop, selectively move bits from set to clear (from disable to enable)
long optionsToSet = (SSL_OP_NO_COMPRESSION);
long optionsToClear = 0;
for (int i = 0; i < methods.length; i++) {
String method = methods[i];
if (method.equals(SUPPORTED_COMPRESSION_METHOD_NULL)) {
// nothing to do to support NULL
} else if (method.equals(SUPPORTED_COMPRESSION_METHOD_ZLIB)) {
optionsToSet &= ~SSL_OP_NO_COMPRESSION;
optionsToClear |= SSL_OP_NO_COMPRESSION;
} else {
// error checked by checkEnabledCompressionMethods
throw new IllegalStateException();
}
}
SSL_set_options(ssl, optionsToSet);
SSL_clear_options(ssl, optionsToClear);
}
/*
* See the OpenSSL ssl.h header file for more information.
*/
public static final int SSL_VERIFY_NONE = 0x00;
public static final int SSL_VERIFY_PEER = 0x01;
public static final int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 0x02;
public static native void SSL_set_verify(int sslNativePointer, int mode);
public static native void SSL_set_session(int sslNativePointer, int sslSessionNativePointer)
throws SSLException;
public static native void SSL_set_session_creation_enabled(
int sslNativePointer, boolean creationEnabled) throws SSLException;
public static native void SSL_set_tlsext_host_name(int sslNativePointer, String hostname)
throws SSLException;
public static native String SSL_get_servername(int sslNativePointer);
/**
* Returns the sslSessionNativePointer of the negotiated session
*/
public static native int SSL_do_handshake(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
int timeout,
boolean client_mode)
throws SSLException, SocketTimeoutException, CertificateException;
/**
* Currently only intended for forcing renegotiation for testing.
* Not used within OpenSSLSocketImpl.
*/
public static native void SSL_renegotiate(int sslNativePointer) throws SSLException;
/**
* Returns the local ASN.1 DER encoded X509 certificates.
*/
public static native byte[][] SSL_get_certificate(int sslNativePointer);
/**
* Returns the peer ASN.1 DER encoded X509 certificates.
*/
public static native byte[][] SSL_get_peer_cert_chain(int sslNativePointer);
/**
* Reads with the native SSL_read function from the encrypted data stream
* @return -1 if error or the end of the stream is reached.
*/
public static native int SSL_read(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
byte[] b, int off, int len, int timeout)
throws IOException;
/**
* Writes with the native SSL_write function to the encrypted data stream.
*/
public static native void SSL_write(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
byte[] b, int off, int len)
throws IOException;
public static native void SSL_interrupt(int sslNativePointer);
public static native void SSL_shutdown(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc) throws IOException;
public static native void SSL_free(int sslNativePointer);
public static native byte[] SSL_SESSION_session_id(int sslSessionNativePointer);
public static native long SSL_SESSION_get_time(int sslSessionNativePointer);
public static native String SSL_SESSION_get_version(int sslSessionNativePointer);
public static native String SSL_SESSION_cipher(int sslSessionNativePointer);
public static native String SSL_SESSION_compress_meth(int sslCtxNativePointer,
int sslSessionNativePointer);
public static native void SSL_SESSION_free(int sslSessionNativePointer);
public static native byte[] i2d_SSL_SESSION(int sslSessionNativePointer);
public static native int d2i_SSL_SESSION(byte[] data);
/**
* A collection of callbacks from the native OpenSSL code that are
* related to the SSL handshake initiated by SSL_do_handshake.
*/
public interface SSLHandshakeCallbacks {
/**
* Verify that we trust the certificate chain is trusted.
*
* @param asn1DerEncodedCertificateChain A chain of ASN.1 DER encoded certificates
* @param authMethod auth algorithm name
*
* @throws CertificateException if the certificate is untrusted
*/
public void verifyCertificateChain(byte[][] asn1DerEncodedCertificateChain, String authMethod)
throws CertificateException;
/**
* Called on an SSL client when the server requests (or
* requires a certificate). The client can respond by using
* SSL_use_certificate and SSL_use_PrivateKey to set a
* certificate if has an appropriate one available, similar to
* how the server provides its certificate.
*
* @param keyTypes key types supported by the server,
* convertible to strings with #keyType
* @param asn1DerEncodedX500Principals CAs known to the server
*/
public void clientCertificateRequested(byte[] keyTypes,
byte[][] asn1DerEncodedX500Principals)
throws CertificateEncodingException, SSLException;
/**
* Called when SSL handshake is completed. Note that this can
* be after SSL_do_handshake returns when handshake cutthrough
* is enabled.
*/
public void handshakeCompleted();
}
}
org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
/*
* Copyright (C) 2007-2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Native glue for Java class org.apache.harmony.xnet.provider.jsse.NativeCrypto
*/
#define LOG_TAG "NativeCrypto"
#include <algorithm>
#include <fcntl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <jni.h>
#include <openssl/dsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
#include "AsynchronousSocketCloseMonitor.h"
#include "JNIHelp.h"
#include "JniConstants.h"
#include "JniException.h"
#include "NetFd.h"
#include "NetworkUtilities.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
#include "UniquePtr.h"
#undef WITH_JNI_TRACE
#undef WITH_JNI_TRACE_DATA
#ifdef WITH_JNI_TRACE
#define JNI_TRACE(...) \
((void)LOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__)); \
/*
((void)printf("I/" LOG_TAG "-jni:")); \
((void)printf(__VA_ARGS__)); \
((void)printf("\n"))
*/
#else
#define JNI_TRACE(...) ((void)0)
#endif
// don't overwhelm logcat
#define WITH_JNI_TRACE_DATA_CHUNK_SIZE 512
struct BIO_Delete {
void operator()(BIO* p) const {
BIO_free(p);
}
};
typedef UniquePtr<BIO, BIO_Delete> Unique_BIO;
struct BIGNUM_Delete {
void operator()(BIGNUM* p) const {
BN_free(p);
}
};
typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
struct DH_Delete {
void operator()(DH* p) const {
DH_free(p);
}
};
typedef UniquePtr<DH, DH_Delete> Unique_DH;
struct DSA_Delete {
void operator()(DSA* p) const {
DSA_free(p);
}
};
typedef UniquePtr<DSA, DSA_Delete> Unique_DSA;
struct EC_KEY_Delete {
void operator()(EC_KEY* p) const {
EC_KEY_free(p);
}
};
typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
struct EVP_MD_CTX_Delete {
void operator()(EVP_MD_CTX* p) const {
EVP_MD_CTX_destroy(p);
}
};
typedef UniquePtr<EVP_MD_CTX, EVP_MD_CTX_Delete> Unique_EVP_MD_CTX;
struct EVP_PKEY_Delete {
void operator()(EVP_PKEY* p) const {
EVP_PKEY_free(p);
}
};
typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
struct PKCS8_PRIV_KEY_INFO_Delete {
void operator()(PKCS8_PRIV_KEY_INFO* p) const {
PKCS8_PRIV_KEY_INFO_free(p);
}
};
typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
struct RSA_Delete {
void operator()(RSA* p) const {
RSA_free(p);
}
};
typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
struct SSL_Delete {
void operator()(SSL* p) const {
SSL_free(p);
}
};
typedef UniquePtr<SSL, SSL_Delete> Unique_SSL;
struct SSL_CTX_Delete {
void operator()(SSL_CTX* p) const {
SSL_CTX_free(p);
}
};
typedef UniquePtr<SSL_CTX, SSL_CTX_Delete> Unique_SSL_CTX;
struct X509_Delete {
void operator()(X509* p) const {
X509_free(p);
}
};
typedef UniquePtr<X509, X509_Delete> Unique_X509;
struct X509_NAME_Delete {
void operator()(X509_NAME* p) const {
X509_NAME_free(p);
}
};
typedef UniquePtr<X509_NAME, X509_NAME_Delete> Unique_X509_NAME;
struct sk_SSL_CIPHER_Delete {
void operator()(STACK_OF(SSL_CIPHER)* p) const {
sk_SSL_CIPHER_free(p);
}
};
typedef UniquePtr<STACK_OF(SSL_CIPHER), sk_SSL_CIPHER_Delete> Unique_sk_SSL_CIPHER;
struct sk_X509_Delete {
void operator()(STACK_OF(X509)* p) const {
sk_X509_free(p);
}
};
typedef UniquePtr<STACK_OF(X509), sk_X509_Delete> Unique_sk_X509;
struct sk_X509_NAME_Delete {
void operator()(STACK_OF(X509_NAME)* p) const {
sk_X509_NAME_free(p);
}
};
typedef UniquePtr<STACK_OF(X509_NAME), sk_X509_NAME_Delete> Unique_sk_X509_NAME;
/**
* Many OpenSSL APIs take ownership of an argument on success but don't free the argument
* on failure. This means we need to tell our scoped pointers when we've transferred ownership,
* without triggering a warning by not using the result of release().
*/
#define OWNERSHIP_TRANSFERRED(obj) \
typeof (obj.release()) _dummy __attribute__((unused)) = obj.release()
/**
* Frees the SSL error state.
*
* OpenSSL keeps an "error stack" per thread, and given that this code
* can be called from arbitrary threads that we don't keep track of,
* we err on the side of freeing the error state promptly (instead of,
* say, at thread death).
*/
static void freeOpenSslErrorState(void) {
ERR_clear_error();
ERR_remove_state(0);
}
/*
* Checks this thread's OpenSSL error queue and throws a RuntimeException if
* necessary.
*
* @return true if an exception was thrown, false if not.
*/
static bool throwExceptionIfNecessary(JNIEnv* env, const char* location __attribute__ ((unused))) {
int error = ERR_get_error();
int result = false;
if (error != 0) {
char message[256];
ERR_error_string_n(error, message, sizeof(message));
JNI_TRACE("OpenSSL error in %s %d: %s", location, error, message);
jniThrowRuntimeException(env, message);
result = true;
}
freeOpenSslErrorState();
return result;
}
/**
* Throws an SocketTimeoutException with the given string as a message.
*/
static void throwSocketTimeoutException(JNIEnv* env, const char* message) {
JNI_TRACE("throwSocketTimeoutException %s", message);
jniThrowException(env, "java/net/SocketTimeoutException", message);
}
/**
* Throws a javax.net.ssl.SSLException with the given string as a message.
*/
static void throwSSLExceptionStr(JNIEnv* env, const char* message) {
JNI_TRACE("throwSSLExceptionStr %s", message);
jniThrowException(env, "javax/net/ssl/SSLException", message);
}
/**
* Throws a javax.net.ssl.SSLProcotolException with the given string as a message.
*/
static void throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) {
JNI_TRACE("throwSSLProtocolExceptionStr %s", message);
jniThrowException(env, "javax/net/ssl/SSLProtocolException", message);
}
/**
* Throws an SSLException with a message constructed from the current
* SSL errors. This will also log the errors.
*
* @param env the JNI environment
* @param ssl the possibly NULL SSL
* @param sslErrorCode error code returned from SSL_get_error() or
* SSL_ERROR_NONE to probe with ERR_get_error
* @param message null-ok; general error message
*/
static void throwSSLExceptionWithSslErrors(
JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message) {
if (message == NULL) {
message = "SSL error";
}
// First consult the SSL error code for the general message.
const char* sslErrorStr = NULL;
switch (sslErrorCode) {
case SSL_ERROR_NONE:
if (ERR_peek_error() == 0) {
sslErrorStr = "OK";
} else {
sslErrorStr = "";
}
break;
case SSL_ERROR_SSL:
sslErrorStr = "Failure in SSL library, usually a protocol error";
break;
case SSL_ERROR_WANT_READ:
sslErrorStr = "SSL_ERROR_WANT_READ occurred. You should never see this.";
break;
case SSL_ERROR_WANT_WRITE:
sslErrorStr = "SSL_ERROR_WANT_WRITE occurred. You should never see this.";
break;
case SSL_ERROR_WANT_X509_LOOKUP:
sslErrorStr = "SSL_ERROR_WANT_X509_LOOKUP occurred. You should never see this.";
break;
case SSL_ERROR_SYSCALL:
sslErrorStr = "I/O error during system call";
break;
case SSL_ERROR_ZERO_RETURN:
sslErrorStr = "SSL_ERROR_ZERO_RETURN occurred. You should never see this.";
break;
case SSL_ERROR_WANT_CONNECT:
sslErrorStr = "SSL_ERROR_WANT_CONNECT occurred. You should never see this.";
break;
case SSL_ERROR_WANT_ACCEPT:
sslErrorStr = "SSL_ERROR_WANT_ACCEPT occurred. You should never see this.";
break;
default:
sslErrorStr = "Unknown SSL error";
}
// Prepend either our explicit message or a default one.
char* str;
if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) {
// problem with asprintf, just throw argument message, log everything
throwSSLExceptionStr(env, message);
LOGV("%s: ssl=%p: %s", message, ssl, sslErrorStr);
freeOpenSslErrorState();
return;
}
char* allocStr = str;
// For protocol errors, SSL might have more information.
if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) {
// Append each error as an additional line to the message.
for (;;) {
char errStr[256];
const char* file;
int line;
const char* data;
int flags;
unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags);
if (err == 0) {
break;
}
ERR_error_string_n(err, errStr, sizeof(errStr));
int ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
(allocStr == NULL) ? "" : allocStr,
errStr,
file,
line,
(flags & ERR_TXT_STRING) ? data : "(no data)",
flags);
if (ret < 0) {
break;
}
free(allocStr);
allocStr = str;
}
// For errors during system calls, errno might be our friend.
} else if (sslErrorCode == SSL_ERROR_SYSCALL) {
if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
free(allocStr);
allocStr = str;
}
// If the error code is invalid, print it.
} else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
free(allocStr);
allocStr = str;
}
}
if (sslErrorCode == SSL_ERROR_SSL) {
throwSSLProtocolExceptionStr(env, allocStr);
} else {
throwSSLExceptionStr(env, allocStr);
}
LOGV("%s", allocStr);
free(allocStr);
freeOpenSslErrorState();
}
/**
* Helper function that grabs the casts an ssl pointer and then checks for nullness.
* If this function returns NULL and <code>throwIfNull</code> is
* passed as <code>true</code>, then this function will call
* <code>throwSSLExceptionStr</code> before returning, so in this case of
* NULL, a caller of this function should simply return and allow JNI
* to do its thing.
*
* @param env the JNI environment
* @param ssl_address; the ssl_address pointer as an integer
* @param throwIfNull whether to throw if the SSL pointer is NULL
* @returns the pointer, which may be NULL
*/
static SSL_CTX* to_SSL_CTX(JNIEnv* env, int ssl_ctx_address, bool throwIfNull) {
SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
if ((ssl_ctx == NULL) && throwIfNull) {
JNI_TRACE("ssl_ctx == null");
jniThrowNullPointerException(env, "ssl_ctx == null");
}
return ssl_ctx;
}
static SSL* to_SSL(JNIEnv* env, int ssl_address, bool throwIfNull) {
SSL* ssl = reinterpret_cast<SSL*>(static_cast<uintptr_t>(ssl_address));
if ((ssl == NULL) && throwIfNull) {
JNI_TRACE("ssl == null");
jniThrowNullPointerException(env, "ssl == null");
}
return ssl;
}
static SSL_SESSION* to_SSL_SESSION(JNIEnv* env, int ssl_session_address, bool throwIfNull) {
SSL_SESSION* ssl_session
= reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
if ((ssl_session == NULL) && throwIfNull) {
JNI_TRACE("ssl_session == null");
jniThrowNullPointerException(env, "ssl_session == null");
}
return ssl_session;
}
/**
* Converts a Java byte[] to an OpenSSL BIGNUM, allocating the BIGNUM on the
* fly.
*/
static BIGNUM* arrayToBignum(JNIEnv* env, jbyteArray source) {
JNI_TRACE("arrayToBignum(%p)", source);
ScopedByteArrayRO sourceBytes(env, source);
if (sourceBytes.get() == NULL) {
JNI_TRACE("arrayToBignum(%p) => NULL", source);
return NULL;
}
BIGNUM* bn = BN_bin2bn(reinterpret_cast<const unsigned char*>(sourceBytes.get()),
sourceBytes.size(),
NULL);
JNI_TRACE("arrayToBignum(%p) => %p", source, bn);
return bn;
}
/**
* OpenSSL locking support. Taken from the O'Reilly book by Viega et al., but I
* suppose there are not many other ways to do this on a Linux system (modulo
* isomorphism).
*/
#define MUTEX_TYPE pthread_mutex_t
#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
#define THREAD_ID pthread_self()
#define THROW_SSLEXCEPTION (-2)
#define THROW_SOCKETTIMEOUTEXCEPTION (-3)
#define THROWN_EXCEPTION (-4)
static MUTEX_TYPE* mutex_buf = NULL;
static void locking_function(int mode, int n, const char*, int) {
if (mode & CRYPTO_LOCK) {
MUTEX_LOCK(mutex_buf[n]);
} else {
MUTEX_UNLOCK(mutex_buf[n]);
}
}
static unsigned long id_function(void) {
return ((unsigned long)THREAD_ID);
}
int THREAD_setup(void) {
mutex_buf = new MUTEX_TYPE[CRYPTO_num_locks()];
if (!mutex_buf) {
return 0;
}
for (int i = 0; i < CRYPTO_num_locks(); ++i) {
MUTEX_SETUP(mutex_buf[i]);
}
CRYPTO_set_id_callback(id_function);
CRYPTO_set_locking_callback(locking_function);
return 1;
}
int THREAD_cleanup(void) {
if (!mutex_buf) {
return 0;
}
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
for (int i = 0; i < CRYPTO_num_locks( ); i++) {
MUTEX_CLEANUP(mutex_buf[i]);
}
free(mutex_buf);
mutex_buf = NULL;
return 1;
}
/**
* Initialization phase for every OpenSSL job: Loads the Error strings, the
* crypto algorithms and reset the OpenSSL library
*/
static void NativeCrypto_clinit(JNIEnv*, jclass)
{
SSL_load_error_strings();
ERR_load_crypto_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
THREAD_setup();
}
/**
* public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g,
* byte[] pub_key, byte[] priv_key);
*/
static EVP_PKEY* NativeCrypto_EVP_PKEY_new_DSA(JNIEnv* env, jclass,
jbyteArray p, jbyteArray q, jbyteArray g,
jbyteArray pub_key, jbyteArray priv_key) {
JNI_TRACE("EVP_PKEY_new_DSA(p=%p, q=%p, g=%p, pub_key=%p, priv_key=%p)",
p, q, g, pub_key, priv_key);
Unique_DSA dsa(DSA_new());
if (dsa.get() == NULL) {
jniThrowRuntimeException(env, "DSA_new failed");
return NULL;
}
dsa->p = arrayToBignum(env, p);
dsa->q = arrayToBignum(env, q);
dsa->g = arrayToBignum(env, g);
dsa->pub_key = arrayToBignum(env, pub_key);
if (priv_key != NULL) {
dsa->priv_key = arrayToBignum(env, priv_key);
}
if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL || dsa->pub_key == NULL) {
jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
return NULL;
}
Unique_EVP_PKEY pkey(EVP_PKEY_new());
if (pkey.get() == NULL) {
jniThrowRuntimeException(env, "EVP_PKEY_new failed");
return NULL;
}
if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) {
jniThrowRuntimeException(env, "EVP_PKEY_assign_DSA failed");
return NULL;
}
OWNERSHIP_TRANSFERRED(dsa);
JNI_TRACE("EVP_PKEY_new_DSA(p=%p, q=%p, g=%p, pub_key=%p, priv_key=%p) => %p",
p, q, g, pub_key, priv_key, pkey.get());
return pkey.release();
}
/**
* private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q);
*/
static EVP_PKEY* NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass,
jbyteArray n, jbyteArray e, jbyteArray d,
jbyteArray p, jbyteArray q) {
JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p)", n, e, d, p, q);
Unique_RSA rsa(RSA_new());
if (rsa.get() == NULL) {
jniThrowRuntimeException(env, "RSA_new failed");
return NULL;
}
rsa->n = arrayToBignum(env, n);
rsa->e = arrayToBignum(env, e);
if (d != NULL) {
rsa->d = arrayToBignum(env, d);
}
if (p != NULL) {
rsa->p = arrayToBignum(env, p);
}
if (q != NULL) {
rsa->q = arrayToBignum(env, q);
}
#ifdef WITH_JNI_TRACE
if (p != NULL && q != NULL) {
int check = RSA_check_key(rsa.get());
JNI_TRACE("EVP_PKEY_new_RSA(...) RSA_check_key returns %d", check);
}
#endif
if (rsa->n == NULL || rsa->e == NULL) {
jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
return NULL;
}
Unique_EVP_PKEY pkey(EVP_PKEY_new());
if (pkey.get() == NULL) {
jniThrowRuntimeException(env, "EVP_PKEY_new failed");
return NULL;
}
if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
jniThrowRuntimeException(env, "EVP_PKEY_new failed");
return NULL;
}
OWNERSHIP_TRANSFERRED(rsa);
JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p) => %p", n, e, d, p, q, pkey.get());
return pkey.release();
}
/**
* private static native void EVP_PKEY_free(int pkey);
*/
static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, EVP_PKEY* pkey) {
JNI_TRACE("EVP_PKEY_free(%p)", pkey);
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
}
/*
* public static native void EVP_MD_CTX_destroy(int)
*/
static void NativeCrypto_EVP_MD_CTX_destroy(JNIEnv*, jclass, EVP_MD_CTX* ctx) {
JNI_TRACE("NativeCrypto_EVP_MD_CTX_destroy(%p)", ctx);
if (ctx != NULL) {
EVP_MD_CTX_destroy(ctx);
}
}
/*
* public static native int EVP_MD_CTX_copy(int)
*/
static jint NativeCrypto_EVP_MD_CTX_copy(JNIEnv* env, jclass, EVP_MD_CTX* ctx) {
JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p)", ctx);
if (ctx == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
}
EVP_MD_CTX* copy = EVP_MD_CTX_create();
if (copy == NULL) {
jniThrowOutOfMemoryError(env, "Unable to allocate copy of EVP_MD_CTX");
return 0;
}
EVP_MD_CTX_init(copy);
int result = EVP_MD_CTX_copy_ex(copy, ctx);
if (result == 0) {
EVP_MD_CTX_destroy(copy);
jniThrowRuntimeException(env, "Unable to copy EVP_MD_CTX");
return 0;
}
JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p) => %p", ctx, copy);
return (jint) copy;
}
/*
* public static native int EVP_DigestFinal(int, byte[], int)
*/
static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, EVP_MD_CTX* ctx,
jbyteArray hash, jint offset) {
JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d)", ctx, hash, offset);
if (ctx == NULL || hash == NULL) {
jniThrowNullPointerException(env, NULL);
return -1;
}
ScopedByteArrayRW hashBytes(env, hash);
if (hashBytes.get() == NULL) {
return -1;
}
unsigned int bytesWritten = -1;
int ok = EVP_DigestFinal(ctx,
reinterpret_cast<unsigned char*>(hashBytes.get() + offset),
&bytesWritten);
if (ok == 0) {
throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestFinal");
}
EVP_MD_CTX_destroy(ctx);
JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d) => %d", ctx, hash, offset, bytesWritten);
return bytesWritten;
}
/*
* public static native int EVP_DigestInit(int)
*/
static int NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, EVP_MD* evp_md) {
JNI_TRACE("NativeCrypto_EVP_DigestInit(%p)", evp_md);
if (evp_md == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
}
Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
if (ctx.get() == NULL) {
jniThrowOutOfMemoryError(env, "Unable to allocate EVP_MD_CTX");
return 0;
}
JNI_TRACE("NativeCrypto_EVP_DigestInit ctx=%p", ctx.get());
int ok = EVP_DigestInit(ctx.get(), evp_md);
if (ok == 0) {
bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestInit");
if (exception) {
return 0;
}
}
return (jint) ctx.release();
}
/*
* public static native int EVP_get_digestbyname(java.lang.String)
*/
static jint NativeCrypto_EVP_get_digestbyname(JNIEnv* env, jclass, jstring algorithm) {
JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%p)", algorithm);
if (algorithm == NULL) {
jniThrowNullPointerException(env, NULL);
return -1;
}
ScopedUtfChars algorithmChars(env, algorithm);
if (algorithmChars.c_str() == NULL) {
return 0;
}
JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s)", algorithmChars.c_str());
const EVP_MD* evp_md = EVP_get_digestbyname(algorithmChars.c_str());
if (evp_md == NULL) {
jniThrowRuntimeException(env, "Hash algorithm not found");
return 0;
}
JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s) => %p", algorithmChars.c_str(), evp_md);
return (jint) evp_md;
}
/*
* public static native int EVP_MD_size(int)
*/
static jint NativeCrypto_EVP_MD_size(JNIEnv* env, jclass, EVP_MD* evp_md) {
JNI_TRACE("NativeCrypto_EVP_MD_size(%p)", evp_md);
if (evp_md == NULL) {
jniThrowNullPointerException(env, NULL);
return -1;
}
int result = EVP_MD_size(evp_md);
JNI_TRACE("NativeCrypto_EVP_MD_size(%p) => %d", evp_md, result);
return result;
}
/*
* public static int void EVP_MD_block_size(int)
*/
static jint NativeCrypto_EVP_MD_block_size(JNIEnv* env, jclass, EVP_MD* evp_md) {
JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p)", evp_md);
if (evp_md == NULL) {
jniThrowNullPointerException(env, NULL);
return -1;
}
int result = EVP_MD_block_size(evp_md);
JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p) => %d", evp_md, result);
return result;
}
/*
* public static native void EVP_DigestUpdate(int, byte[], int, int)
*/
static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass, EVP_MD_CTX* ctx,
jbyteArray buffer, jint offset, jint length) {
JNI_TRACE("NativeCrypto_EVP_DigestUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
if (offset < 0 || length < 0) {
jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
return;
}
if (ctx == NULL || buffer == NULL) {
jniThrowNullPointerException(env, NULL);
return;
}
ScopedByteArrayRO bufferBytes(env, buffer);
if (bufferBytes.get() == NULL) {
return;
}
int ok = EVP_DigestUpdate(ctx,
reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
length);
if (ok == 0) {
throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestUpdate");
}
}
/*
* public static native int EVP_VerifyInit(java.lang.String)
*/
static jint NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass, jstring algorithm) {
JNI_TRACE("NativeCrypto_EVP_VerifyInit(%p)", algorithm);
if (algorithm == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
}
Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
if (ctx.get() == NULL) {
jniThrowOutOfMemoryError(env, "Unable to allocate EVP_MD_CTX");
return 0;
}
JNI_TRACE("NativeCrypto_EVP_VerifyInit ctx=%p", ctx.get());
ScopedUtfChars algorithmChars(env, algorithm);
if (algorithmChars.c_str() == NULL) {
return 0;
}
JNI_TRACE("NativeCrypto_EVP_VerifyInit algorithmChars=%s", algorithmChars.c_str());
const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
if (digest == NULL) {
jniThrowRuntimeException(env, "Hash algorithm not found");
return 0;
}
int ok = EVP_VerifyInit(ctx.get(), digest);
if (ok == 0) {
bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyInit");
if (exception) {
return 0;
}
}
return (jint) ctx.release();
}
/*
* public static native void EVP_VerifyUpdate(int, byte[], int, int)
*/
static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, EVP_MD_CTX* ctx,
jbyteArray buffer, jint offset, jint length) {
JNI_TRACE("NativeCrypto_EVP_VerifyUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
if (ctx == NULL || buffer == NULL) {
jniThrowNullPointerException(env, NULL);
return;
}
ScopedByteArrayRO bufferBytes(env, buffer);
if (bufferBytes.get() == NULL) {
return;
}
int ok = EVP_VerifyUpdate(ctx,
reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
length);
if (ok == 0) {
throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyUpdate");
}
}
/*
* public static native int EVP_VerifyFinal(int, byte[], int, int, int)
*/
static int NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jbyteArray buffer,
jint offset, jint length, EVP_PKEY* pkey) {
JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p)",
ctx, buffer, offset, length, pkey);
if (ctx == NULL || buffer == NULL || pkey == NULL) {
jniThrowNullPointerException(env, NULL);
return -1;
}
ScopedByteArrayRO bufferBytes(env, buffer);
if (bufferBytes.get() == NULL) {
return -1;
}
int ok = EVP_VerifyFinal(ctx,
reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
length,
pkey);
if (ok == 0) {
throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyFinal");
}
JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d",
ctx, buffer, offset, length, pkey, ok);
return ok;
}
/**
* Verifies an RSA signature.
*/
static void NativeCrypto_RAND_seed(JNIEnv* env, jclass, jbyteArray seed) {
JNI_TRACE("NativeCrypto_RAND_seed seed=%p", seed);
ScopedByteArrayRO randseed(env, seed);
if (randseed.get() == NULL) {
return;
}
RAND_seed(randseed.get(), randseed.size());
}
static int NativeCrypto_RAND_load_file(JNIEnv* env, jclass, jstring filename, jlong max_bytes) {
JNI_TRACE("NativeCrypto_RAND_load_file filename=%p max_bytes=%lld", filename, max_bytes);
ScopedUtfChars file(env, filename);
if (file.c_str() == NULL) {
return -1;
}
int result = RAND_load_file(file.c_str(), max_bytes);
JNI_TRACE("NativeCrypto_RAND_load_file file=%s => %d", file.c_str(), result);
return result;
}
#ifdef WITH_JNI_TRACE
/**
* Based on example logging call back from SSL_CTX_set_info_callback man page
*/
static void info_callback_LOG(const SSL* s __attribute__ ((unused)), int where, int ret)
{
int w = where & ~SSL_ST_MASK;
const char* str;
if (w & SSL_ST_CONNECT) {
str = "SSL_connect";
} else if (w & SSL_ST_ACCEPT) {
str = "SSL_accept";
} else {
str = "undefined";
}
if (where & SSL_CB_LOOP) {
JNI_TRACE("ssl=%p %s:%s %s", s, str, SSL_state_string(s), SSL_state_string_long(s));
} else if (where & SSL_CB_ALERT) {
str = (where & SSL_CB_READ) ? "read" : "write";
JNI_TRACE("ssl=%p SSL3 alert %s:%s:%s %s %s",
s,
str,
SSL_alert_type_string(ret),
SSL_alert_desc_string(ret),
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
} else if (where & SSL_CB_EXIT) {
if (ret == 0) {
JNI_TRACE("ssl=%p %s:failed exit in %s %s",
s, str, SSL_state_string(s), SSL_state_string_long(s));
} else if (ret < 0) {
JNI_TRACE("ssl=%p %s:error exit in %s %s",
s, str, SSL_state_string(s), SSL_state_string_long(s));
} else if (ret == 1) {
JNI_TRACE("ssl=%p %s:ok exit in %s %s",
s, str, SSL_state_string(s), SSL_state_string_long(s));
} else {
JNI_TRACE("ssl=%p %s:unknown exit %d in %s %s",
s, str, ret, SSL_state_string(s), SSL_state_string_long(s));
}
} else if (where & SSL_CB_HANDSHAKE_START) {
JNI_TRACE("ssl=%p handshake start in %s %s",
s, SSL_state_string(s), SSL_state_string_long(s));
} else if (where & SSL_CB_HANDSHAKE_DONE) {
JNI_TRACE("ssl=%p handshake done in %s %s",
s, SSL_state_string(s), SSL_state_string_long(s));
} else {
JNI_TRACE("ssl=%p %s:unknown where %d in %s %s",
s, str, where, SSL_state_string(s), SSL_state_string_long(s));
}
}
#endif
/**
* Returns an array containing all the X509 certificate's bytes.
*/
static jobjectArray getCertificateBytes(JNIEnv* env, const STACK_OF(X509)* chain)
{
if (chain == NULL) {
// Chain can be NULL if the associated cipher doesn't do certs.
return NULL;
}
int count = sk_X509_num(chain);
if (count <= 0) {
return NULL;
}
jobjectArray joa = env->NewObjectArray(count, JniConstants::byteArrayClass, NULL);
if (joa == NULL) {
return NULL;
}
for (int i = 0; i < count; i++) {
X509* cert = sk_X509_value(chain, i);
int len = i2d_X509(cert, NULL);
if (len < 0) {
return NULL;
}
ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(len));
if (byteArray.get() == NULL) {
return NULL;
}
ScopedByteArrayRW bytes(env, byteArray.get());
if (bytes.get() == NULL) {
return NULL;
}
unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get());
int n = i2d_X509(cert, &p);
if (n < 0) {
return NULL;
}
env->SetObjectArrayElement(joa, i, byteArray.get());
}
return joa;
}
/**
* Returns an array containing all the X500 principal's bytes.
*/
static jobjectArray getPrincipalBytes(JNIEnv* env, const STACK_OF(X509_NAME)* names)
{
if (names == NULL) {
return NULL;
}
int count = sk_X509_NAME_num(names);
if (count <= 0) {
return NULL;
}
jobjectArray joa = env->NewObjectArray(count, JniConstants::byteArrayClass, NULL);
if (joa == NULL) {
return NULL;
}
for (int i = 0; i < count; i++) {
X509_NAME* principal = sk_X509_NAME_value(names, i);
int len = i2d_X
|
|
|
Goto Forum:
Current Time: Mon Sep 23 18:42:42 GMT 2024
Powered by FUDForum. Page generated in 0.09020 seconds
|