diff options
author | Kenny Root <kroot@google.com> | 2013-10-02 18:31:22 -0700 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2013-10-02 18:31:22 -0700 |
commit | b151db09530f8e6fd39576d0172333f77aba363f (patch) | |
tree | a84e2b03b1fb431c8e0f7f88fc60d0b660852fca | |
parent | ba7e87db8b9a121e8fb3f8ee868f27054b124825 (diff) | |
parent | b6fb99fd5afa7b21b5ea48635d06560fd4efad00 (diff) | |
download | libcore-b151db09530f8e6fd39576d0172333f77aba363f.zip libcore-b151db09530f8e6fd39576d0172333f77aba363f.tar.gz libcore-b151db09530f8e6fd39576d0172333f77aba363f.tar.bz2 |
resolved conflicts for merge of b6fb99fd to klp-dev-plus-aosp
Change-Id: I7823612ade542b0f988e34f0ca188c07db97b673
137 files changed, 1 insertions, 39288 deletions
@@ -19,7 +19,7 @@ LOCAL_PATH := $(call my-dir) # Subprojects with separate makefiles # -subdirs := benchmarks crypto +subdirs := benchmarks subdir_makefiles := $(call all-named-subdir-makefiles,$(subdirs)) # diff --git a/crypto/Android.mk b/crypto/Android.mk deleted file mode 100644 index cb71664..0000000 --- a/crypto/Android.mk +++ /dev/null @@ -1,189 +0,0 @@ -# -*- mode: makefile -*- -# Copyright (C) 2013 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 -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# 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. - -# -# Definitions for building the Conscrypt Java library, native code, -# and associated tests. -# - -# -# Common definitions for host and target. -# - -# Conscrypt is divided into modules. -# -# The structure is: -# -# src/ -# main/ # To be shipped on every device. -# java/ # Java source for library code. -# native/ # C++ source for library code. -# resources/ # Support files. -# test/ # Built only on demand, for testing. -# java/ # Java source for tests. -# native/ # C++ source for tests (rare). -# resources/ # Support files. -# -# All subdirectories are optional (hence the "2> /dev/null"s below). - -LOCAL_PATH := $(call my-dir) - -local_javac_flags=-encoding UTF-8 -#local_javac_flags+=-Xlint:all -Xlint:-serial,-deprecation,-unchecked -local_javac_flags+=-Xmaxwarns 9999999 - -core_cflags := -Wall -Wextra -Werror -core_cppflags := -std=gnu++11 - -# -# Build for the target (device). -# - -# Create the conscrypt library -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java) -LOCAL_JAVA_LIBRARIES := core -LOCAL_NO_STANDARD_LIBRARIES := true -LOCAL_JAVACFLAGS := $(local_javac_flags) -LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := conscrypt -LOCAL_REQUIRED_MODULES := libjavacrypto -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_JAVA_LIBRARY) - -# Create the conscrypt library without jarjar for tests -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java) -LOCAL_JAVA_LIBRARIES := core -LOCAL_NO_STANDARD_LIBRARIES := true -LOCAL_JAVACFLAGS := $(local_javac_flags) -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := conscrypt-nojarjar -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_JAVA_LIBRARY) - -ifeq ($(LIBCORE_SKIP_TESTS),) -# Make the conscrypt-tests library. -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under,src/test/java) -LOCAL_NO_STANDARD_LIBRARIES := true -LOCAL_JAVA_LIBRARIES := bouncycastle core core-junit -LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support conscrypt-nojarjar -LOCAL_JAVACFLAGS := $(local_javac_flags) -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := conscrypt-tests -LOCAL_REQUIRED_MODULES := libjavacrypto -LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_JAVA_LIBRARY) -endif - -# Platform conscrypt crypto JNI library -include $(CLEAR_VARS) -LOCAL_CFLAGS += $(core_cflags) -LOCAL_CFLAGS += -DJNI_JARJAR_PREFIX="com/android/" -LOCAL_CPPFLAGS += $(core_cppflags) -LOCAL_SRC_FILES := \ - src/main/native/org_conscrypt_NativeCrypto.cpp -LOCAL_C_INCLUDES += \ - external/openssl/include \ - libcore/include \ - libcore/luni/src/main/native -LOCAL_SHARED_LIBRARIES := libcrypto libjavacore liblog libnativehelper libssl libz -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := libjavacrypto -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_SHARED_LIBRARY) - -# -# Build for the host. -# - -ifeq ($(WITH_HOST_DALVIK),true) - # Make the conscrypt-hostdex library - include $(CLEAR_VARS) - LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java) - LOCAL_JAVA_LIBRARIES := core-hostdex - LOCAL_NO_STANDARD_LIBRARIES := true - LOCAL_JAVACFLAGS := $(local_javac_flags) - LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt - LOCAL_BUILD_HOST_DEX := true - LOCAL_MODULE_TAGS := optional - LOCAL_MODULE := conscrypt-hostdex - LOCAL_REQUIRED_MODULES := libjavacrypto - LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - include $(BUILD_HOST_JAVA_LIBRARY) - - # Make the conscrypt-hostdex-nojarjar for tests - include $(CLEAR_VARS) - LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java) - LOCAL_JAVA_LIBRARIES := core-hostdex - LOCAL_NO_STANDARD_LIBRARIES := true - LOCAL_JAVACFLAGS := $(local_javac_flags) - LOCAL_BUILD_HOST_DEX := true - LOCAL_MODULE_TAGS := optional - LOCAL_MODULE := conscrypt-hostdex-nojarjar - LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - include $(BUILD_HOST_JAVA_LIBRARY) - - # Make the conscrypt-tests library. - ifeq ($(LIBCORE_SKIP_TESTS),) - include $(CLEAR_VARS) - LOCAL_SRC_FILES := $(call all-java-files-under,src/test/java) - LOCAL_NO_STANDARD_LIBRARIES := true - LOCAL_JAVA_LIBRARIES := bouncycastle-hostdex core-hostdex core-junit-hostdex core-tests-support-hostdex conscrypt-hostdex-nojarjar - LOCAL_JAVACFLAGS := $(local_javac_flags) - LOCAL_MODULE_TAGS := optional - LOCAL_MODULE := conscrypt-tests-hostdex - LOCAL_REQUIRED_MODULES := libjavacrypto - LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - LOCAL_BUILD_HOST_DEX := true - include $(BUILD_HOST_JAVA_LIBRARY) - endif - - # Conscrypt native library for host - include $(CLEAR_VARS) - LOCAL_SRC_FILES += \ - src/main/native/org_conscrypt_NativeCrypto.cpp - LOCAL_C_INCLUDES += \ - external/openssl/include \ - libcore/include \ - libcore/luni/src/main/native - LOCAL_CPPFLAGS += $(core_cppflags) - LOCAL_LDLIBS += -lpthread - LOCAL_MODULE_TAGS := optional - LOCAL_MODULE := libjavacrypto - LOCAL_CFLAGS += -DJNI_JARJAR_PREFIX="com/android/" - LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - LOCAL_SHARED_LIBRARIES := libcrypto-host libjavacore liblog libnativehelper libssl-host - include $(BUILD_HOST_SHARED_LIBRARY) - - # Conscrypt native library for nojarjar'd version - include $(CLEAR_VARS) - LOCAL_SRC_FILES += \ - src/main/native/org_conscrypt_NativeCrypto.cpp - LOCAL_C_INCLUDES += \ - external/openssl/include \ - libcore/include \ - libcore/luni/src/main/native - LOCAL_CPPFLAGS += $(core_cppflags) - LOCAL_LDLIBS += -lpthread - LOCAL_MODULE_TAGS := optional - LOCAL_MODULE := libconscrypt_jni - LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - LOCAL_SHARED_LIBRARIES := libcrypto-host libjavacore liblog libnativehelper libssl-host - include $(BUILD_HOST_SHARED_LIBRARY) -endif diff --git a/crypto/jarjar-rules.txt b/crypto/jarjar-rules.txt deleted file mode 100644 index 0eb6ac2..0000000 --- a/crypto/jarjar-rules.txt +++ /dev/null @@ -1 +0,0 @@ -rule org.conscrypt.** com.android.@0 diff --git a/crypto/src/main/java/org/conscrypt/AbstractSessionContext.java b/crypto/src/main/java/org/conscrypt/AbstractSessionContext.java deleted file mode 100644 index 4aed70c..0000000 --- a/crypto/src/main/java/org/conscrypt/AbstractSessionContext.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionContext; - -/** - * Supports SSL session caches. - */ -abstract class AbstractSessionContext implements SSLSessionContext { - - volatile int maximumSize; - volatile int timeout; - - final long sslCtxNativePointer = NativeCrypto.SSL_CTX_new(); - - /** Identifies OpenSSL sessions. */ - static final int OPEN_SSL = 1; - - private final Map<ByteArray, SSLSession> sessions - = new LinkedHashMap<ByteArray, SSLSession>() { - @Override - protected boolean removeEldestEntry( - Map.Entry<ByteArray, SSLSession> eldest) { - boolean remove = maximumSize > 0 && size() > maximumSize; - if (remove) { - remove(eldest.getKey()); - sessionRemoved(eldest.getValue()); - } - return false; - } - }; - - /** - * Constructs a new session context. - * - * @param maximumSize of cache - * @param timeout for cache entries - */ - AbstractSessionContext(int maximumSize, int timeout) { - this.maximumSize = maximumSize; - this.timeout = timeout; - } - - /** - * Returns the collection of sessions ordered from oldest to newest - */ - private Iterator<SSLSession> sessionIterator() { - synchronized (sessions) { - SSLSession[] array = sessions.values().toArray( - new SSLSession[sessions.size()]); - return Arrays.asList(array).iterator(); - } - } - - public final Enumeration<byte[]> getIds() { - final Iterator<SSLSession> i = sessionIterator(); - return new Enumeration<byte[]>() { - private SSLSession next; - public boolean hasMoreElements() { - if (next != null) { - return true; - } - while (i.hasNext()) { - SSLSession session = i.next(); - if (session.isValid()) { - next = session; - return true; - } - } - next = null; - return false; - } - public byte[] nextElement() { - if (hasMoreElements()) { - byte[] id = next.getId(); - next = null; - return id; - } - throw new NoSuchElementException(); - } - }; - } - - public final int getSessionCacheSize() { - return maximumSize; - } - - public final int getSessionTimeout() { - return timeout; - } - - /** - * Makes sure cache size is < maximumSize. - */ - protected void trimToSize() { - synchronized (sessions) { - int size = sessions.size(); - if (size > maximumSize) { - int removals = size - maximumSize; - Iterator<SSLSession> i = sessions.values().iterator(); - do { - SSLSession session = i.next(); - i.remove(); - sessionRemoved(session); - } while (--removals > 0); - } - } - } - - public void setSessionTimeout(int seconds) - throws IllegalArgumentException { - if (seconds < 0) { - throw new IllegalArgumentException("seconds < 0"); - } - timeout = seconds; - - synchronized (sessions) { - Iterator<SSLSession> i = sessions.values().iterator(); - while (i.hasNext()) { - SSLSession session = i.next(); - // SSLSession's know their context and consult the - // timeout as part of their validity condition. - if (!session.isValid()) { - i.remove(); - sessionRemoved(session); - } - } - } - } - - /** - * Called when a session is removed. Used by ClientSessionContext - * to update its host-and-port based cache. - */ - protected abstract void sessionRemoved(SSLSession session); - - public final void setSessionCacheSize(int size) - throws IllegalArgumentException { - if (size < 0) { - throw new IllegalArgumentException("size < 0"); - } - - int oldMaximum = maximumSize; - maximumSize = size; - - // Trim cache to size if necessary. - if (size < oldMaximum) { - trimToSize(); - } - } - - /** - * Converts the given session to bytes. - * - * @return session data as bytes or null if the session can't be converted - */ - byte[] toBytes(SSLSession session) { - // TODO: Support SSLSessionImpl, too. - if (!(session instanceof OpenSSLSessionImpl)) { - return null; - } - - OpenSSLSessionImpl sslSession = (OpenSSLSessionImpl) session; - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DataOutputStream daos = new DataOutputStream(baos); - - daos.writeInt(OPEN_SSL); // session type ID - - // Session data. - byte[] data = sslSession.getEncoded(); - daos.writeInt(data.length); - daos.write(data); - - // Certificates. - Certificate[] certs = session.getPeerCertificates(); - daos.writeInt(certs.length); - - for (Certificate cert : certs) { - data = cert.getEncoded(); - daos.writeInt(data.length); - daos.write(data); - } - // TODO: local certificates? - - return baos.toByteArray(); - } catch (IOException e) { - log(e); - return null; - } catch (CertificateEncodingException e) { - log(e); - return null; - } - } - - /** - * Creates a session from the given bytes. - * - * @return a session or null if the session can't be converted - */ - SSLSession toSession(byte[] data, String host, int port) { - ByteArrayInputStream bais = new ByteArrayInputStream(data); - DataInputStream dais = new DataInputStream(bais); - try { - int type = dais.readInt(); - if (type != OPEN_SSL) { - log(new AssertionError("Unexpected type ID: " + type)); - return null; - } - - int length = dais.readInt(); - byte[] sessionData = new byte[length]; - dais.readFully(sessionData); - - int count = dais.readInt(); - X509Certificate[] certs = new X509Certificate[count]; - for (int i = 0; i < count; i++) { - length = dais.readInt(); - byte[] certData = new byte[length]; - dais.readFully(certData); - certs[i] = OpenSSLX509Certificate.fromX509Der(certData); - } - - return new OpenSSLSessionImpl(sessionData, host, port, certs, this); - } catch (IOException e) { - log(e); - return null; - } - } - - public SSLSession getSession(byte[] sessionId) { - if (sessionId == null) { - throw new NullPointerException("sessionId == null"); - } - ByteArray key = new ByteArray(sessionId); - SSLSession session; - synchronized (sessions) { - session = sessions.get(key); - } - if (session != null && session.isValid()) { - return session; - } - return null; - } - - void putSession(SSLSession session) { - byte[] id = session.getId(); - if (id.length == 0) { - return; - } - ByteArray key = new ByteArray(id); - synchronized (sessions) { - sessions.put(key, session); - } - } - - static void log(Throwable t) { - System.logW("Error converting session.", t); - } - - @Override protected void finalize() throws Throwable { - try { - NativeCrypto.SSL_CTX_free(sslCtxNativePointer); - } finally { - super.finalize(); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/AlertException.java b/crypto/src/main/java/org/conscrypt/AlertException.java deleted file mode 100644 index a483021..0000000 --- a/crypto/src/main/java/org/conscrypt/AlertException.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import javax.net.ssl.SSLException; - -/** - * This exception is used to signal that a fatal alert has occurred while working through the - * protocol. - */ -public class AlertException extends RuntimeException { - - private static final long serialVersionUID = -4448327177165687581L; - // SSLException to be thrown to application side - private final SSLException reason; - // alert description code - private final byte description; - - /** - * Constructs the instance. - * - * @param description The alert description code from {@link AlertProtocol} - * @param reason The SSLException to be thrown to application side after alert processing - * (sending the record with alert, shutdown work, etc). - * @see AlertProtocol - */ - protected AlertException(byte description, SSLException reason) { - super(reason); - this.reason = reason; - this.description = description; - } - - /** - * Returns the reason of alert. This reason should be rethrown after alert processing. - * - * @return the reason of alert. - */ - protected SSLException getReason() { - return reason; - } - - /** - * Returns alert's description code. - * - * @return alert description code from {@link AlertProtocol} - * @see AlertProtocol for more information about possible reason codes. - */ - protected byte getDescriptionCode() { - return description; - } -} diff --git a/crypto/src/main/java/org/conscrypt/AlertProtocol.java b/crypto/src/main/java/org/conscrypt/AlertProtocol.java deleted file mode 100644 index 0330e79..0000000 --- a/crypto/src/main/java/org/conscrypt/AlertProtocol.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * This class encapsulates the functionality of Alert Protocol. - * Constant values are taken according to the TLS v1 specification - * (http://www.ietf.org/rfc/rfc2246.txt), p 7.2. - */ -public class AlertProtocol { - - // ------------------------ AlertLevel codes -------------------------- - /** - * Defines the severity of alert as warning - */ - protected static final byte WARNING = 1; - /** - * Defines the severity of alert as fatal - */ - protected static final byte FATAL = 2; - - // --------------------- AlertDescription codes ----------------------- - /** - * Defines the description code of the close_notify alert - */ - protected static final byte CLOSE_NOTIFY = 0; - /** - * Defines the description code of the unexpected_message alert - */ - protected static final byte UNEXPECTED_MESSAGE = 10; - /** - * Defines the description code of the bad_record_mac alert - */ - protected static final byte BAD_RECORD_MAC = 20; - /** - * Defines the description code of the decryption_failed alert - */ - protected static final byte DECRYPTION_FAILED = 21; - /** - * Defines the description code of the record_overflow alert - */ - protected static final byte RECORD_OVERFLOW = 22; - /** - * Defines the description code of the decompression_failure alert - */ - protected static final byte DECOMPRESSION_FAILURE = 30; - /** - * Defines the description code of the handshake_failure alert - */ - protected static final byte HANDSHAKE_FAILURE = 40; - /** - * Defines the description code of the bad_certificate alert - */ - protected static final byte BAD_CERTIFICATE = 42; - /** - * Defines the description code of the unsupported_certificate alert - */ - protected static final byte UNSUPPORTED_CERTIFICATE = 43; - /** - * Defines the description code of the certificate_revoked alert - */ - protected static final byte CERTIFICATE_REVOKED = 44; - /** - * Defines the description code of the certificate_expired alert - */ - protected static final byte CERTIFICATE_EXPIRED = 45; - /** - * Defines the description code of the certificate_unknown alert - */ - protected static final byte CERTIFICATE_UNKNOWN = 46; - /** - * Defines the description code of the illegal_parameter alert - */ - protected static final byte ILLEGAL_PARAMETER = 47; - /** - * Defines the description code of the unknown_ca alert - */ - protected static final byte UNKNOWN_CA = 48; - /** - * Defines the description code of the access_denied alert - */ - protected static final byte ACCESS_DENIED = 49; - /** - * Defines the description code of the decode_error alert - */ - protected static final byte DECODE_ERROR = 50; - /** - * Defines the description code of the decrypt_error alert - */ - protected static final byte DECRYPT_ERROR = 51; - /** - * Defines the description code of the export_restriction alert - */ - protected static final byte EXPORT_RESTRICTION = 60; - /** - * Defines the description code of the protocol_version alert - */ - protected static final byte PROTOCOL_VERSION = 70; - /** - * Defines the description code of the insufficient_security alert - */ - protected static final byte INSUFFICIENT_SECURITY = 71; - /** - * Defines the description code of the internal_error alert - */ - protected static final byte INTERNAL_ERROR = 80; - /** - * Defines the description code of the user_canceled alert - */ - protected static final byte USER_CANCELED = 90; - /** - * Defines the description code of the no_renegotiation alert - */ - protected static final byte NO_RENEGOTIATION = 100; - // holds level and description codes - private final byte[] alert = new byte[2]; - // record protocol to be used to wrap the alerts - private SSLRecordProtocol recordProtocol; - - private Logger.Stream logger = Logger.getStream("alert"); - - /** - * Creates the instance of AlertProtocol. - * Note that class is not ready to work without providing of - * record protocol - * @see #setRecordProtocol - */ - protected AlertProtocol() {} - - /** - * Sets up the record protocol to be used by this allert protocol. - */ - protected void setRecordProtocol(SSLRecordProtocol recordProtocol) { - this.recordProtocol = recordProtocol; - } - - /** - * Reports an alert to be sent/received by transport. - * This method is usually called during processing - * of the income TSL record: if it contains alert message from another - * peer, or if warning alert occured during the processing of the - * message and this warning should be sent to another peer. - * @param level alert level code - * @param description alert description code - */ - protected void alert(byte level, byte description) { - if (logger != null) { - logger.println("Alert.alert: "+level+" "+description); - } - this.alert[0] = level; - this.alert[1] = description; - } - - /** - * Returns the description code of alert or -100 if there - * is no alert. - */ - protected byte getDescriptionCode() { - return (alert[0] != 0) ? alert[1] : -100; - } - - /** - * Resets the protocol to be in "no alert" state. - * This method shoud be called after processing of the reported alert. - */ - protected void setProcessed() { - // free the info about alert - if (logger != null) { - logger.println("Alert.setProcessed"); - } - this.alert[0] = 0; - } - - /** - * Checks if any alert has occured. - */ - protected boolean hasAlert() { - return (alert[0] != 0); - } - - /** - * Checks if occured alert is fatal alert. - */ - protected boolean isFatalAlert() { - return (alert[0] == 2); - } - - /** - * Returns the string representation of occured alert. - * If no alert has occured null is returned. - */ - protected String getAlertDescription() { - switch (alert[1]) { - case CLOSE_NOTIFY: - return "close_notify"; - case UNEXPECTED_MESSAGE: - return "unexpected_message"; - case BAD_RECORD_MAC: - return "bad_record_mac"; - case DECRYPTION_FAILED: - return "decryption_failed"; - case RECORD_OVERFLOW: - return "record_overflow"; - case DECOMPRESSION_FAILURE: - return "decompression_failure"; - case HANDSHAKE_FAILURE: - return "handshake_failure"; - case BAD_CERTIFICATE: - return "bad_certificate"; - case UNSUPPORTED_CERTIFICATE: - return "unsupported_certificate"; - case CERTIFICATE_REVOKED: - return "certificate_revoked"; - case CERTIFICATE_EXPIRED: - return "certificate_expired"; - case CERTIFICATE_UNKNOWN: - return "certificate_unknown"; - case ILLEGAL_PARAMETER: - return "illegal_parameter"; - case UNKNOWN_CA: - return "unknown_ca"; - case ACCESS_DENIED: - return "access_denied"; - case DECODE_ERROR: - return "decode_error"; - case DECRYPT_ERROR: - return "decrypt_error"; - case EXPORT_RESTRICTION: - return "export_restriction"; - case PROTOCOL_VERSION: - return "protocol_version"; - case INSUFFICIENT_SECURITY: - return "insufficient_security"; - case INTERNAL_ERROR: - return "internal_error"; - case USER_CANCELED: - return "user_canceled"; - case NO_RENEGOTIATION: - return "no_renegotiation"; - } - return null; - } - - /** - * Returns the record with reported alert message. - * The returned array of bytes is ready to be sent to another peer. - * Note, that this method does not automatically set the state of alert - * protocol in "no alert" state, so after wrapping the method setProcessed - * should be called. - */ - protected byte[] wrap() { - byte[] res = recordProtocol.wrap(ContentType.ALERT, alert, 0, 2); - return res; - } - - /** - * Shutdown the protocol. It will be impossible to use the instance - * after the calling of this method. - */ - protected void shutdown() { - alert[0] = 0; - alert[1] = 0; - recordProtocol = null; - } -} - diff --git a/crypto/src/main/java/org/conscrypt/Appendable.java b/crypto/src/main/java/org/conscrypt/Appendable.java deleted file mode 100644 index d22c5a8..0000000 --- a/crypto/src/main/java/org/conscrypt/Appendable.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * This interface represents the ability of the input stream related classes to provide additional - * data to be read. - */ -public interface Appendable { - - /** - * Provides the additional data to be read. - * - * @param src the source data to be appended. - */ - public void append(byte[] src); - -} diff --git a/crypto/src/main/java/org/conscrypt/ByteArray.java b/crypto/src/main/java/org/conscrypt/ByteArray.java deleted file mode 100644 index be682de..0000000 --- a/crypto/src/main/java/org/conscrypt/ByteArray.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2011 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.util.Arrays; - -/** - * Byte array wrapper for hashtable use. Implements equals() and hashCode(). - */ -final class ByteArray { - private final byte[] bytes; - private final int hashCode; - - ByteArray(byte[] bytes) { - this.bytes = bytes; - this.hashCode = Arrays.hashCode(bytes); - } - - @Override public int hashCode() { - return hashCode; - } - - @Override public boolean equals(Object o) { - if (!(o instanceof ByteArray)) { - return false; - } - ByteArray lhs = (ByteArray) o; - return Arrays.equals(bytes, lhs.bytes); - } -} diff --git a/crypto/src/main/java/org/conscrypt/CertPinManager.java b/crypto/src/main/java/org/conscrypt/CertPinManager.java deleted file mode 100644 index 22578fc..0000000 --- a/crypto/src/main/java/org/conscrypt/CertPinManager.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import libcore.io.IoUtils; -import libcore.util.BasicLruCache; - -/** - * This class provides a simple interface for cert pinning. - */ -public class CertPinManager { - - private long lastModified; - - private final Map<String, PinListEntry> entries = new HashMap<String, PinListEntry>(); - private final BasicLruCache<String, String> hostnameCache = new BasicLruCache<String, String>(10); - - private boolean initialized = false; - private static final boolean DEBUG = false; - - private final File pinFile; - private final TrustedCertificateStore certStore; - - public CertPinManager(TrustedCertificateStore store) throws PinManagerException { - pinFile = new File("/data/misc/keychain/pins"); - certStore = store; - rebuild(); - } - - /** Test only */ - public CertPinManager(String path, TrustedCertificateStore store) throws PinManagerException { - if (path == null) { - throw new NullPointerException("path == null"); - } - pinFile = new File(path); - certStore = store; - rebuild(); - } - - /** - * This is the public interface for cert pinning. - * - * Given a hostname and a certificate chain this verifies that the chain includes - * certs from the pinned list provided. - * - * If the chain doesn't include those certs and is in enforcing mode, then this method - * returns true and the certificate check should fail. - */ - public boolean chainIsNotPinned(String hostname, List<X509Certificate> chain) - throws PinManagerException { - // lookup the entry - PinListEntry entry = lookup(hostname); - - // return its result or false if there's no pin - if (entry != null) { - return entry.chainIsNotPinned(chain); - } - return false; - } - - private synchronized void rebuild() throws PinManagerException { - // reread the pin file - String pinFileContents = readPinFile(); - - if (pinFileContents != null) { - // rebuild the pinned certs - for (String entry : getPinFileEntries(pinFileContents)) { - try { - PinListEntry pin = new PinListEntry(entry, certStore); - entries.put(pin.getCommonName(), pin); - } catch (PinEntryException e) { - log("Pinlist contains a malformed pin: " + entry, e); - } - } - - // clear the cache - hostnameCache.evictAll(); - - // set the last modified time - lastModified = pinFile.lastModified(); - - // we've been fully initialized and are ready to go - initialized = true; - } - } - - private String readPinFile() throws PinManagerException { - try { - return IoUtils.readFileAsString(pinFile.getPath()); - } catch (FileNotFoundException e) { - // there's no pin list, all certs are unpinned - return null; - } catch (IOException e) { - // this is unexpected, fail - throw new PinManagerException("Unexpected error reading pin list; failing.", e); - } - } - - private static String[] getPinFileEntries(String pinFileContents) { - return pinFileContents.split("\n"); - } - - private synchronized PinListEntry lookup(String hostname) throws PinManagerException { - - // if we don't have any data, don't bother - if (!initialized) { - return null; - } - - // check to see if our cache is valid - if (cacheIsNotValid()) { - rebuild(); - } - - // if so, check the hostname cache - String cn = hostnameCache.get(hostname); - if (cn != null) { - // if we hit, return the corresponding entry - return entries.get(cn); - } - - // otherwise, get the matching cn - cn = getMatchingCN(hostname); - if (cn != null) { - hostnameCache.put(hostname, cn); - // we have a matching CN, return that entry - return entries.get(cn); - } - - // if we got here, we don't have a matching CN for this hostname - return null; - } - - private boolean cacheIsNotValid() { - return pinFile.lastModified() != lastModified; - } - - private String getMatchingCN(String hostname) { - String bestMatch = ""; - for (String cn : entries.keySet()) { - // skip shorter CNs since they can't be better matches - if (cn.length() < bestMatch.length()) { - continue; - } - // now verify that the CN matches at all - if (isHostnameMatchedBy(hostname, cn)) { - bestMatch = cn; - } - } - return bestMatch; - } - - /** - * Returns true if {@code hostName} matches the name or pattern {@code cn}. - * - * @param hostName lowercase host name. - * @param cn certificate host name. May include wildcards like - * {@code *.android.com}. - */ - private static boolean isHostnameMatchedBy(String hostName, String cn) { - if (hostName == null || hostName.isEmpty() || cn == null || cn.isEmpty()) { - return false; - } - - cn = cn.toLowerCase(Locale.US); - - if (!cn.contains("*")) { - return hostName.equals(cn); - } - - if (cn.startsWith("*.") && hostName.regionMatches(0, cn, 2, cn.length() - 2)) { - return true; // "*.foo.com" matches "foo.com" - } - - int asterisk = cn.indexOf('*'); - int dot = cn.indexOf('.'); - if (asterisk > dot) { - return false; // malformed; wildcard must be in the first part of - // the cn - } - - if (!hostName.regionMatches(0, cn, 0, asterisk)) { - return false; // prefix before '*' doesn't match - } - - int suffixLength = cn.length() - (asterisk + 1); - int suffixStart = hostName.length() - suffixLength; - if (hostName.indexOf('.', asterisk) < suffixStart) { - return false; // wildcard '*' can't match a '.' - } - - if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) { - return false; // suffix after '*' doesn't match - } - - return true; - } - - private static void log(String s, Exception e) { - if (DEBUG) { - System.out.println("PINFILE: " + s); - if (e != null) { - e.printStackTrace(); - } - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/CertificateMessage.java b/crypto/src/main/java/org/conscrypt/CertificateMessage.java deleted file mode 100644 index 0c0e092..0000000 --- a/crypto/src/main/java/org/conscrypt/CertificateMessage.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.ArrayList; - -/** - * Represents server/client certificate message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS - * 1.0 spec., 7.4.2. Server certificate; 7.4.6. Client certificate</a> - * - */ -public class CertificateMessage extends Message { - - /** - * Certificates - */ - X509Certificate[] certs; - - /** - * Certificates in encoded form - */ - byte[][] encoded_certs; - - /** - * Creates inbound message - * - * @param in - * @param length - * @throws IOException - */ - public CertificateMessage(HandshakeIODataStream in, int length) throws IOException { - int l = in.readUint24(); // total_length - if (l == 0) { // message contais no certificates - if (length != 3) { // no more bytes after total_length - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect CertificateMessage"); - } - certs = new X509Certificate[0]; - encoded_certs = new byte[0][0]; - this.length = 3; - return; - } - CertificateFactory cf; - try { - cf = CertificateFactory.getInstance("X509"); - } catch (CertificateException e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e); - return; - } - ArrayList<X509Certificate> certsList = new ArrayList<X509Certificate>(); - int size = 0; - int enc_size = 0; - while (l > 0) { - size = in.readUint24(); - l -= 3; - try { - certsList.add((X509Certificate) cf.generateCertificate(in)); - } catch (CertificateException e) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR", e); - } - l -= size; - enc_size += size; - } - certs = certsList.toArray(new X509Certificate[certsList.size()]); - this.length = 3 + 3 * certs.length + enc_size; - if (this.length != length) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect CertificateMessage"); - } - } - - /** - * Creates outbound message - * - * @param certs - */ - public CertificateMessage(X509Certificate[] certs) { - if (certs == null) { - this.certs = new X509Certificate[0]; - encoded_certs = new byte[0][0]; - length = 3; - return; - } - this.certs = certs; - if (encoded_certs == null) { - encoded_certs = new byte[certs.length][]; - for (int i = 0; i < certs.length; i++) { - try { - encoded_certs[i] = certs[i].getEncoded(); - } catch (CertificateEncodingException e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", - e); - } - } - } - length = 3 + 3 * encoded_certs.length; - for (int i = 0; i < encoded_certs.length; i++) { - length += encoded_certs[i].length; - } - } - - /** - * Sends message - * - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - - int total_length = 0; - if (encoded_certs == null) { - encoded_certs = new byte[certs.length][]; - for (int i = 0; i < certs.length; i++) { - try { - encoded_certs[i] = certs[i].getEncoded(); - } catch (CertificateEncodingException e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", - e); - } - } - } - total_length = 3 * encoded_certs.length; - for (int i = 0; i < encoded_certs.length; i++) { - total_length += encoded_certs[i].length; - } - out.writeUint24(total_length); - for (int i = 0; i < encoded_certs.length; i++) { - out.writeUint24(encoded_certs[i].length); - out.write(encoded_certs[i]); - } - - } - - public String getAuthType() { - return certs[0].getPublicKey().getAlgorithm(); - } - - /** - * Returns message type - */ - @Override - public int getType() { - return Handshake.CERTIFICATE; - } - -} diff --git a/crypto/src/main/java/org/conscrypt/CertificateRequest.java b/crypto/src/main/java/org/conscrypt/CertificateRequest.java deleted file mode 100644 index 6d08cc2..0000000 --- a/crypto/src/main/java/org/conscrypt/CertificateRequest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import javax.security.auth.x500.X500Principal; -import libcore.io.Streams; - -/** - * - * Represents certificate request message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.4. - * Certificate request</a> - */ -public class CertificateRequest extends Message { - - /** - * Requested certificate types - */ - final byte[] certificate_types; - - /** - * Certificate authorities - */ - final X500Principal[] certificate_authorities; - - /** - * Requested certificate types as Strings - * ("RSA", "DSA", "DH_RSA" or "DH_DSA") - */ - private String[] types; - - /** - * Encoded form of certificate authorities - */ - private byte[][] encoded_principals; - - /** - * Creates outbound message - * - * @param certificate_types - * @param accepted - array of certificate authority certificates - */ - public CertificateRequest(byte[] certificate_types, - X509Certificate[] accepted) { - - if (accepted == null) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "CertificateRequest: array of certificate authority certificates is null"); - } - this.certificate_types = certificate_types; - - int totalPrincipalsLength = 0; - certificate_authorities = new X500Principal[accepted.length]; - encoded_principals = new byte[accepted.length][]; - for (int i = 0; i < accepted.length; i++) { - certificate_authorities[i] = accepted[i].getIssuerX500Principal(); - encoded_principals[i] = certificate_authorities[i].getEncoded(); - totalPrincipalsLength += encoded_principals[i].length + 2; - } - - length = 3 + certificate_types.length + totalPrincipalsLength; - } - - /** - * Creates inbound message - * - * @param in - * @param length - * @throws IOException - */ - public CertificateRequest(HandshakeIODataStream in, int length) throws IOException { - int size = in.readUint8(); - certificate_types = new byte[size]; - Streams.readFully(in, certificate_types); - size = in.readUint16(); - int totalPrincipalsLength = 0; - int principalLength = 0; - ArrayList<X500Principal> principals = new ArrayList<X500Principal>(); - while (totalPrincipalsLength < size) { - principalLength = in.readUint16(); // encoded X500Principal size - principals.add(new X500Principal(in)); - totalPrincipalsLength += 2; - totalPrincipalsLength += principalLength; - } - certificate_authorities = principals.toArray(new X500Principal[principals.size()]); - this.length = 3 + certificate_types.length + totalPrincipalsLength; - if (this.length != length) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect CertificateRequest"); - } - } - - /** - * Sends message - * - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - - out.writeUint8(certificate_types.length); - for (int i = 0; i < certificate_types.length; i++) { - out.write(certificate_types[i]); - } - int authoritiesLength = 0; - for (int i = 0; i < certificate_authorities.length; i++) { - authoritiesLength += encoded_principals[i].length +2; - } - out.writeUint16(authoritiesLength); - for (int i = 0; i < certificate_authorities.length; i++) { - out.writeUint16(encoded_principals[i].length); - out.write(encoded_principals[i]); - } - } - - /** - * Returns message type - */ - @Override - public int getType() { - return Handshake.CERTIFICATE_REQUEST; - } - - /** - * Returns requested certificate types as array of strings - */ - public String[] getTypesAsString() { - if (types == null) { - types = new String[certificate_types.length]; - for (int i = 0; i < types.length; i++) { - String type = CipherSuite.getClientKeyType(certificate_types[i]); - if (type == null) { - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect CertificateRequest"); - } - types[i] = type; - } - } - return types; - } - -} diff --git a/crypto/src/main/java/org/conscrypt/CertificateVerify.java b/crypto/src/main/java/org/conscrypt/CertificateVerify.java deleted file mode 100644 index 8ba394a..0000000 --- a/crypto/src/main/java/org/conscrypt/CertificateVerify.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; - -/** - * Represents certificate verify message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.8. - * Certificate verify</a> - */ -public class CertificateVerify extends Message { - - /** - * Signature - */ - byte[] signedHash; - - /** - * Creates outbound message - * - * @param hash - */ - public CertificateVerify(byte[] hash) { - if (hash == null || hash.length == 0) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "INTERNAL ERROR: incorrect certificate verify hash"); - } - this.signedHash = hash; - length = hash.length + 2; - } - - /** - * Creates inbound message - * - * @param in - * @param length - * @throws IOException - */ - public CertificateVerify(HandshakeIODataStream in, int length) - throws IOException { - if (length == 0) { - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect CertificateVerify"); - } else { - if (in.readUint16() != length - 2) { - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect CertificateVerify"); - } - signedHash = in.read(length -2); - } - this.length = length; - } - - /** - * Sends message - * - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - if (signedHash.length != 0) { - out.writeUint16(signedHash.length); - out.write(signedHash); - } - } - - /** - * Returns message type - */ - @Override - public int getType() { - return Handshake.CERTIFICATE_VERIFY; - } -} diff --git a/crypto/src/main/java/org/conscrypt/ChainStrengthAnalyzer.java b/crypto/src/main/java/org/conscrypt/ChainStrengthAnalyzer.java deleted file mode 100644 index dc4f9b7..0000000 --- a/crypto/src/main/java/org/conscrypt/ChainStrengthAnalyzer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPublicKey; - -public final class ChainStrengthAnalyzer { - - private static final int MIN_MODULUS = 1024; - private static final String[] OID_BLACKLIST = {"1.2.840.113549.1.1.4"}; // MD5withRSA - - public static final void check(X509Certificate[] chain) throws CertificateException { - for (X509Certificate cert : chain) { - checkCert(cert); - } - } - - private static final void checkCert(X509Certificate cert) throws CertificateException { - checkModulusLength(cert); - checkNotMD5(cert); - } - - private static final void checkModulusLength(X509Certificate cert) throws CertificateException { - Object pubkey = cert.getPublicKey(); - if (pubkey instanceof RSAPublicKey) { - int modulusLength = ((RSAPublicKey) pubkey).getModulus().bitLength(); - if(!(modulusLength >= MIN_MODULUS)) { - throw new CertificateException("Modulus is < 1024 bits"); - } - } - } - - private static final void checkNotMD5(X509Certificate cert) throws CertificateException { - String oid = cert.getSigAlgOID(); - for (String blacklisted : OID_BLACKLIST) { - if (oid.equals(blacklisted)) { - throw new CertificateException("Signature uses an insecure hash function"); - } - } - } -} - diff --git a/crypto/src/main/java/org/conscrypt/CipherSuite.java b/crypto/src/main/java/org/conscrypt/CipherSuite.java deleted file mode 100644 index 6d2a3e8..0000000 --- a/crypto/src/main/java/org/conscrypt/CipherSuite.java +++ /dev/null @@ -1,1184 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.GeneralSecurityException; -import java.util.Hashtable; -import javax.crypto.Cipher; - -/** - * Represents Cipher Suite as defined in TLS 1.0 spec., - * A.5. The CipherSuite; - * C. CipherSuite definitions. - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec.</a> - * - */ -public class CipherSuite { - - /** - * true if this cipher suite is supported - */ - boolean supported = true; - - /** - * cipher suite key exchange - */ - final int keyExchange; - - /** - * algorithm used for authentication ("RSA", "DSA", "DH", null for anonymous) - */ - final String authType; - - /** - * cipher - */ - final String cipherName; - - /** - * Cipher information - */ - final int keyMaterial; - final int expandedKeyMaterial; - final int effectiveKeyBytes; - final int ivSize; - final private int blockSize; - - // cipher suite code - private final byte[] cipherSuiteCode; - - // cipher suite name - private final String name; - - // true if cipher suite is exportable - private final boolean isExportable; - - // Hash algorithm - final private String hashName; - - // MAC algorithm - final private String hmacName; - - // Hash size - final private int hashSize; - - /** - * key exchange values - */ - static final int KEY_EXCHANGE_RSA = 1; - static final int KEY_EXCHANGE_RSA_EXPORT = 2; - static final int KEY_EXCHANGE_DHE_DSS = 3; - static final int KEY_EXCHANGE_DHE_DSS_EXPORT = 4; - static final int KEY_EXCHANGE_DHE_RSA = 5; - static final int KEY_EXCHANGE_DHE_RSA_EXPORT = 6; - // BEGIN android-removed - // static final int KEY_EXCHANGE_DH_DSS = 7; - // static final int KEY_EXCHANGE_DH_RSA = 8; - // END android-removed - static final int KEY_EXCHANGE_DH_anon = 9; - static final int KEY_EXCHANGE_DH_anon_EXPORT = 10; - // BEGIN android-removed - // static final int KEY_EXCHANGE_DH_DSS_EXPORT = 11; - // static final int KEY_EXCHANGE_DH_RSA_EXPORT = 12; - // END android-removed - static final int KEY_EXCHANGE_ECDH_ECDSA = 13; - static final int KEY_EXCHANGE_ECDHE_ECDSA = 14; - static final int KEY_EXCHANGE_ECDH_RSA = 15; - static final int KEY_EXCHANGE_ECDHE_RSA = 16; - static final int KEY_EXCHANGE_ECDH_anon = 17; - - /** - * TLS cipher suite codes - */ - static final byte[] CODE_SSL_NULL_WITH_NULL_NULL = { 0x00, 0x00 }; - static final byte[] CODE_SSL_RSA_WITH_NULL_MD5 = { 0x00, 0x01 }; - static final byte[] CODE_SSL_RSA_WITH_NULL_SHA = { 0x00, 0x02 }; - static final byte[] CODE_SSL_RSA_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x03 }; - static final byte[] CODE_SSL_RSA_WITH_RC4_128_MD5 = { 0x00, 0x04 }; - static final byte[] CODE_SSL_RSA_WITH_RC4_128_SHA = { 0x00, 0x05 }; - static final byte[] CODE_SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00, 0x06 }; - // BEGIN android-removed - // static final byte[] CODE_TLS_RSA_WITH_IDEA_CBC_SHA = { 0x00, 0x07 }; - // END android-removed - static final byte[] CODE_SSL_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x08 }; - static final byte[] CODE_SSL_RSA_WITH_DES_CBC_SHA = { 0x00, 0x09 }; - static final byte[] CODE_SSL_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x0A }; - // BEGIN android-removed - // static final byte[] CODE_SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0B }; - // static final byte[] CODE_SSL_DH_DSS_WITH_DES_CBC_SHA = { 0x00, 0x0C }; - // static final byte[] CODE_SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x0D }; - // static final byte[] CODE_SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0E }; - // static final byte[] CODE_SSL_DH_RSA_WITH_DES_CBC_SHA = { 0x00, 0x0F }; - // static final byte[] CODE_SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x10 }; - // END android-removed - static final byte[] CODE_SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x11 }; - static final byte[] CODE_SSL_DHE_DSS_WITH_DES_CBC_SHA = { 0x00, 0x12 }; - static final byte[] CODE_SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x13 }; - static final byte[] CODE_SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x14 }; - static final byte[] CODE_SSL_DHE_RSA_WITH_DES_CBC_SHA = { 0x00, 0x15 }; - static final byte[] CODE_SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x16 }; - static final byte[] CODE_SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x17 }; - static final byte[] CODE_SSL_DH_anon_WITH_RC4_128_MD5 = { 0x00, 0x18 }; - static final byte[] CODE_SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x19 }; - static final byte[] CODE_SSL_DH_anon_WITH_DES_CBC_SHA = { 0x00, 0x1A }; - static final byte[] CODE_SSL_DH_anon_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x1B }; - - // AES Cipher Suites from RFC 3268 - http://www.ietf.org/rfc/rfc3268.txt - static final byte[] CODE_TLS_RSA_WITH_AES_128_CBC_SHA = { 0x00, 0x2F }; - //static final byte[] CODE_TLS_DH_DSS_WITH_AES_128_CBC_SHA = { 0x00, 0x30 }; - //static final byte[] CODE_TLS_DH_RSA_WITH_AES_128_CBC_SHA = { 0x00, 0x31 }; - static final byte[] CODE_TLS_DHE_DSS_WITH_AES_128_CBC_SHA = { 0x00, 0x32 }; - static final byte[] CODE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = { 0x00, 0x33 }; - static final byte[] CODE_TLS_DH_anon_WITH_AES_128_CBC_SHA = { 0x00, 0x34 }; - static final byte[] CODE_TLS_RSA_WITH_AES_256_CBC_SHA = { 0x00, 0x35 }; - //static final byte[] CODE_TLS_DH_DSS_WITH_AES_256_CBC_SHA = { 0x00, 0x36 }; - //static final byte[] CODE_TLS_DH_RSA_WITH_AES_256_CBC_SHA = { 0x00, 0x37 }; - static final byte[] CODE_TLS_DHE_DSS_WITH_AES_256_CBC_SHA = { 0x00, 0x38 }; - static final byte[] CODE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = { 0x00, 0x39 }; - static final byte[] CODE_TLS_DH_anon_WITH_AES_256_CBC_SHA = { 0x00, 0x3A }; - - // EC Cipher Suites from RFC 4492 - http://www.ietf.org/rfc/rfc4492.txt - static final byte[] CODE_TLS_ECDH_ECDSA_WITH_NULL_SHA = { (byte) 0xc0, 0x01}; - static final byte[] CODE_TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { (byte) 0xc0, 0x02}; - static final byte[] CODE_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { (byte) 0xc0, 0x03}; - static final byte[] CODE_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { (byte) 0xc0, 0x04}; - static final byte[] CODE_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { (byte) 0xc0, 0x05}; - static final byte[] CODE_TLS_ECDHE_ECDSA_WITH_NULL_SHA = { (byte) 0xc0, 0x06}; - static final byte[] CODE_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { (byte) 0xc0, 0x07}; - static final byte[] CODE_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { (byte) 0xc0, 0x08}; - static final byte[] CODE_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { (byte) 0xc0, 0x09}; - static final byte[] CODE_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { (byte) 0xc0, 0x0A}; - static final byte[] CODE_TLS_ECDH_RSA_WITH_NULL_SHA = { (byte) 0xc0, 0x0B}; - static final byte[] CODE_TLS_ECDH_RSA_WITH_RC4_128_SHA = { (byte) 0xc0, 0x0C}; - static final byte[] CODE_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { (byte) 0xc0, 0x0D}; - static final byte[] CODE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { (byte) 0xc0, 0x0E}; - static final byte[] CODE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { (byte) 0xc0, 0x0F}; - static final byte[] CODE_TLS_ECDHE_RSA_WITH_NULL_SHA = { (byte) 0xc0, 0x10}; - static final byte[] CODE_TLS_ECDHE_RSA_WITH_RC4_128_SHA = { (byte) 0xc0, 0x11}; - static final byte[] CODE_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { (byte) 0xc0, 0x12}; - static final byte[] CODE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { (byte) 0xc0, 0x13}; - static final byte[] CODE_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { (byte) 0xc0, 0x14}; - static final byte[] CODE_TLS_ECDH_anon_WITH_NULL_SHA = { (byte) 0xc0, 0x15}; - static final byte[] CODE_TLS_ECDH_anon_WITH_RC4_128_SHA = { (byte) 0xc0, 0x16}; - static final byte[] CODE_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { (byte) 0xc0, 0x17}; - static final byte[] CODE_TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { (byte) 0xc0, 0x18}; - static final byte[] CODE_TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { (byte) 0xc0, 0x19}; - - static final CipherSuite SSL_NULL_WITH_NULL_NULL = new CipherSuite( - "SSL_NULL_WITH_NULL_NULL", true, 0, null, null, null, - CODE_SSL_NULL_WITH_NULL_NULL); - - static final CipherSuite SSL_RSA_WITH_NULL_MD5 = new CipherSuite( - "SSL_RSA_WITH_NULL_MD5", true, KEY_EXCHANGE_RSA, "RSA", null, "MD5", - CODE_SSL_RSA_WITH_NULL_MD5); - - static final CipherSuite SSL_RSA_WITH_NULL_SHA = new CipherSuite( - "SSL_RSA_WITH_NULL_SHA", true, KEY_EXCHANGE_RSA, "RSA", null, "SHA", - CODE_SSL_RSA_WITH_NULL_SHA); - - static final CipherSuite SSL_RSA_EXPORT_WITH_RC4_40_MD5 = new CipherSuite( - "SSL_RSA_EXPORT_WITH_RC4_40_MD5", true, KEY_EXCHANGE_RSA_EXPORT, - "RSA", "RC4_40", "MD5", CODE_SSL_RSA_EXPORT_WITH_RC4_40_MD5); - - static final CipherSuite SSL_RSA_WITH_RC4_128_MD5 = new CipherSuite( - "SSL_RSA_WITH_RC4_128_MD5", false, KEY_EXCHANGE_RSA, "RSA", "RC4_128", - "MD5", CODE_SSL_RSA_WITH_RC4_128_MD5); - - static final CipherSuite SSL_RSA_WITH_RC4_128_SHA = new CipherSuite( - "SSL_RSA_WITH_RC4_128_SHA", false, KEY_EXCHANGE_RSA, "RSA", "RC4_128", - "SHA", CODE_SSL_RSA_WITH_RC4_128_SHA); - - static final CipherSuite SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = new CipherSuite( - "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", true, KEY_EXCHANGE_RSA_EXPORT, - "RSA", "RC2_CBC_40", "MD5", CODE_SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5); - - // BEGIN android-removed - // static final CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = new CipherSuite( - // "TLS_RSA_WITH_IDEA_CBC_SHA", false, KEY_EXCHANGE_RSA, "RSA", "IDEA_CBC", - // "SHA", CODE_TLS_RSA_WITH_IDEA_CBC_SHA); - // END android-removed - - static final CipherSuite SSL_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( - "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", true, KEY_EXCHANGE_RSA_EXPORT, - "RSA", "DES40_CBC", "SHA", CODE_SSL_RSA_EXPORT_WITH_DES40_CBC_SHA); - - static final CipherSuite SSL_RSA_WITH_DES_CBC_SHA = new CipherSuite( - "SSL_RSA_WITH_DES_CBC_SHA", false, KEY_EXCHANGE_RSA, "RSA", "DES_CBC", - "SHA", CODE_SSL_RSA_WITH_DES_CBC_SHA); - - static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite( - "SSL_RSA_WITH_3DES_EDE_CBC_SHA", false, KEY_EXCHANGE_RSA, - "RSA", "3DES_EDE_CBC", "SHA", CODE_SSL_RSA_WITH_3DES_EDE_CBC_SHA); - - // BEGIN android-removed - // static final CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( - // "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", true, - // KEY_EXCHANGE_DH_DSS_EXPORT, "DH", "DES40_CBC", "SHA", - // CODE_SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); - // - // static final CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = new CipherSuite( - // "SSL_DH_DSS_WITH_DES_CBC_SHA", false, KEY_EXCHANGE_DH_DSS, - // "DH", "DES_CBC", "SHA", CODE_SSL_DH_DSS_WITH_DES_CBC_SHA); - // - // static final CipherSuite SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA = new CipherSuite( - // "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", false, KEY_EXCHANGE_DH_DSS, - // "DH", "3DES_EDE_CBC", "SHA", CODE_SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA); - // - // static final CipherSuite SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( - // "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", true, - // KEY_EXCHANGE_DH_RSA_EXPORT, "DH", "DES40_CBC", "SHA", - // CODE_SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); - // - // static final CipherSuite SSL_DH_RSA_WITH_DES_CBC_SHA = new CipherSuite( - // "SSL_DH_RSA_WITH_DES_CBC_SHA", false, KEY_EXCHANGE_DH_RSA, - // "DH", "DES_CBC", "SHA", CODE_SSL_DH_RSA_WITH_DES_CBC_SHA); - // - // static final CipherSuite SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite( - // "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", false, KEY_EXCHANGE_DH_RSA, - // "DH", "3DES_EDE_CBC", "SHA", CODE_SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA); - // END android-removed - - static final CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( - "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", true, - KEY_EXCHANGE_DHE_DSS_EXPORT, "DSA", "DES40_CBC", "SHA", - CODE_SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA); - - static final CipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA = new CipherSuite( - "SSL_DHE_DSS_WITH_DES_CBC_SHA", false, KEY_EXCHANGE_DHE_DSS, - "DSA", "DES_CBC", "SHA", CODE_SSL_DHE_DSS_WITH_DES_CBC_SHA); - - static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = new CipherSuite( - "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", false, KEY_EXCHANGE_DHE_DSS, - "DSA", "3DES_EDE_CBC", "SHA", CODE_SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA); - - static final CipherSuite SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( - "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", true, - KEY_EXCHANGE_DHE_RSA_EXPORT, "RSA", "DES40_CBC", "SHA", - CODE_SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA); - - static final CipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA = new CipherSuite( - "SSL_DHE_RSA_WITH_DES_CBC_SHA", false, KEY_EXCHANGE_DHE_RSA, - "RSA", "DES_CBC", "SHA", CODE_SSL_DHE_RSA_WITH_DES_CBC_SHA); - - static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite( - "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", false, KEY_EXCHANGE_DHE_RSA, - "RSA", "3DES_EDE_CBC", "SHA", CODE_SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA); - - static final CipherSuite SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = new CipherSuite( - "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", true, - KEY_EXCHANGE_DH_anon_EXPORT, "DH", "RC4_40", "MD5", - CODE_SSL_DH_anon_EXPORT_WITH_RC4_40_MD5); - - static final CipherSuite SSL_DH_anon_WITH_RC4_128_MD5 = new CipherSuite( - "SSL_DH_anon_WITH_RC4_128_MD5", false, KEY_EXCHANGE_DH_anon, - "DH", "RC4_128", "MD5", CODE_SSL_DH_anon_WITH_RC4_128_MD5); - - static final CipherSuite SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite( - "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", true, - KEY_EXCHANGE_DH_anon_EXPORT, "DH", "DES40_CBC", "SHA", - CODE_SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA); - - static final CipherSuite SSL_DH_anon_WITH_DES_CBC_SHA = new CipherSuite( - "SSL_DH_anon_WITH_DES_CBC_SHA", false, KEY_EXCHANGE_DH_anon, - "DH", "DES_CBC", "SHA", CODE_SSL_DH_anon_WITH_DES_CBC_SHA); - - static final CipherSuite SSL_DH_anon_WITH_3DES_EDE_CBC_SHA = new CipherSuite( - "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", false, KEY_EXCHANGE_DH_anon, - "DH", "3DES_EDE_CBC", "SHA", CODE_SSL_DH_anon_WITH_3DES_EDE_CBC_SHA); - - static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_RSA, - "RSA", - "AES_128_CBC", - "SHA", - CODE_TLS_RSA_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_DHE_DSS, - "DSA", - "AES_128_CBC", - "SHA", - CODE_TLS_DHE_DSS_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_DHE_RSA, - "RSA", - "AES_128_CBC", - "SHA", - CODE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_DH_anon_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_DH_anon, - "DH", - "AES_128_CBC", - "SHA", - CODE_TLS_DH_anon_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_RSA_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_RSA, - "RSA", - "AES_256_CBC", - "SHA", - CODE_TLS_RSA_WITH_AES_256_CBC_SHA); - static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_DHE_DSS, - "DSA", - "AES_256_CBC", - "SHA", - CODE_TLS_DHE_DSS_WITH_AES_256_CBC_SHA); - static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_DHE_RSA, - "RSA", - "AES_256_CBC", - "SHA", - CODE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA); - static final CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_DH_anon_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_DH_anon, - "DH", - "AES_256_CBC", - "SHA", - CODE_TLS_DH_anon_WITH_AES_256_CBC_SHA); - - static final CipherSuite TLS_ECDH_ECDSA_WITH_NULL_SHA - = new CipherSuite("TLS_ECDH_ECDSA_WITH_NULL_SHA", - false, - KEY_EXCHANGE_ECDH_ECDSA, - "EC", - null, - "SHA", - CODE_TLS_ECDH_ECDSA_WITH_NULL_SHA); - static final CipherSuite TLS_ECDH_ECDSA_WITH_RC4_128_SHA - = new CipherSuite("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", - false, - KEY_EXCHANGE_ECDH_ECDSA, - "EC", - "RC4_128", - "SHA", - CODE_TLS_ECDH_ECDSA_WITH_RC4_128_SHA); - static final CipherSuite TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - = new CipherSuite("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_ECDSA, - "EC", - "3DES_EDE_CBC", - "SHA", - CODE_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA); - static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_ECDSA, - "EC", - "AES_128_CBC", - "SHA", - CODE_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_ECDSA, - "EC", - "AES_256_CBC", - "SHA", - CODE_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA); - static final CipherSuite TLS_ECDHE_ECDSA_WITH_NULL_SHA - = new CipherSuite("TLS_ECDHE_ECDSA_WITH_NULL_SHA", - false, - KEY_EXCHANGE_ECDHE_ECDSA, - "EC", - null, - "SHA", - CODE_TLS_ECDHE_ECDSA_WITH_NULL_SHA); - static final CipherSuite TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - = new CipherSuite("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - false, - KEY_EXCHANGE_ECDHE_ECDSA, - "EC", - "RC4_128", - "SHA", - CODE_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA); - static final CipherSuite TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - = new CipherSuite("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", - false, - KEY_EXCHANGE_ECDHE_ECDSA, - "EC", - "3DES_EDE_CBC", - "SHA", - CODE_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA); - static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_ECDHE_ECDSA, - "EC", - "AES_128_CBC", - "SHA", - CODE_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_ECDHE_ECDSA, - "EC", - "AES_256_CBC", - "SHA", - CODE_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA); - static final CipherSuite TLS_ECDH_RSA_WITH_NULL_SHA - = new CipherSuite("TLS_ECDH_RSA_WITH_NULL_SHA", - false, - KEY_EXCHANGE_ECDH_RSA, - "EC", - null, - "SHA", - CODE_TLS_ECDH_RSA_WITH_NULL_SHA); - static final CipherSuite TLS_ECDH_RSA_WITH_RC4_128_SHA - = new CipherSuite("TLS_ECDH_RSA_WITH_RC4_128_SHA", - false, - KEY_EXCHANGE_ECDH_RSA, - "EC", - "RC4_128", - "SHA", - CODE_TLS_ECDH_RSA_WITH_RC4_128_SHA); - static final CipherSuite TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - = new CipherSuite("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_RSA, - "EC", - "3DES_EDE_CBC", - "SHA", - CODE_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA); - static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_RSA, - "EC", - "AES_128_CBC", - "SHA", - CODE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_RSA, - "EC", - "AES_256_CBC", - "SHA", - CODE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA); - static final CipherSuite TLS_ECDHE_RSA_WITH_NULL_SHA - = new CipherSuite("TLS_ECDHE_RSA_WITH_NULL_SHA", - false, - KEY_EXCHANGE_ECDHE_RSA, - "EC", - null, - "SHA", - CODE_TLS_ECDHE_RSA_WITH_NULL_SHA); - static final CipherSuite TLS_ECDHE_RSA_WITH_RC4_128_SHA - = new CipherSuite("TLS_ECDHE_RSA_WITH_RC4_128_SHA", - false, - KEY_EXCHANGE_ECDHE_RSA, - "EC", - "RC4_128", - "SHA", - CODE_TLS_ECDHE_RSA_WITH_RC4_128_SHA); - static final CipherSuite TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - = new CipherSuite("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - false, - KEY_EXCHANGE_ECDHE_RSA, - "EC", - "3DES_EDE_CBC", - "SHA", - CODE_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA); - static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_ECDHE_RSA, - "EC", - "AES_128_CBC", - "SHA", - CODE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_ECDHE_RSA, - "EC", - "AES_256_CBC", - "SHA", - CODE_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA); - static final CipherSuite TLS_ECDH_anon_WITH_NULL_SHA - = new CipherSuite("TLS_ECDH_anon_WITH_NULL_SHA", - false, - KEY_EXCHANGE_ECDH_anon, - "EC", - null, - "SHA", - CODE_TLS_ECDH_anon_WITH_NULL_SHA); - static final CipherSuite TLS_ECDH_anon_WITH_RC4_128_SHA - = new CipherSuite("TLS_ECDH_anon_WITH_RC4_128_SHA", - false, - KEY_EXCHANGE_ECDH_anon, - "EC", - "RC4_128", - "SHA", - CODE_TLS_ECDH_anon_WITH_RC4_128_SHA); - static final CipherSuite TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA - = new CipherSuite("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_anon, - "EC", - "3DES_EDE_CBC", - "SHA", - CODE_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA); - static final CipherSuite TLS_ECDH_anon_WITH_AES_128_CBC_SHA - = new CipherSuite("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_anon, - "EC", - "AES_128_CBC", - "SHA", - CODE_TLS_ECDH_anon_WITH_AES_128_CBC_SHA); - static final CipherSuite TLS_ECDH_anon_WITH_AES_256_CBC_SHA - = new CipherSuite("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", - false, - KEY_EXCHANGE_ECDH_anon, - "EC", - "AES_256_CBC", - "SHA", - CODE_TLS_ECDH_anon_WITH_AES_256_CBC_SHA); - - // arrays for quick access to cipher suite by code - private static final CipherSuite[] SUITES_BY_CODE_0x00 = { - // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml - SSL_NULL_WITH_NULL_NULL, // { 0x00, 0x00 }; - SSL_RSA_WITH_NULL_MD5, // { 0x00, 0x01 }; - SSL_RSA_WITH_NULL_SHA, // { 0x00, 0x02 }; - SSL_RSA_EXPORT_WITH_RC4_40_MD5, // { 0x00, 0x03 }; - SSL_RSA_WITH_RC4_128_MD5, // { 0x00, 0x04 }; - SSL_RSA_WITH_RC4_128_SHA, // { 0x00, 0x05 }; - // BEGIN android-changed - null, // SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, // { 0x00, 0x06 }; - null, // TLS_RSA_WITH_IDEA_CBC_SHA, // { 0x00, 0x07 }; - // END android-changed - SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, // { 0x00, 0x08 }; - SSL_RSA_WITH_DES_CBC_SHA, // { 0x00, 0x09 }; - SSL_RSA_WITH_3DES_EDE_CBC_SHA, // { 0x00, 0x0a }; - // BEGIN android-changed - null, // SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA // { 0x00, 0x0b }; - null, // SSL_DH_DSS_WITH_DES_CBC_SHA, // { 0x00, 0x0c }; - null, // SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA, // { 0x00, 0x0d }; - null, // SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, // { 0x00, 0x0e }; - null, // SSL_DH_RSA_WITH_DES_CBC_SHA, // { 0x00, 0x0f }; - null, // SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA, // { 0x00, 0x10 }; - // END android-changed - SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, // { 0x00, 0x11 }; - SSL_DHE_DSS_WITH_DES_CBC_SHA, // { 0x00, 0x12 }; - SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, // { 0x00, 0x13 }; - SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, // { 0x00, 0x14 }; - SSL_DHE_RSA_WITH_DES_CBC_SHA, // { 0x00, 0x15 }; - SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, // { 0x00, 0x16 }; - SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, // { 0x00, 0x17 }; - SSL_DH_anon_WITH_RC4_128_MD5, // { 0x00, 0x18 }; - SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, // { 0x00, 0x19 }; - SSL_DH_anon_WITH_DES_CBC_SHA, // { 0x00, 0x1A }; - SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, // { 0x00, 0x1B }; - // BEGIN android-added - null, // SSL_FORTEZZA_KEA_WITH_NULL_SHA // { 0x00, 0x1C }; - null, // SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA // { 0x00, 0x1D }; - null, // TLS_KRB5_WITH_DES_CBC_SHA // { 0x00, 0x1E }; - null, // TLS_KRB5_WITH_3DES_EDE_CBC_SHA // { 0x00, 0x1F }; - null, // TLS_KRB5_WITH_RC4_128_SHA // { 0x00, 0x20 }; - null, // TLS_KRB5_WITH_IDEA_CBC_SHA // { 0x00, 0x21 }; - null, // TLS_KRB5_WITH_DES_CBC_MD5 // { 0x00, 0x22 }; - null, // TLS_KRB5_WITH_3DES_EDE_CBC_MD5 // { 0x00, 0x23 }; - null, // TLS_KRB5_WITH_RC4_128_MD5 // { 0x00, 0x24 }; - null, // TLS_KRB5_WITH_IDEA_CBC_MD5 // { 0x00, 0x25 }; - null, // TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA // { 0x00, 0x26 }; - null, // TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA // { 0x00, 0x27 }; - null, // TLS_KRB5_EXPORT_WITH_RC4_40_SHA // { 0x00, 0x28 }; - null, // TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 // { 0x00, 0x29 }; - null, // TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 // { 0x00, 0x2A }; - null, // TLS_KRB5_EXPORT_WITH_RC4_40_MD5 // { 0x00, 0x2B }; - null, // TLS_PSK_WITH_NULL_SHA // { 0x00, 0x2C }; - null, // TLS_DHE_PSK_WITH_NULL_SHA // { 0x00, 0x2D }; - null, // TLS_RSA_PSK_WITH_NULL_SHA // { 0x00, 0x2E }; - TLS_RSA_WITH_AES_128_CBC_SHA, // { 0x00, 0x2F }; - null, // TLS_DH_DSS_WITH_AES_128_CBC_SHA // { 0x00, 0x30 }; - null, // TLS_DH_RSA_WITH_AES_128_CBC_SHA // { 0x00, 0x31 }; - TLS_DHE_DSS_WITH_AES_128_CBC_SHA, // { 0x00, 0x32 }; - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, // { 0x00, 0x33 }; - TLS_DH_anon_WITH_AES_128_CBC_SHA, // { 0x00, 0x34 }; - TLS_RSA_WITH_AES_256_CBC_SHA, // { 0x00, 0x35 }; - null, // TLS_DH_DSS_WITH_AES_256_CBC_SHA, // { 0x00, 0x36 }; - null, // TLS_DH_RSA_WITH_AES_256_CBC_SHA, // { 0x00, 0x37 }; - TLS_DHE_DSS_WITH_AES_256_CBC_SHA, // { 0x00, 0x38 }; - TLS_DHE_RSA_WITH_AES_256_CBC_SHA, // { 0x00, 0x39 }; - TLS_DH_anon_WITH_AES_256_CBC_SHA, // { 0x00, 0x3A }; - // END android-added - }; - private static final CipherSuite[] SUITES_BY_CODE_0xc0 = { - null, // { 0xc0, 0x00}; - TLS_ECDH_ECDSA_WITH_NULL_SHA, // { 0xc0, 0x01}; - TLS_ECDH_ECDSA_WITH_RC4_128_SHA, // { 0xc0, 0x02}; - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x03}; - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, // { 0xc0, 0x04}; - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, // { 0xc0, 0x05}; - TLS_ECDHE_ECDSA_WITH_NULL_SHA, // { 0xc0, 0x06}; - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, // { 0xc0, 0x07}; - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x08}; - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, // { 0xc0, 0x09}; - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, // { 0xc0, 0x0A}; - TLS_ECDH_RSA_WITH_NULL_SHA, // { 0xc0, 0x0B}; - TLS_ECDH_RSA_WITH_RC4_128_SHA, // { 0xc0, 0x0C}; - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x0D}; - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, // { 0xc0, 0x0E}; - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, // { 0xc0, 0x0F}; - TLS_ECDHE_RSA_WITH_NULL_SHA, // { 0xc0, 0x10}; - TLS_ECDHE_RSA_WITH_RC4_128_SHA, // { 0xc0, 0x11}; - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x12}; - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, // { 0xc0, 0x13}; - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, // { 0xc0, 0x14}; - TLS_ECDH_anon_WITH_NULL_SHA, // { 0xc0, 0x15}; - TLS_ECDH_anon_WITH_RC4_128_SHA, // { 0xc0, 0x16}; - TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x17}; - TLS_ECDH_anon_WITH_AES_128_CBC_SHA, // { 0xc0, 0x18}; - TLS_ECDH_anon_WITH_AES_256_CBC_SHA, // { 0xc0, 0x19}; - // TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x1A}; - // TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x1B}; - // TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x1C}; - // TLS_SRP_SHA_WITH_AES_128_CBC_SHA, // { 0xc0, 0x1D}; - // TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, // { 0xc0, 0x1E}; - // TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, // { 0xc0, 0x1F}; - // TLS_SRP_SHA_WITH_AES_256_CBC_SHA, // { 0xc0, 0x20}; - // TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, // { 0xc0, 0x21}; - // TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, // { 0xc0, 0x22}; - // TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // { 0xc0, 0x23}; - // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, // { 0xc0, 0x24}; - // TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, // { 0xc0, 0x25}; - // TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, // { 0xc0, 0x26}; - // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // { 0xc0, 0x27}; - // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, // { 0xc0, 0x28}; - // TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, // { 0xc0, 0x29}; - // TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, // { 0xc0, 0x2A}; - // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // { 0xc0, 0x2B}; - // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, // { 0xc0, 0x2C}; - // TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, // { 0xc0, 0x2D}; - // TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, // { 0xc0, 0x2E}; - // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // { 0xc0, 0x2F}; - // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, // { 0xc0, 0x30}; - // TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, // { 0xc0, 0x31}; - // TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, // { 0xc0, 0x32}; - // TLS_ECDHE_PSK_WITH_RC4_128_SHA, // { 0xc0, 0x33}; - // TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, // { 0xc0, 0x34}; - // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, // { 0xc0, 0x35}; - // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, // { 0xc0, 0x36}; - // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, // { 0xc0, 0x37}; - // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, // { 0xc0, 0x38}; - // TLS_ECDHE_PSK_WITH_NULL_SHA, // { 0xc0, 0x39}; - // TLS_ECDHE_PSK_WITH_NULL_SHA256, // { 0xc0, 0x3A}; - // TLS_ECDHE_PSK_WITH_NULL_SHA384, // { 0xc0, 0x3B}; - }; - - // hash for quick access to cipher suite by name - private static final Hashtable<String, CipherSuite> SUITES_BY_NAME; - - /** - * array of supported cipher suites. - * Set of supported suites is defined at the moment provider's start - */ - // TODO Dynamically supported suites: new providers may be dynamically - // added/removed and the set of supported suites may be changed - static final CipherSuite[] SUPPORTED_CIPHER_SUITES; - - /** - * array of supported cipher suites names - */ - static final String[] SUPPORTED_CIPHER_SUITE_NAMES; - - /** - * default cipher suites - */ - static final CipherSuite[] DEFAULT_CIPHER_SUITES; - - static { - SUITES_BY_NAME = new Hashtable<String, CipherSuite>(); - int count_0x00 = registerCipherSuitesByCode(SUITES_BY_CODE_0x00); - int count_0xc0 = registerCipherSuitesByCode(SUITES_BY_CODE_0xc0); - int count = count_0x00 + count_0xc0; - SUPPORTED_CIPHER_SUITES = new CipherSuite[count]; - SUPPORTED_CIPHER_SUITE_NAMES = new String[count]; - registerSupportedCipherSuites(0, SUITES_BY_CODE_0x00); - registerSupportedCipherSuites(count_0x00, SUITES_BY_CODE_0xc0); - - CipherSuite[] defaultCipherSuites = { - SSL_RSA_WITH_RC4_128_MD5, - SSL_RSA_WITH_RC4_128_SHA, - TLS_RSA_WITH_AES_128_CBC_SHA, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - SSL_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 - }; - count = 0; - for (int i = 0; i < defaultCipherSuites.length; i++) { - if (defaultCipherSuites[i].supported) { - count++; - } - } - DEFAULT_CIPHER_SUITES = new CipherSuite[count]; - count = 0; - for (int i = 0; i < defaultCipherSuites.length; i++) { - if (defaultCipherSuites[i].supported) { - DEFAULT_CIPHER_SUITES[count++] = defaultCipherSuites[i]; - } - } - } - private static int registerCipherSuitesByCode(CipherSuite[] cipherSuites) { - int count = 0; - for (int i = 0; i < cipherSuites.length; i++) { - if (cipherSuites[i] == SSL_NULL_WITH_NULL_NULL) { - continue; - } - if (cipherSuites[i] == null) { - continue; - } - SUITES_BY_NAME.put(cipherSuites[i].getName(), cipherSuites[i]); - if (cipherSuites[i].supported) { - count++; - } - } - return count; - } - private static void registerSupportedCipherSuites(int offset, CipherSuite[] cipherSuites) { - int count = offset; - for (int i = 0; i < cipherSuites.length; i++) { - if (cipherSuites[i] == SSL_NULL_WITH_NULL_NULL) { - continue; - } - if (cipherSuites[i] == null) { - continue; - } - if (cipherSuites[i].supported) { - SUPPORTED_CIPHER_SUITES[count] = cipherSuites[i]; - SUPPORTED_CIPHER_SUITE_NAMES[count] = SUPPORTED_CIPHER_SUITES[count].getName(); - count++; - } - } - } - - /** - * Returns CipherSuite by name - */ - public static CipherSuite getByName(String name) { - return SUITES_BY_NAME.get(name); - } - - /** - * Returns CipherSuite based on TLS CipherSuite code - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., A.5. The CipherSuite</a> - */ - public static CipherSuite getByCode(byte b1, byte b2) { - int i1 = b1 & 0xff; - int i2 = b2 & 0xff; - CipherSuite cs = getCipherSuiteByCode(0, i1, i2); - if (cs != null) { - return cs; - } - return new CipherSuite("UNKNOWN_" + i1 + "_" + i2, false, 0, null, - null, null, new byte[] { b1, b2 }); - } - - /** - * Returns CipherSuite based on V2CipherSpec code - * as described in TLS 1.0 spec., E. Backward Compatibility With SSL - */ - public static CipherSuite getByCode(byte b1, byte b2, byte b3) { - int i1 = b1 & 0xff; - int i2 = b2 & 0xff; - int i3 = b3 & 0xff; - CipherSuite cs = getCipherSuiteByCode(i1, i2, i3); - if (cs != null) { - return cs; - } - return new CipherSuite("UNKNOWN_" + i1 + "_" + i2 + "_" + i3, false, 0, - null, null, null, new byte[] { b1, b2, b3 }); - } - - private static CipherSuite getCipherSuiteByCode(int i1, int i2, int i3) { - CipherSuite[] cipherSuites; - if (i1 == 0x00 && i2 == 0x00) { - cipherSuites = SUITES_BY_CODE_0x00; - } else if (i1 == 0x00 && i2 == 0xc0) { - cipherSuites = SUITES_BY_CODE_0xc0; - } else { - return null; - } - if (i3 >= cipherSuites.length) { - return null; - } - return cipherSuites[i3]; - } - - /** - * Creates CipherSuite - */ - private CipherSuite(String name, boolean isExportable, int keyExchange, - String authType, String cipherName, String hash, byte[] code) { - this.name = name; - this.keyExchange = keyExchange; - this.authType = authType; - this.isExportable = isExportable; - if (cipherName == null) { - this.cipherName = null; - keyMaterial = 0; - expandedKeyMaterial = 0; - effectiveKeyBytes = 0; - ivSize = 0; - blockSize = 0; - // BEGIN android-removed - // } else if ("IDEA_CBC".equals(cipherName)) { - // this.cipherName = "IDEA/CBC/NoPadding"; - // keyMaterial = 16; - // expandedKeyMaterial = 16; - // effectiveKeyBytes = 16; - // ivSize = 8; - // blockSize = 8; - // } else if ("RC2_CBC_40".equals(cipherName)) { - // this.cipherName = "RC2/CBC/NoPadding"; - // keyMaterial = 5; - // expandedKeyMaterial = 16; - // effectiveKeyBytes = 5; - // ivSize = 8; - // blockSize = 8; - // END android-removed - } else if ("RC4_40".equals(cipherName)) { - this.cipherName = "RC4"; - keyMaterial = 5; - expandedKeyMaterial = 16; - effectiveKeyBytes = 5; - ivSize = 0; - blockSize = 0; - } else if ("RC4_128".equals(cipherName)) { - this.cipherName = "RC4"; - keyMaterial = 16; - expandedKeyMaterial = 16; - effectiveKeyBytes = 16; - ivSize = 0; - blockSize = 0; - } else if ("DES40_CBC".equals(cipherName)) { - this.cipherName = "DES/CBC/NoPadding"; - keyMaterial = 5; - expandedKeyMaterial = 8; - effectiveKeyBytes = 5; - ivSize = 8; - blockSize = 8; - } else if ("DES_CBC".equals(cipherName)) { - this.cipherName = "DES/CBC/NoPadding"; - keyMaterial = 8; - expandedKeyMaterial = 8; - effectiveKeyBytes = 7; - ivSize = 8; - blockSize = 8; - } else if ("3DES_EDE_CBC".equals(cipherName)) { - this.cipherName = "DESede/CBC/NoPadding"; - keyMaterial = 24; - expandedKeyMaterial = 24; - effectiveKeyBytes = 24; - ivSize = 8; - blockSize = 8; - } else if ("AES_128_CBC".equals(cipherName)) { - this.cipherName = "AES/CBC/NoPadding"; - keyMaterial = 16; - expandedKeyMaterial = 16; - effectiveKeyBytes = 16; - ivSize = 16; - blockSize = 16; - } else if ("AES_256_CBC".equals(cipherName)) { - this.cipherName = "AES/CBC/NoPadding"; - keyMaterial = 32; - expandedKeyMaterial = 32; - effectiveKeyBytes = 32; - ivSize = 16; - blockSize = 16; - } else { - this.cipherName = cipherName; - keyMaterial = 0; - expandedKeyMaterial = 0; - effectiveKeyBytes = 0; - ivSize = 0; - blockSize = 0; - } - - if ("MD5".equals(hash)) { - this.hmacName = "HmacMD5"; - this.hashName = "MD5"; - hashSize = 16; - } else if ("SHA".equals(hash)) { - this.hmacName = "HmacSHA1"; - this.hashName = "SHA-1"; - hashSize = 20; - } else { - this.hmacName = null; - this.hashName = null; - hashSize = 0; - } - - cipherSuiteCode = code; - - if (this.cipherName != null) { - try { - Cipher.getInstance(this.cipherName); - } catch (GeneralSecurityException e) { - supported = false; - } - } - - // We define the Elliptic Curve cipher suites for use with - // code shared by OpenSSL, but they are not supported by - // SSLEngine or SSLSocket's built with SSLEngine. - if (this.name.startsWith("TLS_EC")) { - supported = false; - } - } - - /** - * Returns true if cipher suite is anonymous - */ - public boolean isAnonymous() { - if (keyExchange == KEY_EXCHANGE_DH_anon - || keyExchange == KEY_EXCHANGE_DH_anon_EXPORT - || keyExchange == KEY_EXCHANGE_ECDH_anon) { - return true; - } - return false; - } - - /** - * Returns array of supported CipherSuites - */ - public static CipherSuite[] getSupported() { - return SUPPORTED_CIPHER_SUITES; - } - - /** - * Returns array of supported cipher suites names - */ - public static String[] getSupportedCipherSuiteNames() { - return SUPPORTED_CIPHER_SUITE_NAMES.clone(); - } - - /** - * Returns cipher suite name - */ - public String getName() { - return name; - } - - /** - * Returns cipher suite code as byte array - */ - public byte[] toBytes() { - return cipherSuiteCode; - } - - /** - * Returns cipher suite description - */ - @Override - public String toString() { - return name + ": " + cipherSuiteCode[0] + " " + cipherSuiteCode[1]; - } - - /** - * Returns cipher algorithm name - */ - public String getBulkEncryptionAlgorithm() { - return cipherName; - } - - /** - * Returns cipher block size - */ - public int getBlockSize() { - return blockSize; - } - - /** - * Returns MAC algorithm name - */ - public String getHmacName() { - return hmacName; - } - - /** - * Returns hash algorithm name - */ - public String getHashName() { - return hashName; - } - - /** - * Returns hash size - */ - public int getMACLength() { - return hashSize; - } - - /** - * Indicates whether this cipher suite is exportable - */ - public boolean isExportable() { - return isExportable; - } - - static final String KEY_TYPE_RSA = "RSA"; - static final String KEY_TYPE_DSA = "DSA"; - static final String KEY_TYPE_DH_RSA = "DH_RSA"; - static final String KEY_TYPE_DH_DSA = "DH_DSA"; - static final String KEY_TYPE_EC = "EC"; - static final String KEY_TYPE_EC_EC = "EC_EC"; - static final String KEY_TYPE_EC_RSA = "EC_RSA"; - - /** - * Returns key type constant suitable for calling - * X509KeyManager.chooseServerAlias or - * X509ExtendedKeyManager.chooseEngineServerAlias. - */ - public String getServerKeyType() { - switch (keyExchange) { - case KEY_EXCHANGE_DHE_RSA: - case KEY_EXCHANGE_DHE_RSA_EXPORT: - case KEY_EXCHANGE_ECDHE_RSA: - case KEY_EXCHANGE_RSA: - case KEY_EXCHANGE_RSA_EXPORT: - return KEY_TYPE_RSA; - case KEY_EXCHANGE_DHE_DSS: - case KEY_EXCHANGE_DHE_DSS_EXPORT: - return KEY_TYPE_DSA; - case KEY_EXCHANGE_ECDH_ECDSA: - case KEY_EXCHANGE_ECDHE_ECDSA: - return KEY_TYPE_EC_EC; - case KEY_EXCHANGE_ECDH_RSA: - return KEY_TYPE_EC_RSA; - case KEY_EXCHANGE_DH_anon: - case KEY_EXCHANGE_DH_anon_EXPORT: - case KEY_EXCHANGE_ECDH_anon: - return null; - default: - throw new IllegalStateException("Unknown key type for key exchange " + keyExchange); - } - } - - /** - * Client certificate types as defined in - * TLS 1.0 spec., 7.4.4. Certificate request. - * EC constants from RFC 4492. - * Names match openssl constants. - */ - static final byte TLS_CT_RSA_SIGN = 1; - static final byte TLS_CT_DSS_SIGN = 2; - static final byte TLS_CT_RSA_FIXED_DH = 3; - static final byte TLS_CT_DSS_FIXED_DH = 4; - static final byte TLS_CT_ECDSA_SIGN = 64; - static final byte TLS_CT_RSA_FIXED_ECDH = 65; - static final byte TLS_CT_ECDSA_FIXED_ECDH = 66; - - /** - * Similar to getServerKeyType, but returns value given TLS - * ClientCertificateType byte values from a CertificateRequest - * message for use with X509KeyManager.chooseClientAlias or - * X509ExtendedKeyManager.chooseEngineClientAlias. - */ - public static String getClientKeyType(byte keyType) { - // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml - switch (keyType) { - case TLS_CT_RSA_SIGN: - return KEY_TYPE_RSA; // RFC rsa_sign - case TLS_CT_DSS_SIGN: - return KEY_TYPE_DSA; // RFC dss_sign - case TLS_CT_RSA_FIXED_DH: - return KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh - case TLS_CT_DSS_FIXED_DH: - return KEY_TYPE_DH_DSA; // RFC dss_fixed_dh - case TLS_CT_ECDSA_SIGN: - return KEY_TYPE_EC; // RFC ecdsa_sign - case TLS_CT_RSA_FIXED_ECDH: - return KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh - case TLS_CT_ECDSA_FIXED_ECDH: - return KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh - default: - return null; - } - } - - private static final String AUTH_TYPE_RSA = "RSA"; - private static final String AUTH_TYPE_RSA_EXPORT = "RSA_EXPORT"; - private static final String AUTH_TYPE_DHE_DSS = "DHE_DSS"; - private static final String AUTH_TYPE_DHE_RSA = "DHE_RSA"; - private static final String AUTH_TYPE_DH_DSS = "DH_DSS"; - private static final String AUTH_TYPE_DH_RSA = "DH_RSA"; - private static final String AUTH_TYPE_ECDH_ECDSA = "ECDH_ECDSA"; - private static final String AUTH_TYPE_ECDH_RSA = "ECDH_RSA"; - private static final String AUTH_TYPE_ECDHE_ECDSA = "ECDHE_ECDSA"; - private static final String AUTH_TYPE_ECDHE_RSA = "ECDHE_RSA"; - - /** - * Returns auth type constant suitable for calling X509TrustManager.checkServerTrusted. - */ - public String getAuthType(boolean emphemeral) { - switch (keyExchange) { - case KEY_EXCHANGE_RSA: - return AUTH_TYPE_RSA; - case KEY_EXCHANGE_RSA_EXPORT: - return emphemeral ? AUTH_TYPE_RSA_EXPORT : AUTH_TYPE_RSA; - case KEY_EXCHANGE_DHE_DSS: - case KEY_EXCHANGE_DHE_DSS_EXPORT: - return AUTH_TYPE_DHE_DSS; - case KEY_EXCHANGE_DHE_RSA: - case KEY_EXCHANGE_DHE_RSA_EXPORT: - return AUTH_TYPE_DHE_RSA; - case KEY_EXCHANGE_ECDH_ECDSA: - return AUTH_TYPE_ECDH_ECDSA; - case KEY_EXCHANGE_ECDHE_ECDSA: - return AUTH_TYPE_ECDHE_ECDSA; - case KEY_EXCHANGE_ECDH_RSA: - return AUTH_TYPE_ECDH_RSA; - case KEY_EXCHANGE_ECDHE_RSA: - return AUTH_TYPE_ECDHE_RSA; - case KEY_EXCHANGE_DH_anon: - case KEY_EXCHANGE_DH_anon_EXPORT: - case KEY_EXCHANGE_ECDH_anon: - return null; - default: - throw new IllegalStateException("Unknown auth type for key exchange " + keyExchange); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/ClientHandshakeImpl.java b/crypto/src/main/java/org/conscrypt/ClientHandshakeImpl.java deleted file mode 100644 index e22024f..0000000 --- a/crypto/src/main/java/org/conscrypt/ClientHandshakeImpl.java +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; -import javax.crypto.interfaces.DHKey; -import javax.crypto.interfaces.DHPublicKey; -import javax.crypto.spec.DHParameterSpec; -import javax.crypto.spec.DHPublicKeySpec; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.X509ExtendedKeyManager; -import javax.net.ssl.X509KeyManager; -import javax.net.ssl.X509TrustManager; -import javax.security.auth.x500.X500Principal; - -/** - * Client side handshake protocol implementation. - * Handshake protocol operates on top of the Record Protocol. - * It is responsible for session negotiating. - * - * The implementation processes inbound server handshake messages, - * creates and sends respond messages. Outbound messages are supplied - * to Record Protocol. Detected errors are reported to the Alert protocol. - * - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7. The - * TLS Handshake Protocol</a> - * - */ -public class ClientHandshakeImpl extends HandshakeProtocol { - - /** - * Creates Client Handshake Implementation - * - * @param owner - */ - ClientHandshakeImpl(Object owner) { - super(owner); - } - - /** - * Starts handshake - * - */ - @Override - public void start() { - if (session == null) { // initial handshake - session = findSessionToResume(); - } else { // start session renegotiation - if (clientHello != null && this.status != FINISHED) { - // current negotiation has not completed - return; // ignore - } - if (!session.isValid()) { - session = null; - } - } - if (session != null) { - isResuming = true; - } else if (parameters.getEnableSessionCreation()){ - isResuming = false; - session = new SSLSessionImpl(parameters.getSecureRandom()); - if (engineOwner != null) { - session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort()); - } else { - session.setPeer(socketOwner.getPeerHostName(), socketOwner.getPeerPort()); - } - session.protocol = ProtocolVersion.getLatestVersion(parameters.getEnabledProtocols()); - recordProtocol.setVersion(session.protocol.version); - } else { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "SSL Session may not be created "); - } - startSession(); - } - - /** - * Starts renegotiation on a new session - * - */ - private void renegotiateNewSession() { - if (parameters.getEnableSessionCreation()){ - isResuming = false; - session = new SSLSessionImpl(parameters.getSecureRandom()); - if (engineOwner != null) { - session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort()); - } else { - session.setPeer(socketOwner.getPeerHostName(), socketOwner.getPeerPort()); - } - session.protocol = ProtocolVersion.getLatestVersion(parameters.getEnabledProtocols()); - recordProtocol.setVersion(session.protocol.version); - startSession(); - } else { - status = NOT_HANDSHAKING; - sendWarningAlert(AlertProtocol.NO_RENEGOTIATION); - } - } - - /* - * Starts/resumes session - */ - private void startSession() { - CipherSuite[] cipher_suites; - if (isResuming) { - cipher_suites = new CipherSuite[] { session.cipherSuite }; - } else { - cipher_suites = parameters.getEnabledCipherSuitesMember(); - } - clientHello = new ClientHello(parameters.getSecureRandom(), - session.protocol.version, session.id, cipher_suites); - session.clientRandom = clientHello.random; - send(clientHello); - status = NEED_UNWRAP; - } - - /** - * Processes inbound handshake messages - * @param bytes - */ - @Override - public void unwrap(byte[] bytes) { - if (this.delegatedTaskErr != null) { - Exception e = this.delegatedTaskErr; - this.delegatedTaskErr = null; - this.fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "Error in delegated task", e); - } - int handshakeType; - io_stream.append(bytes); - while (io_stream.available() > 0) { - io_stream.mark(); - int length; - try { - handshakeType = io_stream.read(); - length = io_stream.readUint24(); - if (io_stream.available() < length) { - io_stream.reset(); - return; - } - switch (handshakeType) { - case 0: // HELLO_REQUEST - // we don't need to take this message into account - // during FINISH message verification, so remove it - io_stream.removeFromMarkedPosition(); - if (clientHello != null - && (clientFinished == null || serverFinished == null)) { - //currently negotiating - ignore - break; - } - // renegotiate - if (session.isValid()) { - session = (SSLSessionImpl) session.clone(); - isResuming = true; - startSession(); - } else { - // if SSLSession is invalidated (e.g. timeout limit is - // exceeded) connection can't resume the session. - renegotiateNewSession(); - } - break; - case 2: // SERVER_HELLO - if (clientHello == null || serverHello != null) { - unexpectedMessage(); - return; - } - serverHello = new ServerHello(io_stream, length); - - //check protocol version - ProtocolVersion servProt = ProtocolVersion.getByVersion(serverHello.server_version); - String[] enabled = parameters.getEnabledProtocols(); - find: { - for (int i = 0; i < enabled.length; i++) { - if (servProt.equals(ProtocolVersion.getByName(enabled[i]))) { - break find; - } - } - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "Bad server hello protocol version"); - } - - // check compression method - if (serverHello.compression_method != 0) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "Bad server hello compression method"); - } - - //check cipher_suite - CipherSuite[] enabledSuites = parameters.getEnabledCipherSuitesMember(); - find: { - for (int i = 0; i < enabledSuites.length; i++) { - if (serverHello.cipher_suite.equals(enabledSuites[i])) { - break find; - } - } - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "Bad server hello cipher suite"); - } - - if (isResuming) { - if (serverHello.session_id.length == 0) { - // server is not willing to establish the new connection - // using specified session - isResuming = false; - } else if (!Arrays.equals(serverHello.session_id, clientHello.session_id)) { - isResuming = false; - } else if (!session.protocol.equals(servProt)) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "Bad server hello protocol version"); - } else if (!session.cipherSuite.equals(serverHello.cipher_suite)) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "Bad server hello cipher suite"); - } - if (serverHello.server_version[1] == 1) { - computerReferenceVerifyDataTLS("server finished"); - } else { - computerReferenceVerifyDataSSLv3(SSLv3Constants.server); - } - } - session.protocol = servProt; - recordProtocol.setVersion(session.protocol.version); - session.cipherSuite = serverHello.cipher_suite; - session.id = serverHello.session_id.clone(); - session.serverRandom = serverHello.random; - break; - case 11: // CERTIFICATE - if (serverHello == null || serverKeyExchange != null - || serverCert != null || isResuming) { - unexpectedMessage(); - return; - } - serverCert = new CertificateMessage(io_stream, length); - break; - case 12: // SERVER_KEY_EXCHANGE - if (serverHello == null || serverKeyExchange != null - || isResuming) { - unexpectedMessage(); - return; - } - serverKeyExchange = new ServerKeyExchange(io_stream, - length, session.cipherSuite.keyExchange); - break; - case 13: // CERTIFICATE_REQUEST - if (serverCert == null || certificateRequest != null - || session.cipherSuite.isAnonymous() || isResuming) { - unexpectedMessage(); - return; - } - certificateRequest = new CertificateRequest(io_stream, length); - break; - case 14: // SERVER_HELLO_DONE - if (serverHello == null || serverHelloDone != null || isResuming) { - unexpectedMessage(); - return; - } - serverHelloDone = new ServerHelloDone(io_stream, length); - if (this.nonBlocking) { - delegatedTasks.add(new DelegatedTask(new Runnable() { - public void run() { - processServerHelloDone(); - } - }, this)); - return; - } - processServerHelloDone(); - break; - case 20: // FINISHED - if (!changeCipherSpecReceived) { - unexpectedMessage(); - return; - } - serverFinished = new Finished(io_stream, length); - verifyFinished(serverFinished.getData()); - session.lastAccessedTime = System.currentTimeMillis(); - session.context = parameters.getClientSessionContext(); - parameters.getClientSessionContext().putSession(session); - if (isResuming) { - sendChangeCipherSpec(); - } else { - session.lastAccessedTime = System.currentTimeMillis(); - status = FINISHED; - } - // XXX there is no cleanup work - break; - default: - unexpectedMessage(); - return; - } - } catch (IOException e) { - // io stream dosn't contain complete handshake message - io_stream.reset(); - return; - } - } - - } - - /** - * Processes SSLv2 Hello message. - * SSLv2 client hello message message is an unexpected message - * for client side of handshake protocol. - * See TLS 1.0 spec., E.1. Version 2 client hello - * @param bytes - */ - @Override - public void unwrapSSLv2(byte[] bytes) { - unexpectedMessage(); - } - - /** - * Creates and sends Finished message - */ - @Override - protected void makeFinished() { - byte[] verify_data; - if (serverHello.server_version[1] == 1) { - verify_data = new byte[12]; - computerVerifyDataTLS("client finished", verify_data); - } else { - verify_data = new byte[36]; - computerVerifyDataSSLv3(SSLv3Constants.client, verify_data); - } - clientFinished = new Finished(verify_data); - send(clientFinished); - if (isResuming) { - session.lastAccessedTime = System.currentTimeMillis(); - status = FINISHED; - } else { - if (serverHello.server_version[1] == 1) { - computerReferenceVerifyDataTLS("server finished"); - } else { - computerReferenceVerifyDataSSLv3(SSLv3Constants.server); - } - status = NEED_UNWRAP; - } - } - - /** - * Processes ServerHelloDone: makes verification of the server messages; sends - * client messages, computers masterSecret, sends ChangeCipherSpec - */ - void processServerHelloDone() { - PrivateKey clientKey = null; - - if (serverCert != null) { - if (session.cipherSuite.isAnonymous()) { - unexpectedMessage(); - return; - } - verifyServerCert(); - } else { - if (!session.cipherSuite.isAnonymous()) { - unexpectedMessage(); - return; - } - } - - // Client certificate - if (certificateRequest != null) { - X509Certificate[] certs = null; - // obtain certificates from key manager - String alias = null; - String[] certTypes = certificateRequest.getTypesAsString(); - X500Principal[] issuers = certificateRequest.certificate_authorities; - X509KeyManager km = parameters.getKeyManager(); - if (km instanceof X509ExtendedKeyManager) { - X509ExtendedKeyManager ekm = (X509ExtendedKeyManager)km; - if (this.socketOwner != null) { - alias = ekm.chooseClientAlias(certTypes, issuers, this.socketOwner); - } else { - alias = ekm.chooseEngineClientAlias(certTypes, issuers, this.engineOwner); - } - if (alias != null) { - certs = ekm.getCertificateChain(alias); - } - } else { - alias = km.chooseClientAlias(certTypes, issuers, this.socketOwner); - if (alias != null) { - certs = km.getCertificateChain(alias); - } - } - - session.localCertificates = certs; - clientCert = new CertificateMessage(certs); - clientKey = km.getPrivateKey(alias); - send(clientCert); - } - // Client key exchange - if (session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA - || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { - // RSA encrypted premaster secret message - Cipher c; - try { - c = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - if (serverKeyExchange != null) { - c.init(Cipher.WRAP_MODE, serverKeyExchange - .getRSAPublicKey()); - } else { - c.init(Cipher.WRAP_MODE, serverCert.certs[0]); - } - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "Unexpected exception", e); - return; - } - preMasterSecret = new byte[48]; - parameters.getSecureRandom().nextBytes(preMasterSecret); - System.arraycopy(clientHello.client_version, 0, preMasterSecret, 0, 2); - try { - clientKeyExchange = new ClientKeyExchange(c - .wrap(new SecretKeySpec(preMasterSecret, "preMasterSecret")), - serverHello.server_version[1] == 1); - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "Unexpected exception", e); - return; - } - } else { - try { - KeyFactory kf = KeyFactory.getInstance("DH"); - KeyAgreement agreement = KeyAgreement.getInstance("DH"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH"); - PublicKey serverPublic; - DHParameterSpec spec; - if (serverKeyExchange != null) { - serverPublic = kf.generatePublic(new DHPublicKeySpec( - serverKeyExchange.par3, serverKeyExchange.par1, - serverKeyExchange.par2)); - spec = new DHParameterSpec(serverKeyExchange.par1, - serverKeyExchange.par2); - } else { - serverPublic = serverCert.certs[0].getPublicKey(); - spec = ((DHPublicKey) serverPublic).getParams(); - } - kpg.initialize(spec); - - KeyPair kp = kpg.generateKeyPair(); - Key key = kp.getPublic(); - if (clientCert != null - && serverCert != null - && (session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA - || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS)) { - PublicKey client_pk = clientCert.certs[0].getPublicKey(); - PublicKey server_pk = serverCert.certs[0].getPublicKey(); - if (client_pk instanceof DHKey - && server_pk instanceof DHKey) { - if (((DHKey) client_pk).getParams().getG().equals( - ((DHKey) server_pk).getParams().getG()) - && ((DHKey) client_pk).getParams().getP() - .equals(((DHKey) server_pk).getParams().getG())) { - // client cert message DH public key parameters - // matched those specified by the - // server in its certificate, - clientKeyExchange = new ClientKeyExchange(); // empty - } - } - } else { - clientKeyExchange = new ClientKeyExchange( - ((DHPublicKey) key).getY()); - } - key = kp.getPrivate(); - agreement.init(key); - agreement.doPhase(serverPublic, true); - preMasterSecret = agreement.generateSecret(); - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "Unexpected exception", e); - return; - } - } - if (clientKeyExchange != null) { - send(clientKeyExchange); - } - - computerMasterSecret(); - - // send certificate verify for all certificates except those containing - // fixed DH parameters - if (clientCert != null && clientCert.certs.length > 0 && !clientKeyExchange.isEmpty()) { - // Certificate verify - String authType = clientKey.getAlgorithm(); - DigitalSignature ds = new DigitalSignature(authType); - ds.init(clientKey); - - if ("RSA".equals(authType)) { - ds.setMD5(io_stream.getDigestMD5()); - ds.setSHA(io_stream.getDigestSHA()); - } else if ("DSA".equals(authType)) { - ds.setSHA(io_stream.getDigestSHA()); - // The Signature should be empty in case of anonymous signature algorithm: - // } else if ("DH".equals(authType)) { - } - certificateVerify = new CertificateVerify(ds.sign()); - send(certificateVerify); - } - - sendChangeCipherSpec(); - } - - /* - * Verifies certificate path - */ - private void verifyServerCert() { - String authType = session.cipherSuite.getAuthType(serverKeyExchange != null); - if (authType == null) { - return; - } - String hostname = null; - if (engineOwner != null) { - hostname = engineOwner.getPeerHost(); - } else { - // we don't want to do an inet address lookup here in case we're talking to a proxy - hostname = socketOwner.getWrappedHostName(); - } - try { - X509TrustManager x509tm = parameters.getTrustManager(); - if (x509tm instanceof TrustManagerImpl) { - TrustManagerImpl tm = (TrustManagerImpl) x509tm; - tm.checkServerTrusted(serverCert.certs, authType, hostname); - } else { - x509tm.checkServerTrusted(serverCert.certs, authType); - } - } catch (CertificateException e) { - fatalAlert(AlertProtocol.BAD_CERTIFICATE, "Not trusted server certificate", e); - return; - } - session.peerCertificates = serverCert.certs; - } - - /** - * Processes ChangeCipherSpec message - */ - @Override - public void receiveChangeCipherSpec() { - if (isResuming) { - if (serverHello == null) { - unexpectedMessage(); - } - } else if (clientFinished == null) { - unexpectedMessage(); - } - changeCipherSpecReceived = true; - } - - // Find session to resume in client session context - private SSLSessionImpl findSessionToResume() { - String host = null; - int port = -1; - if (engineOwner != null) { - host = engineOwner.getPeerHost(); - port = engineOwner.getPeerPort(); - } else { - host = socketOwner.getPeerHostName(); - port = socketOwner.getPeerPort(); - } - if (host == null || port == -1) { - return null; // starts new session - } - - ClientSessionContext context = parameters.getClientSessionContext(); - SSLSessionImpl session - = (SSLSessionImpl) context.getSession(host, port); - if (session != null) { - session = (SSLSessionImpl) session.clone(); - } - return session; - } - -} diff --git a/crypto/src/main/java/org/conscrypt/ClientHello.java b/crypto/src/main/java/org/conscrypt/ClientHello.java deleted file mode 100644 index 2bf9f5f..0000000 --- a/crypto/src/main/java/org/conscrypt/ClientHello.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.SecureRandom; -import java.util.Arrays; -import libcore.io.Streams; -import org.conscrypt.util.EmptyArray; - -/** - * Represents Client Hello message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.1.2. - * Client hello</a> - * - */ -public class ClientHello extends Message { - - /** - * Client version - */ - final byte[] client_version; - - /** - * Random bytes - */ - final byte[] random = new byte[32]; - - /** - * Session id - */ - final byte[] session_id; - - /** - * Cipher suites supported by the client - */ - final CipherSuite[] cipher_suites; - - /** - * Compression methods supported by the client - */ - final byte[] compression_methods; - - /** - * Creates outbound message - * @param sr - * @param version - * @param ses_id - * @param cipher_suite - */ - public ClientHello(SecureRandom sr, byte[] version, byte[] ses_id, - CipherSuite[] cipher_suite) { - client_version = version; - long gmt_unix_time = System.currentTimeMillis()/1000; - sr.nextBytes(random); - random[0] = (byte) (gmt_unix_time & 0xFF000000 >>> 24); - random[1] = (byte) (gmt_unix_time & 0xFF0000 >>> 16); - random[2] = (byte) (gmt_unix_time & 0xFF00 >>> 8); - random[3] = (byte) (gmt_unix_time & 0xFF); - session_id = ses_id; - this.cipher_suites = cipher_suite; - compression_methods = new byte[] { 0 }; // CompressionMethod.null - length = 38 + session_id.length + (this.cipher_suites.length << 1) - + compression_methods.length; - } - - /** - * Creates inbound message - * @param in - * @param length - * @throws IOException - */ - public ClientHello(HandshakeIODataStream in, int length) throws IOException { - client_version = new byte[2]; - client_version[0] = (byte) in.readUint8(); - client_version[1] = (byte) in.readUint8(); - Streams.readFully(in, random); - int size = in.read(); - session_id = new byte[size]; - in.read(session_id, 0, size); - int l = in.readUint16(); - if ((l & 0x01) == 0x01) { // cipher suites length must be an even number - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect ClientHello"); - } - size = l >> 1; - cipher_suites = new CipherSuite[size]; - for (int i = 0; i < size; i++) { - byte b0 = (byte) in.read(); - byte b1 = (byte) in.read(); - cipher_suites[i] = CipherSuite.getByCode(b0, b1); - } - size = in.read(); - compression_methods = new byte[size]; - in.read(compression_methods, 0, size); - this.length = 38 + session_id.length + (cipher_suites.length << 1) - + compression_methods.length; - if (this.length > length) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect ClientHello"); - } - // for forward compatibility, extra data is permitted; - // must be ignored - if (this.length < length) { - in.skip(length - this.length); - this.length = length; - } - } - /** - * Parse V2ClientHello - * @param in - * @throws IOException - */ - public ClientHello(HandshakeIODataStream in) throws IOException { - if (in.readUint8() != 1) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect V2ClientHello"); - } - client_version = new byte[2]; - client_version[0] = (byte) in.readUint8(); - client_version[1] = (byte) in.readUint8(); - int cipher_spec_length = in.readUint16(); - if (in.readUint16() != 0) { // session_id_length - // as client already knows the protocol known to a server it should - // initiate the connection in that native protocol - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect V2ClientHello, cannot be used for resuming"); - } - int challenge_length = in.readUint16(); - if (challenge_length < 16) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect V2ClientHello, short challenge data"); - } - session_id = EmptyArray.BYTE; - cipher_suites = new CipherSuite[cipher_spec_length/3]; - for (int i = 0; i < cipher_suites.length; i++) { - byte b0 = (byte) in.read(); - byte b1 = (byte) in.read(); - byte b2 = (byte) in.read(); - cipher_suites[i] = CipherSuite.getByCode(b0, b1, b2); - } - compression_methods = new byte[] { 0 }; // CompressionMethod.null - - if (challenge_length < 32) { - Arrays.fill(random, 0, 32 - challenge_length, (byte)0); - System.arraycopy(in.read(challenge_length), 0, random, 32 - challenge_length, challenge_length); - } else if (challenge_length == 32) { - System.arraycopy(in.read(32), 0, random, 0, 32); - } else { - System.arraycopy(in.read(challenge_length), challenge_length - 32, random, 0, 32); - } - if (in.available() > 0) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect V2ClientHello, extra data"); - } - this.length = 38 + session_id.length + (cipher_suites.length << 1) - + compression_methods.length; - } - - /** - * Sends message - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - out.write(client_version); - out.write(random); - out.writeUint8(session_id.length); - out.write(session_id); - int size = cipher_suites.length << 1; - out.writeUint16(size); - for (int i = 0; i < cipher_suites.length; i++) { - out.write(cipher_suites[i].toBytes()); - } - out.writeUint8(compression_methods.length); - for (int i = 0; i < compression_methods.length; i++) { - out.write(compression_methods[i]); - } - } - - /** - * Returns client random - * @return client random - */ - public byte[] getRandom() { - return random; - } - - /** - * Returns message type - */ - @Override - public int getType() { - return Handshake.CLIENT_HELLO; - } -} diff --git a/crypto/src/main/java/org/conscrypt/ClientKeyExchange.java b/crypto/src/main/java/org/conscrypt/ClientKeyExchange.java deleted file mode 100644 index 5cad36b..0000000 --- a/crypto/src/main/java/org/conscrypt/ClientKeyExchange.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.math.BigInteger; -import libcore.io.Streams; -import org.conscrypt.util.EmptyArray; - -/** - * Represents client key exchange message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.7. - * Client key exchange message</a> - * - */ -public class ClientKeyExchange extends Message { - - /** - * Exchange keys - */ - final byte[] exchange_keys; - - /** - * Equals true if TLS1.0 protocol is used - */ - boolean isTLS; - - /** - * Equals true if key exchange algorithm is RSA - */ - final boolean isRSA; - - /** - * Creates outbound message - * @param encrypted_pre_master_secret - * @param isTLS - */ - public ClientKeyExchange(byte[] encrypted_pre_master_secret, boolean isTLS) { - this.exchange_keys = encrypted_pre_master_secret; - length = this.exchange_keys.length; - if (isTLS) { - length += 2; - } - this.isTLS = isTLS; - isRSA = true; - } - - /** - * Creates outbound message - * @param dh_Yc - */ - public ClientKeyExchange(BigInteger dh_Yc) { - byte[] bb = dh_Yc.toByteArray(); - if (bb[0] == 0) { - exchange_keys = new byte[bb.length-1]; - System.arraycopy(bb, 1, exchange_keys, 0, exchange_keys.length); - } else { - exchange_keys = bb; - } - length = exchange_keys.length +2; - isRSA = false; - } - - /** - * Creates empty message - * - */ - public ClientKeyExchange() { - exchange_keys = EmptyArray.BYTE; - length = 0; - isRSA = false; - } - - /** - * Creates inbound message - * @param length - * @param isTLS - * @param isRSA - * @throws IOException - */ - public ClientKeyExchange(HandshakeIODataStream in, int length, boolean isTLS, boolean isRSA) - throws IOException { - this.isTLS = isTLS; - this.isRSA = isRSA; - if (length == 0) { - this.length = 0; - exchange_keys = EmptyArray.BYTE; - } else { - int size; - if (isRSA && !isTLS) {// SSL3.0 RSA - size = length; - this.length = size; - } else { // DH or TLSv1 RSA - size = in.readUint16(); - this.length = 2 + size; - } - exchange_keys = new byte[size]; - Streams.readFully(in, exchange_keys); - if (this.length != length) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect ClientKeyExchange"); - } - } - } - - /** - * Sends message - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - if (exchange_keys.length != 0) { - if (!isRSA || isTLS) {// DH or TLSv1 RSA - out.writeUint16(exchange_keys.length); - } - out.write(exchange_keys); - } - } - - /** - * Returns message type - */ - @Override - public int getType() { - return Handshake.CLIENT_KEY_EXCHANGE; - } - - /** - * Returns true if the message is empty (in case of implicit DH Yc) - */ - public boolean isEmpty() { - return (exchange_keys.length == 0); - } -} diff --git a/crypto/src/main/java/org/conscrypt/ClientSessionContext.java b/crypto/src/main/java/org/conscrypt/ClientSessionContext.java deleted file mode 100644 index 27a39cf..0000000 --- a/crypto/src/main/java/org/conscrypt/ClientSessionContext.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.util.HashMap; -import java.util.Map; -import javax.net.ssl.SSLSession; - -/** - * Caches client sessions. Indexes by host and port. Users are typically - * looking to reuse any session for a given host and port. - */ -public class ClientSessionContext extends AbstractSessionContext { - - /** - * Sessions indexed by host and port. Protect from concurrent - * access by holding a lock on sessionsByHostAndPort. - */ - final Map<HostAndPort, SSLSession> sessionsByHostAndPort - = new HashMap<HostAndPort, SSLSession>(); - - private SSLClientSessionCache persistentCache; - - public ClientSessionContext() { - super(10, 0); - } - - public int size() { - return sessionsByHostAndPort.size(); - } - - public void setPersistentCache(SSLClientSessionCache persistentCache) { - this.persistentCache = persistentCache; - } - - protected void sessionRemoved(SSLSession session) { - String host = session.getPeerHost(); - int port = session.getPeerPort(); - if (host == null) { - return; - } - HostAndPort hostAndPortKey = new HostAndPort(host, port); - synchronized (sessionsByHostAndPort) { - sessionsByHostAndPort.remove(hostAndPortKey); - } - } - - /** - * Finds a cached session for the given host name and port. - * - * @param host of server - * @param port of server - * @return cached session or null if none found - */ - public SSLSession getSession(String host, int port) { - if (host == null) { - return null; - } - SSLSession session; - HostAndPort hostAndPortKey = new HostAndPort(host, port); - synchronized (sessionsByHostAndPort) { - session = sessionsByHostAndPort.get(hostAndPortKey); - } - if (session != null && session.isValid()) { - return session; - } - - // Look in persistent cache. - if (persistentCache != null) { - byte[] data = persistentCache.getSessionData(host, port); - if (data != null) { - session = toSession(data, host, port); - if (session != null && session.isValid()) { - super.putSession(session); - synchronized (sessionsByHostAndPort) { - sessionsByHostAndPort.put(hostAndPortKey, session); - } - return session; - } - } - } - - return null; - } - - @Override - public void putSession(SSLSession session) { - super.putSession(session); - - String host = session.getPeerHost(); - int port = session.getPeerPort(); - if (host == null) { - return; - } - - HostAndPort hostAndPortKey = new HostAndPort(host, port); - synchronized (sessionsByHostAndPort) { - sessionsByHostAndPort.put(hostAndPortKey, session); - } - - // TODO: This in a background thread. - if (persistentCache != null) { - byte[] data = toBytes(session); - if (data != null) { - persistentCache.putSessionData(session, data); - } - } - } - - static class HostAndPort { - final String host; - final int port; - - HostAndPort(String host, int port) { - this.host = host; - this.port = port; - } - - @Override public int hashCode() { - return host.hashCode() * 31 + port; - } - - @Override public boolean equals(Object o) { - if (!(o instanceof HostAndPort)) { - return false; - } - HostAndPort lhs = (HostAndPort) o; - return host.equals(lhs.host) && port == lhs.port; - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/ConnectionState.java b/crypto/src/main/java/org/conscrypt/ConnectionState.java deleted file mode 100644 index 82fbf3c..0000000 --- a/crypto/src/main/java/org/conscrypt/ConnectionState.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import javax.crypto.Cipher; - -/** - * This abstract class is a base for Record Protocol operating environmet - * of different SSL protocol versions. - */ -public abstract class ConnectionState { - - /** - * The cipher used for encode operations - */ - protected Cipher encCipher; - - /** - * The cipher used for decode operations - */ - protected Cipher decCipher; - - /** - * The block size, or zero if not a block cipher - */ - protected int block_size; - - /** - * The size of MAC used under this connection state - */ - protected int hash_size; - - /** - * Write sequence number which is incremented after each - * encrypt call - */ - protected final byte[] write_seq_num = {0, 0, 0, 0, 0, 0, 0, 0}; - - /** - * Read sequence number which is incremented after each - * decrypt call - */ - protected final byte[] read_seq_num = {0, 0, 0, 0, 0, 0, 0, 0}; - - protected Logger.Stream logger = Logger.getStream("conn_state"); - - /** - * Returns the minimal possible size of the - * Generic[Stream|Block]Cipher structure under this - * connection state. - */ - protected int getMinFragmentSize() { - // block ciphers return value with padding included - return encCipher.getOutputSize(1+hash_size); // 1 byte for data - } - - /** - * Returns the size of the Generic[Stream|Block]Cipher structure - * corresponding to the content data of specified size. - */ - protected int getFragmentSize(int content_size) { - return encCipher.getOutputSize(content_size+hash_size); - } - - /** - * Returns the minimal upper bound of the content size enclosed - * into the Generic[Stream|Block]Cipher structure of specified size. - * For stream ciphers the returned value will be exact value. - */ - protected int getContentSize(int generic_cipher_size) { - //it does not take the padding of block ciphered structures - //into account (so returned value can be greater than actual) - return decCipher.getOutputSize(generic_cipher_size)-hash_size; - } - - /** - * Returns the number of bytes of padding required to round the - * content up to the required block size. Assumes power of two - * block size. - */ - protected int getPaddingSize(int content_size) { - int mask = block_size - 1; - return (block_size - (content_size & mask)); - } - - /** - * Creates the GenericStreamCipher or GenericBlockCipher - * data structure for specified data of specified type. - * @param type - the ContentType of the provided data - * @param fragment - the byte array containing the - * data to be encrypted under the current connection state. - */ - protected byte[] encrypt(byte type, byte[] fragment) { - return encrypt(type, fragment, 0, fragment.length); - } - - /** - * Creates the GenericStreamCipher or GenericBlockCipher - * data structure for specified data of specified type. - * @param type - the ContentType of the provided data - * @param fragment - the byte array containing the - * data to be encrypted under the current connection state. - * @param offset - the offset from which the data begins with. - * @param len - the length of the data. - */ - protected abstract byte[] encrypt - (byte type, byte[] fragment, int offset, int len); - - /** - * Retrieves the fragment of the Plaintext structure of - * the specified type from the provided data. - * @param type - the ContentType of the data to be decrypted. - * @param fragment - the byte array containing the - * data to be encrypted under the current connection state. - */ - protected byte[] decrypt(byte type, byte[] fragment) { - return decrypt(type, fragment, 0, fragment.length); - } - - /** - * Retrieves the fragment of the Plaintext structure of - * the specified type from the provided data. - * @param type - the ContentType of the data to be decrypted. - * @param fragment - the byte array containing the - * data to be encrypted under the current connection state. - * @param offset - the offset from which the data begins with. - * @param len - the length of the data. - */ - protected abstract byte[] decrypt - (byte type, byte[] fragment, int offset, int len); - - /** - * Increments the sequence number. - */ - protected static void incSequenceNumber(byte[] seq_num) { - int octet = 7; - while (octet >= 0) { - seq_num[octet] ++; - if (seq_num[octet] == 0) { - // characteristic overflow, so - // carrying a number in adding - octet --; - } else { - return; - } - } - } - - /** - * Shutdownes the protocol. It will be impossiblke to use the instance - * after the calling of this method. - */ - protected void shutdown() { - encCipher = null; - decCipher = null; - for (int i=0; i<write_seq_num.length; i++) { - write_seq_num[i] = 0; - read_seq_num[i] = 0; - } - } -} - diff --git a/crypto/src/main/java/org/conscrypt/ConnectionStateSSLv3.java b/crypto/src/main/java/org/conscrypt/ConnectionStateSSLv3.java deleted file mode 100644 index 84b8483..0000000 --- a/crypto/src/main/java/org/conscrypt/ConnectionStateSSLv3.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.util.Arrays; -import javax.crypto.Cipher; -import javax.crypto.NullCipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.SSLProtocolException; - -/** - * This class encapsulates the operating environment of the SSL v3 - * (http://wp.netscape.com/eng/ssl3) Record Protocol and provides - * relating encryption/decryption functionality. - * The work functionality is based on the security - * parameters negotiated during the handshake. - */ -public class ConnectionStateSSLv3 extends ConnectionState { - - // digest to create and check the message integrity info - private final MessageDigest messageDigest; - private final byte[] mac_write_secret; - private final byte[] mac_read_secret; - - // paddings - private final byte[] pad_1; - private final byte[] pad_2; - // array will hold the part of the MAC material: - // length of 3 == 1(SSLCompressed.type) + 2(SSLCompressed.length) - // (more on SSLv3 MAC computation and payload protection see - // SSL v3 specification, p. 5.2.3) - private final byte[] mac_material_part = new byte[3]; - - /** - * Creates the instance of SSL v3 Connection State. All of the - * security parameters are provided by session object. - * @param session the sessin object which incapsulates - * all of the security parameters established by handshake protocol. - * The key calculation for the state is done according - * to the SSL v3 Protocol specification. - * (http://www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt) - */ - protected ConnectionStateSSLv3(SSLSessionImpl session) { - try { - CipherSuite cipherSuite = session.cipherSuite; - - boolean is_exportabe = cipherSuite.isExportable(); - hash_size = cipherSuite.getMACLength(); - int key_size = (is_exportabe) - ? cipherSuite.keyMaterial - : cipherSuite.expandedKeyMaterial; - int iv_size = cipherSuite.ivSize; - block_size = cipherSuite.getBlockSize(); - - String algName = cipherSuite.getBulkEncryptionAlgorithm(); - String hashName = cipherSuite.getHashName(); - if (logger != null) { - logger.println("ConnectionStateSSLv3.create:"); - logger.println(" cipher suite name: " - + session.getCipherSuite()); - logger.println(" encryption alg name: " + algName); - logger.println(" hash alg name: " + hashName); - logger.println(" hash size: " + hash_size); - logger.println(" block size: " + block_size); - logger.println(" IV size:" + iv_size); - logger.println(" key size: " + key_size); - } - - byte[] clientRandom = session.clientRandom; - byte[] serverRandom = session.serverRandom; - // so we need PRF value of size of - // 2*hash_size + 2*key_size + 2*iv_size - byte[] key_block = new byte[2*hash_size + 2*key_size + 2*iv_size]; - byte[] seed = new byte[clientRandom.length + serverRandom.length]; - System.arraycopy(serverRandom, 0, seed, 0, serverRandom.length); - System.arraycopy(clientRandom, 0, seed, serverRandom.length, - clientRandom.length); - - PRF.computePRF_SSLv3(key_block, session.master_secret, seed); - - byte[] client_mac_secret = new byte[hash_size]; - byte[] server_mac_secret = new byte[hash_size]; - byte[] client_key = new byte[key_size]; - byte[] server_key = new byte[key_size]; - - boolean is_client = !session.isServer; - - System.arraycopy(key_block, 0, client_mac_secret, 0, hash_size); - System.arraycopy(key_block, hash_size, - server_mac_secret, 0, hash_size); - System.arraycopy(key_block, 2*hash_size, client_key, 0, key_size); - System.arraycopy(key_block, 2*hash_size+key_size, - server_key, 0, key_size); - - IvParameterSpec clientIV = null; - IvParameterSpec serverIV = null; - - if (is_exportabe) { - if (logger != null) { - logger.println("ConnectionStateSSLv3: is_exportable"); - } - - MessageDigest md5 = MessageDigest.getInstance("MD5"); - md5.update(client_key); - md5.update(clientRandom); - md5.update(serverRandom); - client_key = md5.digest(); - - md5.update(server_key); - md5.update(serverRandom); - md5.update(clientRandom); - server_key = md5.digest(); - - key_size = cipherSuite.expandedKeyMaterial; - - if (block_size != 0) { - md5.update(clientRandom); - md5.update(serverRandom); - clientIV = new IvParameterSpec(md5.digest(), 0, iv_size); - md5.update(serverRandom); - md5.update(clientRandom); - serverIV = new IvParameterSpec(md5.digest(), 0, iv_size); - } - } else if (block_size != 0) { - clientIV = new IvParameterSpec(key_block, - 2*hash_size+2*key_size, iv_size); - serverIV = new IvParameterSpec(key_block, - 2*hash_size+2*key_size+iv_size, iv_size); - } - - if (logger != null) { - logger.println("is exportable: "+is_exportabe); - logger.println("master_secret"); - logger.print(session.master_secret); - logger.println("client_random"); - logger.print(clientRandom); - logger.println("server_random"); - logger.print(serverRandom); - //logger.println("key_block"); - //logger.print(key_block); - logger.println("client_mac_secret"); - logger.print(client_mac_secret); - logger.println("server_mac_secret"); - logger.print(server_mac_secret); - logger.println("client_key"); - logger.print(client_key, 0, key_size); - logger.println("server_key"); - logger.print(server_key, 0, key_size); - if (clientIV != null) { - logger.println("client_iv"); - logger.print(clientIV.getIV()); - logger.println("server_iv"); - logger.print(serverIV.getIV()); - } else { - logger.println("no IV."); - } - } - - if (algName == null) { - encCipher = new NullCipher(); - decCipher = new NullCipher(); - } else { - encCipher = Cipher.getInstance(algName); - decCipher = Cipher.getInstance(algName); - if (is_client) { // client side - encCipher.init(Cipher.ENCRYPT_MODE, - new SecretKeySpec(client_key, 0, key_size, algName), - clientIV); - decCipher.init(Cipher.DECRYPT_MODE, - new SecretKeySpec(server_key, 0, key_size, algName), - serverIV); - } else { // server side - encCipher.init(Cipher.ENCRYPT_MODE, - new SecretKeySpec(server_key, 0, key_size, algName), - serverIV); - decCipher.init(Cipher.DECRYPT_MODE, - new SecretKeySpec(client_key, 0, key_size, algName), - clientIV); - } - } - - messageDigest = MessageDigest.getInstance(hashName); - if (is_client) { // client side - mac_write_secret = client_mac_secret; - mac_read_secret = server_mac_secret; - } else { // server side - mac_write_secret = server_mac_secret; - mac_read_secret = client_mac_secret; - } - if (hashName.equals("MD5")) { - pad_1 = SSLv3Constants.MD5pad1; - pad_2 = SSLv3Constants.MD5pad2; - } else { - pad_1 = SSLv3Constants.SHApad1; - pad_2 = SSLv3Constants.SHApad2; - } - } catch (Exception e) { - e.printStackTrace(); - throw new AlertException(AlertProtocol.INTERNAL_ERROR, - new SSLProtocolException( - "Error during computation of security parameters")); - } - } - - /** - * Creates the GenericStreamCipher or GenericBlockCipher - * data structure for specified data of specified type. - * @throws AlertException if alert was occurred. - */ - @Override - protected byte[] encrypt(byte type, byte[] fragment, int offset, int len) { - try { - int content_mac_length = len + hash_size; - int padding_length = (block_size == 0) ? 0 : getPaddingSize(++content_mac_length); - byte[] res = new byte[content_mac_length + padding_length]; - System.arraycopy(fragment, offset, res, 0, len); - - mac_material_part[0] = type; - mac_material_part[1] = (byte) ((0x00FF00 & len) >> 8); - mac_material_part[2] = (byte) (0x0000FF & len); - - messageDigest.update(mac_write_secret); - messageDigest.update(pad_1); - messageDigest.update(write_seq_num); - messageDigest.update(mac_material_part); - messageDigest.update(fragment, offset, len); - byte[] digest = messageDigest.digest(); - messageDigest.update(mac_write_secret); - messageDigest.update(pad_2); - messageDigest.update(digest); - digest = messageDigest.digest(); - System.arraycopy(digest, 0, res, len, hash_size); - - //if (logger != null) { - // logger.println("MAC Material:"); - // logger.print(write_seq_num); - // logger.print(mac_material_header); - // logger.print(fragment, offset, len); - //} - - if (block_size != 0) { - // do padding: - Arrays.fill(res, content_mac_length-1, - res.length, (byte) (padding_length)); - } - if (logger != null) { - logger.println("SSLRecordProtocol.encrypt: " - + (block_size != 0 - ? "GenericBlockCipher with padding[" - +padding_length+"]:" - : "GenericStreamCipher:")); - logger.print(res); - } - byte[] rez = new byte[encCipher.getOutputSize(res.length)]; - encCipher.update(res, 0, res.length, rez); - incSequenceNumber(write_seq_num); - return rez; - } catch (GeneralSecurityException e) { - e.printStackTrace(); - throw new AlertException(AlertProtocol.INTERNAL_ERROR, - new SSLProtocolException("Error during the encryption")); - } - } - - /** - * Retrieves the fragment of the Plaintext structure of - * the specified type from the provided data. - * @throws AlertException if alert was occured. - */ - @Override - protected byte[] decrypt(byte type, byte[] fragment, - int offset, int len) { - // plain data of the Generic[Stream|Block]Cipher structure - byte[] data = decCipher.update(fragment, offset, len); - // the 'content' part of the structure - byte[] content; - if (block_size != 0) { - // check padding - int padding_length = data[data.length-1] & 0xFF; - for (int i=0; i<padding_length; i++) { - if ((data[data.length-2-i] & 0xFF) != padding_length) { - throw new AlertException( - AlertProtocol.DECRYPTION_FAILED, - new SSLProtocolException( - "Received message has bad padding")); - } - } - content = new byte[data.length - hash_size - padding_length - 1]; - } else { - content = new byte[data.length - hash_size]; - } - - byte[] mac_value; - - mac_material_part[0] = type; - mac_material_part[1] = (byte) ((0x00FF00 & content.length) >> 8); - mac_material_part[2] = (byte) (0x0000FF & content.length); - - messageDigest.update(mac_read_secret); - messageDigest.update(pad_1); - messageDigest.update(read_seq_num); - messageDigest.update(mac_material_part); - messageDigest.update(data, 0, content.length); - mac_value = messageDigest.digest(); - messageDigest.update(mac_read_secret); - messageDigest.update(pad_2); - messageDigest.update(mac_value); - mac_value = messageDigest.digest(); - - if (logger != null) { - logger.println("Decrypted:"); - logger.print(data); - //logger.println("MAC Material:"); - //logger.print(read_seq_num); - //logger.print(mac_material_header); - //logger.print(data, 0, content.length); - logger.println("Expected mac value:"); - logger.print(mac_value); - } - // checking the mac value - for (int i=0; i<hash_size; i++) { - if (mac_value[i] != data[i+content.length]) { - throw new AlertException(AlertProtocol.BAD_RECORD_MAC, - new SSLProtocolException("Bad record MAC")); - } - } - System.arraycopy(data, 0, content, 0, content.length); - incSequenceNumber(read_seq_num); - return content; - } - - /** - * Shutdown the protocol. It will be impossible to use the instance - * after the calling of this method. - */ - @Override - protected void shutdown() { - Arrays.fill(mac_write_secret, (byte) 0); - Arrays.fill(mac_read_secret, (byte) 0); - super.shutdown(); - } -} - diff --git a/crypto/src/main/java/org/conscrypt/ConnectionStateTLS.java b/crypto/src/main/java/org/conscrypt/ConnectionStateTLS.java deleted file mode 100644 index a4d9de8..0000000 --- a/crypto/src/main/java/org/conscrypt/ConnectionStateTLS.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.GeneralSecurityException; -import java.util.Arrays; -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.NullCipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.SSLProtocolException; - -/** - * This class encapsulates the operating environment of the TLS v1 - * (http://www.ietf.org/rfc/rfc2246.txt) Record Protocol and provides - * relating encryption/decryption functionality. - * The work functionality is based on the security - * parameters negotiated during the handshake. - */ -public class ConnectionStateTLS extends ConnectionState { - - // Pre-calculated prf label values: - // "key expansion".getBytes() - private static byte[] KEY_EXPANSION_LABEL = { - (byte) 0x6B, (byte) 0x65, (byte) 0x79, (byte) 0x20, (byte) 0x65, - (byte) 0x78, (byte) 0x70, (byte) 0x61, (byte) 0x6E, (byte) 0x73, - (byte) 0x69, (byte) 0x6F, (byte) 0x6E }; - - // "client write key".getBytes() - private static byte[] CLIENT_WRITE_KEY_LABEL = { - (byte) 0x63, (byte) 0x6C, (byte) 0x69, (byte) 0x65, (byte) 0x6E, - (byte) 0x74, (byte) 0x20, (byte) 0x77, (byte) 0x72, (byte) 0x69, - (byte) 0x74, (byte) 0x65, (byte) 0x20, (byte) 0x6B, (byte) 0x65, - (byte) 0x79 }; - - // "server write key".getBytes() - private static byte[] SERVER_WRITE_KEY_LABEL = { - (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, - (byte) 0x72, (byte) 0x20, (byte) 0x77, (byte) 0x72, (byte) 0x69, - (byte) 0x74, (byte) 0x65, (byte) 0x20, (byte) 0x6B, (byte) 0x65, - (byte) 0x79 }; - - // "IV block".getBytes() - private static byte[] IV_BLOCK_LABEL = { - (byte) 0x49, (byte) 0x56, (byte) 0x20, (byte) 0x62, (byte) 0x6C, - (byte) 0x6F, (byte) 0x63, (byte) 0x6B }; - - // MACs to create and check the message integrity info - private final Mac encMac; - private final Mac decMac; - - // Once created permanently used array: - // is used to create the header of the MAC material value: - // 5 == 1(TLSCompressed.type) + 2(TLSCompressed.version) + - // 2(TLSCompressed.length) - private final byte[] mac_material_header = new byte[] {0, 3, 1, 0, 0}; - - /** - * Creates the instance of TLS v1 Connection State. All of the - * security parameters are provided by session object. - * @param session the sessin object which incapsulates - * all of the security parameters established by handshake protocol. - * The key calculation for the state is done according - * to the TLS v 1.0 Protocol specification. - * (http://www.ietf.org/rfc/rfc2246.txt) - */ - protected ConnectionStateTLS(SSLSessionImpl session) { - try { - CipherSuite cipherSuite = session.cipherSuite; - - hash_size = cipherSuite.getMACLength(); - boolean is_exportabe = cipherSuite.isExportable(); - int key_size = (is_exportabe) - ? cipherSuite.keyMaterial - : cipherSuite.expandedKeyMaterial; - int iv_size = cipherSuite.ivSize; - block_size = cipherSuite.getBlockSize(); - - String algName = cipherSuite.getBulkEncryptionAlgorithm(); - String macName = cipherSuite.getHmacName(); - if (logger != null) { - logger.println("ConnectionStateTLS.create:"); - logger.println(" cipher suite name: " - + cipherSuite.getName()); - logger.println(" encryption alg name: " + algName); - logger.println(" mac alg name: " + macName); - logger.println(" hash size: " + hash_size); - logger.println(" block size: " + block_size); - logger.println(" IV size:" + iv_size); - logger.println(" key size: " + key_size); - } - - byte[] clientRandom = session.clientRandom; - byte[] serverRandom = session.serverRandom; - // so we need PRF value of size of - // 2*hash_size + 2*key_size + 2*iv_size - byte[] key_block = new byte[2*hash_size + 2*key_size + 2*iv_size]; - byte[] seed = new byte[clientRandom.length + serverRandom.length]; - System.arraycopy(serverRandom, 0, seed, 0, serverRandom.length); - System.arraycopy(clientRandom, 0, seed, serverRandom.length, - clientRandom.length); - - PRF.computePRF(key_block, session.master_secret, - KEY_EXPANSION_LABEL, seed); - - byte[] client_mac_secret = new byte[hash_size]; - byte[] server_mac_secret = new byte[hash_size]; - byte[] client_key = new byte[key_size]; - byte[] server_key = new byte[key_size]; - - boolean is_client = !session.isServer; - - System.arraycopy(key_block, 0, client_mac_secret, 0, hash_size); - System.arraycopy(key_block, hash_size, - server_mac_secret, 0, hash_size); - System.arraycopy(key_block, 2*hash_size, client_key, 0, key_size); - System.arraycopy(key_block, 2*hash_size+key_size, - server_key, 0, key_size); - - IvParameterSpec clientIV = null; - IvParameterSpec serverIV = null; - - if (is_exportabe) { - System.arraycopy(clientRandom, 0, - seed, 0, clientRandom.length); - System.arraycopy(serverRandom, 0, - seed, clientRandom.length, serverRandom.length); - byte[] final_client_key = - new byte[cipherSuite.expandedKeyMaterial]; - byte[] final_server_key = - new byte[cipherSuite.expandedKeyMaterial]; - PRF.computePRF(final_client_key, client_key, - CLIENT_WRITE_KEY_LABEL, seed); - PRF.computePRF(final_server_key, server_key, - SERVER_WRITE_KEY_LABEL, seed); - client_key = final_client_key; - server_key = final_server_key; - if (block_size != 0) { - byte[] iv_block = new byte[2*iv_size]; - PRF.computePRF(iv_block, null, IV_BLOCK_LABEL, seed); - clientIV = new IvParameterSpec(iv_block, 0, iv_size); - serverIV = new IvParameterSpec(iv_block, iv_size, iv_size); - } - } else if (block_size != 0) { - clientIV = new IvParameterSpec(key_block, - 2*(hash_size+key_size), iv_size); - serverIV = new IvParameterSpec(key_block, - 2*(hash_size+key_size)+iv_size, iv_size); - } - - if (logger != null) { - logger.println("is exportable: "+is_exportabe); - logger.println("master_secret"); - logger.print(session.master_secret); - logger.println("client_random"); - logger.print(clientRandom); - logger.println("server_random"); - logger.print(serverRandom); - //logger.println("key_block"); - //logger.print(key_block); - logger.println("client_mac_secret"); - logger.print(client_mac_secret); - logger.println("server_mac_secret"); - logger.print(server_mac_secret); - logger.println("client_key"); - logger.print(client_key); - logger.println("server_key"); - logger.print(server_key); - if (clientIV == null) { - logger.println("no IV."); - } else { - logger.println("client_iv"); - logger.print(clientIV.getIV()); - logger.println("server_iv"); - logger.print(serverIV.getIV()); - } - } - - if (algName == null) { - encCipher = new NullCipher(); - decCipher = new NullCipher(); - } else { - encCipher = Cipher.getInstance(algName); - decCipher = Cipher.getInstance(algName); - if (is_client) { // client side - encCipher.init(Cipher.ENCRYPT_MODE, - new SecretKeySpec(client_key, algName), clientIV); - decCipher.init(Cipher.DECRYPT_MODE, - new SecretKeySpec(server_key, algName), serverIV); - } else { // server side - encCipher.init(Cipher.ENCRYPT_MODE, - new SecretKeySpec(server_key, algName), serverIV); - decCipher.init(Cipher.DECRYPT_MODE, - new SecretKeySpec(client_key, algName), clientIV); - } - } - - encMac = Mac.getInstance(macName); - decMac = Mac.getInstance(macName); - if (is_client) { // client side - encMac.init(new SecretKeySpec(client_mac_secret, macName)); - decMac.init(new SecretKeySpec(server_mac_secret, macName)); - } else { // server side - encMac.init(new SecretKeySpec(server_mac_secret, macName)); - decMac.init(new SecretKeySpec(client_mac_secret, macName)); - } - } catch (Exception e) { - e.printStackTrace(); - throw new AlertException(AlertProtocol.INTERNAL_ERROR, - new SSLProtocolException( - "Error during computation of security parameters")); - } - } - - /** - * Creates the GenericStreamCipher or GenericBlockCipher - * data structure for specified data of specified type. - * @throws AlertException if alert was occurred. - */ - @Override - protected byte[] encrypt(byte type, byte[] fragment, int offset, int len) { - try { - int content_mac_length = len + hash_size; - int padding_length = (block_size == 0) ? 0 : getPaddingSize(++content_mac_length); - byte[] res = new byte[content_mac_length + padding_length]; - System.arraycopy(fragment, offset, res, 0, len); - - mac_material_header[0] = type; - mac_material_header[3] = (byte) ((0x00FF00 & len) >> 8); - mac_material_header[4] = (byte) (0x0000FF & len); - - encMac.update(write_seq_num); - encMac.update(mac_material_header); - encMac.update(fragment, offset, len); - encMac.doFinal(res, len); - - //if (logger != null) { - // logger.println("MAC Material:"); - // logger.print(write_seq_num); - // logger.print(mac_material_header); - // logger.print(fragment, offset, len); - //} - - if (block_size != 0) { - // do padding: - Arrays.fill(res, content_mac_length-1, - res.length, (byte) (padding_length)); - } - if (logger != null) { - logger.println("SSLRecordProtocol.do_encryption: Generic" - + (block_size != 0 - ? "BlockCipher with padding["+padding_length+"]:" - : "StreamCipher:")); - logger.print(res); - } - byte[] rez = new byte[encCipher.getOutputSize(res.length)]; - // We should not call just doFinal because it reinitialize - // the cipher, but as says rfc 2246: - // "For stream ciphers that do not use a synchronization - // vector (such as RC4), the stream cipher state from the end - // of one record is simply used on the subsequent packet." - // and for block ciphers: - // "The IV for subsequent records is the last ciphertext block from - // the previous record." - // i.e. we should keep the cipher state. - encCipher.update(res, 0, res.length, rez); - incSequenceNumber(write_seq_num); - return rez; - } catch (GeneralSecurityException e) { - e.printStackTrace(); - throw new AlertException(AlertProtocol.INTERNAL_ERROR, - new SSLProtocolException("Error during the encryption")); - } - } - - /** - * Retrieves the fragment of the Plaintext structure of - * the specified type from the provided data representing - * the Generic[Stream|Block]Cipher structure. - * @throws AlertException if alert was occurred. - */ - @Override - protected byte[] decrypt(byte type, byte[] fragment, - int offset, int len) { - // plain data of the Generic[Stream|Block]Cipher structure - byte[] data = decCipher.update(fragment, offset, len); - // the 'content' part of the structure - byte[] content; - if (block_size != 0) { - // check padding - int padding_length = data[data.length - 1] & 0xFF; - for (int i=0; i<padding_length; i++) { - if ((data[data.length-2-i] & 0xFF) != padding_length) { - throw new AlertException( - AlertProtocol.DECRYPTION_FAILED, - new SSLProtocolException( - "Received message has bad padding")); - } - } - content = new byte[data.length - hash_size - padding_length - 1]; - } else { - content = new byte[data.length - hash_size]; - } - - mac_material_header[0] = type; - mac_material_header[3] = (byte) ((0x00FF00 & content.length) >> 8); - mac_material_header[4] = (byte) (0x0000FF & content.length); - - decMac.update(read_seq_num); - decMac.update(mac_material_header); - decMac.update(data, 0, content.length); // mac.update(fragment); - byte[] mac_value = decMac.doFinal(); - if (logger != null) { - logger.println("Decrypted:"); - logger.print(data); - //logger.println("MAC Material:"); - //logger.print(read_seq_num); - //logger.print(mac_material_header); - //logger.print(data, 0, content.length); - logger.println("Expected mac value:"); - logger.print(mac_value); - } - // checking the mac value - for (int i=0; i<hash_size; i++) { - if (mac_value[i] != data[i+content.length]) { - throw new AlertException(AlertProtocol.BAD_RECORD_MAC, - new SSLProtocolException("Bad record MAC")); - } - } - System.arraycopy(data, 0, content, 0, content.length); - incSequenceNumber(read_seq_num); - return content; - } -} - diff --git a/crypto/src/main/java/org/conscrypt/ContentType.java b/crypto/src/main/java/org/conscrypt/ContentType.java deleted file mode 100644 index b09f029..0000000 --- a/crypto/src/main/java/org/conscrypt/ContentType.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * This class incapsulates the constants determining the - * types of SSL/TLS record's content data. - * Constant values are taken according to the TLS v1 specification - * (http://www.ietf.org/rfc/rfc2246.txt). - */ -public class ContentType { - - /** - * Identifies change cipher spec message - */ - protected static final byte CHANGE_CIPHER_SPEC = 20; - - /** - * Identifies alert message - */ - protected static final byte ALERT = 21; - - /** - * Identifies handshake message - */ - protected static final byte HANDSHAKE = 22; - - /** - * Identifies application data message - */ - protected static final byte APPLICATION_DATA = 23; - -} - diff --git a/crypto/src/main/java/org/conscrypt/DHParameters.java b/crypto/src/main/java/org/conscrypt/DHParameters.java deleted file mode 100644 index 7a742b2..0000000 --- a/crypto/src/main/java/org/conscrypt/DHParameters.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * This class contains well-known primes - */ -public class DHParameters { - - // Well-known 512 bit prime - // http://news.hping.org/sci.crypt.archive/2370.html - private static byte[] prime512 = new byte[] { (byte) 0xF5, (byte) 0x2A, (byte) 0xFF, - (byte) 0x3C, (byte) 0xE1, (byte) 0xB1, (byte) 0x29, (byte) 0x40, - (byte) 0x18, (byte) 0x11, (byte) 0x8D, (byte) 0x7C, (byte) 0x84, - (byte) 0xA7, (byte) 0x0A, (byte) 0x72, (byte) 0xD6, (byte) 0x86, - (byte) 0xC4, (byte) 0x03, (byte) 0x19, (byte) 0xC8, (byte) 0x07, - (byte) 0x29, (byte) 0x7A, (byte) 0xCA, (byte) 0x95, (byte) 0x0C, - (byte) 0xD9, (byte) 0x96, (byte) 0x9F, (byte) 0xAB, (byte) 0xD0, - (byte) 0x0A, (byte) 0x50, (byte) 0x9B, (byte) 0x02, (byte) 0x46, - (byte) 0xD3, (byte) 0x08, (byte) 0x3D, (byte) 0x66, (byte) 0xA4, - (byte) 0x5D, (byte) 0x41, (byte) 0x9F, (byte) 0x9C, (byte) 0x7C, - (byte) 0xBD, (byte) 0x89, (byte) 0x4B, (byte) 0x22, (byte) 0x19, - (byte) 0x26, (byte) 0xBA, (byte) 0xAB, (byte) 0xA2, (byte) 0x5E, - (byte) 0xC3, (byte) 0x55, (byte) 0xE9, (byte) 0x2A, (byte) 0x05, - (byte) 0x5F }; - - // Well-Known Group 1: A 768 bit prime rfc 2539 - // (http://www.ietf.org/rfc/rfc2539.txt?number=2539) - private static byte[] primeGroup1 = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC9, - (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68, - (byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62, - (byte) 0x8B, (byte) 0x80, (byte) 0xDC, (byte) 0x1C, (byte) 0xD1, - (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A, - (byte) 0x67, (byte) 0xCC, (byte) 0x74, (byte) 0x02, (byte) 0x0B, - (byte) 0xBE, (byte) 0xA6, (byte) 0x3B, (byte) 0x13, (byte) 0x9B, - (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79, - (byte) 0x8E, (byte) 0x34, (byte) 0x04, (byte) 0xDD, (byte) 0xEF, - (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD, (byte) 0x3A, - (byte) 0x43, (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A, - (byte) 0x6D, (byte) 0xF2, (byte) 0x5F, (byte) 0x14, (byte) 0x37, - (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D, - (byte) 0x51, (byte) 0xC2, (byte) 0x45, (byte) 0xE4, (byte) 0x85, - (byte) 0xB5, (byte) 0x76, (byte) 0x62, (byte) 0x5E, (byte) 0x7E, - (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9, - (byte) 0xA6, (byte) 0x3A, (byte) 0x36, (byte) 0x20, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF }; - - // Well-Known Group 2: A 1024 bit prime rfc 2539 - // (http://www.ietf.org/rfc/rfc2539.txt?number=2539) - private static byte[] primeGroup2 = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC9, - (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68, - (byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62, - (byte) 0x8B, (byte) 0x80, (byte) 0xDC, (byte) 0x1C, (byte) 0xD1, - (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A, - (byte) 0x67, (byte) 0xCC, (byte) 0x74, (byte) 0x02, (byte) 0x0B, - (byte) 0xBE, (byte) 0xA6, (byte) 0x3B, (byte) 0x13, (byte) 0x9B, - (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79, - (byte) 0x8E, (byte) 0x34, (byte) 0x04, (byte) 0xDD, (byte) 0xEF, - (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD, (byte) 0x3A, - (byte) 0x43, (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A, - (byte) 0x6D, (byte) 0xF2, (byte) 0x5F, (byte) 0x14, (byte) 0x37, - (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D, - (byte) 0x51, (byte) 0xC2, (byte) 0x45, (byte) 0xE4, (byte) 0x85, - (byte) 0xB5, (byte) 0x76, (byte) 0x62, (byte) 0x5E, (byte) 0x7E, - (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9, - (byte) 0xA6, (byte) 0x37, (byte) 0xED, (byte) 0x6B, (byte) 0x0B, - (byte) 0xFF, (byte) 0x5C, (byte) 0xB6, (byte) 0xF4, (byte) 0x06, - (byte) 0xB7, (byte) 0xED, (byte) 0xEE, (byte) 0x38, (byte) 0x6B, - (byte) 0xFB, (byte) 0x5A, (byte) 0x89, (byte) 0x9F, (byte) 0xA5, - (byte) 0xAE, (byte) 0x9F, (byte) 0x24, (byte) 0x11, (byte) 0x7C, - (byte) 0x4B, (byte) 0x1F, (byte) 0xE6, (byte) 0x49, (byte) 0x28, - (byte) 0x66, (byte) 0x51, (byte) 0xEC, (byte) 0xE6, (byte) 0x53, - (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF - }; - - private static byte[] prime; - - static { -//TODO set prime depand on some system or security property - prime = prime512; - } - - /** - * Returns prime bytes - * @return - */ - public static byte[] getPrime() { - return prime; - } -}
\ No newline at end of file diff --git a/crypto/src/main/java/org/conscrypt/DataStream.java b/crypto/src/main/java/org/conscrypt/DataStream.java deleted file mode 100644 index d65b01a..0000000 --- a/crypto/src/main/java/org/conscrypt/DataStream.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * This interface represents the ability of the - * classes to provide the chunks of data. - */ -public interface DataStream { - - /** - * Checks if there is data to be read. - * @return true if there is the input data in the stream, - * false otherwise - */ - public boolean hasData(); - - /** - * Retrieves the data of specified length from the stream. - * If the data size in the stream is less than specified length, - * method returns all the data contained in the stream. - * @return byte array containing the demanded data. - */ - public byte[] getData(int length); - -} - diff --git a/crypto/src/main/java/org/conscrypt/DefaultSSLContextImpl.java b/crypto/src/main/java/org/conscrypt/DefaultSSLContextImpl.java deleted file mode 100644 index c90787f..0000000 --- a/crypto/src/main/java/org/conscrypt/DefaultSSLContextImpl.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.SecureRandom; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -/** - * Support class for this package. - */ -public final class DefaultSSLContextImpl extends OpenSSLContextImpl { - - /** - * Accessed by SSLContextImpl(DefaultSSLContextImpl) holding the - * DefaultSSLContextImpl.class monitor - */ - private static KeyManager[] KEY_MANAGERS; - - /** - * Accessed by SSLContextImpl(DefaultSSLContextImpl) holding the - * DefaultSSLContextImpl.class monitor - */ - private static TrustManager[] TRUST_MANAGERS; - - /** - * DefaultSSLContextImpl delegates the work to the super class - * since there is no way to put a synchronized around both the - * call to super and the rest of this constructor to guarantee - * that we don't have races in creating the state shared between - * all default SSLContexts. - */ - public DefaultSSLContextImpl() throws GeneralSecurityException, IOException { - super(null); - } - - // TODO javax.net.ssl.keyStoreProvider system property - KeyManager[] getKeyManagers () throws GeneralSecurityException, IOException { - if (KEY_MANAGERS != null) { - return KEY_MANAGERS; - } - // find KeyStore, KeyManagers - String keystore = System.getProperty("javax.net.ssl.keyStore"); - if (keystore == null) { - return null; - } - String keystorepwd = System.getProperty("javax.net.ssl.keyStorePassword"); - char[] pwd = (keystorepwd == null) ? null : keystorepwd.toCharArray(); - - KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); - InputStream is = null; - try { - is = new BufferedInputStream(new FileInputStream(keystore)); - ks.load(is, pwd); - } finally { - if (is != null) { - is.close(); - } - } - - String kmfAlg = KeyManagerFactory.getDefaultAlgorithm(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfAlg); - kmf.init(ks, pwd); - KEY_MANAGERS = kmf.getKeyManagers(); - return KEY_MANAGERS; - } - - // TODO javax.net.ssl.trustStoreProvider system property - TrustManager[] getTrustManagers() throws GeneralSecurityException, IOException { - if (TRUST_MANAGERS != null) { - return TRUST_MANAGERS; - } - - // find TrustStore, TrustManagers - String keystore = System.getProperty("javax.net.ssl.trustStore"); - if (keystore == null) { - return null; - } - String keystorepwd = System.getProperty("javax.net.ssl.trustStorePassword"); - char[] pwd = (keystorepwd == null) ? null : keystorepwd.toCharArray(); - - // TODO Defaults: jssecacerts; cacerts - KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); - InputStream is = null; - try { - is = new BufferedInputStream(new FileInputStream(keystore)); - ks.load(is, pwd); - } finally { - if (is != null) { - is.close(); - } - } - String tmfAlg = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlg); - tmf.init(ks); - TRUST_MANAGERS = tmf.getTrustManagers(); - return TRUST_MANAGERS; - } - - @Override - public void engineInit(KeyManager[] kms, TrustManager[] tms, - SecureRandom sr) throws KeyManagementException { - throw new KeyManagementException("Do not init() the default SSLContext "); - } -} diff --git a/crypto/src/main/java/org/conscrypt/DelegatedTask.java b/crypto/src/main/java/org/conscrypt/DelegatedTask.java deleted file mode 100644 index 8eab2ea..0000000 --- a/crypto/src/main/java/org/conscrypt/DelegatedTask.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * Delegated Runnable task for SSLEngine - */ -public class DelegatedTask implements Runnable { - - private final HandshakeProtocol handshaker; - private final Runnable action; - - public DelegatedTask(Runnable action, HandshakeProtocol handshaker) { - this.action = action; - this.handshaker = handshaker; - } - - public void run() { - synchronized (handshaker) { - try { - action.run(); - } catch (RuntimeException e) { - // pass exception to HandshakeProtocol - handshaker.delegatedTaskErr = e; - } - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/DigitalSignature.java b/crypto/src/main/java/org/conscrypt/DigitalSignature.java deleted file mode 100644 index 04886c5..0000000 --- a/crypto/src/main/java/org/conscrypt/DigitalSignature.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.DigestException; -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.cert.Certificate; -import java.util.Arrays; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.net.ssl.SSLException; -import org.conscrypt.util.EmptyArray; - -/** - * This class represents Signature type, as described in TLS v 1.0 Protocol - * specification, 7.4.3. It allow to init, update and sign hash. Hash algorithm - * depends on SignatureAlgorithm. - * - * select (SignatureAlgorithm) - * { case anonymous: struct { }; - * case rsa: - * digitally-signed struct { - * opaque md5_hash[16]; - * opaque sha_hash[20]; - * }; - * case dsa: - * digitally-signed struct { - * opaque sha_hash[20]; - * }; - * } Signature; - * - * Digital signing description see in TLS spec., 4.7. - * (http://www.ietf.org/rfc/rfc2246.txt) - * - */ -public class DigitalSignature { - - private final MessageDigest md5; - private final MessageDigest sha; - private final Signature signature; - private final Cipher cipher; - - private byte[] md5_hash; - private byte[] sha_hash; - - /** - * Create Signature type - * @param algorithm the key algorithm used for the signature - */ - public DigitalSignature(String algorithm) { - try { - sha = MessageDigest.getInstance("SHA-1"); - - if ("RSA".equals(algorithm)) { - md5 = MessageDigest.getInstance("MD5"); - cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - signature = null; - } else if ("DSA".equals(algorithm)) { - // SignatureAlgorithm is dsa - signature = Signature.getInstance("NONEwithDSA"); - cipher = null; - md5 = null; - } else { - cipher = null; - signature = null; - md5 = null; - } - } catch (NoSuchAlgorithmException e) { - // this should never happen - throw new AssertionError(e); - } catch (NoSuchPaddingException e) { - // this should never happen - throw new AssertionError(e); - } - } - - /** - * Initiate Signature type by private key - * @param key - */ - public void init(PrivateKey key) { - try { - if (signature != null) { - signature.initSign(key); - } else if (cipher != null) { - cipher.init(Cipher.ENCRYPT_MODE, key); - } - } catch (InvalidKeyException e){ - throw new AlertException(AlertProtocol.BAD_CERTIFICATE, - new SSLException("init - invalid private key", e)); - } - } - - /** - * Initiate Signature type by certificate - * @param cert - */ - public void init(Certificate cert) { - try { - if (signature != null) { - signature.initVerify(cert); - } else if (cipher != null) { - cipher.init(Cipher.DECRYPT_MODE, cert); - } - } catch (InvalidKeyException e){ - throw new AlertException(AlertProtocol.BAD_CERTIFICATE, - new SSLException("init - invalid certificate", e)); - } - } - - /** - * Update Signature hash - * @param data - */ - public void update(byte[] data) { - if (sha != null) { - sha.update(data); - } - if (md5 != null) { - md5.update(data); - } - } - - /** - * Sets MD5 hash - * @param data - */ - public void setMD5(byte[] data) { - md5_hash = data; - } - - /** - * Sets SHA hash - * @param data - */ - public void setSHA(byte[] data) { - sha_hash = data; - } - - /** - * Sign hash - * @return Signature bytes - */ - public byte[] sign() { - try { - if (md5 != null && md5_hash == null) { - md5_hash = new byte[16]; - md5.digest(md5_hash, 0, md5_hash.length); - } - if (md5_hash != null) { - if (signature != null) { - signature.update(md5_hash); - } else if (cipher != null) { - cipher.update(md5_hash); - } - } - if (sha != null && sha_hash == null) { - sha_hash = new byte[20]; - sha.digest(sha_hash, 0, sha_hash.length); - } - if (sha_hash != null) { - if (signature != null) { - signature.update(sha_hash); - } else if (cipher != null) { - cipher.update(sha_hash); - } - } - if (signature != null) { - return signature.sign(); - } else if (cipher != null) { - return cipher.doFinal(); - } - return EmptyArray.BYTE; - } catch (DigestException e){ - return EmptyArray.BYTE; - } catch (SignatureException e){ - return EmptyArray.BYTE; - } catch (BadPaddingException e){ - return EmptyArray.BYTE; - } catch (IllegalBlockSizeException e){ - return EmptyArray.BYTE; - } - } - - /** - * Verifies the signature data. - * @param data - the signature bytes - * @return true if verified - */ - public boolean verifySignature(byte[] data) { - if (signature != null) { - try { - signature.update(sha_hash); - return signature.verify(data); - } catch (SignatureException e) { - return false; - } - } - - if (cipher != null) { - final byte[] decrypt; - try { - decrypt = cipher.doFinal(data); - } catch (IllegalBlockSizeException e) { - return false; - } catch (BadPaddingException e) { - return false; - } - - final byte[] md5_sha; - if (md5_hash != null && sha_hash != null) { - md5_sha = new byte[md5_hash.length + sha_hash.length]; - System.arraycopy(md5_hash, 0, md5_sha, 0, md5_hash.length); - System.arraycopy(sha_hash, 0, md5_sha, md5_hash.length, sha_hash.length); - } else if (md5_hash != null) { - md5_sha = md5_hash; - } else { - md5_sha = sha_hash; - } - - return Arrays.equals(decrypt, md5_sha); - } else if (data == null || data.length == 0) { - return true; - } else { - return false; - } - } - -} diff --git a/crypto/src/main/java/org/conscrypt/EndOfBufferException.java b/crypto/src/main/java/org/conscrypt/EndOfBufferException.java deleted file mode 100644 index acd3417..0000000 --- a/crypto/src/main/java/org/conscrypt/EndOfBufferException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; - -/** - * This exception indicates that data could not be read from the stream because the underlying input - * stream reached its end. - */ -public class EndOfBufferException extends IOException { - - private static final long serialVersionUID = 1838636631255369519L; - - public EndOfBufferException() { - } - -} diff --git a/crypto/src/main/java/org/conscrypt/EndOfSourceException.java b/crypto/src/main/java/org/conscrypt/EndOfSourceException.java deleted file mode 100644 index 4789cd8..0000000 --- a/crypto/src/main/java/org/conscrypt/EndOfSourceException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; - -/** - * This exception indicates that data could not be read from the buffered stream because underlying - * data buffer was exhausted. - */ -public class EndOfSourceException extends IOException { - - private static final long serialVersionUID = -4673611435974054413L; - - public EndOfSourceException() { - } - -} diff --git a/crypto/src/main/java/org/conscrypt/FileClientSessionCache.java b/crypto/src/main/java/org/conscrypt/FileClientSessionCache.java deleted file mode 100644 index e4dab13..0000000 --- a/crypto/src/main/java/org/conscrypt/FileClientSessionCache.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import javax.net.ssl.SSLSession; -import libcore.io.IoUtils; - -/** - * File-based cache implementation. Only one process should access the - * underlying directory at a time. - */ -public class FileClientSessionCache { - - public static final int MAX_SIZE = 12; // ~72k - - private FileClientSessionCache() {} - - /** - * This cache creates one file per SSL session using "host.port" for - * the file name. Files are created or replaced when session data is put - * in the cache (see {@link #putSessionData}). Files are read on - * cache hits, but not on cache misses. - * - * <p>When the number of session files exceeds MAX_SIZE, we delete the - * least-recently-used file. We don't current persist the last access time, - * so the ordering actually ends up being least-recently-modified in some - * cases and even just "not accessed in this process" if the filesystem - * doesn't track last modified times. - */ - static class Impl implements SSLClientSessionCache { - - /** Directory to store session files in. */ - final File directory; - - /** - * Map of name -> File. Keeps track of the order files were accessed in. - */ - Map<String, File> accessOrder = newAccessOrder(); - - /** The number of files on disk. */ - int size; - - /** - * The initial set of files. We use this to defer adding information - * about all files to accessOrder until necessary. - */ - String[] initialFiles; - - /** - * Constructs a new cache backed by the given directory. - */ - Impl(File directory) throws IOException { - boolean exists = directory.exists(); - if (exists && !directory.isDirectory()) { - throw new IOException(directory + " exists but is not a directory."); - } - - if (exists) { - // Read and sort initial list of files. We defer adding - // information about these files to accessOrder until necessary - // (see indexFiles()). Sorting the list enables us to detect - // cache misses in getSessionData(). - // Note: Sorting an array here was faster than creating a - // HashSet on Dalvik. - initialFiles = directory.list(); - if (initialFiles == null) { - // File.list() will return null in error cases without throwing IOException - // http://b/3363561 - throw new IOException(directory + " exists but cannot list contents."); - } - Arrays.sort(initialFiles); - size = initialFiles.length; - } else { - // Create directory. - if (!directory.mkdirs()) { - throw new IOException("Creation of " + directory + " directory failed."); - } - size = 0; - } - - this.directory = directory; - } - - /** - * Creates a new access-ordered linked hash map. - */ - private static Map<String, File> newAccessOrder() { - return new LinkedHashMap<String, File>( - MAX_SIZE, 0.75f, true /* access order */); - } - - /** - * Gets the file name for the given host and port. - */ - private static String fileName(String host, int port) { - if (host == null) { - throw new NullPointerException("host == null"); - } - return host + "." + port; - } - - public synchronized byte[] getSessionData(String host, int port) { - /* - * Note: This method is only called when the in-memory cache - * in SSLSessionContext misses, so it would be unnecessarily - * redundant for this cache to store data in memory. - */ - - String name = fileName(host, port); - File file = accessOrder.get(name); - - if (file == null) { - // File wasn't in access order. Check initialFiles... - if (initialFiles == null) { - // All files are in accessOrder, so it doesn't exist. - return null; - } - - // Look in initialFiles. - if (Arrays.binarySearch(initialFiles, name) < 0) { - // Not found. - return null; - } - - // The file is on disk but not in accessOrder yet. - file = new File(directory, name); - accessOrder.put(name, file); - } - - FileInputStream in; - try { - in = new FileInputStream(file); - } catch (FileNotFoundException e) { - logReadError(host, file, e); - return null; - } - try { - int size = (int) file.length(); - byte[] data = new byte[size]; - new DataInputStream(in).readFully(data); - return data; - } catch (IOException e) { - logReadError(host, file, e); - return null; - } finally { - IoUtils.closeQuietly(in); - } - } - - static void logReadError(String host, File file, Throwable t) { - System.logW("Error reading session data for " + host + " from " + file + ".", t); - } - - public synchronized void putSessionData(SSLSession session, - byte[] sessionData) { - String host = session.getPeerHost(); - if (sessionData == null) { - throw new NullPointerException("sessionData == null"); - } - - String name = fileName(host, session.getPeerPort()); - File file = new File(directory, name); - - // Used to keep track of whether or not we're expanding the cache. - boolean existedBefore = file.exists(); - - FileOutputStream out; - try { - out = new FileOutputStream(file); - } catch (FileNotFoundException e) { - // We can't write to the file. - logWriteError(host, file, e); - return; - } - - // If we expanded the cache (by creating a new file)... - if (!existedBefore) { - size++; - - // Delete an old file if necessary. - makeRoom(); - } - - boolean writeSuccessful = false; - try { - out.write(sessionData); - writeSuccessful = true; - } catch (IOException e) { - logWriteError(host, file, e); - } finally { - boolean closeSuccessful = false; - try { - out.close(); - closeSuccessful = true; - } catch (IOException e) { - logWriteError(host, file, e); - } finally { - if (!writeSuccessful || !closeSuccessful) { - // Storage failed. Clean up. - delete(file); - } else { - // Success! - accessOrder.put(name, file); - } - } - } - } - - /** - * Deletes old files if necessary. - */ - private void makeRoom() { - if (size <= MAX_SIZE) { - return; - } - - indexFiles(); - - // Delete LRUed files. - int removals = size - MAX_SIZE; - Iterator<File> i = accessOrder.values().iterator(); - do { - delete(i.next()); - i.remove(); - } while (--removals > 0); - } - - /** - * Lazily updates accessOrder to know about all files as opposed to - * just the files accessed since this process started. - */ - private void indexFiles() { - String[] initialFiles = this.initialFiles; - if (initialFiles != null) { - this.initialFiles = null; - - // Files on disk only, sorted by last modified time. - // TODO: Use last access time. - Set<CacheFile> diskOnly = new TreeSet<CacheFile>(); - for (String name : initialFiles) { - // If the file hasn't been accessed in this process... - if (!accessOrder.containsKey(name)) { - diskOnly.add(new CacheFile(directory, name)); - } - } - - if (!diskOnly.isEmpty()) { - // Add files not accessed in this process to the beginning - // of accessOrder. - Map<String, File> newOrder = newAccessOrder(); - for (CacheFile cacheFile : diskOnly) { - newOrder.put(cacheFile.name, cacheFile); - } - newOrder.putAll(accessOrder); - - this.accessOrder = newOrder; - } - } - } - - @SuppressWarnings("ThrowableInstanceNeverThrown") - private void delete(File file) { - if (!file.delete()) { - System.logW("Failed to delete " + file + ".", new IOException()); - } - size--; - } - - static void logWriteError(String host, File file, Throwable t) { - System.logW("Error writing session data for " + host + " to " + file + ".", t); - } - } - - /** - * Maps directories to the cache instances that are backed by those - * directories. We synchronize access using the cache instance, so it's - * important that everyone shares the same instance. - */ - static final Map<File, FileClientSessionCache.Impl> caches - = new HashMap<File, FileClientSessionCache.Impl>(); - - /** - * Returns a cache backed by the given directory. Creates the directory - * (including parent directories) if necessary. This cache should have - * exclusive access to the given directory. - * - * @param directory to store files in - * @return a cache backed by the given directory - * @throws IOException if the file exists and is not a directory or if - * creating the directories fails - */ - public static synchronized SSLClientSessionCache usingDirectory( - File directory) throws IOException { - FileClientSessionCache.Impl cache = caches.get(directory); - if (cache == null) { - cache = new FileClientSessionCache.Impl(directory); - caches.put(directory, cache); - } - return cache; - } - - /** For testing. */ - static synchronized void reset() { - caches.clear(); - } - - /** A file containing a piece of cached data. */ - static class CacheFile extends File { - - final String name; - - CacheFile(File dir, String name) { - super(dir, name); - this.name = name; - } - - long lastModified = -1; - - @Override - public long lastModified() { - long lastModified = this.lastModified; - if (lastModified == -1) { - lastModified = this.lastModified = super.lastModified(); - } - return lastModified; - } - - @Override - public int compareTo(File another) { - // Sort by last modified time. - long result = lastModified() - another.lastModified(); - if (result == 0) { - return super.compareTo(another); - } - return result < 0 ? -1 : 1; - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/Finished.java b/crypto/src/main/java/org/conscrypt/Finished.java deleted file mode 100644 index e0b7eaa..0000000 --- a/crypto/src/main/java/org/conscrypt/Finished.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; - -/** - * - * Represents Finished message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.9. - * Finished</a> - * - */ -public class Finished extends Message { - - // verify data - private byte[] data; - - /** - * Creates outbound message - * @param bytes - */ - public Finished(byte[] bytes) { - data = bytes; - length = data.length; - } - - /** - * Creates inbound message - * @param in - * @param length - * @throws IOException - */ - public Finished(HandshakeIODataStream in, int length) - throws IOException { - if (length == 12 || length == 36) { - data = in.read(length); - this.length = data.length; - } else { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect Finished"); - } - } - - @Override - public void send(HandshakeIODataStream out) { - out.write(data); - } - - /** - * Returns message type - */ - @Override - public int getType() { - return Handshake.FINISHED; - } - - /** - * Returns verify data - */ - public byte[] getData() { - return data; - } -} diff --git a/crypto/src/main/java/org/conscrypt/Handshake.java b/crypto/src/main/java/org/conscrypt/Handshake.java deleted file mode 100644 index 7cee71b..0000000 --- a/crypto/src/main/java/org/conscrypt/Handshake.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * - * This class incapsulates the constants determining the types of handshake - * messages as defined in TLS 1.0 spec., 7.4. Handshake protocol. - * (http://www.ietf.org/rfc/rfc2246.txt) - * - */ -public class Handshake { - - /** - * - * hello_request handshake type - */ - public static final byte HELLO_REQUEST = 0; - - /** - * - * client_hello handshake type - */ - public static final byte CLIENT_HELLO = 1; - - /** - * - * server_hello handshake type - */ - public static final byte SERVER_HELLO = 2; - - /** - * - * certificate handshake type - */ - public static final byte CERTIFICATE = 11; - - /** - * - * server_key_exchange handshake type - */ - public static final byte SERVER_KEY_EXCHANGE = 12; - - /** - * - * certificate_request handshake type - */ - public static final byte CERTIFICATE_REQUEST = 13; - - /** - * - * server_hello_done handshake type - */ - public static final byte SERVER_HELLO_DONE = 14; - - /** - * - * certificate_verify handshake type - */ - public static final byte CERTIFICATE_VERIFY = 15; - - /** - * - * client_key_exchange handshake type - */ - public static final byte CLIENT_KEY_EXCHANGE = 16; - - /** - * - * finished handshake type - */ - public static final byte FINISHED = 20; - -}
\ No newline at end of file diff --git a/crypto/src/main/java/org/conscrypt/HandshakeIODataStream.java b/crypto/src/main/java/org/conscrypt/HandshakeIODataStream.java deleted file mode 100644 index 0723820..0000000 --- a/crypto/src/main/java/org/conscrypt/HandshakeIODataStream.java +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.PrintStream; -import java.security.MessageDigest; -import java.util.Arrays; -import java.util.Locale; -import javax.net.ssl.SSLHandshakeException; - -/** - * This class provides Input/Output data functionality - * for handshake layer. It provides read and write operations - * and accumulates all sent/received handshake's data. - * This class can be presented as a combination of 2 data pipes. - * The first data pipe is a pipe of income data: append method - * places the data at the beginning of the pipe, and read methods - * consume the data from the pipe. The second pipe is an outcoming - * data pipe: write operations plases the data into the pipe, - * and getData methods consume the data. - * It is important to note that work with pipe cound not be - * started if there is unconsumed data in another pipe. It is - * reasoned by the following: handshake protocol performs read - * and write operations consecuently. I.e. it first reads all - * income data and only than produces the responce and places it - * into the stream. - * The read operations of the stream presented by the methods - * of SSLInputStream which in its turn is an extension of InputStream. - * So this stream can be used as an InputStream parameter for - * certificate generation. - * Also input stream functionality supports marks. The marks - * help to reset the position of the stream in case of incompleate - * handshake records. Note that in case of exhausting - * of income data the EndOfBufferException is thown which implies - * the following: - * 1. the stream contains scrappy handshake record, - * 2. the read position should be reseted to marked, - * 3. and more income data is expected. - * The throwing of the exception (instead of returning of -1 value - * or incompleate filling of destination buffer) - * helps to speed up the process of scrappy data recognition and - * processing. - * For more information about TLS handshake process see - * TLS v 1 specification at http://www.ietf.org/rfc/rfc2246.txt. - */ -public class HandshakeIODataStream - extends SSLInputStream implements org.conscrypt.Appendable, DataStream { - - // Objects are used to compute digests of data passed - // during the handshake phase - private static final MessageDigest md5; - private static final MessageDigest sha; - - static { - try { - md5 = MessageDigest.getInstance("MD5"); - sha = MessageDigest.getInstance("SHA-1"); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException( - "Could not initialize the Digest Algorithms."); - } - } - - public HandshakeIODataStream() {} - - // buffer is used to keep the handshaking data; - private int buff_size = 1024; - private int inc_buff_size = 1024; - private byte[] buffer = new byte[buff_size]; - - - // ---------------- Input related functionality ----------------- - - // position of the next byte to read - private int read_pos; - private int marked_pos; - // position of the last byte to read + 1 - private int read_pos_end; - - @Override - public int available() { - return read_pos_end - read_pos; - } - - @Override - public boolean markSupported() { - return true; - } - - @Override - public void mark(int limit) { - marked_pos = read_pos; - } - - public void mark() { - marked_pos = read_pos; - } - - @Override - public void reset() { - read_pos = marked_pos; - } - - /** - * Removes the data from the marked position to - * the current read position. The method is usefull when it is needed - * to delete one message from the internal buffer. - */ - protected void removeFromMarkedPosition() { - System.arraycopy(buffer, read_pos, - buffer, marked_pos, read_pos_end - read_pos); - read_pos_end -= (read_pos - marked_pos); - read_pos = marked_pos; - } - - /** - * read an opaque value; - * @param byte: byte - * @return - */ - @Override - public int read() throws IOException { - if (read_pos == read_pos_end) { - //return -1; - throw new EndOfBufferException(); - } - return buffer[read_pos++] & 0xFF; - } - - /** - * reads vector of opaque values - * @param new: long - * @return - */ - @Override - public byte[] read(int length) throws IOException { - if (length > available()) { - throw new EndOfBufferException(); - } - byte[] res = new byte[length]; - System.arraycopy(buffer, read_pos, res, 0, length); - read_pos = read_pos + length; - return res; - } - - @Override - public int read(byte[] dst, int offset, int length) throws IOException { - if (length > available()) { - throw new EndOfBufferException(); - } - System.arraycopy(buffer, read_pos, dst, offset, length); - read_pos = read_pos + length; - return length; - } - - // ------------------- Extending of the input data --------------------- - - /** - * Appends the income data to be read by handshake protocol. - * The attempts to overflow the buffer by means of this methods - * seem to be futile because of: - * 1. The SSL protocol specifies the maximum size of the record - * and record protocol does not pass huge messages. - * (see TLS v1 specification http://www.ietf.org/rfc/rfc2246.txt , - * p 6.2) - * 2. After each call of this method, handshake protocol should - * start (and starts) the operations on received data and recognize - * the fake data if such was provided (to check the size of certificate - * for example). - */ - public void append(byte[] src) { - append(src, 0, src.length); - } - - private void append(byte[] src, int from, int length) { - if (read_pos == read_pos_end) { - // start reading state after writing - if (write_pos_beg != write_pos) { - // error: outboud handshake data was not sent, - // but inbound handshake data has been received. - throw new AlertException( - AlertProtocol.UNEXPECTED_MESSAGE, - new SSLHandshakeException( - "Handshake message has been received before " - + "the last oubound message had been sent.")); - } - if (read_pos < write_pos) { - read_pos = write_pos; - read_pos_end = read_pos; - } - } - if (read_pos_end + length > buff_size) { - enlargeBuffer(read_pos_end+length-buff_size); - } - System.arraycopy(src, from, buffer, read_pos_end, length); - read_pos_end += length; - } - - private void enlargeBuffer(int size) { - buff_size = (size < inc_buff_size) - ? buff_size + inc_buff_size - : buff_size + size; - byte[] new_buff = new byte[buff_size]; - System.arraycopy(buffer, 0, new_buff, 0, buffer.length); - buffer = new_buff; - } - - protected void clearBuffer() { - read_pos = 0; - marked_pos = 0; - read_pos_end = 0; - write_pos = 0; - write_pos_beg = 0; - Arrays.fill(buffer, (byte) 0); - } - - // ------------------- Output related functionality -------------------- - - // position in the buffer available for write - private int write_pos; - // position in the buffer where the last write session has begun - private int write_pos_beg; - - // checks if the data can be written in the buffer - private void check(int length) { - // (write_pos == write_pos_beg) iff: - // 1. there were not write operations yet - // 2. all written data was demanded by getData methods - if (write_pos == write_pos_beg) { - // just started to write after the reading - if (read_pos != read_pos_end) { - // error: attempt to write outbound data into the stream before - // all the inbound handshake data had been read - throw new AlertException( - AlertProtocol.INTERNAL_ERROR, - new SSLHandshakeException("Data was not fully read: " - + read_pos + " " + read_pos_end)); - } - // set up the write positions - if (write_pos_beg < read_pos_end) { - write_pos_beg = read_pos_end; - write_pos = write_pos_beg; - } - } - // if there is not enought free space in the buffer - enlarge it: - if (write_pos + length >= buff_size) { - enlargeBuffer(length); - } - } - - /** - * Writes an opaque value - * @param byte: byte - */ - public void write(byte b) { - check(1); - buffer[write_pos++] = b; - } - - /** - * Writes Uint8 value - * @param long: the value to be written (last byte) - */ - public void writeUint8(long n) { - check(1); - buffer[write_pos++] = (byte) (n & 0x00ff); - } - - /** - * Writes Uint16 value - * @param long: the value to be written (last 2 bytes) - */ - public void writeUint16(long n) { - check(2); - buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8); - buffer[write_pos++] = (byte) (n & 0x00ff); - } - - /** - * Writes Uint24 value - * @param long: the value to be written (last 3 bytes) - */ - public void writeUint24(long n) { - check(3); - buffer[write_pos++] = (byte) ((n & 0x00ff0000) >> 16); - buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8); - buffer[write_pos++] = (byte) (n & 0x00ff); - } - - /** - * Writes Uint32 value - * @param long: the value to be written (last 4 bytes) - */ - public void writeUint32(long n) { - check(4); - buffer[write_pos++] = (byte) ((n & 0x00ff000000) >> 24); - buffer[write_pos++] = (byte) ((n & 0x00ff0000) >> 16); - buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8); - buffer[write_pos++] = (byte) (n & 0x00ff); - } - - /** - * Writes Uint64 value - * @param long: the value to be written - */ - public void writeUint64(long n) { - check(8); - buffer[write_pos++] = (byte) ((n & 0x00ff00000000000000L) >> 56); - buffer[write_pos++] = (byte) ((n & 0x00ff000000000000L) >> 48); - buffer[write_pos++] = (byte) ((n & 0x00ff0000000000L) >> 40); - buffer[write_pos++] = (byte) ((n & 0x00ff00000000L) >> 32); - buffer[write_pos++] = (byte) ((n & 0x00ff000000) >> 24); - buffer[write_pos++] = (byte) ((n & 0x00ff0000) >> 16); - buffer[write_pos++] = (byte) ((n & 0x00ff00) >> 8); - buffer[write_pos++] = (byte) (n & 0x00ff); - } - - /** - * writes vector of opaque values - * @param vector the vector to be written - */ - public void write(byte[] vector) { - check(vector.length); - System.arraycopy(vector, 0, buffer, write_pos, vector.length); - write_pos += vector.length; - } - - // ------------------- Retrieve the written bytes ---------------------- - - public boolean hasData() { - return (write_pos > write_pos_beg); - } - - /** - * returns the chunk of stored data with the length no more than specified. - * @param length: int - * @return - */ - public byte[] getData(int length) { - byte[] res; - if (write_pos - write_pos_beg < length) { - res = new byte[write_pos - write_pos_beg]; - System.arraycopy(buffer, write_pos_beg, - res, 0, write_pos-write_pos_beg); - write_pos_beg = write_pos; - } else { - res = new byte[length]; - System.arraycopy(buffer, write_pos_beg, res, 0, length); - write_pos_beg += length; - } - return res; - } - - // ---------------------- Message Digest Functionality ---------------- - - /** - * Returns the MD5 digest of the data passed throught the stream - * @return MD5 digest - */ - protected byte[] getDigestMD5() { - synchronized (md5) { - int len = (read_pos_end > write_pos) - ? read_pos_end - : write_pos; - md5.update(buffer, 0, len); - return md5.digest(); - } - } - - /** - * Returns the SHA-1 digest of the data passed throught the stream - * @return SHA-1 digest - */ - protected byte[] getDigestSHA() { - synchronized (sha) { - int len = (read_pos_end > write_pos) - ? read_pos_end - : write_pos; - sha.update(buffer, 0, len); - return sha.digest(); - } - } - - /** - * Returns the MD5 digest of the data passed throught the stream - * except last message - * @return MD5 digest - */ - protected byte[] getDigestMD5withoutLast() { - synchronized (md5) { - md5.update(buffer, 0, marked_pos); - return md5.digest(); - } - } - - /** - * Returns the SHA-1 digest of the data passed throught the stream - * except last message - * @return SHA-1 digest - */ - protected byte[] getDigestSHAwithoutLast() { - synchronized (sha) { - sha.update(buffer, 0, marked_pos); - return sha.digest(); - } - } - - /** - * Returns all the data passed throught the stream - * @return all the data passed throught the stream at the moment - */ - protected byte[] getMessages() { - int len = (read_pos_end > write_pos) ? read_pos_end : write_pos; - byte[] res = new byte[len]; - System.arraycopy(buffer, 0, res, 0, len); - return res; - } -} diff --git a/crypto/src/main/java/org/conscrypt/HandshakeProtocol.java b/crypto/src/main/java/org/conscrypt/HandshakeProtocol.java deleted file mode 100644 index 73d00ae..0000000 --- a/crypto/src/main/java/org/conscrypt/HandshakeProtocol.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.interfaces.RSAKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPublicKeySpec; -import java.util.Arrays; -import java.util.Vector; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; - -/** - * Base class for ClientHandshakeImpl and ServerHandshakeImpl classes. - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4. - * Handshake protocol</a> - * - */ -public abstract class HandshakeProtocol { - - /** - * Handshake status NEED_UNWRAP - HandshakeProtocol needs to receive data - */ - public static final int NEED_UNWRAP = 1; - - /** - * Handshake status NOT_HANDSHAKING - is not currently handshaking - */ - public static final int NOT_HANDSHAKING = 2; - - /** - * Handshake status FINISHED - HandshakeProtocol has just finished - */ - public static final int FINISHED = 3; - - /** - * Handshake status NEED_TASK - HandshakeProtocol needs the results of delegated task - */ - public static final int NEED_TASK = 4; - - /** - * Current handshake status - */ - protected int status = NOT_HANDSHAKING; - - /** - * IO stream for income/outcome handshake data - */ - protected HandshakeIODataStream io_stream = new HandshakeIODataStream(); - - /** - * SSL Record Protocol implementation. - */ - protected SSLRecordProtocol recordProtocol; - - /** - * SSLParametersImpl suplied by SSLSocket or SSLEngine - */ - protected SSLParametersImpl parameters; - - /** - * Delegated tasks for this handshake implementation - */ - protected Vector<DelegatedTask> delegatedTasks = new Vector<DelegatedTask>(); - - /** - * Indicates non-blocking handshake - */ - protected boolean nonBlocking; - - /** - * Pending session - */ - protected SSLSessionImpl session; - - /** - * Sent and received handshake messages - */ - protected ClientHello clientHello; - protected ServerHello serverHello; - protected CertificateMessage serverCert; - protected ServerKeyExchange serverKeyExchange; - protected CertificateRequest certificateRequest; - protected ServerHelloDone serverHelloDone; - protected CertificateMessage clientCert; - protected ClientKeyExchange clientKeyExchange; - protected CertificateVerify certificateVerify; - protected Finished clientFinished; - protected Finished serverFinished; - - /** - * Indicates that change cipher spec message has been received - */ - protected boolean changeCipherSpecReceived = false; - - /** - * Indicates previous session resuming - */ - protected boolean isResuming = false; - - /** - * Premaster secret - */ - protected byte[] preMasterSecret; - - /** - * Exception occured in delegated task - */ - protected Exception delegatedTaskErr; - - // reference verify_data used to verify finished message - private byte[] verify_data = new byte[12]; - - // Encoding of "master secret" string: "master secret".getBytes() - private byte[] master_secret_bytes = - {109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 }; - - // indicates whether protocol needs to send change cipher spec message - private boolean needSendCCSpec = false; - - // indicates whether protocol needs to send change cipher spec message - protected boolean needSendHelloRequest = false; - - /** - * SSLEngine owning this HandshakeProtocol - */ - public SSLEngineImpl engineOwner; - - /** - * SSLSocket owning this HandshakeProtocol - */ - public SSLSocketImpl socketOwner; - - /** - * Creates HandshakeProtocol instance - * @param owner - */ - protected HandshakeProtocol(Object owner) { - if (owner instanceof SSLEngineImpl) { - engineOwner = (SSLEngineImpl) owner; - nonBlocking = true; - this.parameters = engineOwner.sslParameters; - } - else if (owner instanceof SSLSocketImpl) { - socketOwner = (SSLSocketImpl) owner; - nonBlocking = false; - this.parameters = socketOwner.sslParameters; - } - } - - /** - * Sets SSL Record Protocol - * @param recordProtocol - */ - public void setRecordProtocol(SSLRecordProtocol recordProtocol) { - this.recordProtocol = recordProtocol; - } - - /** - * Start session negotiation - */ - public abstract void start(); - - /** - * Stops the current session renegotiation process. - * Such functionality is needed when it is session renegotiation - * process and no_renegotiation alert message is received - * from another peer. - * @param session - */ - protected void stop() { - clearMessages(); - status = NOT_HANDSHAKING; - } - - /** - * Returns handshake status - */ - public SSLEngineResult.HandshakeStatus getStatus() { - if (io_stream.hasData() || needSendCCSpec || - needSendHelloRequest || delegatedTaskErr != null) { - return SSLEngineResult.HandshakeStatus.NEED_WRAP; - } - if (!delegatedTasks.isEmpty()) { - return SSLEngineResult.HandshakeStatus.NEED_TASK; - } - - switch (status) { - case HandshakeProtocol.NEED_UNWRAP: - return SSLEngineResult.HandshakeStatus.NEED_UNWRAP; - case HandshakeProtocol.FINISHED: - status = NOT_HANDSHAKING; - clearMessages(); - return SSLEngineResult.HandshakeStatus.FINISHED; - default: // HandshakeProtocol.NOT_HANDSHAKING: - return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; - } - } - - /** - * Returns pending session - * @return session - */ - public SSLSessionImpl getSession() { - return session; - } - - protected void sendChangeCipherSpec() { - needSendCCSpec = true; - } - - protected void sendHelloRequest() { - needSendHelloRequest = true; - } - - /** - * Proceses inbound ChangeCipherSpec message - */ - abstract void receiveChangeCipherSpec(); - - /** - * Creates and sends finished message - */ - abstract void makeFinished(); - - /** - * Proceses inbound handshake messages - * @param bytes - */ - public abstract void unwrap(byte[] bytes); - - /** - * Processes SSLv2 Hello message - * @param bytes - */ - public abstract void unwrapSSLv2(byte[] bytes); - - /** - * Processes outbound handshake messages - */ - public byte[] wrap() { - if (delegatedTaskErr != null) { - // process error occured in delegated task - Exception e = delegatedTaskErr; - delegatedTaskErr = null; - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "Error occured in delegated task:" + e.getMessage(), e); - } - if (io_stream.hasData()) { - return recordProtocol.wrap(ContentType.HANDSHAKE, io_stream); - } else if (needSendCCSpec) { - makeFinished(); - needSendCCSpec = false; - return recordProtocol.getChangeCipherSpecMesage(getSession()); - } else if (needSendHelloRequest) { - needSendHelloRequest = false; - return recordProtocol.wrap(ContentType.HANDSHAKE, - // hello request message - // (see TLS v 1 specification: - // http://www.ietf.org/rfc/rfc2246.txt) - new byte[] {0, 0, 0, 0}, 0, 4); - } else { - return null; // nothing to send; - } - } - - /** - * Sends fatal alert, breaks execution - * - * @param description - */ - protected void sendWarningAlert(byte description) { - recordProtocol.alert(AlertProtocol.WARNING, description); - } - - /** - * Sends fatal alert, breaks execution - * - * @param description - * @param reason - */ - protected void fatalAlert(byte description, String reason) { - throw new AlertException(description, new SSLHandshakeException(reason)); - } - - /** - * Sends fatal alert, breaks execution - * - * @param description - * @param reason - * @param cause - */ - protected void fatalAlert(byte description, String reason, Exception cause) { - throw new AlertException(description, new SSLException(reason, cause)); - } - - /** - * Sends fatal alert, breaks execution - * - * @param description - * @param cause - */ - protected void fatalAlert(byte description, SSLException cause) { - throw new AlertException(description, cause); - } - - /** - * Computers reference TLS verify_data that is used to verify finished message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS spec. 7.4.9. Finished</a> - * @param label - */ - protected void computerReferenceVerifyDataTLS(String label) { - computerVerifyDataTLS(label, verify_data); - } - - /** - * Computer TLS verify_data - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS spec. 7.4.9. Finished</a> - * @param label - * @param buf - */ - protected void computerVerifyDataTLS(String label, byte[] buf) { - byte[] md5_digest = io_stream.getDigestMD5(); - byte[] sha_digest = io_stream.getDigestSHA(); - - byte[] digest = new byte[md5_digest.length + sha_digest.length]; - System.arraycopy(md5_digest, 0, digest, 0, md5_digest.length); - System.arraycopy(sha_digest, 0, digest, md5_digest.length, - sha_digest.length); - try { - PRF.computePRF(buf, session.master_secret, - label.getBytes(), digest); - } catch (GeneralSecurityException e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e); - } - } - - /** - * Computer reference SSLv3 verify_data that is used to verify finished message - * @see "SSLv3 spec. 7.6.9. Finished" - * @param label - */ - protected void computerReferenceVerifyDataSSLv3(byte[] sender) { - verify_data = new byte[36]; - computerVerifyDataSSLv3(sender, verify_data); - } - - /** - * Computer SSLv3 verify_data - * @see "SSLv3 spec. 7.6.9. Finished" - * @param label - * @param buf - */ - protected void computerVerifyDataSSLv3(byte[] sender, byte[] buf) { - MessageDigest md5; - MessageDigest sha; - try { - md5 = MessageDigest.getInstance("MD5"); - sha = MessageDigest.getInstance("SHA-1"); - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "Could not initialize the Digest Algorithms.", - e); - return; - } - try { - byte[] handshake_messages = io_stream.getMessages(); - md5.update(handshake_messages); - md5.update(sender); - md5.update(session.master_secret); - byte[] b = md5.digest(SSLv3Constants.MD5pad1); - md5.update(session.master_secret); - md5.update(SSLv3Constants.MD5pad2); - System.arraycopy(md5.digest(b), 0, buf, 0, 16); - - sha.update(handshake_messages); - sha.update(sender); - sha.update(session.master_secret); - b = sha.digest(SSLv3Constants.SHApad1); - sha.update(session.master_secret); - sha.update(SSLv3Constants.SHApad2); - System.arraycopy(sha.digest(b), 0, buf, 16, 20); - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e); - - } - } - - /** - * Verifies finished data - * - * @param data - * @param isServer - */ - protected void verifyFinished(byte[] data) { - if (!Arrays.equals(verify_data, data)) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "Incorrect FINISED"); - } - } - - /** - * Sends fatal alert "UNEXPECTED MESSAGE" - * - */ - protected void unexpectedMessage() { - fatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, "UNEXPECTED MESSAGE"); - } - - /** - * Writes message to HandshakeIODataStream - * - * @param message - */ - public void send(Message message) { - io_stream.writeUint8(message.getType()); - io_stream.writeUint24(message.length()); - message.send(io_stream); - } - - /** - * Computers master secret - * - */ - public void computerMasterSecret() { - byte[] seed = new byte[64]; - System.arraycopy(clientHello.getRandom(), 0, seed, 0, 32); - System.arraycopy(serverHello.getRandom(), 0, seed, 32, 32); - session.master_secret = new byte[48]; - if (serverHello.server_version[1] == 1) { // TLSv1 - try { - PRF.computePRF(session.master_secret, preMasterSecret, - master_secret_bytes, seed); - } catch (GeneralSecurityException e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "PRF error", e); - } - } else { // SSL3.0 - PRF.computePRF_SSLv3(session.master_secret, preMasterSecret, seed); - } - - //delete preMasterSecret from memory - Arrays.fill(preMasterSecret, (byte)0); - preMasterSecret = null; - } - - /** - * Returns a delegated task. - * @return Delegated task or null - */ - public Runnable getTask() { - if (delegatedTasks.isEmpty()) { - return null; - } - return delegatedTasks.remove(0); - } - - /** - * Clears previously sent and received handshake messages - */ - protected void clearMessages() { - io_stream.clearBuffer(); - clientHello = null; - serverHello = null; - serverCert = null; - serverKeyExchange = null; - certificateRequest = null; - serverHelloDone = null; - clientCert = null; - clientKeyExchange = null; - certificateVerify = null; - clientFinished = null; - serverFinished = null; - } - - /** - * Returns RSA key length - * @param pk - * @return - * @throws NoSuchAlgorithmException - * @throws InvalidKeySpecException - */ - protected static int getRSAKeyLength(PublicKey pk) - throws NoSuchAlgorithmException, InvalidKeySpecException { - - BigInteger mod; - if (pk instanceof RSAKey) { - mod = ((RSAKey) pk).getModulus(); - } else { - KeyFactory kf = KeyFactory.getInstance("RSA"); - mod = kf.getKeySpec(pk, RSAPublicKeySpec.class) - .getModulus(); - } - return mod.bitLength(); - } - - /** - * Shuts down the protocol. It will be impossible to use the instance - * after calling this method. - */ - protected void shutdown() { - clearMessages(); - session = null; - preMasterSecret = null; - delegatedTasks.clear(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/HelloRequest.java b/crypto/src/main/java/org/conscrypt/HelloRequest.java deleted file mode 100644 index 20efbfd..0000000 --- a/crypto/src/main/java/org/conscrypt/HelloRequest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; - -/** - * - * Represents Hello Request message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.1.1. - * Hello request</a> - * - */ -public class HelloRequest extends Message { - - /** - * Creates outbound message - * - */ - public HelloRequest() { - } - - /** - * Creates inbound message - * @param in - * @param length - * @throws IOException - */ - public HelloRequest(HandshakeIODataStream in, int length) - throws IOException { - if (length != 0) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect HelloRequest"); - } - } - - /** - * Sends message - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - } - - @Override - public int length() { - return 0; - } - - /** - * Returns message type - * @return - */ - @Override - public int getType() { - return Handshake.HELLO_REQUEST; - } - -} diff --git a/crypto/src/main/java/org/conscrypt/JSSEProvider.java b/crypto/src/main/java/org/conscrypt/JSSEProvider.java deleted file mode 100644 index ad56976..0000000 --- a/crypto/src/main/java/org/conscrypt/JSSEProvider.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.Provider; - -/** - * JSSE Provider implementation. - * - * This implementation is based on TLS v 1.0 and SSL v3 protocol specifications. - * - * <ul> - * <li><a href="http://www.ietf.org/rfc/rfc2246.txt">TLS v 1.0 Protocol - * specification</a></li> - * <li><a href="http://wp.netscape.com/eng/ssl3">SSL v3 Protocol - * specification</a></li> - * </ul> - * - * Provider implementation supports the following cipher suites: - * TLS_NULL_WITH_NULL_NULL - * TLS_RSA_WITH_NULL_MD5 - * TLS_RSA_WITH_NULL_SHA - * TLS_RSA_EXPORT_WITH_RC4_40_MD5 - * TLS_RSA_WITH_RC4_128_MD5 - * TLS_RSA_WITH_RC4_128_SHA - * TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 - * TLS_RSA_WITH_IDEA_CBC_SHA - * TLS_RSA_EXPORT_WITH_DES40_CBC_SHA - * TLS_RSA_WITH_DES_CBC_SHA - * TLS_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA - * TLS_DH_DSS_WITH_DES_CBC_SHA - * TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA - * TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA - * TLS_DH_RSA_WITH_DES_CBC_SHA - * TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA - * TLS_DHE_DSS_WITH_DES_CBC_SHA - * TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA - * TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - * TLS_DHE_RSA_WITH_DES_CBC_SHA - * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 - * TLS_DH_anon_WITH_RC4_128_MD5 - * TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA - * TLS_DH_anon_WITH_DES_CBC_SHA - * TLS_DH_anon_WITH_3DES_EDE_CBC_SHA - * - * The real set of available cipher suites depends on set of available - * crypto algorithms. These algorithms must be provided by some crypto - * provider. - * - * The following cipher algorithms are used by different cipher suites: - * IDEA/CBC/NoPadding - * RC2/CBC/NoPadding - * RC4 - * DES/CBC/NoPadding - * DES/CBC/NoPadding - * DESede/CBC/NoPadding - * - * Also the current JSSE provider implementation uses the following - * crypto algorithms: - * - * Algorithms that MUST be provided by crypto provider: - * Mac HmacMD5 - * Mac HmacSHA1 - * MessageDigest MD5 - * MessageDigest SHA-1 - * CertificateFactory X509 - * - * The cipher suites with RSA key exchange may also require: - * Cipher RSA - * KeyPairGenerator RSA - * KeyFactory RSA - * - * The cipher suites with DH key exchange may also require: - * Signature NONEwithDSA - * KeyPairGenerator DiffieHellman or DH - * KeyFactory DiffieHellman or DH - * KeyAgreement DiffieHellman or DH - * KeyPairGenerator DiffieHellman or DH - * - * Trust manager implementation requires: - * CertPathValidator PKIX - * CertificateFactory X509 - * - */ -public final class JSSEProvider extends Provider { - - private static final long serialVersionUID = 3075686092260669675L; - - public JSSEProvider() { - super("HarmonyJSSE", 1.0, "Harmony JSSE Provider"); - - put("SSLContext.SSL", SSLContextImpl.class.getName()); - put("SSLContext.SSLv3", SSLContextImpl.class.getName()); - put("SSLContext.TLS", SSLContextImpl.class.getName()); - put("SSLContext.TLSv1", SSLContextImpl.class.getName()); - - put("KeyManagerFactory.PKIX", KeyManagerFactoryImpl.class.getName()); - put("Alg.Alias.KeyManagerFactory.X509", "PKIX"); - - put("TrustManagerFactory.PKIX", TrustManagerFactoryImpl.class.getName()); - put("Alg.Alias.TrustManagerFactory.X509", "PKIX"); - - put("KeyStore.AndroidCAStore", TrustedCertificateKeyStoreSpi.class.getName()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/KeyManagerFactoryImpl.java b/crypto/src/main/java/org/conscrypt/KeyManagerFactoryImpl.java deleted file mode 100644 index 3ad9be9..0000000 --- a/crypto/src/main/java/org/conscrypt/KeyManagerFactoryImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactorySpi; -import javax.net.ssl.ManagerFactoryParameters; -import org.conscrypt.util.EmptyArray; - -/** - * KeyManagerFactory implementation. - * @see KeyManagerFactorySpi - */ -public class KeyManagerFactoryImpl extends KeyManagerFactorySpi { - - // source of key material - private KeyStore keyStore; - - //password - private char[] pwd; - - /** - * @see KeyManagerFactorySpi#engineInit(KeyStore ks, char[] password) - */ - @Override - protected void engineInit(KeyStore ks, char[] password) - throws KeyStoreException, NoSuchAlgorithmException, - UnrecoverableKeyException { - if (ks != null) { - keyStore = ks; - if (password != null) { - pwd = password.clone(); - } else { - pwd = EmptyArray.CHAR; - } - } else { - keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - String keyStoreName = System.getProperty("javax.net.ssl.keyStore"); - String keyStorePwd = null; - if (keyStoreName == null || keyStoreName.equalsIgnoreCase("NONE") || keyStoreName.isEmpty()) { - try { - keyStore.load(null, null); - } catch (IOException e) { - throw new KeyStoreException(e); - } catch (CertificateException e) { - throw new KeyStoreException(e); - } - } else { - keyStorePwd = System.getProperty("javax.net.ssl.keyStorePassword"); - if (keyStorePwd == null) { - pwd = EmptyArray.CHAR; - } else { - pwd = keyStorePwd.toCharArray(); - } - try { - keyStore.load(new FileInputStream(new File(keyStoreName)), pwd); - } catch (FileNotFoundException e) { - throw new KeyStoreException(e); - } catch (IOException e) { - throw new KeyStoreException(e); - } catch (CertificateException e) { - throw new KeyStoreException(e); - } - } - - } - - } - - /** - * @see KeyManagerFactorySpi#engineInit(ManagerFactoryParameters spec) - */ - @Override - protected void engineInit(ManagerFactoryParameters spec) - throws InvalidAlgorithmParameterException { - throw new InvalidAlgorithmParameterException( - "ManagerFactoryParameters not supported"); - - } - - /** - * @see KeyManagerFactorySpi#engineGetKeyManagers() - */ - @Override - protected KeyManager[] engineGetKeyManagers() { - if (keyStore == null) { - throw new IllegalStateException("KeyManagerFactory is not initialized"); - } - return new KeyManager[] { new KeyManagerImpl(keyStore, pwd) }; - } - -} diff --git a/crypto/src/main/java/org/conscrypt/KeyManagerImpl.java b/crypto/src/main/java/org/conscrypt/KeyManagerImpl.java deleted file mode 100644 index 7a6c92c..0000000 --- a/crypto/src/main/java/org/conscrypt/KeyManagerImpl.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.net.Socket; -import java.security.KeyStore; -import java.security.KeyStore.PrivateKeyEntry; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.UnrecoverableEntryException; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.List; -import java.util.Locale; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.X509ExtendedKeyManager; -import javax.security.auth.x500.X500Principal; - -/** - * KeyManager implementation. - * - * This implementation uses hashed key store information. It works faster than retrieving all of the - * data from the key store. Any key store changes, that happen after key manager was created, have - * no effect. The implementation does not use peer information (host, port) that may be obtained - * from socket or engine. - * - * @see javax.net.ssl.KeyManager - * - */ -public class KeyManagerImpl extends X509ExtendedKeyManager { - - // hashed key store information - private final Hashtable<String, PrivateKeyEntry> hash; - - /** - * Creates Key manager - * - * @param keyStore - * @param pwd - */ - public KeyManagerImpl(KeyStore keyStore, char[] pwd) { - this.hash = new Hashtable<String, PrivateKeyEntry>(); - final Enumeration<String> aliases; - try { - aliases = keyStore.aliases(); - } catch (KeyStoreException e) { - return; - } - for (; aliases.hasMoreElements();) { - final String alias = aliases.nextElement(); - try { - if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) { - final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore - .getEntry(alias, new KeyStore.PasswordProtection(pwd)); - hash.put(alias, entry); - } - } catch (KeyStoreException e) { - continue; - } catch (UnrecoverableEntryException e) { - continue; - } catch (NoSuchAlgorithmException e) { - continue; - } - } - } - - public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) { - final String[] al = chooseAlias(keyTypes, issuers); - return (al == null ? null : al[0]); - } - - public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { - final String[] al = chooseAlias(new String[] { keyType }, issuers); - return (al == null ? null : al[0]); - } - - public X509Certificate[] getCertificateChain(String alias) { - if (alias == null) { - return null; - } - if (hash.containsKey(alias)) { - Certificate[] certs = hash.get(alias).getCertificateChain(); - if (certs[0] instanceof X509Certificate) { - X509Certificate[] xcerts = new X509Certificate[certs.length]; - for (int i = 0; i < certs.length; i++) { - xcerts[i] = (X509Certificate) certs[i]; - } - return xcerts; - } - } - return null; - - } - - public String[] getClientAliases(String keyType, Principal[] issuers) { - return chooseAlias(new String[] { keyType }, issuers); - } - - public String[] getServerAliases(String keyType, Principal[] issuers) { - return chooseAlias(new String[] { keyType }, issuers); - } - - public PrivateKey getPrivateKey(String alias) { - if (alias == null) { - return null; - } - if (hash.containsKey(alias)) { - return hash.get(alias).getPrivateKey(); - } - return null; - } - - @Override - public String chooseEngineClientAlias(String[] keyTypes, Principal[] issuers, SSLEngine engine) { - final String[] al = chooseAlias(keyTypes, issuers); - return (al == null ? null : al[0]); - } - - @Override - public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { - final String[] al = chooseAlias(new String[] { keyType }, issuers); - return (al == null ? null : al[0]); - } - - private String[] chooseAlias(String[] keyTypes, Principal[] issuers) { - if (keyTypes == null || keyTypes.length == 0) { - return null; - } - List<Principal> issuersList = (issuers == null) ? null : Arrays.asList(issuers); - ArrayList<String> found = new ArrayList<String>(); - for (Enumeration<String> aliases = hash.keys(); aliases.hasMoreElements();) { - final String alias = aliases.nextElement(); - final KeyStore.PrivateKeyEntry entry = hash.get(alias); - final Certificate[] chain = entry.getCertificateChain(); - final Certificate cert = chain[0]; - final String certKeyAlg = cert.getPublicKey().getAlgorithm(); - final String certSigAlg = (cert instanceof X509Certificate - ? ((X509Certificate) cert).getSigAlgName().toUpperCase(Locale.US) - : null); - for (String keyAlgorithm : keyTypes) { - if (keyAlgorithm == null) { - continue; - } - final String sigAlgorithm; - // handle cases like EC_EC and EC_RSA - int index = keyAlgorithm.indexOf('_'); - if (index == -1) { - sigAlgorithm = null; - } else { - sigAlgorithm = keyAlgorithm.substring(index + 1); - keyAlgorithm = keyAlgorithm.substring(0, index); - } - // key algorithm does not match - if (!certKeyAlg.equals(keyAlgorithm)) { - continue; - } - /* - * TODO find a more reliable test for signature - * algorithm. Unfortunately value varies with - * provider. For example for "EC" it could be - * "SHA1WithECDSA" or simply "ECDSA". - */ - // sig algorithm does not match - if (sigAlgorithm != null && certSigAlg != null - && !certSigAlg.contains(sigAlgorithm)) { - continue; - } - // no issuers to match, just add to return list and continue - if (issuers == null || issuers.length == 0) { - found.add(alias); - continue; - } - // check that a certificate in the chain was issued by one of the specified issuers - for (Certificate certFromChain : chain) { - if (!(certFromChain instanceof X509Certificate)) { - // skip non-X509Certificates - continue; - } - X509Certificate xcertFromChain = (X509Certificate) certFromChain; - /* - * Note use of X500Principal from - * getIssuerX500Principal as opposed to Principal - * from getIssuerDN. Principal.equals test does - * not work in the case where - * xcertFromChain.getIssuerDN is a bouncycastle - * org.bouncycastle.jce.X509Principal. - */ - X500Principal issuerFromChain = xcertFromChain.getIssuerX500Principal(); - if (issuersList.contains(issuerFromChain)) { - found.add(alias); - } - } - } - } - if (!found.isEmpty()) { - return found.toArray(new String[found.size()]); - } - return null; - } -} diff --git a/crypto/src/main/java/org/conscrypt/Logger.java b/crypto/src/main/java/org/conscrypt/Logger.java deleted file mode 100644 index 9241c8a..0000000 --- a/crypto/src/main/java/org/conscrypt/Logger.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.PrintStream; -import java.util.Locale; -import org.conscrypt.util.EmptyArray; - -/** - * This class provides debug logging for JSSE provider implementation - * TODO: Use java.util.logging - */ -public class Logger { - - public static class Stream extends PrintStream { - private final String prefix; - private static int indent = 0; - - public Stream(String name) { - super(System.err); - prefix = name + "["+Thread.currentThread().getName()+"] "; - } - - @Override - public void print(String msg) { - for (int i=0; i<indent; i++) { - super.print(" "); - } - super.print(msg); - } - - public void newIndent() { - indent ++; - } - - public void endIndent() { - indent --; - } - - @Override - public void println(String msg) { - print(prefix); - super.println(msg); - } - - public void print(byte[] data) { - printAsHex(16, " ", "", data, 0, data.length); - } - - public void print(byte[] data, int offset, int len) { - printAsHex(16, " ", "", data, offset, len); - } - - public void printAsHex(int perLine, String prefix, String delimiter, byte[] data) { - printAsHex(perLine, prefix, delimiter, data, 0, data.length); - } - - public void printAsHex(int perLine, String prefix, String delimiter, - byte[] data, int offset, int len) { - StringBuilder line = new StringBuilder(); - for (int i = 0; i < len; i++) { - line.append(prefix); - line.append(Byte.toHexString(data[i+offset], false)); - line.append(delimiter); - - if (((i+1)%perLine) == 0) { - super.println(line.toString()); - line = new StringBuilder(); - } - } - super.println(line.toString()); - } - } - - private static String[] names; - - static { - try { - names = System.getProperty("jsse", "").split(","); - } catch (Exception e) { - names = EmptyArray.STRING; - } - } - - public static Stream getStream(String name) { - for (int i=0; i<names.length; i++) { - if (names[i].equals(name)) { - return new Stream(name); - } - } - return null; - } -} diff --git a/crypto/src/main/java/org/conscrypt/Message.java b/crypto/src/main/java/org/conscrypt/Message.java deleted file mode 100644 index 3b932d0..0000000 --- a/crypto/src/main/java/org/conscrypt/Message.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; - -/** - * - * Base class for handshake messages - */ -public abstract class Message { - - /* - * Message length - */ - protected int length; - - /** - * Returns message type - */ - abstract int getType(); - - /** - * Returns message length - */ - public int length() { - return length; - } - - /** - * Sends message - * @param out - */ - abstract void send(HandshakeIODataStream out); - - /** - * Sends fatal alert - * @param description - * @param reason - */ - protected void fatalAlert(byte description, String reason) { - throw new AlertException(description, new SSLHandshakeException(reason)); - } - - /** - * Sends fatal alert - * @param description - * @param reason - * @param cause - */ - protected void fatalAlert(byte description, String reason, Throwable cause) { - throw new AlertException(description, new SSLException(reason, cause)); - } -} diff --git a/crypto/src/main/java/org/conscrypt/NativeCrypto.java b/crypto/src/main/java/org/conscrypt/NativeCrypto.java deleted file mode 100644 index 0c1d9fe..0000000 --- a/crypto/src/main/java/org/conscrypt/NativeCrypto.java +++ /dev/null @@ -1,1069 +0,0 @@ -/* - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.OutputStream; -import java.net.SocketTimeoutException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SignatureException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateParsingException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.net.ssl.SSLException; -import javax.security.auth.x500.X500Principal; - -/** - * Provides the Java side of our JNI glue for OpenSSL. - */ -public final class NativeCrypto { - - // --- OpenSSL library initialization -------------------------------------- - static { - /* - * If we're compiled as part of Android, should use a different JNI - * library name. Detect this by looking for the jarjar'd package name. - */ - if ("com.android.org.conscrypt".equals(NativeCrypto.class.getPackage().getName())) { - System.loadLibrary("javacrypto"); - } else { - System.loadLibrary("conscrypt_jni"); - } - - clinit(); - } - - private native static void clinit(); - - // --- ENGINE functions ---------------------------------------------------- - public static native void ENGINE_load_dynamic(); - - public static native long ENGINE_by_id(String id); - - public static native int ENGINE_add(long e); - - public static native int ENGINE_init(long e); - - public static native int ENGINE_finish(long e); - - public static native int ENGINE_free(long e); - - public static native long ENGINE_load_private_key(long e, String key_id); - - public static native String ENGINE_get_id(long engineRef); - - public static native int ENGINE_ctrl_cmd_string(long engineRef, String cmd, String arg, - int cmd_optional); - - // --- DSA/RSA public/private key handling functions ----------------------- - - public static native long EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g, - byte[] pub_key, byte[] priv_key); - - public static native long EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q, - byte[] dmp1, byte[] dmq1, byte[] iqmp); - - public static native long EVP_PKEY_new_mac_key(int type, byte[] key); - - public static native int EVP_PKEY_size(long pkey); - - public static native int EVP_PKEY_type(long pkey); - - public static native String EVP_PKEY_print_public(long pkeyRef); - - public static native String EVP_PKEY_print_private(long pkeyRef); - - public static native void EVP_PKEY_free(long pkey); - - public static native int EVP_PKEY_cmp(long pkey1, long pkey2); - - public static native byte[] i2d_PKCS8_PRIV_KEY_INFO(long pkey); - - public static native long d2i_PKCS8_PRIV_KEY_INFO(byte[] data); - - public static native byte[] i2d_PUBKEY(long pkey); - - public static native long d2i_PUBKEY(byte[] data); - - public static native long RSA_generate_key_ex(int modulusBits, byte[] publicExponent); - - public static native int RSA_size(long pkey); - - public static native int RSA_private_encrypt(int flen, byte[] from, byte[] to, long pkey, - int padding); - - public static native int RSA_public_decrypt(int flen, byte[] from, byte[] to, long pkey, - int padding) throws BadPaddingException, SignatureException; - - public static native int RSA_public_encrypt(int flen, byte[] from, byte[] to, long pkey, - int padding); - - public static native int RSA_private_decrypt(int flen, byte[] from, byte[] to, long pkey, - int padding) throws BadPaddingException, SignatureException; - - /** - * @return array of {n, e} - */ - public static native byte[][] get_RSA_public_params(long rsa); - - /** - * @return array of {n, e, d, p, q, dmp1, dmq1, iqmp} - */ - public static native byte[][] get_RSA_private_params(long rsa); - - public static native long DSA_generate_key(int primeBits, byte[] seed, byte[] g, byte[] p, - byte[] q); - - /** - * @return array of {g, p, q, y(pub), x(priv)} - */ - public static native byte[][] get_DSA_params(long dsa); - - public static native byte[] i2d_RSAPublicKey(long rsa); - - public static native byte[] i2d_RSAPrivateKey(long rsa); - - public static native byte[] i2d_DSAPublicKey(long dsa); - - public static native byte[] i2d_DSAPrivateKey(long dsa); - - // --- EC functions -------------------------- - - /** - * Used to request EC_GROUP_new_curve_GFp to EC_GROUP_new_curve - */ - public static final int EC_CURVE_GFP = 1; - - /** - * Used to request EC_GROUP_new_curve_GF2m to EC_GROUP_new_curve - */ - public static final int EC_CURVE_GF2M = 2; - - /** - * EC_GROUP_set_asn1_flag: indicates an EC_GROUP is a NamedCurve. - */ - public static final int OPENSSL_EC_NAMED_CURVE = 0x001; - - /** - * EC_GROUP_set_point_conversion_form: indicates compressed ASN.1 format - */ - public static final int POINT_CONVERSION_COMPRESSED = 2; - - /** - * EC_GROUP_set_point_conversion_form: indicates uncompressed ASN.1 format - */ - public static final int POINT_CONVERSION_UNCOMPRESSED = 4; - - /** - * EC_GROUP_set_point_conversion_form: indicates hybrid ASN.1 format - */ - public static final int POINT_CONVERSION_HYBRID = 4; - - public static native long EVP_PKEY_new_EC_KEY(long groupRef, long pubkeyRef, byte[] privkey); - - public static native long EC_GROUP_new_by_curve_name(String curveName); - - public static native long EC_GROUP_new_curve(int type, byte[] p, byte[] a, byte[] b); - - public static native long EC_GROUP_dup(long groupRef); - - public static native void EC_GROUP_set_asn1_flag(long groupRef, int flag); - - public static native void EC_GROUP_set_point_conversion_form(long groupRef, int form); - - public static native String EC_GROUP_get_curve_name(long groupRef); - - public static native byte[][] EC_GROUP_get_curve(long groupRef); - - public static native void EC_GROUP_clear_free(long ctx); - - public static native boolean EC_GROUP_cmp(long ctx1, long ctx2); - - public static native void EC_GROUP_set_generator(long groupCtx, long pointCtx, byte[] n, byte[] h); - - public static native long EC_GROUP_get_generator(long groupCtx); - - public static native int get_EC_GROUP_type(long groupCtx); - - public static native byte[] EC_GROUP_get_order(long groupCtx); - - public static native int EC_GROUP_get_degree(long groupCtx); - - public static native byte[] EC_GROUP_get_cofactor(long groupCtx); - - public static native long EC_POINT_new(long groupRef); - - public static native void EC_POINT_clear_free(long pointRef); - - public static native boolean EC_POINT_cmp(long groupRef, long pointRef1, long pointRef2); - - public static native byte[][] EC_POINT_get_affine_coordinates(long groupCtx, long pointCtx); - - public static native void EC_POINT_set_affine_coordinates(long groupCtx, long pointCtx, byte[] x, - byte[] y); - - public static native long EC_KEY_generate_key(long groupRef); - - public static native long EC_KEY_get0_group(long pkeyRef); - - public static native byte[] EC_KEY_get_private_key(long keyRef); - - public static native long EC_KEY_get_public_key(long keyRef); - - public static native int ECDH_compute_key( - byte[] out, int outOffset, long publicKeyRef, long privateKeyRef); - - // --- Message digest functions -------------- - - public static native long EVP_get_digestbyname(String name); - - public static native int EVP_MD_size(long evp_md); - - public static native int EVP_MD_block_size(long evp_md); - - // --- Message digest context functions -------------- - - public static native long EVP_MD_CTX_create(); - - public static native void EVP_MD_CTX_init(long ctx); - - public static native void EVP_MD_CTX_destroy(long ctx); - - public static native long EVP_MD_CTX_copy(long ctx); - - // --- Digest handling functions ------------------------------------------- - - public static native long EVP_DigestInit(long evp_md); - - public static native void EVP_DigestUpdate(long ctx, byte[] buffer, int offset, int length); - - public static native int EVP_DigestFinal(long ctx, byte[] hash, int offset); - - // --- MAC handling functions ---------------------------------------------- - - public static native void EVP_DigestSignInit(long evp_md_ctx, long evp_md, long evp_pkey); - - public static native void EVP_DigestSignUpdate(long evp_md_ctx, byte[] in); - - public static native byte[] EVP_DigestSignFinal(long evp_md_ctx); - - // --- Signature handling functions ---------------------------------------- - - public static native long EVP_SignInit(String algorithm); - - public static native void EVP_SignUpdate(long ctx, byte[] buffer, - int offset, int length); - - public static native int EVP_SignFinal(long ctx, byte[] signature, int offset, long key); - - public static native long EVP_VerifyInit(String algorithm); - - public static native void EVP_VerifyUpdate(long ctx, byte[] buffer, - int offset, int length); - - public static native int EVP_VerifyFinal(long ctx, byte[] signature, - int offset, int length, long key); - - - // --- Block ciphers ------------------------------------------------------- - - public static native long EVP_get_cipherbyname(String string); - - public static native void EVP_CipherInit_ex(long ctx, long evpCipher, byte[] key, byte[] iv, - boolean encrypting); - - public static native int EVP_CipherUpdate(long ctx, byte[] out, int outOffset, byte[] in, - int inOffset, int inLength); - - public static native int EVP_CipherFinal_ex(long ctx, byte[] out, int outOffset) - throws BadPaddingException, IllegalBlockSizeException; - - public static native int EVP_CIPHER_iv_length(long evpCipher); - - public static native long EVP_CIPHER_CTX_new(); - - public static native int EVP_CIPHER_CTX_block_size(long ctx); - - public static native int get_EVP_CIPHER_CTX_buf_len(long ctx); - - public static native void EVP_CIPHER_CTX_set_padding(long ctx, boolean enablePadding); - - public static native void EVP_CIPHER_CTX_set_key_length(long ctx, int keyBitSize); - - public static native void EVP_CIPHER_CTX_cleanup(long ctx); - - // --- 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); - - public static native void RAND_bytes(byte[] output); - - // --- ASN.1 objects ------------------------------------------------------- - - public static native int OBJ_txt2nid(String oid); - - public static native String OBJ_txt2nid_longName(String oid); - - public static native String OBJ_txt2nid_oid(String oid); - - // --- 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()); - int offset = 0; - return (((digest[offset++] & 0xff) << 0) | - ((digest[offset++] & 0xff) << 8) | - ((digest[offset++] & 0xff) << 16) | - ((digest[offset ] & 0xff) << 24)); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } - } - - public static native String X509_NAME_print_ex(long x509nameCtx, long flags); - - // --- X509 ---------------------------------------------------------------- - - /** Used to request get_X509_GENERAL_NAME_stack get the "altname" field. */ - public static final int GN_STACK_SUBJECT_ALT_NAME = 1; - - /** - * Used to request get_X509_GENERAL_NAME_stack get the issuerAlternativeName - * extension. - */ - public static final int GN_STACK_ISSUER_ALT_NAME = 2; - - /** - * Used to request only non-critical types in get_X509*_ext_oids. - */ - public static final int EXTENSION_TYPE_NON_CRITICAL = 0; - - /** - * Used to request only critical types in get_X509*_ext_oids. - */ - public static final int EXTENSION_TYPE_CRITICAL = 1; - - public static native long d2i_X509_bio(long bioCtx); - - public static native long d2i_X509(byte[] encoded); - - public static native long PEM_read_bio_X509(long bioCtx); - - public static native byte[] i2d_X509(long x509ctx); - - /** Takes an X509 context not an X509_PUBKEY context. */ - public static native byte[] i2d_X509_PUBKEY(long x509ctx); - - public static native byte[] ASN1_seq_pack_X509(long[] x509CertRefs); - - public static native long[] ASN1_seq_unpack_X509_bio(long bioRef); - - public static native void X509_free(long x509ctx); - - public static native int X509_cmp(long x509ctx1, long x509ctx2); - - public static native int get_X509_hashCode(long x509ctx); - - public static native void X509_print_ex(long bioCtx, long x509ctx, long nmflag, long certflag); - - public static native byte[] X509_get_issuer_name(long x509ctx); - - public static native byte[] X509_get_subject_name(long x509ctx); - - public static native String get_X509_sig_alg_oid(long x509ctx); - - public static native byte[] get_X509_sig_alg_parameter(long x509ctx); - - public static native boolean[] get_X509_issuerUID(long x509ctx); - - public static native boolean[] get_X509_subjectUID(long x509ctx); - - public static native long X509_get_pubkey(long x509ctx) throws NoSuchAlgorithmException; - - public static native String get_X509_pubkey_oid(long x509ctx); - - public static native byte[] X509_get_ext_oid(long x509ctx, String oid); - - public static native String[] get_X509_ext_oids(long x509ctx, int critical); - - public static native Object[][] get_X509_GENERAL_NAME_stack(long x509ctx, int type) - throws CertificateParsingException; - - public static native boolean[] get_X509_ex_kusage(long x509ctx); - - public static native String[] get_X509_ex_xkusage(long x509ctx); - - public static native int get_X509_ex_pathlen(long x509ctx); - - public static native long X509_get_notBefore(long x509ctx); - - public static native long X509_get_notAfter(long x509ctx); - - public static native long X509_get_version(long x509ctx); - - public static native byte[] X509_get_serialNumber(long x509ctx); - - public static native void X509_verify(long x509ctx, long pkeyCtx); - - public static native byte[] get_X509_cert_info_enc(long x509ctx); - - public static native byte[] get_X509_signature(long x509ctx); - - public static native int get_X509_ex_flags(long x509ctx); - - public static native int X509_check_issued(long ctx, long ctx2); - - // --- X509 EXFLAG --------------------------------------------------------- - - public static final int EXFLAG_CA = 0x10; - - public static final int EXFLAG_CRITICAL = 0x200; - - // --- PKCS7 --------------------------------------------------------------- - - /** Used as the "which" field in d2i_PKCS7_bio and PEM_read_bio_PKCS7. */ - public static final int PKCS7_CERTS = 1; - - /** Used as the "which" field in d2i_PKCS7_bio and PEM_read_bio_PKCS7. */ - public static final int PKCS7_CRLS = 2; - - /** Returns an array of X509 or X509_CRL pointers. */ - public static native long[] d2i_PKCS7_bio(long bioCtx, int which); - - /** Returns an array of X509 or X509_CRL pointers. */ - public static native byte[] i2d_PKCS7(long[] certs); - - /** Returns an array of X509 or X509_CRL pointers. */ - public static native long[] PEM_read_bio_PKCS7(long bioCtx, int which); - - // --- X509_CRL ------------------------------------------------------------ - - public static native long d2i_X509_CRL_bio(long bioCtx); - - public static native long PEM_read_bio_X509_CRL(long bioCtx); - - public static native byte[] i2d_X509_CRL(long x509CrlCtx); - - public static native void X509_CRL_free(long x509CrlCtx); - - public static native void X509_CRL_print(long bioCtx, long x509CrlCtx); - - public static native String get_X509_CRL_sig_alg_oid(long x509CrlCtx); - - public static native byte[] get_X509_CRL_sig_alg_parameter(long x509CrlCtx); - - public static native byte[] X509_CRL_get_issuer_name(long x509CrlCtx); - - /** Returns X509_REVOKED reference that is not duplicated! */ - public static native long X509_CRL_get0_by_cert(long x509CrlCtx, long x509Ctx); - - /** Returns X509_REVOKED reference that is not duplicated! */ - public static native long X509_CRL_get0_by_serial(long x509CrlCtx, byte[] serial); - - /** Returns an array of X509_REVOKED that are owned by the caller. */ - public static native long[] X509_CRL_get_REVOKED(long x509CrlCtx); - - public static native String[] get_X509_CRL_ext_oids(long x509ctx, int critical); - - public static native byte[] X509_CRL_get_ext_oid(long x509CrlCtx, String oid); - - public static native long X509_CRL_get_version(long x509CrlCtx); - - public static native long X509_CRL_get_ext(long x509CrlCtx, String oid); - - public static native byte[] get_X509_CRL_signature(long x509ctx); - - public static native void X509_CRL_verify(long x509CrlCtx, long pkeyCtx); - - public static native byte[] get_X509_CRL_crl_enc(long x509CrlCtx); - - public static native long X509_CRL_get_lastUpdate(long x509CrlCtx); - - public static native long X509_CRL_get_nextUpdate(long x509CrlCtx); - - // --- X509_REVOKED -------------------------------------------------------- - - public static native long X509_REVOKED_dup(long x509RevokedCtx); - - public static native byte[] i2d_X509_REVOKED(long x509RevokedCtx); - - public static native String[] get_X509_REVOKED_ext_oids(long x509ctx, int critical); - - public static native byte[] X509_REVOKED_get_ext_oid(long x509RevokedCtx, String oid); - - public static native byte[] X509_REVOKED_get_serialNumber(long x509RevokedCtx); - - public static native long X509_REVOKED_get_ext(long x509RevokedCtx, String oid); - - /** Returns ASN1_TIME reference. */ - public static native long get_X509_REVOKED_revocationDate(long x509RevokedCtx); - - public static native void X509_REVOKED_print(long bioRef, long x509RevokedCtx); - - // --- X509_EXTENSION ------------------------------------------------------ - - public static native int X509_supported_extension(long x509ExtensionRef); - - // --- ASN1_TIME ----------------------------------------------------------- - - public static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal); - - // --- BIO stream creation ------------------------------------------------- - - public static native long create_BIO_InputStream(OpenSSLBIOInputStream is); - - public static native long create_BIO_OutputStream(OutputStream os); - - public static native int BIO_read(long bioRef, byte[] buffer); - - public static native void BIO_write(long bioRef, byte[] buffer, int offset, int length) - throws IOException; - - public static native void BIO_free(long bioRef); - - // --- SSL handling -------------------------------------------------------- - - private static final String SUPPORTED_PROTOCOL_SSLV3 = "SSLv3"; - private static final String SUPPORTED_PROTOCOL_TLSV1 = "TLSv1"; - private static final String SUPPORTED_PROTOCOL_TLSV1_1 = "TLSv1.1"; - private static final String SUPPORTED_PROTOCOL_TLSV1_2 = "TLSv1.2"; - - 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; - } - - // EVP_PKEY types from evp.h and objects.h - public static final int EVP_PKEY_RSA = 6; // NID_rsaEcnryption - public static final int EVP_PKEY_DSA = 116; // NID_dsa - public static final int EVP_PKEY_DH = 28; // NID_dhKeyAgreement - public static final int EVP_PKEY_EC = 408; // NID_X9_62_id_ecPublicKey - public static final int EVP_PKEY_HMAC = 855; // NID_hmac - public static final int EVP_PKEY_CMAC = 894; // NID_cmac - - // RSA padding modes from rsa.h - public static final int RSA_PKCS1_PADDING = 1; - public static final int RSA_NO_PADDING = 3; - - // SSL mode from ssl.h - public static final long SSL_MODE_HANDSHAKE_CUTTHROUGH = 0x00000020L; - - // SSL options from ssl.h - public static final long SSL_OP_NO_TICKET = 0x00004000L; - public static final long SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000L; - public static final long SSL_OP_NO_SSLv3 = 0x02000000L; - public static final long SSL_OP_NO_TLSv1 = 0x04000000L; - public static final long SSL_OP_NO_TLSv1_1 = 0x10000000L; - public static final long SSL_OP_NO_TLSv1_2 = 0x08000000L; - - public static native long 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(long ssl_ctx); - - public static native void SSL_CTX_set_session_id_context(long ssl_ctx, byte[] sid_ctx); - - public static native long SSL_new(long ssl_ctx) throws SSLException; - - public static native void SSL_enable_tls_channel_id(long ssl) throws SSLException; - - public static native byte[] SSL_get_tls_channel_id(long ssl) throws SSLException; - - public static native void SSL_set1_tls_channel_id(long ssl, long pkey); - - public static native void SSL_use_certificate(long ssl, long[] x509refs); - - public static native void SSL_use_PrivateKey(long ssl, long pkey); - - public static native void SSL_check_private_key(long ssl) throws SSLException; - - public static native void SSL_set_client_CA_list(long ssl, byte[][] asn1DerEncodedX500Principals); - - public static native long SSL_get_mode(long ssl); - - public static native long SSL_set_mode(long ssl, long mode); - - public static native long SSL_clear_mode(long ssl, long mode); - - public static native long SSL_get_options(long ssl); - - public static native long SSL_set_options(long ssl, long options); - - public static native long SSL_clear_options(long ssl, long options); - - public static String[] getDefaultProtocols() { - return new String[] { SUPPORTED_PROTOCOL_SSLV3, - SUPPORTED_PROTOCOL_TLSV1, - }; - } - - public static String[] getSupportedProtocols() { - return new String[] { SUPPORTED_PROTOCOL_SSLV3, - SUPPORTED_PROTOCOL_TLSV1, - SUPPORTED_PROTOCOL_TLSV1_1, - SUPPORTED_PROTOCOL_TLSV1_2, - }; - } - - public static void setEnabledProtocols(long 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 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2); - 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 if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1_1)) { - optionsToSet &= ~SSL_OP_NO_TLSv1_1; - optionsToClear |= SSL_OP_NO_TLSv1_1; - } else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1_2)) { - optionsToSet &= ~SSL_OP_NO_TLSv1_2; - optionsToClear |= SSL_OP_NO_TLSv1_2; - } 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)) - && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1_1)) - && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1_2))) { - throw new IllegalArgumentException("protocol " + protocol - + " is not supported"); - } - } - return protocols; - } - - public static native void SSL_set_cipher_lists(long ssl, String[] ciphers); - - public static void setEnabledCipherSuites(long 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; - } - - /* - * 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(long sslNativePointer, int mode); - - public static native void SSL_set_session(long sslNativePointer, long sslSessionNativePointer) - throws SSLException; - - public static native void SSL_set_session_creation_enabled( - long sslNativePointer, boolean creationEnabled) throws SSLException; - - public static native void SSL_set_tlsext_host_name(long sslNativePointer, String hostname) - throws SSLException; - public static native String SSL_get_servername(long sslNativePointer); - - /** - * Enables NPN for all SSL connections in the context. - * - * <p>For clients this causes the NPN extension to be included in the - * ClientHello message. - * - * <p>For servers this causes the NPN extension to be included in the - * ServerHello message. The NPN extension will not be included in the - * ServerHello response if the client didn't include it in the ClientHello - * request. - * - * <p>In either case the caller should pass a non-null byte array of NPN - * protocols to {@link #SSL_do_handshake}. - */ - public static native void SSL_CTX_enable_npn(long sslCtxNativePointer); - - /** - * Disables NPN for all SSL connections in the context. - */ - public static native void SSL_CTX_disable_npn(long sslCtxNativePointer); - - /** - * For clients, sets the list of supported ALPN protocols in wire-format - * (length-prefixed 8-bit strings) on an SSL context. - */ - public static native int SSL_CTX_set_alpn_protos(long sslCtxPointer, byte[] protos); - - /** - * Returns the selected ALPN protocol. If the server did not select a - * protocol, {@code null} will be returned. - */ - public static native byte[] SSL_get0_alpn_selected(long sslPointer); - - /** - * Returns the sslSessionNativePointer of the negotiated session. If this is - * a server negotiation, supplying the {@code alpnProtocols} will enable - * ALPN negotiation. - */ - public static native int SSL_do_handshake(long sslNativePointer, - FileDescriptor fd, - SSLHandshakeCallbacks shc, - int timeoutMillis, - boolean client_mode, - byte[] npnProtocols, - byte[] alpnProtocols) - throws SSLException, SocketTimeoutException, CertificateException; - - public static native byte[] SSL_get_npn_negotiated_protocol(long sslNativePointer); - - /** - * Currently only intended for forcing renegotiation for testing. - * Not used within OpenSSLSocketImpl. - */ - public static native void SSL_renegotiate(long sslNativePointer) throws SSLException; - - /** - * Returns the local X509 certificate references. Must X509_free when done. - */ - public static native long[] SSL_get_certificate(long sslNativePointer); - - /** - * Returns the peer X509 certificate references. Must X509_free when done. - */ - public static native long[] SSL_get_peer_cert_chain(long 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(long sslNativePointer, - FileDescriptor fd, - SSLHandshakeCallbacks shc, - byte[] b, int off, int len, int readTimeoutMillis) - throws IOException; - - /** - * Writes with the native SSL_write function to the encrypted data stream. - */ - public static native void SSL_write(long sslNativePointer, - FileDescriptor fd, - SSLHandshakeCallbacks shc, - byte[] b, int off, int len, int writeTimeoutMillis) - throws IOException; - - public static native void SSL_interrupt(long sslNativePointer); - public static native void SSL_shutdown(long sslNativePointer, - FileDescriptor fd, - SSLHandshakeCallbacks shc) throws IOException; - - public static native void SSL_free(long sslNativePointer); - - public static native byte[] SSL_SESSION_session_id(long sslSessionNativePointer); - - public static native long SSL_SESSION_get_time(long sslSessionNativePointer); - - public static native String SSL_SESSION_get_version(long sslSessionNativePointer); - - public static native String SSL_SESSION_cipher(long sslSessionNativePointer); - - public static native void SSL_SESSION_free(long sslSessionNativePointer); - - public static native byte[] i2d_SSL_SESSION(long sslSessionNativePointer); - - public static native long 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 certificateChainRefs chain of X.509 certificate references - * @param authMethod auth algorithm name - * - * @throws CertificateException if the certificate is untrusted - */ - public void verifyCertificateChain(long[] certificateChainRefs, 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(); - } - - public static native long ERR_peek_last_error(); -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLBIOInputStream.java b/crypto/src/main/java/org/conscrypt/OpenSSLBIOInputStream.java deleted file mode 100644 index 26971d5..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLBIOInputStream.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Provides an interface to OpenSSL's BIO system directly from a Java - * InputStream. It allows an OpenSSL API to read directly from something more - * flexible interface than a byte array. - */ -public class OpenSSLBIOInputStream extends FilterInputStream { - private long ctx; - - public OpenSSLBIOInputStream(InputStream is) { - super(is); - - ctx = NativeCrypto.create_BIO_InputStream(this); - } - - public long getBioContext() { - return ctx; - } - - /** - * Similar to a {@code readLine} method, but matches what OpenSSL expects - * from a {@code BIO_gets} method. - */ - public int gets(byte[] buffer) throws IOException { - if (buffer == null || buffer.length == 0) { - return 0; - } - - int offset = 0; - int inputByte = 0; - while (offset < buffer.length) { - inputByte = read(); - if (inputByte == -1) { - // EOF - break; - } - if (inputByte == '\n') { - if (offset == 0) { - // If we haven't read anything yet, ignore CRLF. - continue; - } else { - break; - } - } - - buffer[offset++] = (byte) inputByte; - } - - return offset; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLCipher.java b/crypto/src/main/java/org/conscrypt/OpenSSLCipher.java deleted file mode 100644 index e3f76bf..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLCipher.java +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.InvalidParameterException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.InvalidParameterSpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.Arrays; -import java.util.Locale; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.CipherSpi; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import org.conscrypt.util.EmptyArray; - -public abstract class OpenSSLCipher extends CipherSpi { - - /** - * Modes that a block cipher may support. - */ - protected static enum Mode { - CBC, - CFB, CFB1, CFB8, CFB128, - CTR, - CTS, - ECB, - OFB, OFB64, OFB128, - PCBC, - } - - /** - * Paddings that a block cipher may support. - */ - protected static enum Padding { - NOPADDING, - PKCS5PADDING, - ISO10126PADDING, - } - - /** - * Native pointer for the OpenSSL EVP_CIPHER context. - */ - private OpenSSLCipherContext cipherCtx = new OpenSSLCipherContext( - NativeCrypto.EVP_CIPHER_CTX_new()); - - /** - * The current cipher mode. - */ - private Mode mode = Mode.ECB; - - /** - * The current cipher padding. - */ - private Padding padding = Padding.PKCS5PADDING; - - /** - * The Initial Vector (IV) used for the current cipher. - */ - private byte[] iv; - - /** - * Current cipher mode: encrypting or decrypting. - */ - private boolean encrypting; - - /** - * The block size of the current cipher. - */ - private int blockSize; - - /** - * The block size of the current mode. - */ - private int modeBlockSize; - - /** - * Whether the cipher has processed any data yet. OpenSSL doesn't like - * calling "doFinal()" in decryption mode without processing any updates. - */ - private boolean calledUpdate; - - protected OpenSSLCipher() { - } - - protected OpenSSLCipher(Mode mode, Padding padding) { - this.mode = mode; - this.padding = padding; - blockSize = getCipherBlockSize(); - } - - /** - * Returns the standard name for the particular algorithm. - */ - protected abstract String getBaseCipherName(); - - /** - * Returns the OpenSSL cipher name for the particular {@code keySize} and - * cipher {@code mode}. - */ - protected abstract String getCipherName(int keySize, Mode mode); - - /** - * Checks whether the cipher supports this particular {@code keySize} (in - * bytes) and throws {@code InvalidKeyException} if it doesn't. - */ - protected abstract void checkSupportedKeySize(int keySize) throws InvalidKeyException; - - /** - * Checks whether the cipher supports this particular cipher {@code mode} - * and throws {@code NoSuchAlgorithmException} if it doesn't. - */ - protected abstract void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException; - - /** - * Checks whether the cipher supports this particular cipher {@code padding} - * and throws {@code NoSuchPaddingException} if it doesn't. - */ - protected abstract void checkSupportedPadding(Padding padding) throws NoSuchPaddingException; - - protected abstract int getCipherBlockSize(); - - protected boolean supportsVariableSizeKey() { - return false; - } - - @Override - protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException { - final Mode mode; - try { - mode = Mode.valueOf(modeStr.toUpperCase(Locale.US)); - } catch (IllegalArgumentException e) { - NoSuchAlgorithmException newE = new NoSuchAlgorithmException("No such mode: " - + modeStr); - newE.initCause(e); - throw newE; - } - checkSupportedMode(mode); - this.mode = mode; - } - - @Override - protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException { - final String paddingStrUpper = paddingStr.toUpperCase(Locale.US); - final Padding padding; - try { - padding = Padding.valueOf(paddingStrUpper); - } catch (IllegalArgumentException e) { - NoSuchPaddingException newE = new NoSuchPaddingException("No such padding: " - + paddingStr); - newE.initCause(e); - throw newE; - } - checkSupportedPadding(padding); - this.padding = padding; - } - - @Override - protected int engineGetBlockSize() { - return blockSize; - } - - /** - * The size of output if {@code doFinal()} is called with this - * {@code inputLen}. If padding is enabled and the size of the input puts it - * right at the block size, it will add another block for the padding. - */ - private int getOutputSize(int inputLen) { - if (modeBlockSize == 1) { - return inputLen; - } else { - final int buffered = NativeCrypto.get_EVP_CIPHER_CTX_buf_len(cipherCtx.getContext()); - if (padding == Padding.NOPADDING) { - return buffered + inputLen; - } else { - final int totalLen = inputLen + buffered + modeBlockSize; - return totalLen - (totalLen % modeBlockSize); - } - } - } - - @Override - protected int engineGetOutputSize(int inputLen) { - return getOutputSize(inputLen); - } - - @Override - protected byte[] engineGetIV() { - return iv; - } - - @Override - protected AlgorithmParameters engineGetParameters() { - if (iv != null && iv.length > 0) { - try { - AlgorithmParameters params = AlgorithmParameters.getInstance(getBaseCipherName()); - params.init(iv); - return params; - } catch (NoSuchAlgorithmException e) { - return null; - } catch (IOException e) { - return null; - } - } - return null; - } - - private void engineInitInternal(int opmode, Key key, byte[] iv, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) { - encrypting = true; - } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) { - encrypting = false; - } else { - throw new InvalidParameterException("Unsupported opmode " + opmode); - } - - if (!(key instanceof SecretKey)) { - throw new InvalidKeyException("Only SecretKey is supported"); - } - - final byte[] encodedKey = key.getEncoded(); - if (encodedKey == null) { - throw new InvalidKeyException("key.getEncoded() == null"); - } - - checkSupportedKeySize(encodedKey.length); - - final long cipherType = NativeCrypto.EVP_get_cipherbyname(getCipherName(encodedKey.length, - mode)); - if (cipherType == 0) { - throw new InvalidAlgorithmParameterException("Cannot find name for key length = " - + (encodedKey.length * 8) + " and mode = " + mode); - } - - final int ivLength = NativeCrypto.EVP_CIPHER_iv_length(cipherType); - if (iv == null && ivLength != 0) { - iv = new byte[ivLength]; - if (encrypting) { - if (random == null) { - random = new SecureRandom(); - } - random.nextBytes(iv); - } - } else if (iv != null && iv.length != ivLength) { - throw new InvalidAlgorithmParameterException("expected IV length of " + ivLength); - } - - this.iv = iv; - - if (supportsVariableSizeKey()) { - NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), cipherType, null, null, - encrypting); - NativeCrypto.EVP_CIPHER_CTX_set_key_length(cipherCtx.getContext(), encodedKey.length); - NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), 0, encodedKey, iv, encrypting); - } else { - NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), cipherType, encodedKey, iv, - encrypting); - } - - // OpenSSL only supports PKCS5 Padding. - NativeCrypto.EVP_CIPHER_CTX_set_padding(cipherCtx.getContext(), - padding == Padding.PKCS5PADDING); - modeBlockSize = NativeCrypto.EVP_CIPHER_CTX_block_size(cipherCtx.getContext()); - calledUpdate = false; - } - - @Override - protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - try { - engineInitInternal(opmode, key, null, random); - } catch (InvalidAlgorithmParameterException e) { - throw new RuntimeException(e); - } - } - - @Override - protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, - SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - final byte[] iv; - if (params instanceof IvParameterSpec) { - IvParameterSpec ivParams = (IvParameterSpec) params; - iv = ivParams.getIV(); - } else { - iv = null; - } - - engineInitInternal(opmode, key, iv, random); - } - - @Override - protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - final AlgorithmParameterSpec spec; - try { - spec = params.getParameterSpec(IvParameterSpec.class); - } catch (InvalidParameterSpecException e) { - throw new InvalidAlgorithmParameterException(e); - } - - engineInit(opmode, key, spec, random); - } - - private final int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset, int maximumLen) throws ShortBufferException { - final int intialOutputOffset = outputOffset; - - final int bytesLeft = output.length - outputOffset; - if (bytesLeft < maximumLen) { - throw new ShortBufferException("output buffer too small during update: " + bytesLeft - + " < " + maximumLen); - } - - outputOffset += NativeCrypto.EVP_CipherUpdate(cipherCtx.getContext(), output, outputOffset, - input, inputOffset, inputLen); - - calledUpdate = true; - - return outputOffset - intialOutputOffset; - } - - @Override - protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - final int maximumLen = getOutputSize(inputLen); - - /* See how large our output buffer would need to be. */ - final byte[] output; - if (maximumLen > 0) { - output = new byte[maximumLen]; - } else { - output = EmptyArray.BYTE; - } - - final int bytesWritten; - try { - bytesWritten = updateInternal(input, inputOffset, inputLen, output, 0, maximumLen); - } catch (ShortBufferException e) { - /* This shouldn't happen. */ - throw new RuntimeException("calculated buffer size was wrong: " + maximumLen); - } - - if (output.length == bytesWritten) { - return output; - } else if (bytesWritten == 0) { - return EmptyArray.BYTE; - } else { - return Arrays.copyOfRange(output, 0, bytesWritten); - } - } - - @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset) throws ShortBufferException { - final int maximumLen = getOutputSize(inputLen); - return updateInternal(input, inputOffset, inputLen, output, outputOffset, maximumLen); - } - - /** - * Reset this Cipher instance state to process a new chunk of data. - */ - private void reset() { - NativeCrypto.EVP_CipherInit_ex(cipherCtx.getContext(), 0, null, null, encrypting); - calledUpdate = false; - } - - private int doFinalInternal(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset, int maximumLen) throws IllegalBlockSizeException, - BadPaddingException, ShortBufferException { - /* Remember this so we can tell how many characters were written. */ - final int initialOutputOffset = outputOffset; - - if (inputLen > 0) { - final int updateBytesWritten = updateInternal(input, inputOffset, inputLen, output, - outputOffset, maximumLen); - outputOffset += updateBytesWritten; - maximumLen -= updateBytesWritten; - } - - /* - * If we're decrypting and haven't had any input, we should return null. - * Otherwise OpenSSL will complain if we call final. - */ - if (!encrypting && !calledUpdate) { - return 0; - } - - /* Allow OpenSSL to pad if necessary and clean up state. */ - final int bytesLeft = output.length - outputOffset; - final int writtenBytes; - if (bytesLeft >= maximumLen) { - writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx.getContext(), output, - outputOffset); - } else { - final byte[] lastBlock = new byte[maximumLen]; - writtenBytes = NativeCrypto.EVP_CipherFinal_ex(cipherCtx.getContext(), lastBlock, 0); - if (writtenBytes > bytesLeft) { - throw new ShortBufferException("buffer is too short: " + writtenBytes + " > " - + bytesLeft); - } else if (writtenBytes > 0) { - System.arraycopy(lastBlock, 0, output, outputOffset, writtenBytes); - } - } - outputOffset += writtenBytes; - - reset(); - - return outputOffset - initialOutputOffset; - } - - @Override - protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) - throws IllegalBlockSizeException, BadPaddingException { - /* - * Other implementations return null if we've never called update() - * while decrypting. - */ - if (!encrypting && !calledUpdate && inputLen == 0) { - reset(); - return null; - } - - final int maximumLen = getOutputSize(inputLen); - /* Assume that we'll output exactly on a byte boundary. */ - final byte[] output = new byte[maximumLen]; - final int bytesWritten; - try { - bytesWritten = doFinalInternal(input, inputOffset, inputLen, output, 0, maximumLen); - } catch (ShortBufferException e) { - /* This should not happen since we sized our own buffer. */ - throw new RuntimeException("our calculated buffer was too small", e); - } - - if (bytesWritten == output.length) { - return output; - } else if (bytesWritten == 0) { - return EmptyArray.BYTE; - } else { - return Arrays.copyOfRange(output, 0, bytesWritten); - } - } - - @Override - protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset) throws ShortBufferException, IllegalBlockSizeException, - BadPaddingException { - if (output == null) { - throw new NullPointerException("output == null"); - } - - final int maximumLen = getOutputSize(inputLen); - return doFinalInternal(input, inputOffset, inputLen, output, outputOffset, maximumLen); - } - - @Override - protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { - try { - byte[] encoded = key.getEncoded(); - return engineDoFinal(encoded, 0, encoded.length); - } catch (BadPaddingException e) { - IllegalBlockSizeException newE = new IllegalBlockSizeException(); - newE.initCause(e); - throw newE; - } - } - - @Override - protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType) - throws InvalidKeyException, NoSuchAlgorithmException { - try { - byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); - if (wrappedKeyType == Cipher.PUBLIC_KEY) { - KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); - return keyFactory.generatePublic(new X509EncodedKeySpec(encoded)); - } else if (wrappedKeyType == Cipher.PRIVATE_KEY) { - KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); - return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded)); - } else if (wrappedKeyType == Cipher.SECRET_KEY) { - return new SecretKeySpec(encoded, wrappedKeyAlgorithm); - } else { - throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType); - } - } catch (IllegalBlockSizeException e) { - throw new InvalidKeyException(e); - } catch (BadPaddingException e) { - throw new InvalidKeyException(e); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } - - public static class AES extends OpenSSLCipher { - private static final int AES_BLOCK_SIZE = 16; - - protected AES(Mode mode, Padding padding) { - super(mode, padding); - } - - public static class CBC extends AES { - public CBC(Padding padding) { - super(Mode.CBC, padding); - } - - public static class NoPadding extends CBC { - public NoPadding() { - super(Padding.NOPADDING); - } - } - - public static class PKCS5Padding extends CBC { - public PKCS5Padding() { - super(Padding.PKCS5PADDING); - } - } - } - - public static class CFB extends AES { - public CFB() { - super(Mode.CFB, Padding.NOPADDING); - } - } - - public static class CTR extends AES { - public CTR() { - super(Mode.CTR, Padding.NOPADDING); - } - } - - public static class ECB extends AES { - public ECB(Padding padding) { - super(Mode.ECB, padding); - } - - public static class NoPadding extends ECB { - public NoPadding() { - super(Padding.NOPADDING); - } - } - - public static class PKCS5Padding extends ECB { - public PKCS5Padding() { - super(Padding.PKCS5PADDING); - } - } - } - - public static class OFB extends AES { - public OFB() { - super(Mode.OFB, Padding.NOPADDING); - } - } - - @Override - protected void checkSupportedKeySize(int keyLength) throws InvalidKeyException { - switch (keyLength) { - case 16: // AES 128 - case 24: // AES 192 - case 32: // AES 256 - return; - default: - throw new InvalidKeyException("Unsupported key size: " + keyLength + " bytes"); - } - } - - @Override - protected void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException { - switch (mode) { - case CBC: - case CFB: - case CFB1: - case CFB8: - case CFB128: - case CTR: - case ECB: - case OFB: - return; - default: - throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString()); - } - } - - @Override - protected void checkSupportedPadding(Padding padding) throws NoSuchPaddingException { - switch (padding) { - case NOPADDING: - case PKCS5PADDING: - return; - default: - throw new NoSuchPaddingException("Unsupported padding " + padding.toString()); - } - } - - @Override - protected String getBaseCipherName() { - return "AES"; - } - - @Override - protected String getCipherName(int keyLength, Mode mode) { - return "aes-" + (keyLength * 8) + "-" + mode.toString().toLowerCase(Locale.US); - } - - @Override - protected int getCipherBlockSize() { - return AES_BLOCK_SIZE; - } - } - - public static class DESEDE extends OpenSSLCipher { - private static int DES_BLOCK_SIZE = 8; - - public DESEDE(Mode mode, Padding padding) { - super(mode, padding); - } - - public static class CBC extends DESEDE { - public CBC(Padding padding) { - super(Mode.CBC, padding); - } - - public static class NoPadding extends CBC { - public NoPadding() { - super(Padding.NOPADDING); - } - } - - public static class PKCS5Padding extends CBC { - public PKCS5Padding() { - super(Padding.PKCS5PADDING); - } - } - } - - public static class CFB extends DESEDE { - public CFB() { - super(Mode.CFB, Padding.NOPADDING); - } - } - - public static class ECB extends DESEDE { - public ECB(Padding padding) { - super(Mode.ECB, padding); - } - - public static class NoPadding extends ECB { - public NoPadding() { - super(Padding.NOPADDING); - } - } - - public static class PKCS5Padding extends ECB { - public PKCS5Padding() { - super(Padding.PKCS5PADDING); - } - } - } - - public static class OFB extends DESEDE { - public OFB() { - super(Mode.OFB, Padding.NOPADDING); - } - } - - @Override - protected String getBaseCipherName() { - return "DESede"; - } - - @Override - protected String getCipherName(int keySize, Mode mode) { - final String baseCipherName; - if (keySize == 16) { - baseCipherName = "des-ede"; - } else { - baseCipherName = "des-ede3"; - } - - if (mode == Mode.ECB) { - return baseCipherName; - } else { - return baseCipherName + "-" + mode.toString().toLowerCase(Locale.US); - } - } - - @Override - protected void checkSupportedKeySize(int keySize) throws InvalidKeyException { - if (keySize != 16 && keySize != 24) { - throw new InvalidKeyException("key size must be 128 or 192 bits"); - } - } - - @Override - protected void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException { - switch (mode) { - case CBC: - case CFB: - case CFB1: - case CFB8: - case ECB: - case OFB: - return; - default: - throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString()); - } - } - - @Override - protected void checkSupportedPadding(Padding padding) throws NoSuchPaddingException { - switch (padding) { - case NOPADDING: - case PKCS5PADDING: - return; - default: - throw new NoSuchPaddingException("Unsupported padding " + padding.toString()); - } - } - - @Override - protected int getCipherBlockSize() { - return DES_BLOCK_SIZE; - } - } - - public static class ARC4 extends OpenSSLCipher { - public ARC4() { - } - - @Override - protected String getBaseCipherName() { - return "ARCFOUR"; - } - - @Override - protected String getCipherName(int keySize, Mode mode) { - return "rc4"; - } - - @Override - protected void checkSupportedKeySize(int keySize) throws InvalidKeyException { - } - - @Override - protected void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException { - throw new NoSuchAlgorithmException("ARC4 does not support modes"); - } - - @Override - protected void checkSupportedPadding(Padding padding) throws NoSuchPaddingException { - throw new NoSuchPaddingException("ARC4 does not support padding"); - } - - @Override - protected int getCipherBlockSize() { - return 0; - } - - @Override - protected boolean supportsVariableSizeKey() { - return true; - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLCipherContext.java b/crypto/src/main/java/org/conscrypt/OpenSSLCipherContext.java deleted file mode 100644 index ffbcad4..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLCipherContext.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -class OpenSSLCipherContext { - private final long context; - - OpenSSLCipherContext(long ctx) { - if (ctx == 0) { - throw new NullPointerException("ctx == 0"); - } - - this.context = ctx; - } - - @Override - protected void finalize() throws Throwable { - try { - NativeCrypto.EVP_CIPHER_CTX_cleanup(context); - } finally { - super.finalize(); - } - } - - long getContext() { - return context; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLCipherRSA.java b/crypto/src/main/java/org/conscrypt/OpenSSLCipherRSA.java deleted file mode 100644 index 9e2f426..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLCipherRSA.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.InvalidParameterException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.SignatureException; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.Arrays; -import java.util.Locale; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.CipherSpi; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.SecretKeySpec; -import org.conscrypt.util.EmptyArray; - -public abstract class OpenSSLCipherRSA extends CipherSpi { - /** - * The current OpenSSL key we're operating on. - */ - private OpenSSLKey key; - - /** - * Current key type: private or public. - */ - private boolean usingPrivateKey; - - /** - * Current cipher mode: encrypting or decrypting. - */ - private boolean encrypting; - - /** - * Buffer for operations - */ - private byte[] buffer; - - /** - * Current offset in the buffer. - */ - private int bufferOffset; - - /** - * Flag that indicates an exception should be thrown when the input is too - * large during doFinal. - */ - private boolean inputTooLarge; - - /** - * Current padding mode - */ - private int padding = NativeCrypto.RSA_PKCS1_PADDING; - - protected OpenSSLCipherRSA(int padding) { - this.padding = padding; - } - - @Override - protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - final String modeUpper = mode.toUpperCase(Locale.ROOT); - if ("NONE".equals(modeUpper) || "ECB".equals(modeUpper)) { - return; - } - - throw new NoSuchAlgorithmException("mode not supported: " + mode); - } - - @Override - protected void engineSetPadding(String padding) throws NoSuchPaddingException { - final String paddingUpper = padding.toUpperCase(Locale.ROOT); - if ("PKCS1PADDING".equals(paddingUpper)) { - this.padding = NativeCrypto.RSA_PKCS1_PADDING; - return; - } - if ("NOPADDING".equals(paddingUpper)) { - this.padding = NativeCrypto.RSA_NO_PADDING; - return; - } - - throw new NoSuchPaddingException("padding not supported: " + padding); - } - - @Override - protected int engineGetBlockSize() { - if (encrypting) { - return paddedBlockSizeBytes(); - } - return keySizeBytes(); - } - - @Override - protected int engineGetOutputSize(int inputLen) { - if (encrypting) { - return keySizeBytes(); - } - return paddedBlockSizeBytes(); - } - - private int paddedBlockSizeBytes() { - int paddedBlockSizeBytes = keySizeBytes(); - if (padding == NativeCrypto.RSA_PKCS1_PADDING) { - paddedBlockSizeBytes--; // for 0 prefix - paddedBlockSizeBytes -= 10; // PKCS1 padding header length - } - return paddedBlockSizeBytes; - } - - private int keySizeBytes() { - if (key == null) { - throw new IllegalStateException("cipher is not initialized"); - } - return NativeCrypto.RSA_size(this.key.getPkeyContext()); - } - - @Override - protected byte[] engineGetIV() { - return null; - } - - @Override - protected AlgorithmParameters engineGetParameters() { - return null; - } - - private void engineInitInternal(int opmode, Key key) throws InvalidKeyException { - if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) { - encrypting = true; - } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) { - encrypting = false; - } else { - throw new InvalidParameterException("Unsupported opmode " + opmode); - } - - if (key instanceof OpenSSLRSAPrivateKey) { - OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) key; - usingPrivateKey = true; - this.key = rsaPrivateKey.getOpenSSLKey(); - } else if (key instanceof RSAPrivateCrtKey) { - RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) key; - usingPrivateKey = true; - this.key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey); - } else if (key instanceof RSAPrivateKey) { - RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) key; - usingPrivateKey = true; - this.key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey); - } else if (key instanceof OpenSSLRSAPublicKey) { - OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) key; - usingPrivateKey = false; - this.key = rsaPublicKey.getOpenSSLKey(); - } else if (key instanceof RSAPublicKey) { - RSAPublicKey rsaPublicKey = (RSAPublicKey) key; - usingPrivateKey = false; - this.key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey); - } else { - throw new InvalidKeyException("Need RSA private or public key"); - } - - buffer = new byte[NativeCrypto.RSA_size(this.key.getPkeyContext())]; - inputTooLarge = false; - } - - @Override - protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - engineInitInternal(opmode, key); - } - - @Override - protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, - SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - if (params != null) { - throw new InvalidAlgorithmParameterException("unknown param type: " - + params.getClass().getName()); - } - - engineInitInternal(opmode, key); - } - - @Override - protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - if (params != null) { - throw new InvalidAlgorithmParameterException("unknown param type: " - + params.getClass().getName()); - } - - engineInitInternal(opmode, key); - } - - @Override - protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - if (bufferOffset + inputLen > buffer.length) { - inputTooLarge = true; - return EmptyArray.BYTE; - } - - System.arraycopy(input, inputOffset, buffer, bufferOffset, inputLen); - bufferOffset += inputLen; - return EmptyArray.BYTE; - } - - @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset) throws ShortBufferException { - engineUpdate(input, inputOffset, inputLen); - return 0; - } - - @Override - protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) - throws IllegalBlockSizeException, BadPaddingException { - if (input != null) { - engineUpdate(input, inputOffset, inputLen); - } - - if (inputTooLarge) { - throw new IllegalBlockSizeException("input must be under " + buffer.length + " bytes"); - } - - final byte[] tmpBuf; - if (bufferOffset != buffer.length) { - if (padding == NativeCrypto.RSA_NO_PADDING) { - tmpBuf = new byte[buffer.length]; - System.arraycopy(buffer, 0, tmpBuf, buffer.length - bufferOffset, bufferOffset); - } else { - tmpBuf = Arrays.copyOf(buffer, bufferOffset); - } - } else { - tmpBuf = buffer; - } - - byte[] output = new byte[buffer.length]; - int resultSize; - if (encrypting) { - if (usingPrivateKey) { - resultSize = NativeCrypto.RSA_private_encrypt(tmpBuf.length, tmpBuf, output, - key.getPkeyContext(), padding); - } else { - resultSize = NativeCrypto.RSA_public_encrypt(tmpBuf.length, tmpBuf, output, - key.getPkeyContext(), padding); - } - } else { - try { - if (usingPrivateKey) { - resultSize = NativeCrypto.RSA_private_decrypt(tmpBuf.length, tmpBuf, output, - key.getPkeyContext(), padding); - } else { - resultSize = NativeCrypto.RSA_public_decrypt(tmpBuf.length, tmpBuf, output, - key.getPkeyContext(), padding); - } - } catch (SignatureException e) { - IllegalBlockSizeException newE = new IllegalBlockSizeException(); - newE.initCause(e); - throw newE; - } - } - if (!encrypting && resultSize != output.length) { - output = Arrays.copyOf(output, resultSize); - } - - bufferOffset = 0; - return output; - } - - @Override - protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset) throws ShortBufferException, IllegalBlockSizeException, - BadPaddingException { - byte[] b = engineDoFinal(input, inputOffset, inputLen); - - final int lastOffset = outputOffset + b.length; - if (lastOffset > output.length) { - throw new ShortBufferException("output buffer is too small " + output.length + " < " - + lastOffset); - } - - System.arraycopy(b, 0, output, outputOffset, b.length); - return b.length; - } - - @Override - protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { - try { - byte[] encoded = key.getEncoded(); - return engineDoFinal(encoded, 0, encoded.length); - } catch (BadPaddingException e) { - IllegalBlockSizeException newE = new IllegalBlockSizeException(); - newE.initCause(e); - throw newE; - } - } - - @Override - protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, - int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { - try { - byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); - if (wrappedKeyType == Cipher.PUBLIC_KEY) { - KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); - return keyFactory.generatePublic(new X509EncodedKeySpec(encoded)); - } else if (wrappedKeyType == Cipher.PRIVATE_KEY) { - KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); - return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded)); - } else if (wrappedKeyType == Cipher.SECRET_KEY) { - return new SecretKeySpec(encoded, wrappedKeyAlgorithm); - } else { - throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType); - } - } catch (IllegalBlockSizeException e) { - throw new InvalidKeyException(e); - } catch (BadPaddingException e) { - throw new InvalidKeyException(e); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } - - public static class PKCS1 extends OpenSSLCipherRSA { - public PKCS1() { - super(NativeCrypto.RSA_PKCS1_PADDING); - } - } - - public static class Raw extends OpenSSLCipherRSA { - public Raw() { - super(NativeCrypto.RSA_NO_PADDING); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLContextImpl.java b/crypto/src/main/java/org/conscrypt/OpenSSLContextImpl.java deleted file mode 100644 index 6b0e5f9..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLContextImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2010 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import javax.net.ssl.SSLServerSocketFactory; -import javax.net.ssl.SSLSocketFactory; - -/** - * Overrides the original SSLContextImpl to provide OpenSSL-based - * SSLSocketFactory and SSLServerSocketFactory instances. - */ -public class OpenSSLContextImpl extends SSLContextImpl { - - public OpenSSLContextImpl() {} - - protected OpenSSLContextImpl(DefaultSSLContextImpl dummy) - throws GeneralSecurityException, IOException { - super(dummy); - } - - @Override - public SSLSocketFactory engineGetSocketFactory() { - if (sslParameters == null) { - throw new IllegalStateException("SSLContext is not initialized."); - } - return new OpenSSLSocketFactoryImpl(sslParameters); - } - - @Override - public SSLServerSocketFactory engineGetServerSocketFactory() { - if (sslParameters == null) { - throw new IllegalStateException("SSLContext is not initialized."); - } - return new OpenSSLServerSocketFactoryImpl(sslParameters); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLDSAKeyFactory.java b/crypto/src/main/java/org/conscrypt/OpenSSLDSAKeyFactory.java deleted file mode 100644 index a9f7067..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLDSAKeyFactory.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactorySpi; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -public class OpenSSLDSAKeyFactory extends KeyFactorySpi { - - @Override - protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (keySpec instanceof DSAPublicKeySpec) { - return new OpenSSLDSAPublicKey((DSAPublicKeySpec) keySpec); - } else if (keySpec instanceof X509EncodedKeySpec) { - return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_DSA); - } - throw new InvalidKeySpecException("Must use DSAPublicKeySpec or X509EncodedKeySpec; was " - + keySpec.getClass().getName()); - } - - @Override - protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (keySpec instanceof DSAPrivateKeySpec) { - return new OpenSSLDSAPrivateKey((DSAPrivateKeySpec) keySpec); - } else if (keySpec instanceof PKCS8EncodedKeySpec) { - return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec, - NativeCrypto.EVP_PKEY_DSA); - } - throw new InvalidKeySpecException("Must use DSAPrivateKeySpec or PKCS8EncodedKeySpec; was " - + keySpec.getClass().getName()); - } - - @Override - protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) - throws InvalidKeySpecException { - if (key == null) { - throw new InvalidKeySpecException("key == null"); - } - - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (!"DSA".equals(key.getAlgorithm())) { - throw new InvalidKeySpecException("Key must be a DSA key"); - } - - if (key instanceof DSAPublicKey && DSAPublicKeySpec.class.isAssignableFrom(keySpec)) { - DSAPublicKey dsaKey = (DSAPublicKey) key; - DSAParams params = dsaKey.getParams(); - return (T) new DSAPublicKeySpec(dsaKey.getY(), params.getP(), params.getQ(), - params.getG()); - } else if (key instanceof PublicKey && DSAPublicKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"X.509".equals(key.getFormat()) || encoded == null) { - throw new InvalidKeySpecException("Not a valid X.509 encoding"); - } - DSAPublicKey dsaKey = - (DSAPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded)); - DSAParams params = dsaKey.getParams(); - return (T) new DSAPublicKeySpec(dsaKey.getY(), params.getP(), params.getQ(), - params.getG()); - } else if (key instanceof DSAPrivateKey - && DSAPrivateKeySpec.class.isAssignableFrom(keySpec)) { - DSAPrivateKey dsaKey = (DSAPrivateKey) key; - DSAParams params = dsaKey.getParams(); - return (T) new DSAPrivateKeySpec(dsaKey.getX(), params.getP(), params.getQ(), - params.getG()); - } else if (key instanceof PrivateKey && DSAPrivateKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"PKCS#8".equals(key.getFormat()) || encoded == null) { - throw new InvalidKeySpecException("Not a valid PKCS#8 encoding"); - } - DSAPrivateKey dsaKey = - (DSAPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - DSAParams params = dsaKey.getParams(); - return (T) new DSAPrivateKeySpec(dsaKey.getX(), params.getP(), params.getQ(), - params.getG()); - } else if (key instanceof PrivateKey - && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"PKCS#8".equals(key.getFormat())) { - throw new InvalidKeySpecException("Encoding type must be PKCS#8; was " - + key.getFormat()); - } else if (encoded == null) { - throw new InvalidKeySpecException("Key is not encodable"); - } - return (T) new PKCS8EncodedKeySpec(encoded); - } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"X.509".equals(key.getFormat())) { - throw new InvalidKeySpecException("Encoding type must be X.509; was " - + key.getFormat()); - } else if (encoded == null) { - throw new InvalidKeySpecException("Key is not encodable"); - } - return (T) new X509EncodedKeySpec(encoded); - } else { - throw new InvalidKeySpecException("Unsupported key type and key spec combination; key=" - + key.getClass().getName() + ", keySpec=" + keySpec.getName()); - } - } - - @Override - protected Key engineTranslateKey(Key key) throws InvalidKeyException { - if (key == null) { - throw new InvalidKeyException("key == null"); - } - if ((key instanceof OpenSSLDSAPublicKey) || (key instanceof OpenSSLDSAPrivateKey)) { - return key; - } else if (key instanceof DSAPublicKey) { - DSAPublicKey dsaKey = (DSAPublicKey) key; - - BigInteger y = dsaKey.getY(); - - DSAParams params = dsaKey.getParams(); - BigInteger p = params.getP(); - BigInteger q = params.getQ(); - BigInteger g = params.getG(); - - try { - return engineGeneratePublic(new DSAPublicKeySpec(y, p, q, g)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if (key instanceof DSAPrivateKey) { - DSAPrivateKey dsaKey = (DSAPrivateKey) key; - - BigInteger x = dsaKey.getX(); - - DSAParams params = dsaKey.getParams(); - BigInteger p = params.getP(); - BigInteger q = params.getQ(); - BigInteger g = params.getG(); - - try { - return engineGeneratePrivate(new DSAPrivateKeySpec(x, p, q, g)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePublic(new X509EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else { - throw new InvalidKeyException("Key must be DSA public or private key; was " - + key.getClass().getName()); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLDSAKeyPairGenerator.java b/crypto/src/main/java/org/conscrypt/OpenSSLDSAKeyPairGenerator.java deleted file mode 100644 index 3428fcc..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLDSAKeyPairGenerator.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.KeyPairGeneratorSpi; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.DSAParameterSpec; - -public class OpenSSLDSAKeyPairGenerator extends KeyPairGeneratorSpi { - - private int primeBits = 1024; - - private SecureRandom random = null; - - private byte[] g; - - private byte[] p; - - private byte[] q; - - @Override - public KeyPair generateKeyPair() { - final byte[] seed; - if (random == null) { - seed = null; - } else { - seed = new byte[20]; - random.nextBytes(seed); - } - - final OpenSSLKey key = new OpenSSLKey(NativeCrypto.DSA_generate_key(primeBits, seed, g, p, - q)); - - final OpenSSLDSAPrivateKey privKey = new OpenSSLDSAPrivateKey(key); - final OpenSSLDSAPublicKey pubKey = new OpenSSLDSAPublicKey(key); - - return new KeyPair(pubKey, privKey); - } - - @Override - public void initialize(int keysize, SecureRandom random) { - primeBits = keysize; - this.random = random; - } - - @Override - public void initialize(AlgorithmParameterSpec params, SecureRandom random) - throws InvalidAlgorithmParameterException { - this.random = random; - - if (params instanceof DSAParameterSpec) { - DSAParameterSpec dsaParams = (DSAParameterSpec) params; - - BigInteger gInt = dsaParams.getG(); - if (gInt != null) { - g = gInt.toByteArray(); - } - - BigInteger pInt = dsaParams.getP(); - if (pInt != null) { - p = pInt.toByteArray(); - } - - BigInteger qInt = dsaParams.getQ(); - if (qInt != null) { - q = qInt.toByteArray(); - } - } else if (params != null) { - throw new InvalidAlgorithmParameterException("Params must be DSAParameterSpec"); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLDSAParams.java b/crypto/src/main/java/org/conscrypt/OpenSSLDSAParams.java deleted file mode 100644 index fd0edf7..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLDSAParams.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.interfaces.DSAParams; -import java.security.spec.AlgorithmParameterSpec; - -public class OpenSSLDSAParams implements DSAParams, AlgorithmParameterSpec { - - private OpenSSLKey key; - - private boolean fetchedParams; - - private BigInteger g; - - private BigInteger p; - - private BigInteger q; - - private BigInteger y; - - private BigInteger x; - - OpenSSLDSAParams(OpenSSLKey key) { - this.key = key; - } - - OpenSSLKey getOpenSSLKey() { - return key; - } - - private synchronized final void ensureReadParams() { - if (fetchedParams) { - return; - } - - byte[][] params = NativeCrypto.get_DSA_params(key.getPkeyContext()); - if (params[0] != null) { - g = new BigInteger(params[0]); - } - if (params[1] != null) { - p = new BigInteger(params[1]); - } - if (params[2] != null) { - q = new BigInteger(params[2]); - } - if (params[3] != null) { - y = new BigInteger(params[3]); - } - if (params[4] != null) { - x = new BigInteger(params[4]); - } - - fetchedParams = true; - } - - @Override - public BigInteger getG() { - ensureReadParams(); - return g; - } - - @Override - public BigInteger getP() { - ensureReadParams(); - return p; - } - - @Override - public BigInteger getQ() { - ensureReadParams(); - return q; - } - - boolean hasParams() { - ensureReadParams(); - return (g != null) && (p != null) && (q != null); - } - - BigInteger getY() { - ensureReadParams(); - return y; - } - - BigInteger getX() { - ensureReadParams(); - return x; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLDSAParams) { - OpenSSLDSAParams other = (OpenSSLDSAParams) o; - - /* - * We can shortcut the true case, but it still may be equivalent but - * different copies. - */ - if (key == other.getOpenSSLKey()) { - return true; - } - } - - if (!(o instanceof DSAParams)) { - return false; - } - - ensureReadParams(); - - DSAParams other = (DSAParams) o; - return g.equals(other.getG()) && p.equals(other.getP()) && q.equals(other.getQ()); - } - - @Override - public int hashCode() { - ensureReadParams(); - - return g.hashCode() ^ p.hashCode() ^ q.hashCode(); - } - - @Override - public String toString() { - ensureReadParams(); - - final StringBuilder sb = new StringBuilder("OpenSSLDSAParams{"); - sb.append("G="); - sb.append(g.toString(16)); - sb.append(",P="); - sb.append(p.toString(16)); - sb.append(",Q="); - sb.append(q.toString(16)); - sb.append('}'); - - return sb.toString(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLDSAPrivateKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLDSAPrivateKey.java deleted file mode 100644 index 0fc4db7..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLDSAPrivateKey.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPrivateKey; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.InvalidKeySpecException; - -public class OpenSSLDSAPrivateKey implements DSAPrivateKey, OpenSSLKeyHolder { - private static final long serialVersionUID = 6524734576187424628L; - - private transient OpenSSLKey key; - - private transient OpenSSLDSAParams params; - - OpenSSLDSAPrivateKey(OpenSSLKey key) { - this.key = key; - } - - @Override - public OpenSSLKey getOpenSSLKey() { - return key; - } - - OpenSSLDSAPrivateKey(DSAPrivateKeySpec dsaKeySpec) throws InvalidKeySpecException { - try { - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( - dsaKeySpec.getP().toByteArray(), - dsaKeySpec.getQ().toByteArray(), - dsaKeySpec.getG().toByteArray(), - null, - dsaKeySpec.getX().toByteArray())); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - } - - private void ensureReadParams() { - if (params == null) { - params = new OpenSSLDSAParams(key); - } - } - - static OpenSSLKey getInstance(DSAPrivateKey dsaPrivateKey) throws InvalidKeyException { - try { - DSAParams dsaParams = dsaPrivateKey.getParams(); - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( - dsaParams.getP().toByteArray(), - dsaParams.getQ().toByteArray(), - dsaParams.getG().toByteArray(), - null, - dsaPrivateKey.getX().toByteArray())); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - @Override - public DSAParams getParams() { - ensureReadParams(); - return params; - } - - @Override - public String getAlgorithm() { - return "DSA"; - } - - @Override - public String getFormat() { - /* - * If we're using an OpenSSL ENGINE, there's no guarantee we can export - * the key. Returning {@code null} tells the caller that there's no - * encoded format. - */ - if (key.isEngineBased()) { - return null; - } - - return "PKCS#8"; - } - - @Override - public byte[] getEncoded() { - /* - * If we're using an OpenSSL ENGINE, there's no guarantee we can export - * the key. Returning {@code null} tells the caller that there's no - * encoded format. - */ - if (key.isEngineBased()) { - return null; - } - - return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext()); - } - - @Override - public BigInteger getX() { - if (key.isEngineBased()) { - throw new UnsupportedOperationException("private key value X cannot be extracted"); - } - - ensureReadParams(); - return params.getX(); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLDSAPrivateKey) { - OpenSSLDSAPrivateKey other = (OpenSSLDSAPrivateKey) o; - - /* - * We can shortcut the true case, but it still may be equivalent but - * different copies. - */ - if (key.equals(other.getOpenSSLKey())) { - return true; - } - } - - if (!(o instanceof DSAPrivateKey)) { - return false; - } - - ensureReadParams(); - - final BigInteger x = params.getX(); - if (x == null) { - /* - * If our X is null, we can't tell if these two private keys are - * equivalent. This usually happens if this key is ENGINE-based. If - * the other key was ENGINE-based, we should have caught it in the - * OpenSSLDSAPrivateKey case. - */ - return false; - } - - final DSAPrivateKey other = (DSAPrivateKey) o; - return x.equals(other.getX()) && params.equals(other.getParams()); - } - - @Override - public int hashCode() { - ensureReadParams(); - - int hash = 1; - - final BigInteger x = getX(); - if (x != null) { - hash = hash * 3 + x.hashCode(); - } - - hash = hash * 7 + params.hashCode(); - - return hash; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("OpenSSLDSAPrivateKey{"); - - if (key.isEngineBased()) { - sb.append("key="); - sb.append(key); - sb.append('}'); - return sb.toString(); - } - - ensureReadParams(); - sb.append("X="); - sb.append(params.getX().toString(16)); - sb.append(','); - sb.append("params="); - sb.append(params.toString()); - sb.append('}'); - - return sb.toString(); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - final BigInteger g = (BigInteger) stream.readObject(); - final BigInteger p = (BigInteger) stream.readObject(); - final BigInteger q = (BigInteger) stream.readObject(); - final BigInteger x = (BigInteger) stream.readObject(); - - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( - p.toByteArray(), - q.toByteArray(), - g.toByteArray(), - null, - x.toByteArray())); - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - if (getOpenSSLKey().isEngineBased()) { - throw new NotSerializableException("engine-based keys can not be serialized"); - } - - stream.defaultWriteObject(); - - ensureReadParams(); - stream.writeObject(params.getG()); - stream.writeObject(params.getP()); - stream.writeObject(params.getQ()); - stream.writeObject(params.getX()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLDSAPublicKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLDSAPublicKey.java deleted file mode 100644 index 1c0bf74..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLDSAPublicKey.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPublicKey; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.InvalidKeySpecException; - -public class OpenSSLDSAPublicKey implements DSAPublicKey, OpenSSLKeyHolder { - private static final long serialVersionUID = 5238609500353792232L; - - private transient OpenSSLKey key; - - private transient OpenSSLDSAParams params; - - OpenSSLDSAPublicKey(OpenSSLKey key) { - this.key = key; - } - - @Override - public OpenSSLKey getOpenSSLKey() { - return key; - } - - OpenSSLDSAPublicKey(DSAPublicKeySpec dsaKeySpec) throws InvalidKeySpecException { - try { - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( - dsaKeySpec.getP().toByteArray(), - dsaKeySpec.getQ().toByteArray(), - dsaKeySpec.getG().toByteArray(), - dsaKeySpec.getY().toByteArray(), - null)); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - } - - private void ensureReadParams() { - if (params == null) { - params = new OpenSSLDSAParams(key); - } - } - - static OpenSSLKey getInstance(DSAPublicKey dsaPublicKey) throws InvalidKeyException { - try { - final DSAParams dsaParams = dsaPublicKey.getParams(); - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( - dsaParams.getP().toByteArray(), - dsaParams.getQ().toByteArray(), - dsaParams.getG().toByteArray(), - dsaPublicKey.getY().toByteArray(), - null)); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - @Override - public DSAParams getParams() { - ensureReadParams(); - - /* - * DSA keys can lack parameters if they're part of a certificate - * chain. In this case, we just return null. - */ - if (!params.hasParams()) { - return null; - } - - return params; - } - - @Override - public String getAlgorithm() { - return "DSA"; - } - - @Override - public String getFormat() { - return "X.509"; - } - - @Override - public byte[] getEncoded() { - return NativeCrypto.i2d_PUBKEY(key.getPkeyContext()); - } - - @Override - public BigInteger getY() { - ensureReadParams(); - return params.getY(); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLDSAPublicKey) { - OpenSSLDSAPublicKey other = (OpenSSLDSAPublicKey) o; - - /* - * We can shortcut the true case, but it still may be equivalent but - * different copies. - */ - if (key.equals(other.getOpenSSLKey())) { - return true; - } - } - - if (!(o instanceof DSAPublicKey)) { - return false; - } - - ensureReadParams(); - - DSAPublicKey other = (DSAPublicKey) o; - return params.getY().equals(other.getY()) && params.equals(other.getParams()); - } - - @Override - public int hashCode() { - ensureReadParams(); - - return params.getY().hashCode() ^ params.hashCode(); - } - - @Override - public String toString() { - ensureReadParams(); - - final StringBuilder sb = new StringBuilder("OpenSSLDSAPublicKey{"); - sb.append("Y="); - sb.append(params.getY().toString(16)); - sb.append(','); - sb.append("params="); - sb.append(params.toString()); - sb.append('}'); - - return sb.toString(); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - final BigInteger g = (BigInteger) stream.readObject(); - final BigInteger p = (BigInteger) stream.readObject(); - final BigInteger q = (BigInteger) stream.readObject(); - final BigInteger y = (BigInteger) stream.readObject(); - - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( - p.toByteArray(), - q.toByteArray(), - g.toByteArray(), - y.toByteArray(), - null)); - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - if (getOpenSSLKey().isEngineBased()) { - throw new NotSerializableException("engine-based keys can not be serialized"); - } - stream.defaultWriteObject(); - - ensureReadParams(); - stream.writeObject(params.getG()); - stream.writeObject(params.getP()); - stream.writeObject(params.getQ()); - stream.writeObject(params.getY()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLDigestContext.java b/crypto/src/main/java/org/conscrypt/OpenSSLDigestContext.java deleted file mode 100644 index b11a862..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLDigestContext.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -public class OpenSSLDigestContext { - private final long context; - - public OpenSSLDigestContext(long ctx) { - if (ctx == 0) { - throw new NullPointerException("ctx == 0"); - } - - this.context = ctx; - } - - @Override - protected void finalize() throws Throwable { - try { - NativeCrypto.EVP_MD_CTX_destroy(context); - } finally { - super.finalize(); - } - } - - long getContext() { - return context; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLECDHKeyAgreement.java b/crypto/src/main/java/org/conscrypt/OpenSSLECDHKeyAgreement.java deleted file mode 100644 index 0d8729c..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLECDHKeyAgreement.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import javax.crypto.KeyAgreementSpi; -import javax.crypto.SecretKey; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.SecretKeySpec; - -/** - * Elliptic Curve Diffie-Hellman key agreement backed by the OpenSSL engine. - */ -public final class OpenSSLECDHKeyAgreement extends KeyAgreementSpi { - - /** OpenSSL handle of the private key. Only available after the engine has been initialized. */ - private OpenSSLKey mOpenSslPrivateKey; - - /** - * Expected length (in bytes) of the agreed key ({@link #mResult}). Only available after the - * engine has been initialized. - */ - private int mExpectedResultLength; - - /** Agreed key. Only available after {@link #engineDoPhase(Key, boolean)} completes. */ - private byte[] mResult; - - @Override - public Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException { - if (mOpenSslPrivateKey == null) { - throw new IllegalStateException("Not initialized"); - } - if (!lastPhase) { - throw new IllegalStateException("ECDH only has one phase"); - } - - if (key == null) { - throw new InvalidKeyException("key == null"); - } - if (!(key instanceof PublicKey)) { - throw new InvalidKeyException("Not a public key: " + key.getClass()); - } - OpenSSLKey openSslPublicKey = translateKeyToEcOpenSSLKey(key); - - byte[] buffer = new byte[mExpectedResultLength]; - int actualResultLength = NativeCrypto.ECDH_compute_key( - buffer, - 0, - openSslPublicKey.getPkeyContext(), - mOpenSslPrivateKey.getPkeyContext()); - byte[] result; - if (actualResultLength == -1) { - throw new RuntimeException("Engine returned " + actualResultLength); - } else if (actualResultLength == mExpectedResultLength) { - // The output is as long as expected -- use the whole buffer - result = buffer; - } else if (actualResultLength < mExpectedResultLength) { - // The output is shorter than expected -- use only what's produced by the engine - result = new byte[actualResultLength]; - System.arraycopy(buffer, 0, mResult, 0, mResult.length); - } else { - // The output is longer than expected - throw new RuntimeException("Engine produced a longer than expected result. Expected: " - + mExpectedResultLength + ", actual: " + actualResultLength); - } - mResult = result; - - return null; // No intermediate key - } - - @Override - protected int engineGenerateSecret(byte[] sharedSecret, int offset) - throws ShortBufferException { - checkCompleted(); - int available = sharedSecret.length - offset; - if (mResult.length > available) { - throw new ShortBufferException( - "Needed: " + mResult.length + ", available: " + available); - } - - System.arraycopy(mResult, 0, sharedSecret, offset, mResult.length); - return mResult.length; - } - - @Override - protected byte[] engineGenerateSecret() { - checkCompleted(); - return mResult; - } - - @Override - protected SecretKey engineGenerateSecret(String algorithm) { - checkCompleted(); - return new SecretKeySpec(engineGenerateSecret(), algorithm); - } - - @Override - protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { - if (key == null) { - throw new InvalidKeyException("key == null"); - } - if (!(key instanceof PrivateKey)) { - throw new InvalidKeyException("Not a private key: " + key.getClass()); - } - - OpenSSLKey openSslKey = translateKeyToEcOpenSSLKey(key); - int fieldSizeBits = NativeCrypto.EC_GROUP_get_degree(NativeCrypto.EC_KEY_get0_group( - openSslKey.getPkeyContext())); - mExpectedResultLength = (fieldSizeBits + 7) / 8; - mOpenSslPrivateKey = openSslKey; - } - - @Override - protected void engineInit(Key key, AlgorithmParameterSpec params, - SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - // ECDH doesn't need an AlgorithmParameterSpec - if (params != null) { - throw new InvalidAlgorithmParameterException("No algorithm parameters supported"); - } - engineInit(key, random); - } - - private void checkCompleted() { - if (mResult == null) { - throw new IllegalStateException("Key agreement not completed"); - } - } - - private static OpenSSLKey translateKeyToEcOpenSSLKey(Key key) throws InvalidKeyException { - try { - return ((OpenSSLKeyHolder) KeyFactory.getInstance( - "EC", OpenSSLProvider.PROVIDER_NAME).translateKey(key)).getOpenSSLKey(); - } catch (Exception e) { - throw new InvalidKeyException("Failed to translate key to OpenSSL EC key", e); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLECGroupContext.java b/crypto/src/main/java/org/conscrypt/OpenSSLECGroupContext.java deleted file mode 100644 index f7f52a6..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLECGroupContext.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidParameterException; -import java.security.spec.ECField; -import java.security.spec.ECFieldF2m; -import java.security.spec.ECFieldFp; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.EllipticCurve; - -public final class OpenSSLECGroupContext { - private final long groupCtx; - - public OpenSSLECGroupContext(long groupCtx) { - this.groupCtx = groupCtx; - } - - public static OpenSSLECGroupContext getCurveByName(String curveName) { - // Workaround for OpenSSL not supporting SECG names for NIST P-192 and P-256 - // (aka ANSI X9.62 prime192v1 and prime256v1) curve names. - if ("secp256r1".equals(curveName)) { - curveName = "prime256v1"; - } else if ("secp192r1".equals(curveName)) { - curveName = "prime192v1"; - } - - final long ctx = NativeCrypto.EC_GROUP_new_by_curve_name(curveName); - if (ctx == 0) { - return null; - } - - NativeCrypto.EC_GROUP_set_point_conversion_form(ctx, - NativeCrypto.POINT_CONVERSION_UNCOMPRESSED); - NativeCrypto.EC_GROUP_set_asn1_flag(ctx, NativeCrypto.OPENSSL_EC_NAMED_CURVE); - - return new OpenSSLECGroupContext(ctx); - } - - public static OpenSSLECGroupContext getInstance(int type, BigInteger p, BigInteger a, - BigInteger b, BigInteger x, BigInteger y, BigInteger n, BigInteger h) { - final long ctx = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), a.toByteArray(), - b.toByteArray()); - if (ctx == 0) { - return null; - } - - NativeCrypto.EC_GROUP_set_point_conversion_form(ctx, - NativeCrypto.POINT_CONVERSION_UNCOMPRESSED); - - OpenSSLECGroupContext group = new OpenSSLECGroupContext(ctx); - - OpenSSLECPointContext generator = new OpenSSLECPointContext(group, - NativeCrypto.EC_POINT_new(ctx)); - - NativeCrypto.EC_POINT_set_affine_coordinates(ctx, generator.getContext(), - x.toByteArray(), y.toByteArray()); - - NativeCrypto.EC_GROUP_set_generator(ctx, generator.getContext(), n.toByteArray(), - h.toByteArray()); - - return group; - } - - @Override - protected void finalize() throws Throwable { - try { - if (groupCtx != 0) { - NativeCrypto.EC_GROUP_clear_free(groupCtx); - } - } finally { - super.finalize(); - } - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof OpenSSLECGroupContext)) { - return false; - } - - final OpenSSLECGroupContext other = (OpenSSLECGroupContext) o; - return NativeCrypto.EC_GROUP_cmp(groupCtx, other.groupCtx); - } - - @Override - public int hashCode() { - // TODO Auto-generated method stub - return super.hashCode(); - } - - public long getContext() { - return groupCtx; - } - - public static OpenSSLECGroupContext getInstance(ECParameterSpec params) - throws InvalidAlgorithmParameterException { - final String curveName = params.getCurveName(); - if (curveName != null) { - return OpenSSLECGroupContext.getCurveByName(curveName); - } - - final EllipticCurve curve = params.getCurve(); - final ECField field = curve.getField(); - - final int type; - final BigInteger p; - if (field instanceof ECFieldFp) { - type = NativeCrypto.EC_CURVE_GFP; - p = ((ECFieldFp) field).getP(); - } else if (field instanceof ECFieldF2m) { - type = NativeCrypto.EC_CURVE_GF2M; - p = ((ECFieldF2m) field).getReductionPolynomial(); - } else { - throw new InvalidParameterException("unhandled field class " - + field.getClass().getName()); - } - - final ECPoint generator = params.getGenerator(); - return OpenSSLECGroupContext.getInstance(type, p, curve.getA(), curve.getB(), - generator.getAffineX(), generator.getAffineY(), params.getOrder(), - BigInteger.valueOf(params.getCofactor())); - } - - public ECParameterSpec getECParameterSpec() { - final String curveName = NativeCrypto.EC_GROUP_get_curve_name(groupCtx); - - final byte[][] curveParams = NativeCrypto.EC_GROUP_get_curve(groupCtx); - final BigInteger p = new BigInteger(curveParams[0]); - final BigInteger a = new BigInteger(curveParams[1]); - final BigInteger b = new BigInteger(curveParams[2]); - - final ECField field; - final int type = NativeCrypto.get_EC_GROUP_type(groupCtx); - if (type == NativeCrypto.EC_CURVE_GFP) { - field = new ECFieldFp(p); - } else if (type == NativeCrypto.EC_CURVE_GF2M) { - field = new ECFieldF2m(p.bitLength() - 1, p); - } else { - throw new RuntimeException("unknown curve type " + type); - } - - final EllipticCurve curve = new EllipticCurve(field, a, b); - - final OpenSSLECPointContext generatorCtx = new OpenSSLECPointContext(this, - NativeCrypto.EC_GROUP_get_generator(groupCtx)); - final ECPoint generator = generatorCtx.getECPoint(); - - final BigInteger order = new BigInteger(NativeCrypto.EC_GROUP_get_order(groupCtx)); - final BigInteger cofactor = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(groupCtx)); - - return new ECParameterSpec(curve, generator, order, cofactor.intValue(), curveName); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLECKeyFactory.java b/crypto/src/main/java/org/conscrypt/OpenSSLECKeyFactory.java deleted file mode 100644 index b39a611..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLECKeyFactory.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactorySpi; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -public class OpenSSLECKeyFactory extends KeyFactorySpi { - - @Override - protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (keySpec instanceof ECPublicKeySpec) { - return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec); - } else if (keySpec instanceof X509EncodedKeySpec) { - return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_EC); - } - throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was " - + keySpec.getClass().getName()); - } - - @Override - protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (keySpec instanceof ECPrivateKeySpec) { - return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec); - } else if (keySpec instanceof PKCS8EncodedKeySpec) { - return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec, - NativeCrypto.EVP_PKEY_EC); - } - throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was " - + keySpec.getClass().getName()); - } - - @Override - protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) - throws InvalidKeySpecException { - if (key == null) { - throw new InvalidKeySpecException("key == null"); - } - - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (!"EC".equals(key.getAlgorithm())) { - throw new InvalidKeySpecException("Key must be an EC key"); - } - - if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) { - ECPublicKey ecKey = (ECPublicKey) key; - return (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams()); - } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"X.509".equals(key.getFormat()) || encoded == null) { - throw new InvalidKeySpecException("Not a valid X.509 encoding"); - } - ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded)); - return (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams()); - } else if (key instanceof ECPrivateKey - && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { - ECPrivateKey ecKey = (ECPrivateKey) key; - return (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams()); - } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"PKCS#8".equals(key.getFormat()) || encoded == null) { - throw new InvalidKeySpecException("Not a valid PKCS#8 encoding"); - } - ECPrivateKey ecKey = - (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - return (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams()); - } else if (key instanceof PrivateKey - && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"PKCS#8".equals(key.getFormat())) { - throw new InvalidKeySpecException("Encoding type must be PKCS#8; was " - + key.getFormat()); - } else if (encoded == null) { - throw new InvalidKeySpecException("Key is not encodable"); - } - return (T) new PKCS8EncodedKeySpec(encoded); - } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"X.509".equals(key.getFormat())) { - throw new InvalidKeySpecException("Encoding type must be X.509; was " - + key.getFormat()); - } else if (encoded == null) { - throw new InvalidKeySpecException("Key is not encodable"); - } - return (T) new X509EncodedKeySpec(encoded); - } else { - throw new InvalidKeySpecException("Unsupported key type and key spec combination; key=" - + key.getClass().getName() + ", keySpec=" + keySpec.getName()); - } - } - - @Override - protected Key engineTranslateKey(Key key) throws InvalidKeyException { - if (key == null) { - throw new InvalidKeyException("key == null"); - } - if ((key instanceof OpenSSLECPublicKey) || (key instanceof OpenSSLECPrivateKey)) { - return key; - } else if (key instanceof ECPublicKey) { - ECPublicKey ecKey = (ECPublicKey) key; - - ECPoint w = ecKey.getW(); - - ECParameterSpec params = ecKey.getParams(); - - try { - return engineGeneratePublic(new ECPublicKeySpec(w, params)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if (key instanceof ECPrivateKey) { - ECPrivateKey ecKey = (ECPrivateKey) key; - - BigInteger s = ecKey.getS(); - - ECParameterSpec params = ecKey.getParams(); - - try { - return engineGeneratePrivate(new ECPrivateKeySpec(s, params)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePublic(new X509EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else { - throw new InvalidKeyException("Key must be EC public or private key; was " - + key.getClass().getName()); - } - } - -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLECKeyPairGenerator.java b/crypto/src/main/java/org/conscrypt/OpenSSLECKeyPairGenerator.java deleted file mode 100644 index 21c8984..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLECKeyPairGenerator.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidParameterException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.util.HashMap; -import java.util.Map; - -public final class OpenSSLECKeyPairGenerator extends KeyPairGenerator { - private static final String ALGORITHM = "EC"; - - private static final int DEFAULT_KEY_SIZE = 192; - - private static final Map<Integer, String> SIZE_TO_CURVE_NAME = new HashMap<Integer, String>(); - - static { - /* NIST curves */ - SIZE_TO_CURVE_NAME.put(192, "prime192v1"); - SIZE_TO_CURVE_NAME.put(224, "secp224r1"); - SIZE_TO_CURVE_NAME.put(256, "prime256v1"); - SIZE_TO_CURVE_NAME.put(384, "secp384r1"); - SIZE_TO_CURVE_NAME.put(521, "secp521r1"); - } - - private OpenSSLECGroupContext group; - - public OpenSSLECKeyPairGenerator() { - super(ALGORITHM); - } - - @Override - public KeyPair generateKeyPair() { - if (group == null) { - final String curveName = SIZE_TO_CURVE_NAME.get(DEFAULT_KEY_SIZE); - group = OpenSSLECGroupContext.getCurveByName(curveName); - } - - final OpenSSLKey key = new OpenSSLKey(NativeCrypto.EC_KEY_generate_key(group.getContext())); - return new KeyPair(new OpenSSLECPublicKey(group, key), new OpenSSLECPrivateKey(group, key)); - } - - @Override - public void initialize(int keysize, SecureRandom random) { - final String name = SIZE_TO_CURVE_NAME.get(keysize); - if (name == null) { - throw new InvalidParameterException("unknown key size " + keysize); - } - - /* - * Store the group in a temporary variable until we know this is a valid - * group. - */ - final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext.getCurveByName(name); - if (possibleGroup == null) { - throw new InvalidParameterException("unknown curve " + name); - } - - group = possibleGroup; - } - - @Override - public void initialize(AlgorithmParameterSpec param, SecureRandom random) - throws InvalidAlgorithmParameterException { - if (param instanceof ECParameterSpec) { - ECParameterSpec ecParam = (ECParameterSpec) param; - - group = OpenSSLECGroupContext.getInstance(ecParam); - } else if (param instanceof ECGenParameterSpec) { - ECGenParameterSpec ecParam = (ECGenParameterSpec) param; - - final String curveName = ecParam.getName(); - - /* - * Store the group in a temporary variable until we know this is a - * valid group. - */ - final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext - .getCurveByName(curveName); - if (possibleGroup == null) { - throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); - } - - group = possibleGroup; - } else { - throw new InvalidAlgorithmParameterException( - "parameter must be ECParameterSpec or ECGenParameterSpec"); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLECPointContext.java b/crypto/src/main/java/org/conscrypt/OpenSSLECPointContext.java deleted file mode 100644 index 49bdaf1..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLECPointContext.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.spec.ECPoint; - -final class OpenSSLECPointContext { - private final OpenSSLECGroupContext group; - private final long pointCtx; - - OpenSSLECPointContext(OpenSSLECGroupContext group, long pointCtx) { - this.group = group; - this.pointCtx = pointCtx; - } - - @Override - protected void finalize() throws Throwable { - try { - if (pointCtx != 0) { - NativeCrypto.EC_POINT_clear_free(pointCtx); - } - } finally { - super.finalize(); - } - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof OpenSSLECPointContext)) { - return false; - } - - final OpenSSLECPointContext other = (OpenSSLECPointContext) o; - if (!NativeCrypto.EC_GROUP_cmp(group.getContext(), other.group.getContext())) { - return false; - } - - return NativeCrypto.EC_POINT_cmp(group.getContext(), pointCtx, other.pointCtx); - } - - public ECPoint getECPoint() { - final byte[][] generatorCoords = NativeCrypto.EC_POINT_get_affine_coordinates( - group.getContext(), pointCtx); - final BigInteger x = new BigInteger(generatorCoords[0]); - final BigInteger y = new BigInteger(generatorCoords[1]); - return new ECPoint(x, y); - } - - @Override - public int hashCode() { - // TODO Auto-generated method stub - return super.hashCode(); - } - - public long getContext() { - return pointCtx; - } - - public static OpenSSLECPointContext getInstance(int curveType, OpenSSLECGroupContext group, - ECPoint javaPoint) { - OpenSSLECPointContext point = new OpenSSLECPointContext(group, - NativeCrypto.EC_POINT_new(group.getContext())); - NativeCrypto.EC_POINT_set_affine_coordinates(group.getContext(), - point.getContext(), javaPoint.getAffineX().toByteArray(), - javaPoint.getAffineY().toByteArray()); - return point; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLECPrivateKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLECPrivateKey.java deleted file mode 100644 index a4b41db..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLECPrivateKey.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.interfaces.ECPrivateKey; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; - -public final class OpenSSLECPrivateKey implements ECPrivateKey, OpenSSLKeyHolder { - private static final long serialVersionUID = -4036633595001083922L; - - private static final String ALGORITHM = "EC"; - - protected transient OpenSSLKey key; - - protected transient OpenSSLECGroupContext group; - - public OpenSSLECPrivateKey(OpenSSLECGroupContext group, OpenSSLKey key) { - this.group = group; - this.key = key; - } - - public OpenSSLECPrivateKey(OpenSSLKey key) { - final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); - this.group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); - this.key = key; - } - - public OpenSSLECPrivateKey(ECPrivateKeySpec ecKeySpec) throws InvalidKeySpecException { - try { - group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams()); - final BigInteger privKey = ecKeySpec.getS(); - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 0, - privKey.toByteArray())); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - } - - public static OpenSSLKey getInstance(ECPrivateKey ecPrivateKey) throws InvalidKeyException { - try { - OpenSSLECGroupContext group = OpenSSLECGroupContext.getInstance(ecPrivateKey - .getParams()); - final BigInteger privKey = ecPrivateKey.getS(); - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 0, - privKey.toByteArray())); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - @Override - public String getAlgorithm() { - return ALGORITHM; - } - - @Override - public String getFormat() { - return "PKCS#8"; - } - - @Override - public byte[] getEncoded() { - return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext()); - } - - @Override - public ECParameterSpec getParams() { - return group.getECParameterSpec(); - } - - @Override - public BigInteger getS() { - if (key.isEngineBased()) { - throw new UnsupportedOperationException("private key value S cannot be extracted"); - } - - return getPrivateKey(); - } - - private BigInteger getPrivateKey() { - return new BigInteger(NativeCrypto.EC_KEY_get_private_key(key.getPkeyContext())); - } - - @Override - public OpenSSLKey getOpenSSLKey() { - return key; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLECPrivateKey) { - OpenSSLECPrivateKey other = (OpenSSLECPrivateKey) o; - return key.equals(other.key); - } - - if (!(o instanceof ECPrivateKey)) { - return false; - } - - final ECPrivateKey other = (ECPrivateKey) o; - if (!getPrivateKey().equals(other.getS())) { - return false; - } - - final ECParameterSpec spec = getParams(); - final ECParameterSpec otherSpec = other.getParams(); - - return spec.getCurve().equals(otherSpec.getCurve()) - && spec.getGenerator().equals(otherSpec.getGenerator()) - && spec.getOrder().equals(otherSpec.getOrder()) - && spec.getCofactor() == otherSpec.getCofactor(); - } - - @Override - public int hashCode() { - return Arrays.hashCode(NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext())); - } - - @Override - public String toString() { - return NativeCrypto.EVP_PKEY_print_private(key.getPkeyContext()); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - byte[] encoded = (byte[]) stream.readObject(); - - key = new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(encoded)); - - final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); - group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - if (key.isEngineBased()) { - throw new NotSerializableException("engine-based keys can not be serialized"); - } - - stream.defaultWriteObject(); - stream.writeObject(getEncoded()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLECPublicKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLECPublicKey.java deleted file mode 100644 index 8f3a0c6..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLECPublicKey.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; - -public final class OpenSSLECPublicKey implements ECPublicKey, OpenSSLKeyHolder { - private static final long serialVersionUID = 3215842926808298020L; - - private static final String ALGORITHM = "EC"; - - protected transient OpenSSLKey key; - - protected transient OpenSSLECGroupContext group; - - public OpenSSLECPublicKey(OpenSSLECGroupContext group, OpenSSLKey key) { - this.group = group; - this.key = key; - } - - public OpenSSLECPublicKey(OpenSSLKey key) { - final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); - this.group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); - this.key = key; - } - - public OpenSSLECPublicKey(ECPublicKeySpec ecKeySpec) throws InvalidKeySpecException { - try { - group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams()); - OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance( - NativeCrypto.get_EC_GROUP_type(group.getContext()), group, ecKeySpec.getW()); - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), - pubKey.getContext(), null)); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - } - - public static OpenSSLKey getInstance(ECPublicKey ecPublicKey) throws InvalidKeyException { - try { - OpenSSLECGroupContext group = OpenSSLECGroupContext - .getInstance(ecPublicKey.getParams()); - OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance( - NativeCrypto.get_EC_GROUP_type(group.getContext()), group, ecPublicKey.getW()); - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), - pubKey.getContext(), null)); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - @Override - public String getAlgorithm() { - return ALGORITHM; - } - - @Override - public String getFormat() { - return "X.509"; - } - - @Override - public byte[] getEncoded() { - return NativeCrypto.i2d_PUBKEY(key.getPkeyContext()); - } - - @Override - public ECParameterSpec getParams() { - return group.getECParameterSpec(); - } - - private ECPoint getPublicKey() { - final OpenSSLECPointContext pubKey = new OpenSSLECPointContext(group, - NativeCrypto.EC_KEY_get_public_key(key.getPkeyContext())); - - return pubKey.getECPoint(); - } - - @Override - public ECPoint getW() { - return getPublicKey(); - } - - @Override - public OpenSSLKey getOpenSSLKey() { - return key; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLECPrivateKey) { - OpenSSLECPrivateKey other = (OpenSSLECPrivateKey) o; - return key.equals(other.key); - } - - if (!(o instanceof ECPublicKey)) { - return false; - } - - final ECPublicKey other = (ECPublicKey) o; - if (!getPublicKey().equals(other.getW())) { - return false; - } - - final ECParameterSpec spec = getParams(); - final ECParameterSpec otherSpec = other.getParams(); - - return spec.getCurve().equals(otherSpec.getCurve()) - && spec.getGenerator().equals(otherSpec.getGenerator()) - && spec.getOrder().equals(otherSpec.getOrder()) - && spec.getCofactor() == otherSpec.getCofactor(); - } - - @Override - public int hashCode() { - return Arrays.hashCode(NativeCrypto.i2d_PUBKEY(key.getPkeyContext())); - } - - @Override - public String toString() { - return NativeCrypto.EVP_PKEY_print_public(key.getPkeyContext()); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - byte[] encoded = (byte[]) stream.readObject(); - - key = new OpenSSLKey(NativeCrypto.d2i_PUBKEY(encoded)); - - final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); - group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - if (key.isEngineBased()) { - throw new NotSerializableException("engine-based keys can not be serialized"); - } - - stream.defaultWriteObject(); - stream.writeObject(getEncoded()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLEngine.java b/crypto/src/main/java/org/conscrypt/OpenSSLEngine.java deleted file mode 100644 index 380e73f..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLEngine.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import javax.crypto.SecretKey; - -public class OpenSSLEngine { - static { - NativeCrypto.ENGINE_load_dynamic(); - } - - private static final Object mLoadingLock = new Object(); - - /** The ENGINE's native handle. */ - private final long ctx; - - public static OpenSSLEngine getInstance(String engine) throws IllegalArgumentException { - if (engine == null) { - throw new NullPointerException("engine == null"); - } - - final long engineCtx; - synchronized (mLoadingLock) { - engineCtx = NativeCrypto.ENGINE_by_id(engine); - if (engineCtx == 0) { - throw new IllegalArgumentException("Unknown ENGINE id: " + engine); - } - - NativeCrypto.ENGINE_add(engineCtx); - } - - return new OpenSSLEngine(engineCtx); - } - - private OpenSSLEngine(long engineCtx) { - ctx = engineCtx; - - if (NativeCrypto.ENGINE_init(engineCtx) == 0) { - NativeCrypto.ENGINE_free(engineCtx); - throw new IllegalArgumentException("Could not initialize engine"); - } - } - - public PrivateKey getPrivateKeyById(String id) throws InvalidKeyException { - if (id == null) { - throw new NullPointerException("id == null"); - } - - final long keyRef = NativeCrypto.ENGINE_load_private_key(ctx, id); - if (keyRef == 0) { - return null; - } - - OpenSSLKey pkey = new OpenSSLKey(keyRef, this, id); - try { - return pkey.getPrivateKey(); - } catch (NoSuchAlgorithmException e) { - throw new InvalidKeyException(e); - } - } - - public SecretKey getSecretKeyById(String id, String algorithm) throws InvalidKeyException { - if (id == null) { - throw new NullPointerException("id == null"); - } - - final long keyRef = NativeCrypto.ENGINE_load_private_key(ctx, id); - if (keyRef == 0) { - return null; - } - - OpenSSLKey pkey = new OpenSSLKey(keyRef, this, id); - try { - return pkey.getSecretKey(algorithm); - } catch (NoSuchAlgorithmException e) { - throw new InvalidKeyException(e); - } - } - - long getEngineContext() { - return ctx; - } - - @Override - protected void finalize() throws Throwable { - try { - NativeCrypto.ENGINE_finish(ctx); - NativeCrypto.ENGINE_free(ctx); - } finally { - super.finalize(); - } - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof OpenSSLEngine)) { - return false; - } - - OpenSSLEngine other = (OpenSSLEngine) o; - - if (other.getEngineContext() == ctx) { - return true; - } - - final String id = NativeCrypto.ENGINE_get_id(ctx); - if (id == null) { - return false; - } - - return id.equals(NativeCrypto.ENGINE_get_id(other.getEngineContext())); - } - - @Override - public int hashCode() { - return (int) ctx; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLKey.java deleted file mode 100644 index fa9a258..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLKey.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import javax.crypto.SecretKey; - -public class OpenSSLKey { - private final long ctx; - - private final OpenSSLEngine engine; - - private final String alias; - - public OpenSSLKey(long ctx) { - this.ctx = ctx; - engine = null; - alias = null; - } - - public OpenSSLKey(long ctx, OpenSSLEngine engine, String alias) { - this.ctx = ctx; - this.engine = engine; - this.alias = alias; - } - - /** - * Returns the raw pointer to the EVP_PKEY context for use in JNI calls. The - * life cycle of this native pointer is managed by the {@code OpenSSLKey} - * instance and must not be destroyed or freed by users of this API. - */ - public long getPkeyContext() { - return ctx; - } - - OpenSSLEngine getEngine() { - return engine; - } - - boolean isEngineBased() { - return engine != null; - } - - public String getAlias() { - return alias; - } - - public static OpenSSLKey fromPrivateKey(PrivateKey key) throws InvalidKeyException { - if (key instanceof OpenSSLKeyHolder) { - return ((OpenSSLKeyHolder) key).getOpenSSLKey(); - } - - if ("PKCS#8".equals(key.getFormat())) { - return new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(key.getEncoded())); - } else { - throw new InvalidKeyException("Unknown key format " + key.getFormat()); - } - } - - public PublicKey getPublicKey() throws NoSuchAlgorithmException { - switch (NativeCrypto.EVP_PKEY_type(ctx)) { - case NativeCrypto.EVP_PKEY_RSA: - return new OpenSSLRSAPublicKey(this); - case NativeCrypto.EVP_PKEY_DSA: - return new OpenSSLDSAPublicKey(this); - case NativeCrypto.EVP_PKEY_EC: - return new OpenSSLECPublicKey(this); - default: - throw new NoSuchAlgorithmException("unknown PKEY type"); - } - } - - static PublicKey getPublicKey(X509EncodedKeySpec keySpec, int type) - throws InvalidKeySpecException { - X509EncodedKeySpec x509KeySpec = (X509EncodedKeySpec) keySpec; - - final OpenSSLKey key; - try { - key = new OpenSSLKey(NativeCrypto.d2i_PUBKEY(x509KeySpec.getEncoded())); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - - if (NativeCrypto.EVP_PKEY_type(key.getPkeyContext()) != type) { - throw new InvalidKeySpecException("Unexpected key type"); - } - - try { - return key.getPublicKey(); - } catch (NoSuchAlgorithmException e) { - throw new InvalidKeySpecException(e); - } - } - - public PrivateKey getPrivateKey() throws NoSuchAlgorithmException { - switch (NativeCrypto.EVP_PKEY_type(ctx)) { - case NativeCrypto.EVP_PKEY_RSA: - return new OpenSSLRSAPrivateKey(this); - case NativeCrypto.EVP_PKEY_DSA: - return new OpenSSLDSAPrivateKey(this); - case NativeCrypto.EVP_PKEY_EC: - return new OpenSSLECPrivateKey(this); - default: - throw new NoSuchAlgorithmException("unknown PKEY type"); - } - } - - static PrivateKey getPrivateKey(PKCS8EncodedKeySpec keySpec, int type) - throws InvalidKeySpecException { - PKCS8EncodedKeySpec pkcs8KeySpec = (PKCS8EncodedKeySpec) keySpec; - - final OpenSSLKey key; - try { - key = new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(pkcs8KeySpec.getEncoded())); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - - if (NativeCrypto.EVP_PKEY_type(key.getPkeyContext()) != type) { - throw new InvalidKeySpecException("Unexpected key type"); - } - - try { - return key.getPrivateKey(); - } catch (NoSuchAlgorithmException e) { - throw new InvalidKeySpecException(e); - } - } - - public SecretKey getSecretKey(String algorithm) throws NoSuchAlgorithmException { - switch (NativeCrypto.EVP_PKEY_type(ctx)) { - case NativeCrypto.EVP_PKEY_HMAC: - case NativeCrypto.EVP_PKEY_CMAC: - return new OpenSSLSecretKey(algorithm, this); - default: - throw new NoSuchAlgorithmException("unknown PKEY type"); - } - } - - @Override - protected void finalize() throws Throwable { - try { - if (ctx != 0) { - NativeCrypto.EVP_PKEY_free(ctx); - } - } finally { - super.finalize(); - } - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof OpenSSLKey)) { - return false; - } - - OpenSSLKey other = (OpenSSLKey) o; - if (ctx == other.getPkeyContext()) { - return true; - } - - /* - * ENGINE-based keys must be checked in a special way. - */ - if (engine == null) { - if (other.getEngine() != null) { - return false; - } - } else if (!engine.equals(other.getEngine())) { - return false; - } else { - if (alias != null) { - return alias.equals(other.getAlias()); - } else if (other.getAlias() != null) { - return false; - } - } - - return NativeCrypto.EVP_PKEY_cmp(ctx, other.getPkeyContext()) == 1; - } - - @Override - public int hashCode() { - int hash = 1; - hash = hash * 17 + (int) ctx; - hash = hash * 31 + (int) (engine == null ? 0 : engine.getEngineContext()); - return hash; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLKeyHolder.java b/crypto/src/main/java/org/conscrypt/OpenSSLKeyHolder.java deleted file mode 100644 index 09af21c..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLKeyHolder.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -public interface OpenSSLKeyHolder { - public OpenSSLKey getOpenSSLKey(); -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLMac.java b/crypto/src/main/java/org/conscrypt/OpenSSLMac.java deleted file mode 100644 index ed163ec..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLMac.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.MacSpi; -import javax.crypto.SecretKey; - -public abstract class OpenSSLMac extends MacSpi { - private final OpenSSLDigestContext ctx = new OpenSSLDigestContext( - NativeCrypto.EVP_MD_CTX_create()); - - /** - * Holds the EVP_MD for the hashing algorithm, e.g. - * EVP_get_digestbyname("sha1"); - */ - private final long evp_md; - - /** - * The key type of the secret key. - */ - private final int evp_pkey_type; - - /** - * The secret key used in this keyed MAC. - */ - private OpenSSLKey macKey; - - /** - * Holds the output size of the message digest. - */ - private final int size; - - /** - * Holds a dummy buffer for writing single bytes to the digest. - */ - private final byte[] singleByte = new byte[1]; - - private OpenSSLMac(long evp_md, int size, int evp_pkey_type) { - this.evp_md = evp_md; - this.size = size; - this.evp_pkey_type = evp_pkey_type; - } - - @Override - protected int engineGetMacLength() { - return size; - } - - @Override - protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, - InvalidAlgorithmParameterException { - if (!(key instanceof SecretKey)) { - throw new InvalidKeyException("key must be a SecretKey"); - } - - if (params != null) { - throw new InvalidAlgorithmParameterException("unknown parameter type"); - } - - if (key instanceof OpenSSLKeyHolder) { - macKey = ((OpenSSLKeyHolder) key).getOpenSSLKey(); - } else { - final byte[] keyBytes = key.getEncoded(); - if (keyBytes == null) { - throw new InvalidKeyException("key cannot be encoded"); - } - - macKey = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_mac_key(evp_pkey_type, keyBytes)); - } - - NativeCrypto.EVP_MD_CTX_init(ctx.getContext()); - - reset(); - } - - private void reset() { - final OpenSSLKey macKey = this.macKey; - if (macKey == null) { - return; - } - NativeCrypto.EVP_DigestSignInit(ctx.getContext(), evp_md, macKey.getPkeyContext()); - } - - @Override - protected void engineUpdate(byte input) { - singleByte[0] = input; - engineUpdate(singleByte, 0, 1); - } - - @Override - protected void engineUpdate(byte[] input, int offset, int len) { - NativeCrypto.EVP_DigestUpdate(ctx.getContext(), input, offset, len); - } - - @Override - protected byte[] engineDoFinal() { - final byte[] output = NativeCrypto.EVP_DigestSignFinal(ctx.getContext()); - reset(); - return output; - } - - @Override - protected void engineReset() { - reset(); - } - - public static class HmacMD5 extends OpenSSLMac { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - - public HmacMD5() { - super(EVP_MD, SIZE, NativeCrypto.EVP_PKEY_HMAC); - } - } - - public static class HmacSHA1 extends OpenSSLMac { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - - public HmacSHA1() { - super(EVP_MD, SIZE, NativeCrypto.EVP_PKEY_HMAC); - } - } - - public static class HmacSHA224 extends OpenSSLMac { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - - public HmacSHA224() throws NoSuchAlgorithmException { - super(EVP_MD, SIZE, NativeCrypto.EVP_PKEY_HMAC); - } - } - - public static class HmacSHA256 extends OpenSSLMac { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - - public HmacSHA256() throws NoSuchAlgorithmException { - super(EVP_MD, SIZE, NativeCrypto.EVP_PKEY_HMAC); - } - } - - public static class HmacSHA384 extends OpenSSLMac { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - - public HmacSHA384() throws NoSuchAlgorithmException { - super(EVP_MD, SIZE, NativeCrypto.EVP_PKEY_HMAC); - } - } - - public static class HmacSHA512 extends OpenSSLMac { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - - public HmacSHA512() { - super(EVP_MD, SIZE, NativeCrypto.EVP_PKEY_HMAC); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLMessageDigestJDK.java b/crypto/src/main/java/org/conscrypt/OpenSSLMessageDigestJDK.java deleted file mode 100644 index 801a721..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLMessageDigestJDK.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * Implements the JDK MessageDigest interface using OpenSSL's EVP API. - */ -public class OpenSSLMessageDigestJDK extends MessageDigest implements Cloneable { - - /** - * Holds a pointer to the native message digest context. - */ - private long ctx; - - /** - * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1"); - */ - private final long evp_md; - - /** - * Holds the output size of the message digest. - */ - private final int size; - - /** - * Holds a dummy buffer for writing single bytes to the digest. - */ - private final byte[] singleByte = new byte[1]; - - /** - * Creates a new OpenSSLMessageDigest instance for the given algorithm - * name. - */ - private OpenSSLMessageDigestJDK(String algorithm, long evp_md, int size) - throws NoSuchAlgorithmException { - super(algorithm); - this.evp_md = evp_md; - this.size = size; - } - - @Override - protected void engineReset() { - free(); - } - - @Override - protected int engineGetDigestLength() { - return size; - } - - @Override - protected void engineUpdate(byte input) { - singleByte[0] = input; - engineUpdate(singleByte, 0, 1); - } - - @Override - protected void engineUpdate(byte[] input, int offset, int len) { - NativeCrypto.EVP_DigestUpdate(getCtx(), input, offset, len); - } - - @Override - protected byte[] engineDigest() { - byte[] result = new byte[size]; - NativeCrypto.EVP_DigestFinal(getCtx(), result, 0); - ctx = 0; // EVP_DigestFinal frees the context as a side effect - return result; - } - - public Object clone() throws CloneNotSupportedException { - OpenSSLMessageDigestJDK d = (OpenSSLMessageDigestJDK) super.clone(); - d.ctx = NativeCrypto.EVP_MD_CTX_copy(getCtx()); - return d; - } - - private long getCtx() { - if (ctx == 0) { - ctx = NativeCrypto.EVP_DigestInit(evp_md); - } - return ctx; - } - - private void free() { - if (ctx != 0) { - NativeCrypto.EVP_MD_CTX_destroy(ctx); - ctx = 0; - } - } - - @Override protected void finalize() throws Throwable { - try { - free(); - } finally { - super.finalize(); - } - } - - public static class MD5 extends OpenSSLMessageDigestJDK { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - public MD5() throws NoSuchAlgorithmException { - super("MD5",EVP_MD, SIZE); - } - } - - public static class SHA1 extends OpenSSLMessageDigestJDK { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - public SHA1() throws NoSuchAlgorithmException { - super("SHA-1", EVP_MD, SIZE); - } - } - - public static class SHA224 extends OpenSSLMessageDigestJDK { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - public SHA224() throws NoSuchAlgorithmException { - super("SHA-224", EVP_MD, SIZE); - } - } - - public static class SHA256 extends OpenSSLMessageDigestJDK { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - public SHA256() throws NoSuchAlgorithmException { - super("SHA-256", EVP_MD, SIZE); - } - } - - public static class SHA384 extends OpenSSLMessageDigestJDK { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - public SHA384() throws NoSuchAlgorithmException { - super("SHA-384", EVP_MD, SIZE); - } - } - - public static class SHA512 extends OpenSSLMessageDigestJDK { - private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512"); - private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); - public SHA512() throws NoSuchAlgorithmException { - super("SHA-512", EVP_MD, SIZE); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLProvider.java b/crypto/src/main/java/org/conscrypt/OpenSSLProvider.java deleted file mode 100644 index 90e08a2..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLProvider.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2010 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.Provider; - -/** - * Provider that goes through OpenSSL for operations. - * <p> - * Every algorithm should have its IANA assigned OID as an alias. See the following URLs for each type: - * <ul> - * <li><a href="http://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml">Hash functions</a></li> - * <li><a href="http://www.iana.org/assignments/dssc/dssc.xml">Signature algorithms</a></li> - * <li><a href="http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html">NIST cryptographic algorithms</a></li> - * </ul> - */ -public final class OpenSSLProvider extends Provider { - private static final long serialVersionUID = 2996752495318905136L; - - public static final String PROVIDER_NAME = "AndroidOpenSSL"; - - public OpenSSLProvider() { - super(PROVIDER_NAME, 1.0, "Android's OpenSSL-backed security provider"); - - // Make sure the platform is initialized. - Platform.setup(); - - final String prefix = getClass().getPackage().getName() + "."; - - /* === SSL Contexts === */ - final String classOpenSSLContextImpl = prefix + "OpenSSLContextImpl"; - put("SSLContext.SSL", classOpenSSLContextImpl); - put("SSLContext.SSLv3", classOpenSSLContextImpl); - put("SSLContext.TLS", classOpenSSLContextImpl); - put("SSLContext.TLSv1", classOpenSSLContextImpl); - put("SSLContext.TLSv1.1", classOpenSSLContextImpl); - put("SSLContext.TLSv1.2", classOpenSSLContextImpl); - put("SSLContext.Default", prefix + "DefaultSSLContextImpl"); - - /* === Message Digests === */ - put("MessageDigest.SHA-1", prefix + "OpenSSLMessageDigestJDK$SHA1"); - put("Alg.Alias.MessageDigest.SHA1", "SHA-1"); - put("Alg.Alias.MessageDigest.SHA", "SHA-1"); - put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA-1"); - - put("MessageDigest.SHA-224", prefix + "OpenSSLMessageDigestJDK$SHA224"); - put("Alg.Alias.MessageDigest.SHA224", "SHA-224"); - put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224"); - - put("MessageDigest.SHA-256", prefix + "OpenSSLMessageDigestJDK$SHA256"); - put("Alg.Alias.MessageDigest.SHA256", "SHA-256"); - put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256"); - - put("MessageDigest.SHA-384", prefix + "OpenSSLMessageDigestJDK$SHA384"); - put("Alg.Alias.MessageDigest.SHA384", "SHA-384"); - put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384"); - - put("MessageDigest.SHA-512", prefix + "OpenSSLMessageDigestJDK$SHA512"); - put("Alg.Alias.MessageDigest.SHA512", "SHA-512"); - put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512"); - - // iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) md5(5) - put("MessageDigest.MD5", prefix + "OpenSSLMessageDigestJDK$MD5"); - put("Alg.Alias.MessageDigest.1.2.840.113549.2.5", "MD5"); - - /* == KeyPairGenerators == */ - put("KeyPairGenerator.RSA", prefix + "OpenSSLRSAKeyPairGenerator"); - put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.1", "RSA"); - - put("KeyPairGenerator.DSA", prefix + "OpenSSLDSAKeyPairGenerator"); - - put("KeyPairGenerator.EC", prefix + "OpenSSLECKeyPairGenerator"); - - /* == KeyFactory == */ - put("KeyFactory.RSA", prefix + "OpenSSLRSAKeyFactory"); - put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.1", "RSA"); - - put("KeyFactory.DSA", prefix + "OpenSSLDSAKeyFactory"); - - put("KeyFactory.EC", prefix + "OpenSSLECKeyFactory"); - - /* == KeyAgreement == */ - put("KeyAgreement.ECDH", prefix + "OpenSSLECDHKeyAgreement"); - - /* == Signatures == */ - put("Signature.MD5WithRSA", prefix + "OpenSSLSignature$MD5RSA"); - put("Alg.Alias.Signature.MD5WithRSAEncryption", "MD5WithRSA"); - put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5WithRSA"); - - put("Signature.SHA1WithRSA", prefix + "OpenSSLSignature$SHA1RSA"); - put("Alg.Alias.Signature.SHA1WithRSAEncryption", "SHA1WithRSA"); - put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSA"); - put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1WithRSA"); - - put("Signature.SHA224WithRSA", prefix + "OpenSSLSignature$SHA224RSA"); - put("Alg.Alias.Signature.SHA224WithRSAEncryption", "SHA224WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA224WithRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1", - "SHA224WithRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.11", - "SHA224WithRSA"); - - put("Signature.SHA256WithRSA", prefix + "OpenSSLSignature$SHA256RSA"); - put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256WithRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1", - "SHA256WithRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11", - "SHA256WithRSA"); - - put("Signature.SHA384WithRSA", prefix + "OpenSSLSignature$SHA384RSA"); - put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384WithRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1", - "SHA384WithRSA"); - - put("Signature.SHA512WithRSA", prefix + "OpenSSLSignature$SHA512RSA"); - put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512WithRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1", - "SHA512WithRSA"); - - put("Signature.SHA1withDSA", prefix + "OpenSSLSignature$SHA1DSA"); - put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA"); - put("Alg.Alias.Signature.DSA", "SHA1withDSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA"); - put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA"); - put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA"); - - put("Signature.NONEwithRSA", prefix + "OpenSSLSignatureRawRSA"); - - put("Signature.ECDSA", prefix + "OpenSSLSignature$SHA1ECDSA"); - put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA"); - put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA"); - // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1) - put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "ECDSA"); - - // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3) - put("Signature.SHA224withECDSA", prefix + "OpenSSLSignature$SHA224ECDSA"); - // ecdsa-with-SHA224(1) - put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.10045.2.1", "SHA224withECDSA"); - - // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3) - put("Signature.SHA256withECDSA", prefix + "OpenSSLSignature$SHA256ECDSA"); - // ecdsa-with-SHA256(2) - put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.10045.2.1", "SHA256withECDSA"); - - put("Signature.SHA384withECDSA", prefix + "OpenSSLSignature$SHA384ECDSA"); - // ecdsa-with-SHA384(3) - put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.10045.2.1", "SHA384withECDSA"); - - put("Signature.SHA512withECDSA", prefix + "OpenSSLSignature$SHA512ECDSA"); - // ecdsa-with-SHA512(4) - put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.10045.2.1", "SHA512withECDSA"); - - /* === SecureRandom === */ - /* - * We have to specify SHA1PRNG because various documentation mentions - * that algorithm by name instead of just recommending calling - * "new SecureRandom()" - */ - put("SecureRandom.SHA1PRNG", prefix + "OpenSSLRandom"); - put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); - - /* === Cipher === */ - put("Cipher.RSA/ECB/NoPadding", prefix + "OpenSSLCipherRSA$Raw"); - put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding"); - put("Cipher.RSA/ECB/PKCS1Padding", prefix + "OpenSSLCipherRSA$PKCS1"); - put("Alg.Alias.Cipher.RSA/None/PKCS1Padding", "RSA/ECB/PKCS1Padding"); - - /* - * OpenSSL only supports a subset of modes, so we'll name them - * explicitly here. - */ - put("Cipher.AES/ECB/NoPadding", prefix + "OpenSSLCipher$AES$ECB$NoPadding"); - put("Cipher.AES/ECB/PKCS5Padding", prefix + "OpenSSLCipher$AES$ECB$PKCS5Padding"); - put("Cipher.AES/CBC/NoPadding", prefix + "OpenSSLCipher$AES$CBC$NoPadding"); - put("Cipher.AES/CBC/PKCS5Padding", prefix + "OpenSSLCipher$AES$CBC$PKCS5Padding"); - put("Cipher.AES/CFB/NoPadding", prefix + "OpenSSLCipher$AES$CFB"); - put("Cipher.AES/CTR/NoPadding", prefix + "OpenSSLCipher$AES$CTR"); - put("Cipher.AES/OFB/NoPadding", prefix + "OpenSSLCipher$AES$OFB"); - - put("Cipher.DESEDE/ECB/NoPadding", prefix + "OpenSSLCipher$DESEDE$ECB$NoPadding"); - put("Cipher.DESEDE/ECB/PKCS5Padding", prefix + "OpenSSLCipher$DESEDE$ECB$PKCS5Padding"); - put("Cipher.DESEDE/CBC/NoPadding", prefix + "OpenSSLCipher$DESEDE$CBC$NoPadding"); - put("Cipher.DESEDE/CBC/PKCS5Padding", prefix + "OpenSSLCipher$DESEDE$CBC$PKCS5Padding"); - put("Cipher.DESEDE/CFB/NoPadding", prefix + "OpenSSLCipher$DESEDE$CFB"); - put("Cipher.DESEDE/OFB/NoPadding", prefix + "OpenSSLCipher$DESEDE$OFB"); - - put("Cipher.ARC4", prefix + "OpenSSLCipher$ARC4"); - - /* === Mac === */ - - put("Mac.HmacMD5", prefix + "OpenSSLMac$HmacMD5"); - - // PKCS#2 - iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) - // http://www.oid-info.com/get/1.2.840.113549.2 - - // HMAC-SHA-1 PRF (7) - put("Mac.HmacSHA1", prefix + "OpenSSLMac$HmacSHA1"); - put("Alg.Alias.Mac.1.2.840.113549.2.7", "HmacSHA1"); - put("Alg.Alias.Mac.HMAC-SHA1", "HmacSHA1"); - put("Alg.Alias.Mac.HMAC/SHA1", "HmacSHA1"); - - // id-hmacWithSHA224 (8) - put("Mac.HmacSHA224", prefix + "OpenSSLMac$HmacSHA224"); - put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA224"); - put("Alg.Alias.Mac.HMAC-SHA224", "HmacSHA224"); - put("Alg.Alias.Mac.HMAC/SHA224", "HmacSHA224"); - - // id-hmacWithSHA256 (9) - put("Mac.HmacSHA256", prefix + "OpenSSLMac$HmacSHA256"); - put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA256"); - put("Alg.Alias.Mac.HMAC-SHA256", "HmacSHA256"); - put("Alg.Alias.Mac.HMAC/SHA256", "HmacSHA256"); - - // id-hmacWithSHA384 (10) - put("Mac.HmacSHA384", prefix + "OpenSSLMac$HmacSHA384"); - put("Alg.Alias.Mac.1.2.840.113549.2.10", "HmacSHA384"); - put("Alg.Alias.Mac.HMAC-SHA384", "HmacSHA384"); - put("Alg.Alias.Mac.HMAC/SHA384", "HmacSHA384"); - - // id-hmacWithSHA384 (11) - put("Mac.HmacSHA512", prefix + "OpenSSLMac$HmacSHA512"); - put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512"); - put("Alg.Alias.Mac.HMAC-SHA512", "HmacSHA512"); - put("Alg.Alias.Mac.HMAC/SHA512", "HmacSHA512"); - - /* === Certificate === */ - - put("CertificateFactory.X509", prefix + "OpenSSLX509CertificateFactory"); - put("Alg.Alias.CertificateFactory.X.509", "X509"); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLRSAKeyFactory.java b/crypto/src/main/java/org/conscrypt/OpenSSLRSAKeyFactory.java deleted file mode 100644 index c785ac6..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLRSAKeyFactory.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactorySpi; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPrivateKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.security.spec.X509EncodedKeySpec; - -public class OpenSSLRSAKeyFactory extends KeyFactorySpi { - - @Override - protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (keySpec instanceof RSAPublicKeySpec) { - return new OpenSSLRSAPublicKey((RSAPublicKeySpec) keySpec); - } else if (keySpec instanceof X509EncodedKeySpec) { - return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_RSA); - } - throw new InvalidKeySpecException("Must use RSAPublicKeySpec or X509EncodedKeySpec; was " - + keySpec.getClass().getName()); - } - - @Override - protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (keySpec instanceof RSAPrivateCrtKeySpec) { - return new OpenSSLRSAPrivateCrtKey((RSAPrivateCrtKeySpec) keySpec); - } else if (keySpec instanceof RSAPrivateKeySpec) { - return new OpenSSLRSAPrivateKey((RSAPrivateKeySpec) keySpec); - } else if (keySpec instanceof PKCS8EncodedKeySpec) { - return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec, - NativeCrypto.EVP_PKEY_RSA); - } - throw new InvalidKeySpecException("Must use RSAPublicKeySpec or PKCS8EncodedKeySpec; was " - + keySpec.getClass().getName()); - } - - @Override - protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) - throws InvalidKeySpecException { - if (key == null) { - throw new InvalidKeySpecException("key == null"); - } - - if (keySpec == null) { - throw new InvalidKeySpecException("keySpec == null"); - } - - if (!"RSA".equals(key.getAlgorithm())) { - throw new InvalidKeySpecException("Key must be a RSA key"); - } - - if (key instanceof RSAPublicKey && RSAPublicKeySpec.class.isAssignableFrom(keySpec)) { - RSAPublicKey rsaKey = (RSAPublicKey) key; - return (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent()); - } else if (key instanceof PublicKey && RSAPublicKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"X.509".equals(key.getFormat()) || encoded == null) { - throw new InvalidKeySpecException("Not a valid X.509 encoding"); - } - RSAPublicKey rsaKey = - (RSAPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded)); - return (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent()); - } else if (key instanceof RSAPrivateCrtKey - && RSAPrivateCrtKeySpec.class.isAssignableFrom(keySpec)) { - RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key; - return (T) new RSAPrivateCrtKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent(), - rsaKey.getPrivateExponent(), rsaKey.getPrimeP(), rsaKey.getPrimeQ(), - rsaKey.getPrimeExponentP(), rsaKey.getPrimeExponentQ(), - rsaKey.getCrtCoefficient()); - } else if (key instanceof RSAPrivateCrtKey - && RSAPrivateKeySpec.class.isAssignableFrom(keySpec)) { - RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key; - return (T) new RSAPrivateKeySpec(rsaKey.getModulus(), rsaKey.getPrivateExponent()); - } else if (key instanceof RSAPrivateKey - && RSAPrivateKeySpec.class.isAssignableFrom(keySpec)) { - RSAPrivateKey rsaKey = (RSAPrivateKey) key; - return (T) new RSAPrivateKeySpec(rsaKey.getModulus(), rsaKey.getPrivateExponent()); - } else if (key instanceof PrivateKey - && RSAPrivateCrtKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"PKCS#8".equals(key.getFormat()) || encoded == null) { - throw new InvalidKeySpecException("Not a valid PKCS#8 encoding"); - } - RSAPrivateKey privKey = - (RSAPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - if (privKey instanceof RSAPrivateCrtKey) { - RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) privKey; - return (T) new RSAPrivateCrtKeySpec(rsaKey.getModulus(), - rsaKey.getPublicExponent(), rsaKey.getPrivateExponent(), - rsaKey.getPrimeP(), rsaKey.getPrimeQ(), rsaKey.getPrimeExponentP(), - rsaKey.getPrimeExponentQ(), rsaKey.getCrtCoefficient()); - } else { - throw new InvalidKeySpecException("Encoded key is not an RSAPrivateCrtKey"); - } - } else if (key instanceof PrivateKey && RSAPrivateKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"PKCS#8".equals(key.getFormat()) || encoded == null) { - throw new InvalidKeySpecException("Not a valid PKCS#8 encoding"); - } - RSAPrivateKey rsaKey = - (RSAPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - return (T) new RSAPrivateKeySpec(rsaKey.getModulus(), rsaKey.getPrivateExponent()); - } else if (key instanceof PrivateKey - && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"PKCS#8".equals(key.getFormat())) { - throw new InvalidKeySpecException("Encoding type must be PKCS#8; was " - + key.getFormat()); - } else if (encoded == null) { - throw new InvalidKeySpecException("Key is not encodable"); - } - return (T) new PKCS8EncodedKeySpec(encoded); - } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { - final byte[] encoded = key.getEncoded(); - if (!"X.509".equals(key.getFormat())) { - throw new InvalidKeySpecException("Encoding type must be X.509; was " - + key.getFormat()); - } else if (encoded == null) { - throw new InvalidKeySpecException("Key is not encodable"); - } - return (T) new X509EncodedKeySpec(encoded); - } else { - throw new InvalidKeySpecException("Unsupported key type and key spec combination; key=" - + key.getClass().getName() + ", keySpec=" + keySpec.getName()); - } - } - - @Override - protected Key engineTranslateKey(Key key) throws InvalidKeyException { - if (key == null) { - throw new InvalidKeyException("key == null"); - } - - if ((key instanceof OpenSSLRSAPublicKey) || (key instanceof OpenSSLRSAPrivateKey)) { - return key; - } else if (key instanceof RSAPublicKey) { - RSAPublicKey rsaKey = (RSAPublicKey) key; - - try { - return engineGeneratePublic(new RSAPublicKeySpec(rsaKey.getModulus(), - rsaKey.getPublicExponent())); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if (key instanceof RSAPrivateCrtKey) { - RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key; - BigInteger modulus = rsaKey.getModulus(); - BigInteger publicExponent = rsaKey.getPublicExponent(); - BigInteger privateExponent = rsaKey.getPrivateExponent(); - BigInteger primeP = rsaKey.getPrimeP(); - BigInteger primeQ = rsaKey.getPrimeQ(); - BigInteger primeExponentP = rsaKey.getPrimeExponentP(); - BigInteger primeExponentQ = rsaKey.getPrimeExponentQ(); - BigInteger crtCoefficient = rsaKey.getCrtCoefficient(); - - try { - return engineGeneratePrivate(new RSAPrivateCrtKeySpec(modulus, publicExponent, - privateExponent, primeP, primeQ, primeExponentP, primeExponentQ, - crtCoefficient)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if (key instanceof RSAPrivateKey) { - RSAPrivateKey rsaKey = (RSAPrivateKey) key; - BigInteger modulus = rsaKey.getModulus(); - BigInteger privateExponent = rsaKey.getPrivateExponent(); - - try { - return engineGeneratePrivate(new RSAPrivateKeySpec(modulus, privateExponent)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePublic(new X509EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else { - throw new InvalidKeyException("Key must be an RSA public or private key; was " - + key.getClass().getName()); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLRSAKeyPairGenerator.java b/crypto/src/main/java/org/conscrypt/OpenSSLRSAKeyPairGenerator.java deleted file mode 100644 index a00219f..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLRSAKeyPairGenerator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.KeyPairGeneratorSpi; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.RSAKeyGenParameterSpec; - -public class OpenSSLRSAKeyPairGenerator extends KeyPairGeneratorSpi { - /** - * Default modulus size is 0x10001 (65537) - */ - private byte[] publicExponent = new byte[] { - 0x01, 0x00, 0x01 - }; - - /** - * Default RSA key size 2048 bits. - */ - private int modulusBits = 2048; - - @Override - public KeyPair generateKeyPair() { - final OpenSSLKey key = new OpenSSLKey(NativeCrypto.RSA_generate_key_ex(modulusBits, - publicExponent)); - - PrivateKey privKey = OpenSSLRSAPrivateKey.getInstance(key); - PublicKey pubKey = new OpenSSLRSAPublicKey(key); - - return new KeyPair(pubKey, privKey); - } - - @Override - public void initialize(int keysize, SecureRandom random) { - this.modulusBits = keysize; - } - - @Override - public void initialize(AlgorithmParameterSpec params, SecureRandom random) - throws InvalidAlgorithmParameterException { - if (!(params instanceof RSAKeyGenParameterSpec)) { - throw new InvalidAlgorithmParameterException("Only RSAKeyGenParameterSpec supported"); - } - - RSAKeyGenParameterSpec spec = (RSAKeyGenParameterSpec) params; - - final BigInteger publicExponent = spec.getPublicExponent(); - if (publicExponent != null) { - this.publicExponent = publicExponent.toByteArray(); - } - - this.modulusBits = spec.getKeysize(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLRSAPrivateCrtKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLRSAPrivateCrtKey.java deleted file mode 100644 index 1cbf5de..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLRSAPrivateCrtKey.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPrivateCrtKeySpec; - -public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSAPrivateCrtKey { - private static final long serialVersionUID = 3785291944868707197L; - - private BigInteger publicExponent; - - private BigInteger primeP; - - private BigInteger primeQ; - - private BigInteger primeExponentP; - - private BigInteger primeExponentQ; - - private BigInteger crtCoefficient; - - OpenSSLRSAPrivateCrtKey(OpenSSLKey key) { - super(key); - } - - OpenSSLRSAPrivateCrtKey(OpenSSLKey key, byte[][] params) { - super(key, params); - } - - public OpenSSLRSAPrivateCrtKey(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException { - super(init(rsaKeySpec)); - } - - private static OpenSSLKey init(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException { - BigInteger modulus = rsaKeySpec.getModulus(); - BigInteger privateExponent = rsaKeySpec.getPrivateExponent(); - - if (modulus == null) { - throw new InvalidKeySpecException("modulus == null"); - } else if (privateExponent == null) { - throw new InvalidKeySpecException("privateExponent == null"); - } - - try { - /* - * OpenSSL uses the public modulus to do RSA blinding. If - * the public modulus is not available, the call to - * EVP_PKEY_new_RSA will turn off blinding for this key - * instance. - */ - final BigInteger publicExponent = rsaKeySpec.getPublicExponent(); - final BigInteger primeP = rsaKeySpec.getPrimeP(); - final BigInteger primeQ = rsaKeySpec.getPrimeQ(); - final BigInteger primeExponentP = rsaKeySpec.getPrimeExponentP(); - final BigInteger primeExponentQ = rsaKeySpec.getPrimeExponentQ(); - final BigInteger crtCoefficient = rsaKeySpec.getCrtCoefficient(); - - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - modulus.toByteArray(), - publicExponent == null ? null : publicExponent.toByteArray(), - privateExponent.toByteArray(), - primeP == null ? null : primeP.toByteArray(), - primeQ == null ? null : primeQ.toByteArray(), - primeExponentP == null ? null : primeExponentP.toByteArray(), - primeExponentQ == null ? null : primeExponentQ.toByteArray(), - crtCoefficient == null ? null : crtCoefficient.toByteArray())); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - } - - static OpenSSLKey getInstance(RSAPrivateCrtKey rsaPrivateKey) throws InvalidKeyException { - BigInteger modulus = rsaPrivateKey.getModulus(); - BigInteger privateExponent = rsaPrivateKey.getPrivateExponent(); - - if (modulus == null) { - throw new InvalidKeyException("modulus == null"); - } else if (privateExponent == null) { - throw new InvalidKeyException("privateExponent == null"); - } - - try { - /* - * OpenSSL uses the public modulus to do RSA blinding. If - * the public modulus is not available, the call to - * EVP_PKEY_new_RSA will turn off blinding for this key - * instance. - */ - final BigInteger publicExponent = rsaPrivateKey.getPublicExponent(); - final BigInteger primeP = rsaPrivateKey.getPrimeP(); - final BigInteger primeQ = rsaPrivateKey.getPrimeQ(); - final BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP(); - final BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ(); - final BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient(); - - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - modulus.toByteArray(), - publicExponent == null ? null : publicExponent.toByteArray(), - privateExponent.toByteArray(), - primeP == null ? null : primeP.toByteArray(), - primeQ == null ? null : primeQ.toByteArray(), - primeExponentP == null ? null : primeExponentP.toByteArray(), - primeExponentQ == null ? null : primeExponentQ.toByteArray(), - crtCoefficient == null ? null : crtCoefficient.toByteArray())); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - @Override - synchronized void readParams(byte[][] params) { - super.readParams(params); - // params[0] read in super.readParams - if (params[1] != null) { - publicExponent = new BigInteger(params[1]); - } - // params[2] read in super.readParams - if (params[3] != null) { - primeP = new BigInteger(params[3]); - } - if (params[4] != null) { - primeQ = new BigInteger(params[4]); - } - if (params[5] != null) { - primeExponentP = new BigInteger(params[5]); - } - if (params[6] != null) { - primeExponentQ = new BigInteger(params[6]); - } - if (params[7] != null) { - crtCoefficient = new BigInteger(params[7]); - } - } - - @Override - public BigInteger getPublicExponent() { - ensureReadParams(); - return publicExponent; - } - - @Override - public BigInteger getPrimeP() { - ensureReadParams(); - return primeP; - } - - @Override - public BigInteger getPrimeQ() { - ensureReadParams(); - return primeQ; - } - - @Override - public BigInteger getPrimeExponentP() { - ensureReadParams(); - return primeExponentP; - } - - @Override - public BigInteger getPrimeExponentQ() { - ensureReadParams(); - return primeExponentQ; - } - - @Override - public BigInteger getCrtCoefficient() { - ensureReadParams(); - return crtCoefficient; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLRSAPrivateKey) { - OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o; - return getOpenSSLKey().equals(other.getOpenSSLKey()); - } - - if (o instanceof RSAPrivateCrtKey) { - ensureReadParams(); - RSAPrivateCrtKey other = (RSAPrivateCrtKey) o; - - if (getOpenSSLKey().isEngineBased()) { - return getModulus().equals(other.getModulus()) - && publicExponent.equals(other.getPublicExponent()); - } else { - return getModulus().equals(other.getModulus()) - && publicExponent.equals(other.getPublicExponent()) - && getPrivateExponent().equals(other.getPrivateExponent()) - && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ()) - && primeExponentP.equals(other.getPrimeExponentP()) - && primeExponentQ.equals(other.getPrimeExponentQ()) - && crtCoefficient.equals(other.getCrtCoefficient()); - } - } else if (o instanceof RSAPrivateKey) { - ensureReadParams(); - RSAPrivateKey other = (RSAPrivateKey) o; - - if (getOpenSSLKey().isEngineBased()) { - return getModulus().equals(other.getModulus()); - } else { - return getModulus().equals(other.getModulus()) - && getPrivateExponent().equals(other.getPrivateExponent()); - } - } - - return false; - } - - @Override - public final int hashCode() { - int hashCode = super.hashCode(); - if (publicExponent != null) { - hashCode ^= publicExponent.hashCode(); - } - return hashCode; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{"); - - final boolean engineBased = getOpenSSLKey().isEngineBased(); - if (engineBased) { - sb.append("key="); - sb.append(getOpenSSLKey()); - sb.append('}'); - } - - ensureReadParams(); - sb.append("modulus="); - sb.append(getModulus().toString(16)); - sb.append(','); - - if (publicExponent != null) { - sb.append("publicExponent="); - sb.append(publicExponent.toString(16)); - sb.append(','); - } - - if (!engineBased) { - sb.append("privateExponent="); - sb.append(getPrivateExponent().toString(16)); - sb.append(','); - } - - if (primeP != null) { - sb.append("primeP="); - sb.append(primeP.toString(16)); - sb.append(','); - } - - if (primeQ != null) { - sb.append("primeQ="); - sb.append(primeQ.toString(16)); - sb.append(','); - } - - if (primeExponentP != null) { - sb.append("primeExponentP="); - sb.append(primeExponentP.toString(16)); - sb.append(','); - } - - if (primeExponentQ != null) { - sb.append("primeExponentQ="); - sb.append(primeExponentQ.toString(16)); - sb.append(','); - } - - if (crtCoefficient != null) { - sb.append("crtCoefficient="); - sb.append(crtCoefficient.toString(16)); - sb.append(','); - } - - return sb.toString(); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - modulus.toByteArray(), - publicExponent == null ? null : publicExponent.toByteArray(), - privateExponent.toByteArray(), - primeP == null ? null : primeP.toByteArray(), - primeQ == null ? null : primeQ.toByteArray(), - primeExponentP == null ? null : primeExponentP.toByteArray(), - primeExponentQ == null ? null : primeExponentQ.toByteArray(), - crtCoefficient == null ? null : crtCoefficient.toByteArray())); - fetchedParams = true; - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - if (getOpenSSLKey().isEngineBased()) { - throw new NotSerializableException("engine-based keys can not be serialized"); - } - - ensureReadParams(); - stream.defaultWriteObject(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java deleted file mode 100644 index 20db293..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPrivateKeySpec; - -public class OpenSSLRSAPrivateKey implements RSAPrivateKey, OpenSSLKeyHolder { - private static final long serialVersionUID = 4872170254439578735L; - - protected transient OpenSSLKey key; - - protected transient boolean fetchedParams; - - protected BigInteger modulus; - - protected BigInteger privateExponent; - - OpenSSLRSAPrivateKey(OpenSSLKey key) { - this.key = key; - } - - OpenSSLRSAPrivateKey(OpenSSLKey key, byte[][] params) { - this(key); - readParams(params); - fetchedParams = true; - } - - @Override - public OpenSSLKey getOpenSSLKey() { - return key; - } - - public OpenSSLRSAPrivateKey(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException { - this(init(rsaKeySpec)); - } - - private static OpenSSLKey init(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException { - final BigInteger modulus = rsaKeySpec.getModulus(); - final BigInteger privateExponent = rsaKeySpec.getPrivateExponent(); - - if (modulus == null) { - throw new InvalidKeySpecException("modulus == null"); - } else if (privateExponent == null) { - throw new InvalidKeySpecException("privateExponent == null"); - } - - try { - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - modulus.toByteArray(), - null, - privateExponent.toByteArray(), - null, - null, - null, - null, - null)); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - } - - static OpenSSLRSAPrivateKey getInstance(OpenSSLKey key) { - byte[][] params = NativeCrypto.get_RSA_private_params(key.getPkeyContext()); - if (params[1] != null) { - return new OpenSSLRSAPrivateCrtKey(key, params); - } - return new OpenSSLRSAPrivateKey(key, params); - } - - static OpenSSLKey getInstance(RSAPrivateKey rsaPrivateKey) throws InvalidKeyException { - final BigInteger modulus = rsaPrivateKey.getModulus(); - final BigInteger privateExponent = rsaPrivateKey.getPrivateExponent(); - - if (modulus == null) { - throw new InvalidKeyException("modulus == null"); - } else if (privateExponent == null) { - throw new InvalidKeyException("privateExponent == null"); - } - - try { - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - modulus.toByteArray(), - null, - privateExponent.toByteArray(), - null, - null, - null, - null, - null)); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - synchronized final void ensureReadParams() { - if (fetchedParams) { - return; - } - readParams(NativeCrypto.get_RSA_private_params(key.getPkeyContext())); - fetchedParams = true; - } - - void readParams(byte[][] params) { - if (params[0] == null) { - throw new NullPointerException("modulus == null"); - } else if (params[2] == null && !key.isEngineBased()) { - throw new NullPointerException("privateExponent == null"); - } - - modulus = new BigInteger(params[0]); - - // ENGINE-based keys are not guaranteed to have a private exponent. - if (params[2] != null) { - privateExponent = new BigInteger(params[2]); - } - } - - @Override - public final BigInteger getPrivateExponent() { - if (key.isEngineBased()) { - throw new UnsupportedOperationException("private exponent cannot be extracted"); - } - - ensureReadParams(); - return privateExponent; - } - - @Override - public final BigInteger getModulus() { - ensureReadParams(); - return modulus; - } - - @Override - public final byte[] getEncoded() { - /* - * If we're using an OpenSSL ENGINE, there's no guarantee we can export - * the key. Returning {@code null} tells the caller that there's no - * encoded format. - */ - if (key.isEngineBased()) { - return null; - } - - return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext()); - } - - public final String getFormat() { - /* - * If we're using an OpenSSL ENGINE, there's no guarantee we can export - * the key. Returning {@code null} tells the caller that there's no - * encoded format. - */ - if (key.isEngineBased()) { - return null; - } - - return "PKCS#8"; - } - - @Override - public final String getAlgorithm() { - return "RSA"; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLRSAPrivateKey) { - OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o; - return key.equals(other.getOpenSSLKey()); - } - - if (o instanceof RSAPrivateKey) { - ensureReadParams(); - RSAPrivateKey other = (RSAPrivateKey) o; - - return modulus.equals(other.getModulus()) - && privateExponent.equals(other.getPrivateExponent()); - } - - return false; - } - - @Override - public int hashCode() { - ensureReadParams(); - int hash = 1; - - hash = hash * 3 + modulus.hashCode(); - if (privateExponent != null) { - hash = hash * 7 + privateExponent.hashCode(); - } - - return hash; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateKey{"); - - final boolean engineBased = key.isEngineBased(); - if (engineBased) { - sb.append("key="); - sb.append(key); - sb.append('}'); - } - - ensureReadParams(); - sb.append("modulus="); - sb.append(modulus.toString(16)); - sb.append(','); - - if (!engineBased) { - sb.append("privateExponent="); - sb.append(privateExponent.toString(16)); - sb.append(','); - } - - return sb.toString(); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - modulus.toByteArray(), - null, - privateExponent.toByteArray(), - null, - null, - null, - null, - null)); - fetchedParams = true; - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - if (getOpenSSLKey().isEngineBased()) { - throw new NotSerializableException("engine-based keys can not be serialized"); - } - - ensureReadParams(); - stream.defaultWriteObject(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java deleted file mode 100644 index 4bbd7e3..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPublicKeySpec; - -public class OpenSSLRSAPublicKey implements RSAPublicKey, OpenSSLKeyHolder { - private static final long serialVersionUID = 123125005824688292L; - - private transient OpenSSLKey key; - - private BigInteger publicExponent; - - private BigInteger modulus; - - private transient boolean fetchedParams; - - OpenSSLRSAPublicKey(OpenSSLKey key) { - this.key = key; - } - - @Override - public OpenSSLKey getOpenSSLKey() { - return key; - } - - OpenSSLRSAPublicKey(RSAPublicKeySpec spec) throws InvalidKeySpecException { - try { - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - spec.getModulus().toByteArray(), - spec.getPublicExponent().toByteArray(), - null, - null, - null, - null, - null, - null)); - } catch (Exception e) { - throw new InvalidKeySpecException(e); - } - } - - static OpenSSLKey getInstance(RSAPublicKey rsaPublicKey) throws InvalidKeyException { - try { - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - rsaPublicKey.getModulus().toByteArray(), - rsaPublicKey.getPublicExponent().toByteArray(), - null, - null, - null, - null, - null, - null)); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - @Override - public String getAlgorithm() { - return "RSA"; - } - - @Override - public String getFormat() { - return "X.509"; - } - - @Override - public byte[] getEncoded() { - return NativeCrypto.i2d_PUBKEY(key.getPkeyContext()); - } - - private void ensureReadParams() { - if (fetchedParams) { - return; - } - - byte[][] params = NativeCrypto.get_RSA_public_params(key.getPkeyContext()); - modulus = new BigInteger(params[0]); - publicExponent = new BigInteger(params[1]); - - fetchedParams = true; - } - - @Override - public BigInteger getModulus() { - ensureReadParams(); - return modulus; - } - - @Override - public BigInteger getPublicExponent() { - ensureReadParams(); - return publicExponent; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (o instanceof OpenSSLRSAPublicKey) { - OpenSSLRSAPublicKey other = (OpenSSLRSAPublicKey) o; - - /* - * We can shortcut the true case, but it still may be equivalent but - * different copies. - */ - if (key.equals(other.getOpenSSLKey())) { - return true; - } - } - - if (!(o instanceof RSAPublicKey)) { - return false; - } - - ensureReadParams(); - - RSAPublicKey other = (RSAPublicKey) o; - return modulus.equals(other.getModulus()) - && publicExponent.equals(other.getPublicExponent()); - } - - @Override - public int hashCode() { - ensureReadParams(); - - return modulus.hashCode() ^ publicExponent.hashCode(); - } - - @Override - public String toString() { - ensureReadParams(); - - final StringBuilder sb = new StringBuilder("OpenSSLRSAPublicKey{"); - sb.append("modulus="); - sb.append(modulus.toString(16)); - sb.append(','); - sb.append("publicExponent="); - sb.append(publicExponent.toString(16)); - sb.append('}'); - - return sb.toString(); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA( - modulus.toByteArray(), - publicExponent.toByteArray(), - null, - null, - null, - null, - null, - null)); - fetchedParams = true; - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - ensureReadParams(); - stream.defaultWriteObject(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLRandom.java b/crypto/src/main/java/org/conscrypt/OpenSSLRandom.java deleted file mode 100644 index 1683bb8..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLRandom.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.Serializable; -import java.security.SecureRandomSpi; - -public class OpenSSLRandom extends SecureRandomSpi implements Serializable { - private static final long serialVersionUID = 8506210602917522860L; - - @Override - protected void engineSetSeed(byte[] seed) { - NativeCrypto.RAND_seed(seed); - } - - @Override - protected void engineNextBytes(byte[] bytes) { - NativeCrypto.RAND_bytes(bytes); - } - - @Override - protected byte[] engineGenerateSeed(int numBytes) { - byte[] output = new byte[numBytes]; - NativeCrypto.RAND_bytes(output); - return output; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLSecretKey.java b/crypto/src/main/java/org/conscrypt/OpenSSLSecretKey.java deleted file mode 100644 index 193356e..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLSecretKey.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.security.InvalidKeyException; -import java.util.Arrays; - -import javax.crypto.SecretKey; - -public class OpenSSLSecretKey implements SecretKey, OpenSSLKeyHolder { - private static final long serialVersionUID = 1831053062911514589L; - - private final String algorithm; - private final int type; - private final byte[] encoded; - - private transient OpenSSLKey key; - - public OpenSSLSecretKey(String algorithm, byte[] encoded) { - this.algorithm = algorithm; - this.encoded = encoded; - - type = NativeCrypto.EVP_PKEY_HMAC; - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_mac_key(type, encoded)); - } - - public OpenSSLSecretKey(String algorithm, OpenSSLKey key) { - this.algorithm = algorithm; - this.key = key; - - type = NativeCrypto.EVP_PKEY_type(key.getPkeyContext()); - encoded = null; - } - - public static OpenSSLKey getInstance(SecretKey key) throws InvalidKeyException { - try { - return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_mac_key(NativeCrypto.EVP_PKEY_HMAC, - key.getEncoded())); - } catch (Exception e) { - throw new InvalidKeyException(e); - } - } - - @Override - public String getAlgorithm() { - return algorithm; - } - - @Override - public String getFormat() { - if (key.isEngineBased()) { - return null; - } - - return "RAW"; - } - - @Override - public byte[] getEncoded() { - if (key.isEngineBased()) { - return null; - } - - return encoded; - } - - @Override - public OpenSSLKey getOpenSSLKey() { - return key; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof SecretKey)) { - return false; - } - - SecretKey other = (SecretKey) o; - if (!algorithm.equals(other.getAlgorithm())) { - return false; - } - - if (o instanceof OpenSSLSecretKey) { - OpenSSLSecretKey otherOpenSSL = (OpenSSLSecretKey) o; - return key.equals(otherOpenSSL.getOpenSSLKey()); - } else if (key.isEngineBased()) { - return false; - } - - if (!getFormat().equals(other.getFormat())) { - return false; - } - - return Arrays.equals(encoded, other.getEncoded()); - } - - @Override - public int hashCode() { - return key.hashCode(); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - - key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_mac_key(type, encoded)); - } - - private void writeObject(ObjectOutputStream stream) throws IOException { - if (getOpenSSLKey().isEngineBased()) { - throw new NotSerializableException("engine-based keys can not be serialized"); - } - - stream.defaultWriteObject(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLServerSocketFactoryImpl.java b/crypto/src/main/java/org/conscrypt/OpenSSLServerSocketFactoryImpl.java deleted file mode 100644 index d14e921..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLServerSocketFactoryImpl.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.security.KeyManagementException; - -public class OpenSSLServerSocketFactoryImpl extends javax.net.ssl.SSLServerSocketFactory { - - private SSLParametersImpl sslParameters; - private IOException instantiationException; - - public OpenSSLServerSocketFactoryImpl() { - try { - this.sslParameters = SSLParametersImpl.getDefault(); - this.sslParameters.setUseClientMode(false); - } catch (KeyManagementException e) { - instantiationException = - new IOException("Delayed instantiation exception:"); - instantiationException.initCause(e); - } - } - - public OpenSSLServerSocketFactoryImpl(SSLParametersImpl sslParameters) { - this.sslParameters = (SSLParametersImpl) sslParameters.clone(); - this.sslParameters.setUseClientMode(false); - } - - public String[] getDefaultCipherSuites() { - return NativeCrypto.getDefaultCipherSuites(); - } - - public String[] getSupportedCipherSuites() { - return NativeCrypto.getSupportedCipherSuites(); - } - - public ServerSocket createServerSocket() throws IOException { - return new OpenSSLServerSocketImpl((SSLParametersImpl) sslParameters.clone()); - } - - public ServerSocket createServerSocket(int port) throws IOException { - return new OpenSSLServerSocketImpl(port, (SSLParametersImpl) sslParameters.clone()); - } - - public ServerSocket createServerSocket(int port, int backlog) - throws IOException { - return new OpenSSLServerSocketImpl(port, - backlog, - (SSLParametersImpl) sslParameters.clone()); - } - - public ServerSocket createServerSocket(int port, - int backlog, - InetAddress iAddress) throws IOException { - return new OpenSSLServerSocketImpl(port, - backlog, - iAddress, - (SSLParametersImpl) sslParameters.clone()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLServerSocketImpl.java b/crypto/src/main/java/org/conscrypt/OpenSSLServerSocketImpl.java deleted file mode 100644 index 4c1f709..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLServerSocketImpl.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.security.PrivateKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import javax.net.ssl.SSLException; - -/** - * OpenSSL-based implementation of server sockets. - */ -public class OpenSSLServerSocketImpl extends javax.net.ssl.SSLServerSocket { - private final SSLParametersImpl sslParameters; - private String[] enabledProtocols = NativeCrypto.getSupportedProtocols(); - private String[] enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); - private boolean channelIdEnabled; - - protected OpenSSLServerSocketImpl(SSLParametersImpl sslParameters) throws IOException { - this.sslParameters = sslParameters; - } - - protected OpenSSLServerSocketImpl(int port, SSLParametersImpl sslParameters) - throws IOException { - super(port); - this.sslParameters = sslParameters; - } - - protected OpenSSLServerSocketImpl(int port, int backlog, SSLParametersImpl sslParameters) - throws IOException { - super(port, backlog); - this.sslParameters = sslParameters; - } - - protected OpenSSLServerSocketImpl(int port, - int backlog, - InetAddress iAddress, - SSLParametersImpl sslParameters) - throws IOException { - super(port, backlog, iAddress); - this.sslParameters = sslParameters; - } - - @Override - public boolean getEnableSessionCreation() { - return sslParameters.getEnableSessionCreation(); - } - - @Override - public void setEnableSessionCreation(boolean flag) { - sslParameters.setEnableSessionCreation(flag); - } - - /** - * The names of the protocols' versions that may be used on this SSL - * connection. - * @return an array of protocols names - */ - @Override - public String[] getSupportedProtocols() { - return NativeCrypto.getSupportedProtocols(); - } - - /** - * The names of the protocols' versions that in use on this SSL connection. - * - * @return an array of protocols names - */ - @Override - public String[] getEnabledProtocols() { - return enabledProtocols.clone(); - } - - /** - * This method enables the protocols' versions listed by - * getSupportedProtocols(). - * - * @param protocols names of all the protocols to enable. - * - * @throws IllegalArgumentException when one or more of the names in the - * array are not supported, or when the array is null. - */ - @Override - public void setEnabledProtocols(String[] protocols) { - enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols); - } - - @Override - public String[] getSupportedCipherSuites() { - return NativeCrypto.getSupportedCipherSuites(); - } - - @Override - public String[] getEnabledCipherSuites() { - return enabledCipherSuites.clone(); - } - - /** - * Enables/disables the TLS Channel ID extension for this server socket. - */ - public void setChannelIdEnabled(boolean enabled) { - channelIdEnabled = enabled; - } - - /** - * Checks whether the TLS Channel ID extension is enabled for this server socket. - */ - public boolean isChannelIdEnabled() { - return channelIdEnabled; - } - - /** - * This method enables the cipher suites listed by - * getSupportedCipherSuites(). - * - * @param suites the names of all the cipher suites to enable - * @throws IllegalArgumentException when one or more of the ciphers in array - * suites are not supported, or when the array is null. - */ - @Override - public void setEnabledCipherSuites(String[] suites) { - enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites); - } - - @Override - public boolean getWantClientAuth() { - return sslParameters.getWantClientAuth(); - } - - @Override - public void setWantClientAuth(boolean want) { - sslParameters.setWantClientAuth(want); - } - - @Override - public boolean getNeedClientAuth() { - return sslParameters.getNeedClientAuth(); - } - - @Override - public void setNeedClientAuth(boolean need) { - sslParameters.setNeedClientAuth(need); - } - - @Override - public void setUseClientMode(boolean mode) { - sslParameters.setUseClientMode(mode); - } - - @Override - public boolean getUseClientMode() { - return sslParameters.getUseClientMode(); - } - - @Override - public Socket accept() throws IOException { - - if (!sslParameters.getUseClientMode()) { - checkEnabledCipherSuites(); - } - - OpenSSLSocketImpl socket = new OpenSSLSocketImpl(sslParameters, - enabledProtocols.clone(), - enabledCipherSuites.clone()); - socket.setChannelIdEnabled(channelIdEnabled); - implAccept(socket); - return socket; - } - - /** - * Check if any of the enabled cipher suites has a chance to work. - * Not 100% accurate, just a useful diagnostic that the RI does. - */ - private void checkEnabledCipherSuites() throws SSLException { - /* Loop over all enabled cipher suites. If we find a problem, - * we just continue to the next one. If we find one that could - * work, we return. This basically makes sure the caller has - * configured some appropriate certificate/key unless - * an anonymous cipher is picked. - */ - for (String enabledCipherSuite : enabledCipherSuites) { - if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) { - continue; - } - String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType(); - if (keyType == null) { - // anonymous always work - return; - } - if (keyType.equals(CipherSuite.KEY_TYPE_RSA) - || keyType.equals(CipherSuite.KEY_TYPE_DH_RSA)) { - if (checkForPrivateKey(keyType, RSAPrivateKey.class)) { - return; - } - continue; - } - if (keyType.equals(CipherSuite.KEY_TYPE_DSA) - || keyType.equals(CipherSuite.KEY_TYPE_DH_DSA)) { - if (checkForPrivateKey(keyType, DSAPrivateKey.class)) { - return; - } - continue; - } - if (keyType.equals(CipherSuite.KEY_TYPE_EC) - || keyType.equals(CipherSuite.KEY_TYPE_EC_RSA) - || keyType.equals(CipherSuite.KEY_TYPE_EC_EC)) { - if (checkForPrivateKey(keyType, ECPrivateKey.class)) { - return; - } - continue; - } - throw new IllegalStateException("Unknown key type " + keyType); - } - throw new SSLException("Could not find any key store entries " - + "to support the enabled cipher suites."); - } - - private boolean checkForPrivateKey(String keyType, Class<?> keyClass) { - String alias = sslParameters.getKeyManager().chooseServerAlias(keyType, null, null); - if (alias == null) { - return false; - } - PrivateKey key = sslParameters.getKeyManager().getPrivateKey(alias); - return (key != null && keyClass.isAssignableFrom(key.getClass())); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLSessionImpl.java b/crypto/src/main/java/org/conscrypt/OpenSSLSessionImpl.java deleted file mode 100644 index 3b7328d..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLSessionImpl.java +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.Principal; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Map; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionBindingEvent; -import javax.net.ssl.SSLSessionBindingListener; -import javax.net.ssl.SSLSessionContext; -import javax.security.cert.CertificateException; - -/** - * Implementation of the class OpenSSLSessionImpl - * based on OpenSSL. - */ -public class OpenSSLSessionImpl implements SSLSession { - - private long creationTime = 0; - long lastAccessedTime = 0; - final X509Certificate[] localCertificates; - final X509Certificate[] peerCertificates; - - private boolean isValid = true; - private final Map<String, Object> values = new HashMap<String, Object>(); - private volatile javax.security.cert.X509Certificate[] peerCertificateChain; - protected long sslSessionNativePointer; - private String peerHost; - private int peerPort = -1; - private String cipherSuite; - private String protocol; - private AbstractSessionContext sessionContext; - private byte[] id; - - /** - * Class constructor creates an SSL session context given the appropriate - * SSL parameters. - */ - protected OpenSSLSessionImpl(long sslSessionNativePointer, X509Certificate[] localCertificates, - X509Certificate[] peerCertificates, String peerHost, int peerPort, - AbstractSessionContext sessionContext) { - this.sslSessionNativePointer = sslSessionNativePointer; - this.localCertificates = localCertificates; - this.peerCertificates = peerCertificates; - this.peerHost = peerHost; - this.peerPort = peerPort; - this.sessionContext = sessionContext; - } - - /** - * Constructs a session from a byte[] containing DER data. This - * allows loading the saved session. - * @throws IOException - */ - OpenSSLSessionImpl(byte[] derData, - String peerHost, int peerPort, - X509Certificate[] peerCertificates, - AbstractSessionContext sessionContext) - throws IOException { - this(NativeCrypto.d2i_SSL_SESSION(derData), - null, - peerCertificates, - peerHost, - peerPort, - sessionContext); - // TODO move this check into native code so we can throw an error with more information - if (this.sslSessionNativePointer == 0) { - throw new IOException("Invalid session data"); - } - } - - /** - * Gets the identifier of the actual SSL session - * @return array of sessions' identifiers. - */ - public byte[] getId() { - if (id == null) { - resetId(); - } - return id; - } - - /** - * Reset the id field to the current value found in the native - * SSL_SESSION. It can change during the lifetime of the session - * because while a session is created during initial handshake, - * with handshake_cutthrough, the SSL_do_handshake may return - * before we have read the session ticket from the server side and - * therefore have computed no id based on the SHA of the ticket. - */ - void resetId() { - id = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer); - } - - /** - * Get the session object in DER format. This allows saving the session - * data or sharing it with other processes. - */ - byte[] getEncoded() { - return NativeCrypto.i2d_SSL_SESSION(sslSessionNativePointer); - } - - /** - * Gets the creation time of the SSL session. - * @return the session's creation time in milliseconds since the epoch - */ - public long getCreationTime() { - if (creationTime == 0) { - creationTime = NativeCrypto.SSL_SESSION_get_time(sslSessionNativePointer); - } - return creationTime; - } - - /** - * Returns the last time this concrete SSL session was accessed. Accessing - * here is to mean that a new connection with the same SSL context data was - * established. - * - * @return the session's last access time in milliseconds since the epoch - */ - public long getLastAccessedTime() { - return (lastAccessedTime == 0) ? getCreationTime() : lastAccessedTime; - } - - /** - * Returns the largest buffer size for the application's data bound to this - * concrete SSL session. - * @return the largest buffer size - */ - public int getApplicationBufferSize() { - return SSLRecordProtocol.MAX_DATA_LENGTH; - } - - /** - * Returns the largest SSL/TLS packet size one can expect for this concrete - * SSL session. - * @return the largest packet size - */ - public int getPacketBufferSize() { - return SSLRecordProtocol.MAX_SSL_PACKET_SIZE; - } - - /** - * Returns the principal (subject) of this concrete SSL session used in the - * handshaking phase of the connection. - * @return a X509 certificate or null if no principal was defined - */ - public Principal getLocalPrincipal() { - if (localCertificates != null && localCertificates.length > 0) { - return localCertificates[0].getSubjectX500Principal(); - } else { - return null; - } - } - - /** - * Returns the certificate(s) of the principal (subject) of this concrete SSL - * session used in the handshaking phase of the connection. The OpenSSL - * native method supports only RSA certificates. - * @return an array of certificates (the local one first and then eventually - * that of the certification authority) or null if no certificate - * were used during the handshaking phase. - */ - public Certificate[] getLocalCertificates() { - return localCertificates; - } - - /** - * Returns the certificate(s) of the peer in this SSL session - * used in the handshaking phase of the connection. - * Please notice hat this method is superseded by - * <code>getPeerCertificates()</code>. - * @return an array of X509 certificates (the peer's one first and then - * eventually that of the certification authority) or null if no - * certificate were used during the SSL connection. - * @throws SSLPeerUnverifiedException if either a non-X.509 certificate - * was used (i.e. Kerberos certificates) or the peer could not - * be verified. - */ - public javax.security.cert.X509Certificate[] getPeerCertificateChain() - throws SSLPeerUnverifiedException { - checkPeerCertificatesPresent(); - javax.security.cert.X509Certificate[] result = peerCertificateChain; - if (result == null) { - // single-check idiom - peerCertificateChain = result = createPeerCertificateChain(); - } - return result; - } - - /** - * Provide a value to initialize the volatile peerCertificateChain - * field based on the native SSL_SESSION - */ - private javax.security.cert.X509Certificate[] createPeerCertificateChain() - throws SSLPeerUnverifiedException { - try { - javax.security.cert.X509Certificate[] chain - = new javax.security.cert.X509Certificate[peerCertificates.length]; - - for (int i = 0; i < peerCertificates.length; i++) { - byte[] encoded = peerCertificates[i].getEncoded(); - chain[i] = javax.security.cert.X509Certificate.getInstance(encoded); - } - return chain; - } catch (CertificateEncodingException e) { - SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage()); - exception.initCause(exception); - throw exception; - } catch (CertificateException e) { - SSLPeerUnverifiedException exception = new SSLPeerUnverifiedException(e.getMessage()); - exception.initCause(exception); - throw exception; - } - } - - /** - * Return the identity of the peer in this SSL session - * determined via certificate(s). - * @return an array of X509 certificates (the peer's one first and then - * eventually that of the certification authority) or null if no - * certificate were used during the SSL connection. - * @throws SSLPeerUnverifiedException if either a non-X.509 certificate - * was used (i.e. Kerberos certificates) or the peer could not - * be verified. - */ - public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { - checkPeerCertificatesPresent(); - return peerCertificates; - } - - /** - * Throw SSLPeerUnverifiedException on null or empty peerCertificates array - */ - private void checkPeerCertificatesPresent() throws SSLPeerUnverifiedException { - if (peerCertificates == null || peerCertificates.length == 0) { - throw new SSLPeerUnverifiedException("No peer certificates"); - } - } - - /** - * The identity of the principal that was used by the peer during the SSL - * handshake phase is returned by this method. - * @return a X500Principal of the last certificate for X509-based - * cipher suites. - * @throws SSLPeerUnverifiedException if either a non-X.509 certificate - * was used (i.e. Kerberos certificates) or the peer does not exist. - * - */ - public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { - checkPeerCertificatesPresent(); - return peerCertificates[0].getSubjectX500Principal(); - } - - /** - * The peer's host name used in this SSL session is returned. It is the host - * name of the client for the server; and that of the server for the client. - * It is not a reliable way to get a fully qualified host name: it is mainly - * used internally to implement links for a temporary cache of SSL sessions. - * - * @return the host name of the peer, or null if no information is - * available. - * - */ - public String getPeerHost() { - return peerHost; - } - - /** - * Returns the peer's port number for the actual SSL session. It is the port - * number of the client for the server; and that of the server for the - * client. It is not a reliable way to get a peer's port number: it is - * mainly used internally to implement links for a temporary cache of SSL - * sessions. - * @return the peer's port number, or -1 if no one is available. - * - */ - public int getPeerPort() { - return peerPort; - } - - /** - * Returns a string identifier of the crypto tools used in the actual SSL - * session. For example AES_256_WITH_MD5. - */ - public String getCipherSuite() { - if (cipherSuite == null) { - String name = NativeCrypto.SSL_SESSION_cipher(sslSessionNativePointer); - cipherSuite = NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.get(name); - if (cipherSuite == null) { - cipherSuite = name; - } - } - return cipherSuite; - } - - /** - * Returns the standard version name of the SSL protocol used in all - * connections pertaining to this SSL session. - */ - public String getProtocol() { - if (protocol == null) { - protocol = NativeCrypto.SSL_SESSION_get_version(sslSessionNativePointer); - } - return protocol; - } - - /** - * Returns the context to which the actual SSL session is bound. A SSL - * context consists of (1) a possible delegate, (2) a provider and (3) a - * protocol. - * @return the SSL context used for this session, or null if it is - * unavailable. - */ - public SSLSessionContext getSessionContext() { - return sessionContext; - } - - /** - * Returns a boolean flag signaling whether a SSL session is valid - * and available for resuming or joining or not. - * - * @return true if this session may be resumed. - */ - public boolean isValid() { - SSLSessionContext context = sessionContext; - if (isValid - && context != null - && context.getSessionTimeout() != 0 - && getCreationTime() + (context.getSessionTimeout() * 1000) - < System.currentTimeMillis()) { - isValid = false; - } - return isValid; - } - - /** - * It invalidates a SSL session forbidding any resumption. - */ - public void invalidate() { - isValid = false; - sessionContext = null; - } - - /** - * Returns the object which is bound to the the input parameter name. - * This name is a sort of link to the data of the SSL session's application - * layer, if any exists. - * - * @param name the name of the binding to find. - * @return the value bound to that name, or null if the binding does not - * exist. - * @throws IllegalArgumentException if the argument is null. - */ - public Object getValue(String name) { - if (name == null) { - throw new IllegalArgumentException("name == null"); - } - return values.get(name); - } - - /** - * Returns an array with the names (sort of links) of all the data - * objects of the application layer bound into the SSL session. - * - * @return a non-null (possibly empty) array of names of the data objects - * bound to this SSL session. - */ - public String[] getValueNames() { - return values.keySet().toArray(new String[values.size()]); - } - - /** - * A link (name) with the specified value object of the SSL session's - * application layer data is created or replaced. If the new (or existing) - * value object implements the <code>SSLSessionBindingListener</code> - * interface, that object will be notified in due course. - * - * @param name the name of the link (no null are - * accepted!) - * @param value data object that shall be bound to - * name. - * @throws IllegalArgumentException if one or both argument(s) is null. - */ - public void putValue(String name, Object value) { - if (name == null || value == null) { - throw new IllegalArgumentException("name == null || value == null"); - } - Object old = values.put(name, value); - if (value instanceof SSLSessionBindingListener) { - ((SSLSessionBindingListener) value) - .valueBound(new SSLSessionBindingEvent(this, name)); - } - if (old instanceof SSLSessionBindingListener) { - ((SSLSessionBindingListener) old) - .valueUnbound(new SSLSessionBindingEvent(this, name)); - } - } - - /** - * Removes a link (name) with the specified value object of the SSL - * session's application layer data. - * - * <p>If the value object implements the <code>SSLSessionBindingListener</code> - * interface, the object will receive a <code>valueUnbound</code> notification. - * - * @param name the name of the link (no null are - * accepted!) - * @throws IllegalArgumentException if the argument is null. - */ - public void removeValue(String name) { - if (name == null) { - throw new IllegalArgumentException("name == null"); - } - Object old = values.remove(name); - if (old instanceof SSLSessionBindingListener) { - SSLSessionBindingListener listener = (SSLSessionBindingListener) old; - listener.valueUnbound(new SSLSessionBindingEvent(this, name)); - } - } - - @Override protected void finalize() throws Throwable { - try { - NativeCrypto.SSL_SESSION_free(sslSessionNativePointer); - } finally { - super.finalize(); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLSignature.java b/crypto/src/main/java/org/conscrypt/OpenSSLSignature.java deleted file mode 100644 index 53b0df0..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLSignature.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidKeyException; -import java.security.InvalidParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; - -/** - * Implements the subset of the JDK Signature interface needed for - * signature verification using OpenSSL. - */ -public class OpenSSLSignature extends Signature { - private static enum EngineType { - RSA, DSA, EC, - }; - - /** - * Holds a pointer to the native message digest context. - */ - private long ctx; - - /** - * The current OpenSSL key we're operating on. - */ - private OpenSSLKey key; - - /** - * Holds the type of the Java algorithm. - */ - private final EngineType engineType; - - /** - * Holds the OpenSSL name of the algorithm (lower case, no dashes). - */ - private final String evpAlgorithm; - - /** - * Holds a dummy buffer for writing single bytes to the digest. - */ - private final byte[] singleByte = new byte[1]; - - /** - * Creates a new OpenSSLSignature instance for the given algorithm name. - * - * @param algorithm OpenSSL name of the algorithm, e.g. "RSA-SHA1". - */ - private OpenSSLSignature(String algorithm, EngineType engineType) - throws NoSuchAlgorithmException { - super(algorithm); - - // We don't support MD2 - if ("RSA-MD2".equals(algorithm)) { - throw new NoSuchAlgorithmException(algorithm); - } - - this.engineType = engineType; - this.evpAlgorithm = algorithm; - } - - @Override - protected void engineUpdate(byte input) { - singleByte[0] = input; - engineUpdate(singleByte, 0, 1); - } - - @Override - protected void engineUpdate(byte[] input, int offset, int len) { - if (state == SIGN) { - if (ctx == 0) { - try { - ctx = NativeCrypto.EVP_SignInit(evpAlgorithm); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - NativeCrypto.EVP_SignUpdate(ctx, input, offset, len); - } else { - if (ctx == 0) { - try { - ctx = NativeCrypto.EVP_VerifyInit(evpAlgorithm); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - NativeCrypto.EVP_VerifyUpdate(ctx, input, offset, len); - } - } - - @Override - protected Object engineGetParameter(String param) throws InvalidParameterException { - return null; - } - - private void checkEngineType(OpenSSLKey pkey) throws InvalidKeyException { - final int pkeyType = NativeCrypto.EVP_PKEY_type(pkey.getPkeyContext()); - - switch (engineType) { - case RSA: - if (pkeyType != NativeCrypto.EVP_PKEY_RSA) { - throw new InvalidKeyException("Signature not initialized as RSA"); - } - break; - case DSA: - if (pkeyType != NativeCrypto.EVP_PKEY_DSA) { - throw new InvalidKeyException("Signature not initialized as DSA"); - } - break; - case EC: - if (pkeyType != NativeCrypto.EVP_PKEY_EC) { - throw new InvalidKeyException("Signature not initialized as EC"); - } - break; - default: - throw new InvalidKeyException("Need DSA or RSA or EC private key"); - } - } - - @Override - protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { - destroyContextIfExists(); - - if (privateKey instanceof OpenSSLKeyHolder) { - OpenSSLKey pkey = ((OpenSSLKeyHolder) privateKey).getOpenSSLKey(); - checkEngineType(pkey); - key = pkey; - } else if (privateKey instanceof RSAPrivateCrtKey) { - if (engineType != EngineType.RSA) { - throw new InvalidKeyException("Signature not initialized as RSA"); - } - - RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey; - key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey); - } else if (privateKey instanceof RSAPrivateKey) { - if (engineType != EngineType.RSA) { - throw new InvalidKeyException("Signature not initialized as RSA"); - } - - RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey; - key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey); - } else if (privateKey instanceof DSAPrivateKey) { - if (engineType != EngineType.DSA) { - throw new InvalidKeyException("Signature not initialized as DSA"); - } - - DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privateKey; - key = OpenSSLDSAPrivateKey.getInstance(dsaPrivateKey); - } else if (privateKey instanceof ECPrivateKey) { - if (engineType != EngineType.EC) { - throw new InvalidKeyException("Signature not initialized as EC"); - } - - ECPrivateKey ecPrivateKey = (ECPrivateKey) privateKey; - key = OpenSSLECPrivateKey.getInstance(ecPrivateKey); - } else { - throw new InvalidKeyException("Need DSA or RSA or EC private key"); - } - } - - @Override - protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - // If we had an existing context, destroy it first. - destroyContextIfExists(); - - if (publicKey instanceof OpenSSLKeyHolder) { - OpenSSLKey pkey = ((OpenSSLKeyHolder) publicKey).getOpenSSLKey(); - checkEngineType(pkey); - key = pkey; - } else if (publicKey instanceof RSAPublicKey) { - if (engineType != EngineType.RSA) { - throw new InvalidKeyException("Signature not initialized as RSA"); - } - - RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; - key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey); - } else if (publicKey instanceof DSAPublicKey) { - if (engineType != EngineType.DSA) { - throw new InvalidKeyException("Signature not initialized as DSA"); - } - - DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey; - key = OpenSSLDSAPublicKey.getInstance(dsaPublicKey); - } else if (publicKey instanceof ECPublicKey) { - if (engineType != EngineType.EC) { - throw new InvalidKeyException("Signature not initialized as EC"); - } - - ECPublicKey ecPublicKey = (ECPublicKey) publicKey; - key = OpenSSLECPublicKey.getInstance(ecPublicKey); - } else { - throw new InvalidKeyException("Need DSA or RSA or EC public key"); - } - } - - @Override - protected void engineSetParameter(String param, Object value) throws InvalidParameterException { - } - - @Override - protected byte[] engineSign() throws SignatureException { - if (key == null) { - // This can't actually happen, but you never know... - throw new SignatureException("Need DSA or RSA or EC private key"); - } - - try { - byte[] buffer = new byte[NativeCrypto.EVP_PKEY_size(key.getPkeyContext())]; - int bytesWritten = NativeCrypto.EVP_SignFinal(ctx, buffer, 0, key.getPkeyContext()); - - byte[] signature = new byte[bytesWritten]; - System.arraycopy(buffer, 0, signature, 0, bytesWritten); - - return signature; - } catch (Exception ex) { - throw new SignatureException(ex); - } finally { - /* - * Java expects the digest context to be reset completely after sign - * calls. - */ - destroyContextIfExists(); - } - } - - @Override - protected boolean engineVerify(byte[] sigBytes) throws SignatureException { - if (key == null) { - // This can't actually happen, but you never know... - throw new SignatureException("Need DSA or RSA public key"); - } - - try { - int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length, - key.getPkeyContext()); - return result == 1; - } catch (Exception ex) { - return false; - } finally { - /* - * Java expects the digest context to be reset completely after - * verify calls. - */ - destroyContextIfExists(); - } - } - - private void destroyContextIfExists() { - if (ctx != 0) { - NativeCrypto.EVP_MD_CTX_destroy(ctx); - ctx = 0; - } - } - - @Override - protected void finalize() throws Throwable { - try { - if (ctx != 0) { - NativeCrypto.EVP_MD_CTX_destroy(ctx); - } - } finally { - super.finalize(); - } - } - - public static final class MD5RSA extends OpenSSLSignature { - public MD5RSA() throws NoSuchAlgorithmException { - super("RSA-MD5", EngineType.RSA); - } - } - public static final class SHA1RSA extends OpenSSLSignature { - public SHA1RSA() throws NoSuchAlgorithmException { - super("RSA-SHA1", EngineType.RSA); - } - } - public static final class SHA224RSA extends OpenSSLSignature { - public SHA224RSA() throws NoSuchAlgorithmException { - super("RSA-SHA224", EngineType.RSA); - } - } - public static final class SHA256RSA extends OpenSSLSignature { - public SHA256RSA() throws NoSuchAlgorithmException { - super("RSA-SHA256", EngineType.RSA); - } - } - public static final class SHA384RSA extends OpenSSLSignature { - public SHA384RSA() throws NoSuchAlgorithmException { - super("RSA-SHA384", EngineType.RSA); - } - } - public static final class SHA512RSA extends OpenSSLSignature { - public SHA512RSA() throws NoSuchAlgorithmException { - super("RSA-SHA512", EngineType.RSA); - } - } - public static final class SHA1DSA extends OpenSSLSignature { - public SHA1DSA() throws NoSuchAlgorithmException { - super("DSA-SHA1", EngineType.DSA); - } - } - public static final class SHA1ECDSA extends OpenSSLSignature { - public SHA1ECDSA() throws NoSuchAlgorithmException { - super("SHA1", EngineType.EC); - } - } - public static final class SHA224ECDSA extends OpenSSLSignature { - public SHA224ECDSA() throws NoSuchAlgorithmException { - super("SHA224", EngineType.EC); - } - } - public static final class SHA256ECDSA extends OpenSSLSignature { - public SHA256ECDSA() throws NoSuchAlgorithmException { - super("SHA256", EngineType.EC); - } - } - public static final class SHA384ECDSA extends OpenSSLSignature { - public SHA384ECDSA() throws NoSuchAlgorithmException { - super("SHA384", EngineType.EC); - } - } - public static final class SHA512ECDSA extends OpenSSLSignature { - public SHA512ECDSA() throws NoSuchAlgorithmException { - super("SHA512", EngineType.EC); - } - } -} - diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLSignatureRawRSA.java b/crypto/src/main/java/org/conscrypt/OpenSSLSignatureRawRSA.java deleted file mode 100644 index 9c4e4ad..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLSignatureRawRSA.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidKeyException; -import java.security.InvalidParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; - -/** - * Implements the JDK Signature interface needed for RAW RSA signature - * generation and verification using OpenSSL. - */ -public class OpenSSLSignatureRawRSA extends Signature { - /** - * The current OpenSSL key we're operating on. - */ - private OpenSSLKey key; - - /** - * Buffer to hold value to be signed or verified. - */ - private byte[] inputBuffer; - - /** - * Current offset in input buffer. - */ - private int inputOffset; - - /** - * Provides a flag to specify when the input is too long. - */ - private boolean inputIsTooLong; - - /** - * Creates a new OpenSSLSignature instance for the given algorithm name. - */ - public OpenSSLSignatureRawRSA() throws NoSuchAlgorithmException { - super("NONEwithRSA"); - } - - @Override - protected void engineUpdate(byte input) { - final int oldOffset = inputOffset++; - - if (inputOffset > inputBuffer.length) { - inputIsTooLong = true; - return; - } - - inputBuffer[oldOffset] = input; - } - - @Override - protected void engineUpdate(byte[] input, int offset, int len) { - final int oldOffset = inputOffset; - inputOffset += len; - - if (inputOffset > inputBuffer.length) { - inputIsTooLong = true; - return; - } - - System.arraycopy(input, offset, inputBuffer, oldOffset, len); - } - - @Override - protected Object engineGetParameter(String param) throws InvalidParameterException { - return null; - } - - @Override - protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { - if (privateKey instanceof OpenSSLRSAPrivateKey) { - OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) privateKey; - key = rsaPrivateKey.getOpenSSLKey(); - } else if (privateKey instanceof RSAPrivateCrtKey) { - RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey; - key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey); - } else if (privateKey instanceof RSAPrivateKey) { - RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey; - key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey); - } else { - throw new InvalidKeyException("Need RSA private key"); - } - - // Allocate buffer according to RSA modulus size. - int maxSize = NativeCrypto.RSA_size(key.getPkeyContext()); - inputBuffer = new byte[maxSize]; - inputOffset = 0; - } - - @Override - protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - if (publicKey instanceof OpenSSLRSAPublicKey) { - OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) publicKey; - key = rsaPublicKey.getOpenSSLKey(); - } else if (publicKey instanceof RSAPublicKey) { - RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; - key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey); - } else { - throw new InvalidKeyException("Need RSA public key"); - } - - // Allocate buffer according to RSA modulus size. - int maxSize = NativeCrypto.RSA_size(key.getPkeyContext()); - inputBuffer = new byte[maxSize]; - inputOffset = 0; - } - - @Override - protected void engineSetParameter(String param, Object value) throws InvalidParameterException { - } - - @Override - protected byte[] engineSign() throws SignatureException { - if (key == null) { - // This can't actually happen, but you never know... - throw new SignatureException("Need RSA private key"); - } - - if (inputIsTooLong) { - throw new SignatureException("input length " + inputOffset + " != " - + inputBuffer.length + " (modulus size)"); - } - - byte[] outputBuffer = new byte[inputBuffer.length]; - try { - NativeCrypto.RSA_private_encrypt(inputOffset, inputBuffer, outputBuffer, - key.getPkeyContext(), NativeCrypto.RSA_PKCS1_PADDING); - return outputBuffer; - } catch (Exception ex) { - throw new SignatureException(ex); - } finally { - inputOffset = 0; - } - } - - @Override - protected boolean engineVerify(byte[] sigBytes) throws SignatureException { - if (key == null) { - // This can't actually happen, but you never know... - throw new SignatureException("Need RSA public key"); - } - - if (inputIsTooLong) { - return false; - } - - byte[] outputBuffer = new byte[inputBuffer.length]; - try { - final int resultSize; - try { - resultSize = NativeCrypto.RSA_public_decrypt(sigBytes.length, sigBytes, - outputBuffer, key.getPkeyContext(), NativeCrypto.RSA_PKCS1_PADDING); - } catch (SignatureException e) { - throw e; - } catch (Exception e) { - return false; - } - /* Make this constant time by comparing every byte. */ - boolean matches = (resultSize == inputOffset); - for (int i = 0; i < resultSize; i++) { - if (inputBuffer[i] != outputBuffer[i]) { - matches = false; - } - } - return matches; - } catch (Exception ex) { - throw new SignatureException(ex); - } finally { - inputOffset = 0; - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLSocketFactoryImpl.java b/crypto/src/main/java/org/conscrypt/OpenSSLSocketFactoryImpl.java deleted file mode 100644 index 72fd89f..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLSocketFactoryImpl.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.security.KeyManagementException; - -public class OpenSSLSocketFactoryImpl extends javax.net.ssl.SSLSocketFactory { - - private final SSLParametersImpl sslParameters; - private final IOException instantiationException; - - public OpenSSLSocketFactoryImpl() { - SSLParametersImpl sslParametersLocal = null; - IOException instantiationExceptionLocal = null; - try { - sslParametersLocal = SSLParametersImpl.getDefault(); - } catch (KeyManagementException e) { - instantiationExceptionLocal = new IOException("Delayed instantiation exception:"); - instantiationExceptionLocal.initCause(e); - } - this.sslParameters = sslParametersLocal; - this.instantiationException = instantiationExceptionLocal; - } - - public OpenSSLSocketFactoryImpl(SSLParametersImpl sslParameters) { - this.sslParameters = sslParameters; - this.instantiationException = null; - } - - public String[] getDefaultCipherSuites() { - return NativeCrypto.getDefaultCipherSuites(); - } - - public String[] getSupportedCipherSuites() { - return NativeCrypto.getSupportedCipherSuites(); - } - - public Socket createSocket() throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new OpenSSLSocketImpl((SSLParametersImpl) sslParameters.clone()); - } - - public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - return new OpenSSLSocketImpl(host, port, (SSLParametersImpl) sslParameters.clone()); - } - - public Socket createSocket(String host, int port, InetAddress localHost, int localPort) - throws IOException, UnknownHostException { - return new OpenSSLSocketImpl(host, - port, - localHost, - localPort, - (SSLParametersImpl) sslParameters.clone()); - } - - public Socket createSocket(InetAddress host, int port) throws IOException { - return new OpenSSLSocketImpl(host, port, (SSLParametersImpl) sslParameters.clone()); - } - - public Socket createSocket(InetAddress address, - int port, - InetAddress localAddress, - int localPort) - throws IOException { - return new OpenSSLSocketImpl(address, - port, - localAddress, - localPort, - (SSLParametersImpl) sslParameters.clone()); - } - - public Socket createSocket(Socket s, String host, int port, boolean autoClose) - throws IOException { - return new OpenSSLSocketImplWrapper(s, - host, - port, - autoClose, - (SSLParametersImpl) sslParameters.clone()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLSocketImpl.java b/crypto/src/main/java/org/conscrypt/OpenSSLSocketImpl.java deleted file mode 100644 index 91891ee..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLSocketImpl.java +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import dalvik.system.BlockGuard; -import dalvik.system.CloseGuard; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -import java.security.InvalidKeyException; -import java.security.PrivateKey; -import java.security.SecureRandom; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLProtocolException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.X509TrustManager; -import javax.security.auth.x500.X500Principal; -import static libcore.io.OsConstants.*; -import libcore.io.ErrnoException; -import libcore.io.Libcore; -import libcore.io.Streams; -import libcore.io.StructTimeval; - -/** - * Implementation of the class OpenSSLSocketImpl based on OpenSSL. - * <p> - * Extensions to SSLSocket include: - * <ul> - * <li>handshake timeout - * <li>session tickets - * <li>Server Name Indication - * </ul> - */ -public class OpenSSLSocketImpl - extends javax.net.ssl.SSLSocket - implements NativeCrypto.SSLHandshakeCallbacks { - - /** - * Protects handshakeStarted and handshakeCompleted. - */ - private final Object handshakeLock = new Object(); - - /** - * First thread to try to handshake sets this to true. - */ - private boolean handshakeStarted = false; - - /** - * Not set to true until the update from native that tells us the - * full handshake is complete, since SSL_do_handshake can return - * before the handshake is completely done due to - * handshake_cutthrough support. - */ - private boolean handshakeCompleted = false; - - /** - * Protected by synchronizing on this. Starts as 0, set by - * startHandshake, reset to 0 on close. - */ - private long sslNativePointer; - - /** - * Protected by synchronizing on this. Starts as null, set by - * getInputStream after startHandshake. - */ - private InputStream is; - - /** - * Protected by synchronizing on this. Starts as null, set by - * getInputStream after startHandshake. - */ - private OutputStream os; - - /** - * OpenSSL only lets one thread read at a time, so this is used to - * make sure we serialize callers of SSL_read. Thread is already - * expected to have completed handshaking. - */ - private final Object readLock = new Object(); - - /** - * OpenSSL only lets one thread write at a time, so this is used - * to make sure we serialize callers of SSL_write. Thread is - * already expected to have completed handshaking. - */ - private final Object writeLock = new Object(); - - private final Socket socket; - private final boolean autoClose; - private final String wrappedHost; - private final int wrappedPort; - private final SSLParametersImpl sslParameters; - private final CloseGuard guard = CloseGuard.get(); - - private String[] enabledProtocols; - private String[] enabledCipherSuites; - private byte[] npnProtocols; - private byte[] alpnProtocols; - private boolean useSessionTickets; - private String hostname; - - /** - * Whether the TLS Channel ID extension is enabled. This field is - * server-side only. - */ - private boolean channelIdEnabled; - - /** - * Private key for the TLS Channel ID extension. This field is - * client-side only. Set during startHandshake. - */ - private OpenSSLKey channelIdPrivateKey; - - /** Set during startHandshake. */ - private OpenSSLSessionImpl sslSession; - - private ArrayList<HandshakeCompletedListener> listeners; - - /** - * Local cache of timeout to avoid getsockopt on every read and - * write for non-wrapped sockets. Note that - * OpenSSLSocketImplWrapper overrides setSoTimeout and - * getSoTimeout to delegate to the wrapped socket. - */ - private int readTimeoutMilliseconds = 0; - private int writeTimeoutMilliseconds = 0; - - private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite - - protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException { - this.socket = this; - this.wrappedHost = null; - this.wrappedPort = -1; - this.autoClose = false; - this.sslParameters = sslParameters; - this.enabledProtocols = NativeCrypto.getDefaultProtocols(); - this.enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); - } - - protected OpenSSLSocketImpl(SSLParametersImpl sslParameters, - String[] enabledProtocols, - String[] enabledCipherSuites) throws IOException { - this.socket = this; - this.wrappedHost = null; - this.wrappedPort = -1; - this.autoClose = false; - this.sslParameters = sslParameters; - this.enabledProtocols = enabledProtocols; - this.enabledCipherSuites = enabledCipherSuites; - } - - protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters) - throws IOException { - super(host, port); - this.socket = this; - this.wrappedHost = null; - this.wrappedPort = -1; - this.autoClose = false; - this.sslParameters = sslParameters; - this.enabledProtocols = NativeCrypto.getDefaultProtocols(); - this.enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); - } - - protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters) - throws IOException { - super(address, port); - this.socket = this; - this.wrappedHost = null; - this.wrappedPort = -1; - this.autoClose = false; - this.sslParameters = sslParameters; - this.enabledProtocols = NativeCrypto.getDefaultProtocols(); - this.enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); - } - - - protected OpenSSLSocketImpl(String host, int port, - InetAddress clientAddress, int clientPort, - SSLParametersImpl sslParameters) throws IOException { - super(host, port, clientAddress, clientPort); - this.socket = this; - this.wrappedHost = null; - this.wrappedPort = -1; - this.autoClose = false; - this.sslParameters = sslParameters; - this.enabledProtocols = NativeCrypto.getDefaultProtocols(); - this.enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); - } - - protected OpenSSLSocketImpl(InetAddress address, int port, - InetAddress clientAddress, int clientPort, - SSLParametersImpl sslParameters) throws IOException { - super(address, port, clientAddress, clientPort); - this.socket = this; - this.wrappedHost = null; - this.wrappedPort = -1; - this.autoClose = false; - this.sslParameters = sslParameters; - this.enabledProtocols = NativeCrypto.getDefaultProtocols(); - this.enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); - } - - /** - * Create an SSL socket that wraps another socket. Invoked by - * OpenSSLSocketImplWrapper constructor. - */ - protected OpenSSLSocketImpl(Socket socket, String host, int port, - boolean autoClose, SSLParametersImpl sslParameters) throws IOException { - this.socket = socket; - this.wrappedHost = host; - this.wrappedPort = port; - this.autoClose = autoClose; - this.sslParameters = sslParameters; - this.enabledProtocols = NativeCrypto.getDefaultProtocols(); - this.enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); - - // this.timeout is not set intentionally. - // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout - // to wrapped socket - } - - /** - * Gets the suitable session reference from the session cache container. - */ - private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) { - String hostName = getPeerHostName(); - int port = getPeerPort(); - if (hostName == null) { - return null; - } - OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port); - if (session == null) { - return null; - } - - String protocol = session.getProtocol(); - boolean protocolFound = false; - for (String enabledProtocol : enabledProtocols) { - if (protocol.equals(enabledProtocol)) { - protocolFound = true; - break; - } - } - if (!protocolFound) { - return null; - } - - String cipherSuite = session.getCipherSuite(); - boolean cipherSuiteFound = false; - for (String enabledCipherSuite : enabledCipherSuites) { - if (cipherSuite.equals(enabledCipherSuite)) { - cipherSuiteFound = true; - break; - } - } - if (!cipherSuiteFound) { - return null; - } - - return session; - } - - private void checkOpen() throws SocketException { - if (isClosed()) { - throw new SocketException("Socket is closed"); - } - } - - /** - * Starts a TLS/SSL handshake on this connection using some native methods - * from the OpenSSL library. It can negotiate new encryption keys, change - * cipher suites, or initiate a new session. The certificate chain is - * verified if the correspondent property in java.Security is set. All - * listeners are notified at the end of the TLS/SSL handshake. - */ - @Override public synchronized void startHandshake() throws IOException { - synchronized (handshakeLock) { - checkOpen(); - if (!handshakeStarted) { - handshakeStarted = true; - } else { - return; - } - } - - // note that this modifies the global seed, not something specific to the connection - final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES; - final SecureRandom secureRandom = sslParameters.getSecureRandomMember(); - if (secureRandom == null) { - NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes); - } else { - NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes)); - } - - final boolean client = sslParameters.getUseClientMode(); - - final long sslCtxNativePointer = (client) ? - sslParameters.getClientSessionContext().sslCtxNativePointer : - sslParameters.getServerSessionContext().sslCtxNativePointer; - - this.sslNativePointer = 0; - boolean exception = true; - try { - sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer); - guard.open("close"); - - if (npnProtocols != null) { - NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer); - } - - if (client && alpnProtocols != null) { - NativeCrypto.SSL_CTX_set_alpn_protos(sslCtxNativePointer, alpnProtocols); - } - - // setup server certificates and private keys. - // clients will receive a call back to request certificates. - if (!client) { - Set<String> keyTypes = new HashSet<String>(); - for (String enabledCipherSuite : enabledCipherSuites) { - if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) { - continue; - } - String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType(); - if (keyType != null) { - keyTypes.add(keyType); - } - } - for (String keyType : keyTypes) { - try { - setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType, - null, - this)); - } catch (CertificateEncodingException e) { - throw new IOException(e); - } - } - } - - NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols); - NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites); - if (useSessionTickets) { - NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET); - } - if (hostname != null) { - NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname); - } - - boolean enableSessionCreation = sslParameters.getEnableSessionCreation(); - if (!enableSessionCreation) { - NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer, - enableSessionCreation); - } - - AbstractSessionContext sessionContext; - OpenSSLSessionImpl sessionToReuse; - if (client) { - // look for client session to reuse - ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext(); - sessionContext = clientSessionContext; - sessionToReuse = getCachedClientSession(clientSessionContext); - if (sessionToReuse != null) { - NativeCrypto.SSL_set_session(sslNativePointer, - sessionToReuse.sslSessionNativePointer); - } - } else { - sessionContext = sslParameters.getServerSessionContext(); - sessionToReuse = null; - } - - // setup peer certificate verification - if (client) { - // TODO support for anonymous cipher would require us to - // conditionally use SSL_VERIFY_NONE - } else { - // needing client auth takes priority... - boolean certRequested; - if (sslParameters.getNeedClientAuth()) { - NativeCrypto.SSL_set_verify(sslNativePointer, - NativeCrypto.SSL_VERIFY_PEER - | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT); - certRequested = true; - // ... over just wanting it... - } else if (sslParameters.getWantClientAuth()) { - NativeCrypto.SSL_set_verify(sslNativePointer, - NativeCrypto.SSL_VERIFY_PEER); - certRequested = true; - // ... and it defaults properly so don't call SSL_set_verify in the common case. - } else { - certRequested = false; - } - - if (certRequested) { - X509TrustManager trustManager = sslParameters.getTrustManager(); - X509Certificate[] issuers = trustManager.getAcceptedIssuers(); - if (issuers != null && issuers.length != 0) { - byte[][] issuersBytes; - try { - issuersBytes = encodeIssuerX509Principals(issuers); - } catch (CertificateEncodingException e) { - throw new IOException("Problem encoding principals", e); - } - NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes); - } - } - } - - // Temporarily use a different timeout for the handshake process - int savedReadTimeoutMilliseconds = getSoTimeout(); - int savedWriteTimeoutMilliseconds = getSoWriteTimeout(); - if (handshakeTimeoutMilliseconds >= 0) { - setSoTimeout(handshakeTimeoutMilliseconds); - setSoWriteTimeout(handshakeTimeoutMilliseconds); - } - - // TLS Channel ID - if (channelIdEnabled) { - if (client) { - // Client-side TLS Channel ID - if (channelIdPrivateKey == null) { - throw new SSLHandshakeException("Invalid TLS channel ID key specified"); - } - NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer, - channelIdPrivateKey.getPkeyContext()); - } else { - // Server-side TLS Channel ID - NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer); - } - } - - int sslSessionNativePointer; - try { - sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer, - socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols, - client ? null : alpnProtocols); - } catch (CertificateException e) { - SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage()); - wrapper.initCause(e); - throw wrapper; - } - byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer); - if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) { - this.sslSession = sessionToReuse; - sslSession.lastAccessedTime = System.currentTimeMillis(); - NativeCrypto.SSL_SESSION_free(sslSessionNativePointer); - } else { - if (!enableSessionCreation) { - // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled - throw new IllegalStateException("SSL Session may not be created"); - } - X509Certificate[] localCertificates - = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer)); - X509Certificate[] peerCertificates - = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer)); - this.sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates, - peerCertificates, getPeerHostName(), getPeerPort(), sessionContext); - // if not, putSession later in handshakeCompleted() callback - if (handshakeCompleted) { - sessionContext.putSession(sslSession); - } - } - - // Restore the original timeout now that the handshake is complete - if (handshakeTimeoutMilliseconds >= 0) { - setSoTimeout(savedReadTimeoutMilliseconds); - setSoWriteTimeout(savedWriteTimeoutMilliseconds); - } - - // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback - if (handshakeCompleted) { - notifyHandshakeCompletedListeners(); - } - - exception = false; - } catch (SSLProtocolException e) { - throw new SSLHandshakeException(e); - } finally { - // on exceptional exit, treat the socket as closed - if (exception) { - close(); - } - } - } - - private 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; - } - - String getPeerHostName() { - if (wrappedHost != null) { - return wrappedHost; - } - InetAddress inetAddress = super.getInetAddress(); - if (inetAddress != null) { - return inetAddress.getHostName(); - } - return null; - } - - int getPeerPort() { - return wrappedHost == null ? super.getPort() : wrappedPort; - } - - /** - * Return a possibly null array of X509Certificates given the - * possibly null array of DER encoded bytes. - */ - private static OpenSSLX509Certificate[] createCertChain(long[] certificateRefs) - throws IOException { - if (certificateRefs == null) { - return null; - } - OpenSSLX509Certificate[] certificates = new OpenSSLX509Certificate[certificateRefs.length]; - for (int i = 0; i < certificateRefs.length; i++) { - certificates[i] = new OpenSSLX509Certificate(certificateRefs[i]); - } - return certificates; - } - - private void setCertificate(String alias) throws CertificateEncodingException, SSLException { - if (alias == null) { - return; - } - PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias); - if (privateKey == null) { - return; - } - X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias); - if (certificates == null) { - return; - } - - /* - * Make sure we keep a reference to the OpenSSLX509Certificate by using - * this array. Otherwise, if they're not OpenSSLX509Certificate - * instances originally, they may be garbage collected before we complete - * our JNI calls. - */ - OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[certificates.length]; - long[] x509refs = new long[certificates.length]; - for (int i = 0; i < certificates.length; i++) { - OpenSSLX509Certificate openSslCert = OpenSSLX509Certificate - .fromCertificate(certificates[i]); - openSslCerts[i] = openSslCert; - x509refs[i] = openSslCert.getContext(); - } - - // Note that OpenSSL says to use SSL_use_certificate before SSL_use_PrivateKey. - NativeCrypto.SSL_use_certificate(sslNativePointer, x509refs); - - try { - final OpenSSLKey key = OpenSSLKey.fromPrivateKey(privateKey); - NativeCrypto.SSL_use_PrivateKey(sslNativePointer, key.getPkeyContext()); - } catch (InvalidKeyException e) { - throw new SSLException(e); - } - - // checks the last installed private key and certificate, - // so need to do this once per loop iteration - NativeCrypto.SSL_check_private_key(sslNativePointer); - } - - @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb - public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) - throws CertificateEncodingException, SSLException { - - String[] keyTypes = new String[keyTypeBytes.length]; - for (int i = 0; i < keyTypeBytes.length; i++) { - keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]); - } - - X500Principal[] issuers; - if (asn1DerEncodedPrincipals == null) { - issuers = null; - } else { - issuers = new X500Principal[asn1DerEncodedPrincipals.length]; - for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { - issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); - } - } - setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this)); - } - - @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback - public void handshakeCompleted() { - handshakeCompleted = true; - - // If sslSession is null, the handshake was completed during - // the call to NativeCrypto.SSL_do_handshake and not during a - // later read operation. That means we do not need to fix up - // the SSLSession and session cache or notify - // HandshakeCompletedListeners, it will be done in - // startHandshake. - if (sslSession == null) { - return; - } - - // reset session id from the native pointer and update the - // appropriate cache. - sslSession.resetId(); - AbstractSessionContext sessionContext = - (sslParameters.getUseClientMode()) - ? sslParameters.getClientSessionContext() - : sslParameters.getServerSessionContext(); - sessionContext.putSession(sslSession); - - // let listeners know we are finally done - notifyHandshakeCompletedListeners(); - } - - private void notifyHandshakeCompletedListeners() { - if (listeners != null && !listeners.isEmpty()) { - // notify the listeners - HandshakeCompletedEvent event = - new HandshakeCompletedEvent(this, sslSession); - for (HandshakeCompletedListener listener : listeners) { - try { - listener.handshakeCompleted(event); - } catch (RuntimeException e) { - // The RI runs the handlers in a separate thread, - // which we do not. But we try to preserve their - // behavior of logging a problem and not killing - // the handshaking thread just because a listener - // has a problem. - Thread thread = Thread.currentThread(); - thread.getUncaughtExceptionHandler().uncaughtException(thread, e); - } - } - } - } - - @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks - @Override public void verifyCertificateChain(long[] certRefs, String authMethod) - throws CertificateException { - try { - if (certRefs == null || certRefs.length == 0) { - throw new SSLException("Peer sent no certificate"); - } - OpenSSLX509Certificate[] peerCertChain = new OpenSSLX509Certificate[certRefs.length]; - for (int i = 0; i < certRefs.length; i++) { - peerCertChain[i] = new OpenSSLX509Certificate(certRefs[i]); - } - boolean client = sslParameters.getUseClientMode(); - if (client) { - X509TrustManager x509tm = sslParameters.getTrustManager(); - if (x509tm instanceof TrustManagerImpl) { - TrustManagerImpl tm = (TrustManagerImpl) x509tm; - tm.checkServerTrusted(peerCertChain, authMethod, wrappedHost); - } else { - x509tm.checkServerTrusted(peerCertChain, authMethod); - } - } else { - String authType = peerCertChain[0].getPublicKey().getAlgorithm(); - sslParameters.getTrustManager().checkClientTrusted(peerCertChain, - authType); - } - - } catch (CertificateException e) { - throw e; - } catch (Exception e) { - throw new CertificateException(e); - } - } - - @Override public InputStream getInputStream() throws IOException { - checkOpen(); - synchronized (this) { - if (is == null) { - is = new SSLInputStream(); - } - - return is; - } - } - - @Override public OutputStream getOutputStream() throws IOException { - checkOpen(); - synchronized (this) { - if (os == null) { - os = new SSLOutputStream(); - } - - return os; - } - } - - /** - * This inner class provides input data stream functionality - * for the OpenSSL native implementation. It is used to - * read data received via SSL protocol. - */ - private class SSLInputStream extends InputStream { - SSLInputStream() throws IOException { - /* - * Note: When startHandshake() throws an exception, no - * SSLInputStream object will be created. - */ - OpenSSLSocketImpl.this.startHandshake(); - } - - /** - * Reads one byte. If there is no data in the underlying buffer, - * this operation can block until the data will be - * available. - * @return read value. - * @throws IOException - */ - @Override - public int read() throws IOException { - return Streams.readSingleByte(this); - } - - /** - * Method acts as described in spec for superclass. - * @see java.io.InputStream#read(byte[],int,int) - */ - @Override - public int read(byte[] buf, int offset, int byteCount) throws IOException { - BlockGuard.getThreadPolicy().onNetwork(); - synchronized (readLock) { - checkOpen(); - Arrays.checkOffsetAndCount(buf.length, offset, byteCount); - if (byteCount == 0) { - return 0; - } - return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(), - OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout()); - } - } - } - - /** - * This inner class provides output data stream functionality - * for the OpenSSL native implementation. It is used to - * write data according to the encryption parameters given in SSL context. - */ - private class SSLOutputStream extends OutputStream { - SSLOutputStream() throws IOException { - /* - * Note: When startHandshake() throws an exception, no - * SSLOutputStream object will be created. - */ - OpenSSLSocketImpl.this.startHandshake(); - } - - /** - * Method acts as described in spec for superclass. - * @see java.io.OutputStream#write(int) - */ - @Override - public void write(int oneByte) throws IOException { - Streams.writeSingleByte(this, oneByte); - } - - /** - * Method acts as described in spec for superclass. - * @see java.io.OutputStream#write(byte[],int,int) - */ - @Override - public void write(byte[] buf, int offset, int byteCount) throws IOException { - BlockGuard.getThreadPolicy().onNetwork(); - synchronized (writeLock) { - checkOpen(); - Arrays.checkOffsetAndCount(buf.length, offset, byteCount); - if (byteCount == 0) { - return; - } - NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(), - OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds); - } - } - } - - - @Override public SSLSession getSession() { - if (sslSession == null) { - try { - startHandshake(); - } catch (IOException e) { - // return an invalid session with - // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" - return SSLSessionImpl.getNullSession(); - } - } - return sslSession; - } - - @Override public void addHandshakeCompletedListener( - HandshakeCompletedListener listener) { - if (listener == null) { - throw new IllegalArgumentException("Provided listener is null"); - } - if (listeners == null) { - listeners = new ArrayList<HandshakeCompletedListener>(); - } - listeners.add(listener); - } - - @Override public void removeHandshakeCompletedListener( - HandshakeCompletedListener listener) { - if (listener == null) { - throw new IllegalArgumentException("Provided listener is null"); - } - if (listeners == null) { - throw new IllegalArgumentException( - "Provided listener is not registered"); - } - if (!listeners.remove(listener)) { - throw new IllegalArgumentException( - "Provided listener is not registered"); - } - } - - @Override public boolean getEnableSessionCreation() { - return sslParameters.getEnableSessionCreation(); - } - - @Override public void setEnableSessionCreation(boolean flag) { - sslParameters.setEnableSessionCreation(flag); - } - - @Override public String[] getSupportedCipherSuites() { - return NativeCrypto.getSupportedCipherSuites(); - } - - @Override public String[] getEnabledCipherSuites() { - return enabledCipherSuites.clone(); - } - - @Override public void setEnabledCipherSuites(String[] suites) { - enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites); - } - - @Override public String[] getSupportedProtocols() { - return NativeCrypto.getSupportedProtocols(); - } - - @Override public String[] getEnabledProtocols() { - return enabledProtocols.clone(); - } - - @Override public void setEnabledProtocols(String[] protocols) { - enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols); - } - - /** - * This method enables session ticket support. - * - * @param useSessionTickets True to enable session tickets - */ - public void setUseSessionTickets(boolean useSessionTickets) { - this.useSessionTickets = useSessionTickets; - } - - /** - * This method enables Server Name Indication - * - * @param hostname the desired SNI hostname, or null to disable - */ - public void setHostname(String hostname) { - this.hostname = hostname; - } - - /** - * Enables/disables TLS Channel ID for this server socket. - * - * <p>This method needs to be invoked before the handshake starts. - * - * @throws IllegalStateException if this is a client socket or if the handshake has already - * started. - - */ - public void setChannelIdEnabled(boolean enabled) { - if (getUseClientMode()) { - throw new IllegalStateException("Client mode"); - } - if (handshakeStarted) { - throw new IllegalStateException( - "Could not enable/disable Channel ID after the initial handshake has" - + " begun."); - } - this.channelIdEnabled = enabled; - } - - /** - * Gets the TLS Channel ID for this server socket. Channel ID is only available once the - * handshake completes. - * - * @return channel ID or {@code null} if not available. - * - * @throws IllegalStateException if this is a client socket or if the handshake has not yet - * completed. - * @throws SSLException if channel ID is available but could not be obtained. - */ - public byte[] getChannelId() throws SSLException { - if (getUseClientMode()) { - throw new IllegalStateException("Client mode"); - } - if (!handshakeCompleted) { - throw new IllegalStateException( - "Channel ID is only available after handshake completes"); - } - return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer); - } - - /** - * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket. - * - * <p>This method needs to be invoked before the handshake starts. - * - * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables - * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST - * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1). - * - * @throws IllegalStateException if this is a server socket or if the handshake has already - * started. - */ - public void setChannelIdPrivateKey(PrivateKey privateKey) { - if (!getUseClientMode()) { - throw new IllegalStateException("Server mode"); - } - if (handshakeStarted) { - throw new IllegalStateException( - "Could not change Channel ID private key after the initial handshake has" - + " begun."); - } - if (privateKey == null) { - this.channelIdEnabled = false; - this.channelIdPrivateKey = null; - } else { - this.channelIdEnabled = true; - try { - this.channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey); - } catch (InvalidKeyException e) { - // Will have error in startHandshake - } - } - } - - @Override public boolean getUseClientMode() { - return sslParameters.getUseClientMode(); - } - - @Override public void setUseClientMode(boolean mode) { - if (handshakeStarted) { - throw new IllegalArgumentException( - "Could not change the mode after the initial handshake has begun."); - } - sslParameters.setUseClientMode(mode); - } - - @Override public boolean getWantClientAuth() { - return sslParameters.getWantClientAuth(); - } - - @Override public boolean getNeedClientAuth() { - return sslParameters.getNeedClientAuth(); - } - - @Override public void setNeedClientAuth(boolean need) { - sslParameters.setNeedClientAuth(need); - } - - @Override public void setWantClientAuth(boolean want) { - sslParameters.setWantClientAuth(want); - } - - @Override public void sendUrgentData(int data) throws IOException { - throw new SocketException("Method sendUrgentData() is not supported."); - } - - @Override public void setOOBInline(boolean on) throws SocketException { - throw new SocketException("Methods sendUrgentData, setOOBInline are not supported."); - } - - @Override public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException { - super.setSoTimeout(readTimeoutMilliseconds); - this.readTimeoutMilliseconds = readTimeoutMilliseconds; - } - - @Override public int getSoTimeout() throws SocketException { - return readTimeoutMilliseconds; - } - - /** - * Note write timeouts are not part of the javax.net.ssl.SSLSocket API - */ - public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException { - this.writeTimeoutMilliseconds = writeTimeoutMilliseconds; - - StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds); - try { - Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv); - } catch (ErrnoException errnoException) { - throw errnoException.rethrowAsSocketException(); - } - } - - /** - * Note write timeouts are not part of the javax.net.ssl.SSLSocket API - */ - public int getSoWriteTimeout() throws SocketException { - return writeTimeoutMilliseconds; - } - - /** - * Set the handshake timeout on this socket. This timeout is specified in - * milliseconds and will be used only during the handshake process. - */ - public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException { - this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds; - } - - @Override public void close() throws IOException { - // TODO: Close SSL sockets using a background thread so they close gracefully. - - synchronized (handshakeLock) { - if (!handshakeStarted) { - // prevent further attempts to start handshake - handshakeStarted = true; - - synchronized (this) { - free(); - - if (socket != this) { - if (autoClose && !socket.isClosed()) { - socket.close(); - } - } else { - if (!super.isClosed()) { - super.close(); - } - } - } - - return; - } - } - - synchronized (this) { - - // Interrupt any outstanding reads or writes before taking the writeLock and readLock - NativeCrypto.SSL_interrupt(sslNativePointer); - - synchronized (writeLock) { - synchronized (readLock) { - // Shut down the SSL connection, per se. - try { - if (handshakeStarted) { - BlockGuard.getThreadPolicy().onNetwork(); - NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(), - this); - } - } catch (IOException ignored) { - /* - * Note that although close() can throw - * IOException, the RI does not throw if there - * is problem sending a "close notify" which - * can happen if the underlying socket is closed. - */ - } finally { - /* - * Even if the above call failed, it is still safe to free - * the native structs, and we need to do so lest we leak - * memory. - */ - free(); - - if (socket != this) { - if (autoClose && !socket.isClosed()) { - socket.close(); - } - } else { - if (!super.isClosed()) { - super.close(); - } - } - } - } - } - } - } - - private void free() { - if (sslNativePointer == 0) { - return; - } - NativeCrypto.SSL_free(sslNativePointer); - sslNativePointer = 0; - guard.close(); - } - - @Override protected void finalize() throws Throwable { - try { - /* - * Just worry about our own state. Notably we do not try and - * close anything. The SocketImpl, either our own - * PlainSocketImpl, or the Socket we are wrapping, will do - * that. This might mean we do not properly SSL_shutdown, but - * if you want to do that, properly close the socket yourself. - * - * The reason why we don't try to SSL_shutdown, is that there - * can be a race between finalizers where the PlainSocketImpl - * finalizer runs first and closes the socket. However, in the - * meanwhile, the underlying file descriptor could be reused - * for another purpose. If we call SSL_shutdown, the - * underlying socket BIOs still have the old file descriptor - * and will write the close notify to some unsuspecting - * reader. - */ - if (guard != null) { - guard.warnIfOpen(); - } - free(); - } finally { - super.finalize(); - } - } - - @Override - public FileDescriptor getFileDescriptor$() { - if (socket == this) { - return super.getFileDescriptor$(); - } else { - return socket.getFileDescriptor$(); - } - } - - /** - * Returns the protocol agreed upon by client and server, or null if no - * protocol was agreed upon. - */ - public byte[] getNpnSelectedProtocol() { - return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer); - } - - /** - * Returns the protocol agreed upon by client and server, or {@code null} if - * no protocol was agreed upon. - */ - public byte[] getAlpnSelectedProtocol() { - return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer); - } - - /** - * Sets the list of protocols this peer is interested in. If null no - * protocols will be used. - * - * @param npnProtocols a non-empty array of protocol names. From - * SSL_select_next_proto, "vector of 8-bit, length prefixed byte - * strings. The length byte itself is not included in the length. A byte - * string of length 0 is invalid. No byte string may be truncated.". - */ - public void setNpnProtocols(byte[] npnProtocols) { - if (npnProtocols != null && npnProtocols.length == 0) { - throw new IllegalArgumentException("npnProtocols.length == 0"); - } - this.npnProtocols = npnProtocols; - } - - /** - * Sets the list of protocols this peer is interested in. If the list is - * {@code null}, no protocols will be used. - * - * @param alpnProtocols a non-empty array of protocol names. From - * SSL_select_next_proto, "vector of 8-bit, length prefixed byte - * strings. The length byte itself is not included in the length. - * A byte string of length 0 is invalid. No byte string may be - * truncated.". - */ - public void setAlpnProtocols(byte[] alpnProtocols) { - if (alpnProtocols != null && alpnProtocols.length == 0) { - throw new IllegalArgumentException("alpnProtocols.length == 0"); - } - this.alpnProtocols = alpnProtocols; - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLSocketImplWrapper.java b/crypto/src/main/java/org/conscrypt/OpenSSLSocketImplWrapper.java deleted file mode 100644 index b6f43fa..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLSocketImplWrapper.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.SocketException; - -/** - * This class wraps the SSL functionality over an existing connected socket. - */ -public class OpenSSLSocketImplWrapper extends OpenSSLSocketImpl { - - private Socket socket; - - protected OpenSSLSocketImplWrapper(Socket socket, String host, int port, - boolean autoClose, SSLParametersImpl sslParameters) throws IOException { - super(socket, host, port, autoClose, sslParameters); - if (!socket.isConnected()) { - throw new SocketException("Socket is not connected."); - } - this.socket = socket; - } - - @Override - public void connect(SocketAddress sockaddr, int timeout) - throws IOException { - throw new IOException("Underlying socket is already connected."); - } - - @Override - public void connect(SocketAddress sockaddr) throws IOException { - throw new IOException("Underlying socket is already connected."); - } - - @Override - public void bind(SocketAddress sockaddr) throws IOException { - throw new IOException("Underlying socket is already connected."); - } - - @Override - public SocketAddress getRemoteSocketAddress() { - return socket.getRemoteSocketAddress(); - } - - @Override - public SocketAddress getLocalSocketAddress() { - return socket.getLocalSocketAddress(); - } - - @Override - public InetAddress getLocalAddress() { - return socket.getLocalAddress(); - } - - @Override - public InetAddress getInetAddress() { - return socket.getInetAddress(); - } - - @Override - public String toString() { - return "SSL socket over " + socket.toString(); - } - - @Override - public void setSoLinger(boolean on, int linger) throws SocketException { - socket.setSoLinger(on, linger); - } - - @Override - public void setTcpNoDelay(boolean on) throws SocketException { - socket.setTcpNoDelay(on); - } - - @Override - public void setReuseAddress(boolean on) throws SocketException { - socket.setReuseAddress(on); - } - - @Override - public void setKeepAlive(boolean on) throws SocketException { - socket.setKeepAlive(on); - } - - @Override - public void setTrafficClass(int tos) throws SocketException { - socket.setTrafficClass(tos); - } - - @Override - public void setSoTimeout(int to) throws SocketException { - socket.setSoTimeout(to); - super.setSoTimeout(to); - } - - @Override - public void setSendBufferSize(int size) throws SocketException { - socket.setSendBufferSize(size); - } - - @Override - public void setReceiveBufferSize(int size) throws SocketException { - socket.setReceiveBufferSize(size); - } - - @Override - public boolean getTcpNoDelay() throws SocketException { - return socket.getTcpNoDelay(); - } - - @Override - public boolean getReuseAddress() throws SocketException { - return socket.getReuseAddress(); - } - - @Override - public boolean getOOBInline() throws SocketException { - return socket.getOOBInline(); - } - - @Override - public boolean getKeepAlive() throws SocketException { - return socket.getKeepAlive(); - } - - @Override - public int getTrafficClass() throws SocketException { - return socket.getTrafficClass(); - } - - @Override - public int getSoTimeout() throws SocketException { - return socket.getSoTimeout(); - } - - @Override - public int getSoLinger() throws SocketException { - return socket.getSoLinger(); - } - - @Override - public int getSendBufferSize() throws SocketException { - return socket.getSendBufferSize(); - } - - @Override - public int getReceiveBufferSize() throws SocketException { - return socket.getReceiveBufferSize(); - } - - @Override - public boolean isConnected() { - return socket.isConnected(); - } - - @Override - public boolean isClosed() { - return socket.isClosed(); - } - - @Override - public boolean isBound() { - return socket.isBound(); - } - - @Override - public boolean isOutputShutdown() { - return socket.isOutputShutdown(); - } - - @Override - public boolean isInputShutdown() { - return socket.isInputShutdown(); - } - - @Override - public int getPort() { - return socket.getPort(); - } - - @Override - public int getLocalPort() { - return socket.getLocalPort(); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLX509CRL.java b/crypto/src/main/java/org/conscrypt/OpenSSLX509CRL.java deleted file mode 100644 index 56b99cc..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLX509CRL.java +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (C) 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import org.apache.harmony.security.utils.AlgNameMapper; -import org.conscrypt.OpenSSLX509CertificateFactory.ParsingException; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Principal; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.cert.CRLException; -import java.security.cert.Certificate; -import java.security.cert.X509CRL; -import java.security.cert.X509CRLEntry; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TimeZone; -import javax.security.auth.x500.X500Principal; - -public class OpenSSLX509CRL extends X509CRL { - private final long mContext; - - private OpenSSLX509CRL(long ctx) { - mContext = ctx; - } - - public static OpenSSLX509CRL fromX509DerInputStream(InputStream is) throws ParsingException { - final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - try { - final long crlCtx = NativeCrypto.d2i_X509_CRL_bio(bis.getBioContext()); - if (crlCtx == 0) { - return null; - } - return new OpenSSLX509CRL(crlCtx); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - } - - public static List<OpenSSLX509CRL> fromPkcs7DerInputStream(InputStream is) - throws ParsingException { - OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - final long[] certRefs; - try { - certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CRLS); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - - final List<OpenSSLX509CRL> certs = new ArrayList<OpenSSLX509CRL>(certRefs.length); - for (int i = 0; i < certRefs.length; i++) { - if (certRefs[i] == 0) { - continue; - } - certs.add(new OpenSSLX509CRL(certRefs[i])); - } - return certs; - } - - public static OpenSSLX509CRL fromX509PemInputStream(InputStream is) throws ParsingException { - final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - try { - final long crlCtx = NativeCrypto.PEM_read_bio_X509_CRL(bis.getBioContext()); - if (crlCtx == 0) { - return null; - } - return new OpenSSLX509CRL(crlCtx); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - } - - public static List<OpenSSLX509CRL> fromPkcs7PemInputStream(InputStream is) - throws ParsingException { - OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - final long[] certRefs; - try { - certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(), - NativeCrypto.PKCS7_CRLS); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - - final List<OpenSSLX509CRL> certs = new ArrayList<OpenSSLX509CRL>(certRefs.length); - for (int i = 0; i < certRefs.length; i++) { - if (certRefs[i] == 0) { - continue; - } - certs.add(new OpenSSLX509CRL(certRefs[i])); - } - return certs; - } - - @Override - public Set<String> getCriticalExtensionOIDs() { - String[] critOids = - NativeCrypto.get_X509_CRL_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL); - - /* - * This API has a special case that if there are no extensions, we - * should return null. So if we have no critical extensions, we'll check - * non-critical extensions. - */ - if ((critOids.length == 0) - && (NativeCrypto.get_X509_CRL_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) { - return null; - } - - return new HashSet<String>(Arrays.asList(critOids)); - } - - @Override - public byte[] getExtensionValue(String oid) { - return NativeCrypto.X509_CRL_get_ext_oid(mContext, oid); - } - - @Override - public Set<String> getNonCriticalExtensionOIDs() { - String[] nonCritOids = - NativeCrypto.get_X509_CRL_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_NON_CRITICAL); - - /* - * This API has a special case that if there are no extensions, we - * should return null. So if we have no non-critical extensions, we'll - * check critical extensions. - */ - if ((nonCritOids.length == 0) - && (NativeCrypto.get_X509_CRL_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) { - return null; - } - - return new HashSet<String>(Arrays.asList(nonCritOids)); - } - - @Override - public boolean hasUnsupportedCriticalExtension() { - final String[] criticalOids = - NativeCrypto.get_X509_CRL_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL); - for (String oid : criticalOids) { - final long extensionRef = NativeCrypto.X509_CRL_get_ext(mContext, oid); - if (NativeCrypto.X509_supported_extension(extensionRef) != 1) { - return true; - } - } - - return false; - } - - @Override - public byte[] getEncoded() throws CRLException { - return NativeCrypto.i2d_X509_CRL(mContext); - } - - private void verifyOpenSSL(OpenSSLKey pkey) throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException { - NativeCrypto.X509_CRL_verify(mContext, pkey.getPkeyContext()); - } - - private void verifyInternal(PublicKey key, String sigProvider) throws CRLException, - NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, - SignatureException { - String sigAlg = getSigAlgName(); - if (sigAlg == null) { - sigAlg = getSigAlgOID(); - } - - final Signature sig; - if (sigProvider == null) { - sig = Signature.getInstance(sigAlg); - } else { - sig = Signature.getInstance(sigAlg, sigProvider); - } - - sig.initVerify(key); - sig.update(getTBSCertList()); - if (!sig.verify(getSignature())) { - throw new SignatureException("signature did not verify"); - } - } - - @Override - public void verify(PublicKey key) throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException { - if (key instanceof OpenSSLKeyHolder) { - OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey(); - verifyOpenSSL(pkey); - return; - } - - verifyInternal(key, null); - } - - @Override - public void verify(PublicKey key, String sigProvider) throws CRLException, - NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, - SignatureException { - verifyInternal(key, sigProvider); - } - - @Override - public int getVersion() { - return (int) NativeCrypto.X509_CRL_get_version(mContext) + 1; - } - - @Override - public Principal getIssuerDN() { - return getIssuerX500Principal(); - } - - @Override - public X500Principal getIssuerX500Principal() { - final byte[] issuer = NativeCrypto.X509_CRL_get_issuer_name(mContext); - return new X500Principal(issuer); - } - - @Override - public Date getThisUpdate() { - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - calendar.set(Calendar.MILLISECOND, 0); - NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_CRL_get_lastUpdate(mContext), - calendar); - return calendar.getTime(); - } - - @Override - public Date getNextUpdate() { - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - calendar.set(Calendar.MILLISECOND, 0); - NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_CRL_get_nextUpdate(mContext), - calendar); - return calendar.getTime(); - } - - @Override - public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) { - final long revokedRef = NativeCrypto.X509_CRL_get0_by_serial(mContext, - serialNumber.toByteArray()); - if (revokedRef == 0) { - return null; - } - - return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(revokedRef)); - } - - @Override - public X509CRLEntry getRevokedCertificate(X509Certificate certificate) { - if (certificate instanceof OpenSSLX509Certificate) { - OpenSSLX509Certificate osslCert = (OpenSSLX509Certificate) certificate; - final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext, - osslCert.getContext()); - - if (x509RevokedRef == 0) { - return null; - } - - return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(x509RevokedRef)); - } - - return getRevokedCertificate(certificate.getSerialNumber()); - } - - @Override - public Set<? extends X509CRLEntry> getRevokedCertificates() { - final long[] entryRefs = NativeCrypto.X509_CRL_get_REVOKED(mContext); - if (entryRefs == null || entryRefs.length == 0) { - return null; - } - - final Set<OpenSSLX509CRLEntry> crlSet = new HashSet<OpenSSLX509CRLEntry>(); - for (long entryRef : entryRefs) { - crlSet.add(new OpenSSLX509CRLEntry(entryRef)); - } - - return crlSet; - } - - @Override - public byte[] getTBSCertList() throws CRLException { - return NativeCrypto.get_X509_CRL_crl_enc(mContext); - } - - @Override - public byte[] getSignature() { - return NativeCrypto.get_X509_CRL_signature(mContext); - } - - @Override - public String getSigAlgName() { - return AlgNameMapper.map2AlgName(getSigAlgOID()); - } - - @Override - public String getSigAlgOID() { - return NativeCrypto.get_X509_CRL_sig_alg_oid(mContext); - } - - @Override - public byte[] getSigAlgParams() { - return NativeCrypto.get_X509_CRL_sig_alg_parameter(mContext); - } - - @Override - public boolean isRevoked(Certificate cert) { - if (!(cert instanceof X509Certificate)) { - return false; - } - - final OpenSSLX509Certificate osslCert; - if (cert instanceof OpenSSLX509Certificate) { - osslCert = (OpenSSLX509Certificate) cert; - } else { - try { - osslCert = OpenSSLX509Certificate.fromX509DerInputStream(new ByteArrayInputStream( - cert.getEncoded())); - } catch (Exception e) { - throw new RuntimeException("cannot convert certificate", e); - } - } - - final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext, - osslCert.getContext()); - - return x509RevokedRef != 0; - } - - @Override - public String toString() { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - final long bioCtx = NativeCrypto.create_BIO_OutputStream(os); - try { - NativeCrypto.X509_CRL_print(bioCtx, mContext); - return os.toString(); - } finally { - NativeCrypto.BIO_free(bioCtx); - } - } - - @Override - protected void finalize() throws Throwable { - try { - if (mContext != 0) { - NativeCrypto.X509_CRL_free(mContext); - } - } finally { - super.finalize(); - } - } - -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java b/crypto/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java deleted file mode 100644 index 470cc98..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.ByteArrayOutputStream; -import java.math.BigInteger; -import java.security.cert.CRLException; -import java.security.cert.X509CRLEntry; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; -import java.util.TimeZone; - -public class OpenSSLX509CRLEntry extends X509CRLEntry { - private final long mContext; - - OpenSSLX509CRLEntry(long ctx) { - mContext = ctx; - } - - @Override - public Set<String> getCriticalExtensionOIDs() { - String[] critOids = - NativeCrypto.get_X509_REVOKED_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_CRITICAL); - - /* - * This API has a special case that if there are no extensions, we - * should return null. So if we have no critical extensions, we'll check - * non-critical extensions. - */ - if ((critOids.length == 0) - && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) { - return null; - } - - return new HashSet<String>(Arrays.asList(critOids)); - } - - @Override - public byte[] getExtensionValue(String oid) { - return NativeCrypto.X509_REVOKED_get_ext_oid(mContext, oid); - } - - @Override - public Set<String> getNonCriticalExtensionOIDs() { - String[] critOids = - NativeCrypto.get_X509_REVOKED_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_NON_CRITICAL); - - /* - * This API has a special case that if there are no extensions, we - * should return null. So if we have no non-critical extensions, we'll - * check critical extensions. - */ - if ((critOids.length == 0) - && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) { - return null; - } - - return new HashSet<String>(Arrays.asList(critOids)); - } - - @Override - public boolean hasUnsupportedCriticalExtension() { - final String[] criticalOids = - NativeCrypto.get_X509_REVOKED_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_CRITICAL); - for (String oid : criticalOids) { - final long extensionRef = NativeCrypto.X509_REVOKED_get_ext(mContext, oid); - if (NativeCrypto.X509_supported_extension(extensionRef) != 1) { - return true; - } - } - - return false; - } - - @Override - public byte[] getEncoded() throws CRLException { - return NativeCrypto.i2d_X509_REVOKED(mContext); - } - - @Override - public BigInteger getSerialNumber() { - return new BigInteger(NativeCrypto.X509_REVOKED_get_serialNumber(mContext)); - } - - @Override - public Date getRevocationDate() { - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - calendar.set(Calendar.MILLISECOND, 0); - NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.get_X509_REVOKED_revocationDate(mContext), - calendar); - return calendar.getTime(); - } - - @Override - public boolean hasExtensions() { - return (NativeCrypto.get_X509_REVOKED_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length != 0) - || (NativeCrypto.get_X509_REVOKED_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_CRITICAL).length != 0); - } - - @Override - public String toString() { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - long bioCtx = NativeCrypto.create_BIO_OutputStream(os); - try { - NativeCrypto.X509_REVOKED_print(bioCtx, mContext); - return os.toString(); - } finally { - NativeCrypto.BIO_free(bioCtx); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLX509CertPath.java b/crypto/src/main/java/org/conscrypt/OpenSSLX509CertPath.java deleted file mode 100644 index 57568b8..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLX509CertPath.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.security.cert.CertPath; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import org.conscrypt.OpenSSLX509CertificateFactory.ParsingException; - -public class OpenSSLX509CertPath extends CertPath { - private static final byte[] PKCS7_MARKER = "-----BEGIN PKCS7".getBytes(); - - private static final int PUSHBACK_SIZE = 64; - - /** - * Supported encoding types for CerthPath. Used by the various APIs that - * encode this into bytes such as {@link #getEncoded()}. - */ - private enum Encoding { - PKI_PATH("PkiPath"), - PKCS7("PKCS7"); - - private final String apiName; - - Encoding(String apiName) { - this.apiName = apiName; - } - - static Encoding findByApiName(String apiName) throws CertificateEncodingException { - for (Encoding element : values()) { - if (element.apiName.equals(apiName)) { - return element; - } - } - - return null; - } - } - - /** Unmodifiable list of encodings for the API. */ - private static final List<String> ALL_ENCODINGS = Collections.unmodifiableList(Arrays - .asList(new String[] { - Encoding.PKI_PATH.apiName, - Encoding.PKCS7.apiName, - })); - - private static final Encoding DEFAULT_ENCODING = Encoding.PKI_PATH; - - private final List<? extends X509Certificate> mCertificates; - - static Iterator<String> getEncodingsIterator() { - return ALL_ENCODINGS.iterator(); - } - - protected OpenSSLX509CertPath(List<? extends X509Certificate> certificates) { - super("X.509"); - - mCertificates = certificates; - } - - @Override - public List<? extends Certificate> getCertificates() { - return Collections.unmodifiableList(mCertificates); - } - - private byte[] getEncoded(Encoding encoding) throws CertificateEncodingException { - final OpenSSLX509Certificate[] certs = new OpenSSLX509Certificate[mCertificates.size()]; - final long[] certRefs = new long[certs.length]; - - for (int i = 0, j = certs.length - 1; j >= 0; i++, j--) { - final X509Certificate cert = mCertificates.get(i); - - if (cert instanceof OpenSSLX509Certificate) { - certs[j] = (OpenSSLX509Certificate) cert; - } else { - certs[j] = OpenSSLX509Certificate.fromX509Der(cert.getEncoded()); - } - - certRefs[j] = certs[j].getContext(); - } - - switch (encoding) { - case PKI_PATH: - return NativeCrypto.ASN1_seq_pack_X509(certRefs); - case PKCS7: - return NativeCrypto.i2d_PKCS7(certRefs); - default: - throw new CertificateEncodingException("Unknown encoding"); - } - } - - @Override - public byte[] getEncoded() throws CertificateEncodingException { - return getEncoded(DEFAULT_ENCODING); - } - - @Override - public byte[] getEncoded(String encoding) throws CertificateEncodingException { - Encoding enc = Encoding.findByApiName(encoding); - if (enc == null) { - throw new CertificateEncodingException("Invalid encoding: " + encoding); - } - - return getEncoded(enc); - } - - @Override - public Iterator<String> getEncodings() { - return getEncodingsIterator(); - } - - private static CertPath fromPkiPathEncoding(InputStream inStream) throws CertificateException { - OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(inStream); - - final boolean markable = inStream.markSupported(); - if (markable) { - inStream.mark(PUSHBACK_SIZE); - } - - final long[] certRefs; - try { - certRefs = NativeCrypto.ASN1_seq_unpack_X509_bio(bis.getBioContext()); - } catch (Exception e) { - if (markable) { - try { - inStream.reset(); - } catch (IOException ignored) { - } - } - throw new CertificateException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - - if (certRefs == null) { - return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList()); - } - - final List<OpenSSLX509Certificate> certs = - new ArrayList<OpenSSLX509Certificate>(certRefs.length); - for (int i = certRefs.length - 1; i >= 0; i--) { - if (certRefs[i] == 0) { - continue; - } - certs.add(new OpenSSLX509Certificate(certRefs[i])); - } - - return new OpenSSLX509CertPath(certs); - } - - private static CertPath fromPkcs7Encoding(InputStream inStream) throws CertificateException { - try { - if (inStream == null || inStream.available() == 0) { - return new OpenSSLX509CertPath(Collections.<X509Certificate> emptyList()); - } - } catch (IOException e) { - throw new CertificateException("Problem reading input stream", e); - } - - final boolean markable = inStream.markSupported(); - if (markable) { - inStream.mark(PUSHBACK_SIZE); - } - - /* Attempt to see if this is a PKCS#7 bag. */ - final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE); - try { - final byte[] buffer = new byte[PKCS7_MARKER.length]; - - final int len = pbis.read(buffer); - if (len < 0) { - /* No need to reset here. The stream was empty or EOF. */ - throw new ParsingException("inStream is empty"); - } - pbis.unread(buffer, 0, len); - - if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) { - return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7PemInputStream(pbis)); - } - - return new OpenSSLX509CertPath(OpenSSLX509Certificate.fromPkcs7DerInputStream(pbis)); - } catch (Exception e) { - if (markable) { - try { - inStream.reset(); - } catch (IOException ignored) { - } - } - throw new CertificateException(e); - } - } - - private static CertPath fromEncoding(InputStream inStream, Encoding encoding) - throws CertificateException { - switch (encoding) { - case PKI_PATH: - return fromPkiPathEncoding(inStream); - case PKCS7: - return fromPkcs7Encoding(inStream); - default: - throw new CertificateEncodingException("Unknown encoding"); - } - } - - public static CertPath fromEncoding(InputStream inStream, String encoding) - throws CertificateException { - if (inStream == null) { - throw new CertificateException("inStream == null"); - } - - Encoding enc = Encoding.findByApiName(encoding); - if (enc == null) { - throw new CertificateException("Invalid encoding: " + encoding); - } - - return fromEncoding(inStream, enc); - } - - public static CertPath fromEncoding(InputStream inStream) throws CertificateException { - return fromEncoding(inStream, DEFAULT_ENCODING); - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLX509Certificate.java b/crypto/src/main/java/org/conscrypt/OpenSSLX509Certificate.java deleted file mode 100644 index 634a981..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLX509Certificate.java +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Principal; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.CertificateParsingException; -import java.security.cert.X509Certificate; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TimeZone; -import javax.security.auth.x500.X500Principal; -import org.apache.harmony.security.utils.AlgNameMapper; -import org.conscrypt.OpenSSLX509CertificateFactory.ParsingException; - -public class OpenSSLX509Certificate extends X509Certificate { - private final long mContext; - - OpenSSLX509Certificate(long ctx) { - mContext = ctx; - } - - public static OpenSSLX509Certificate fromX509DerInputStream(InputStream is) - throws ParsingException { - @SuppressWarnings("resource") - final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - try { - final long certCtx = NativeCrypto.d2i_X509_bio(bis.getBioContext()); - if (certCtx == 0) { - return null; - } - return new OpenSSLX509Certificate(certCtx); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - } - - public static OpenSSLX509Certificate fromX509Der(byte[] encoded) { - final long certCtx = NativeCrypto.d2i_X509(encoded); - if (certCtx == 0) { - return null; - } - return new OpenSSLX509Certificate(certCtx); - } - - public static List<OpenSSLX509Certificate> fromPkcs7DerInputStream(InputStream is) - throws ParsingException { - @SuppressWarnings("resource") - OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - final long[] certRefs; - try { - certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CERTS); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - - if (certRefs == null) { - return Collections.emptyList(); - } - - final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>( - certRefs.length); - for (int i = 0; i < certRefs.length; i++) { - if (certRefs[i] == 0) { - continue; - } - certs.add(new OpenSSLX509Certificate(certRefs[i])); - } - return certs; - } - - public static OpenSSLX509Certificate fromX509PemInputStream(InputStream is) - throws ParsingException { - @SuppressWarnings("resource") - final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - try { - final long certCtx = NativeCrypto.PEM_read_bio_X509(bis.getBioContext()); - if (certCtx == 0L) { - return null; - } - return new OpenSSLX509Certificate(certCtx); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - } - - public static List<OpenSSLX509Certificate> fromPkcs7PemInputStream(InputStream is) - throws ParsingException { - @SuppressWarnings("resource") - OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); - - final long[] certRefs; - try { - certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(), - NativeCrypto.PKCS7_CERTS); - } catch (Exception e) { - throw new ParsingException(e); - } finally { - NativeCrypto.BIO_free(bis.getBioContext()); - } - - final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>( - certRefs.length); - for (int i = 0; i < certRefs.length; i++) { - if (certRefs[i] == 0) { - continue; - } - certs.add(new OpenSSLX509Certificate(certRefs[i])); - } - return certs; - } - - public static OpenSSLX509Certificate fromCertificate(Certificate cert) - throws CertificateEncodingException { - if (cert instanceof OpenSSLX509Certificate) { - return (OpenSSLX509Certificate) cert; - } else if (cert instanceof X509Certificate) { - return fromX509Der(cert.getEncoded()); - } else { - throw new CertificateEncodingException("Only X.509 certificates are supported"); - } - } - - @Override - public Set<String> getCriticalExtensionOIDs() { - String[] critOids = - NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL); - - /* - * This API has a special case that if there are no extensions, we - * should return null. So if we have no critical extensions, we'll check - * non-critical extensions. - */ - if ((critOids.length == 0) - && (NativeCrypto.get_X509_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) { - return null; - } - - return new HashSet<String>(Arrays.asList(critOids)); - } - - @Override - public byte[] getExtensionValue(String oid) { - return NativeCrypto.X509_get_ext_oid(mContext, oid); - } - - @Override - public Set<String> getNonCriticalExtensionOIDs() { - String[] nonCritOids = - NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_NON_CRITICAL); - - /* - * This API has a special case that if there are no extensions, we - * should return null. So if we have no non-critical extensions, we'll - * check critical extensions. - */ - if ((nonCritOids.length == 0) - && (NativeCrypto.get_X509_ext_oids(mContext, - NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) { - return null; - } - - return new HashSet<String>(Arrays.asList(nonCritOids)); - } - - @Override - public boolean hasUnsupportedCriticalExtension() { - return (NativeCrypto.get_X509_ex_flags(mContext) & NativeCrypto.EXFLAG_CRITICAL) != 0; - } - - @Override - public void checkValidity() throws CertificateExpiredException, - CertificateNotYetValidException { - checkValidity(new Date()); - } - - @Override - public void checkValidity(Date date) throws CertificateExpiredException, - CertificateNotYetValidException { - if (getNotBefore().compareTo(date) > 0) { - throw new CertificateNotYetValidException(); - } - - if (getNotAfter().compareTo(date) < 0) { - throw new CertificateExpiredException(); - } - } - - @Override - public int getVersion() { - return (int) NativeCrypto.X509_get_version(mContext) + 1; - } - - @Override - public BigInteger getSerialNumber() { - return new BigInteger(NativeCrypto.X509_get_serialNumber(mContext)); - } - - @Override - public Principal getIssuerDN() { - return getIssuerX500Principal(); - } - - @Override - public Principal getSubjectDN() { - return getSubjectX500Principal(); - } - - @Override - public Date getNotBefore() { - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - calendar.set(Calendar.MILLISECOND, 0); - NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notBefore(mContext), calendar); - return calendar.getTime(); - } - - @Override - public Date getNotAfter() { - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - calendar.set(Calendar.MILLISECOND, 0); - NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notAfter(mContext), calendar); - return calendar.getTime(); - } - - @Override - public byte[] getTBSCertificate() throws CertificateEncodingException { - return NativeCrypto.get_X509_cert_info_enc(mContext); - } - - @Override - public byte[] getSignature() { - return NativeCrypto.get_X509_signature(mContext); - } - - @Override - public String getSigAlgName() { - return AlgNameMapper.map2AlgName(getSigAlgOID()); - } - - @Override - public String getSigAlgOID() { - return NativeCrypto.get_X509_sig_alg_oid(mContext); - } - - @Override - public byte[] getSigAlgParams() { - return NativeCrypto.get_X509_sig_alg_parameter(mContext); - } - - @Override - public boolean[] getIssuerUniqueID() { - return NativeCrypto.get_X509_issuerUID(mContext); - } - - @Override - public boolean[] getSubjectUniqueID() { - return NativeCrypto.get_X509_subjectUID(mContext); - } - - @Override - public boolean[] getKeyUsage() { - final boolean[] kusage = NativeCrypto.get_X509_ex_kusage(mContext); - if (kusage == null) { - return null; - } - - if (kusage.length >= 9) { - return kusage; - } - - final boolean resized[] = new boolean[9]; - System.arraycopy(kusage, 0, resized, 0, kusage.length); - return resized; - } - - @Override - public int getBasicConstraints() { - if ((NativeCrypto.get_X509_ex_flags(mContext) & NativeCrypto.EXFLAG_CA) == 0) { - return -1; - } - - final int pathLen = NativeCrypto.get_X509_ex_pathlen(mContext); - if (pathLen == -1) { - return Integer.MAX_VALUE; - } - - return pathLen; - } - - @Override - public byte[] getEncoded() throws CertificateEncodingException { - return NativeCrypto.i2d_X509(mContext); - } - - private void verifyOpenSSL(OpenSSLKey pkey) throws CertificateException, - NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, - SignatureException { - try { - NativeCrypto.X509_verify(mContext, pkey.getPkeyContext()); - } catch (RuntimeException e) { - throw new CertificateException(e); - } - } - - private void verifyInternal(PublicKey key, String sigProvider) throws CertificateException, - NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, - SignatureException { - String sigAlg = getSigAlgName(); - if (sigAlg == null) { - sigAlg = getSigAlgOID(); - } - - final Signature sig; - if (sigProvider == null) { - sig = Signature.getInstance(sigAlg); - } else { - sig = Signature.getInstance(sigAlg, sigProvider); - } - - sig.initVerify(key); - sig.update(getTBSCertificate()); - if (!sig.verify(getSignature())) { - throw new SignatureException("signature did not verify"); - } - } - - @Override - public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException { - if (key instanceof OpenSSLKeyHolder) { - OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey(); - verifyOpenSSL(pkey); - return; - } - - verifyInternal(key, null); - } - - @Override - public void verify(PublicKey key, String sigProvider) throws CertificateException, - NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, - SignatureException { - verifyInternal(key, sigProvider); - } - - @Override - public String toString() { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - long bioCtx = NativeCrypto.create_BIO_OutputStream(os); - try { - NativeCrypto.X509_print_ex(bioCtx, mContext, 0, 0); - return os.toString(); - } finally { - NativeCrypto.BIO_free(bioCtx); - } - } - - @Override - public PublicKey getPublicKey() { - /* First try to generate the key from supported OpenSSL key types. */ - try { - OpenSSLKey pkey = new OpenSSLKey(NativeCrypto.X509_get_pubkey(mContext)); - return pkey.getPublicKey(); - } catch (NoSuchAlgorithmException ignored) { - } - - /* Try generating the key using other Java providers. */ - String oid = NativeCrypto.get_X509_pubkey_oid(mContext); - byte[] encoded = NativeCrypto.i2d_X509_PUBKEY(mContext); - try { - KeyFactory kf = KeyFactory.getInstance(oid); - return kf.generatePublic(new X509EncodedKeySpec(encoded)); - } catch (NoSuchAlgorithmException ignored) { - } catch (InvalidKeySpecException ignored) { - } - - /* - * We couldn't find anything else, so just return a nearly-unusable - * X.509-encoded key. - */ - return new X509PublicKey(oid, encoded); - } - - @Override - public X500Principal getIssuerX500Principal() { - final byte[] issuer = NativeCrypto.X509_get_issuer_name(mContext); - return new X500Principal(issuer); - } - - @Override - public X500Principal getSubjectX500Principal() { - final byte[] subject = NativeCrypto.X509_get_subject_name(mContext); - return new X500Principal(subject); - } - - @Override - public List<String> getExtendedKeyUsage() throws CertificateParsingException { - String[] extUsage = NativeCrypto.get_X509_ex_xkusage(mContext); - if (extUsage == null) { - return null; - } - - return Arrays.asList(extUsage); - } - - private static Collection<List<?>> alternativeNameArrayToList(Object[][] altNameArray) { - if (altNameArray == null) { - return null; - } - - Collection<List<?>> coll = new ArrayList<List<?>>(altNameArray.length); - for (int i = 0; i < altNameArray.length; i++) { - coll.add(Collections.unmodifiableList(Arrays.asList(altNameArray[i]))); - } - - return Collections.unmodifiableCollection(coll); - } - - @Override - public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException { - return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext, - NativeCrypto.GN_STACK_SUBJECT_ALT_NAME)); - } - - @Override - public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException { - return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext, - NativeCrypto.GN_STACK_ISSUER_ALT_NAME)); - } - - @Override - public boolean equals(Object other) { - if (other instanceof OpenSSLX509Certificate) { - OpenSSLX509Certificate o = (OpenSSLX509Certificate) other; - - return NativeCrypto.X509_cmp(mContext, o.mContext) == 0; - } - - return super.equals(other); - } - - @Override - public int hashCode() { - /* Make this faster since we might be in hash-based structures. */ - return NativeCrypto.get_X509_hashCode(mContext); - } - - long getContext() { - return mContext; - } - - @Override - protected void finalize() throws Throwable { - try { - if (mContext != 0) { - NativeCrypto.X509_free(mContext); - } - } finally { - super.finalize(); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLX509CertificateFactory.java b/crypto/src/main/java/org/conscrypt/OpenSSLX509CertificateFactory.java deleted file mode 100644 index 75fdedb..0000000 --- a/crypto/src/main/java/org/conscrypt/OpenSSLX509CertificateFactory.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.security.cert.CRL; -import java.security.cert.CRLException; -import java.security.cert.CertPath; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactorySpi; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -public class OpenSSLX509CertificateFactory extends CertificateFactorySpi { - private static final byte[] PKCS7_MARKER = "-----BEGIN PKCS7".getBytes(); - - private static final int PUSHBACK_SIZE = 64; - - static class ParsingException extends Exception { - private static final long serialVersionUID = 8390802697728301325L; - - public ParsingException(String message) { - super(message); - } - - public ParsingException(Exception cause) { - super(cause); - } - - public ParsingException(String message, Exception cause) { - super(message, cause); - } - } - - /** - * The code for X509 Certificates and CRL is pretty much the same. We use - * this abstract class to share the code between them. This makes it ugly, - * but it's already written in this language anyway. - */ - private static abstract class Parser<T> { - public T generateItem(InputStream inStream) throws ParsingException { - if (inStream == null) { - throw new ParsingException("inStream == null"); - } - - final boolean markable = inStream.markSupported(); - if (markable) { - inStream.mark(PKCS7_MARKER.length); - } - - final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE); - try { - final byte[] buffer = new byte[PKCS7_MARKER.length]; - - final int len = pbis.read(buffer); - if (len < 0) { - /* No need to reset here. The stream was empty or EOF. */ - throw new ParsingException("inStream is empty"); - } - pbis.unread(buffer, 0, len); - - if (buffer[0] == '-') { - if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) { - List<? extends T> items = fromPkcs7PemInputStream(pbis); - if (items.size() == 0) { - return null; - } - items.get(0); - } else { - return fromX509PemInputStream(pbis); - } - } - - /* PKCS#7 bags have a byte 0x06 at position 4 in the stream. */ - if (buffer[4] == 0x06) { - List<? extends T> certs = fromPkcs7DerInputStream(pbis); - if (certs.size() == 0) { - return null; - } - return certs.get(0); - } else { - return fromX509DerInputStream(pbis); - } - } catch (Exception e) { - if (markable) { - try { - inStream.reset(); - } catch (IOException ignored) { - } - } - throw new ParsingException(e); - } - } - - public Collection<? extends T> generateItems(InputStream inStream) - throws ParsingException { - if (inStream == null) { - throw new ParsingException("inStream == null"); - } - try { - if (inStream.available() == 0) { - return Collections.emptyList(); - } - } catch (IOException e) { - throw new ParsingException("Problem reading input stream", e); - } - - final boolean markable = inStream.markSupported(); - if (markable) { - inStream.mark(PUSHBACK_SIZE); - } - - /* Attempt to see if this is a PKCS#7 bag. */ - final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE); - try { - final byte[] buffer = new byte[PKCS7_MARKER.length]; - - final int len = pbis.read(buffer); - if (len < 0) { - /* No need to reset here. The stream was empty or EOF. */ - throw new ParsingException("inStream is empty"); - } - pbis.unread(buffer, 0, len); - - if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) { - return fromPkcs7PemInputStream(pbis); - } - - /* PKCS#7 bags have a byte 0x06 at position 4 in the stream. */ - if (buffer[4] == 0x06) { - return fromPkcs7DerInputStream(pbis); - } - } catch (Exception e) { - if (markable) { - try { - inStream.reset(); - } catch (IOException ignored) { - } - } - throw new ParsingException(e); - } - - /* - * It wasn't, so just try to keep grabbing certificates until we - * can't anymore. - */ - final List<T> coll = new ArrayList<T>(); - T c = null; - do { - /* - * If this stream supports marking, try to mark here in case - * there is an error during certificate generation. - */ - if (markable) { - inStream.mark(PUSHBACK_SIZE); - } - - try { - c = generateItem(pbis); - coll.add(c); - } catch (ParsingException e) { - /* - * If this stream supports marking, attempt to reset it to - * the mark before the failure. - */ - if (markable) { - try { - inStream.reset(); - } catch (IOException ignored) { - } - } - - c = null; - } - } while (c != null); - - return coll; - } - - protected abstract T fromX509PemInputStream(InputStream pbis) throws ParsingException; - - protected abstract T fromX509DerInputStream(InputStream pbis) throws ParsingException; - - protected abstract List<? extends T> fromPkcs7PemInputStream(InputStream is) - throws ParsingException; - - protected abstract List<? extends T> fromPkcs7DerInputStream(InputStream is) - throws ParsingException; - } - - private Parser<OpenSSLX509Certificate> certificateParser = - new Parser<OpenSSLX509Certificate>() { - @Override - public OpenSSLX509Certificate fromX509PemInputStream(InputStream is) - throws ParsingException { - return OpenSSLX509Certificate.fromX509PemInputStream(is); - } - - @Override - public OpenSSLX509Certificate fromX509DerInputStream(InputStream is) - throws ParsingException { - return OpenSSLX509Certificate.fromX509DerInputStream(is); - } - - @Override - public List<? extends OpenSSLX509Certificate> - fromPkcs7PemInputStream(InputStream is) throws ParsingException { - return OpenSSLX509Certificate.fromPkcs7PemInputStream(is); - } - - @Override - public List<? extends OpenSSLX509Certificate> - fromPkcs7DerInputStream(InputStream is) throws ParsingException { - return OpenSSLX509Certificate.fromPkcs7DerInputStream(is); - } - }; - - private Parser<OpenSSLX509CRL> crlParser = - new Parser<OpenSSLX509CRL>() { - @Override - public OpenSSLX509CRL fromX509PemInputStream(InputStream is) - throws ParsingException { - return OpenSSLX509CRL.fromX509PemInputStream(is); - } - - @Override - public OpenSSLX509CRL fromX509DerInputStream(InputStream is) - throws ParsingException { - return OpenSSLX509CRL.fromX509DerInputStream(is); - } - - @Override - public List<? extends OpenSSLX509CRL> fromPkcs7PemInputStream(InputStream is) - throws ParsingException { - return OpenSSLX509CRL.fromPkcs7PemInputStream(is); - } - - @Override - public List<? extends OpenSSLX509CRL> fromPkcs7DerInputStream(InputStream is) - throws ParsingException { - return OpenSSLX509CRL.fromPkcs7DerInputStream(is); - } - }; - - @Override - public Certificate engineGenerateCertificate(InputStream inStream) throws CertificateException { - try { - return certificateParser.generateItem(inStream); - } catch (ParsingException e) { - throw new CertificateException(e); - } - } - - @Override - public Collection<? extends Certificate> engineGenerateCertificates( - InputStream inStream) throws CertificateException { - try { - return certificateParser.generateItems(inStream); - } catch (ParsingException e) { - throw new CertificateException(e); - } - } - - @Override - public CRL engineGenerateCRL(InputStream inStream) throws CRLException { - try { - return crlParser.generateItem(inStream); - } catch (ParsingException e) { - throw new CRLException(e); - } - } - - @Override - public Collection<? extends CRL> engineGenerateCRLs(InputStream inStream) throws CRLException { - if (inStream == null) { - return Collections.emptyList(); - } - - try { - return crlParser.generateItems(inStream); - } catch (ParsingException e) { - throw new CRLException(e); - } - } - - @Override - public Iterator<String> engineGetCertPathEncodings() { - return OpenSSLX509CertPath.getEncodingsIterator(); - } - - @Override - public CertPath engineGenerateCertPath(InputStream inStream) throws CertificateException { - return OpenSSLX509CertPath.fromEncoding(inStream); - } - - @Override - public CertPath engineGenerateCertPath(InputStream inStream, String encoding) - throws CertificateException { - return OpenSSLX509CertPath.fromEncoding(inStream, encoding); - } - - @Override - public CertPath engineGenerateCertPath(List<? extends Certificate> certificates) - throws CertificateException { - final List<X509Certificate> filtered = new ArrayList<X509Certificate>(certificates.size()); - for (int i = 0; i < certificates.size(); i++) { - final Certificate c = certificates.get(i); - - if (!(c instanceof X509Certificate)) { - throw new CertificateException("Certificate not X.509 type at index " + i); - } - - filtered.add((X509Certificate) c); - } - - return new OpenSSLX509CertPath(filtered); - } -} diff --git a/crypto/src/main/java/org/conscrypt/PRF.java b/crypto/src/main/java/org/conscrypt/PRF.java deleted file mode 100644 index afbbb45..0000000 --- a/crypto/src/main/java/org/conscrypt/PRF.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.SSLException; - -/** - * This class provides functionality for computation - * of PRF values for TLS (http://www.ietf.org/rfc/rfc2246.txt) - * and SSL v3 (http://wp.netscape.com/eng/ssl3) protocols. - */ -public class PRF { - private static Logger.Stream logger = Logger.getStream("prf"); - - private static Mac md5_mac; - private static Mac sha_mac; - protected static MessageDigest md5; - protected static MessageDigest sha; - private static int md5_mac_length; - private static int sha_mac_length; - - static private void init() { - try { - md5_mac = Mac.getInstance("HmacMD5"); - sha_mac = Mac.getInstance("HmacSHA1"); - } catch (NoSuchAlgorithmException e) { - throw new AlertException(AlertProtocol.INTERNAL_ERROR, - new SSLException( - "There is no provider of HmacSHA1 or HmacMD5 " - + "algorithms installed in the system")); - } - md5_mac_length = md5_mac.getMacLength(); - sha_mac_length = sha_mac.getMacLength(); - try { - md5 = MessageDigest.getInstance("MD5"); - sha = MessageDigest.getInstance("SHA-1"); - } catch (Exception e) { - throw new AlertException(AlertProtocol.INTERNAL_ERROR, - new SSLException( - "Could not initialize the Digest Algorithms.")); - } - } - - /** - * Computes the value of SSLv3 pseudo random function. - * @param out: the buffer to fill up with the value of the function. - * @param secret: the buffer containing the secret value to generate prf. - * @param seed: the seed to be used. - */ - static synchronized void computePRF_SSLv3(byte[] out, byte[] secret, byte[] seed) { - if (sha == null) { - init(); - } - int pos = 0; - int iteration = 1; - byte[] digest; - while (pos < out.length) { - byte[] pref = new byte[iteration]; - Arrays.fill(pref, (byte) (64 + iteration++)); - sha.update(pref); - sha.update(secret); - sha.update(seed); - md5.update(secret); - md5.update(sha.digest()); - digest = md5.digest(); // length == 16 - if (pos + 16 > out.length) { - System.arraycopy(digest, 0, out, pos, out.length - pos); - pos = out.length; - } else { - System.arraycopy(digest, 0, out, pos, 16); - pos += 16; - } - } - } - - /** - * Computes the value of TLS pseudo random function. - * @param out: the buffer to fill up with the value of the function. - * @param secret: the buffer containing the secret value to generate prf. - * @param str_bytes: the label bytes to be used. - * @param seed: the seed to be used. - */ - synchronized static void computePRF(byte[] out, byte[] secret, - byte[] str_byts, byte[] seed) throws GeneralSecurityException { - if (sha_mac == null) { - init(); - } - // Do concatenation of the label with the seed: - // (metterings show that is is faster to concatenate the arrays - // and to call HMAC.update on cancatenation, than twice call for - // each of the part, i.e.: - // time(HMAC.update(label+seed)) - // < time(HMAC.update(label)) + time(HMAC.update(seed)) - // but it takes more memmory (approximaty on 4%) - /* - byte[] tmp_seed = new byte[seed.length + str_byts.length]; - System.arraycopy(str_byts, 0, tmp_seed, 0, str_byts.length); - System.arraycopy(seed, 0, tmp_seed, str_byts.length, seed.length); - seed = tmp_seed; - */ - SecretKeySpec keyMd5; - SecretKeySpec keySha1; - if ((secret == null) || (secret.length == 0)) { - secret = new byte[8]; - keyMd5 = new SecretKeySpec(secret, "HmacMD5"); - keySha1 = new SecretKeySpec(secret, "HmacSHA1"); - } else { - int length = secret.length >> 1; // division by 2 - int offset = secret.length & 1; // remainder - keyMd5 = new SecretKeySpec(secret, 0, length + offset, - "HmacMD5"); - keySha1 = new SecretKeySpec(secret, length, length - + offset, "HmacSHA1"); - } - - //byte[] str_byts = label.getBytes(); - - if (logger != null) { - logger.println("secret["+secret.length+"]: "); - logger.printAsHex(16, "", " ", secret); - logger.println("label["+str_byts.length+"]: "); - logger.printAsHex(16, "", " ", str_byts); - logger.println("seed["+seed.length+"]: "); - logger.printAsHex(16, "", " ", seed); - logger.println("MD5 key:"); - logger.printAsHex(16, "", " ", keyMd5.getEncoded()); - logger.println("SHA1 key:"); - logger.printAsHex(16, "", " ", keySha1.getEncoded()); - } - - md5_mac.init(keyMd5); - sha_mac.init(keySha1); - - int pos = 0; - md5_mac.update(str_byts); - byte[] hash = md5_mac.doFinal(seed); // A(1) - while (pos < out.length) { - md5_mac.update(hash); - md5_mac.update(str_byts); - md5_mac.update(seed); - if (pos + md5_mac_length < out.length) { - md5_mac.doFinal(out, pos); - pos += md5_mac_length; - } else { - System.arraycopy(md5_mac.doFinal(), 0, out, - pos, out.length - pos); - break; - } - // make A(i) - hash = md5_mac.doFinal(hash); - } - if (logger != null) { - logger.println("P_MD5:"); - logger.printAsHex(md5_mac_length, "", " ", out); - } - - pos = 0; - sha_mac.update(str_byts); - hash = sha_mac.doFinal(seed); // A(1) - byte[] sha1hash; - while (pos < out.length) { - sha_mac.update(hash); - sha_mac.update(str_byts); - sha1hash = sha_mac.doFinal(seed); - for (int i = 0; (i < sha_mac_length) & (pos < out.length); i++) { - out[pos++] ^= sha1hash[i]; - } - // make A(i) - hash = sha_mac.doFinal(hash); - } - - if (logger != null) { - logger.println("PRF:"); - logger.printAsHex(sha_mac_length, "", " ", out); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/PinEntryException.java b/crypto/src/main/java/org/conscrypt/PinEntryException.java deleted file mode 100644 index 8c651db..0000000 --- a/crypto/src/main/java/org/conscrypt/PinEntryException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -// public for testing by CertPinManagerTest -public class PinEntryException extends Exception { - - PinEntryException() { - } - - PinEntryException(String msg) { - super(msg); - } -} - diff --git a/crypto/src/main/java/org/conscrypt/PinFailureLogger.java b/crypto/src/main/java/org/conscrypt/PinFailureLogger.java deleted file mode 100644 index bdb44a9..0000000 --- a/crypto/src/main/java/org/conscrypt/PinFailureLogger.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.List; -import libcore.io.Base64; -import libcore.io.DropBox; - -public class PinFailureLogger { - - private static final long LOG_INTERVAL_NANOS = 1000 * 1000 * 1000 * 60 * 60; - - private static long lastLoggedNanos = 0; - - public static synchronized void log(String cn, boolean chainContainsUserCert, - boolean pinIsEnforcing, - List<X509Certificate> chain) { - // if we've logged recently, don't do it again - if (!timeToLog()) { - return; - } - // otherwise, log the event - writeToLog(cn, chainContainsUserCert, pinIsEnforcing, chain); - // update the last logged time - lastLoggedNanos = System.nanoTime(); - } - - protected static synchronized void writeToLog(String cn, boolean chainContainsUserCert, - boolean pinIsEnforcing, - List<X509Certificate> chain) { - StringBuilder sb = new StringBuilder(); - sb.append(cn); - sb.append("|"); - sb.append(chainContainsUserCert); - sb.append("|"); - sb.append(pinIsEnforcing); - sb.append("|"); - for (X509Certificate cert : chain) { - try { - sb.append(Base64.encode(cert.getEncoded())); - } catch (CertificateEncodingException e) { - sb.append("Error: could not encode certificate"); - } - sb.append("|"); - } - DropBox.addText("exp_det_cert_pin_failure", sb.toString()); - } - - protected static boolean timeToLog() { - long currentTimeNanos = System.nanoTime(); - return ((currentTimeNanos - lastLoggedNanos) > LOG_INTERVAL_NANOS); - } -} - diff --git a/crypto/src/main/java/org/conscrypt/PinListEntry.java b/crypto/src/main/java/org/conscrypt/PinListEntry.java deleted file mode 100644 index a401700..0000000 --- a/crypto/src/main/java/org/conscrypt/PinListEntry.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import libcore.io.EventLogger; - -/** - * This class represents a single entry in the pin file. - */ -// public for testing by CertPinManagerTest -public class PinListEntry { - - /** The Common Name (CN) as used on the SSL certificate */ - private final String cn; - - /** - * Determines whether a failed match here will prevent the chain from being accepted. If true, - * an unpinned chain will log and cause a match failure. If false, it will merely log. - */ - private final boolean enforcing; - - private final Set<String> pinnedFingerprints = new HashSet<String>(); - - private static final boolean DEBUG = false; - - private final TrustedCertificateStore certStore; - - public String getCommonName() { - return cn; - } - - public boolean getEnforcing() { - return enforcing; - } - - public PinListEntry(String entry, TrustedCertificateStore store) throws PinEntryException { - if (entry == null) { - throw new NullPointerException("entry == null"); - } - certStore = store; - // Examples: - // *.google.com=true|34c8a0d...9e04ca05f,9e04ca05f...34c8a0d - // *.android.com=true|ca05f...8a0d34c - // clients.google.com=false|9e04ca05f...34c8a0d,34c8a0d...9e04ca05f - String[] values = entry.split("[=,|]"); - // entry must have a CN, an enforcement value, and at least one pin - if (values.length < 3) { - throw new PinEntryException("Received malformed pin entry"); - } - // get the cn - cn = values[0]; // is there more validation we can do here? - enforcing = enforcementValueFromString(values[1]); - // the remainder should be pins - addPins(Arrays.copyOfRange(values, 2, values.length)); - } - - private static boolean enforcementValueFromString(String val) throws PinEntryException { - if (val.equals("true")) { - return true; - } else if (val.equals("false")) { - return false; - } else { - throw new PinEntryException("Enforcement status is not a valid value"); - } - } - - /** - * Checks the given chain against the pin list corresponding to this entry. - * - * If the pin list does not contain the required certs and the enforcing field is true then - * this returns true, indicating a verification error. Otherwise, it returns false and - * verification should proceed. - */ - public boolean chainIsNotPinned(List<X509Certificate> chain) { - for (X509Certificate cert : chain) { - String fingerprint = getFingerprint(cert); - if (pinnedFingerprints.contains(fingerprint)) { - return false; - } - } - logPinFailure(chain); - return enforcing; - } - - private static String getFingerprint(X509Certificate cert) { - try { - MessageDigest dgst = MessageDigest.getInstance("SHA512"); - byte[] encoded = cert.getPublicKey().getEncoded(); - byte[] fingerprint = dgst.digest(encoded); - return IntegralToString.bytesToHexString(fingerprint, false); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } - } - - private void addPins(String[] pins) { - for (String pin : pins) { - validatePin(pin); - } - Collections.addAll(pinnedFingerprints, pins); - } - - private static void validatePin(String pin) { - // check to make sure the length is correct - if (pin.length() != 128) { - throw new IllegalArgumentException("Pin is not a valid length"); - } - // check to make sure that it's a valid hex string - try { - new BigInteger(pin, 16); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Pin is not a valid hex string", e); - } - } - - private boolean chainContainsUserCert(List<X509Certificate> chain) { - if (certStore == null) { - return false; - } - for (X509Certificate cert : chain) { - if (certStore.isUserAddedCertificate(cert)) { - return true; - } - } - return false; - } - - private void logPinFailure(List<X509Certificate> chain) { - PinFailureLogger.log(cn, chainContainsUserCert(chain), enforcing, chain); - } -} - diff --git a/crypto/src/main/java/org/conscrypt/PinManagerException.java b/crypto/src/main/java/org/conscrypt/PinManagerException.java deleted file mode 100644 index e52ae83..0000000 --- a/crypto/src/main/java/org/conscrypt/PinManagerException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -class PinManagerException extends Exception { - - PinManagerException() { - } - - PinManagerException(String msg) { - super(msg); - } - - PinManagerException(String msg, Exception e) { - super(msg, e); - } -} - diff --git a/crypto/src/main/java/org/conscrypt/Platform.java b/crypto/src/main/java/org/conscrypt/Platform.java deleted file mode 100644 index 3a577ce..0000000 --- a/crypto/src/main/java/org/conscrypt/Platform.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import org.apache.harmony.security.utils.AlgNameMapper; -import org.apache.harmony.security.utils.AlgNameMapperSource; - -class Platform { - private static class NoPreloadHolder { - public static final Platform MAPPER = new Platform(); - } - - /** - * Runs all the setup for the platform that only needs to run once. - */ - public static void setup() { - NoPreloadHolder.MAPPER.ping(); - } - - /** - * Just a placeholder to make sure the class is initialized. - */ - private void ping() { - } - - private Platform() { - AlgNameMapper.setSource(new OpenSSLMapper()); - } - - private static class OpenSSLMapper implements AlgNameMapperSource { - @Override - public String mapNameToOid(String algName) { - return NativeCrypto.OBJ_txt2nid_oid(algName); - } - - @Override - public String mapOidToName(String oid) { - return NativeCrypto.OBJ_txt2nid_longName(oid); - } - } -}
\ No newline at end of file diff --git a/crypto/src/main/java/org/conscrypt/ProtocolVersion.java b/crypto/src/main/java/org/conscrypt/ProtocolVersion.java deleted file mode 100644 index 4e2555c..0000000 --- a/crypto/src/main/java/org/conscrypt/ProtocolVersion.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.util.Hashtable; - -/** - * - * Represents Protocol Version - */ -public class ProtocolVersion { - /** - * Protocols supported by this provider implementation - */ - public static final String[] supportedProtocols = new String[] { "TLSv1", - "SSLv3" }; - - private static Hashtable<String, ProtocolVersion> protocolsByName = new Hashtable<String, ProtocolVersion>(4); - - /** - * - * Returns true if protocol version is supported - * - * @param version - */ - public static boolean isSupported(byte[] version) { - if (version[0] != 3 || (version[1] != 0 && version[1] != 1)) { - return false; - } - return true; - } - - /** - * Returns ProtocolVersion - * - * @param version - * @return - */ - public static ProtocolVersion getByVersion(byte[] version) { - if (version[0] == 3) { - if (version[1] == 1) { - return TLSv1; - } - if (version[1] == 0) { - return SSLv3; - } - } - return null; - } - - /** - * Returns true if provider supports protocol version - * - * @param name - * @return - */ - public static boolean isSupported(String name) { - return protocolsByName.containsKey(name); - } - - /** - * Returns ProtocolVersion - * - * @param name - * @return - */ - public static ProtocolVersion getByName(String name) { - return protocolsByName.get(name); - } - - /** - * Highest protocol version supported by provider implementation - * - * @param protocols - * @return - */ - public static ProtocolVersion getLatestVersion(String[] protocols) { - if (protocols == null || protocols.length == 0) { - return null; - } - ProtocolVersion latest = getByName(protocols[0]); - ProtocolVersion current; - for (int i = 1; i < protocols.length; i++) { - current = getByName(protocols[i]); - if (current == null) { - continue; - } - if ((latest == null) - || (latest.version[0] < current.version[0]) - || (latest.version[0] == current.version[0] && latest.version[1] < current.version[1])) { - latest = current; - } - } - return latest; - - } - - /** - * SSL 3.0 protocol version - */ - public static final ProtocolVersion SSLv3 = new ProtocolVersion("SSLv3", - new byte[] { 3, 0 }); - - /** - * TLS 1.0 protocol version - */ - public static final ProtocolVersion TLSv1 = new ProtocolVersion("TLSv1", - new byte[] { 3, 1 }); - - static { - protocolsByName.put(SSLv3.name, SSLv3); - protocolsByName.put(TLSv1.name, TLSv1); - protocolsByName.put("SSL", SSLv3); - protocolsByName.put("TLS", TLSv1); - } - - /** - * Protocol name - */ - public final String name; - - /** - * Protocol version as byte array - */ - public final byte[] version; - - private ProtocolVersion(String name, byte[] version) { - this.name = name; - this.version = version; - } -}
\ No newline at end of file diff --git a/crypto/src/main/java/org/conscrypt/SSLBufferedInput.java b/crypto/src/main/java/org/conscrypt/SSLBufferedInput.java deleted file mode 100644 index d2834d3..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLBufferedInput.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * This is a wrapper input stream for ByteBuffer data source. - * Among with the read functionality it provides info - * about number of cunsumed bytes from the source ByteBuffer. - * The source ByteBuffer object can be reseted. - * So one instance of this wrapper can be reused for several - * ByteBuffer data sources. - */ -public class SSLBufferedInput extends SSLInputStream { - - private ByteBuffer in; - private int bytik; - private int consumed = 0; - - /** - * Constructor - */ - protected SSLBufferedInput() {} - - /** - * Sets the buffer as a data source - */ - protected void setSourceBuffer(ByteBuffer in) { - consumed = 0; - this.in = in; - } - - @Override - public int available() throws IOException { - // in assumption that the buffer has been set - return in.remaining(); - } - - /** - * Returns the number of consumed bytes. - */ - protected int consumed() { - return consumed; - } - - /** - * Reads the following byte value. If there are no bytes in the source - * buffer, method throws java.nio.BufferUnderflowException. - */ - @Override - public int read() throws IOException { - // TODO: implement optimized read(int) - // and read(byte[], int, int) methods - bytik = in.get() & 0x00FF; - consumed ++; - return bytik; - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLClientSessionCache.java b/crypto/src/main/java/org/conscrypt/SSLClientSessionCache.java deleted file mode 100644 index d070a02..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLClientSessionCache.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import javax.net.ssl.SSLSession; - -/** - * A persistent {@link javax.net.ssl.SSLSession} cache used by - * {@link javax.net.ssl.SSLSessionContext} to share client-side SSL sessions - * across processes. For example, this cache enables applications to - * persist and reuse sessions across restarts. - * - * <p>The {@code SSLSessionContext} implementation converts - * {@code SSLSession}s into raw bytes and vice versa. The exact makeup of the - * session data is dependent upon the caller's implementation and is opaque to - * the {@code SSLClientSessionCache} implementation. - */ -public interface SSLClientSessionCache { - - /** - * Gets data from a pre-existing session for a given server host and port. - * - * @param host from {@link javax.net.ssl.SSLSession#getPeerHost()} - * @param port from {@link javax.net.ssl.SSLSession#getPeerPort()} - * @return the session data or null if none is cached - * @throws NullPointerException if host is null - */ - public byte[] getSessionData(String host, int port); - - /** - * Stores session data for the given session. - * - * @param session to cache data for - * @param sessionData to cache - * @throws NullPointerException if session, result of - * {@code session.getPeerHost()} or data is null - */ - public void putSessionData(SSLSession session, byte[] sessionData); -}
\ No newline at end of file diff --git a/crypto/src/main/java/org/conscrypt/SSLContextImpl.java b/crypto/src/main/java/org/conscrypt/SSLContextImpl.java deleted file mode 100644 index 75aed4f..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLContextImpl.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.SecureRandom; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContextSpi; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLServerSocketFactory; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -/** - * Implementation of SSLContext service provider interface. - */ -public class SSLContextImpl extends SSLContextSpi { - - /** - * The default SSLContextImpl for use with SSLContext.getInstance("Default"). - * Protected by the DefaultSSLContextImpl.class monitor. - */ - private static DefaultSSLContextImpl DEFAULT_SSL_CONTEXT_IMPL; - - /** Client session cache. */ - private final ClientSessionContext clientSessionContext; - - /** Server session cache. */ - private final ServerSessionContext serverSessionContext; - - protected SSLParametersImpl sslParameters; - - public SSLContextImpl() { - clientSessionContext = new ClientSessionContext(); - serverSessionContext = new ServerSessionContext(); - } - - /** - * Constuctor for the DefaultSSLContextImpl. - * @param dummy is null, used to distinguish this case from the - * public SSLContextImpl() constructor. - */ - protected SSLContextImpl(DefaultSSLContextImpl dummy) - throws GeneralSecurityException, IOException { - synchronized (DefaultSSLContextImpl.class) { - if (DEFAULT_SSL_CONTEXT_IMPL == null) { - clientSessionContext = new ClientSessionContext(); - serverSessionContext = new ServerSessionContext(); - DEFAULT_SSL_CONTEXT_IMPL = (DefaultSSLContextImpl)this; - } else { - clientSessionContext = DEFAULT_SSL_CONTEXT_IMPL.engineGetClientSessionContext(); - serverSessionContext = DEFAULT_SSL_CONTEXT_IMPL.engineGetServerSessionContext(); - } - sslParameters = new SSLParametersImpl(DEFAULT_SSL_CONTEXT_IMPL.getKeyManagers(), - DEFAULT_SSL_CONTEXT_IMPL.getTrustManagers(), - null, - clientSessionContext, - serverSessionContext); - } - } - - /** - * Initializes this {@code SSLContext} instance. All of the arguments are - * optional, and the security providers will be searched for the required - * implementations of the needed algorithms. - * - * @param kms the key sources or {@code null} - * @param tms the trust decision sources or {@code null} - * @param sr the randomness source or {@code null} - * @throws KeyManagementException if initializing this instance fails - */ - @Override - public void engineInit(KeyManager[] kms, TrustManager[] tms, - SecureRandom sr) throws KeyManagementException { - sslParameters = new SSLParametersImpl(kms, tms, sr, - clientSessionContext, serverSessionContext); - } - - @Override - public SSLSocketFactory engineGetSocketFactory() { - if (sslParameters == null) { - throw new IllegalStateException("SSLContext is not initialized."); - } - return new SSLSocketFactoryImpl(sslParameters); - } - - @Override - public SSLServerSocketFactory engineGetServerSocketFactory() { - if (sslParameters == null) { - throw new IllegalStateException("SSLContext is not initialized."); - } - return new SSLServerSocketFactoryImpl(sslParameters); - } - - @Override - public SSLEngine engineCreateSSLEngine(String host, int port) { - if (sslParameters == null) { - throw new IllegalStateException("SSLContext is not initialized."); - } - SSLParametersImpl p = (SSLParametersImpl) sslParameters.clone(); - p.setUseClientMode(false); - return new SSLEngineImpl(host, port, p); - } - - @Override - public SSLEngine engineCreateSSLEngine() { - if (sslParameters == null) { - throw new IllegalStateException("SSLContext is not initialized."); - } - SSLParametersImpl p = (SSLParametersImpl) sslParameters.clone(); - p.setUseClientMode(false); - return new SSLEngineImpl(p); - } - - @Override - public ServerSessionContext engineGetServerSessionContext() { - return serverSessionContext; - } - - @Override - public ClientSessionContext engineGetClientSessionContext() { - return clientSessionContext; - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLEngineAppData.java b/crypto/src/main/java/org/conscrypt/SSLEngineAppData.java deleted file mode 100644 index f2cb77d..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLEngineAppData.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.nio.ByteBuffer; -import javax.net.ssl.SSLException; - -/** - * This class is used to retrieve the application data - * arrived for the SSLEngine. - */ -public class SSLEngineAppData implements Appendable { - - /** - * Buffer containing received application data. - */ - byte[] buffer; - - /** - * Constructor - */ - protected SSLEngineAppData() {} - - /** - * Stores received data. The source data is not cloned, - * just the array reference is remembered into the buffer field. - */ - public void append(byte[] src) { - if (buffer != null) { - throw new AlertException( - AlertProtocol.INTERNAL_ERROR, - new SSLException("Attempt to override the data")); - } - buffer = src; - } - - /** - * Places the data from the buffer into the array of destination - * ByteBuffer objects. - */ - protected int placeTo(ByteBuffer[] dsts, int offset, int length) { - if (buffer == null) { - return 0; - } - int pos = 0; - int len = buffer.length; - int rem; - // write data to the buffers - for (int i=offset; i<offset+length; i++) { - rem = dsts[i].remaining(); - // TODO: optimization work - use hasArray, array(), arraycopy - if (len - pos < rem) { - // can fully write remaining data into buffer - dsts[i].put(buffer, pos, len - pos); - pos = len; - // data was written, exit - break; - } - // write chunk of data - dsts[i].put(buffer, pos, rem); - pos += rem; - } - if (pos != len) { - // The data did not feet into the buffers, - // it should not happen, because the destination buffers - // had been checked for the space before record unwrapping. - // But if it so, we should allert about internal error. - throw new AlertException( - AlertProtocol.INTERNAL_ERROR, - new SSLException( - "The received application data could not be fully written" - + "into the destination buffers")); - } - buffer = null; - return len; - } -} - diff --git a/crypto/src/main/java/org/conscrypt/SSLEngineDataStream.java b/crypto/src/main/java/org/conscrypt/SSLEngineDataStream.java deleted file mode 100644 index f4a2d2d..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLEngineDataStream.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.nio.ByteBuffer; - -/** - * This class provides the DataStream functionality - * implemented over the array of ByteBuffer instances. - * Among with the data chunks read functionality - * it provides the info about amount of consumed data. - * The source ByteBuffer objects can be replaced by other. - * So one instance of this wrapper can be reused for several - * data sources. - */ -public class SSLEngineDataStream implements DataStream { - - private ByteBuffer[] srcs; - private int offset; - private int limit; - - private int available; - private int consumed; - - protected SSLEngineDataStream() {} - - protected void setSourceBuffers(ByteBuffer[] srcs, int offset, int length) { - this.srcs = srcs; - this.offset = offset; - this.limit = offset+length; - this.consumed = 0; - this.available = 0; - for (int i=offset; i<limit; i++) { - if (srcs[i] == null) { - throw new IllegalStateException( - "Some of the input parameters are null"); - } - available += srcs[i].remaining(); - } - } - - public int available() { - return available; - } - - public boolean hasData() { - return available > 0; - } - - public byte[] getData(int length) { - // TODO: optimization work: - // use ByteBuffer.get(byte[],int,int) - // and ByteBuffer.hasArray() methods - int len = (length < available) ? length : available; - available -= len; - consumed += len; - byte[] res = new byte[len]; - int pos = 0; - loop: - for (; offset<limit; offset++) { - while (srcs[offset].hasRemaining()) { - res[pos++] = srcs[offset].get(); - len --; - if (len == 0) { - break loop; - } - } - } - return res; - } - - protected int consumed() { - return consumed; - } -} - diff --git a/crypto/src/main/java/org/conscrypt/SSLEngineImpl.java b/crypto/src/main/java/org/conscrypt/SSLEngineImpl.java deleted file mode 100644 index 3ed9980..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLEngineImpl.java +++ /dev/null @@ -1,753 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ReadOnlyBufferException; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSession; - -/** - * Implementation of SSLEngine. - * @see javax.net.ssl.SSLEngine class documentation for more information. - */ -public class SSLEngineImpl extends SSLEngine { - - // indicates if peer mode was set - private boolean peer_mode_was_set = false; - // indicates if handshake has been started - private boolean handshake_started = false; - // indicates if inbound operations finished - private boolean isInboundDone = false; - // indicates if outbound operations finished - private boolean isOutboundDone = false; - // indicates if close_notify alert had been sent to another peer - private boolean close_notify_was_sent = false; - // indicates if close_notify alert had been received from another peer - private boolean close_notify_was_received = false; - // indicates if engine was closed (it means that - // all the works on it are done, except (probably) some finalizing work) - private boolean engine_was_closed = false; - // indicates if engine was shutted down (it means that - // all cleaning work had been done and the engine is not operable) - private boolean engine_was_shutteddown = false; - - // record protocol to be used - protected SSLRecordProtocol recordProtocol; - // input stream for record protocol - private SSLBufferedInput recProtIS; - // handshake protocol to be used - private HandshakeProtocol handshakeProtocol; - // alert protocol to be used - private AlertProtocol alertProtocol; - // place where application data will be stored - private SSLEngineAppData appData; - // outcoming application data stream - private SSLEngineDataStream dataStream = new SSLEngineDataStream(); - // active session object - private SSLSessionImpl session; - - // peer configuration parameters - protected SSLParametersImpl sslParameters; - - // in case of emergency situations when data could not be - // placed in destination buffers it will be stored in this - // fields - private byte[] remaining_wrapped_data = null; - private byte[] remaining_hsh_data = null; - - // logger - private Logger.Stream logger = Logger.getStream("engine"); - - protected SSLEngineImpl(SSLParametersImpl sslParameters) { - this.sslParameters = sslParameters; - } - - protected SSLEngineImpl(String host, int port, SSLParametersImpl sslParameters) { - super(host, port); - this.sslParameters = sslParameters; - } - - /** - * Starts the handshake. - * @throws SSLException - * @see javax.net.ssl.SSLEngine#beginHandshake() method documentation - * for more information - */ - @Override - public void beginHandshake() throws SSLException { - if (engine_was_closed) { - throw new SSLException("Engine has already been closed."); - } - if (!peer_mode_was_set) { - throw new IllegalStateException("Client/Server mode was not set"); - } - if (!handshake_started) { - handshake_started = true; - if (getUseClientMode()) { - handshakeProtocol = new ClientHandshakeImpl(this); - } else { - handshakeProtocol = new ServerHandshakeImpl(this); - } - appData = new SSLEngineAppData(); - alertProtocol = new AlertProtocol(); - recProtIS = new SSLBufferedInput(); - recordProtocol = new SSLRecordProtocol(handshakeProtocol, - alertProtocol, recProtIS, appData); - } - handshakeProtocol.start(); - } - - /** - * Closes inbound operations of this engine - * @throws SSLException - * @see javax.net.ssl.SSLEngine#closeInbound() method documentation - * for more information - */ - @Override - public void closeInbound() throws SSLException { - if (logger != null) { - logger.println("closeInbound() "+isInboundDone); - } - if (isInboundDone) { - return; - } - isInboundDone = true; - engine_was_closed = true; - if (handshake_started) { - if (!close_notify_was_received) { - if (session != null) { - session.invalidate(); - } - alertProtocol.alert(AlertProtocol.FATAL, - AlertProtocol.INTERNAL_ERROR); - throw new SSLException("Inbound is closed before close_notify " - + "alert has been received."); - } - } else { - // engine is closing before initial handshake has been made - shutdown(); - } - } - - /** - * Closes outbound operations of this engine - * @see javax.net.ssl.SSLEngine#closeOutbound() method documentation - * for more information - */ - @Override - public void closeOutbound() { - if (logger != null) { - logger.println("closeOutbound() "+isOutboundDone); - } - if (isOutboundDone) { - return; - } - isOutboundDone = true; - if (handshake_started) { - // initial handshake had been started - alertProtocol.alert(AlertProtocol.WARNING, - AlertProtocol.CLOSE_NOTIFY); - close_notify_was_sent = true; - } else { - // engine is closing before initial handshake has been made - shutdown(); - } - engine_was_closed = true; - } - - /** - * Returns handshake's delegated tasks to be run - * @return the delegated task to be executed. - * @see javax.net.ssl.SSLEngine#getDelegatedTask() method documentation - * for more information - */ - @Override - public Runnable getDelegatedTask() { - return handshakeProtocol.getTask(); - } - - /** - * Returns names of supported cipher suites. - * @return array of strings containing the names of supported cipher suites - * @see javax.net.ssl.SSLEngine#getSupportedCipherSuites() method - * documentation for more information - */ - @Override - public String[] getSupportedCipherSuites() { - return CipherSuite.getSupportedCipherSuiteNames(); - } - - // --------------- SSLParameters based methods --------------------- - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getEnabledCipherSuites() method - * documentation for more information - */ - @Override - public String[] getEnabledCipherSuites() { - return sslParameters.getEnabledCipherSuites(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#setEnabledCipherSuites(String[]) method - * documentation for more information - */ - @Override - public void setEnabledCipherSuites(String[] suites) { - sslParameters.setEnabledCipherSuites(suites); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getSupportedProtocols() method - * documentation for more information - */ - @Override - public String[] getSupportedProtocols() { - return ProtocolVersion.supportedProtocols.clone(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getEnabledProtocols() method - * documentation for more information - */ - @Override - public String[] getEnabledProtocols() { - return sslParameters.getEnabledProtocols(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#setEnabledProtocols(String[]) method - * documentation for more information - */ - @Override - public void setEnabledProtocols(String[] protocols) { - sslParameters.setEnabledProtocols(protocols); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#setUseClientMode(boolean) method - * documentation for more information - */ - @Override - public void setUseClientMode(boolean mode) { - if (handshake_started) { - throw new IllegalArgumentException( - "Could not change the mode after the initial handshake has begun."); - } - sslParameters.setUseClientMode(mode); - peer_mode_was_set = true; - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getUseClientMode() method - * documentation for more information - */ - @Override - public boolean getUseClientMode() { - return sslParameters.getUseClientMode(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#setNeedClientAuth(boolean) method - * documentation for more information - */ - @Override - public void setNeedClientAuth(boolean need) { - sslParameters.setNeedClientAuth(need); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getNeedClientAuth() method - * documentation for more information - */ - @Override - public boolean getNeedClientAuth() { - return sslParameters.getNeedClientAuth(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#setWantClientAuth(boolean) method - * documentation for more information - */ - @Override - public void setWantClientAuth(boolean want) { - sslParameters.setWantClientAuth(want); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getWantClientAuth() method - * documentation for more information - */ - @Override - public boolean getWantClientAuth() { - return sslParameters.getWantClientAuth(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#setEnableSessionCreation(boolean) method - * documentation for more information - */ - @Override - public void setEnableSessionCreation(boolean flag) { - sslParameters.setEnableSessionCreation(flag); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getEnableSessionCreation() method - * documentation for more information - */ - @Override - public boolean getEnableSessionCreation() { - return sslParameters.getEnableSessionCreation(); - } - - // ----------------------------------------------------------------- - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getHandshakeStatus() method - * documentation for more information - */ - @Override - public SSLEngineResult.HandshakeStatus getHandshakeStatus() { - if (!handshake_started || engine_was_shutteddown) { - // initial handshake has not been started yet - return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; - } - if (alertProtocol.hasAlert()) { - // need to send an alert - return SSLEngineResult.HandshakeStatus.NEED_WRAP; - } - if (close_notify_was_sent && !close_notify_was_received) { - // waiting for "close_notify" response - return SSLEngineResult.HandshakeStatus.NEED_UNWRAP; - } - return handshakeProtocol.getStatus(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#getSession() method - * documentation for more information - */ - @Override - public SSLSession getSession() { - if (session != null) { - return session; - } - return SSLSessionImpl.getNullSession(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#isInboundDone() method - * documentation for more information - */ - @Override - public boolean isInboundDone() { - return isInboundDone || engine_was_closed; - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLEngine#isOutboundDone() method - * documentation for more information - */ - @Override - public boolean isOutboundDone() { - return isOutboundDone; - } - - /** - * Decodes one complete SSL/TLS record provided in the source buffer. - * If decoded record contained application data, this data will - * be placed in the destination buffers. - * For more information about TLS record fragmentation see - * TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2. - * @param src source buffer containing SSL/TLS record. - * @param dsts destination buffers to place received application data. - * @see javax.net.ssl.SSLEngine#unwrap(ByteBuffer,ByteBuffer[],int,int) - * method documentation for more information - */ - @Override - public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, - int offset, int length) throws SSLException { - if (engine_was_shutteddown) { - return new SSLEngineResult(SSLEngineResult.Status.CLOSED, - SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0); - } - if ((src == null) || (dsts == null)) { - throw new IllegalStateException( - "Some of the input parameters are null"); - } - - if (!handshake_started) { - beginHandshake(); - } - - SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus(); - // If is is initial handshake or connection closure stage, - // check if this call was made in spite of handshake status - if ((session == null || engine_was_closed) && ( - handshakeStatus.equals( - SSLEngineResult.HandshakeStatus.NEED_WRAP) || - handshakeStatus.equals( - SSLEngineResult.HandshakeStatus.NEED_TASK))) { - return new SSLEngineResult( - getEngineStatus(), handshakeStatus, 0, 0); - } - - if (src.remaining() < recordProtocol.getMinRecordSize()) { - return new SSLEngineResult( - SSLEngineResult.Status.BUFFER_UNDERFLOW, - getHandshakeStatus(), 0, 0); - } - - try { - src.mark(); - // check the destination buffers and count their capacity - int capacity = 0; - for (int i=offset; i<offset+length; i++) { - if (dsts[i] == null) { - throw new IllegalStateException( - "Some of the input parameters are null"); - } - if (dsts[i].isReadOnly()) { - throw new ReadOnlyBufferException(); - } - capacity += dsts[i].remaining(); - } - if (capacity < recordProtocol.getDataSize(src.remaining())) { - return new SSLEngineResult( - SSLEngineResult.Status.BUFFER_OVERFLOW, - getHandshakeStatus(), 0, 0); - } - recProtIS.setSourceBuffer(src); - // unwrap the record contained in source buffer, pass it - // to appropriate client protocol (alert, handshake, or app) - // and retrieve the type of unwrapped data - int type = recordProtocol.unwrap(); - // process the data and return the result - switch (type) { - case ContentType.HANDSHAKE: - case ContentType.CHANGE_CIPHER_SPEC: - if (handshakeProtocol.getStatus().equals( - SSLEngineResult.HandshakeStatus.FINISHED)) { - session = recordProtocol.getSession(); - } - break; - case ContentType.APPLICATION_DATA: - break; - case ContentType.ALERT: - if (alertProtocol.isFatalAlert()) { - alertProtocol.setProcessed(); - if (session != null) { - session.invalidate(); - } - String description = "Fatal alert received " - + alertProtocol.getAlertDescription(); - shutdown(); - throw new SSLException(description); - } else { - if (logger != null) { - logger.println("Warning allert has been received: " - + alertProtocol.getAlertDescription()); - } - switch(alertProtocol.getDescriptionCode()) { - case AlertProtocol.CLOSE_NOTIFY: - alertProtocol.setProcessed(); - close_notify_was_received = true; - if (!close_notify_was_sent) { - closeOutbound(); - closeInbound(); - } else { - closeInbound(); - shutdown(); - } - break; - case AlertProtocol.NO_RENEGOTIATION: - alertProtocol.setProcessed(); - if (session == null) { - // message received during the initial - // handshake - throw new AlertException( - AlertProtocol.HANDSHAKE_FAILURE, - new SSLHandshakeException( - "Received no_renegotiation " - + "during the initial handshake")); - } else { - // just stop the handshake - handshakeProtocol.stop(); - } - break; - default: - alertProtocol.setProcessed(); - } - } - break; - } - return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), - recProtIS.consumed(), - // place the app. data (if any) into the dest. buffers - // and get the number of produced bytes: - appData.placeTo(dsts, offset, length)); - } catch (BufferUnderflowException e) { - // there was not enought data ource buffer to make complete packet - src.reset(); - return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, - getHandshakeStatus(), 0, 0); - } catch (AlertException e) { - // fatal alert occured - alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode()); - engine_was_closed = true; - src.reset(); - if (session != null) { - session.invalidate(); - } - // shutdown work will be made after the alert will be sent - // to another peer (by wrap method) - throw e.getReason(); - } catch (SSLException e) { - throw e; - } catch (IOException e) { - alertProtocol.alert(AlertProtocol.FATAL, - AlertProtocol.INTERNAL_ERROR); - engine_was_closed = true; - // shutdown work will be made after the alert will be sent - // to another peer (by wrap method) - throw new SSLException(e.getMessage()); - } - } - - /** - * Encodes the application data into SSL/TLS record. If handshake status - * of the engine differs from NOT_HANDSHAKING the operation can work - * without consuming of the source data. - * For more information about TLS record fragmentation see - * TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2. - * @param srcs the source buffers with application data to be encoded - * into SSL/TLS record. - * @param offset the offset in the destination buffers array pointing to - * the first buffer with the source data. - * @param len specifies the maximum number of buffers to be procesed. - * @param dst the destination buffer where encoded data will be placed. - * @see javax.net.ssl.SSLEngine#wrap(ByteBuffer[],int,int,ByteBuffer) method - * documentation for more information - */ - @Override - public SSLEngineResult wrap(ByteBuffer[] srcs, int offset, - int len, ByteBuffer dst) throws SSLException { - if (engine_was_shutteddown) { - return new SSLEngineResult(SSLEngineResult.Status.CLOSED, - SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0); - } - if ((srcs == null) || (dst == null)) { - throw new IllegalStateException( - "Some of the input parameters are null"); - } - if (dst.isReadOnly()) { - throw new ReadOnlyBufferException(); - } - - if (!handshake_started) { - beginHandshake(); - } - - SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus(); - // If it is an initial handshake or connection closure stage, - // check if this call was made in spite of handshake status - if ((session == null || engine_was_closed) && ( - handshakeStatus.equals( - SSLEngineResult.HandshakeStatus.NEED_UNWRAP) || - handshakeStatus.equals( - SSLEngineResult.HandshakeStatus.NEED_TASK))) { - return new SSLEngineResult( - getEngineStatus(), handshakeStatus, 0, 0); - } - - int capacity = dst.remaining(); - int produced = 0; - - if (alertProtocol.hasAlert()) { - // we have an alert to be sent - if (capacity < recordProtocol.getRecordSize(2)) { - return new SSLEngineResult( - SSLEngineResult.Status.BUFFER_OVERFLOW, - handshakeStatus, 0, 0); - } - byte[] alert_data = alertProtocol.wrap(); - // place the alert record into destination - dst.put(alert_data); - if (alertProtocol.isFatalAlert()) { - alertProtocol.setProcessed(); - if (session != null) { - session.invalidate(); - } - // fatal alert has been sent, so shut down the engine - shutdown(); - return new SSLEngineResult( - SSLEngineResult.Status.CLOSED, - SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, - 0, alert_data.length); - } else { - alertProtocol.setProcessed(); - // check if the works on this engine have been done - if (close_notify_was_sent && close_notify_was_received) { - shutdown(); - return new SSLEngineResult(SSLEngineResult.Status.CLOSED, - SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, - 0, alert_data.length); - } - return new SSLEngineResult( - getEngineStatus(), - getHandshakeStatus(), - 0, alert_data.length); - } - } - - if (capacity < recordProtocol.getMinRecordSize()) { - if (logger != null) { - logger.println("Capacity of the destination(" - +capacity+") < MIN_PACKET_SIZE(" - +recordProtocol.getMinRecordSize()+")"); - } - return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, - handshakeStatus, 0, 0); - } - - try { - if (!handshakeStatus.equals( - SSLEngineResult.HandshakeStatus.NEED_WRAP)) { - // so we wraps application data - dataStream.setSourceBuffers(srcs, offset, len); - if ((capacity < SSLRecordProtocol.MAX_SSL_PACKET_SIZE) && - (capacity < recordProtocol.getRecordSize( - dataStream.available()))) { - if (logger != null) { - logger.println("The destination buffer(" - +capacity+") can not take the resulting packet(" - + recordProtocol.getRecordSize( - dataStream.available())+")"); - } - return new SSLEngineResult( - SSLEngineResult.Status.BUFFER_OVERFLOW, - handshakeStatus, 0, 0); - } - if (remaining_wrapped_data == null) { - remaining_wrapped_data = - recordProtocol.wrap(ContentType.APPLICATION_DATA, - dataStream); - } - if (capacity < remaining_wrapped_data.length) { - // It should newer happen because we checked the destination - // buffer size, but there is a possibility - // (if dest buffer was filled outside) - // so we just remember the data into remaining_wrapped_data - // and will enclose it during the the next call - return new SSLEngineResult( - SSLEngineResult.Status.BUFFER_OVERFLOW, - handshakeStatus, dataStream.consumed(), 0); - } else { - dst.put(remaining_wrapped_data); - produced = remaining_wrapped_data.length; - remaining_wrapped_data = null; - return new SSLEngineResult(getEngineStatus(), - handshakeStatus, dataStream.consumed(), produced); - } - } else { - if (remaining_hsh_data == null) { - remaining_hsh_data = handshakeProtocol.wrap(); - } - if (capacity < remaining_hsh_data.length) { - // It should newer happen because we checked the destination - // buffer size, but there is a possibility - // (if dest buffer was filled outside) - // so we just remember the data into remaining_hsh_data - // and will enclose it during the the next call - return new SSLEngineResult( - SSLEngineResult.Status.BUFFER_OVERFLOW, - handshakeStatus, 0, 0); - } else { - dst.put(remaining_hsh_data); - produced = remaining_hsh_data.length; - remaining_hsh_data = null; - - handshakeStatus = handshakeProtocol.getStatus(); - if (handshakeStatus.equals( - SSLEngineResult.HandshakeStatus.FINISHED)) { - session = recordProtocol.getSession(); - } - } - return new SSLEngineResult( - getEngineStatus(), getHandshakeStatus(), 0, produced); - } - } catch (AlertException e) { - // fatal alert occured - alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode()); - engine_was_closed = true; - if (session != null) { - session.invalidate(); - } - // shutdown work will be made after the alert will be sent - // to another peer (by wrap method) - throw e.getReason(); - } - } - - // Shutdownes the engine and makes all cleanup work. - private void shutdown() { - engine_was_closed = true; - engine_was_shutteddown = true; - isOutboundDone = true; - isInboundDone = true; - if (handshake_started) { - alertProtocol.shutdown(); - alertProtocol = null; - handshakeProtocol.shutdown(); - handshakeProtocol = null; - recordProtocol.shutdown(); - recordProtocol = null; - } - } - - - private SSLEngineResult.Status getEngineStatus() { - return (engine_was_closed) - ? SSLEngineResult.Status.CLOSED - : SSLEngineResult.Status.OK; - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLInputStream.java b/crypto/src/main/java/org/conscrypt/SSLInputStream.java deleted file mode 100644 index c8a5eca..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLInputStream.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This class is a base for all input stream classes used - * in protocol implementation. It extends an InputStream with - * some additional read methods allowing to read TLS specific - * data types such as uint8, uint32 etc (see TLS v 1 specification - * at http://www.ietf.org/rfc/rfc2246.txt). - */ -public abstract class SSLInputStream extends InputStream { - - @Override - public abstract int available() throws IOException; - - /** - * Reads the following byte value. Note that in the case of - * reaching of the end of the data this methods throws the - * exception, not return -1. The type of exception depends - * on implementation. It was done for simplifying and speeding - * up of processing of such cases. - * @see org.conscrypt.SSLStreamedInput#read() - * @see org.conscrypt.SSLBufferedInput#read() - * @see org.conscrypt.HandshakeIODataStream#read() - */ - @Override - public abstract int read() throws IOException; - - /** - * Reads and returns uint8 value. - */ - public int readUint8() throws IOException { - return read() & 0x00FF; - } - - /** - * Reads and returns uint16 value. - */ - public int readUint16() throws IOException { - return (read() << 8) | (read() & 0x00FF); - } - - /** - * Reads and returns uint24 value. - */ - public int readUint24() throws IOException { - return (read() << 16) | (read() << 8) | (read() & 0x00FF); - } - - /** - * Reads and returns uint32 value. - */ - public long readUint32() throws IOException { - return (read() << 24) | (read() << 16) - | (read() << 8) | (read() & 0x00FF); - } - - /** - * Reads and returns uint64 value. - */ - public long readUint64() throws IOException { - long hi = readUint32(); - long lo = readUint32(); - return (hi << 32) | lo; - } - - /** - * Returns the vector of opaque values of specified length; - * @param length - the length of the vector to be read. - * @return the read data - * @throws IOException if read operation could not be finished. - */ - public byte[] read(int length) throws IOException { - byte[] res = new byte[length]; - for (int i=0; i<length; i++) { - res[i] = (byte) read(); - } - return res; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - int read_b; - int i = 0; - do { - if ((read_b = read()) == -1) { - return (i == 0) ? -1 : i; - } - b[off+i] = (byte) read_b; - i++; - } while ((available() != 0) && (i<len)); - return i; - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLParametersImpl.java b/crypto/src/main/java/org/conscrypt/SSLParametersImpl.java deleted file mode 100644 index 21b8ae2..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLParametersImpl.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.UnrecoverableKeyException; -import java.util.Arrays; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509KeyManager; -import javax.net.ssl.X509TrustManager; - -/** - * The instances of this class encapsulate all the info - * about enabled cipher suites and protocols, - * as well as the information about client/server mode of - * ssl socket, whether it require/want client authentication or not, - * and controls whether new SSL sessions may be established by this - * socket or not. - */ -public class SSLParametersImpl implements Cloneable { - - // default source of authentication keys - private static volatile X509KeyManager defaultKeyManager; - // default source of authentication trust decisions - private static volatile X509TrustManager defaultTrustManager; - // default source of random numbers - private static volatile SecureRandom defaultSecureRandom; - // default SSL parameters - private static volatile SSLParametersImpl defaultParameters; - - // client session context contains the set of reusable - // client-side SSL sessions - private final ClientSessionContext clientSessionContext; - // server session context contains the set of reusable - // server-side SSL sessions - private final ServerSessionContext serverSessionContext; - // source of authentication keys - private X509KeyManager keyManager; - // source of authentication trust decisions - private X509TrustManager trustManager; - // source of random numbers - private SecureRandom secureRandom; - - // cipher suites available for SSL connection - private CipherSuite[] enabledCipherSuites; - // string representations of available cipher suites - private String[] enabledCipherSuiteNames = null; - - // protocols available for SSL connection - private String[] enabledProtocols = ProtocolVersion.supportedProtocols; - - // if the peer with this parameters tuned to work in client mode - private boolean client_mode = true; - // if the peer with this parameters tuned to require client authentication - private boolean need_client_auth = false; - // if the peer with this parameters tuned to request client authentication - private boolean want_client_auth = false; - // if the peer with this parameters allowed to cteate new SSL session - private boolean enable_session_creation = true; - - protected CipherSuite[] getEnabledCipherSuitesMember() { - if (enabledCipherSuites == null) { - this.enabledCipherSuites = CipherSuite.DEFAULT_CIPHER_SUITES; - } - return enabledCipherSuites; - } - - /** - * Initializes the parameters. Naturally this constructor is used - * in SSLContextImpl.engineInit method which directly passes its - * parameters. In other words this constructor holds all - * the functionality provided by SSLContext.init method. - * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[], - * SecureRandom)} for more information - */ - protected SSLParametersImpl(KeyManager[] kms, TrustManager[] tms, - SecureRandom sr, ClientSessionContext clientSessionContext, - ServerSessionContext serverSessionContext) - throws KeyManagementException { - this.serverSessionContext = serverSessionContext; - this.clientSessionContext = clientSessionContext; - - // It's not described by the spec of SSLContext what should happen - // if the arrays of length 0 are specified. This implementation - // behave as for null arrays (i.e. use installed security providers) - - // initialize keyManager - if ((kms == null) || (kms.length == 0)) { - keyManager = getDefaultKeyManager(); - } else { - keyManager = findX509KeyManager(kms); - } - - // initialize trustManager - if ((tms == null) || (tms.length == 0)) { - trustManager = getDefaultTrustManager(); - } else { - trustManager = findX509TrustManager(tms); - } - // initialize secure random - // BEGIN android-removed - // if (sr == null) { - // if (defaultSecureRandom == null) { - // defaultSecureRandom = new SecureRandom(); - // } - // secureRandom = defaultSecureRandom; - // } else { - // secureRandom = sr; - // } - // END android-removed - // BEGIN android-added - // We simply use the SecureRandom passed in by the caller. If it's - // null, we don't replace it by a new instance. The native code below - // then directly accesses /dev/urandom. Not the most elegant solution, - // but faster than going through the SecureRandom object. - secureRandom = sr; - // END android-added - } - - protected static SSLParametersImpl getDefault() throws KeyManagementException { - SSLParametersImpl result = defaultParameters; - if (result == null) { - // single-check idiom - defaultParameters = result = new SSLParametersImpl(null, - null, - null, - new ClientSessionContext(), - new ServerSessionContext()); - } - return (SSLParametersImpl) result.clone(); - } - - /** - * @return server session context - */ - protected ServerSessionContext getServerSessionContext() { - return serverSessionContext; - } - - /** - * @return client session context - */ - protected ClientSessionContext getClientSessionContext() { - return clientSessionContext; - } - - /** - * @return key manager - */ - protected X509KeyManager getKeyManager() { - return keyManager; - } - - /** - * @return trust manager - */ - protected X509TrustManager getTrustManager() { - return trustManager; - } - - /** - * @return secure random - */ - protected SecureRandom getSecureRandom() { - if (secureRandom != null) { - return secureRandom; - } - SecureRandom result = defaultSecureRandom; - if (result == null) { - // single-check idiom - defaultSecureRandom = result = new SecureRandom(); - } - secureRandom = result; - return secureRandom; - } - - /** - * @return the secure random member reference, even it is null - */ - protected SecureRandom getSecureRandomMember() { - return secureRandom; - } - - /** - * @return the names of enabled cipher suites - */ - protected String[] getEnabledCipherSuites() { - if (enabledCipherSuiteNames == null) { - CipherSuite[] enabledCipherSuites = getEnabledCipherSuitesMember(); - enabledCipherSuiteNames = new String[enabledCipherSuites.length]; - for (int i = 0; i< enabledCipherSuites.length; i++) { - enabledCipherSuiteNames[i] = enabledCipherSuites[i].getName(); - } - } - return enabledCipherSuiteNames.clone(); - } - - /** - * Sets the set of available cipher suites for use in SSL connection. - * @param suites: String[] - * @return - */ - protected void setEnabledCipherSuites(String[] suites) { - if (suites == null) { - throw new IllegalArgumentException("suites == null"); - } - CipherSuite[] cipherSuites = new CipherSuite[suites.length]; - for (int i=0; i<suites.length; i++) { - String suite = suites[i]; - if (suite == null) { - throw new IllegalArgumentException("suites[" + i + "] == null"); - } - cipherSuites[i] = CipherSuite.getByName(suite); - if (cipherSuites[i] == null || !cipherSuites[i].supported) { - throw new IllegalArgumentException(suite + " is not supported."); - } - } - enabledCipherSuites = cipherSuites; - enabledCipherSuiteNames = suites; - } - - /** - * @return the set of enabled protocols - */ - protected String[] getEnabledProtocols() { - return enabledProtocols.clone(); - } - - /** - * Sets the set of available protocols for use in SSL connection. - * @param protocols String[] - */ - protected void setEnabledProtocols(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 (!ProtocolVersion.isSupported(protocol)) { - throw new IllegalArgumentException("Protocol " + protocol + " is not supported."); - } - } - enabledProtocols = protocols; - } - - /** - * Tunes the peer holding this parameters to work in client mode. - * @param mode if the peer is configured to work in client mode - */ - protected void setUseClientMode(boolean mode) { - client_mode = mode; - } - - /** - * Returns the value indicating if the parameters configured to work - * in client mode. - */ - protected boolean getUseClientMode() { - return client_mode; - } - - /** - * Tunes the peer holding this parameters to require client authentication - */ - protected void setNeedClientAuth(boolean need) { - need_client_auth = need; - // reset the want_client_auth setting - want_client_auth = false; - } - - /** - * Returns the value indicating if the peer with this parameters tuned - * to require client authentication - */ - protected boolean getNeedClientAuth() { - return need_client_auth; - } - - /** - * Tunes the peer holding this parameters to request client authentication - */ - protected void setWantClientAuth(boolean want) { - want_client_auth = want; - // reset the need_client_auth setting - need_client_auth = false; - } - - /** - * Returns the value indicating if the peer with this parameters - * tuned to request client authentication - * @return - */ - protected boolean getWantClientAuth() { - return want_client_auth; - } - - /** - * Allows/disallows the peer holding this parameters to - * create new SSL session - */ - protected void setEnableSessionCreation(boolean flag) { - enable_session_creation = flag; - } - - /** - * Returns the value indicating if the peer with this parameters - * allowed to cteate new SSL session - */ - protected boolean getEnableSessionCreation() { - return enable_session_creation; - } - - /** - * Returns the clone of this object. - * @return the clone. - */ - @Override - protected Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(e); - } - } - - private static X509KeyManager getDefaultKeyManager() throws KeyManagementException { - X509KeyManager result = defaultKeyManager; - if (result == null) { - // single-check idiom - defaultKeyManager = result = createDefaultKeyManager(); - } - return result; - } - private static X509KeyManager createDefaultKeyManager() throws KeyManagementException { - try { - String algorithm = KeyManagerFactory.getDefaultAlgorithm(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); - kmf.init(null, null); - KeyManager[] kms = kmf.getKeyManagers(); - return findX509KeyManager(kms); - } catch (NoSuchAlgorithmException e) { - throw new KeyManagementException(e); - } catch (KeyStoreException e) { - throw new KeyManagementException(e); - } catch (UnrecoverableKeyException e) { - throw new KeyManagementException(e); - } - } - private static X509KeyManager findX509KeyManager(KeyManager[] kms) throws KeyManagementException { - for (KeyManager km : kms) { - if (km instanceof X509KeyManager) { - return (X509KeyManager)km; - } - } - throw new KeyManagementException("Failed to find an X509KeyManager in " + Arrays.toString(kms)); - } - - /** - * Gets the default trust manager. - * - * TODO: Move this to a published API under dalvik.system. - */ - public static X509TrustManager getDefaultTrustManager() throws KeyManagementException { - X509TrustManager result = defaultTrustManager; - if (result == null) { - // single-check idiom - defaultTrustManager = result = createDefaultTrustManager(); - } - return result; - } - private static X509TrustManager createDefaultTrustManager() throws KeyManagementException { - try { - String algorithm = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); - tmf.init((KeyStore) null); - TrustManager[] tms = tmf.getTrustManagers(); - X509TrustManager trustManager = findX509TrustManager(tms); - return trustManager; - } catch (NoSuchAlgorithmException e) { - throw new KeyManagementException(e); - } catch (KeyStoreException e) { - throw new KeyManagementException(e); - } - } - private static X509TrustManager findX509TrustManager(TrustManager[] tms) throws KeyManagementException { - for (TrustManager tm : tms) { - if (tm instanceof X509TrustManager) { - return (X509TrustManager)tm; - } - } - throw new KeyManagementException("Failed to find an X509TrustManager in " + Arrays.toString(tms)); - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLRecordProtocol.java b/crypto/src/main/java/org/conscrypt/SSLRecordProtocol.java deleted file mode 100644 index 24b6c61..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLRecordProtocol.java +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import javax.net.ssl.SSLProtocolException; - -/** - * This class performs functionality dedicated to SSL record layer. - * It unpacks and routes income data to the appropriate - * client protocol (handshake, alert, application data protocols) - * and packages outcome data into SSL/TLS records. - * Initially created object has null connection state and does not - * perform any cryptography computations over the income/outcome data. - * After handshake protocol agreed upon security parameters they are placed - * into SSLSessionImpl object and available for record protocol as - * pending session. The order of setting up of the pending session - * as an active session differs for client and server modes. - * So for client mode the parameters are provided by handshake protocol - * during retrieving of change_cipher_spec message to be sent (by calling of - * getChangeCipherSpecMesage method). - * For server side mode record protocol retrieves the parameters from - * handshake protocol after receiving of client's change_cipher_spec message. - * After the pending session has been set up as a current session, - * new connection state object is created and used for encryption/decryption - * of the messages. - * Among with base functionality this class provides the information about - * constrains on the data length, and information about correspondence - * of plain and encrypted data lengths. - * For more information on TLS v1 see http://www.ietf.org/rfc/rfc2246.txt, - * on SSL v3 see http://wp.netscape.com/eng/ssl3, - * on SSL v2 see http://wp.netscape.com/eng/security/SSL_2.html. - */ -public class SSLRecordProtocol { - - /** - * Maximum length of allowed plain data fragment - * as specified by TLS specification. - */ - protected static final int MAX_DATA_LENGTH = 16384; // 2^14 - /** - * Maximum length of allowed compressed data fragment - * as specified by TLS specification. - */ - protected static final int MAX_COMPRESSED_DATA_LENGTH - = MAX_DATA_LENGTH + 1024; - /** - * Maximum length of allowed ciphered data fragment - * as specified by TLS specification. - */ - protected static final int MAX_CIPHERED_DATA_LENGTH - = MAX_COMPRESSED_DATA_LENGTH + 1024; - /** - * Maximum length of ssl record. It is counted as: - * type(1) + version(2) + length(2) + MAX_CIPHERED_DATA_LENGTH - */ - protected static final int MAX_SSL_PACKET_SIZE - = MAX_CIPHERED_DATA_LENGTH + 5; - // the SSL session used for connection - private SSLSessionImpl session; - // protocol version of the connection - private byte[] version; - // input stream of record protocol - private SSLInputStream in; - // handshake protocol object to which handshaking data will be transmitted - private HandshakeProtocol handshakeProtocol; - // alert protocol to indicate alerts occurred/received - private AlertProtocol alertProtocol; - // application data object to which application data will be transmitted - private Appendable appData; - // connection state holding object - private ConnectionState - activeReadState, activeWriteState, pendingConnectionState; - - // logger - private Logger.Stream logger = Logger.getStream("record"); - - // flag indicating if session object has been changed after - // handshake phase (to distinguish session pending state) - private boolean sessionWasChanged = false; - - // change cipher spec message content - private static final byte[] change_cipher_spec_byte = new byte[] {1}; - - /** - * Creates an instance of record protocol and tunes - * up the client protocols to use ut. - * @param handshakeProtocol: HandshakeProtocol - * @param alertProtocol: AlertProtocol - * @param in: SSLInputStream - * @param appData: Appendable - */ - protected SSLRecordProtocol(HandshakeProtocol handshakeProtocol, - AlertProtocol alertProtocol, - SSLInputStream in, - Appendable appData) { - this.handshakeProtocol = handshakeProtocol; - this.handshakeProtocol.setRecordProtocol(this); - this.alertProtocol = alertProtocol; - this.alertProtocol.setRecordProtocol(this); - this.in = in; - this.appData = appData; - } - - /** - * Returns the session obtained during the handshake negotiation. - * If the handshake process was not completed, method returns null. - * @return the session in effect. - */ - protected SSLSessionImpl getSession() { - return session; - } - - /** - * Returns the minimum possible length of the SSL record. - * @return - */ - protected int getMinRecordSize() { - return (activeReadState == null) - ? 6 // type + version + length + 1 byte of data - : 5 + activeReadState.getMinFragmentSize(); - } - - /** - * Returns the record length for the specified incoming data length. - * If actual resulting record length is greater than - * MAX_CIPHERED_DATA_LENGTH, MAX_CIPHERED_DATA_LENGTH is returned. - */ - protected int getRecordSize(int data_size) { - if (activeWriteState == null) { - return 5+data_size; // type + version + length + data_size - } else { - int res = 5 + activeWriteState.getFragmentSize(data_size); - return (res > MAX_CIPHERED_DATA_LENGTH) - ? MAX_CIPHERED_DATA_LENGTH // so the source data should be - // split into several packets - : res; - } - } - - /** - * Returns the upper bound of length of data containing in the record with - * specified length. - * If the provided record_size is greater or equal to - * MAX_CIPHERED_DATA_LENGTH the returned value will be - * MAX_DATA_LENGTH - * counted as for data with - * MAX_CIPHERED_DATA_LENGTH length. - */ - protected int getDataSize(int record_size) { - record_size -= 5; // - (type + version + length + data_size) - if (record_size > MAX_CIPHERED_DATA_LENGTH) { - // the data of such size consists of the several packets - return MAX_DATA_LENGTH; - } - if (activeReadState == null) { - return record_size; - } - return activeReadState.getContentSize(record_size); - } - - /** - * Depending on the Connection State (Session) encrypts and compress - * the provided data, and packs it into TLSCiphertext structure. - * @param content_type: int - * @return ssl packet created over the current connection state - */ - protected byte[] wrap(byte content_type, DataStream dataStream) { - byte[] fragment = dataStream.getData(MAX_DATA_LENGTH); - return wrap(content_type, fragment, 0, fragment.length); - } - - /** - * Depending on the Connection State (Session) encrypts and compress - * the provided data, and packs it into TLSCiphertext structure. - * @param content_type: int - * @param fragment: byte[] - * @return ssl packet created over the current connection state - */ - protected byte[] wrap(byte content_type, - byte[] fragment, int offset, int len) { - if (logger != null) { - logger.println("SSLRecordProtocol.wrap: TLSPlaintext.fragment[" - +len+"]:"); - logger.print(fragment, offset, len); - } - if (len > MAX_DATA_LENGTH) { - throw new AlertException( - AlertProtocol.INTERNAL_ERROR, - new SSLProtocolException( - "The provided chunk of data is too big: " + len - + " > MAX_DATA_LENGTH == "+MAX_DATA_LENGTH)); - } - byte[] ciphered_fragment = fragment; - if (activeWriteState != null) { - ciphered_fragment = - activeWriteState.encrypt(content_type, fragment, offset, len); - if (ciphered_fragment.length > MAX_CIPHERED_DATA_LENGTH) { - throw new AlertException( - AlertProtocol.INTERNAL_ERROR, - new SSLProtocolException( - "The ciphered data increased more than on 1024 bytes")); - } - if (logger != null) { - logger.println("SSLRecordProtocol.wrap: TLSCiphertext.fragment[" - +ciphered_fragment.length+"]:"); - logger.print(ciphered_fragment); - } - } - return packetize(content_type, version, ciphered_fragment); - } - - private byte[] packetize(byte type, byte[] version, byte[] fragment) { - byte[] buff = new byte[5+fragment.length]; - buff[0] = type; - if (version != null) { - buff[1] = version[0]; - buff[2] = version[1]; - } else { - buff[1] = 3; - buff[2] = 1; - } - buff[3] = (byte) ((0x00FF00 & fragment.length) >> 8); - buff[4] = (byte) (0x0000FF & fragment.length); - System.arraycopy(fragment, 0, buff, 5, fragment.length); - return buff; - } - - /** - * Set the ssl session to be used after sending the changeCipherSpec message - * @param session: SSLSessionImpl - */ - private void setSession(SSLSessionImpl session) { - if (!sessionWasChanged) { - // session was not changed for current handshake process - if (logger != null) { - logger.println("SSLRecordProtocol.setSession: Set pending session"); - logger.println(" cipher name: " + session.getCipherSuite()); - } - this.session = session; - // create new connection state - pendingConnectionState = ((version == null) || (version[1] == 1)) - ? (ConnectionState) new ConnectionStateTLS(getSession()) - : (ConnectionState) new ConnectionStateSSLv3(getSession()); - sessionWasChanged = true; - } else { - // wait for rehandshaking's session - sessionWasChanged = false; - } - } - - /** - * Returns the change cipher spec message to be sent to another peer. - * The pending connection state will be built on the base of provided - * session object - * The calling of this method triggers pending write connection state to - * be active. - * @return ssl record containing the "change cipher spec" message. - */ - protected byte[] getChangeCipherSpecMesage(SSLSessionImpl session) { - // make change_cipher_spec_message: - byte[] change_cipher_spec_message; - if (activeWriteState == null) { - change_cipher_spec_message = new byte[] { - ContentType.CHANGE_CIPHER_SPEC, version[0], - version[1], 0, 1, 1 - }; - } else { - change_cipher_spec_message = - packetize(ContentType.CHANGE_CIPHER_SPEC, version, - activeWriteState.encrypt(ContentType.CHANGE_CIPHER_SPEC, - change_cipher_spec_byte, 0, 1)); - } - setSession(session); - activeWriteState = pendingConnectionState; - if (logger != null) { - logger.println("SSLRecordProtocol.getChangeCipherSpecMesage"); - logger.println("activeWriteState = pendingConnectionState"); - logger.print(change_cipher_spec_message); - } - return change_cipher_spec_message; - } - - /** - * Retrieves the fragment field of TLSCiphertext, and than - * depending on the established Connection State - * decrypts and decompresses it. The following structure is expected - * on the input at the moment of the call: - * - * struct { - * ContentType type; - * ProtocolVersion version; - * uint16 length; - * select (CipherSpec.cipher_type) { - * case stream: GenericStreamCipher; - * case block: GenericBlockCipher; - * } fragment; - * } TLSCiphertext; - * - * (as specified by RFC 2246, TLS v1 Protocol specification) - * - * In addition this method can recognize SSLv2 hello message which - * are often used to establish the SSL/TLS session. - * - * @throws IOException if some io errors have been occurred - * @throws EndOfSourceException if underlying input stream - * has ran out of data. - * @throws EndOfBufferException if there was not enough data - * to build complete ssl packet. - * @return the type of unwrapped message. - */ - protected int unwrap() throws IOException { - if (logger != null) { - logger.println("SSLRecordProtocol.unwrap: BEGIN ["); - } - int type = in.readUint8(); - if ((type < ContentType.CHANGE_CIPHER_SPEC) - || (type > ContentType.APPLICATION_DATA)) { - if (logger != null) { - logger.println("Non v3.1 message type:" + type); - } - if (type >= 0x80) { - // it is probably SSL v2 client_hello message - // (see SSL v2 spec at: - // http://wp.netscape.com/eng/security/SSL_2.html) - int length = (type & 0x7f) << 8 | in.read(); - byte[] fragment = in.read(length); - handshakeProtocol.unwrapSSLv2(fragment); - if (logger != null) { - logger.println( - "SSLRecordProtocol:unwrap ] END, SSLv2 type"); - } - return ContentType.HANDSHAKE; - } - throw new AlertException(AlertProtocol.UNEXPECTED_MESSAGE, - new SSLProtocolException( - "Unexpected message type has been received: "+type)); - } - if (logger != null) { - logger.println("Got the message of type: " + type); - } - if (version != null) { - if ((in.read() != version[0]) - || (in.read() != version[1])) { - throw new AlertException(AlertProtocol.UNEXPECTED_MESSAGE, - new SSLProtocolException( - "Unexpected message type has been received: " + - type)); - } - } else { - in.skip(2); // just skip the version number - } - int length = in.readUint16(); - if (logger != null) { - logger.println("TLSCiphertext.fragment["+length+"]: ..."); - } - if (length > MAX_CIPHERED_DATA_LENGTH) { - throw new AlertException(AlertProtocol.RECORD_OVERFLOW, - new SSLProtocolException( - "Received message is too big.")); - } - byte[] fragment = in.read(length); - if (logger != null) { - logger.print(fragment); - } - if (activeReadState != null) { - fragment = activeReadState.decrypt((byte) type, fragment); - if (logger != null) { - logger.println("TLSPlaintext.fragment:"); - logger.print(fragment); - } - } - if (fragment.length > MAX_DATA_LENGTH) { - throw new AlertException(AlertProtocol.DECOMPRESSION_FAILURE, - new SSLProtocolException( - "Decompressed plain data is too big.")); - } - switch (type) { - case ContentType.CHANGE_CIPHER_SPEC: - // notify handshake protocol: - handshakeProtocol.receiveChangeCipherSpec(); - setSession(handshakeProtocol.getSession()); - // change cipher spec message has been received, so: - if (logger != null) { - logger.println("activeReadState = pendingConnectionState"); - } - activeReadState = pendingConnectionState; - break; - case ContentType.ALERT: - alert(fragment[0], fragment[1]); - break; - case ContentType.HANDSHAKE: - handshakeProtocol.unwrap(fragment); - break; - case ContentType.APPLICATION_DATA: - if (logger != null) { - logger.println( - "TLSCiphertext.unwrap: APP DATA["+length+"]:"); - logger.println(new String(fragment)); - } - appData.append(fragment); - break; - default: - throw new AlertException(AlertProtocol.UNEXPECTED_MESSAGE, - new SSLProtocolException( - "Unexpected message type has been received: " + - type)); - } - if (logger != null) { - logger.println("SSLRecordProtocol:unwrap ] END, type: " + type); - } - return type; - } - - /** - * Passes the alert information to the alert protocol. - * @param level: byte - * @param description: byte - */ - protected void alert(byte level, byte description) { - if (logger != null) { - logger.println("SSLRecordProtocol.allert: "+level+" "+description); - } - alertProtocol.alert(level, description); - } - - /** - * Sets up the SSL version used in this connection. - * This method is calling from the handshake protocol after - * it becomes known which protocol version will be used. - * @param ver: byte[] - * @return - */ - protected void setVersion(byte[] ver) { - this.version = ver; - } - - /** - * Shuts down the protocol. It will be impossible to use the instance - * after the calling of this method. - */ - protected void shutdown() { - session = null; - version = null; - in = null; - handshakeProtocol = null; - alertProtocol = null; - appData = null; - if (pendingConnectionState != null) { - pendingConnectionState.shutdown(); - } - pendingConnectionState = null; - if (activeReadState != null) { - activeReadState.shutdown(); - } - activeReadState = null; - if (activeReadState != null) { - activeReadState.shutdown(); - } - activeWriteState = null; - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLServerSessionCache.java b/crypto/src/main/java/org/conscrypt/SSLServerSessionCache.java deleted file mode 100644 index a380ce9..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLServerSessionCache.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import javax.net.ssl.SSLSession; - -/** - * A persistent {@link javax.net.ssl.SSLSession} cache used by - * {@link javax.net.ssl.SSLSessionContext} to share server-side SSL sessions - * across processes. For example, this cache enables one server to resume - * a session started by a different server based on a session ID provided - * by the client. - * - * <p>The {@code SSLSessionContext} implementation converts - * {@code SSLSession}s into raw bytes and vice versa. The exact makeup of the - * session data is dependent upon the caller's implementation and is opaque to - * the {@code SSLServerSessionCache} implementation. - */ -public interface SSLServerSessionCache { - - /** - * Gets the session data for given session ID. - * - * @param id from {@link javax.net.ssl.SSLSession#getId()} - * @return the session data or null if none is cached - * @throws NullPointerException if id is null - */ - public byte[] getSessionData(byte[] id); - - /** - * Stores session data for the given session. - * - * @param session to cache data for - * @param sessionData to cache - * @throws NullPointerException if session or data is null - */ - public void putSessionData(SSLSession session, byte[] sessionData); -}
\ No newline at end of file diff --git a/crypto/src/main/java/org/conscrypt/SSLServerSocketFactoryImpl.java b/crypto/src/main/java/org/conscrypt/SSLServerSocketFactoryImpl.java deleted file mode 100644 index 5b16f85..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLServerSocketFactoryImpl.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.security.KeyManagementException; -import javax.net.ssl.SSLServerSocketFactory; -import org.conscrypt.util.EmptyArray; - -/** - * Implementation of SSLServerSocketFactory. - */ -public class SSLServerSocketFactoryImpl extends SSLServerSocketFactory { - - private SSLParametersImpl sslParameters; - private IOException instantiationException; - - /** - * Constructor. - */ - public SSLServerSocketFactoryImpl() { - try { - this.sslParameters = SSLParametersImpl.getDefault(); - this.sslParameters.setUseClientMode(false); - } catch (KeyManagementException e) { - instantiationException = - new IOException("Delayed instantiation exception:"); - instantiationException.initCause(e); - } - } - - /** - * Constructor. - */ - protected SSLServerSocketFactoryImpl(SSLParametersImpl sslParameters) { - this.sslParameters = (SSLParametersImpl) sslParameters.clone(); - this.sslParameters.setUseClientMode(false); - } - - /** - * @see javax.net.ssl.SSLServerSocketFactory#getDefaultCipherSuites() - */ - @Override - public String[] getDefaultCipherSuites() { - if (instantiationException != null) { - return EmptyArray.STRING; - } - return sslParameters.getEnabledCipherSuites(); - } - - /** - * @see javax.net.ssl.SSLServerSocketFactory#getSupportedCipherSuites() - */ - @Override - public String[] getSupportedCipherSuites() { - if (instantiationException != null) { - return EmptyArray.STRING; - } - return CipherSuite.getSupportedCipherSuiteNames(); - } - - /** - * @see javax.net.ServerSocketFactory#createServerSocket() - */ - @Override - public ServerSocket createServerSocket() throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLServerSocketImpl((SSLParametersImpl) sslParameters.clone()); - } - - - /** - * @see javax.net.ServerSocketFactory#createServerSocket(int) - */ - @Override - public ServerSocket createServerSocket(int port) throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLServerSocketImpl(port, - (SSLParametersImpl) sslParameters.clone()); - } - - /** - * @see javax.net.ServerSocketFactory#createServerSocket(int,int) - */ - @Override - public ServerSocket createServerSocket(int port, int backlog) - throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLServerSocketImpl(port, backlog, - (SSLParametersImpl) sslParameters.clone()); - } - - /** - * @see javax.net.ServerSocketFactory#createServerSocket(int,int,InetAddress) - */ - @Override - public ServerSocket createServerSocket(int port, int backlog, - InetAddress iAddress) throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLServerSocketImpl(port, backlog, iAddress, - (SSLParametersImpl) sslParameters.clone()); - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLServerSocketImpl.java b/crypto/src/main/java/org/conscrypt/SSLServerSocketImpl.java deleted file mode 100644 index a30e3b4..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLServerSocketImpl.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import javax.net.ssl.SSLServerSocket; - -/** - * SSLServerSocket implementation - * @see javax.net.ssl.SSLServerSocket class documentation for more information. - */ -public class SSLServerSocketImpl extends SSLServerSocket { - - // the sslParameters object encapsulates all the info - // about supported and enabled cipher suites and protocols, - // as well as the information about client/server mode of - // ssl socket, whether it require/want client authentication or not, - // and controls whether new SSL sessions may be established by this - // socket or not. - private final SSLParametersImpl sslParameters; - - // logger - private Logger.Stream logger = Logger.getStream("ssocket"); - - /** - * Ctor - * @param sslParameters: SSLParameters - * @throws IOException - */ - protected SSLServerSocketImpl(SSLParametersImpl sslParameters) throws IOException { - this.sslParameters = sslParameters; - } - - /** - * Ctor - * @param port: int - * @param sslParameters: SSLParameters - * @throws IOException - */ - protected SSLServerSocketImpl(int port, SSLParametersImpl sslParameters) - throws IOException { - super(port); - this.sslParameters = sslParameters; - } - - /** - * Ctor - * @param port: int - * @param backlog: int - * @param sslParameters: SSLParameters - * @throws IOException - */ - protected SSLServerSocketImpl(int port, int backlog, - SSLParametersImpl sslParameters) throws IOException { - super(port, backlog); - this.sslParameters = sslParameters; - } - - /** - * Ctor - * @param port: int - * @param backlog: int - * @param iAddress: InetAddress - * @param sslParameters: SSLParameters - * @throws IOException - */ - protected SSLServerSocketImpl(int port, int backlog, - InetAddress iAddress, - SSLParametersImpl sslParameters) - throws IOException { - super(port, backlog, iAddress); - this.sslParameters = sslParameters; - } - - // --------------- SSLParameters based methods --------------------- - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getSupportedCipherSuites() - * method documentation for more information - */ - @Override - public String[] getSupportedCipherSuites() { - return CipherSuite.getSupportedCipherSuiteNames(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getEnabledCipherSuites() - * method documentation for more information - */ - @Override - public String[] getEnabledCipherSuites() { - return sslParameters.getEnabledCipherSuites(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#setEnabledCipherSuites(String[]) - * method documentation for more information - */ - @Override - public void setEnabledCipherSuites(String[] suites) { - sslParameters.setEnabledCipherSuites(suites); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getSupportedProtocols() - * method documentation for more information - */ - @Override - public String[] getSupportedProtocols() { - return ProtocolVersion.supportedProtocols.clone(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getEnabledProtocols() - * method documentation for more information - */ - @Override - public String[] getEnabledProtocols() { - return sslParameters.getEnabledProtocols(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#setEnabledProtocols(String[]) - * method documentation for more information - */ - @Override - public void setEnabledProtocols(String[] protocols) { - sslParameters.setEnabledProtocols(protocols); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#setUseClientMode(boolean) - * method documentation for more information - */ - @Override - public void setUseClientMode(boolean mode) { - sslParameters.setUseClientMode(mode); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getUseClientMode() - * method documentation for more information - */ - @Override - public boolean getUseClientMode() { - return sslParameters.getUseClientMode(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#setNeedClientAuth(boolean) - * method documentation for more information - */ - @Override - public void setNeedClientAuth(boolean need) { - sslParameters.setNeedClientAuth(need); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getNeedClientAuth() - * method documentation for more information - */ - @Override - public boolean getNeedClientAuth() { - return sslParameters.getNeedClientAuth(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#setWantClientAuth(boolean) - * method documentation for more information - */ - @Override - public void setWantClientAuth(boolean want) { - sslParameters.setWantClientAuth(want); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getWantClientAuth() - * method documentation for more information - */ - @Override - public boolean getWantClientAuth() { - return sslParameters.getWantClientAuth(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#setEnableSessionCreation(boolean) - * method documentation for more information - */ - @Override - public void setEnableSessionCreation(boolean flag) { - sslParameters.setEnableSessionCreation(flag); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLServerSocket#getEnableSessionCreation() - * method documentation for more information - */ - @Override - public boolean getEnableSessionCreation() { - return sslParameters.getEnableSessionCreation(); - } - - - // ------------- ServerSocket's methods overridings ---------------- - - /** - * This method works according to the specification of implemented class. - * @see java.net.ServerSocket#accept() - * method documentation for more information - */ - @Override - public Socket accept() throws IOException { - if (logger != null) { - logger.println("SSLServerSocketImpl.accept .."); - } - SSLSocketImpl s = new SSLSocketImpl( - (SSLParametersImpl) sslParameters.clone()); - implAccept(s); - s.init(); - if (logger != null) { - logger.println("SSLServerSocketImpl: accepted, initialized"); - } - return s; - } - - /** - * Returns the string representation of the object. - */ - @Override - public String toString() { - return "[SSLServerSocketImpl]"; - } - - // ----------------------------------------------------------------- -} diff --git a/crypto/src/main/java/org/conscrypt/SSLSessionImpl.java b/crypto/src/main/java/org/conscrypt/SSLSessionImpl.java deleted file mode 100644 index 9631b1e..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLSessionImpl.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.Principal; -import java.security.SecureRandom; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Map; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionBindingEvent; -import javax.net.ssl.SSLSessionBindingListener; -import javax.net.ssl.SSLSessionContext; -import org.conscrypt.util.EmptyArray; - -public final class SSLSessionImpl implements SSLSession, Cloneable { - - /* - * Holds default instances so class preloading doesn't create an instance of - * it. - */ - private static class DefaultHolder { - public static final SSLSessionImpl NULL_SESSION = new SSLSessionImpl(null); - } - - private long creationTime; - private boolean isValid = true; - private final Map<String, Object> values = new HashMap<String, Object>(); - - byte[] id; - long lastAccessedTime; - ProtocolVersion protocol; - CipherSuite cipherSuite; - SSLSessionContext context; - X509Certificate[] localCertificates; - X509Certificate[] peerCertificates; - private String peerHost; - private int peerPort = -1; - byte[] master_secret; - byte[] clientRandom; - byte[] serverRandom; - final boolean isServer; - - public static SSLSessionImpl getNullSession() { - return DefaultHolder.NULL_SESSION; - } - - public SSLSessionImpl(CipherSuite cipher_suite, SecureRandom secureRandom) { - creationTime = System.currentTimeMillis(); - lastAccessedTime = creationTime; - if (cipher_suite == null) { - this.cipherSuite = CipherSuite.SSL_NULL_WITH_NULL_NULL; - id = EmptyArray.BYTE; - isServer = false; - isValid = false; - } else { - this.cipherSuite = cipher_suite; - id = new byte[32]; - secureRandom.nextBytes(id); - long time = creationTime / 1000; - id[28] = (byte) ((time & 0xFF000000) >>> 24); - id[29] = (byte) ((time & 0x00FF0000) >>> 16); - id[30] = (byte) ((time & 0x0000FF00) >>> 8); - id[31] = (byte) ((time & 0x000000FF)); - isServer = true; - } - - } - - public SSLSessionImpl(SecureRandom secureRandom) { - this(null, secureRandom); - } - - public int getApplicationBufferSize() { - return SSLRecordProtocol.MAX_DATA_LENGTH; - } - - public String getCipherSuite() { - return cipherSuite.getName(); - } - - public long getCreationTime() { - return creationTime; - } - - public byte[] getId() { - return id; - } - - public long getLastAccessedTime() { - return lastAccessedTime; - } - - public Certificate[] getLocalCertificates() { - return localCertificates; - } - - public Principal getLocalPrincipal() { - if (localCertificates != null && localCertificates.length > 0) { - return localCertificates[0].getSubjectX500Principal(); - } - return null; - } - - public int getPacketBufferSize() { - return SSLRecordProtocol.MAX_SSL_PACKET_SIZE; - } - - public javax.security.cert.X509Certificate[] getPeerCertificateChain() - throws SSLPeerUnverifiedException { - if (peerCertificates == null) { - throw new SSLPeerUnverifiedException("No peer certificate"); - } - javax.security.cert.X509Certificate[] certs = new javax.security.cert.X509Certificate[peerCertificates.length]; - for (int i = 0; i < certs.length; i++) { - try { - certs[i] = javax.security.cert.X509Certificate.getInstance(peerCertificates[i] - .getEncoded()); - } catch (javax.security.cert.CertificateException ignored) { - } catch (CertificateEncodingException ignored) { - } - } - return certs; - } - - public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { - if (peerCertificates == null) { - throw new SSLPeerUnverifiedException("No peer certificate"); - } - return peerCertificates; - } - - public String getPeerHost() { - return peerHost; - } - - public int getPeerPort() { - return peerPort; - } - - public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { - if (peerCertificates == null) { - throw new SSLPeerUnverifiedException("No peer certificate"); - } - return peerCertificates[0].getSubjectX500Principal(); - } - - public String getProtocol() { - return (protocol == null) ? "NONE" : protocol.name; - } - - public SSLSessionContext getSessionContext() { - return context; - } - - public Object getValue(String name) { - if (name == null) { - throw new IllegalArgumentException("name == null"); - } - return values.get(name); - } - - public String[] getValueNames() { - return values.keySet().toArray(new String[values.size()]); - } - - public void invalidate() { - isValid = false; - context = null; - } - - public boolean isValid() { - if (isValid && context != null && context.getSessionTimeout() != 0 - && lastAccessedTime + context.getSessionTimeout() > System.currentTimeMillis()) { - isValid = false; - } - return isValid; - } - - public void putValue(String name, Object value) { - if (name == null || value == null) { - throw new IllegalArgumentException("name == null || value == null"); - } - Object old = values.put(name, value); - if (value instanceof SSLSessionBindingListener) { - ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name)); - } - if (old instanceof SSLSessionBindingListener) { - ((SSLSessionBindingListener) old).valueUnbound(new SSLSessionBindingEvent(this, name)); - } - - } - - public void removeValue(String name) { - if (name == null) { - throw new IllegalArgumentException("name == null"); - } - Object old = values.remove(name); - if (old instanceof SSLSessionBindingListener) { - SSLSessionBindingListener listener = (SSLSessionBindingListener) old; - listener.valueUnbound(new SSLSessionBindingEvent(this, name)); - } - } - - @Override - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(e); - } - } - - void setPeer(String peerHost, int peerPort) { - this.peerHost = peerHost; - this.peerPort = peerPort; - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLSocketFactoryImpl.java b/crypto/src/main/java/org/conscrypt/SSLSocketFactoryImpl.java deleted file mode 100644 index dc971ac..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLSocketFactoryImpl.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import javax.net.ssl.SSLSocketFactory; -import org.conscrypt.util.EmptyArray; - -/** - * Implementation of SSLSocketFactory. - */ -public class SSLSocketFactoryImpl extends SSLSocketFactory { - - private final SSLParametersImpl sslParameters; - private final IOException instantiationException; - - /** - * Constructor. - */ - public SSLSocketFactoryImpl() { - SSLParametersImpl sslParametersLocal = null; - IOException instantiationExceptionLocal = null; - try { - sslParametersLocal = SSLParametersImpl.getDefault(); - } catch (KeyManagementException e) { - instantiationExceptionLocal = new IOException("Delayed instantiation exception:"); - instantiationExceptionLocal.initCause(e); - } - this.sslParameters = sslParametersLocal; - this.instantiationException = instantiationExceptionLocal; - } - - /** - * Constructor. - */ - protected SSLSocketFactoryImpl(SSLParametersImpl sslParameters) { - this.sslParameters = sslParameters; - this.instantiationException = null; - } - - /** - * @see javax.net.ssl.SSLSocketFactory#getDefaultCipherSuites() - */ - @Override - public String[] getDefaultCipherSuites() { - if (instantiationException != null) { - return EmptyArray.STRING; - } - return sslParameters.getEnabledCipherSuites(); - } - - /** - * @see javax.net.ssl.SSLSocketFactory#getSupportedCipherSuites() - */ - @Override - public String[] getSupportedCipherSuites() { - if (instantiationException != null) { - return EmptyArray.STRING; - } - return CipherSuite.getSupportedCipherSuiteNames(); - } - - /** - * @see javax.net.ssl.SSLSocketFactory#createSocket(Socket,String,int,boolean) - */ - @Override - public Socket createSocket(Socket s, String host, int port, - boolean autoClose) throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLSocketWrapper(s, host, port, autoClose, (SSLParametersImpl) sslParameters - .clone()); - } - - // -------------- Methods inherided from SocketFactory -------------- - - /** - * @see javax.net.SocketFactory#createSocket() - */ - @Override - public Socket createSocket() throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLSocketImpl((SSLParametersImpl) sslParameters.clone()); - } - - /** - * @see javax.net.SocketFactory#createSocket(String,int) - */ - @Override - public Socket createSocket(String host, int port) - throws IOException, UnknownHostException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLSocketImpl(host, port, - (SSLParametersImpl) sslParameters.clone()); - } - - /** - * @see javax.net.SocketFactory#createSocket(String,int,InetAddress,int) - */ - @Override - public Socket createSocket(String host, int port, - InetAddress localHost, int localPort) throws IOException, - UnknownHostException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLSocketImpl(host, port, localHost, localPort, - (SSLParametersImpl) sslParameters.clone()); - } - - /** - * @see javax.net.SocketFactory#createSocket(InetAddress,int) - */ - @Override - public Socket createSocket(InetAddress host, int port) - throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLSocketImpl(host, port, - (SSLParametersImpl) sslParameters.clone()); - } - - /** - * @see javax.net.SocketFactory#createSocket(InetAddress,int,InetAddress,int) - */ - @Override - public Socket createSocket(InetAddress address, int port, - InetAddress localAddress, int localPort) throws IOException { - if (instantiationException != null) { - throw instantiationException; - } - return new SSLSocketImpl(address, port, localAddress, localPort, - (SSLParametersImpl) sslParameters.clone()); - } - - // ------------------------------------------------------------------ -} diff --git a/crypto/src/main/java/org/conscrypt/SSLSocketImpl.java b/crypto/src/main/java/org/conscrypt/SSLSocketImpl.java deleted file mode 100644 index 138a143..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLSocketImpl.java +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.SocketAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; - -/** - * SSLSocket implementation. - * @see javax.net.ssl.SSLSocket class documentation for more information. - */ -public class SSLSocketImpl extends SSLSocket { - - // indicates if handshake has been started - private boolean handshake_started = false; - - // used when we're wrapping a socket - private final String wrappedHost; - private final int wrappedPort; - - // record protocol to be used - protected SSLRecordProtocol recordProtocol; - // handshake protocol to be used - private HandshakeProtocol handshakeProtocol; - // alert protocol to be used - private AlertProtocol alertProtocol; - // application data input stream, this stream is presented by - // ssl socket as an input stream. Additionally this object is a - // place where application data will be stored by record protocol - private SSLSocketInputStream appDataIS; - // outgoing application data stream - private SSLSocketOutputStream appDataOS; - // active session object - private SSLSessionImpl session; - - private boolean socket_was_closed = false; - - // the sslParameters object encapsulates all the info - // about supported and enabled cipher suites and protocols, - // as well as the information about client/server mode of - // ssl socket, whether it require/want client authentication or not, - // and controls whether new SSL sessions may be established by this - // socket or not. - protected SSLParametersImpl sslParameters; - // super's streams to be wrapped: - protected InputStream input; - protected OutputStream output; - // handshake complete listeners - private ArrayList<HandshakeCompletedListener> listeners; - // logger - private Logger.Stream logger = Logger.getStream("socket"); - - // ----------------- Constructors and initializers -------------------- - - /** - * Constructor - * @param sslParameters: SSLParametersImpl - * @see javax.net.ssl.SSLSocket#SSLSocket() method documentation - * for more information. - */ - protected SSLSocketImpl(SSLParametersImpl sslParameters) { - this.sslParameters = sslParameters; - this.wrappedHost = null; - this.wrappedPort = -1; - // init should be called after creation! - } - - /** - * Constructor - * @param host: String - * @param port: int - * @param sslParameters: SSLParametersImpl - * @throws IOException - * @throws UnknownHostException - * @see javax.net.ssl.SSLSocket#SSLSocket(String,int) - * method documentation for more information. - */ - protected SSLSocketImpl(String host, int port, SSLParametersImpl sslParameters) - throws IOException, UnknownHostException { - super(host, port); - this.wrappedHost = host; - this.wrappedPort = port; - this.sslParameters = sslParameters; - init(); - } - - /** - * Constructor - * @param host: String - * @param port: int - * @param localHost: InetAddress - * @param localPort: int - * @param sslParameters: SSLParametersImpl - * @throws IOException - * @throws UnknownHostException - * @see javax.net.ssl.SSLSocket#SSLSocket(String,int,InetAddress,int) - * method documentation for more information. - */ - protected SSLSocketImpl(String host, int port, - InetAddress localHost, int localPort, - SSLParametersImpl sslParameters) throws IOException, - UnknownHostException { - super(host, port, localHost, localPort); - this.wrappedHost = host; - this.wrappedPort = port; - this.sslParameters = sslParameters; - init(); - } - - /** - * Constructor - * @param host: InetAddress - * @param port: int - * @param sslParameters: SSLParametersImpl - * @return - * @throws IOException - * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int) - * method documentation for more information. - */ - protected SSLSocketImpl(InetAddress host, int port, - SSLParametersImpl sslParameters) throws IOException { - super(host, port); - this.sslParameters = sslParameters; - this.wrappedHost = null; - this.wrappedPort = -1; - init(); - } - - /** - * Constructor - * @param address: InetAddress - * @param port: int - * @param localAddress: InetAddress - * @param localPort: int - * @param sslParameters: SSLParametersImpl - * @return - * @throws IOException - * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int,InetAddress,int) - * method documentation for more information. - */ - protected SSLSocketImpl(InetAddress address, int port, - InetAddress localAddress, int localPort, - SSLParametersImpl sslParameters) throws IOException { - super(address, port, localAddress, localPort); - this.sslParameters = sslParameters; - this.wrappedHost = null; - this.wrappedPort = -1; - init(); - } - - /** - * Initialize the SSL socket. - */ - protected void init() throws IOException { - if (appDataIS != null) { - // already initialized - return; - } - initTransportLayer(); - appDataIS = new SSLSocketInputStream(this); - appDataOS = new SSLSocketOutputStream(this); - } - - /** - * Initialize the transport data streams. - */ - protected void initTransportLayer() throws IOException { - input = super.getInputStream(); - output = super.getOutputStream(); - } - - /** - * Closes the transport data streams. - */ - protected void closeTransportLayer() throws IOException { - super.close(); - if (input != null) { - input.close(); - output.close(); - } - } - - String getWrappedHostName() { - return wrappedHost; - } - - int getWrappedPort() { - return wrappedPort; - } - - String getPeerHostName() { - if (wrappedHost != null) { - return wrappedHost; - } - InetAddress inetAddress = super.getInetAddress(); - if (inetAddress != null) { - return inetAddress.getHostName(); - } - return null; - } - - int getPeerPort() { - return (wrappedPort == -1) ? super.getPort() : wrappedPort; - } - - // --------------- SSLParameters based methods --------------------- - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites() - * method documentation for more information - */ - @Override - public String[] getSupportedCipherSuites() { - return CipherSuite.getSupportedCipherSuiteNames(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites() - * method documentation for more information - */ - @Override - public String[] getEnabledCipherSuites() { - return sslParameters.getEnabledCipherSuites(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[]) - * method documentation for more information - */ - @Override - public void setEnabledCipherSuites(String[] suites) { - sslParameters.setEnabledCipherSuites(suites); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getSupportedProtocols() - * method documentation for more information - */ - @Override - public String[] getSupportedProtocols() { - return ProtocolVersion.supportedProtocols.clone(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getEnabledProtocols() - * method documentation for more information - */ - @Override - public String[] getEnabledProtocols() { - return sslParameters.getEnabledProtocols(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#setEnabledProtocols(String[]) - * method documentation for more information - */ - @Override - public void setEnabledProtocols(String[] protocols) { - sslParameters.setEnabledProtocols(protocols); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean) - * method documentation for more information - */ - @Override - public void setUseClientMode(boolean mode) { - if (handshake_started) { - throw new IllegalArgumentException( - "Could not change the mode after the initial handshake has begun."); - } - sslParameters.setUseClientMode(mode); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getUseClientMode() - * method documentation for more information - */ - @Override - public boolean getUseClientMode() { - return sslParameters.getUseClientMode(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean) - * method documentation for more information - */ - @Override - public void setNeedClientAuth(boolean need) { - sslParameters.setNeedClientAuth(need); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getNeedClientAuth() - * method documentation for more information - */ - @Override - public boolean getNeedClientAuth() { - return sslParameters.getNeedClientAuth(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean) - * method documentation for more information - */ - @Override - public void setWantClientAuth(boolean want) { - sslParameters.setWantClientAuth(want); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getWantClientAuth() - * method documentation for more information - */ - @Override - public boolean getWantClientAuth() { - return sslParameters.getWantClientAuth(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean) - * method documentation for more information - */ - @Override - public void setEnableSessionCreation(boolean flag) { - sslParameters.setEnableSessionCreation(flag); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getEnableSessionCreation() - * method documentation for more information - */ - @Override - public boolean getEnableSessionCreation() { - return sslParameters.getEnableSessionCreation(); - } - - // ----------------------------------------------------------------- - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getSession() - * method documentation for more information - */ - @Override - public SSLSession getSession() { - if (!handshake_started) { - try { - startHandshake(); - } catch (IOException e) { - // return an invalid session with - // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" - return SSLSessionImpl.getNullSession(); - } - } - return session; - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(HandshakeCompletedListener) - * method documentation for more information - */ - @Override - public void addHandshakeCompletedListener( - HandshakeCompletedListener listener) { - if (listener == null) { - throw new IllegalArgumentException("Provided listener is null"); - } - if (listeners == null) { - listeners = new ArrayList<HandshakeCompletedListener>(); - } - listeners.add(listener); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(HandshakeCompletedListener) - * method documentation for more information - */ - @Override - public void removeHandshakeCompletedListener( - HandshakeCompletedListener listener) { - if (listener == null) { - throw new IllegalArgumentException("Provided listener is null"); - } - if (listeners == null) { - throw new IllegalArgumentException( - "Provided listener is not registered"); - } - if (!listeners.remove(listener)) { - throw new IllegalArgumentException( - "Provided listener is not registered"); - } - } - - /** - * Performs the handshake process over the SSL/TLS connection - * as described in rfc 2246, TLS v1 specification - * http://www.ietf.org/rfc/rfc2246.txt. If the initial handshake - * has been already done, this method initiates rehandshake. - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#startHandshake() - * method documentation for more information - */ - @Override - public void startHandshake() throws IOException { - if (appDataIS == null) { - throw new IOException("Socket is not connected."); - } - if (socket_was_closed) { - throw new IOException("Socket has already been closed."); - } - - if (!handshake_started) { - handshake_started = true; - if (sslParameters.getUseClientMode()) { - if (logger != null) { - logger.println("SSLSocketImpl: CLIENT"); - } - handshakeProtocol = new ClientHandshakeImpl(this); - } else { - if (logger != null) { - logger.println("SSLSocketImpl: SERVER"); - } - handshakeProtocol = new ServerHandshakeImpl(this); - } - - alertProtocol = new AlertProtocol(); - recordProtocol = new SSLRecordProtocol(handshakeProtocol, - alertProtocol, new SSLStreamedInput(input), - appDataIS.dataPoint); - } - - if (logger != null) { - logger.println("SSLSocketImpl.startHandshake"); - } - - handshakeProtocol.start(); - - doHandshake(); - - if (logger != null) { - logger.println("SSLSocketImpl.startHandshake: END"); - } - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getInputStream() - * method documentation for more information - */ - @Override - public InputStream getInputStream() throws IOException { - if (socket_was_closed) { - throw new IOException("Socket has already been closed."); - } - return appDataIS; - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#getOutputStream() - * method documentation for more information - */ - @Override - public OutputStream getOutputStream() throws IOException { - if (socket_was_closed) { - throw new IOException("Socket has already been closed."); - } - return appDataOS; - } - - /** - * This method works according to the specification of implemented class. - * @see java.net.Socket#connect(SocketAddress) - * method documentation for more information - */ - @Override - public void connect(SocketAddress endpoint) throws IOException { - super.connect(endpoint); - init(); - } - - /** - * This method works according to the specification of implemented class. - * @see java.net.Socket#connect(SocketAddress,int) - * method documentation for more information - */ - @Override - public void connect(SocketAddress endpoint, int timeout) - throws IOException { - super.connect(endpoint, timeout); - init(); - } - - /** - * This method works according to the specification of implemented class. - * @see javax.net.ssl.SSLSocket#close() - * method documentation for more information - */ - @Override - public void close() throws IOException { - if (logger != null) { - logger.println("SSLSocket.close "+socket_was_closed); - } - if (!socket_was_closed) { - if (handshake_started) { - alertProtocol.alert(AlertProtocol.WARNING, - AlertProtocol.CLOSE_NOTIFY); - try { - output.write(alertProtocol.wrap()); - } catch (IOException ex) { } - alertProtocol.setProcessed(); - } - shutdown(); - closeTransportLayer(); - socket_was_closed = true; - } - } - - /** - * This method is not supported for SSLSocket implementation. - */ - @Override - public void sendUrgentData(int data) throws IOException { - throw new SocketException( - "Method sendUrgentData() is not supported."); - } - - /** - * This method is not supported for SSLSocket implementation. - */ - @Override - public void setOOBInline(boolean on) throws SocketException { - throw new SocketException( - "Methods sendUrgentData, setOOBInline are not supported."); - } - - // ----------------------------------------------------------------- - - private void shutdown() { - if (handshake_started) { - alertProtocol.shutdown(); - alertProtocol = null; - handshakeProtocol.shutdown(); - handshakeProtocol = null; - recordProtocol.shutdown(); - recordProtocol = null; - } - socket_was_closed = true; - } - - /** - * This method is called by SSLSocketInputStream class - * when client application tries to read application data from - * the stream, but there is no data in its underlying buffer. - * @throws IOException - */ - protected void needAppData() throws IOException { - if (!handshake_started) { - startHandshake(); - } - int type; - if (logger != null) { - logger.println("SSLSocket.needAppData.."); - } - try { - while(appDataIS.available() == 0) { - // read and unwrap the record contained in the transport - // input stream (SSLStreamedInput), pass it - // to appropriate client protocol (alert, handshake, or app) - // and retrieve the type of unwrapped data - switch (type = recordProtocol.unwrap()) { - case ContentType.HANDSHAKE: - if (!handshakeProtocol.getStatus().equals( - SSLEngineResult.HandshakeStatus - .NOT_HANDSHAKING)) { - // handshake protocol got addressed to it message - // and did not ignore it, so it's a rehandshake - doHandshake(); - } - break; - case ContentType.ALERT: - processAlert(); - if (socket_was_closed) { - return; - } - break; - case ContentType.APPLICATION_DATA: - if (logger != null) { - logger.println( - "SSLSocket.needAppData: got the data"); - } - break; - default: - // will throw exception - reportFatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, - new SSLException("Unexpected message of type " - + type + " has been got")); - } - if (alertProtocol.hasAlert()) { - // warning alert occurred during wrap or unwrap - // (note: fatal alert causes AlertException - // to be thrown) - output.write(alertProtocol.wrap()); - alertProtocol.setProcessed(); - } - if (socket_was_closed) { - appDataIS.setEnd(); - return; - } - } - } catch (AlertException e) { - // will throw exception - reportFatalAlert(e.getDescriptionCode(), e.getReason()); - } catch (EndOfSourceException e) { - // end of socket's input stream has been reached - appDataIS.setEnd(); - } - if (logger != null) { - logger.println("SSLSocket.needAppData: app data len: " - + appDataIS.available()); - } - } - - /** - * This method is called by SSLSocketOutputStream when a client application - * tries to send the data over ssl protocol. - */ - protected void writeAppData(byte[] data, int offset, int len) throws IOException { - if (!handshake_started) { - startHandshake(); - } - if (logger != null) { - logger.println("SSLSocket.writeAppData: " + - len + " " + SSLRecordProtocol.MAX_DATA_LENGTH); - //logger.println(new String(data, offset, len)); - } - try { - if (len < SSLRecordProtocol.MAX_DATA_LENGTH) { - output.write(recordProtocol.wrap(ContentType.APPLICATION_DATA, - data, offset, len)); - } else { - while (len >= SSLRecordProtocol.MAX_DATA_LENGTH) { - output.write(recordProtocol.wrap( - ContentType.APPLICATION_DATA, data, offset, - SSLRecordProtocol.MAX_DATA_LENGTH)); - offset += SSLRecordProtocol.MAX_DATA_LENGTH; - len -= SSLRecordProtocol.MAX_DATA_LENGTH; - } - if (len > 0) { - output.write( - recordProtocol.wrap(ContentType.APPLICATION_DATA, - data, offset, len)); - } - } - } catch (AlertException e) { - // will throw exception - reportFatalAlert(e.getDescriptionCode(), e.getReason()); - } - } - - /* - * Performs handshake process over this connection. The handshake - * process is directed by the handshake status code provided by - * handshake protocol. If this status is NEED_WRAP, method retrieves - * handshake message from handshake protocol and sends it to another peer. - * If this status is NEED_UNWRAP, method receives and processes handshake - * message from another peer. Each of this stages (wrap/unwrap) change - * the state of handshake protocol and this process is performed - * until handshake status is FINISHED. After handshake process is finished - * handshake completed event are sent to the registered listeners. - * For more information about the handshake process see - * TLS v1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 7.3. - */ - private void doHandshake() throws IOException { - SSLEngineResult.HandshakeStatus status; - int type; - try { - while (!(status = handshakeProtocol.getStatus()).equals( - SSLEngineResult.HandshakeStatus.FINISHED)) { - if (logger != null) { - String s = (status.equals( - SSLEngineResult.HandshakeStatus.NEED_WRAP)) - ? "NEED_WRAP" - : (status.equals( - SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) - ? "NEED_UNWRAP" - : "STATUS: OTHER!"; - logger.println("SSLSocketImpl: HS status: "+s+" "+status); - } - if (status.equals(SSLEngineResult.HandshakeStatus.NEED_WRAP)) { - output.write(handshakeProtocol.wrap()); - } else if (status.equals( - SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) { - // read and unwrap the record contained in the transport - // input stream (SSLStreamedInput), pass it - // to appropriate client protocol (alert, handshake, or app) - // and retrieve the type of unwrapped data - switch (type = recordProtocol.unwrap()) { - case ContentType.HANDSHAKE: - case ContentType.CHANGE_CIPHER_SPEC: - break; - case ContentType.APPLICATION_DATA: - // So it's rehandshake and - // if app data buffer will be overloaded - // it will throw alert exception. - // Probably we should count the number of - // not handshaking data and make additional - // constraints (do not expect buffer overflow). - break; - case ContentType.ALERT: - processAlert(); - if (socket_was_closed) { - return; - } - break; - default: - // will throw exception - reportFatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, - new SSLException( - "Unexpected message of type " - + type + " has been got")); - } - } else { - // will throw exception - reportFatalAlert(AlertProtocol.INTERNAL_ERROR, - new SSLException( - "Handshake passed unexpected status: "+status)); - } - if (alertProtocol.hasAlert()) { - // warning alert occurred during wrap or unwrap - // (note: fatal alert causes AlertException - // to be thrown) - output.write(alertProtocol.wrap()); - alertProtocol.setProcessed(); - } - } - } catch (EndOfSourceException e) { - appDataIS.setEnd(); - throw new IOException("Connection was closed"); - } catch (AlertException e) { - // will throw exception - reportFatalAlert(e.getDescriptionCode(), e.getReason()); - } - - session = recordProtocol.getSession(); - if (listeners != null) { - // notify the listeners - HandshakeCompletedEvent event = - new HandshakeCompletedEvent(this, session); - int size = listeners.size(); - for (int i=0; i<size; i++) { - listeners.get(i) - .handshakeCompleted(event); - } - } - } - - /* - * Process received alert message - */ - private void processAlert() throws IOException { - if (!alertProtocol.hasAlert()) { - return; - } - if (alertProtocol.isFatalAlert()) { - alertProtocol.setProcessed(); - String description = "Fatal alert received " - + alertProtocol.getAlertDescription(); - shutdown(); - throw new SSLException(description); - } - - if (logger != null) { - logger.println("Warning alert received: " - + alertProtocol.getAlertDescription()); - } - switch(alertProtocol.getDescriptionCode()) { - case AlertProtocol.CLOSE_NOTIFY: - alertProtocol.setProcessed(); - appDataIS.setEnd(); - close(); - return; - default: - alertProtocol.setProcessed(); - // TODO: process other warning messages - } - } - - /* - * Sends fatal alert message and throws exception - */ - private void reportFatalAlert(byte description_code, - SSLException reason) throws IOException { - alertProtocol.alert(AlertProtocol.FATAL, description_code); - try { - // the output stream can be closed - output.write(alertProtocol.wrap()); - } catch (IOException ex) { } - alertProtocol.setProcessed(); - shutdown(); - throw reason; - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLSocketInputStream.java b/crypto/src/main/java/org/conscrypt/SSLSocketInputStream.java deleted file mode 100644 index 36c5c03..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLSocketInputStream.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.InputStream; -import javax.net.ssl.SSLException; - -/** - * This class provides input data stream functionality - * for SSLSocket. It accumulates the application data - * received by SSL protocol. - */ -public final class SSLSocketInputStream extends InputStream { - - // The size of the internal data buffer. - // It should not be less than maximum data chunk enclosed - // in one ssl packet. - private static final int BUFFER_SIZE = SSLRecordProtocol.MAX_DATA_LENGTH; - - // Internal buffer accumulating the received application data - private byte[] buffer = new byte[BUFFER_SIZE]; - - // position of the next byte to read from the buffer - private int pos; - - // position of the last byte to read + 1 - private int end; - - // the ssl socket owning the stream - private final SSLSocketImpl owner; - - // the flag indicating that the end of the (owner's) input stream - // has been reached - private boolean end_reached = false; - - /** - * Creates the application data input stream for specified socket. - * @param owner the socket which will provide this input stream - * to client applications. - */ - protected SSLSocketInputStream(SSLSocketImpl owner) { - this.owner = owner; - } - - // The helper delivering the application data from the record layer - protected Adapter dataPoint = new Adapter(); - - /** - * Tells to the stream that the end of the income data has - * been reached. - */ - protected void setEnd() { - end_reached = true; - } - - // ------------------ InputStream implementation ------------------- - - /** - * Returns the number of bytes available for reading without blocking. - * @return the number of available bytes. - * @throws IOException - */ - @Override - public int available() throws IOException { - return end - pos; - } - - /** - * Closes the stream - * @throws IOException - */ - @Override - public void close() throws IOException { - buffer = null; - } - - /** - * Reads one byte. If there is no data in the underlying buffer, - * this operation can block until the data will be - * available. - * @return read value. - * @throws IOException - */ - @Override - public int read() throws IOException { - if (buffer == null) { - throw new IOException("Stream was closed."); - } - while (pos == end) { - if (end_reached) { - return -1; - } - // If there is no data in the buffer - // - will block until the data will be provided by - // record layer - owner.needAppData(); - } - return buffer[pos++] & 0xFF; - } - - @Override public int read(byte[] b, int off, int len) throws IOException { - int read_b; - int i = 0; - do { - if ((read_b = read()) == -1) { - return (i == 0) ? -1 : i; - } - b[off+i] = (byte) read_b; - i++; - } while ((available() != 0) && (i<len)); - return i; - } - - // The helper class delivering the application data from the record layer - // to this input stream. - // It 'adapts' the InputStream interface to Appendable, which is used for - // transmission of income data from the record protocol to its clients. - private class Adapter implements org.conscrypt.Appendable { - /** - * Appends the data to the stream. - * This method could be implemented in the outer class - * itself, but it could be insecure. - */ - public void append(byte[] src) { - int length = src.length; - if (BUFFER_SIZE - (end - pos) < length) { - // If the size of the buffer is greater than or equals to - // SSLRecordProtocol.MAX_DATA_LENGTH this situation will - // happen iff: - // 1. the length of received data fragment is greater - // than allowed by the spec - // 2. it is rehandshaking stage and we have got several - // extra app data messages. - // In any case it is better to throw alert exception. - throw new AlertException(AlertProtocol.INTERNAL_ERROR, - new SSLException("Could not accept income app data.")); - } - if (end + length > BUFFER_SIZE) { - // move the content of the buffer to the beginning - System.arraycopy(buffer, pos, buffer, 0, end-pos); - end -= pos; - pos = 0; - } - System.arraycopy(src, 0, buffer, end, length); - end = end + length; - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLSocketOutputStream.java b/crypto/src/main/java/org/conscrypt/SSLSocketOutputStream.java deleted file mode 100644 index e3afed7..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLSocketOutputStream.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.OutputStream; -import libcore.io.Streams; - -/** - * This is a application data output stream used in SSLSocket - * implementation. - * The written bytes are encrypted, packed into the records, - * and then sent to the peer host. - */ -public class SSLSocketOutputStream extends OutputStream { - private final SSLSocketImpl owner; - - protected SSLSocketOutputStream(SSLSocketImpl owner) { - this.owner = owner; - } - - @Override public void write(int b) throws IOException { - Streams.writeSingleByte(this, b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - owner.writeAppData(b, off, len); - } -} diff --git a/crypto/src/main/java/org/conscrypt/SSLSocketWrapper.java b/crypto/src/main/java/org/conscrypt/SSLSocketWrapper.java deleted file mode 100644 index 2110aea..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLSocketWrapper.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.SocketException; - -/** - * This class wraps the SSL fuctionality over existing conneted socket. - */ -public class SSLSocketWrapper extends SSLSocketImpl { - - private final Socket socket; - private final boolean autoClose; - - protected SSLSocketWrapper(Socket socket, String host, int port, boolean autoClose, - SSLParametersImpl sslParameters) throws IOException { - super(host, port, sslParameters); - if (!socket.isConnected()) { - throw new SocketException("Socket is not connected."); - } - this.socket = socket; - this.autoClose = autoClose; - init(); - } - - @Override - protected void initTransportLayer() throws IOException { - input = socket.getInputStream(); - output = socket.getOutputStream(); - } - - @Override - protected void closeTransportLayer() throws IOException { - if (autoClose && (input != null)) { - socket.close(); - input.close(); - output.close(); - } - } - - // ------------------- Wrapping method implementations --------------- - - @Override - public void connect(SocketAddress sockaddr, int timeout) - throws IOException { - throw new IOException("Underlying socket is already connected."); - } - - @Override - public void connect(SocketAddress sockaddr) throws IOException { - throw new IOException("Underlying socket is already connected."); - } - - @Override - public void bind(SocketAddress sockaddr) throws IOException { - throw new IOException("Underlying socket is already connected."); - } - - @Override - public SocketAddress getRemoteSocketAddress() { - return socket.getRemoteSocketAddress(); - } - - @Override - public SocketAddress getLocalSocketAddress() { - return socket.getLocalSocketAddress(); - } - - @Override - public InetAddress getLocalAddress() { - return socket.getLocalAddress(); - } - - @Override - public InetAddress getInetAddress() { - return socket.getInetAddress(); - } - - @Override - public String toString() { - return "SSL socket over " + socket.toString(); - } - - @Override - public void setSoLinger(boolean on, int linger) throws SocketException { - socket.setSoLinger(on, linger); - } - - @Override - public void setTcpNoDelay(boolean on) throws SocketException { - socket.setTcpNoDelay(on); - } - - @Override - public void setReuseAddress(boolean on) throws SocketException { - socket.setReuseAddress(on); - } - - @Override - public void setKeepAlive(boolean on) throws SocketException { - socket.setKeepAlive(on); - } - - @Override - public void setTrafficClass(int tos) throws SocketException { - socket.setTrafficClass(tos); - } - - @Override - public void setSoTimeout(int to) throws SocketException { - socket.setSoTimeout(to); - } - - @Override - public void setSendBufferSize(int size) throws SocketException { - socket.setSendBufferSize(size); - } - - @Override - public void setReceiveBufferSize(int size) throws SocketException { - socket.setReceiveBufferSize(size); - } - - @Override - public boolean getTcpNoDelay() throws SocketException { - return socket.getTcpNoDelay(); - } - - @Override - public boolean getReuseAddress() throws SocketException { - return socket.getReuseAddress(); - } - - @Override - public boolean getOOBInline() throws SocketException { - return socket.getOOBInline(); - } - - @Override - public boolean getKeepAlive() throws SocketException { - return socket.getKeepAlive(); - } - - @Override - public int getTrafficClass() throws SocketException { - return socket.getTrafficClass(); - } - - @Override - public int getSoTimeout() throws SocketException { - return socket.getSoTimeout(); - } - - @Override - public int getSoLinger() throws SocketException { - return socket.getSoLinger(); - } - - @Override - public int getSendBufferSize() throws SocketException { - return socket.getSendBufferSize(); - } - - @Override - public int getReceiveBufferSize() throws SocketException { - return socket.getReceiveBufferSize(); - } - - @Override - public boolean isConnected() { - return socket.isConnected(); - } - - @Override - public boolean isClosed() { - return socket.isClosed(); - } - - @Override - public boolean isBound() { - return socket.isBound(); - } - - @Override - public boolean isOutputShutdown() { - return socket.isOutputShutdown(); - } - - @Override - public boolean isInputShutdown() { - return socket.isInputShutdown(); - } - - @Override - public int getPort() { - return socket.getPort(); - } - - @Override - public int getLocalPort() { - return socket.getLocalPort(); - } - - @Override - public FileDescriptor getFileDescriptor$() { - return socket.getFileDescriptor$(); - } - - // ------------------------------------------------------------------- - -} - diff --git a/crypto/src/main/java/org/conscrypt/SSLStreamedInput.java b/crypto/src/main/java/org/conscrypt/SSLStreamedInput.java deleted file mode 100644 index 4c8a885..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLStreamedInput.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This class acts like a filtered input stream: it takes - * the bytes from another InputStream. - */ -public class SSLStreamedInput extends SSLInputStream { - - private InputStream in; - - public SSLStreamedInput(InputStream in) { - this.in = in; - } - - @Override - public int available() throws IOException { - return in.available(); - } - - /** - * Read an opaque value from the stream. - * @return the value read from the underlying stream. - * @throws IOException if the data could not be read from - * the underlying stream - * @throws org.conscrypt.EndOfSourceException if the end of the underlying - * stream has been reached. - */ - @Override - public int read() throws IOException { - int res = in.read(); - if (res < 0) { - throw new EndOfSourceException(); - } - return res; - } -} - diff --git a/crypto/src/main/java/org/conscrypt/SSLv3Constants.java b/crypto/src/main/java/org/conscrypt/SSLv3Constants.java deleted file mode 100644 index ea6482f..0000000 --- a/crypto/src/main/java/org/conscrypt/SSLv3Constants.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -/** - * - * Contains SSL 3.0 constants - * @see <a href="http://wp.netscape.com/eng/ssl3">SSL 3.0 Spec.</a> - */ -public class SSLv3Constants { - - /** - * Client is a sender. Used in hash calculating for finished message. - * @see <a href="http://wp.netscape.com/eng/ssl3">SSL 3.0 Spec., 5.6.9 - * Finished</a> - */ - static final byte[] client = new byte[] { 0x43, 0x4C, 0x4E, 0x54 }; - - /** - * Server is a sender. Used in hash calculating for finished message. - * @see <a href="http://wp.netscape.com/eng/ssl3">SSL 3.0 Spec., 5.6.9 - * Finished</a> - */ - static final byte[] server = new byte[] { 0x53, 0x52, 0x56, 0x52 }; - - /** - * pad_1 for MD5 - * @see <a href="http://wp.netscape.com/eng/ssl3">SSL 3.0 Spec., 5.2.3.1 - * Null or standard stream cipher</a> - */ - static final byte[] MD5pad1 = new byte[] { 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 }; - - /** - * pad_1 for SHA - * @see <a href="http://wp.netscape.com/eng/ssl3">SSL 3.0 Spec., 5.2.3.1 - * Null or standard stream cipher</a> - */ - static final byte[] SHApad1 = new byte[] { 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36 }; - - /** - * pad_2 for MD5 - * @see <a href="http://wp.netscape.com/eng/ssl3">SSL 3.0 Spec., 5.2.3.1 - * Null or standard stream cipher</a> - */ - static final byte[] MD5pad2 = new byte[] { 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C }; - - /** - * pad_2 for SHA - * @see <a href="http://wp.netscape.com/eng/ssl3">SSL 3.0 Spec., 5.2.3.1 - * Null or standard stream cipher</a> - */ - static final byte[] SHApad2 = new byte[] { 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, - 0x5C, 0x5C, 0x5C }; -} diff --git a/crypto/src/main/java/org/conscrypt/ServerHandshakeImpl.java b/crypto/src/main/java/org/conscrypt/ServerHandshakeImpl.java deleted file mode 100644 index 590dd17..0000000 --- a/crypto/src/main/java/org/conscrypt/ServerHandshakeImpl.java +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PrivilegedExceptionAction; -import java.security.PublicKey; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPublicKey; -import java.util.Arrays; -import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; -import javax.crypto.interfaces.DHPublicKey; -import javax.crypto.spec.DHParameterSpec; -import javax.crypto.spec.DHPublicKeySpec; -import javax.net.ssl.X509ExtendedKeyManager; -import javax.net.ssl.X509KeyManager; -import javax.net.ssl.X509TrustManager; - -/** - * Server side handshake protocol implementation. - * Handshake protocol operates on top of the Record Protocol. - * It responsible for negotiating a session. - * - * The implementation processes inbound client handshake messages, - * creates and sends respond messages. Outbound messages are supplied - * to Record Protocol. Detected errors are reported to the Alert protocol. - * - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4. - * Handshake protocol.</a> - * - */ -public class ServerHandshakeImpl extends HandshakeProtocol { - - // private key used in key exchange - private PrivateKey privKey; - - /** - * Creates Server Handshake Implementation - * - * @param owner - */ - public ServerHandshakeImpl(Object owner) { - super(owner); - status = NEED_UNWRAP; - } - - /** - * Start session negotiation - */ - @Override - public void start() { - if (session == null) { // initial handshake - status = NEED_UNWRAP; - return; // wait client hello - } - if (clientHello != null && this.status != FINISHED) { - // current negotiation has not completed - return; // ignore - } - - // renegotiation - sendHelloRequest(); - status = NEED_UNWRAP; - } - - /** - * Proceses inbound handshake messages - * @param bytes - */ - @Override - public void unwrap(byte[] bytes) { - - io_stream.append(bytes); - while (io_stream.available() > 0) { - int handshakeType; - int length; - io_stream.mark(); - try { - handshakeType = io_stream.read(); - length = io_stream.readUint24(); - if (io_stream.available() < length) { - io_stream.reset(); - return; - } - - switch (handshakeType) { - case 1: // CLIENT_HELLO - if (clientHello != null && this.status != FINISHED) { - // Client hello has been received during handshake - unexpectedMessage(); - return; - } - // if protocol planed to send Hello Request message - // - cancel this demand. - needSendHelloRequest = false; - clientHello = new ClientHello(io_stream, length); - if (nonBlocking) { - delegatedTasks.add(new DelegatedTask(new Runnable() { - public void run() { - processClientHello(); - } - }, this)); - return; - } - processClientHello(); - break; - - case 11: // CLIENT CERTIFICATE - if (isResuming || certificateRequest == null - || serverHelloDone == null || clientCert != null) { - unexpectedMessage(); - return; - } - clientCert = new CertificateMessage(io_stream, length); - if (clientCert.certs.length == 0) { - if (parameters.getNeedClientAuth()) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "HANDSHAKE FAILURE: no client certificate received"); - } - } else { - String authType = clientCert.getAuthType(); - try { - parameters.getTrustManager().checkClientTrusted( - clientCert.certs, authType); - } catch (CertificateException e) { - fatalAlert(AlertProtocol.BAD_CERTIFICATE, - "Untrusted Client Certificate ", e); - } - session.peerCertificates = clientCert.certs; - } - break; - - case 15: // CERTIFICATE_VERIFY - if (isResuming - || clientKeyExchange == null - || clientCert == null - || clientKeyExchange.isEmpty() //client certificate - // contains fixed DH - // parameters - || certificateVerify != null - || changeCipherSpecReceived) { - unexpectedMessage(); - return; - } - certificateVerify = new CertificateVerify(io_stream, length); - - String authType = clientCert.getAuthType(); - DigitalSignature ds = new DigitalSignature(authType); - ds.init(clientCert.certs[0]); - byte[] md5_hash = null; - byte[] sha_hash = null; - - if ("RSA".equals(authType)) { - md5_hash = io_stream.getDigestMD5withoutLast(); - sha_hash = io_stream.getDigestSHAwithoutLast(); - } else if ("DSA".equals(authType)) { - sha_hash = io_stream.getDigestSHAwithoutLast(); - // The Signature should be empty in case of anonymous signature algorithm: - // } else if ("DH".equals(authType)) { - } - ds.setMD5(md5_hash); - ds.setSHA(sha_hash); - if (!ds.verifySignature(certificateVerify.signedHash)) { - fatalAlert(AlertProtocol.DECRYPT_ERROR, - "DECRYPT ERROR: CERTIFICATE_VERIFY incorrect signature"); - } - break; - case 16: // CLIENT_KEY_EXCHANGE - if (isResuming - || serverHelloDone == null - || clientKeyExchange != null - || (clientCert == null && parameters.getNeedClientAuth())) { - unexpectedMessage(); - return; - } - if (session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA - || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { - clientKeyExchange = new ClientKeyExchange(io_stream, - length, serverHello.server_version[1] == 1, - true); - Cipher c = null; - try { - c = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - c.init(Cipher.UNWRAP_MODE, privKey); - preMasterSecret = c.unwrap(clientKeyExchange.exchange_keys, - "preMasterSecret", - Cipher.SECRET_KEY).getEncoded(); - // check preMasterSecret: - if (preMasterSecret.length != 48 - || preMasterSecret[0] != clientHello.client_version[0] - || preMasterSecret[1] != clientHello.client_version[1]) { - // incorrect preMasterSecret - // prevent an attack (see TLS 1.0 spec., 7.4.7.1.) - preMasterSecret = new byte[48]; - parameters.getSecureRandom().nextBytes( - preMasterSecret); - } - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "INTERNAL ERROR", e); - } - } else { // diffie hellman key exchange - clientKeyExchange = new ClientKeyExchange(io_stream, - length, serverHello.server_version[1] == 1, - false); - if (clientKeyExchange.isEmpty()) { - // TODO check that client cert. DH params - // matched server cert. DH params - - // client cert. contains fixed DH parameters - preMasterSecret = ((DHPublicKey) clientCert.certs[0].getPublicKey()).getY().toByteArray(); - } else { - try { - KeyFactory kf = KeyFactory.getInstance("DH"); - KeyAgreement agreement = KeyAgreement.getInstance("DH"); - PublicKey clientPublic = kf.generatePublic(new DHPublicKeySpec( - new BigInteger( - 1, - clientKeyExchange.exchange_keys), - serverKeyExchange.par1, - serverKeyExchange.par2)); - agreement.init(privKey); - agreement.doPhase(clientPublic, true); - preMasterSecret = agreement.generateSecret(); - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, - "INTERNAL ERROR", e); - return; - } - } - } - - computerMasterSecret(); - break; - - case 20: // FINISHED - if (!isResuming && !changeCipherSpecReceived) { - unexpectedMessage(); - return; - } - - clientFinished = new Finished(io_stream, length); - verifyFinished(clientFinished.getData()); - session.context = parameters.getServerSessionContext(); - parameters.getServerSessionContext().putSession(session); - if (!isResuming) { - sendChangeCipherSpec(); - } else { - session.lastAccessedTime = System.currentTimeMillis(); - status = FINISHED; - } - break; - default: - unexpectedMessage(); - return; - } - } catch (IOException e) { - // io stream dosn't contain complete handshake message - io_stream.reset(); - return; - } - } - } - /** - * Processes SSLv2 Hello message - * @ see TLS 1.0 spec., E.1. Version 2 client hello - * @param bytes - */ - @Override - public void unwrapSSLv2(byte[] bytes) { - io_stream.append(bytes); - io_stream.mark(); - try { - clientHello = new ClientHello(io_stream); - } catch (IOException e) { - io_stream.reset(); - return; - } - if (nonBlocking) { - delegatedTasks.add(new DelegatedTask(new Runnable() { - public void run() { - processClientHello(); - } - }, this)); - return; - } - processClientHello(); - } - - /** - * - * Processes Client Hello message. - * Server responds to client hello message with server hello - * and (if necessary) server certificate, server key exchange, - * certificate request, and server hello done messages. - */ - void processClientHello() { - CipherSuite cipher_suite; - - // check that clientHello contains CompressionMethod.null - checkCompression: { - for (int i = 0; i < clientHello.compression_methods.length; i++) { - if (clientHello.compression_methods[i] == 0) { - break checkCompression; - } - } - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "HANDSHAKE FAILURE. Incorrect client hello message"); - } - - byte[] server_version = clientHello.client_version; - if (!ProtocolVersion.isSupported(clientHello.client_version)) { - if (clientHello.client_version[0] >= 3) { - // Protocol from the future, admit that the newest thing we know is TLSv1 - server_version = ProtocolVersion.TLSv1.version; - } else { - fatalAlert(AlertProtocol.PROTOCOL_VERSION, - "PROTOCOL VERSION. Unsupported client version " - + clientHello.client_version[0] - + clientHello.client_version[1]); - } - } - - isResuming = false; - FIND: if (clientHello.session_id.length != 0) { - // client wishes to reuse session - - SSLSessionImpl sessionToResume; - boolean reuseCurrent = false; - - // reuse current session - if (session != null - && Arrays.equals(session.id, clientHello.session_id)) { - if (session.isValid()) { - isResuming = true; - break FIND; - } - reuseCurrent = true; - } - - // find session in cash - sessionToResume = findSessionToResume(clientHello.session_id); - if (sessionToResume == null || !sessionToResume.isValid()) { - if (!parameters.getEnableSessionCreation()) { - if (reuseCurrent) { - // we can continue current session - sendWarningAlert(AlertProtocol.NO_RENEGOTIATION); - status = NOT_HANDSHAKING; - clearMessages(); - return; - } - // throw AlertException - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "SSL Session may not be created"); - } - session = null; - } else { - session = (SSLSessionImpl)sessionToResume.clone(); - isResuming = true; - } - } - - if (isResuming) { - cipher_suite = session.cipherSuite; - // clientHello.cipher_suites must include at least cipher_suite from the session - checkCipherSuite: { - for (int i = 0; i < clientHello.cipher_suites.length; i++) { - if (cipher_suite.equals(clientHello.cipher_suites[i])) { - break checkCipherSuite; - } - } - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "HANDSHAKE FAILURE. Incorrect client hello message"); - } - } else { - cipher_suite = selectSuite(clientHello.cipher_suites); - if (cipher_suite == null) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "HANDSHAKE FAILURE. NO COMMON SUITE"); - } - if (!parameters.getEnableSessionCreation()) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, - "SSL Session may not be created"); - } - session = new SSLSessionImpl(cipher_suite, parameters.getSecureRandom()); - if (engineOwner != null) { - session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort()); - } else { - session.setPeer(socketOwner.getInetAddress().getHostName(), socketOwner.getPort()); - } - } - - recordProtocol.setVersion(server_version); - session.protocol = ProtocolVersion.getByVersion(server_version); - session.clientRandom = clientHello.random; - - // create server hello message - serverHello = new ServerHello(parameters.getSecureRandom(), - server_version, - session.getId(), cipher_suite, (byte) 0); //CompressionMethod.null - session.serverRandom = serverHello.random; - send(serverHello); - if (isResuming) { - sendChangeCipherSpec(); - return; - } - - // create and send server certificate message if needed - if (!cipher_suite.isAnonymous()) { // need to send server certificate - X509Certificate[] certs = null; - String certType = cipher_suite.getServerKeyType(); - if (certType == null) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "NO CERT TYPE FOR " + cipher_suite.getName()); - } - // obtain certificates from key manager - String alias = null; - X509KeyManager km = parameters.getKeyManager(); - if (km instanceof X509ExtendedKeyManager) { - X509ExtendedKeyManager ekm = (X509ExtendedKeyManager)km; - if (this.socketOwner != null) { - alias = ekm.chooseServerAlias(certType, null, - this.socketOwner); - } else { - alias = ekm.chooseEngineServerAlias(certType, null, - this.engineOwner); - } - if (alias != null) { - certs = ekm.getCertificateChain(alias); - } - } else { - alias = km.chooseServerAlias(certType, null, this.socketOwner); - if (alias != null) { - certs = km.getCertificateChain(alias); - } - } - - if (certs == null) { - fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "NO SERVER CERTIFICATE FOUND"); - return; - } - session.localCertificates = certs; - serverCert = new CertificateMessage(certs); - privKey = km.getPrivateKey(alias); - send(serverCert); - } - - // create and send server key exchange message if needed - RSAPublicKey rsakey = null; - DHPublicKeySpec dhkeySpec = null; - byte[] hash = null; - BigInteger p = null; - BigInteger g = null; - - KeyPairGenerator kpg = null; - - try { - if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { - PublicKey pk = serverCert.certs[0].getPublicKey(); - if (getRSAKeyLength(pk) > 512) { - // key is longer than 512 bits - kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(512); - } - } else if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS - || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS_EXPORT - || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA - || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA_EXPORT - || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DH_anon - || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT) { - kpg = KeyPairGenerator.getInstance("DH"); - p = new BigInteger(1, DHParameters.getPrime()); - g = new BigInteger("2"); - DHParameterSpec spec = new DHParameterSpec(p, g); - kpg.initialize(spec); - } - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e); - } - - if (kpg != null) { - // need to send server key exchange message - DigitalSignature ds = new DigitalSignature(cipher_suite.authType); - KeyPair kp = null; - try { - kp = kpg.genKeyPair(); - if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { - rsakey = (RSAPublicKey) kp.getPublic(); - } else { - DHPublicKey dhkey = (DHPublicKey) kp.getPublic(); - KeyFactory kf = KeyFactory.getInstance("DH"); - dhkeySpec = kf.getKeySpec(dhkey, DHPublicKeySpec.class); - } - if (!cipher_suite.isAnonymous()) { // calculate signed_params - - // init by private key which correspond to - // server certificate - ds.init(privKey); - - // use emphemeral key for key exchange - privKey = kp.getPrivate(); - ds.update(clientHello.getRandom()); - ds.update(serverHello.getRandom()); - - byte[] tmp; - byte[] tmpLength = new byte[2]; -//FIXME 1_byte==0x00 - if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { - tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getModulus()); - tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8); - tmpLength[1] = (byte) (tmp.length & 0xFF); - ds.update(tmpLength); - ds.update(tmp); - tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getPublicExponent()); - tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8); - tmpLength[1] = (byte) (tmp.length & 0xFF); - ds.update(tmpLength); - ds.update(tmp); - } else { - tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getP()); - tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8); - tmpLength[1] = (byte) (tmp.length & 0xFF); - ds.update(tmpLength); - ds.update(tmp); - tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getG()); - tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8); - tmpLength[1] = (byte) (tmp.length & 0xFF); - ds.update(tmpLength); - ds.update(tmp); - tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getY()); - tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8); - tmpLength[1] = (byte) (tmp.length & 0xFF); - ds.update(tmpLength); - ds.update(tmp); - } - hash = ds.sign(); - } else { - privKey = kp.getPrivate(); // use emphemeral key for key exchange - } - } catch (Exception e) { - fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e); - } - - if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { - serverKeyExchange = new ServerKeyExchange(rsakey.getModulus(), - rsakey.getPublicExponent(), null, hash); - } else { - serverKeyExchange = new ServerKeyExchange(p, - g, dhkeySpec.getY(), hash); - } - send(serverKeyExchange); - } - - // CERTIFICATE_REQUEST - certRequest: if (parameters.getWantClientAuth() - || parameters.getNeedClientAuth()) { - X509Certificate[] accepted; - try { - X509TrustManager tm = parameters.getTrustManager(); - accepted = tm.getAcceptedIssuers(); - } catch (ClassCastException e) { - // don't send certificateRequest - break certRequest; - } - byte[] requestedClientCertTypes = { CipherSuite.TLS_CT_RSA_SIGN, - CipherSuite.TLS_CT_DSS_SIGN }; - certificateRequest = new CertificateRequest( - requestedClientCertTypes, accepted); - send(certificateRequest); - } - - // SERVER_HELLO_DONE - serverHelloDone = new ServerHelloDone(); - send(serverHelloDone); - status = NEED_UNWRAP; - } - - /** - * Creates and sends finished message - */ - @Override - protected void makeFinished() { - byte[] verify_data; - boolean isTLS = (serverHello.server_version[1] == 1); // TLS 1.0 protocol - if (isTLS) { - verify_data = new byte[12]; - computerVerifyDataTLS("server finished", verify_data); - } else { // SSL 3.0 protocol (http://wp.netscape.com/eng/ssl3) - verify_data = new byte[36]; - computerVerifyDataSSLv3(SSLv3Constants.server, verify_data); - } - serverFinished = new Finished(verify_data); - send(serverFinished); - if (isResuming) { - if (isTLS) { - computerReferenceVerifyDataTLS("client finished"); - } else { - computerReferenceVerifyDataSSLv3(SSLv3Constants.client); - } - status = NEED_UNWRAP; - } else { - session.lastAccessedTime = System.currentTimeMillis(); - status = FINISHED; - } - } - - // find sesssion in the session hash - private SSLSessionImpl findSessionToResume(byte[] session_id) { - return (SSLSessionImpl)parameters.getServerSessionContext().getSession(session_id); - } - - // find appropriate cipher_suite in the client suites - private CipherSuite selectSuite(CipherSuite[] clientSuites) { - for (CipherSuite clientSuite : clientSuites) { - if (!clientSuite.supported) { - continue; - } - for (CipherSuite enabledCipherSuite : parameters.getEnabledCipherSuitesMember()) { - if (clientSuite.equals(enabledCipherSuite)) { - return clientSuite; - } - } - } - return null; - } - - /** - * Processes inbound ChangeCipherSpec message - */ - @Override - public void receiveChangeCipherSpec() { - if (isResuming) { - if (serverFinished == null) { - unexpectedMessage(); - } else { - changeCipherSpecReceived = true; - } - } else { - if ((parameters.getNeedClientAuth() && clientCert == null) - || clientKeyExchange == null - || (clientCert != null && clientCert.certs.length > 0 - && !clientKeyExchange.isEmpty() - && certificateVerify == null)) { - unexpectedMessage(); - } else { - changeCipherSpecReceived = true; - } - if (serverHello.server_version[1] == 1) { - computerReferenceVerifyDataTLS("client finished"); - } else { - computerReferenceVerifyDataSSLv3(SSLv3Constants.client); - } - } - } - -} diff --git a/crypto/src/main/java/org/conscrypt/ServerHello.java b/crypto/src/main/java/org/conscrypt/ServerHello.java deleted file mode 100644 index 3cc3b46..0000000 --- a/crypto/src/main/java/org/conscrypt/ServerHello.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.SecureRandom; -import libcore.io.Streams; - -/** - * - * Represents server hello message. - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.1.3. - * Server hello.</a> - */ -public class ServerHello extends Message { - - /** - * Server version - */ - byte[] server_version = new byte[2]; - - /** - * Random bytes - */ - byte[] random = new byte[32]; - - /** - * Session id - */ - byte[] session_id; - - /** - * Selected cipher suite - */ - CipherSuite cipher_suite; - - /** - * Selected compression method - */ - byte compression_method; - - /** - * Creates outbound message - * @param sr - * @param server_version - * @param session_id - * @param cipher_suite - * @param compression_method - */ - public ServerHello(SecureRandom sr, byte[] server_version, - byte[] session_id, CipherSuite cipher_suite, byte compression_method) { - long gmt_unix_time = new java.util.Date().getTime() / 1000; - sr.nextBytes(random); - random[0] = (byte) ((gmt_unix_time & 0xFF000000) >>> 24); - random[1] = (byte) ((gmt_unix_time & 0xFF0000) >>> 16); - random[2] = (byte) ((gmt_unix_time & 0xFF00) >>> 8); - random[3] = (byte) (gmt_unix_time & 0xFF); - this.session_id = session_id; - this.cipher_suite = cipher_suite; - this.compression_method = compression_method; - this.server_version = server_version; - length = 38 + session_id.length; - } - - /** - * Creates inbound message - * @param in - * @param length - * @throws IOException - */ - public ServerHello(HandshakeIODataStream in, int length) throws IOException { - - server_version[0] = (byte) in.read(); - server_version[1] = (byte) in.read(); - Streams.readFully(in, random); - int size = in.readUint8(); - session_id = new byte[size]; - in.read(session_id, 0, size); - byte b0 = (byte) in.read(); - byte b1 = (byte) in.read(); - cipher_suite = CipherSuite.getByCode(b0, b1); - compression_method = (byte) in.read(); - this.length = 38 + session_id.length; - if (this.length != length) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect ServerHello"); - } - - } - - /** - * Sends message - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - out.write(server_version); - out.write(random); - out.writeUint8(session_id.length); - out.write(session_id); - out.write(cipher_suite.toBytes()); - out.write(compression_method); - length = 38 + session_id.length; - } - - /** - * Returns server random - * @return - */ - public byte[] getRandom() { - return random; - } - - /** - * Returns message type - * @return - */ - @Override - public int getType() { - return Handshake.SERVER_HELLO; - } -} diff --git a/crypto/src/main/java/org/conscrypt/ServerHelloDone.java b/crypto/src/main/java/org/conscrypt/ServerHelloDone.java deleted file mode 100644 index 3e40f9a..0000000 --- a/crypto/src/main/java/org/conscrypt/ServerHelloDone.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; - -/** - * - * Represents server hello done message - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.5. - * Server hello done</a> - * - */ -public class ServerHelloDone extends Message { - - /** - * Creates outbound message - * - */ - public ServerHelloDone() { - } - - /** - * Creates inbound message - * @param in - * @param length - * @throws IOException - */ - public ServerHelloDone(HandshakeIODataStream in, int length) - throws IOException { - if (length != 0) { - fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect ServerHelloDone"); - } - } - - /** - * Sends message - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - } - - /** - * Returns message length - * @return - */ - @Override - public int length() { - return 0; - } - - /** - * Returns message type - * @return - */ - @Override - public int getType() { - return Handshake.SERVER_HELLO_DONE; - } -} diff --git a/crypto/src/main/java/org/conscrypt/ServerKeyExchange.java b/crypto/src/main/java/org/conscrypt/ServerKeyExchange.java deleted file mode 100644 index e928f72..0000000 --- a/crypto/src/main/java/org/conscrypt/ServerKeyExchange.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.RSAPublicKeySpec; - -/** - * - * Represents server key exchange message. - * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.3. - * Server key exchange message.</a> - * - */ -public class ServerKeyExchange extends Message { - - // ServerRSAParams ServerDHParams - final BigInteger par1; // rsa_modulus dh_p - final byte[] bytes1; - - final BigInteger par2; // rsa_exponent dh_g - final byte[] bytes2; - - final BigInteger par3; // dh_Ys - final byte[] bytes3; - - /** - * Signature - */ - final byte[] hash; - - private RSAPublicKey key; - - /** - * Creates outbound message - * @param par1 rsa_modulus or dh_p - * @param par2 rsa_exponent or dh_g - * @param par3 dh_Ys for ServerDHParams; should be null for ServerRSAParams - * @param hash should be null for anonymous SignatureAlgorithm - */ - public ServerKeyExchange(BigInteger par1, BigInteger par2, BigInteger par3, - byte[] hash) { - this.par1 = par1; - this.par2 = par2; - this.par3 = par3; - this.hash = hash; - - bytes1 = toUnsignedByteArray(this.par1); - - bytes2 = toUnsignedByteArray(this.par2); - - length = 4 + bytes1.length + bytes2.length; - if (hash != null) { - length += 2 + hash.length; - } - if (par3 == null) { - bytes3 = null; - return; - } - bytes3 = toUnsignedByteArray(this.par3); - length += 2 + bytes3.length; - } - - /** - * Remove first byte if 0. Needed because BigInteger.toByteArray() sometimes - * returns a zero prefix. - */ - public static byte[] toUnsignedByteArray(BigInteger bi) { - if (bi == null) { - return null; - } - byte[] bb = bi.toByteArray(); - // bb is not null, and has at least 1 byte - ZERO is represented as [0] - if (bb[0] == 0) { - byte[] noZero = new byte[bb.length - 1]; - System.arraycopy(bb, 1, noZero, 0, noZero.length); - return noZero; - } else { - return bb; - } - } - - /** - * Creates inbound message - * @param in - * @param length - * @param keyExchange - * @throws IOException - */ - public ServerKeyExchange(HandshakeIODataStream in, int length, - int keyExchange) throws IOException { - - int size = in.readUint16(); - bytes1 = in.read(size); - par1 = new BigInteger(1, bytes1); - this.length = 2 + bytes1.length; - size = in.readUint16(); - bytes2 = in.read(size); - par2 = new BigInteger(1, bytes2); - this.length += 2 + bytes2.length; - if (keyExchange != CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { - size = in.readUint16(); - bytes3 = in.read(size); - par3 = new BigInteger(1, bytes3); - this.length += 2 + bytes3.length; - } else { - par3 = null; - bytes3 = null; - } - if (keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT - && keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon) { - size = in.readUint16(); - hash = in.read(size); - this.length += 2 + hash.length; - } else { - hash = null; - } - if (this.length != length) { - fatalAlert(AlertProtocol.DECODE_ERROR, - "DECODE ERROR: incorrect ServerKeyExchange"); - } - } - - /** - * Sends message - * @param out - */ - @Override - public void send(HandshakeIODataStream out) { - out.writeUint16(bytes1.length); - out.write(bytes1); - out.writeUint16(bytes2.length); - out.write(bytes2); - if (bytes3 != null) { - out.writeUint16(bytes3.length); - out.write(bytes3); - } - if (hash != null) { - out.writeUint16(hash.length); - out.write(hash); - } - } - - /** - * Returns RSAPublicKey generated using ServerRSAParams - * (rsa_modulus and rsa_exponent). - * - * @return - */ - public RSAPublicKey getRSAPublicKey() { - if (key != null) { - return key; - } - try { - KeyFactory kf = KeyFactory.getInstance("RSA"); - key = (RSAPublicKey) kf.generatePublic(new RSAPublicKeySpec(par1, - par2)); - } catch (Exception e) { - return null; - } - return key; - } - - /** - * Returns message type - * @return - */ - @Override - public int getType() { - return Handshake.SERVER_KEY_EXCHANGE; - } - -} diff --git a/crypto/src/main/java/org/conscrypt/ServerSessionContext.java b/crypto/src/main/java/org/conscrypt/ServerSessionContext.java deleted file mode 100644 index 8bd8b0f..0000000 --- a/crypto/src/main/java/org/conscrypt/ServerSessionContext.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import javax.net.ssl.SSLSession; - -/** - * Caches server sessions. Indexes by session ID. Users typically look up - * sessions using the ID provided by an SSL client. - */ -public class ServerSessionContext extends AbstractSessionContext { - - private SSLServerSessionCache persistentCache; - - public ServerSessionContext() { - super(100, 0); - - // TODO make sure SSL_CTX does not automaticaly clear sessions we want it to cache - // SSL_CTX_set_session_cache_mode(sslCtxNativePointer, SSL_SESS_CACHE_NO_AUTO_CLEAR); - - // TODO remove SSL_CTX session cache limit so we can manage it - // SSL_CTX_sess_set_cache_size(sslCtxNativePointer, 0); - - // TODO override trimToSize and removeEldestEntry to use - // SSL_CTX_sessions to remove from native cache - - // Set a trivial session id context. OpenSSL uses this to make - // sure you don't reuse sessions externalized with i2d_SSL_SESSION - // between apps. However our sessions are either in memory or - // exported to a app's SSLServerSessionCache. - NativeCrypto.SSL_CTX_set_session_id_context(sslCtxNativePointer, new byte[] { ' ' }); - } - - public void setPersistentCache(SSLServerSessionCache persistentCache) { - this.persistentCache = persistentCache; - } - - protected void sessionRemoved(SSLSession session) {} - - @Override - public SSLSession getSession(byte[] sessionId) { - SSLSession session = super.getSession(sessionId); - if (session != null) { - return session; - } - - // Check persistent cache. - if (persistentCache != null) { - byte[] data = persistentCache.getSessionData(sessionId); - if (data != null) { - session = toSession(data, null, -1); - if (session != null && session.isValid()) { - super.putSession(session); - return session; - } - } - } - - return null; - } - - @Override - void putSession(SSLSession session) { - super.putSession(session); - - // TODO: In background thread. - if (persistentCache != null) { - byte[] data = toBytes(session); - if (data != null) { - persistentCache.putSessionData(session, data); - } - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/TrustManagerFactoryImpl.java b/crypto/src/main/java/org/conscrypt/TrustManagerFactoryImpl.java deleted file mode 100644 index 150d018..0000000 --- a/crypto/src/main/java/org/conscrypt/TrustManagerFactoryImpl.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import javax.net.ssl.ManagerFactoryParameters; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactorySpi; - -/** - * - * TrustManagerFactory service provider interface implementation. - * - * @see javax.net.ssl.TrustManagerFactorySpi - */ -public class TrustManagerFactoryImpl extends TrustManagerFactorySpi { - - private KeyStore keyStore; - - /** - * @see javax.net.ssl.TrustManagerFactorySpi#engineInit(KeyStore) - */ - @Override - public void engineInit(KeyStore ks) throws KeyStoreException { - if (ks != null) { - keyStore = ks; - } else { - keyStore = KeyStore.getInstance("AndroidCAStore"); - try { - keyStore.load(null, null); - } catch (IOException e) { - throw new KeyStoreException(e); - } catch (CertificateException e) { - throw new KeyStoreException(e); - } catch (NoSuchAlgorithmException e) { - throw new KeyStoreException(e); - } - } - } - - /** - * @see javax.net.ssl#engineInit(ManagerFactoryParameters) - */ - @Override - public void engineInit(ManagerFactoryParameters spec) - throws InvalidAlgorithmParameterException { - throw new InvalidAlgorithmParameterException( - "ManagerFactoryParameters not supported"); - } - - /** - * @see javax.net.ssl#engineGetTrustManagers() - */ - @Override - public TrustManager[] engineGetTrustManagers() { - if (keyStore == null) { - throw new IllegalStateException( - "TrustManagerFactory is not initialized"); - } - return new TrustManager[] { new TrustManagerImpl(keyStore) }; - } -} diff --git a/crypto/src/main/java/org/conscrypt/TrustManagerImpl.java b/crypto/src/main/java/org/conscrypt/TrustManagerImpl.java deleted file mode 100644 index ef366d2..0000000 --- a/crypto/src/main/java/org/conscrypt/TrustManagerImpl.java +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.cert.CertPath; -import java.security.cert.CertPathValidator; -import java.security.cert.CertPathValidatorException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateParsingException; -import java.security.cert.CertificateFactory; -import java.security.cert.PKIXCertPathChecker; -import java.security.cert.PKIXParameters; -import java.security.cert.TrustAnchor; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.net.ssl.X509TrustManager; -import libcore.io.EventLogger; - -/** - * - * TrustManager implementation. The implementation is based on CertPathValidator - * PKIX and CertificateFactory X509 implementations. This implementations should - * be provided by some certification provider. - * - * @see javax.net.ssl.X509TrustManager - */ -public final class TrustManagerImpl implements X509TrustManager { - - /** - * The AndroidCAStore if non-null, null otherwise. - */ - private final KeyStore rootKeyStore; - - /** - * The CertPinManager, which validates the chain against a host-to-pin mapping - */ - private CertPinManager pinManager; - - /** - * The backing store for the AndroidCAStore if non-null. This will - * be null when the rootKeyStore is null, implying we are not - * using the AndroidCAStore. - */ - private final TrustedCertificateStore trustedCertificateStore; - - private final CertPathValidator validator; - - /** - * An index of TrustAnchor instances that we've seen. Unlike the - * TrustedCertificateStore, this may contain intermediate CAs. - */ - private final TrustedCertificateIndex trustedCertificateIndex; - - /** - * This is lazily initialized in the AndroidCAStore case since it - * forces us to bring all the CAs into memory. In the - * non-AndroidCAStore, we initialize this as part of the - * constructor. - */ - private final X509Certificate[] acceptedIssuers; - - private final Exception err; - private final CertificateFactory factory; - - /** - * Creates X509TrustManager based on a keystore - * - * @param ks - */ - public TrustManagerImpl(KeyStore keyStore) { - this(keyStore, null); - } - - /** - * For testing only - */ - public TrustManagerImpl(KeyStore keyStore, CertPinManager manager) { - CertPathValidator validatorLocal = null; - CertificateFactory factoryLocal = null; - KeyStore rootKeyStoreLocal = null; - TrustedCertificateStore trustedCertificateStoreLocal = null; - TrustedCertificateIndex trustedCertificateIndexLocal = null; - X509Certificate[] acceptedIssuersLocal = null; - Exception errLocal = null; - try { - validatorLocal = CertPathValidator.getInstance("PKIX"); - factoryLocal = CertificateFactory.getInstance("X509"); - - // if we have an AndroidCAStore, we will lazily load CAs - if ("AndroidCAStore".equals(keyStore.getType())) { - rootKeyStoreLocal = keyStore; - trustedCertificateStoreLocal = new TrustedCertificateStore(); - acceptedIssuersLocal = null; - trustedCertificateIndexLocal = new TrustedCertificateIndex(); - } else { - rootKeyStoreLocal = null; - trustedCertificateStoreLocal = null; - acceptedIssuersLocal = acceptedIssuers(keyStore); - trustedCertificateIndexLocal - = new TrustedCertificateIndex(trustAnchors(acceptedIssuersLocal)); - } - - } catch (Exception e) { - errLocal = e; - } - - if (manager != null) { - this.pinManager = manager; - } else { - try { - pinManager = new CertPinManager(trustedCertificateStoreLocal); - } catch (PinManagerException e) { - throw new SecurityException("Could not initialize CertPinManager", e); - } - } - - this.rootKeyStore = rootKeyStoreLocal; - this.trustedCertificateStore = trustedCertificateStoreLocal; - this.validator = validatorLocal; - this.factory = factoryLocal; - this.trustedCertificateIndex = trustedCertificateIndexLocal; - this.acceptedIssuers = acceptedIssuersLocal; - this.err = errLocal; - } - - private static X509Certificate[] acceptedIssuers(KeyStore ks) { - try { - // Note that unlike the PKIXParameters code to create a Set of - // TrustAnchors from a KeyStore, this version takes from both - // TrustedCertificateEntry and PrivateKeyEntry, not just - // TrustedCertificateEntry, which is why TrustManagerImpl - // cannot just use an PKIXParameters(KeyStore) - // constructor. - - // TODO remove duplicates if same cert is found in both a - // PrivateKeyEntry and TrustedCertificateEntry - List<X509Certificate> trusted = new ArrayList<X509Certificate>(); - for (Enumeration<String> en = ks.aliases(); en.hasMoreElements();) { - final String alias = en.nextElement(); - final X509Certificate cert = (X509Certificate) ks.getCertificate(alias); - if (cert != null) { - trusted.add(cert); - } - } - return trusted.toArray(new X509Certificate[trusted.size()]); - } catch (KeyStoreException e) { - return new X509Certificate[0]; - } - } - - private static Set<TrustAnchor> trustAnchors(X509Certificate[] certs) { - Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>(certs.length); - for (X509Certificate cert : certs) { - trustAnchors.add(new TrustAnchor(cert, null)); - } - return trustAnchors; - } - - @Override public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - checkTrusted(chain, authType, null, true); - } - - @Override public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - checkTrusted(chain, authType, null, false); - } - - /** - * Validates whether a server is trusted. If hostname is given and non-null it also checks if - * chain is pinned appropriately for that host. If null, it does not check for pinned certs. - * The return value is a list of the certificates used for making the trust decision. - */ - public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType, - String host) throws CertificateException { - return checkTrusted(chain, authType, host, false); - } - - public void handleTrustStorageUpdate() { - if (acceptedIssuers == null) { - trustedCertificateIndex.reset(); - } else { - trustedCertificateIndex.reset(trustAnchors(acceptedIssuers)); - } - } - - private List<X509Certificate> checkTrusted(X509Certificate[] chain, String authType, - String host, boolean clientAuth) - throws CertificateException { - if (chain == null || chain.length == 0 || authType == null || authType.length() == 0) { - throw new IllegalArgumentException("null or zero-length parameter"); - } - if (err != null) { - throw new CertificateException(err); - } - - // get the cleaned up chain and trust anchor - Set<TrustAnchor> trustAnchor = new HashSet<TrustAnchor>(); // there can only be one! - X509Certificate[] newChain = cleanupCertChainAndFindTrustAnchors(chain, trustAnchor); - - // add the first trust anchor to the chain, which may be an intermediate - List<X509Certificate> wholeChain = new ArrayList<X509Certificate>(); - wholeChain.addAll(Arrays.asList(newChain)); - // trustAnchor is actually just a single element - for (TrustAnchor trust : trustAnchor) { - wholeChain.add(trust.getTrustedCert()); - } - - // add all the cached certificates from the cert index, avoiding loops - // this gives us a full chain from leaf to root, which we use for cert pinning and pass - // back out to callers when we return. - X509Certificate last = wholeChain.get(wholeChain.size() - 1); - while (true) { - TrustAnchor cachedTrust = trustedCertificateIndex.findByIssuerAndSignature(last); - // the cachedTrust can be null if there isn't anything in the index or if a user has - // trusted a non-self-signed cert. - if (cachedTrust == null) { - break; - } - - // at this point we have a cached trust anchor, but don't know if its one we got from - // the server. Extract the cert, compare it to the last element in the chain, and add it - // if we haven't seen it before. - X509Certificate next = cachedTrust.getTrustedCert(); - if (next != last) { - wholeChain.add(next); - last = next; - } else { - // if next == last then we found a self-signed cert and the chain is done - break; - } - } - - // build the cert path from the array of certs sans trust anchors - CertPath certPath = factory.generateCertPath(Arrays.asList(newChain)); - - if (host != null) { - boolean chainIsNotPinned = true; - try { - chainIsNotPinned = pinManager.chainIsNotPinned(host, wholeChain); - } catch (PinManagerException e) { - throw new CertificateException(e); - } - if (chainIsNotPinned) { - throw new CertificateException(new CertPathValidatorException( - "Certificate path is not properly pinned.", null, certPath, -1)); - } - } - - if (newChain.length == 0) { - // chain was entirely trusted, skip the validator - return wholeChain; - } - - if (trustAnchor.isEmpty()) { - throw new CertificateException(new CertPathValidatorException( - "Trust anchor for certification path not found.", null, certPath, -1)); - } - - // There's no point in checking trust anchors here, and it will throw off the MD5 check, - // so we just hand it the chain without anchors - ChainStrengthAnalyzer.check(newChain); - - try { - PKIXParameters params = new PKIXParameters(trustAnchor); - params.setRevocationEnabled(false); - params.addCertPathChecker(new ExtendedKeyUsagePKIXCertPathChecker(clientAuth, - newChain[0])); - validator.validate(certPath, params); - // Add intermediate CAs to the index to tolerate sites - // that assume that the browser will have cached these. - // The server certificate is skipped by skipping the - // zeroth element of new chain and note that the root CA - // will have been removed in - // cleanupCertChainAndFindTrustAnchors. http://b/3404902 - for (int i = 1; i < newChain.length; i++) { - trustedCertificateIndex.index(newChain[i]); - } - } catch (InvalidAlgorithmParameterException e) { - throw new CertificateException(e); - } catch (CertPathValidatorException e) { - throw new CertificateException(e); - } - - return wholeChain; - } - - /** - * Clean up the certificate chain, returning a cleaned up chain, - * which may be a new array instance if elements were removed. - * Theoretically, we shouldn't have to do this, but various web - * servers in practice are mis-configured to have out-of-order - * certificates, expired self-issued root certificate, or CAs with - * unsupported signature algorithms such as - * md2WithRSAEncryption. This also handles removing old certs - * after bridge CA certs. - */ - private X509Certificate[] cleanupCertChainAndFindTrustAnchors(X509Certificate[] chain, - Set<TrustAnchor> trustAnchors) { - X509Certificate[] original = chain; - - // 1. Clean the received certificates chain. - int currIndex; - // Start with the first certificate in the chain, assuming it - // is the leaf certificate (server or client cert). - for (currIndex = 0; currIndex < chain.length; currIndex++) { - // Walk the chain to find a "subject" matching - // the "issuer" of the current certificate. In a properly - // ordered chain this should be the next cert and be fast. - // If not, we reorder things to be as the validator will - // expect. - boolean foundNext = false; - for (int nextIndex = currIndex + 1; nextIndex < chain.length; nextIndex++) { - if (chain[currIndex].getIssuerDN().equals(chain[nextIndex].getSubjectDN())) { - foundNext = true; - // Exchange certificates so that 0 through currIndex + 1 are in proper order - if (nextIndex != currIndex + 1) { - // don't mutuate original chain, which may be directly from an SSLSession - if (chain == original) { - chain = original.clone(); - } - X509Certificate tempCertificate = chain[nextIndex]; - chain[nextIndex] = chain[currIndex + 1]; - chain[currIndex + 1] = tempCertificate; - } - break; - } - } - // If we can't find the next in the chain, just give up - // and use what we found so far. This drops unrelated - // certificates that have nothing to do with the cert - // chain. - if (!foundNext) { - break; - } - } - - // 2. Find the trust anchor in the chain, if any - int anchorIndex; - for (anchorIndex = 0; anchorIndex <= currIndex; anchorIndex++) { - // If the current cert is a TrustAnchor, we can ignore the rest of the chain. - // This avoids including "bridge" CA certs that added for legacy compatibility. - TrustAnchor trustAnchor = findTrustAnchorBySubjectAndPublicKey(chain[anchorIndex]); - if (trustAnchor != null) { - trustAnchors.add(trustAnchor); - break; - } - } - - // 3. If the chain is now shorter, copy to an appropriately sized array. - int chainLength = anchorIndex; - X509Certificate[] newChain = ((chainLength == chain.length) - ? chain - : Arrays.copyOf(chain, chainLength)); - - // 4. If we didn't find a trust anchor earlier, look for one now - if (trustAnchors.isEmpty()) { - TrustAnchor trustAnchor = findTrustAnchorByIssuerAndSignature(newChain[anchorIndex-1]); - if (trustAnchor != null) { - trustAnchors.add(trustAnchor); - } - } - return newChain; - } - - /** - * If an EKU extension is present in the end-entity certificate, - * it MUST contain an appropriate key usage. For servers, this - * includes anyExtendedKeyUsage, serverAuth, or the historical - * Server Gated Cryptography options of nsSGC or msSGC. For - * clients, this includes anyExtendedKeyUsage and clientAuth. - */ - private static class ExtendedKeyUsagePKIXCertPathChecker extends PKIXCertPathChecker { - - private static final String EKU_OID = "2.5.29.37"; - - private static final String EKU_anyExtendedKeyUsage = "2.5.29.37.0"; - private static final String EKU_clientAuth = "1.3.6.1.5.5.7.3.2"; - private static final String EKU_serverAuth = "1.3.6.1.5.5.7.3.1"; - private static final String EKU_nsSGC = "2.16.840.1.113730.4.1"; - private static final String EKU_msSGC = "1.3.6.1.4.1.311.10.3.3"; - - private static final Set<String> SUPPORTED_EXTENSIONS - = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(EKU_OID))); - - private final boolean clientAuth; - private final X509Certificate leaf; - - private ExtendedKeyUsagePKIXCertPathChecker(boolean clientAuth, X509Certificate leaf) { - this.clientAuth = clientAuth; - this.leaf = leaf; - } - - @Override public void init(boolean forward) throws CertPathValidatorException { - } - - @Override public boolean isForwardCheckingSupported() { - return true; - } - - @Override public Set<String> getSupportedExtensions() { - return SUPPORTED_EXTENSIONS; - } - - @Override public void check(Certificate c, Collection<String> unresolvedCritExts) - throws CertPathValidatorException { - // We only want to validate the EKU on the leaf certificate. - if (c != leaf) { - return; - } - List<String> ekuOids; - try { - ekuOids = leaf.getExtendedKeyUsage(); - } catch (CertificateParsingException e) { - // A malformed EKU is bad news, consider it fatal. - throw new CertPathValidatorException(e); - } - // We are here to check EKU, but there is none. - if (ekuOids == null) { - return; - } - - boolean goodExtendedKeyUsage = false; - for (String ekuOid : ekuOids) { - // anyExtendedKeyUsage for clients and servers - if (ekuOid.equals(EKU_anyExtendedKeyUsage)) { - goodExtendedKeyUsage = true; - break; - } - - // clients - if (clientAuth) { - if (ekuOid.equals(EKU_clientAuth)) { - goodExtendedKeyUsage = true; - break; - } - continue; - } - - // servers - if (ekuOid.equals(EKU_serverAuth)) { - goodExtendedKeyUsage = true; - break; - } - if (ekuOid.equals(EKU_nsSGC)) { - goodExtendedKeyUsage = true; - break; - } - if (ekuOid.equals(EKU_msSGC)) { - goodExtendedKeyUsage = true; - break; - } - } - if (goodExtendedKeyUsage) { - // Mark extendedKeyUsage as resolved if present. - unresolvedCritExts.remove(EKU_OID); - } else { - throw new CertPathValidatorException("End-entity certificate does not have a valid " - + "extendedKeyUsage."); - } - } - } - - private TrustAnchor findTrustAnchorByIssuerAndSignature(X509Certificate lastCert) { - TrustAnchor trustAnchor = trustedCertificateIndex.findByIssuerAndSignature(lastCert); - if (trustAnchor != null) { - return trustAnchor; - } - if (trustedCertificateStore == null) { - return null; - } - // we have a KeyStore and the issuer of the last cert in - // the chain seems to be missing from the - // TrustedCertificateIndex, check the KeyStore for a hit - X509Certificate issuer = trustedCertificateStore.findIssuer(lastCert); - if (issuer != null) { - return trustedCertificateIndex.index(issuer); - } - return null; - } - - /** - * Check the trustedCertificateIndex for the cert to see if it is - * already trusted and failing that check the KeyStore if it is - * available. - */ - private TrustAnchor findTrustAnchorBySubjectAndPublicKey(X509Certificate cert) { - TrustAnchor trustAnchor = trustedCertificateIndex.findBySubjectAndPublicKey(cert); - if (trustAnchor != null) { - return trustAnchor; - } - if (trustedCertificateStore == null) { - // not trusted and no TrustedCertificateStore to check - return null; - } - // probe KeyStore for a cert. AndroidCAStore stores its - // contents hashed by cert subject on the filesystem to make - // this faster than scanning all key store entries. - if (trustedCertificateStore.isTrustAnchor(cert)) { - // add new TrustAnchor to params index to avoid - // checking filesystem next time around. - return trustedCertificateIndex.index(cert); - } - return null; - } - - @Override public X509Certificate[] getAcceptedIssuers() { - return (acceptedIssuers != null) ? acceptedIssuers.clone() : acceptedIssuers(rootKeyStore); - } -} diff --git a/crypto/src/main/java/org/conscrypt/TrustedCertificateIndex.java b/crypto/src/main/java/org/conscrypt/TrustedCertificateIndex.java deleted file mode 100644 index b322cd1..0000000 --- a/crypto/src/main/java/org/conscrypt/TrustedCertificateIndex.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.PublicKey; -import java.security.cert.CertPathValidatorException; -import java.security.cert.TrustAnchor; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.security.auth.x500.X500Principal; - -/** - * Indexes {@code TrustAnchor} instances so they can be found in O(1) - * time instead of O(N). - */ -public final class TrustedCertificateIndex { - - private final Map<X500Principal, List<TrustAnchor>> subjectToTrustAnchors - = new HashMap<X500Principal, List<TrustAnchor>>(); - - public TrustedCertificateIndex() {} - - public TrustedCertificateIndex(Set<TrustAnchor> anchors) { - index(anchors); - } - - private void index(Set<TrustAnchor> anchors) { - for (TrustAnchor anchor : anchors) { - index(anchor); - } - } - - public TrustAnchor index(X509Certificate cert) { - TrustAnchor anchor = new TrustAnchor(cert, null); - index(anchor); - return anchor; - } - - public void index(TrustAnchor anchor) { - X500Principal subject; - X509Certificate cert = anchor.getTrustedCert(); - if (cert != null) { - subject = cert.getSubjectX500Principal(); - } else { - subject = anchor.getCA(); - } - - synchronized (subjectToTrustAnchors) { - List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject); - if (anchors == null) { - anchors = new ArrayList<TrustAnchor>(1); - subjectToTrustAnchors.put(subject, anchors); - } - anchors.add(anchor); - } - } - - public void reset() { - synchronized (subjectToTrustAnchors) { - subjectToTrustAnchors.clear(); - } - } - - public void reset(Set<TrustAnchor> anchors) { - synchronized (subjectToTrustAnchors) { - reset(); - index(anchors); - } - } - - public TrustAnchor findByIssuerAndSignature(X509Certificate cert) { - X500Principal issuer = cert.getIssuerX500Principal(); - synchronized (subjectToTrustAnchors) { - List<TrustAnchor> anchors = subjectToTrustAnchors.get(issuer); - if (anchors == null) { - return null; - } - - for (TrustAnchor anchor : anchors) { - PublicKey publicKey; - try { - X509Certificate caCert = anchor.getTrustedCert(); - if (caCert != null) { - publicKey = caCert.getPublicKey(); - } else { - publicKey = anchor.getCAPublicKey(); - } - cert.verify(publicKey); - return anchor; - } catch (Exception ignored) { - } - } - } - return null; - } - - public TrustAnchor findBySubjectAndPublicKey(X509Certificate cert) { - X500Principal subject = cert.getSubjectX500Principal(); - synchronized (subjectToTrustAnchors) { - List<TrustAnchor> anchors = subjectToTrustAnchors.get(subject); - if (anchors == null) { - return null; - } - return findBySubjectAndPublicKey(cert, anchors); - } - } - - private static TrustAnchor findBySubjectAndPublicKey(X509Certificate cert, - Collection<TrustAnchor> anchors) { - PublicKey certPublicKey = cert.getPublicKey(); - for (TrustAnchor anchor : anchors) { - PublicKey caPublicKey; - try { - X509Certificate caCert = anchor.getTrustedCert(); - if (caCert != null) { - caPublicKey = caCert.getPublicKey(); - } else { - caPublicKey = anchor.getCAPublicKey(); - } - if (caPublicKey.equals(certPublicKey)) { - return anchor; - } - } catch (Exception e) { - // can happen with unsupported public key types - } - } - return null; - } -} diff --git a/crypto/src/main/java/org/conscrypt/TrustedCertificateKeyStoreSpi.java b/crypto/src/main/java/org/conscrypt/TrustedCertificateKeyStoreSpi.java deleted file mode 100644 index c2d5c33..0000000 --- a/crypto/src/main/java/org/conscrypt/TrustedCertificateKeyStoreSpi.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2011 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.InputStream; -import java.io.OutputStream; -import java.security.Key; -import java.security.KeyStoreSpi; -import java.security.cert.Certificate; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; - -/** - * A KeyStoreSpi wrapper for the TrustedCertificateStore. - */ -public final class TrustedCertificateKeyStoreSpi extends KeyStoreSpi { - - private final TrustedCertificateStore store = new TrustedCertificateStore(); - - @Override public Key engineGetKey(String alias, char[] password) { - if (alias == null) { - throw new NullPointerException("alias == null"); - } - return null; - } - - @Override public Certificate[] engineGetCertificateChain(String alias) { - if (alias == null) { - throw new NullPointerException("alias == null"); - } - return null; - } - - @Override public Certificate engineGetCertificate(String alias) { - return store.getCertificate(alias); - } - - @Override public Date engineGetCreationDate(String alias) { - return store.getCreationDate(alias); - } - - @Override public void engineSetKeyEntry( - String alias, Key key, char[] password, Certificate[] chain) { - throw new UnsupportedOperationException(); - } - - @Override public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) { - throw new UnsupportedOperationException(); - } - - @Override public void engineSetCertificateEntry(String alias, Certificate cert) { - if (alias == null) { - throw new NullPointerException("alias == null"); - } - throw new UnsupportedOperationException(); - } - - @Override public void engineDeleteEntry(String alias) { - throw new UnsupportedOperationException(); - } - - @Override public Enumeration<String> engineAliases() { - return Collections.enumeration(store.aliases()); - } - - @Override public boolean engineContainsAlias(String alias) { - return store.containsAlias(alias); - } - - @Override public int engineSize() { - return store.aliases().size(); - } - - @Override public boolean engineIsKeyEntry(String alias) { - if (alias == null) { - throw new NullPointerException("alias == null"); - } - return false; - } - - @Override public boolean engineIsCertificateEntry(String alias) { - return engineContainsAlias(alias); - } - - @Override public String engineGetCertificateAlias(Certificate c) { - return store.getCertificateAlias(c); - } - - @Override public void engineStore(OutputStream stream, char[] password) { - throw new UnsupportedOperationException(); - } - - @Override public void engineLoad(InputStream stream, char[] password) { - if (stream != null) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/TrustedCertificateStore.java b/crypto/src/main/java/org/conscrypt/TrustedCertificateStore.java deleted file mode 100644 index 1356776..0000000 --- a/crypto/src/main/java/org/conscrypt/TrustedCertificateStore.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (C) 2011 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.security.auth.x500.X500Principal; -import libcore.io.IoUtils; - -/** - * A source for trusted root certificate authority (CA) certificates - * supporting an immutable system CA directory along with mutable - * directories allowing the user addition of custom CAs and user - * removal of system CAs. This store supports the {@code - * TrustedCertificateKeyStoreSpi} wrapper to allow a traditional - * KeyStore interface for use with {@link - * javax.net.ssl.TrustManagerFactory.init}. - * - * <p>The CAs are accessed via {@code KeyStore} style aliases. Aliases - * are made up of a prefix identifying the source ("system:" vs - * "user:") and a suffix based on the OpenSSL X509_NAME_hash_old - * function of the CA's subject name. For example, the system CA for - * "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification - * Authority" could be represented as "system:7651b327.0". By using - * the subject hash, operations such as {@link #getCertificateAlias - * getCertificateAlias} can be implemented efficiently without - * scanning the entire store. - * - * <p>In addition to supporting the {@code - * TrustedCertificateKeyStoreSpi} implementation, {@code - * TrustedCertificateStore} also provides the additional public - * methods {@link #isTrustAnchor} and {@link #findIssuer} to allow - * efficient lookup operations for CAs again based on the file naming - * convention. - * - * <p>The KeyChainService users the {@link installCertificate} and - * {@link #deleteCertificateEntry} to install user CAs as well as - * delete those user CAs as well as system CAs. The deletion of system - * CAs is performed by placing an exact copy of that CA in the deleted - * directory. Such deletions are intended to persist across upgrades - * but not intended to mask a CA with a matching name or public key - * but is otherwise reissued in a system update. Reinstalling a - * deleted system certificate simply removes the copy from the deleted - * directory, reenabling the original in the system directory. - * - * <p>Note that the default mutable directory is created by init via - * configuration in the system/core/rootdir/init.rc file. The - * directive "mkdir /data/misc/keychain 0775 system system" - * ensures that its owner and group are the system uid and system - * gid and that it is world readable but only writable by the system - * user. - */ -public final class TrustedCertificateStore { - - private static final String PREFIX_SYSTEM = "system:"; - private static final String PREFIX_USER = "user:"; - - public static final boolean isSystem(String alias) { - return alias.startsWith(PREFIX_SYSTEM); - } - public static final boolean isUser(String alias) { - return alias.startsWith(PREFIX_USER); - } - - private static final File CA_CERTS_DIR_SYSTEM; - private static final File CA_CERTS_DIR_ADDED; - private static final File CA_CERTS_DIR_DELETED; - private static final CertificateFactory CERT_FACTORY; - static { - String ANDROID_ROOT = System.getenv("ANDROID_ROOT"); - String ANDROID_DATA = System.getenv("ANDROID_DATA"); - CA_CERTS_DIR_SYSTEM = new File(ANDROID_ROOT + "/etc/security/cacerts"); - CA_CERTS_DIR_ADDED = new File(ANDROID_DATA + "/misc/keychain/cacerts-added"); - CA_CERTS_DIR_DELETED = new File(ANDROID_DATA + "/misc/keychain/cacerts-removed"); - - try { - CERT_FACTORY = CertificateFactory.getInstance("X509"); - } catch (CertificateException e) { - throw new AssertionError(e); - } - } - - private final File systemDir; - private final File addedDir; - private final File deletedDir; - - public TrustedCertificateStore() { - this(CA_CERTS_DIR_SYSTEM, CA_CERTS_DIR_ADDED, CA_CERTS_DIR_DELETED); - } - - public TrustedCertificateStore(File systemDir, File addedDir, File deletedDir) { - this.systemDir = systemDir; - this.addedDir = addedDir; - this.deletedDir = deletedDir; - } - - public Certificate getCertificate(String alias) { - return getCertificate(alias, false); - } - - public Certificate getCertificate(String alias, boolean includeDeletedSystem) { - - File file = fileForAlias(alias); - if (file == null || (isUser(alias) && isTombstone(file))) { - return null; - } - X509Certificate cert = readCertificate(file); - if (cert == null || (isSystem(alias) - && !includeDeletedSystem - && isDeletedSystemCertificate(cert))) { - // skip malformed certs as well as deleted system ones - return null; - } - return cert; - } - - private File fileForAlias(String alias) { - if (alias == null) { - throw new NullPointerException("alias == null"); - } - File file; - if (isSystem(alias)) { - file = new File(systemDir, alias.substring(PREFIX_SYSTEM.length())); - } else if (isUser(alias)) { - file = new File(addedDir, alias.substring(PREFIX_USER.length())); - } else { - return null; - } - if (!file.exists() || isTombstone(file)) { - // silently elide tombstones - return null; - } - return file; - } - - private boolean isTombstone(File file) { - return file.length() == 0; - } - - private X509Certificate readCertificate(File file) { - if (!file.isFile()) { - return null; - } - InputStream is = null; - try { - is = new BufferedInputStream(new FileInputStream(file)); - return (X509Certificate) CERT_FACTORY.generateCertificate(is); - } catch (IOException e) { - return null; - } catch (CertificateException e) { - // reading a cert while its being installed can lead to this. - // just pretend like its not available yet. - return null; - } finally { - IoUtils.closeQuietly(is); - } - } - - private void writeCertificate(File file, X509Certificate cert) - throws IOException, CertificateException { - File dir = file.getParentFile(); - dir.mkdirs(); - dir.setReadable(true, false); - dir.setExecutable(true, false); - OutputStream os = null; - try { - os = new FileOutputStream(file); - os.write(cert.getEncoded()); - } finally { - IoUtils.closeQuietly(os); - } - file.setReadable(true, false); - } - - private boolean isDeletedSystemCertificate(X509Certificate x) { - return getCertificateFile(deletedDir, x).exists(); - } - - public Date getCreationDate(String alias) { - // containsAlias check ensures the later fileForAlias result - // was not a deleted system cert. - if (!containsAlias(alias)) { - return null; - } - File file = fileForAlias(alias); - if (file == null) { - return null; - } - long time = file.lastModified(); - if (time == 0) { - return null; - } - return new Date(time); - } - - public Set<String> aliases() { - Set<String> result = new HashSet<String>(); - addAliases(result, PREFIX_USER, addedDir); - addAliases(result, PREFIX_SYSTEM, systemDir); - return result; - } - - public Set<String> userAliases() { - Set<String> result = new HashSet<String>(); - addAliases(result, PREFIX_USER, addedDir); - return result; - } - - private void addAliases(Set<String> result, String prefix, File dir) { - String[] files = dir.list(); - if (files == null) { - return; - } - for (String filename : files) { - String alias = prefix + filename; - if (containsAlias(alias)) { - result.add(alias); - } - } - } - - public Set<String> allSystemAliases() { - Set<String> result = new HashSet<String>(); - String[] files = systemDir.list(); - if (files == null) { - return result; - } - for (String filename : files) { - String alias = PREFIX_SYSTEM + filename; - if (containsAlias(alias, true)) { - result.add(alias); - } - } - return result; - } - - public boolean containsAlias(String alias) { - return containsAlias(alias, false); - } - - private boolean containsAlias(String alias, boolean includeDeletedSystem) { - return getCertificate(alias, includeDeletedSystem) != null; - } - - public String getCertificateAlias(Certificate c) { - if (c == null || !(c instanceof X509Certificate)) { - return null; - } - X509Certificate x = (X509Certificate) c; - File user = getCertificateFile(addedDir, x); - if (user.exists()) { - return PREFIX_USER + user.getName(); - } - if (isDeletedSystemCertificate(x)) { - return null; - } - File system = getCertificateFile(systemDir, x); - if (system.exists()) { - return PREFIX_SYSTEM + system.getName(); - } - return null; - } - - /** - * Returns true to indicate that the certificate was added by the - * user, false otherwise. - */ - public boolean isUserAddedCertificate(X509Certificate cert) { - return getCertificateFile(addedDir, cert).exists(); - } - - /** - * Returns a File for where the certificate is found if it exists - * or where it should be installed if it does not exist. The - * caller can disambiguate these cases by calling {@code - * File.exists()} on the result. - */ - private File getCertificateFile(File dir, final X509Certificate x) { - // compare X509Certificate.getEncoded values - CertSelector selector = new CertSelector() { - @Override public boolean match(X509Certificate cert) { - return cert.equals(x); - } - }; - return findCert(dir, x.getSubjectX500Principal(), selector, File.class); - } - - /** - * This non-{@code KeyStoreSpi} public interface is used by {@code - * TrustManagerImpl} to locate a CA certificate with the same name - * and public key as the provided {@code X509Certificate}. We - * match on the name and public key and not the entire certificate - * since a CA may be reissued with the same name and PublicKey but - * with other differences (for example when switching signature - * from md2WithRSAEncryption to SHA1withRSA) - */ - public boolean isTrustAnchor(final X509Certificate c) { - // compare X509Certificate.getPublicKey values - CertSelector selector = new CertSelector() { - @Override public boolean match(X509Certificate ca) { - return ca.getPublicKey().equals(c.getPublicKey()); - } - }; - boolean user = findCert(addedDir, - c.getSubjectX500Principal(), - selector, - Boolean.class); - if (user) { - return true; - } - X509Certificate system = findCert(systemDir, - c.getSubjectX500Principal(), - selector, - X509Certificate.class); - return system != null && !isDeletedSystemCertificate(system); - } - - /** - * This non-{@code KeyStoreSpi} public interface is used by {@code - * TrustManagerImpl} to locate the CA certificate that signed the - * provided {@code X509Certificate}. - */ - public X509Certificate findIssuer(final X509Certificate c) { - // match on verified issuer of Certificate - CertSelector selector = new CertSelector() { - @Override public boolean match(X509Certificate ca) { - try { - c.verify(ca.getPublicKey()); - return true; - } catch (Exception e) { - return false; - } - } - }; - X500Principal issuer = c.getIssuerX500Principal(); - X509Certificate user = findCert(addedDir, issuer, selector, X509Certificate.class); - if (user != null) { - return user; - } - X509Certificate system = findCert(systemDir, issuer, selector, X509Certificate.class); - if (system != null && !isDeletedSystemCertificate(system)) { - return system; - } - return null; - } - - private static boolean isSelfIssuedCertificate(OpenSSLX509Certificate cert) { - final long ctx = cert.getContext(); - return NativeCrypto.X509_check_issued(ctx, ctx) == 0; - } - - /** - * Converts the {@code cert} to the internal OpenSSL X.509 format so we can - * run {@link NativeCrypto} methods on it. - */ - private static OpenSSLX509Certificate convertToOpenSSLIfNeeded(X509Certificate cert) - throws CertificateException { - if (cert == null) { - return null; - } - - if (cert instanceof OpenSSLX509Certificate) { - return (OpenSSLX509Certificate) cert; - } - - try { - return OpenSSLX509Certificate.fromX509Der(cert.getEncoded()); - } catch (Exception e) { - throw new CertificateException(e); - } - } - - /** - * Attempt to build a certificate chain from the supplied {@code leaf} - * argument through the chain of issuers as high up as known. If the chain - * can't be completed, the most complete chain available will be returned. - * This means that a list with only the {@code leaf} certificate is returned - * if no issuer certificates could be found. - * - * @throws CertificateException if there was a problem parsing the - * certificates - */ - public List<X509Certificate> getCertificateChain(X509Certificate leaf) - throws CertificateException { - final List<OpenSSLX509Certificate> chain = new ArrayList<OpenSSLX509Certificate>(); - chain.add(convertToOpenSSLIfNeeded(leaf)); - - for (int i = 0; true; i++) { - OpenSSLX509Certificate cert = chain.get(i); - if (isSelfIssuedCertificate(cert)) { - break; - } - OpenSSLX509Certificate issuer = convertToOpenSSLIfNeeded(findIssuer(cert)); - if (issuer == null) { - break; - } - chain.add(issuer); - } - - return new ArrayList<X509Certificate>(chain); - } - - // like java.security.cert.CertSelector but with X509Certificate and without cloning - private static interface CertSelector { - public boolean match(X509Certificate cert); - } - - private <T> T findCert( - File dir, X500Principal subject, CertSelector selector, Class<T> desiredReturnType) { - - String hash = hash(subject); - for (int index = 0; true; index++) { - File file = file(dir, hash, index); - if (!file.isFile()) { - // could not find a match, no file exists, bail - if (desiredReturnType == Boolean.class) { - return (T) Boolean.FALSE; - } - if (desiredReturnType == File.class) { - // we return file so that caller that wants to - // write knows what the next available has - // location is - return (T) file; - } - return null; - } - if (isTombstone(file)) { - continue; - } - X509Certificate cert = readCertificate(file); - if (cert == null) { - // skip problem certificates - continue; - } - if (selector.match(cert)) { - if (desiredReturnType == X509Certificate.class) { - return (T) cert; - } - if (desiredReturnType == Boolean.class) { - return (T) Boolean.TRUE; - } - if (desiredReturnType == File.class) { - return (T) file; - } - throw new AssertionError(); - } - } - } - - private String hash(X500Principal name) { - int hash = NativeCrypto.X509_NAME_hash_old(name); - return IntegralToString.intToHexString(hash, false, 8); - } - - private File file(File dir, String hash, int index) { - return new File(dir, hash + '.' + index); - } - - /** - * This non-{@code KeyStoreSpi} public interface is used by the - * {@code KeyChainService} to install new CA certificates. It - * silently ignores the certificate if it already exists in the - * store. - */ - public void installCertificate(X509Certificate cert) throws IOException, CertificateException { - if (cert == null) { - throw new NullPointerException("cert == null"); - } - File system = getCertificateFile(systemDir, cert); - if (system.exists()) { - File deleted = getCertificateFile(deletedDir, cert); - if (deleted.exists()) { - // we have a system cert that was marked deleted. - // remove the deleted marker to expose the original - if (!deleted.delete()) { - throw new IOException("Could not remove " + deleted); - } - return; - } - // otherwise we just have a dup of an existing system cert. - // return taking no further action. - return; - } - File user = getCertificateFile(addedDir, cert); - if (user.exists()) { - // we have an already installed user cert, bail. - return; - } - // install the user cert - writeCertificate(user, cert); - } - - /** - * This could be considered the implementation of {@code - * TrustedCertificateKeyStoreSpi.engineDeleteEntry} but we - * consider {@code TrustedCertificateKeyStoreSpi} to be read - * only. Instead, this is used by the {@code KeyChainService} to - * delete CA certificates. - */ - public void deleteCertificateEntry(String alias) throws IOException, CertificateException { - if (alias == null) { - return; - } - File file = fileForAlias(alias); - if (file == null) { - return; - } - if (isSystem(alias)) { - X509Certificate cert = readCertificate(file); - if (cert == null) { - // skip problem certificates - return; - } - File deleted = getCertificateFile(deletedDir, cert); - if (deleted.exists()) { - // already deleted system certificate - return; - } - // write copy of system cert to marked as deleted - writeCertificate(deleted, cert); - return; - } - if (isUser(alias)) { - // truncate the file to make a tombstone by opening and closing. - // we need ensure that we don't leave a gap before a valid cert. - new FileOutputStream(file).close(); - removeUnnecessaryTombstones(alias); - return; - } - // non-existant user cert, nothing to delete - } - - private void removeUnnecessaryTombstones(String alias) throws IOException { - if (!isUser(alias)) { - throw new AssertionError(alias); - } - int dotIndex = alias.lastIndexOf('.'); - if (dotIndex == -1) { - throw new AssertionError(alias); - } - - String hash = alias.substring(PREFIX_USER.length(), dotIndex); - int lastTombstoneIndex = Integer.parseInt(alias.substring(dotIndex + 1)); - - if (file(addedDir, hash, lastTombstoneIndex + 1).exists()) { - return; - } - while (lastTombstoneIndex >= 0) { - File file = file(addedDir, hash, lastTombstoneIndex); - if (!isTombstone(file)) { - break; - } - if (!file.delete()) { - throw new IOException("Could not remove " + file); - } - lastTombstoneIndex--; - } - } -} diff --git a/crypto/src/main/java/org/conscrypt/X509PublicKey.java b/crypto/src/main/java/org/conscrypt/X509PublicKey.java deleted file mode 100644 index 8d09fc2..0000000 --- a/crypto/src/main/java/org/conscrypt/X509PublicKey.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2013 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.PublicKey; -import java.util.Arrays; - -/** - * A simple but useless key class that holds X.509 public key information when - * the appropriate KeyFactory for the key algorithm is not available. - */ -public class X509PublicKey implements PublicKey { - private static final long serialVersionUID = -8610156854731664298L; - - private final String algorithm; - - private final byte[] encoded; - - public X509PublicKey(String algorithm, byte[] encoded) { - this.algorithm = algorithm; - this.encoded = encoded; - } - - @Override - public String getAlgorithm() { - return algorithm; - } - - @Override - public String getFormat() { - return "X.509"; - } - - @Override - public byte[] getEncoded() { - return encoded; - } - - @Override - public String toString() { - return "X509PublicKey [algorithm=" + algorithm + ", encoded=" + Arrays.toString(encoded) - + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((algorithm == null) ? 0 : algorithm.hashCode()); - result = prime * result + Arrays.hashCode(encoded); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - X509PublicKey other = (X509PublicKey) obj; - if (algorithm == null) { - if (other.algorithm != null) - return false; - } else if (!algorithm.equals(other.algorithm)) - return false; - if (!Arrays.equals(encoded, other.encoded)) - return false; - return true; - } -} diff --git a/crypto/src/main/java/org/conscrypt/util/EmptyArray.java b/crypto/src/main/java/org/conscrypt/util/EmptyArray.java deleted file mode 100644 index e474562..0000000 --- a/crypto/src/main/java/org/conscrypt/util/EmptyArray.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ - -// Copied from libcore.util.EmptyArray - -package org.conscrypt.util; - -public final class EmptyArray { - private EmptyArray() {} - - public static final boolean[] BOOLEAN = new boolean[0]; - public static final byte[] BYTE = new byte[0]; - public static final char[] CHAR = new char[0]; - public static final double[] DOUBLE = new double[0]; - public static final int[] INT = new int[0]; - - public static final Class<?>[] CLASS = new Class[0]; - public static final Object[] OBJECT = new Object[0]; - public static final String[] STRING = new String[0]; - public static final Throwable[] THROWABLE = new Throwable[0]; - public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0]; -}
\ No newline at end of file diff --git a/crypto/src/main/native/org_conscrypt_NativeCrypto.cpp b/crypto/src/main/native/org_conscrypt_NativeCrypto.cpp deleted file mode 100644 index 0a95fc3..0000000 --- a/crypto/src/main/native/org_conscrypt_NativeCrypto.cpp +++ /dev/null @@ -1,8195 +0,0 @@ -/* - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt.NativeCrypto - */ - -#define TO_STRING1(x) #x -#define TO_STRING(x) TO_STRING1(x) -#ifndef JNI_JARJAR_PREFIX -#define CONSCRYPT_UNBUNDLED -#define JNI_JARJAR_PREFIX -#endif - -#define LOG_TAG "NativeCrypto" - -#include <arpa/inet.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <unistd.h> - -#include <jni.h> - -#include <openssl/asn1t.h> -#include <openssl/dsa.h> -#include <openssl/engine.h> -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/rand.h> -#include <openssl/rsa.h> -#include <openssl/ssl.h> -#include <openssl/x509v3.h> - -#include "AsynchronousSocketCloseMonitor.h" -#include "cutils/log.h" -#include "JNIHelp.h" -#include "JniConstants.h" -#include "JniException.h" -#include "NetFd.h" -#include "ScopedLocalRef.h" -#include "ScopedPrimitiveArray.h" -#include "ScopedUtfChars.h" -#include "UniquePtr.h" - -#undef WITH_JNI_TRACE -#undef WITH_JNI_TRACE_DATA - -/* - * How to use this for debugging with Wireshark: - * - * 1. Pull lines from logcat to a file that looks like (without quotes): - * "RSA Session-ID:... Master-Key:..." <CR> - * "RSA Session-ID:... Master-Key:..." <CR> - * <etc> - * 2. Start Wireshark - * 3. Go to Edit -> Preferences -> SSL -> (Pre-)Master-Key log and fill in - * the file you put the lines in above. - * 4. Follow the stream that corresponds to the desired "Session-ID" in - * the Server Hello. - */ -#undef WITH_JNI_TRACE_KEYS - -#ifdef WITH_JNI_TRACE -#define JNI_TRACE(...) \ - ((void)ALOG(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 - -static JavaVM* gJavaVM; -static jclass openSslOutputStreamClass; - -static jclass byteArrayClass; -static jclass calendarClass; -static jclass objectClass; -static jclass objectArrayClass; -static jclass integerClass; -static jclass inputStreamClass; -static jclass outputStreamClass; -static jclass stringClass; - -static jmethodID calendar_setMethod; -static jmethodID inputStream_readMethod; -static jmethodID integer_valueOfMethod; -static jmethodID openSslInputStream_readLineMethod; -static jmethodID outputStream_writeMethod; -static jmethodID outputStream_flushMethod; - -struct OPENSSL_Delete { - void operator()(void* p) const { - OPENSSL_free(p); - } -}; -typedef UniquePtr<unsigned char, OPENSSL_Delete> Unique_OPENSSL_str; - -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 ASN1_INTEGER_Delete { - void operator()(ASN1_INTEGER* p) const { - ASN1_INTEGER_free(p); - } -}; -typedef UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> Unique_ASN1_INTEGER; - -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_GROUP_Delete { - void operator()(EC_GROUP* p) const { - EC_GROUP_clear_free(p); - } -}; -typedef UniquePtr<EC_GROUP, EC_GROUP_Delete> Unique_EC_GROUP; - -struct EC_POINT_Delete { - void operator()(EC_POINT* p) const { - EC_POINT_clear_free(p); - } -}; -typedef UniquePtr<EC_POINT, EC_POINT_Delete> Unique_EC_POINT; - -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_CIPHER_CTX_Delete { - void operator()(EVP_CIPHER_CTX* p) const { - EVP_CIPHER_CTX_cleanup(p); - } -}; -typedef UniquePtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_Delete> Unique_EVP_CIPHER_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 ASN1_BIT_STRING_Delete { - void operator()(ASN1_BIT_STRING* p) const { - ASN1_BIT_STRING_free(p); - } -}; -typedef UniquePtr<ASN1_BIT_STRING, ASN1_BIT_STRING_Delete> Unique_ASN1_BIT_STRING; - -struct ASN1_OBJECT_Delete { - void operator()(ASN1_OBJECT* p) const { - ASN1_OBJECT_free(p); - } -}; -typedef UniquePtr<ASN1_OBJECT, ASN1_OBJECT_Delete> Unique_ASN1_OBJECT; - -struct ASN1_GENERALIZEDTIME_Delete { - void operator()(ASN1_GENERALIZEDTIME* p) const { - ASN1_GENERALIZEDTIME_free(p); - } -}; -typedef UniquePtr<ASN1_GENERALIZEDTIME, ASN1_GENERALIZEDTIME_Delete> Unique_ASN1_GENERALIZEDTIME; - -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 PKCS7_Delete { - void operator()(PKCS7* p) const { - PKCS7_free(p); - } -}; -typedef UniquePtr<PKCS7, PKCS7_Delete> Unique_PKCS7; - -struct sk_SSL_CIPHER_Delete { - void operator()(STACK_OF(SSL_CIPHER)* p) const { - // We don't own SSL_CIPHER references, so no need for pop_free - 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_pop_free(p, X509_free); - } -}; -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_pop_free(p, X509_NAME_free); - } -}; -typedef UniquePtr<STACK_OF(X509_NAME), sk_X509_NAME_Delete> Unique_sk_X509_NAME; - -struct sk_ASN1_OBJECT_Delete { - void operator()(STACK_OF(ASN1_OBJECT)* p) const { - sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free); - } -}; -typedef UniquePtr<STACK_OF(ASN1_OBJECT), sk_ASN1_OBJECT_Delete> Unique_sk_ASN1_OBJECT; - -struct sk_GENERAL_NAME_Delete { - void operator()(STACK_OF(GENERAL_NAME)* p) const { - sk_GENERAL_NAME_pop_free(p, GENERAL_NAME_free); - } -}; -typedef UniquePtr<STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_Delete> Unique_sk_GENERAL_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) \ - do { typeof (obj.release()) _dummy __attribute__((unused)) = obj.release(); } while(0) - -/** - * 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); -} - -/** - * Throws a OutOfMemoryError with the given string as a message. - */ -static void jniThrowOutOfMemory(JNIEnv* env, const char* message) { - jniThrowException(env, "java/lang/OutOfMemoryError", message); -} - -/** - * Throws a BadPaddingException with the given string as a message. - */ -static void throwBadPaddingException(JNIEnv* env, const char* message) { - JNI_TRACE("throwBadPaddingException %s", message); - jniThrowException(env, "javax/crypto/BadPaddingException", message); -} - -/** - * Throws a SignatureException with the given string as a message. - */ -static void throwSignatureException(JNIEnv* env, const char* message) { - JNI_TRACE("throwSignatureException %s", message); - jniThrowException(env, "java/security/SignatureException", message); -} - -/** - * Throws a InvalidKeyException with the given string as a message. - */ -static void throwInvalidKeyException(JNIEnv* env, const char* message) { - JNI_TRACE("throwInvalidKeyException %s", message); - jniThrowException(env, "java/security/InvalidKeyException", message); -} - -/** - * Throws a SignatureException with the given string as a message. - */ -static void throwIllegalBlockSizeException(JNIEnv* env, const char* message) { - JNI_TRACE("throwIllegalBlockSizeException %s", message); - jniThrowException(env, "javax/crypto/IllegalBlockSizeException", message); -} - -/** - * Throws a NoSuchAlgorithmException with the given string as a message. - */ -static void throwNoSuchAlgorithmException(JNIEnv* env, const char* message) { - JNI_TRACE("throwUnknownAlgorithmException %s", message); - jniThrowException(env, "java/security/NoSuchAlgorithmException", message); -} - -static void throwForAsn1Error(JNIEnv* env, int reason, const char *message) { - switch (reason) { - case ASN1_R_UNABLE_TO_DECODE_RSA_KEY: - case ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY: - case ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE: - case ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE: - case ASN1_R_WRONG_PUBLIC_KEY_TYPE: - throwInvalidKeyException(env, message); - break; - case ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM: - throwNoSuchAlgorithmException(env, message); - break; - default: - jniThrowRuntimeException(env, message); - break; - } -} - -static void throwForEvpError(JNIEnv* env, int reason, const char *message) { - switch (reason) { - case EVP_R_BAD_DECRYPT: - throwBadPaddingException(env, message); - break; - case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: - case EVP_R_WRONG_FINAL_BLOCK_LENGTH: - throwIllegalBlockSizeException(env, message); - break; - case EVP_R_BAD_KEY_LENGTH: - case EVP_R_BN_DECODE_ERROR: - case EVP_R_BN_PUBKEY_ERROR: - case EVP_R_INVALID_KEY_LENGTH: - case EVP_R_MISSING_PARAMETERS: - case EVP_R_UNSUPPORTED_KEY_SIZE: - case EVP_R_UNSUPPORTED_KEYLENGTH: - throwInvalidKeyException(env, message); - break; - case EVP_R_WRONG_PUBLIC_KEY_TYPE: - throwSignatureException(env, message); - break; - case EVP_R_UNSUPPORTED_ALGORITHM: - throwNoSuchAlgorithmException(env, message); - break; - default: - jniThrowRuntimeException(env, message); - break; - } -} - -static void throwForRsaError(JNIEnv* env, int reason, const char *message) { - switch (reason) { - case RSA_R_BLOCK_TYPE_IS_NOT_01: - case RSA_R_BLOCK_TYPE_IS_NOT_02: - throwBadPaddingException(env, message); - break; - case RSA_R_ALGORITHM_MISMATCH: - case RSA_R_BAD_SIGNATURE: - case RSA_R_DATA_GREATER_THAN_MOD_LEN: - case RSA_R_DATA_TOO_LARGE_FOR_MODULUS: - case RSA_R_INVALID_MESSAGE_LENGTH: - case RSA_R_WRONG_SIGNATURE_LENGTH: - throwSignatureException(env, message); - break; - case RSA_R_UNKNOWN_ALGORITHM_TYPE: - throwNoSuchAlgorithmException(env, message); - break; - case RSA_R_MODULUS_TOO_LARGE: - case RSA_R_NO_PUBLIC_EXPONENT: - throwInvalidKeyException(env, message); - break; - default: - jniThrowRuntimeException(env, message); - break; - } -} - -static void throwForX509Error(JNIEnv* env, int reason, const char *message) { - switch (reason) { - case X509_R_UNSUPPORTED_ALGORITHM: - throwNoSuchAlgorithmException(env, message); - break; - default: - jniThrowRuntimeException(env, message); - break; - } -} - -/* - * 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))) { - const char* file; - int line; - const char* data; - int flags; - unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags); - int result = false; - - if (error != 0) { - char message[256]; - ERR_error_string_n(error, message, sizeof(message)); - int library = ERR_GET_LIB(error); - int reason = ERR_GET_REASON(error); - JNI_TRACE("OpenSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s", - location, error, library, reason, file, line, message, - (flags & ERR_TXT_STRING) ? data : "(no data)"); - switch (library) { - case ERR_LIB_RSA: - throwForRsaError(env, reason, message); - break; - case ERR_LIB_ASN1: - throwForAsn1Error(env, reason, message); - break; - case ERR_LIB_EVP: - throwForEvpError(env, reason, message); - break; - case ERR_LIB_X509: - throwForX509Error(env, reason, message); - break; - case ERR_LIB_DSA: - throwInvalidKeyException(env, message); - break; - default: - jniThrowRuntimeException(env, message); - break; - } - 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); - ALOGV("%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); - } - - ALOGV("%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, jlong 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, jlong 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, jlong 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. Returns true on success. If the return value is false, there is a - * pending exception. - */ -static bool arrayToBignum(JNIEnv* env, jbyteArray source, BIGNUM** dest) { - JNI_TRACE("arrayToBignum(%p, %p)", source, *dest); - - ScopedByteArrayRO sourceBytes(env, source); - if (sourceBytes.get() == NULL) { - JNI_TRACE("arrayToBignum(%p) => NULL", source); - return false; - } - *dest = BN_bin2bn(reinterpret_cast<const unsigned char*>(sourceBytes.get()), - sourceBytes.size(), - NULL); - if (*dest == NULL) { - jniThrowRuntimeException(env, "Conversion to BIGNUM failed"); - JNI_TRACE("arrayToBignum(%p) => threw exception", source); - return false; - } - - JNI_TRACE("arrayToBignum(%p) => %p", source, *dest); - return true; -} - -/** - * Converts an OpenSSL BIGNUM to a Java byte[] array. - */ -static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source, const char* sourceName) { - JNI_TRACE("bignumToArray(%p, %s)", source, sourceName); - - if (source == NULL) { - jniThrowNullPointerException(env, sourceName); - return NULL; - } - - jbyteArray javaBytes = env->NewByteArray(BN_num_bytes(source) + 1); - ScopedByteArrayRW bytes(env, javaBytes); - if (bytes.get() == NULL) { - JNI_TRACE("bignumToArray(%p, %s) => NULL", source, sourceName); - return NULL; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get()); - - // Set the sign for the Java code. - if (BN_is_negative(source)) { - *tmp = 0xFF; - } else { - *tmp = 0x00; - } - - if (BN_num_bytes(source) > 0 && BN_bn2bin(source, tmp + 1) <= 0) { - throwExceptionIfNecessary(env, "bignumToArray"); - return NULL; - } - - JNI_TRACE("bignumToArray(%p, %s) => %p", source, sourceName, javaBytes); - return javaBytes; -} - -/** - * Converts various OpenSSL ASN.1 types to a jbyteArray with DER-encoded data - * inside. The "i2d_func" function pointer is a function of the "i2d_<TYPE>" - * from the OpenSSL ASN.1 API. - */ -template<typename T, int (*i2d_func)(T*, unsigned char**)> -jbyteArray ASN1ToByteArray(JNIEnv* env, T* obj) { - if (obj == NULL) { - jniThrowNullPointerException(env, "ASN1 input == null"); - JNI_TRACE("ASN1ToByteArray(%p) => null input", obj); - return NULL; - } - - int derLen = i2d_func(obj, NULL); - if (derLen < 0) { - throwExceptionIfNecessary(env, "ASN1ToByteArray"); - JNI_TRACE("ASN1ToByteArray(%p) => measurement failed", obj); - return NULL; - } - - ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(derLen)); - if (byteArray.get() == NULL) { - JNI_TRACE("ASN1ToByteArray(%p) => creating byte array failed", obj); - return NULL; - } - - ScopedByteArrayRW bytes(env, byteArray.get()); - if (bytes.get() == NULL) { - JNI_TRACE("ASN1ToByteArray(%p) => using byte array failed", obj); - return NULL; - } - - unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get()); - int ret = i2d_func(obj, &p); - if (ret < 0) { - throwExceptionIfNecessary(env, "ASN1ToByteArray"); - JNI_TRACE("ASN1ToByteArray(%p) => final conversion failed", obj); - return NULL; - } - - JNI_TRACE("ASN1ToByteArray(%p) => success (%d bytes written)", obj, ret); - return byteArray.release(); -} - -template<typename T, T* (*d2i_func)(T**, const unsigned char**, long)> -T* ByteArrayToASN1(JNIEnv* env, jbyteArray byteArray) { - ScopedByteArrayRO bytes(env, byteArray); - if (bytes.get() == NULL) { - JNI_TRACE("ByteArrayToASN1(%p) => using byte array failed", byteArray); - return 0; - } - - const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get()); - return d2i_func(NULL, &tmp, bytes.size()); -} - -/** - * Converts ASN.1 BIT STRING to a jbooleanArray. - */ -jbooleanArray ASN1BitStringToBooleanArray(JNIEnv* env, ASN1_BIT_STRING* bitStr) { - int size = bitStr->length * 8; - if (bitStr->flags & ASN1_STRING_FLAG_BITS_LEFT) { - size -= bitStr->flags & 0x07; - } - - ScopedLocalRef<jbooleanArray> bitsRef(env, env->NewBooleanArray(size)); - if (bitsRef.get() == NULL) { - return NULL; - } - - ScopedBooleanArrayRW bitsArray(env, bitsRef.get()); - for (int i = 0; i < static_cast<int>(bitsArray.size()); i++) { - bitsArray[i] = ASN1_BIT_STRING_get_bit(bitStr, i); - } - - return bitsRef.release(); -} - -/** - * To avoid the round-trip to ASN.1 and back in X509_dup, we just up the reference count. - */ -static X509* X509_dup_nocopy(X509* x509) { - if (x509 == NULL) { - return NULL; - } - CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); - return x509; -} - -/** - * BIO for InputStream - */ -class BIO_Stream { -public: - BIO_Stream(jobject stream) : - mEof(false) { - JNIEnv* env = getEnv(); - mStream = env->NewGlobalRef(stream); - } - - ~BIO_Stream() { - JNIEnv* env = getEnv(); - - env->DeleteGlobalRef(mStream); - } - - bool isEof() const { - JNI_TRACE("isEof? %s", mEof ? "yes" : "no"); - return mEof; - } - - int flush() { - JNIEnv* env = getEnv(); - if (env == NULL) { - return -1; - } - - env->CallVoidMethod(mStream, outputStream_flushMethod); - if (env->ExceptionCheck()) { - return -1; - } - - return 1; - } - -protected: - jobject getStream() { - return mStream; - } - - void setEof(bool eof) { - mEof = eof; - } - - JNIEnv* getEnv() { - JNIEnv* env; - - if (gJavaVM->AttachCurrentThread(&env, NULL) < 0) { - return NULL; - } - - return env; - } - -private: - jobject mStream; - bool mEof; -}; - -class BIO_InputStream : public BIO_Stream { -public: - BIO_InputStream(jobject stream) : - BIO_Stream(stream) { - } - - int read(char *buf, int len) { - return read_internal(buf, len, inputStream_readMethod); - } - - int gets(char *buf, int len) { - if (len > PEM_LINE_LENGTH) { - len = PEM_LINE_LENGTH; - } - - int read = read_internal(buf, len - 1, openSslInputStream_readLineMethod); - buf[read] = '\0'; - JNI_TRACE("BIO::gets \"%s\"", buf); - return read; - } - -private: - int read_internal(char *buf, int len, jmethodID method) { - JNIEnv* env = getEnv(); - if (env == NULL) { - JNI_TRACE("BIO_InputStream::read could not get JNIEnv"); - return -1; - } - - ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len)); - if (javaBytes.get() == NULL) { - JNI_TRACE("BIO_InputStream::read failed call to NewByteArray"); - return -1; - } - - jint read = env->CallIntMethod(getStream(), method, javaBytes.get()); - if (env->ExceptionCheck()) { - JNI_TRACE("BIO_InputStream::read failed call to InputStream#read"); - return -1; - } - - /* Java uses -1 to indicate EOF condition. */ - if (read == -1) { - setEof(true); - read = 0; - } else if (read > 0) { - env->GetByteArrayRegion(javaBytes.get(), 0, read, reinterpret_cast<jbyte*>(buf)); - } - - return read; - } - -public: - /** Length of PEM-encoded line (64) plus CR plus NULL */ - static const int PEM_LINE_LENGTH = 66; -}; - -class BIO_OutputStream : public BIO_Stream { -public: - BIO_OutputStream(jobject stream) : - BIO_Stream(stream) { - } - - int write(const char *buf, int len) { - JNIEnv* env = getEnv(); - if (env == NULL) { - JNI_TRACE("BIO_OutputStream::write => could not get JNIEnv"); - return -1; - } - - ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len)); - if (javaBytes.get() == NULL) { - JNI_TRACE("BIO_OutputStream::write => failed call to NewByteArray"); - return -1; - } - - env->SetByteArrayRegion(javaBytes.get(), 0, len, reinterpret_cast<const jbyte*>(buf)); - - env->CallVoidMethod(getStream(), outputStream_writeMethod, javaBytes.get()); - if (env->ExceptionCheck()) { - JNI_TRACE("BIO_OutputStream::write => failed call to OutputStream#write"); - return -1; - } - - return len; - } -}; - -static int bio_stream_create(BIO *b) { - b->init = 1; - b->num = 0; - b->ptr = NULL; - b->flags = 0; - return 1; -} - -static int bio_stream_destroy(BIO *b) { - if (b == NULL) { - return 0; - } - - if (b->ptr != NULL) { - delete static_cast<BIO_Stream*>(b->ptr); - b->ptr = NULL; - } - - b->init = 0; - b->flags = 0; - return 1; -} - -static int bio_stream_read(BIO *b, char *buf, int len) { - BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr); - return stream->read(buf, len); -} - -static int bio_stream_write(BIO *b, const char *buf, int len) { - BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr); - return stream->write(buf, len); -} - -static int bio_stream_puts(BIO *b, const char *buf) { - BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr); - return stream->write(buf, strlen(buf)); -} - -static int bio_stream_gets(BIO *b, char *buf, int len) { - BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr); - return stream->gets(buf, len); -} - -static void bio_stream_assign(BIO *b, BIO_Stream* stream) { - b->ptr = static_cast<void*>(stream); -} - -static long bio_stream_ctrl(BIO *b, int cmd, long, void *) { - BIO_Stream* stream = static_cast<BIO_Stream*>(b->ptr); - - switch (cmd) { - case BIO_CTRL_EOF: - return stream->isEof() ? 1 : 0; - case BIO_CTRL_FLUSH: - return stream->flush(); - default: - return 0; - } -} - -static BIO_METHOD stream_bio_method = { - ( 100 | 0x0400 ), /* source/sink BIO */ - "InputStream/OutputStream BIO", - bio_stream_write, /* bio_write */ - bio_stream_read, /* bio_read */ - bio_stream_puts, /* bio_puts */ - bio_stream_gets, /* bio_gets */ - bio_stream_ctrl, /* bio_ctrl */ - bio_stream_create, /* bio_create */ - bio_stream_destroy, /* bio_free */ - NULL, /* no bio_callback_ctrl */ -}; - -/** - * Copied from libnativehelper NetworkUtilites.cpp - */ -static bool setBlocking(int fd, bool blocking) { - int flags = fcntl(fd, F_GETFL); - if (flags == -1) { - return false; - } - - if (!blocking) { - flags |= O_NONBLOCK; - } else { - flags &= ~O_NONBLOCK; - } - - int rc = fcntl(fd, F_SETFL, flags); - return (rc != -1); -} - -/** - * 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(); -} - -static void NativeCrypto_ENGINE_load_dynamic(JNIEnv*, jclass) { - JNI_TRACE("ENGINE_load_dynamic()"); - - ENGINE_load_dynamic(); -} - -static jlong NativeCrypto_ENGINE_by_id(JNIEnv* env, jclass, jstring idJava) { - JNI_TRACE("ENGINE_by_id(%p)", idJava); - - ScopedUtfChars id(env, idJava); - if (id.c_str() == NULL) { - JNI_TRACE("ENGINE_by_id(%p) => id == null", idJava); - return 0; - } - JNI_TRACE("ENGINE_by_id(\"%s\")", id.c_str()); - - ENGINE* e = ENGINE_by_id(id.c_str()); - if (e == NULL) { - freeOpenSslErrorState(); - } - - JNI_TRACE("ENGINE_by_id(\"%s\") => %p", id.c_str(), e); - return reinterpret_cast<uintptr_t>(e); -} - -static jint NativeCrypto_ENGINE_add(JNIEnv* env, jclass, jlong engineRef) { - ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); - JNI_TRACE("ENGINE_add(%p)", e); - - if (e == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); - return 0; - } - - int ret = ENGINE_add(e); - - /* - * We tolerate errors, because the most likely error is that - * the ENGINE is already in the list. - */ - freeOpenSslErrorState(); - - JNI_TRACE("ENGINE_add(%p) => %d", e, ret); - return ret; -} - -static jint NativeCrypto_ENGINE_init(JNIEnv* env, jclass, jlong engineRef) { - ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); - JNI_TRACE("ENGINE_init(%p)", e); - - if (e == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); - return 0; - } - - int ret = ENGINE_init(e); - JNI_TRACE("ENGINE_init(%p) => %d", e, ret); - return ret; -} - -static jint NativeCrypto_ENGINE_finish(JNIEnv* env, jclass, jlong engineRef) { - ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); - JNI_TRACE("ENGINE_finish(%p)", e); - - if (e == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); - return 0; - } - - int ret = ENGINE_finish(e); - JNI_TRACE("ENGINE_finish(%p) => %d", e, ret); - return ret; -} - -static jint NativeCrypto_ENGINE_free(JNIEnv* env, jclass, jlong engineRef) { - ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); - JNI_TRACE("ENGINE_free(%p)", e); - - if (e == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); - return 0; - } - - int ret = ENGINE_free(e); - JNI_TRACE("ENGINE_free(%p) => %d", e, ret); - return ret; -} - -static jlong NativeCrypto_ENGINE_load_private_key(JNIEnv* env, jclass, jlong engineRef, - jstring idJava) { - ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); - JNI_TRACE("ENGINE_load_private_key(%p, %p)", e, idJava); - - ScopedUtfChars id(env, idJava); - if (id.c_str() == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "id == NULL"); - return 0; - } - - Unique_EVP_PKEY pkey(ENGINE_load_private_key(e, id.c_str(), NULL, NULL)); - if (pkey.get() == NULL) { - throwExceptionIfNecessary(env, "ENGINE_load_private_key"); - return 0; - } - - JNI_TRACE("ENGINE_load_private_key(%p, %p) => %p", e, idJava, pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -static jstring NativeCrypto_ENGINE_get_id(JNIEnv* env, jclass, jlong engineRef) -{ - ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); - JNI_TRACE("ENGINE_get_id(%p)", e); - - if (e == NULL) { - jniThrowNullPointerException(env, "engine == null"); - JNI_TRACE("ENGINE_get_id(%p) => engine == null", e); - return NULL; - } - - const char *id = ENGINE_get_id(e); - ScopedLocalRef<jstring> idJava(env, env->NewStringUTF(id)); - - JNI_TRACE("ENGINE_get_id(%p) => \"%s\"", e, id); - return idJava.release(); -} - -static jint NativeCrypto_ENGINE_ctrl_cmd_string(JNIEnv* env, jclass, jlong engineRef, - jstring cmdJava, jstring argJava, jint cmd_optional) -{ - ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); - JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d)", e, cmdJava, argJava, cmd_optional); - - if (e == NULL) { - jniThrowNullPointerException(env, "engine == null"); - JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d) => engine == null", e, cmdJava, argJava, - cmd_optional); - return 0; - } - - ScopedUtfChars cmdChars(env, cmdJava); - if (cmdChars.c_str() == NULL) { - return 0; - } - - UniquePtr<ScopedUtfChars> arg; - const char* arg_c_str = NULL; - if (argJava != NULL) { - arg.reset(new ScopedUtfChars(env, argJava)); - arg_c_str = arg->c_str(); - if (arg_c_str == NULL) { - return 0; - } - } - JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d)", e, cmdChars.c_str(), arg_c_str, - cmd_optional); - - int ret = ENGINE_ctrl_cmd_string(e, cmdChars.c_str(), arg_c_str, cmd_optional); - if (ret != 1) { - throwExceptionIfNecessary(env, "ENGINE_ctrl_cmd_string"); - JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => threw error", e, - cmdChars.c_str(), arg_c_str, cmd_optional); - return 0; - } - - JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => %d", e, cmdChars.c_str(), - arg_c_str, cmd_optional, ret); - return ret; -} - -/** - * public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g, - * byte[] pub_key, byte[] priv_key); - */ -static jlong 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 0; - } - - if (!arrayToBignum(env, p, &dsa->p)) { - return 0; - } - - if (!arrayToBignum(env, q, &dsa->q)) { - return 0; - } - - if (!arrayToBignum(env, g, &dsa->g)) { - return 0; - } - - if (pub_key != NULL && !arrayToBignum(env, pub_key, &dsa->pub_key)) { - return 0; - } - - if (priv_key != NULL && !arrayToBignum(env, priv_key, &dsa->priv_key)) { - return 0; - } - - if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL - || (dsa->pub_key == NULL && dsa->priv_key == NULL)) { - jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM"); - return 0; - } - - Unique_EVP_PKEY pkey(EVP_PKEY_new()); - if (pkey.get() == NULL) { - jniThrowRuntimeException(env, "EVP_PKEY_new failed"); - return 0; - } - if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) { - jniThrowRuntimeException(env, "EVP_PKEY_assign_DSA failed"); - return 0; - } - 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 reinterpret_cast<jlong>(pkey.release()); -} - -/** - * private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q); - */ -static jlong NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass, - jbyteArray n, jbyteArray e, jbyteArray d, - jbyteArray p, jbyteArray q, - jbyteArray dmp1, jbyteArray dmq1, - jbyteArray iqmp) { - JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p, dmp1=%p, dmq1=%p, iqmp=%p)", - n, e, d, p, q, dmp1, dmq1, iqmp); - - Unique_RSA rsa(RSA_new()); - if (rsa.get() == NULL) { - jniThrowRuntimeException(env, "RSA_new failed"); - return 0; - } - - if (e == NULL && d == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "e == NULL && d == NULL"); - JNI_TRACE("NativeCrypto_EVP_PKEY_new_RSA => e == NULL && d == NULL"); - return 0; - } - - if (!arrayToBignum(env, n, &rsa->n)) { - return 0; - } - - if (e != NULL && !arrayToBignum(env, e, &rsa->e)) { - return 0; - } - - if (d != NULL && !arrayToBignum(env, d, &rsa->d)) { - return 0; - } - - if (p != NULL && !arrayToBignum(env, p, &rsa->p)) { - return 0; - } - - if (q != NULL && !arrayToBignum(env, q, &rsa->q)) { - return 0; - } - - if (dmp1 != NULL && !arrayToBignum(env, dmp1, &rsa->dmp1)) { - return 0; - } - - if (dmq1 != NULL && !arrayToBignum(env, dmq1, &rsa->dmq1)) { - return 0; - } - - if (iqmp != NULL && !arrayToBignum(env, iqmp, &rsa->iqmp)) { - return 0; - } - -#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 && rsa->d == NULL)) { - jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM"); - return 0; - } - - /* - * If the private exponent is available, there is the potential to do signing - * operations. If the public exponent is also available, OpenSSL will do RSA - * blinding. Enable it if possible. - */ - if (rsa->d != NULL) { - if (rsa->e != NULL) { - JNI_TRACE("EVP_PKEY_new_RSA(...) enabling RSA blinding => %p", rsa.get()); - RSA_blinding_on(rsa.get(), NULL); - } else { - JNI_TRACE("EVP_PKEY_new_RSA(...) disabling RSA blinding => %p", rsa.get()); - RSA_blinding_off(rsa.get()); - } - } - - Unique_EVP_PKEY pkey(EVP_PKEY_new()); - if (pkey.get() == NULL) { - jniThrowRuntimeException(env, "EVP_PKEY_new failed"); - return 0; - } - if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) { - jniThrowRuntimeException(env, "EVP_PKEY_new failed"); - return 0; - } - OWNERSHIP_TRANSFERRED(rsa); - JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p dmp1=%p, dmq1=%p, iqmp=%p) => %p", - n, e, d, p, q, dmp1, dmq1, iqmp, pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -static jlong NativeCrypto_EVP_PKEY_new_EC_KEY(JNIEnv* env, jclass, jlong groupRef, - jlong pubkeyRef, jbyteArray keyJavaBytes) { - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - const EC_POINT* pubkey = reinterpret_cast<const EC_POINT*>(pubkeyRef); - JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p)", group, pubkey, keyJavaBytes); - - Unique_BIGNUM key(NULL); - if (keyJavaBytes != NULL) { - BIGNUM* keyRef; - if (!arrayToBignum(env, keyJavaBytes, &keyRef)) { - return 0; - } - key.reset(keyRef); - } - - Unique_EC_KEY eckey(EC_KEY_new()); - if (eckey.get() == NULL) { - jniThrowRuntimeException(env, "EC_KEY_new failed"); - return 0; - } - - if (EC_KEY_set_group(eckey.get(), group) != 1) { - JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) > EC_KEY_set_group failed", group, pubkey, - keyJavaBytes); - throwExceptionIfNecessary(env, "EC_KEY_set_group"); - return 0; - } - - if (pubkey != NULL) { - if (EC_KEY_set_public_key(eckey.get(), pubkey) != 1) { - JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group, - pubkey, keyJavaBytes); - throwExceptionIfNecessary(env, "EC_KEY_set_public_key"); - return 0; - } - } - - if (key.get() != NULL) { - if (EC_KEY_set_private_key(eckey.get(), key.get()) != 1) { - JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group, - pubkey, keyJavaBytes); - throwExceptionIfNecessary(env, "EC_KEY_set_private_key"); - return 0; - } - if (pubkey == NULL) { - Unique_EC_POINT calcPubkey(EC_POINT_new(group)); - if (!EC_POINT_mul(group, calcPubkey.get(), key.get(), NULL, NULL, NULL)) { - JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => can't calulate public key", group, - pubkey, keyJavaBytes); - throwExceptionIfNecessary(env, "EC_KEY_set_private_key"); - return 0; - } - EC_KEY_set_public_key(eckey.get(), calcPubkey.get()); - } - } - - if (!EC_KEY_check_key(eckey.get())) { - JNI_TRACE("EVP_KEY_new_EC_KEY(%p, %p, %p) => invalid key created", group, pubkey, keyJavaBytes); - throwExceptionIfNecessary(env, "EC_KEY_check_key"); - return 0; - } - - Unique_EVP_PKEY pkey(EVP_PKEY_new()); - if (pkey.get() == NULL) { - JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes); - throwExceptionIfNecessary(env, "EVP_PKEY_new failed"); - return 0; - } - if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) { - JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes); - jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed"); - return 0; - } - OWNERSHIP_TRANSFERRED(eckey); - - JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => %p", group, pubkey, keyJavaBytes, pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -static jlong NativeCrypto_EVP_PKEY_new_mac_key(JNIEnv* env, jclass, jint pkeyType, - jbyteArray keyJavaBytes) -{ - JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p)", pkeyType, keyJavaBytes); - - ScopedByteArrayRO key(env, keyJavaBytes); - if (key.get() == NULL) { - return 0; - } - - const unsigned char* tmp = reinterpret_cast<const unsigned char*>(key.get()); - Unique_EVP_PKEY pkey(EVP_PKEY_new_mac_key(pkeyType, (ENGINE *) NULL, tmp, key.size())); - if (pkey.get() == NULL) { - JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => threw error", pkeyType, keyJavaBytes); - throwExceptionIfNecessary(env, "ENGINE_load_private_key"); - return 0; - } - - JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => %p", pkeyType, keyJavaBytes, pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -static int NativeCrypto_EVP_PKEY_type(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EVP_PKEY_type(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, NULL); - return -1; - } - - int result = EVP_PKEY_type(pkey->type); - JNI_TRACE("EVP_PKEY_type(%p) => %d", pkey, result); - return result; -} - -/** - * private static native int EVP_PKEY_size(int pkey); - */ -static int NativeCrypto_EVP_PKEY_size(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EVP_PKEY_size(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, NULL); - return -1; - } - - int result = EVP_PKEY_size(pkey); - JNI_TRACE("EVP_PKEY_size(%p) => %d", pkey, result); - return result; -} - -static jstring NativeCrypto_EVP_PKEY_print_public(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EVP_PKEY_print_public(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - return NULL; - } - - Unique_BIO buffer(BIO_new(BIO_s_mem())); - if (buffer.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate BIO"); - return NULL; - } - - if (EVP_PKEY_print_public(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) { - throwExceptionIfNecessary(env, "EVP_PKEY_print_public"); - return NULL; - } - // Null terminate this - BIO_write(buffer.get(), "\0", 1); - - char *tmp; - BIO_get_mem_data(buffer.get(), &tmp); - jstring description = env->NewStringUTF(tmp); - - JNI_TRACE("EVP_PKEY_print_public(%p) => \"%s\"", pkey, tmp); - return description; -} - -static jstring NativeCrypto_EVP_PKEY_print_private(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EVP_PKEY_print_private(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - return NULL; - } - - Unique_BIO buffer(BIO_new(BIO_s_mem())); - if (buffer.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate BIO"); - return NULL; - } - - if (EVP_PKEY_print_private(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) { - throwExceptionIfNecessary(env, "EVP_PKEY_print_private"); - return NULL; - } - // Null terminate this - BIO_write(buffer.get(), "\0", 1); - - char *tmp; - BIO_get_mem_data(buffer.get(), &tmp); - jstring description = env->NewStringUTF(tmp); - - JNI_TRACE("EVP_PKEY_print_private(%p) => \"%s\"", pkey, tmp); - return description; -} - -static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EVP_PKEY_free(%p)", pkey); - - if (pkey != NULL) { - EVP_PKEY_free(pkey); - } -} - -static jint NativeCrypto_EVP_PKEY_cmp(JNIEnv* env, jclass, jlong pkey1Ref, jlong pkey2Ref) { - EVP_PKEY* pkey1 = reinterpret_cast<EVP_PKEY*>(pkey1Ref); - EVP_PKEY* pkey2 = reinterpret_cast<EVP_PKEY*>(pkey2Ref); - JNI_TRACE("EVP_PKEY_cmp(%p, %p)", pkey1, pkey2); - - if (pkey1 == NULL) { - JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey1 == NULL", pkey1, pkey2); - jniThrowNullPointerException(env, "pkey1 == NULL"); - return -1; - } else if (pkey2 == NULL) { - JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey2 == NULL", pkey1, pkey2); - jniThrowNullPointerException(env, "pkey2 == NULL"); - return -1; - } - - int result = EVP_PKEY_cmp(pkey1, pkey2); - JNI_TRACE("EVP_PKEY_cmp(%p, %p) => %d", pkey1, pkey2, result); - return result; -} - -/* - * static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int, byte[]) - */ -static jbyteArray NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("i2d_PKCS8_PRIV_KEY_INFO(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, NULL); - return NULL; - } - - Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey)); - if (pkcs8.get() == NULL) { - throwExceptionIfNecessary(env, "NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO"); - JNI_TRACE("key=%p i2d_PKCS8_PRIV_KEY_INFO => error from key to PKCS8", pkey); - return NULL; - } - - return ASN1ToByteArray<PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO>(env, pkcs8.get()); -} - -/* - * static native int d2i_PKCS8_PRIV_KEY_INFO(byte[]) - */ -static jlong NativeCrypto_d2i_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jbyteArray keyJavaBytes) { - JNI_TRACE("d2i_PKCS8_PRIV_KEY_INFO(%p)", keyJavaBytes); - - ScopedByteArrayRO bytes(env, keyJavaBytes); - if (bytes.get() == NULL) { - JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => threw exception", keyJavaBytes); - return 0; - } - - const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get()); - Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &tmp, bytes.size())); - if (pkcs8.get() == NULL) { - throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO"); - JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from DER to PKCS8", keyJavaBytes); - return 0; - } - - Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); - if (pkey.get() == NULL) { - throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO"); - JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from PKCS8 to key", keyJavaBytes); - return 0; - } - - JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => %p", keyJavaBytes, pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -/* - * static native byte[] i2d_PUBKEY(int) - */ -static jbyteArray NativeCrypto_i2d_PUBKEY(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("i2d_PUBKEY(%p)", pkey); - return ASN1ToByteArray<EVP_PKEY, i2d_PUBKEY>(env, pkey); -} - -/* - * static native int d2i_PUBKEY(byte[]) - */ -static jlong NativeCrypto_d2i_PUBKEY(JNIEnv* env, jclass, jbyteArray javaBytes) { - JNI_TRACE("d2i_PUBKEY(%p)", javaBytes); - - ScopedByteArrayRO bytes(env, javaBytes); - if (bytes.get() == NULL) { - JNI_TRACE("d2i_PUBKEY(%p) => threw error", javaBytes); - return 0; - } - - const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get()); - Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, bytes.size())); - if (pkey.get() == NULL) { - JNI_TRACE("bytes=%p d2i_PUBKEY => threw exception", javaBytes); - throwExceptionIfNecessary(env, "d2i_PUBKEY"); - return 0; - } - - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -/* - * public static native int RSA_generate_key(int modulusBits, byte[] publicExponent); - */ -static jlong NativeCrypto_RSA_generate_key_ex(JNIEnv* env, jclass, jint modulusBits, - jbyteArray publicExponent) { - JNI_TRACE("RSA_generate_key_ex(%d, %p)", modulusBits, publicExponent); - - BIGNUM* eRef; - if (!arrayToBignum(env, publicExponent, &eRef)) { - return 0; - } - Unique_BIGNUM e(eRef); - - Unique_RSA rsa(RSA_new()); - if (rsa.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate RSA key"); - return 0; - } - - if (RSA_generate_key_ex(rsa.get(), modulusBits, e.get(), NULL) < 0) { - throwExceptionIfNecessary(env, "RSA_generate_key_ex"); - return 0; - } - - Unique_EVP_PKEY pkey(EVP_PKEY_new()); - if (pkey.get() == NULL) { - jniThrowRuntimeException(env, "RSA_generate_key_ex failed"); - return 0; - } - - if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) { - jniThrowRuntimeException(env, "RSA_generate_key_ex failed"); - return 0; - } - - OWNERSHIP_TRANSFERRED(rsa); - JNI_TRACE("RSA_generate_key_ex(n=%d, e=%p) => %p", modulusBits, publicExponent, pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -static jint NativeCrypto_RSA_size(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("RSA_size(%p)", pkey); - - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); - if (rsa.get() == NULL) { - jniThrowRuntimeException(env, "RSA_size failed"); - return 0; - } - - return static_cast<jint>(RSA_size(rsa.get())); -} - -typedef int RSACryptOperation(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, - int padding); - -static jint RSA_crypt_operation(RSACryptOperation operation, - const char* caller __attribute__ ((unused)), JNIEnv* env, jint flen, - jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("%s(%d, %p, %p, %p)", caller, flen, fromJavaBytes, toJavaBytes, pkey); - - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); - if (rsa.get() == NULL) { - return -1; - } - - ScopedByteArrayRO from(env, fromJavaBytes); - if (from.get() == NULL) { - return -1; - } - - ScopedByteArrayRW to(env, toJavaBytes); - if (to.get() == NULL) { - return -1; - } - - int resultSize = operation(static_cast<int>(flen), - reinterpret_cast<const unsigned char*>(from.get()), - reinterpret_cast<unsigned char*>(to.get()), rsa.get(), padding); - if (resultSize == -1) { - JNI_TRACE("%s => failed", caller); - throwExceptionIfNecessary(env, "RSA_crypt_operation"); - return -1; - } - - JNI_TRACE("%s(%d, %p, %p, %p) => %d", caller, flen, fromJavaBytes, toJavaBytes, pkey, - resultSize); - return static_cast<jint>(resultSize); -} - -static jint NativeCrypto_RSA_private_encrypt(JNIEnv* env, jclass, jint flen, - jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) { - return RSA_crypt_operation(RSA_private_encrypt, __FUNCTION__, - env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); -} -static jint NativeCrypto_RSA_public_decrypt(JNIEnv* env, jclass, jint flen, - jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) { - return RSA_crypt_operation(RSA_public_decrypt, __FUNCTION__, - env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); -} -static jint NativeCrypto_RSA_public_encrypt(JNIEnv* env, jclass, jint flen, - jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) { - return RSA_crypt_operation(RSA_public_encrypt, __FUNCTION__, - env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); -} -static jint NativeCrypto_RSA_private_decrypt(JNIEnv* env, jclass, jint flen, - jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) { - return RSA_crypt_operation(RSA_private_decrypt, __FUNCTION__, - env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); -} - -/* - * public static native byte[][] get_RSA_public_params(int); - */ -static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("get_RSA_public_params(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - return 0; - } - - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); - if (rsa.get() == NULL) { - throwExceptionIfNecessary(env, "get_RSA_public_params failed"); - return 0; - } - - jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL); - if (joa == NULL) { - return NULL; - } - - jbyteArray n = bignumToArray(env, rsa->n, "n"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 0, n); - - jbyteArray e = bignumToArray(env, rsa->e, "e"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 1, e); - - return joa; -} - -/* - * public static native byte[][] get_RSA_private_params(int); - */ -static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("get_RSA_public_params(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - return 0; - } - - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); - if (rsa.get() == NULL) { - throwExceptionIfNecessary(env, "get_RSA_public_params failed"); - return 0; - } - - jobjectArray joa = env->NewObjectArray(8, byteArrayClass, NULL); - if (joa == NULL) { - return NULL; - } - - jbyteArray n = bignumToArray(env, rsa->n, "n"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 0, n); - - if (rsa->e != NULL) { - jbyteArray e = bignumToArray(env, rsa->e, "e"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 1, e); - } - - if (rsa->d != NULL) { - jbyteArray d = bignumToArray(env, rsa->d, "d"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 2, d); - } - - if (rsa->p != NULL) { - jbyteArray p = bignumToArray(env, rsa->p, "p"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 3, p); - } - - if (rsa->q != NULL) { - jbyteArray q = bignumToArray(env, rsa->q, "q"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 4, q); - } - - if (rsa->dmp1 != NULL) { - jbyteArray dmp1 = bignumToArray(env, rsa->dmp1, "dmp1"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 5, dmp1); - } - - if (rsa->dmq1 != NULL) { - jbyteArray dmq1 = bignumToArray(env, rsa->dmq1, "dmq1"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 6, dmq1); - } - - if (rsa->iqmp != NULL) { - jbyteArray iqmp = bignumToArray(env, rsa->iqmp, "iqmp"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 7, iqmp); - } - - return joa; -} - -/* - * public static native int DSA_generate_key(int, byte[]); - */ -static jlong NativeCrypto_DSA_generate_key(JNIEnv* env, jclass, jint primeBits, - jbyteArray seedJavaBytes, jbyteArray gBytes, jbyteArray pBytes, jbyteArray qBytes) { - JNI_TRACE("DSA_generate_key(%d, %p, %p, %p, %p)", primeBits, seedJavaBytes, - gBytes, pBytes, qBytes); - - UniquePtr<unsigned char[]> seedPtr; - unsigned long seedSize = 0; - if (seedJavaBytes != NULL) { - ScopedByteArrayRO seed(env, seedJavaBytes); - if (seed.get() == NULL) { - return 0; - } - - seedSize = seed.size(); - seedPtr.reset(new unsigned char[seedSize]); - - memcpy(seedPtr.get(), seed.get(), seedSize); - } - - Unique_DSA dsa(DSA_new()); - if (dsa.get() == NULL) { - JNI_TRACE("DSA_generate_key failed"); - jniThrowOutOfMemory(env, "Unable to allocate DSA key"); - freeOpenSslErrorState(); - return 0; - } - - if (gBytes != NULL && pBytes != NULL && qBytes != NULL) { - JNI_TRACE("DSA_generate_key parameters specified"); - - if (!arrayToBignum(env, gBytes, &dsa->g)) { - return 0; - } - - if (!arrayToBignum(env, pBytes, &dsa->p)) { - return 0; - } - - if (!arrayToBignum(env, qBytes, &dsa->q)) { - return 0; - } - } else { - JNI_TRACE("DSA_generate_key generating parameters"); - - if (!DSA_generate_parameters_ex(dsa.get(), primeBits, seedPtr.get(), seedSize, NULL, NULL, NULL)) { - JNI_TRACE("DSA_generate_key => param generation failed"); - throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_parameters_ex failed"); - return 0; - } - } - - if (!DSA_generate_key(dsa.get())) { - JNI_TRACE("DSA_generate_key failed"); - throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_key failed"); - return 0; - } - - Unique_EVP_PKEY pkey(EVP_PKEY_new()); - if (pkey.get() == NULL) { - JNI_TRACE("DSA_generate_key failed"); - jniThrowRuntimeException(env, "NativeCrypto_DSA_generate_key failed"); - freeOpenSslErrorState(); - return 0; - } - - if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) { - JNI_TRACE("DSA_generate_key failed"); - throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_key failed"); - return 0; - } - - OWNERSHIP_TRANSFERRED(dsa); - JNI_TRACE("DSA_generate_key(n=%d, e=%p) => %p", primeBits, seedPtr.get(), pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -/* - * public static native byte[][] get_DSA_params(int); - */ -static jobjectArray NativeCrypto_get_DSA_params(JNIEnv* env, jclass, jlong pkeyRef) { - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("get_DSA_params(%p)", pkey); - - Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); - if (dsa.get() == NULL) { - throwExceptionIfNecessary(env, "get_DSA_params failed"); - return 0; - } - - jobjectArray joa = env->NewObjectArray(5, byteArrayClass, NULL); - if (joa == NULL) { - return NULL; - } - - if (dsa->g != NULL) { - jbyteArray g = bignumToArray(env, dsa->g, "g"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 0, g); - } - - if (dsa->p != NULL) { - jbyteArray p = bignumToArray(env, dsa->p, "p"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 1, p); - } - - if (dsa->q != NULL) { - jbyteArray q = bignumToArray(env, dsa->q, "q"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 2, q); - } - - if (dsa->pub_key != NULL) { - jbyteArray pub_key = bignumToArray(env, dsa->pub_key, "pub_key"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 3, pub_key); - } - - if (dsa->priv_key != NULL) { - jbyteArray priv_key = bignumToArray(env, dsa->priv_key, "priv_key"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 4, priv_key); - } - - return joa; -} - -#define EC_CURVE_GFP 1 -#define EC_CURVE_GF2M 2 - -/** - * Return group type or 0 if unknown group. - * EC_GROUP_GFP or EC_GROUP_GF2M - */ -static int get_EC_GROUP_type(const EC_GROUP* group) -{ - const EC_METHOD* method = EC_GROUP_method_of(group); - if (method == EC_GFp_nist_method() - || method == EC_GFp_mont_method() - || method == EC_GFp_simple_method()) { - return EC_CURVE_GFP; - } else if (method == EC_GF2m_simple_method()) { - return EC_CURVE_GF2M; - } - - return 0; -} - -static jlong NativeCrypto_EC_GROUP_new_by_curve_name(JNIEnv* env, jclass, jstring curveNameJava) -{ - JNI_TRACE("EC_GROUP_new_by_curve_name(%p)", curveNameJava); - - ScopedUtfChars curveName(env, curveNameJava); - if (curveName.c_str() == NULL) { - return 0; - } - JNI_TRACE("EC_GROUP_new_by_curve_name(%s)", curveName.c_str()); - - int nid = OBJ_sn2nid(curveName.c_str()); - if (nid == NID_undef) { - JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID name", curveName.c_str()); - return 0; - } - - EC_GROUP* group = EC_GROUP_new_by_curve_name(nid); - if (group == NULL) { - JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID %d", curveName.c_str(), nid); - freeOpenSslErrorState(); - return 0; - } - - JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => %p", curveName.c_str(), group); - return reinterpret_cast<uintptr_t>(group); -} - -static void NativeCrypto_EC_GROUP_set_asn1_flag(JNIEnv* env, jclass, jlong groupRef, - jint flag) -{ - EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d)", group, flag); - - if (group == NULL) { - JNI_TRACE("EC_GROUP_set_asn1_flag => group == NULL"); - jniThrowNullPointerException(env, "group == NULL"); - return; - } - - EC_GROUP_set_asn1_flag(group, flag); - JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d) => success", group, flag); -} - -static void NativeCrypto_EC_GROUP_set_point_conversion_form(JNIEnv* env, jclass, - jlong groupRef, jint form) -{ - EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d)", group, form); - - if (group == NULL) { - JNI_TRACE("EC_GROUP_set_point_conversion_form => group == NULL"); - jniThrowNullPointerException(env, "group == NULL"); - return; - } - - EC_GROUP_set_point_conversion_form(group, static_cast<point_conversion_form_t>(form)); - JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d) => success", group, form); -} - -static jlong NativeCrypto_EC_GROUP_new_curve(JNIEnv* env, jclass, jint type, jbyteArray pJava, - jbyteArray aJava, jbyteArray bJava) -{ - JNI_TRACE("EC_GROUP_new_curve(%d, %p, %p, %p)", type, pJava, aJava, bJava); - - BIGNUM* pRef; - if (!arrayToBignum(env, pJava, &pRef)) { - return 0; - } - Unique_BIGNUM p(pRef); - - BIGNUM* aRef; - if (!arrayToBignum(env, aJava, &aRef)) { - return 0; - } - Unique_BIGNUM a(aRef); - - BIGNUM* bRef; - if (!arrayToBignum(env, bJava, &bRef)) { - return 0; - } - Unique_BIGNUM b(bRef); - - EC_GROUP* group; - switch (type) { - case EC_CURVE_GFP: - group = EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), (BN_CTX*) NULL); - break; - case EC_CURVE_GF2M: - group = EC_GROUP_new_curve_GF2m(p.get(), a.get(), b.get(), (BN_CTX*) NULL); - break; - default: - jniThrowRuntimeException(env, "invalid group"); - return 0; - } - - if (group == NULL) { - throwExceptionIfNecessary(env, "EC_GROUP_new_curve"); - } - - JNI_TRACE("EC_GROUP_new_curve(%d, %p, %p, %p) => %p", type, pJava, aJava, bJava, group); - return reinterpret_cast<uintptr_t>(group); -} - -static jlong NativeCrypto_EC_GROUP_dup(JNIEnv* env, jclass, jlong groupRef) { - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_dup(%p)", group); - - if (group == NULL) { - JNI_TRACE("EC_GROUP_dup => group == NULL"); - jniThrowNullPointerException(env, "group == NULL"); - return 0; - } - - EC_GROUP* groupDup = EC_GROUP_dup(group); - JNI_TRACE("EC_GROUP_dup(%p) => %p", group, groupDup); - return reinterpret_cast<uintptr_t>(groupDup); -} - -static jstring NativeCrypto_EC_GROUP_get_curve_name(JNIEnv* env, jclass, jlong groupRef) { - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_get_curve_name(%p)", group); - - if (group == NULL) { - JNI_TRACE("EC_GROUP_get_curve_name => group == NULL"); - jniThrowNullPointerException(env, "group == NULL"); - return 0; - } - - int nid = EC_GROUP_get_curve_name(group); - if (nid == NID_undef) { - JNI_TRACE("EC_GROUP_get_curve_name(%p) => unnamed curve", group); - return NULL; - } - - const char* shortName = OBJ_nid2sn(nid); - JNI_TRACE("EC_GROUP_get_curve_name(%p) => \"%s\"", group, shortName); - return env->NewStringUTF(shortName); -} - -static jobjectArray NativeCrypto_EC_GROUP_get_curve(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_get_curve(%p)", group); - - Unique_BIGNUM p(BN_new()); - Unique_BIGNUM a(BN_new()); - Unique_BIGNUM b(BN_new()); - - int ret; - switch (get_EC_GROUP_type(group)) { - case EC_CURVE_GFP: - ret = EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), (BN_CTX*) NULL); - break; - case EC_CURVE_GF2M: - ret = EC_GROUP_get_curve_GF2m(group, p.get(), a.get(), b.get(), (BN_CTX*)NULL); - break; - default: - jniThrowRuntimeException(env, "invalid group"); - return NULL; - } - if (ret != 1) { - throwExceptionIfNecessary(env, "EC_GROUP_get_curve"); - return NULL; - } - - jobjectArray joa = env->NewObjectArray(3, byteArrayClass, NULL); - if (joa == NULL) { - return NULL; - } - - jbyteArray pArray = bignumToArray(env, p.get(), "p"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 0, pArray); - - jbyteArray aArray = bignumToArray(env, a.get(), "a"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 1, aArray); - - jbyteArray bArray = bignumToArray(env, b.get(), "b"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 2, bArray); - - JNI_TRACE("EC_GROUP_get_curve(%p) => %p", group, joa); - return joa; -} - -static jbyteArray NativeCrypto_EC_GROUP_get_order(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_get_order(%p)", group); - - Unique_BIGNUM order(BN_new()); - if (order.get() == NULL) { - JNI_TRACE("EC_GROUP_get_order(%p) => can't create BN", group); - jniThrowOutOfMemory(env, "BN_new"); - return NULL; - } - - if (EC_GROUP_get_order(group, order.get(), NULL) != 1) { - JNI_TRACE("EC_GROUP_get_order(%p) => threw error", group); - throwExceptionIfNecessary(env, "EC_GROUP_get_order"); - return NULL; - } - - jbyteArray orderArray = bignumToArray(env, order.get(), "order"); - if (env->ExceptionCheck()) { - return NULL; - } - - JNI_TRACE("EC_GROUP_get_order(%p) => %p", group, orderArray); - return orderArray; -} - -static jint NativeCrypto_EC_GROUP_get_degree(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_get_degree(%p)", group); - - jint degree = EC_GROUP_get_degree(group); - if (degree == 0) { - JNI_TRACE("EC_GROUP_get_degree(%p) => unsupported", group); - jniThrowRuntimeException(env, "not supported"); - return 0; - } - - JNI_TRACE("EC_GROUP_get_degree(%p) => %d", group, degree); - return degree; -} - -static jbyteArray NativeCrypto_EC_GROUP_get_cofactor(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_get_cofactor(%p)", group); - - Unique_BIGNUM cofactor(BN_new()); - if (cofactor.get() == NULL) { - JNI_TRACE("EC_GROUP_get_cofactor(%p) => can't create BN", group); - jniThrowOutOfMemory(env, "BN_new"); - return NULL; - } - - if (EC_GROUP_get_cofactor(group, cofactor.get(), NULL) != 1) { - JNI_TRACE("EC_GROUP_get_cofactor(%p) => threw error", group); - throwExceptionIfNecessary(env, "EC_GROUP_get_cofactor"); - return NULL; - } - - jbyteArray cofactorArray = bignumToArray(env, cofactor.get(), "cofactor"); - if (env->ExceptionCheck()) { - return NULL; - } - - JNI_TRACE("EC_GROUP_get_cofactor(%p) => %p", group, cofactorArray); - return cofactorArray; -} - -static jint NativeCrypto_get_EC_GROUP_type(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("get_EC_GROUP_type(%p)", group); - - int type = get_EC_GROUP_type(group); - if (type == 0) { - JNI_TRACE("get_EC_GROUP_type(%p) => curve type", group); - jniThrowRuntimeException(env, "unknown curve type"); - } else { - JNI_TRACE("get_EC_GROUP_type(%p) => %d", group, type); - } - return type; -} - -static void NativeCrypto_EC_GROUP_clear_free(JNIEnv* env, jclass, jlong groupRef) -{ - EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_clear_free(%p)", group); - - if (group == NULL) { - JNI_TRACE("EC_GROUP_clear_free => group == NULL"); - jniThrowNullPointerException(env, "group == NULL"); - return; - } - - EC_GROUP_clear_free(group); - JNI_TRACE("EC_GROUP_clear_free(%p) => success", group); -} - -static jboolean NativeCrypto_EC_GROUP_cmp(JNIEnv* env, jclass, jlong group1Ref, jlong group2Ref) -{ - const EC_GROUP* group1 = reinterpret_cast<const EC_GROUP*>(group1Ref); - const EC_GROUP* group2 = reinterpret_cast<const EC_GROUP*>(group2Ref); - JNI_TRACE("EC_GROUP_cmp(%p, %p)", group1, group2); - - if (group1 == NULL || group2 == NULL) { - JNI_TRACE("EC_GROUP_cmp(%p, %p) => group1 == null || group2 == null", group1, group2); - jniThrowNullPointerException(env, "group1 == null || group2 == null"); - return false; - } - - int ret = EC_GROUP_cmp(group1, group2, (BN_CTX*)NULL); - - JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", group1, group2, ret); - return ret == 0; -} - -static void NativeCrypto_EC_GROUP_set_generator(JNIEnv* env, jclass, jlong groupRef, jlong pointRef, jbyteArray njavaBytes, jbyteArray hjavaBytes) -{ - EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef); - const EC_POINT* point = reinterpret_cast<const EC_POINT*>(pointRef); - JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p)", group, point, njavaBytes, hjavaBytes); - - if (group == NULL || point == NULL) { - JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p) => group == null || point == null", - group, point, njavaBytes, hjavaBytes); - jniThrowNullPointerException(env, "group == null || point == null"); - return; - } - - BIGNUM* nRef; - if (!arrayToBignum(env, njavaBytes, &nRef)) { - return; - } - Unique_BIGNUM n(nRef); - - BIGNUM* hRef; - if (!arrayToBignum(env, hjavaBytes, &hRef)) { - return; - } - Unique_BIGNUM h(hRef); - - int ret = EC_GROUP_set_generator(group, point, n.get(), h.get()); - if (ret == 0) { - throwExceptionIfNecessary(env, "EC_GROUP_set_generator"); - } - - JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p) => %d", group, point, njavaBytes, hjavaBytes, ret); -} - -static jlong NativeCrypto_EC_GROUP_get_generator(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_GROUP_get_generator(%p)", group); - - if (group == NULL) { - JNI_TRACE("EC_POINT_get_generator(%p) => group == null", group); - jniThrowNullPointerException(env, "group == null"); - return 0; - } - - const EC_POINT* generator = EC_GROUP_get0_generator(group); - - Unique_EC_POINT dup(EC_POINT_dup(generator, group)); - if (dup.get() == NULL) { - JNI_TRACE("EC_GROUP_get_generator(%p) => oom error", group); - jniThrowOutOfMemory(env, "unable to dupe generator"); - return 0; - } - - JNI_TRACE("EC_GROUP_get_generator(%p) => %p", group, dup.get()); - return reinterpret_cast<uintptr_t>(dup.release()); -} - -static jlong NativeCrypto_EC_POINT_new(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_POINT_new(%p)", group); - - if (group == NULL) { - JNI_TRACE("EC_POINT_new(%p) => group == null", group); - jniThrowNullPointerException(env, "group == null"); - return 0; - } - - EC_POINT* point = EC_POINT_new(group); - if (point == NULL) { - jniThrowOutOfMemory(env, "Unable create an EC_POINT"); - return 0; - } - - return reinterpret_cast<uintptr_t>(point); -} - -static void NativeCrypto_EC_POINT_clear_free(JNIEnv* env, jclass, jlong groupRef) { - EC_POINT* group = reinterpret_cast<EC_POINT*>(groupRef); - JNI_TRACE("EC_POINT_clear_free(%p)", group); - - if (group == NULL) { - JNI_TRACE("EC_POINT_clear_free => group == NULL"); - jniThrowNullPointerException(env, "group == NULL"); - return; - } - - EC_POINT_clear_free(group); - JNI_TRACE("EC_POINT_clear_free(%p) => success", group); -} - -static jboolean NativeCrypto_EC_POINT_cmp(JNIEnv* env, jclass, jlong groupRef, jlong point1Ref, jlong point2Ref) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - const EC_POINT* point1 = reinterpret_cast<const EC_POINT*>(point1Ref); - const EC_POINT* point2 = reinterpret_cast<const EC_POINT*>(point2Ref); - JNI_TRACE("EC_POINT_cmp(%p, %p, %p)", group, point1, point2); - - if (group == NULL || point1 == NULL || point2 == NULL) { - JNI_TRACE("EC_POINT_cmp(%p, %p, %p) => group == null || point1 == null || point2 == null", - group, point1, point2); - jniThrowNullPointerException(env, "group == null || point1 == null || point2 == null"); - return false; - } - - int ret = EC_POINT_cmp(group, point1, point2, (BN_CTX*)NULL); - - JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", point1, point2, ret); - return ret == 0; -} - -static void NativeCrypto_EC_POINT_set_affine_coordinates(JNIEnv* env, jclass, - jlong groupRef, jlong pointRef, jbyteArray xjavaBytes, jbyteArray yjavaBytes) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - EC_POINT* point = reinterpret_cast<EC_POINT*>(pointRef); - JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p)", group, point, xjavaBytes, - yjavaBytes); - - if (group == NULL || point == NULL) { - JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => group == null || point == null", - group, point, xjavaBytes, yjavaBytes); - jniThrowNullPointerException(env, "group == null || point == null"); - return; - } - - BIGNUM* xRef; - if (!arrayToBignum(env, xjavaBytes, &xRef)) { - return; - } - Unique_BIGNUM x(xRef); - - BIGNUM* yRef; - if (!arrayToBignum(env, yjavaBytes, &yRef)) { - return; - } - Unique_BIGNUM y(yRef); - - int ret; - switch (get_EC_GROUP_type(group)) { - case EC_CURVE_GFP: - ret = EC_POINT_set_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL); - break; - case EC_CURVE_GF2M: - ret = EC_POINT_set_affine_coordinates_GF2m(group, point, x.get(), y.get(), NULL); - break; - default: - jniThrowRuntimeException(env, "invalid curve type"); - return; - } - - if (ret != 1) { - throwExceptionIfNecessary(env, "EC_POINT_set_affine_coordinates"); - } - - JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => %d", group, point, - xjavaBytes, yjavaBytes, ret); -} - -static jobjectArray NativeCrypto_EC_POINT_get_affine_coordinates(JNIEnv* env, jclass, jlong groupRef, - jlong pointRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - const EC_POINT* point = reinterpret_cast<const EC_POINT*>(pointRef); - JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", group, point); - - Unique_BIGNUM x(BN_new()); - Unique_BIGNUM y(BN_new()); - - int ret; - switch (get_EC_GROUP_type(group)) { - case EC_CURVE_GFP: - ret = EC_POINT_get_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL); - break; - case EC_CURVE_GF2M: - ret = EC_POINT_get_affine_coordinates_GF2m(group, point, x.get(), y.get(), NULL); - break; - default: - jniThrowRuntimeException(env, "invalid curve type"); - return NULL; - } - if (ret != 1) { - JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", group, point); - throwExceptionIfNecessary(env, "EC_POINT_get_affine_coordinates"); - return NULL; - } - - jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL); - if (joa == NULL) { - return NULL; - } - - jbyteArray xBytes = bignumToArray(env, x.get(), "x"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 0, xBytes); - - jbyteArray yBytes = bignumToArray(env, y.get(), "y"); - if (env->ExceptionCheck()) { - return NULL; - } - env->SetObjectArrayElement(joa, 1, yBytes); - - JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p) => %p", group, point, joa); - return joa; -} - -static jlong NativeCrypto_EC_KEY_generate_key(JNIEnv* env, jclass, jlong groupRef) -{ - const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef); - JNI_TRACE("EC_KEY_generate_key(%p)", group); - - Unique_EC_KEY eckey(EC_KEY_new()); - if (eckey.get() == NULL) { - JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_new() oom", group); - jniThrowOutOfMemory(env, "Unable to create an EC_KEY"); - return 0; - } - - if (EC_KEY_set_group(eckey.get(), group) != 1) { - JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_set_group error", group); - throwExceptionIfNecessary(env, "EC_KEY_set_group"); - return 0; - } - - if (EC_KEY_generate_key(eckey.get()) != 1) { - JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_generate_key error", group); - throwExceptionIfNecessary(env, "EC_KEY_set_group"); - return 0; - } - - Unique_EVP_PKEY pkey(EVP_PKEY_new()); - if (pkey.get() == NULL) { - JNI_TRACE("EC_KEY_generate_key(%p) => threw error", group); - throwExceptionIfNecessary(env, "EC_KEY_generate_key"); - return 0; - } - if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) { - jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed"); - return 0; - } - OWNERSHIP_TRANSFERRED(eckey); - - JNI_TRACE("EC_KEY_generate_key(%p) => %p", group, pkey.get()); - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -static jlong NativeCrypto_EC_KEY_get0_group(JNIEnv* env, jclass, jlong pkeyRef) -{ - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EC_KEY_get0_group(%p)", pkey); - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - JNI_TRACE("EC_KEY_get0_group(%p) => pkey == null", pkey); - return 0; - } - - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { - jniThrowRuntimeException(env, "not EC key"); - JNI_TRACE("EC_KEY_get0_group(%p) => not EC key (type == %d)", pkey, - EVP_PKEY_type(pkey->type)); - return 0; - } - - const EC_GROUP* group = EC_KEY_get0_group(pkey->pkey.ec); - JNI_TRACE("EC_KEY_get0_group(%p) => %p", pkey, group); - return reinterpret_cast<uintptr_t>(group); -} - -static jbyteArray NativeCrypto_EC_KEY_get_private_key(JNIEnv* env, jclass, jlong pkeyRef) -{ - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EC_KEY_get_private_key(%p)", pkey); - - Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); - if (eckey.get() == NULL) { - throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY"); - return NULL; - } - - const BIGNUM *privkey = EC_KEY_get0_private_key(eckey.get()); - - jbyteArray privBytes = bignumToArray(env, privkey, "privkey"); - if (env->ExceptionCheck()) { - JNI_TRACE("EC_KEY_get_private_key(%p) => threw error", pkey); - return NULL; - } - - JNI_TRACE("EC_KEY_get_private_key(%p) => %p", pkey, privBytes); - return privBytes; -} - -static jlong NativeCrypto_EC_KEY_get_public_key(JNIEnv* env, jclass, jlong pkeyRef) -{ - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EC_KEY_get_public_key(%p)", pkey); - - Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); - if (eckey.get() == NULL) { - throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY"); - return 0; - } - - Unique_EC_POINT dup(EC_POINT_dup(EC_KEY_get0_public_key(eckey.get()), - EC_KEY_get0_group(eckey.get()))); - if (dup.get() == NULL) { - JNI_TRACE("EC_KEY_get_public_key(%p) => can't dup public key", pkey); - jniThrowRuntimeException(env, "EC_POINT_dup"); - return 0; - } - - JNI_TRACE("EC_KEY_get_public_key(%p) => %p", pkey, dup.get()); - return reinterpret_cast<uintptr_t>(dup.release()); -} - -static jint NativeCrypto_ECDH_compute_key(JNIEnv* env, jclass, - jbyteArray outArray, jint outOffset, jlong pubkeyRef, jlong privkeyRef) -{ - EVP_PKEY* pubPkey = reinterpret_cast<EVP_PKEY*>(pubkeyRef); - EVP_PKEY* privPkey = reinterpret_cast<EVP_PKEY*>(privkeyRef); - JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p)", outArray, outOffset, pubPkey, privPkey); - - ScopedByteArrayRW out(env, outArray); - if (out.get() == NULL) { - JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p) can't get output buffer", - outArray, outOffset, pubPkey, privPkey); - return -1; - } - - if ((outOffset < 0) || ((size_t) outOffset >= out.size())) { - jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); - return -1; - } - - Unique_EC_KEY pubkey(EVP_PKEY_get1_EC_KEY(pubPkey)); - if (pubkey.get() == NULL) { - JNI_TRACE("ECDH_compute_key(%p) => can't get public key", pubPkey); - throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public"); - return -1; - } - - const EC_POINT* pubkeyPoint = EC_KEY_get0_public_key(pubkey.get()); - if (pubkeyPoint == NULL) { - JNI_TRACE("ECDH_compute_key(%p) => can't get public key point", pubPkey); - throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public"); - return -1; - } - - Unique_EC_KEY privkey(EVP_PKEY_get1_EC_KEY(privPkey)); - if (privkey.get() == NULL) { - throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY private"); - return -1; - } - - int outputLength = ECDH_compute_key( - &out[outOffset], - out.size() - outOffset, - pubkeyPoint, - privkey.get(), - NULL // No KDF - ); - if (outputLength == -1) { - throwExceptionIfNecessary(env, "ECDH_compute_key"); - return -1; - } - - return outputLength; -} - -static jlong NativeCrypto_EVP_MD_CTX_create(JNIEnv* env, jclass) { - JNI_TRACE("EVP_MD_CTX_create()"); - - Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create()); - if (ctx.get() == NULL) { - jniThrowOutOfMemory(env, "Unable create a EVP_MD_CTX"); - return 0; - } - - JNI_TRACE("EVP_MD_CTX_create() => %p", ctx.get()); - return reinterpret_cast<uintptr_t>(ctx.release()); -} - -static void NativeCrypto_EVP_MD_CTX_init(JNIEnv*, jclass, jlong ctxRef) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - JNI_TRACE("NativeCrypto_EVP_MD_CTX_init(%p)", ctx); - - if (ctx != NULL) { - EVP_MD_CTX_init(ctx); - } -} - -static void NativeCrypto_EVP_MD_CTX_destroy(JNIEnv*, jclass, jlong ctxRef) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - JNI_TRACE("NativeCrypto_EVP_MD_CTX_destroy(%p)", ctx); - - if (ctx != NULL) { - EVP_MD_CTX_destroy(ctx); - } -} - -static jlong NativeCrypto_EVP_MD_CTX_copy(JNIEnv* env, jclass, jlong ctxRef) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p)", ctx); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - return 0; - } - - EVP_MD_CTX* copy = EVP_MD_CTX_create(); - if (copy == NULL) { - jniThrowOutOfMemory(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"); - freeOpenSslErrorState(); - return 0; - } - - JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p) => %p", ctx, copy); - return reinterpret_cast<uintptr_t>(copy); -} - -/* - * public static native int EVP_DigestFinal(int, byte[], int) - */ -static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, jlong ctxRef, - jbyteArray hash, jint offset) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d)", ctx, hash, offset); - - if (ctx == NULL || hash == NULL) { - jniThrowNullPointerException(env, "ctx == null || hash == 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 jlong NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, jlong evpMdRef) { - EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef); - 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) { - jniThrowOutOfMemory(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 reinterpret_cast<uintptr_t>(ctx.release()); -} - -/* - * public static native int EVP_get_digestbyname(java.lang.String) - */ -static jlong 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 reinterpret_cast<uintptr_t>(evp_md); -} - -/* - * public static native int EVP_MD_size(int) - */ -static jint NativeCrypto_EVP_MD_size(JNIEnv* env, jclass, jint evpMdRef) { - EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef); - 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, jlong evpMdRef) { - EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef); - 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, jlong ctxRef, - jbyteArray buffer, jint offset, jint length) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - 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"); - } -} - -static void NativeCrypto_EVP_DigestSignInit(JNIEnv* env, jclass, jlong evpMdCtxRef, - const jlong evpMdRef, jlong pkeyRef) { - EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef); - const EVP_MD* md = reinterpret_cast<const EVP_MD*>(evpMdRef); - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("EVP_DigestSignInit(%p, %p, %p)", mdCtx, md, pkey); - - if (mdCtx == NULL) { - jniThrowNullPointerException(env, "mdCtx == null"); - return; - } - - if (md == NULL) { - jniThrowNullPointerException(env, "md == null"); - return; - } - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - return; - } - - if (EVP_DigestSignInit(mdCtx, (EVP_PKEY_CTX **) NULL, md, (ENGINE *) NULL, pkey) <= 0) { - JNI_TRACE("ctx=%p EVP_DigestSignInit => threw exception", mdCtx); - throwExceptionIfNecessary(env, "EVP_DigestSignInit"); - return; - } - - JNI_TRACE("EVP_DigestSignInit(%p, %p, %p) => success", mdCtx, md, pkey); -} - -static void NativeCrypto_EVP_DigestSignUpdate(JNIEnv* env, jclass, jint evpMdCtxRef, - jbyteArray inJavaBytes, jint inOffset, jint inLength) -{ - EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef); - JNI_TRACE("EVP_DigestSignUpdate(%p, %p, %d, %d)", mdCtx, inJavaBytes, inOffset, inLength); - - if (mdCtx == NULL) { - jniThrowNullPointerException(env, "mdCtx == null"); - return; - } - - ScopedByteArrayRO inBytes(env, inJavaBytes); - if (inBytes.get() == NULL) { - return; - } - - if (inOffset < 0 || size_t(inOffset) > inBytes.size()) { - jniThrowException(env, "java/lang/IndexOutOfBoundsException", "inOffset"); - return; - } - - const ssize_t inEnd = inOffset + inLength; - if (inEnd < 0 || size_t(inEnd) >= inBytes.size()) { - jniThrowException(env, "java/lang/IndexOutOfBoundsException", "inLength"); - return; - } - - const unsigned char *tmp = reinterpret_cast<const unsigned char *>(inBytes.get()); - if (!EVP_DigestSignUpdate(mdCtx, tmp + inOffset, inLength)) { - JNI_TRACE("ctx=%p EVP_DigestSignUpdate => threw exception", mdCtx); - throwExceptionIfNecessary(env, "EVP_DigestSignUpdate"); - } - - JNI_TRACE("EVP_DigestSignUpdate(%p, %p, %d, %d) => success", mdCtx, inJavaBytes, inOffset, - inLength); -} - -static jbyteArray NativeCrypto_EVP_DigestSignFinal(JNIEnv* env, jclass, jlong evpMdCtxRef) -{ - EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef); - JNI_TRACE("EVP_DigestSignFinal(%p)", mdCtx); - - if (mdCtx == NULL) { - jniThrowNullPointerException(env, "mdCtx == null"); - return NULL; - } - - const size_t expectedSize = EVP_MD_CTX_size(mdCtx); - ScopedLocalRef<jbyteArray> outJavaBytes(env, env->NewByteArray(expectedSize)); - if (outJavaBytes.get() == NULL) { - return NULL; - } - ScopedByteArrayRW outBytes(env, outJavaBytes.get()); - if (outBytes.get() == NULL) { - return NULL; - } - unsigned char *tmp = reinterpret_cast<unsigned char*>(outBytes.get()); - size_t len; - if (!EVP_DigestSignFinal(mdCtx, tmp, &len)) { - JNI_TRACE("ctx=%p EVP_DigestSignFinal => threw exception", mdCtx); - throwExceptionIfNecessary(env, "EVP_DigestSignFinal"); - return 0; - } - - if (len != expectedSize) { - jniThrowRuntimeException(env, "hash size unexpected"); - return 0; - } - - JNI_TRACE("EVP_DigestSignFinal(%p) => %p", mdCtx, outJavaBytes.get()); - return outJavaBytes.release(); -} - -static jlong NativeCrypto_EVP_SignInit(JNIEnv* env, jclass, jstring algorithm) { - JNI_TRACE("NativeCrypto_EVP_SignInit(%p)", algorithm); - - if (algorithm == NULL) { - jniThrowNullPointerException(env, NULL); - return 0; - } - - Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create()); - if (ctx.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate EVP_MD_CTX"); - return 0; - } - JNI_TRACE("NativeCrypto_EVP_SignInit ctx=%p", ctx.get()); - - ScopedUtfChars algorithmChars(env, algorithm); - if (algorithmChars.c_str() == NULL) { - return 0; - } - JNI_TRACE("NativeCrypto_EVP_SignInit algorithmChars=%s", algorithmChars.c_str()); - - const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str())); - if (digest == NULL) { - JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => hash not found", algorithmChars.c_str()); - throwExceptionIfNecessary(env, "Hash algorithm not found"); - return 0; - } - - int ok = EVP_SignInit(ctx.get(), digest); - if (ok == 0) { - bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignInit"); - if (exception) { - JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => threw exception", algorithmChars.c_str()); - return 0; - } - } - - JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => %p", algorithmChars.c_str(), ctx.get()); - return reinterpret_cast<uintptr_t>(ctx.release()); -} - -/* - * public static native void EVP_SignUpdate(int, byte[], int, int) - */ -static void NativeCrypto_EVP_SignUpdate(JNIEnv* env, jclass, jlong ctxRef, - jbyteArray buffer, jint offset, jint length) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - JNI_TRACE("NativeCrypto_EVP_SignUpdate(%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_SignUpdate(ctx, - reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset), - length); - if (ok == 0) { - throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignUpdate"); - } -} - -/* - * public static native int EVP_SignFinal(int, byte[], int, int) - */ -static jint NativeCrypto_EVP_SignFinal(JNIEnv* env, jclass, jlong ctxRef, jbyteArray signature, - jint offset, jlong pkeyRef) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p)", ctx, signature, offset, pkey); - - if (ctx == NULL || pkey == NULL) { - jniThrowNullPointerException(env, NULL); - return -1; - } - - ScopedByteArrayRW signatureBytes(env, signature); - if (signatureBytes.get() == NULL) { - return -1; - } - unsigned int bytesWritten = -1; - int ok = EVP_SignFinal(ctx, - reinterpret_cast<unsigned char*>(signatureBytes.get() + offset), - &bytesWritten, - pkey); - if (ok == 0) { - throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignFinal"); - } - JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) => %u", - ctx, signature, offset, pkey, bytesWritten); - - return bytesWritten; -} - -/* - * public static native int EVP_VerifyInit(java.lang.String) - */ -static jlong 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) { - jniThrowOutOfMemory(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 reinterpret_cast<uintptr_t>(ctx.release()); -} - -/* - * public static native void EVP_VerifyUpdate(int, byte[], int, int) - */ -static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, jlong ctxRef, - jbyteArray buffer, jint offset, jint length) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - 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 jint NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, jlong ctxRef, jbyteArray buffer, - jint offset, jint length, jlong pkeyRef) { - EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - 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"); - } - - /* - * For DSA keys, OpenSSL appears to have a bug where it returns - * errors for any result != 1. See dsa_ossl.c in dsa_do_verify - */ - freeOpenSslErrorState(); - - JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d", - ctx, buffer, offset, length, pkey, ok); - - return ok; -} - -static jlong NativeCrypto_EVP_get_cipherbyname(JNIEnv* env, jclass, jstring algorithm) { - JNI_TRACE("EVP_get_cipherbyname(%p)", algorithm); - if (algorithm == NULL) { - JNI_TRACE("EVP_get_cipherbyname(%p) => threw exception algorithm == null", algorithm); - jniThrowNullPointerException(env, NULL); - return -1; - } - - ScopedUtfChars algorithmChars(env, algorithm); - if (algorithmChars.c_str() == NULL) { - return 0; - } - JNI_TRACE("EVP_get_cipherbyname(%p) => algorithm = %s", algorithm, algorithmChars.c_str()); - - const EVP_CIPHER* evp_cipher = EVP_get_cipherbyname(algorithmChars.c_str()); - if (evp_cipher == NULL) { - freeOpenSslErrorState(); - } - - JNI_TRACE("EVP_get_cipherbyname(%s) => %p", algorithmChars.c_str(), evp_cipher); - return reinterpret_cast<uintptr_t>(evp_cipher); -} - -static void NativeCrypto_EVP_CipherInit_ex(JNIEnv* env, jclass, jlong ctxRef, jlong evpCipherRef, - jbyteArray keyArray, jbyteArray ivArray, jboolean encrypting) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef); - JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d)", ctx, evpCipher, keyArray, ivArray, - encrypting ? 1 : 0); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - JNI_TRACE("EVP_CipherUpdate => ctx == null"); - return; - } - - // The key can be null if we need to set extra parameters. - UniquePtr<unsigned char[]> keyPtr; - if (keyArray != NULL) { - ScopedByteArrayRO keyBytes(env, keyArray); - if (keyBytes.get() == NULL) { - return; - } - - keyPtr.reset(new unsigned char[keyBytes.size()]); - memcpy(keyPtr.get(), keyBytes.get(), keyBytes.size()); - } - - // The IV can be null if we're using ECB. - UniquePtr<unsigned char[]> ivPtr; - if (ivArray != NULL) { - ScopedByteArrayRO ivBytes(env, ivArray); - if (ivBytes.get() == NULL) { - return; - } - - ivPtr.reset(new unsigned char[ivBytes.size()]); - memcpy(ivPtr.get(), ivBytes.get(), ivBytes.size()); - } - - if (!EVP_CipherInit_ex(ctx, evpCipher, NULL, keyPtr.get(), ivPtr.get(), encrypting ? 1 : 0)) { - throwExceptionIfNecessary(env, "EVP_CipherInit_ex"); - JNI_TRACE("EVP_CipherInit_ex => error initializing cipher"); - return; - } - - JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d) => success", ctx, evpCipher, keyArray, ivArray, - encrypting ? 1 : 0); -} - -/* - * public static native int EVP_CipherUpdate(int ctx, byte[] out, int outOffset, byte[] in, - * int inOffset); - */ -static jint NativeCrypto_EVP_CipherUpdate(JNIEnv* env, jclass, jlong ctxRef, jbyteArray outArray, - jint outOffset, jbyteArray inArray, jint inOffset, jint inLength) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d)", ctx, outArray, outOffset, inArray, inOffset); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - JNI_TRACE("ctx=%p EVP_CipherUpdate => ctx == null", ctx); - return 0; - } - - ScopedByteArrayRO inBytes(env, inArray); - if (inBytes.get() == NULL) { - return 0; - } - const size_t inSize = inBytes.size(); - if (size_t(inOffset + inLength) > inSize) { - jniThrowException(env, "java/lang/IndexOutOfBoundsException", - "in.length < (inSize + inOffset)"); - return 0; - } - - ScopedByteArrayRW outBytes(env, outArray); - if (outBytes.get() == NULL) { - return 0; - } - const size_t outSize = outBytes.size(); - if (size_t(outOffset + inLength) > outSize) { - jniThrowException(env, "java/lang/IndexOutOfBoundsException", - "out.length < inSize + outOffset + blockSize - 1"); - return 0; - } - - JNI_TRACE("ctx=%p EVP_CipherUpdate in=%p in.length=%d inOffset=%d inLength=%d out=%p out.length=%d outOffset=%d", - ctx, inBytes.get(), inBytes.size(), inOffset, inLength, outBytes.get(), outBytes.size(), outOffset); - - unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get()); - const unsigned char* in = reinterpret_cast<const unsigned char*>(inBytes.get()); - - int outl; - if (!EVP_CipherUpdate(ctx, out + outOffset, &outl, in + inOffset, inLength)) { - throwExceptionIfNecessary(env, "EVP_CipherUpdate"); - JNI_TRACE("ctx=%p EVP_CipherUpdate => threw error", ctx); - return 0; - } - - JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d) => %d", ctx, outArray, outOffset, inArray, - inOffset, outl); - return outl; -} - -static jint NativeCrypto_EVP_CipherFinal_ex(JNIEnv* env, jclass, jlong ctxRef, jbyteArray outArray, - jint outOffset) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - JNI_TRACE("EVP_CipherFinal_ex(%p, %p, %d)", ctx, outArray, outOffset); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - JNI_TRACE("ctx=%p EVP_CipherFinal_ex => ctx == null", ctx); - return 0; - } - - ScopedByteArrayRW outBytes(env, outArray); - if (outBytes.get() == NULL) { - return 0; - } - - unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get()); - - int outl; - if (!EVP_CipherFinal_ex(ctx, out + outOffset, &outl)) { - throwExceptionIfNecessary(env, "EVP_CipherFinal_ex"); - JNI_TRACE("ctx=%p EVP_CipherFinal_ex => threw error", ctx); - return 0; - } - - JNI_TRACE("EVP_CipherFinal(%p, %p, %d) => %d", ctx, outArray, outOffset, outl); - return outl; -} - -static jint NativeCrypto_EVP_CIPHER_iv_length(JNIEnv* env, jclass, jlong evpCipherRef) { - const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef); - JNI_TRACE("EVP_CIPHER_iv_length(%p)", evpCipher); - - if (evpCipher == NULL) { - jniThrowNullPointerException(env, "evpCipher == null"); - JNI_TRACE("EVP_CIPHER_iv_length => evpCipher == null"); - return 0; - } - - const int ivLength = EVP_CIPHER_iv_length(evpCipher); - JNI_TRACE("EVP_CIPHER_iv_length(%p) => %d", evpCipher, ivLength); - return ivLength; -} - -static jlong NativeCrypto_EVP_CIPHER_CTX_new(JNIEnv* env, jclass) { - JNI_TRACE("EVP_CIPHER_CTX_new()"); - - Unique_EVP_CIPHER_CTX ctx(EVP_CIPHER_CTX_new()); - if (ctx.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate cipher context"); - JNI_TRACE("EVP_CipherInit_ex => context allocation error"); - return 0; - } - - JNI_TRACE("EVP_CIPHER_CTX_new() => %p", ctx.get()); - return reinterpret_cast<uintptr_t>(ctx.release()); -} - -static jint NativeCrypto_EVP_CIPHER_CTX_block_size(JNIEnv* env, jclass, jlong ctxRef) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - JNI_TRACE("EVP_CIPHER_CTX_block_size(%p)", ctx); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - JNI_TRACE("ctx=%p EVP_CIPHER_CTX_block_size => ctx == null", ctx); - return 0; - } - - int blockSize = EVP_CIPHER_CTX_block_size(ctx); - JNI_TRACE("EVP_CIPHER_CTX_block_size(%p) => %d", ctx, blockSize); - return blockSize; -} - -static jint NativeCrypto_get_EVP_CIPHER_CTX_buf_len(JNIEnv* env, jclass, jlong ctxRef) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p)", ctx); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - JNI_TRACE("ctx=%p get_EVP_CIPHER_CTX_buf_len => ctx == null", ctx); - return 0; - } - - int buf_len = ctx->buf_len; - JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p) => %d", ctx, buf_len); - return buf_len; -} - -static void NativeCrypto_EVP_CIPHER_CTX_set_padding(JNIEnv* env, jclass, jlong ctxRef, jboolean enablePaddingBool) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - jint enablePadding = enablePaddingBool ? 1 : 0; - JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d)", ctx, enablePadding); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_padding => ctx == null", ctx); - return; - } - - EVP_CIPHER_CTX_set_padding(ctx, enablePadding); // Not void, but always returns 1. - JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d) => success", ctx, enablePadding); -} - -static void NativeCrypto_EVP_CIPHER_CTX_set_key_length(JNIEnv* env, jclass, jlong ctxRef, - jint keySizeBits) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d)", ctx, keySizeBits); - - if (ctx == NULL) { - jniThrowNullPointerException(env, "ctx == null"); - JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_key_length => ctx == null", ctx); - return; - } - - if (!EVP_CIPHER_CTX_set_key_length(ctx, keySizeBits)) { - throwExceptionIfNecessary(env, "NativeCrypto_EVP_CIPHER_CTX_set_key_length"); - JNI_TRACE("NativeCrypto_EVP_CIPHER_CTX_set_key_length => threw error"); - return; - } - JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d) => success", ctx, keySizeBits); -} - -static void NativeCrypto_EVP_CIPHER_CTX_cleanup(JNIEnv* env, jclass, jlong ctxRef) { - EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); - JNI_TRACE("EVP_CIPHER_CTX_cleanup(%p)", ctx); - - if (ctx != NULL) { - if (!EVP_CIPHER_CTX_cleanup(ctx)) { - throwExceptionIfNecessary(env, "EVP_CIPHER_CTX_cleanup"); - JNI_TRACE("EVP_CIPHER_CTX_cleanup => threw error"); - return; - } - } - JNI_TRACE("EVP_CIPHER_CTX_cleanup(%p) => success", ctx); -} - -/** - * public static native void RAND_seed(byte[]); - */ -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 jint 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; -} - -static void NativeCrypto_RAND_bytes(JNIEnv* env, jclass, jbyteArray output) { - JNI_TRACE("NativeCrypto_RAND_bytes(%p)", output); - - ScopedByteArrayRW outputBytes(env, output); - if (outputBytes.get() == NULL) { - return; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(outputBytes.get()); - if (RAND_bytes(tmp, outputBytes.size()) <= 0) { - throwExceptionIfNecessary(env, "NativeCrypto_RAND_bytes"); - JNI_TRACE("tmp=%p NativeCrypto_RAND_bytes => threw error", tmp); - return; - } - - JNI_TRACE("NativeCrypto_RAND_bytes(%p) => success", output); -} - -static jint NativeCrypto_OBJ_txt2nid(JNIEnv* env, jclass, jstring oidStr) { - JNI_TRACE("OBJ_txt2nid(%p)", oidStr); - - ScopedUtfChars oid(env, oidStr); - if (oid.c_str() == NULL) { - return 0; - } - - int nid = OBJ_txt2nid(oid.c_str()); - JNI_TRACE("OBJ_txt2nid(%s) => %d", oid.c_str(), nid); - return nid; -} - -static jstring NativeCrypto_OBJ_txt2nid_longName(JNIEnv* env, jclass, jstring oidStr) { - JNI_TRACE("OBJ_txt2nid_longName(%p)", oidStr); - - ScopedUtfChars oid(env, oidStr); - if (oid.c_str() == NULL) { - return NULL; - } - - JNI_TRACE("OBJ_txt2nid_longName(%s)", oid.c_str()); - - int nid = OBJ_txt2nid(oid.c_str()); - if (nid == NID_undef) { - JNI_TRACE("OBJ_txt2nid_longName(%s) => NID_undef", oid.c_str()); - freeOpenSslErrorState(); - return NULL; - } - - const char* longName = OBJ_nid2ln(nid); - JNI_TRACE("OBJ_txt2nid_longName(%s) => %s", oid.c_str(), longName); - return env->NewStringUTF(longName); -} - -static jstring ASN1_OBJECT_to_OID_string(JNIEnv* env, ASN1_OBJECT* obj) { - /* - * The OBJ_obj2txt API doesn't "measure" if you pass in NULL as the buffer. - * Just make a buffer that's large enough here. The documentation recommends - * 80 characters. - */ - char output[128]; - int ret = OBJ_obj2txt(output, sizeof(output), obj, 1); - if (ret < 0) { - throwExceptionIfNecessary(env, "ASN1_OBJECT_to_OID_string"); - return NULL; - } else if (size_t(ret) >= sizeof(output)) { - jniThrowRuntimeException(env, "ASN1_OBJECT_to_OID_string buffer too small"); - return NULL; - } - - JNI_TRACE("ASN1_OBJECT_to_OID_string(%p) => %s", obj, output); - return env->NewStringUTF(output); -} - -static jlong NativeCrypto_create_BIO_InputStream(JNIEnv* env, jclass, jobject streamObj) { - JNI_TRACE("create_BIO_InputStream(%p)", streamObj); - - if (streamObj == NULL) { - jniThrowNullPointerException(env, "stream == null"); - return 0; - } - - Unique_BIO bio(BIO_new(&stream_bio_method)); - if (bio.get() == NULL) { - return 0; - } - - bio_stream_assign(bio.get(), new BIO_InputStream(streamObj)); - - JNI_TRACE("create_BIO_InputStream(%p) => %p", streamObj, bio.get()); - return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release())); -} - -static jlong NativeCrypto_create_BIO_OutputStream(JNIEnv* env, jclass, jobject streamObj) { - JNI_TRACE("create_BIO_OutputStream(%p)", streamObj); - - if (streamObj == NULL) { - jniThrowNullPointerException(env, "stream == null"); - return 0; - } - - Unique_BIO bio(BIO_new(&stream_bio_method)); - if (bio.get() == NULL) { - return 0; - } - - bio_stream_assign(bio.get(), new BIO_OutputStream(streamObj)); - - JNI_TRACE("create_BIO_OutputStream(%p) => %p", streamObj, bio.get()); - return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release())); -} - -static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("BIO_read(%p, %p)", bio, outputJavaBytes); - - if (outputJavaBytes == NULL) { - jniThrowNullPointerException(env, "output == null"); - JNI_TRACE("BIO_read(%p, %p) => output == null", bio, outputJavaBytes); - return 0; - } - - int outputSize = env->GetArrayLength(outputJavaBytes); - - UniquePtr<unsigned char[]> buffer(new unsigned char[outputSize]); - if (buffer.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate buffer for read"); - return 0; - } - - int read = BIO_read(bio, buffer.get(), outputSize); - if (read <= 0) { - jniThrowException(env, "java/io/IOException", "BIO_read"); - JNI_TRACE("BIO_read(%p, %p) => threw IO exception", bio, outputJavaBytes); - return 0; - } - - env->SetByteArrayRegion(outputJavaBytes, 0, read, reinterpret_cast<jbyte*>(buffer.get())); - JNI_TRACE("BIO_read(%p, %p) => %d", bio, outputJavaBytes, read); - return read; -} - -static void NativeCrypto_BIO_write(JNIEnv* env, jclass, jlong bioRef, jbyteArray inputJavaBytes, - jint offset, jint length) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("BIO_write(%p, %p, %d, %d)", bio, inputJavaBytes, offset, length); - - if (inputJavaBytes == NULL) { - jniThrowNullPointerException(env, "input == null"); - return; - } - - if (offset < 0 || length < 0) { - jniThrowException(env, "java/lang/IndexOutOfBoundsException", "offset < 0 || length < 0"); - JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length); - return; - } - - int inputSize = env->GetArrayLength(inputJavaBytes); - if (inputSize < offset + length) { - jniThrowException(env, "java/lang/IndexOutOfBoundsException", - "input.length < offset + length"); - JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length); - return; - } - - UniquePtr<unsigned char[]> buffer(new unsigned char[length]); - if (buffer.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate buffer for write"); - return; - } - - env->GetByteArrayRegion(inputJavaBytes, offset, length, reinterpret_cast<jbyte*>(buffer.get())); - if (BIO_write(bio, buffer.get(), length) != length) { - freeOpenSslErrorState(); - jniThrowException(env, "java/io/IOException", "BIO_write"); - JNI_TRACE("BIO_write(%p, %p, %d, %d) => IO error", bio, inputJavaBytes, offset, length); - return; - } - - JNI_TRACE("BIO_write(%p, %p, %d, %d) => success", bio, inputJavaBytes, offset, length); -} - -static void NativeCrypto_BIO_free(JNIEnv* env, jclass, jlong bioRef) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("BIO_free(%p)", bio); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - return; - } - - BIO_free(bio); -} - -static jstring X509_NAME_to_jstring(JNIEnv* env, X509_NAME* name, unsigned long flags) { - JNI_TRACE("X509_NAME_to_jstring(%p)", name); - - Unique_BIO buffer(BIO_new(BIO_s_mem())); - if (buffer.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate BIO"); - JNI_TRACE("X509_NAME_to_jstring(%p) => threw error", name); - return NULL; - } - - /* Don't interpret the string. */ - flags &= ~(ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_MSB); - - /* Write in given format and null terminate. */ - X509_NAME_print_ex(buffer.get(), name, 0, flags); - BIO_write(buffer.get(), "\0", 1); - - char *tmp; - BIO_get_mem_data(buffer.get(), &tmp); - JNI_TRACE("X509_NAME_to_jstring(%p) => \"%s\"", name, tmp); - return env->NewStringUTF(tmp); -} - - -/** - * Converts GENERAL_NAME items to the output format expected in - * X509Certificate#getSubjectAlternativeNames and - * X509Certificate#getIssuerAlternativeNames return. - */ -static jobject GENERAL_NAME_to_jobject(JNIEnv* env, GENERAL_NAME* gen) { - switch (gen->type) { - case GEN_EMAIL: - case GEN_DNS: - case GEN_URI: { - // This must not be a T61String and must not contain NULLs. - const char* data = reinterpret_cast<const char*>(ASN1_STRING_data(gen->d.ia5)); - ssize_t len = ASN1_STRING_length(gen->d.ia5); - if ((len == static_cast<ssize_t>(strlen(data))) - && (ASN1_PRINTABLE_type(ASN1_STRING_data(gen->d.ia5), len) != V_ASN1_T61STRING)) { - JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI \"%s\"", gen, data); - return env->NewStringUTF(data); - } else { - jniThrowException(env, "java/security/cert/CertificateParsingException", - "Invalid dNSName encoding"); - JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI invalid", gen); - return NULL; - } - } - case GEN_DIRNAME: - /* Write in RFC 2253 format */ - return X509_NAME_to_jstring(env, gen->d.directoryName, XN_FLAG_RFC2253); - case GEN_IPADD: { - const void *ip = reinterpret_cast<const void *>(gen->d.ip->data); - if (gen->d.ip->length == 4) { - // IPv4 - UniquePtr<char[]> buffer(new char[INET_ADDRSTRLEN]); - if (inet_ntop(AF_INET, ip, buffer.get(), INET_ADDRSTRLEN) != NULL) { - JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 %s", gen, buffer.get()); - return env->NewStringUTF(buffer.get()); - } else { - JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 failed %s", gen, strerror(errno)); - } - } else if (gen->d.ip->length == 16) { - // IPv6 - UniquePtr<char[]> buffer(new char[INET6_ADDRSTRLEN]); - if (inet_ntop(AF_INET6, ip, buffer.get(), INET6_ADDRSTRLEN) != NULL) { - JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 %s", gen, buffer.get()); - return env->NewStringUTF(buffer.get()); - } else { - JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 failed %s", gen, strerror(errno)); - } - } - - /* Invalid IP encodings are pruned out without throwing an exception. */ - return NULL; - } - case GEN_RID: - return ASN1_OBJECT_to_OID_string(env, gen->d.registeredID); - case GEN_OTHERNAME: - case GEN_X400: - default: - return ASN1ToByteArray<GENERAL_NAME, i2d_GENERAL_NAME>(env, gen); - } - - return NULL; -} - -#define GN_STACK_SUBJECT_ALT_NAME 1 -#define GN_STACK_ISSUER_ALT_NAME 2 - -static jobjectArray NativeCrypto_get_X509_GENERAL_NAME_stack(JNIEnv* env, jclass, jlong x509Ref, - jint type) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d)", x509, type); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => x509 == null", x509, type); - return NULL; - } - - X509_check_ca(x509); - - STACK_OF(GENERAL_NAME)* gn_stack; - Unique_sk_GENERAL_NAME stackHolder; - if (type == GN_STACK_SUBJECT_ALT_NAME) { - gn_stack = x509->altname; - } else if (type == GN_STACK_ISSUER_ALT_NAME) { - stackHolder.reset( - static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(x509, NID_issuer_alt_name, - NULL, NULL))); - gn_stack = stackHolder.get(); - } else { - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => unknown type", x509, type); - return NULL; - } - - int count = sk_GENERAL_NAME_num(gn_stack); - if (count <= 0) { - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => null (no entries)", x509, type); - return NULL; - } - - /* - * Keep track of how many originally so we can ignore any invalid - * values later. - */ - const int origCount = count; - - ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, objectArrayClass, NULL)); - for (int i = 0, j = 0; i < origCount; i++, j++) { - GENERAL_NAME* gen = sk_GENERAL_NAME_value(gn_stack, i); - ScopedLocalRef<jobject> val(env, GENERAL_NAME_to_jobject(env, gen)); - if (env->ExceptionCheck()) { - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => threw exception parsing gen name", - x509, type); - return NULL; - } - - /* - * If it's NULL, we'll have to skip this, reduce the number of total - * entries, and fix up the array later. - */ - if (val.get() == NULL) { - j--; - count--; - continue; - } - - ScopedLocalRef<jobjectArray> item(env, env->NewObjectArray(2, objectClass, NULL)); - - ScopedLocalRef<jobject> type(env, env->CallStaticObjectMethod(integerClass, - integer_valueOfMethod, gen->type)); - env->SetObjectArrayElement(item.get(), 0, type.get()); - env->SetObjectArrayElement(item.get(), 1, val.get()); - - env->SetObjectArrayElement(joa.get(), j, item.get()); - } - - if (count == 0) { - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to 0; returning NULL", - x509, type, origCount); - joa.reset(NULL); - } else if (origCount != count) { - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to %d", x509, type, - origCount, count); - - ScopedLocalRef<jobjectArray> joa_copy(env, env->NewObjectArray(count, objectArrayClass, - NULL)); - - for (int i = 0; i < count; i++) { - ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(joa.get(), i)); - env->SetObjectArrayElement(joa_copy.get(), i, item.get()); - } - - joa.reset(joa_copy.release()); - } - - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => %d entries", x509, type, count); - return joa.release(); -} - -static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_notBefore(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("X509_get_notBefore(%p) => x509 == null", x509); - return 0; - } - - ASN1_TIME* notBefore = X509_get_notBefore(x509); - JNI_TRACE("X509_get_notBefore(%p) => %p", x509, notBefore); - return reinterpret_cast<uintptr_t>(notBefore); -} - -static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_notAfter(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("X509_get_notAfter(%p) => x509 == null", x509); - return 0; - } - - ASN1_TIME* notAfter = X509_get_notAfter(x509); - JNI_TRACE("X509_get_notAfter(%p) => %p", x509, notAfter); - return reinterpret_cast<uintptr_t>(notAfter); -} - -static long NativeCrypto_X509_get_version(JNIEnv*, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_version(%p)", x509); - - long version = X509_get_version(x509); - JNI_TRACE("X509_get_version(%p) => %ld", x509, version); - return version; -} - -template<typename T> -static jbyteArray get_X509Type_serialNumber(JNIEnv* env, T* x509Type, ASN1_INTEGER* (*get_serial_func)(T*)) { - JNI_TRACE("get_X509Type_serialNumber(%p)", x509Type); - - if (x509Type == NULL) { - jniThrowNullPointerException(env, "x509Type == null"); - JNI_TRACE("get_X509Type_serialNumber(%p) => x509Type == null", x509Type); - return NULL; - } - - ASN1_INTEGER* serialNumber = get_serial_func(x509Type); - Unique_BIGNUM serialBn(ASN1_INTEGER_to_BN(serialNumber, NULL)); - if (serialBn.get() == NULL) { - JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type); - return NULL; - } - - ScopedLocalRef<jbyteArray> serialArray(env, bignumToArray(env, serialBn.get(), "serialBn")); - if (env->ExceptionCheck()) { - JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type); - return NULL; - } - - JNI_TRACE("X509_get_serialNumber(%p) => %p", x509Type, serialArray.get()); - return serialArray.release(); -} - -/* OpenSSL includes set_serialNumber but not get. */ -#if !defined(X509_REVOKED_get_serialNumber) -static ASN1_INTEGER* X509_REVOKED_get_serialNumber(X509_REVOKED* x) { - return x->serialNumber; -} -#endif - -static jbyteArray NativeCrypto_X509_get_serialNumber(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_serialNumber(%p)", x509); - return get_X509Type_serialNumber<X509>(env, x509, X509_get_serialNumber); -} - -static jbyteArray NativeCrypto_X509_REVOKED_get_serialNumber(JNIEnv* env, jclass, jlong x509RevokedRef) { - X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); - JNI_TRACE("X509_REVOKED_get_serialNumber(%p)", revoked); - return get_X509Type_serialNumber<X509_REVOKED>(env, revoked, X509_REVOKED_get_serialNumber); -} - -static void NativeCrypto_X509_verify(JNIEnv* env, jclass, jlong x509Ref, jlong pkeyRef) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("X509_verify(%p, %p)", x509, pkey); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("X509_verify(%p, %p) => x509 == null", x509, pkey); - return; - } - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - JNI_TRACE("X509_verify(%p, %p) => pkey == null", x509, pkey); - return; - } - - if (X509_verify(x509, pkey) != 1) { - throwExceptionIfNecessary(env, "X509_verify"); - JNI_TRACE("X509_verify(%p, %p) => verify failure", x509, pkey); - } else { - JNI_TRACE("X509_verify(%p, %p) => verify success", x509, pkey); - } -} - -static jbyteArray NativeCrypto_get_X509_cert_info_enc(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_cert_info_enc(%p)", x509); - return ASN1ToByteArray<X509_CINF, i2d_X509_CINF>(env, x509->cert_info); -} - -static jint NativeCrypto_get_X509_ex_flags(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_ex_flags(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_ex_flags(%p) => x509 == null", x509); - return 0; - } - - X509_check_ca(x509); - - return x509->ex_flags; -} - -static jboolean NativeCrypto_X509_check_issued(JNIEnv*, jclass, jlong x509Ref1, jlong x509Ref2) { - X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1)); - X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2)); - JNI_TRACE("X509_check_issued(%p, %p)", x509_1, x509_2); - - int ret = X509_check_issued(x509_1, x509_2); - JNI_TRACE("X509_check_issued(%p, %p) => %d", x509_1, x509_2, ret); - return ret; -} - -static void get_X509_signature(X509 *x509, ASN1_BIT_STRING** signature) { - *signature = x509->signature; -} - -static void get_X509_CRL_signature(X509_CRL *crl, ASN1_BIT_STRING** signature) { - *signature = crl->signature; -} - -template<typename T> -static jbyteArray get_X509Type_signature(JNIEnv* env, T* x509Type, void (*get_signature_func)(T*, ASN1_BIT_STRING**)) { - JNI_TRACE("get_X509Type_signature(%p)", x509Type); - - if (x509Type == NULL) { - jniThrowNullPointerException(env, "x509Type == null"); - JNI_TRACE("get_X509Type_signature(%p) => x509Type == null", x509Type); - return NULL; - } - - ASN1_BIT_STRING* signature; - get_signature_func(x509Type, &signature); - - ScopedLocalRef<jbyteArray> signatureArray(env, env->NewByteArray(signature->length)); - if (env->ExceptionCheck()) { - JNI_TRACE("get_X509Type_signature(%p) => threw exception", x509Type); - return NULL; - } - - ScopedByteArrayRW signatureBytes(env, signatureArray.get()); - if (signatureBytes.get() == NULL) { - JNI_TRACE("get_X509Type_signature(%p) => using byte array failed", x509Type); - return NULL; - } - - memcpy(signatureBytes.get(), signature->data, signature->length); - - JNI_TRACE("get_X509Type_signature(%p) => %p (%d bytes)", x509Type, signatureArray.get(), - signature->length); - return signatureArray.release(); -} - -static jbyteArray NativeCrypto_get_X509_signature(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_signature(%p)", x509); - return get_X509Type_signature<X509>(env, x509, get_X509_signature); -} - -static jbyteArray NativeCrypto_get_X509_CRL_signature(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("get_X509_CRL_signature(%p)", crl); - return get_X509Type_signature<X509_CRL>(env, crl, get_X509_CRL_signature); -} - -static jlong NativeCrypto_X509_CRL_get0_by_cert(JNIEnv* env, jclass, jlong x509crlRef, jlong x509Ref) { - X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef)); - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_CRL_get0_by_cert(%p, %p)", x509crl, x509); - - if (x509crl == NULL) { - jniThrowNullPointerException(env, "x509crl == null"); - JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509crl == null", x509crl, x509); - return 0; - } else if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509 == null", x509crl, x509); - return 0; - } - - X509_REVOKED* revoked = NULL; - int ret = X509_CRL_get0_by_cert(x509crl, &revoked, x509); - if (ret == 0) { - JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => none", x509crl, x509); - return 0; - } - - JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, x509, revoked); - return reinterpret_cast<uintptr_t>(revoked); -} - -static jlong NativeCrypto_X509_CRL_get0_by_serial(JNIEnv* env, jclass, jlong x509crlRef, jbyteArray serialArray) { - X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef)); - JNI_TRACE("X509_CRL_get0_by_serial(%p, %p)", x509crl, serialArray); - - if (x509crl == NULL) { - jniThrowNullPointerException(env, "x509crl == null"); - JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => crl == null", x509crl, serialArray); - return 0; - } - - Unique_BIGNUM serialBn(BN_new()); - if (serialBn.get() == NULL) { - JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN allocation failed", x509crl, serialArray); - return 0; - } - - BIGNUM* serialBare = serialBn.get(); - if (!arrayToBignum(env, serialArray, &serialBare)) { - if (!env->ExceptionCheck()) { - jniThrowNullPointerException(env, "serial == null"); - } - JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray); - return 0; - } - - Unique_ASN1_INTEGER serialInteger(BN_to_ASN1_INTEGER(serialBn.get(), NULL)); - if (serialInteger.get() == NULL) { - JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray); - return 0; - } - - X509_REVOKED* revoked = NULL; - int ret = X509_CRL_get0_by_serial(x509crl, &revoked, serialInteger.get()); - if (ret == 0) { - JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => none", x509crl, serialArray); - return 0; - } - - JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, serialArray, revoked); - return reinterpret_cast<uintptr_t>(revoked); -} - - -/* This appears to be missing from OpenSSL. */ -#if !defined(X509_REVOKED_dup) -X509_REVOKED* X509_REVOKED_dup(X509_REVOKED* x) { - return reinterpret_cast<X509_REVOKED*>(ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), x)); -} -#endif - -static jlongArray NativeCrypto_X509_CRL_get_REVOKED(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_get_REVOKED(%p)", crl); - - if (crl == NULL) { - jniThrowNullPointerException(env, "crl == null"); - return NULL; - } - - STACK_OF(X509_REVOKED)* stack = X509_CRL_get_REVOKED(crl); - if (stack == NULL) { - JNI_TRACE("X509_CRL_get_REVOKED(%p) => stack is null", crl); - return NULL; - } - - size_t size = sk_X509_REVOKED_num(stack); - - ScopedLocalRef<jlongArray> revokedArray(env, env->NewLongArray(size)); - ScopedLongArrayRW revoked(env, revokedArray.get()); - for (size_t i = 0; i < size; i++) { - X509_REVOKED* item = reinterpret_cast<X509_REVOKED*>(sk_X509_REVOKED_value(stack, i)); - revoked[i] = reinterpret_cast<uintptr_t>(X509_REVOKED_dup(item)); - } - - JNI_TRACE("X509_CRL_get_REVOKED(%p) => %p [size=%d]", stack, revokedArray.get(), size); - return revokedArray.release(); -} - -static jbyteArray NativeCrypto_i2d_X509_CRL(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("i2d_X509_CRL(%p)", crl); - return ASN1ToByteArray<X509_CRL, i2d_X509_CRL>(env, crl); -} - -static void NativeCrypto_X509_CRL_free(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_free(%p)", crl); - - if (crl == NULL) { - jniThrowNullPointerException(env, "crl == null"); - JNI_TRACE("X509_CRL_free(%p) => crl == null", crl); - return; - } - - X509_CRL_free(crl); -} - -static void NativeCrypto_X509_CRL_print(JNIEnv* env, jclass, jlong bioRef, jlong x509CrlRef) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_print(%p, %p)", bio, crl); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - JNI_TRACE("X509_CRL_print(%p, %p) => bio == null", bio, crl); - return; - } - - if (crl == NULL) { - jniThrowNullPointerException(env, "crl == null"); - JNI_TRACE("X509_CRL_print(%p, %p) => crl == null", bio, crl); - return; - } - - if (!X509_CRL_print(bio, crl)) { - throwExceptionIfNecessary(env, "X509_CRL_print"); - JNI_TRACE("X509_CRL_print(%p, %p) => threw error", bio, crl); - } else { - JNI_TRACE("X509_CRL_print(%p, %p) => success", bio, crl); - } -} - -static jstring NativeCrypto_get_X509_CRL_sig_alg_oid(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("get_X509_CRL_sig_alg_oid(%p)", crl); - - if (crl == NULL || crl->sig_alg == NULL) { - jniThrowNullPointerException(env, "crl == NULL || crl->sig_alg == NULL"); - JNI_TRACE("get_X509_CRL_sig_alg_oid(%p) => crl == NULL", crl); - return NULL; - } - - return ASN1_OBJECT_to_OID_string(env, crl->sig_alg->algorithm); -} - -static jbyteArray NativeCrypto_get_X509_CRL_sig_alg_parameter(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p)", crl); - - if (crl == NULL) { - jniThrowNullPointerException(env, "crl == null"); - JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => crl == null", crl); - return NULL; - } - - if (crl->sig_alg->parameter == NULL) { - JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => null", crl); - return NULL; - } - - return ASN1ToByteArray<ASN1_TYPE, i2d_ASN1_TYPE>(env, crl->sig_alg->parameter); -} - -static jbyteArray NativeCrypto_X509_CRL_get_issuer_name(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_get_issuer_name(%p)", crl); - return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_CRL_get_issuer(crl)); -} - -static long NativeCrypto_X509_CRL_get_version(JNIEnv*, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_get_version(%p)", crl); - - long version = X509_CRL_get_version(crl); - JNI_TRACE("X509_CRL_get_version(%p) => %ld", crl, version); - return version; -} - -template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int), - X509_EXTENSION* (*get_ext_func)(T*, int)> -static X509_EXTENSION *X509Type_get_ext(JNIEnv* env, T* x509Type, jstring oidString) { - JNI_TRACE("X509Type_get_ext(%p)", x509Type); - - if (x509Type == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - return NULL; - } - - ScopedUtfChars oid(env, oidString); - if (oid.c_str() == NULL) { - return NULL; - } - - Unique_ASN1_OBJECT asn1(OBJ_txt2obj(oid.c_str(), 1)); - if (asn1.get() == NULL) { - JNI_TRACE("X509Type_get_ext(%p, %s) => oid conversion failed", x509Type, oid.c_str()); - freeOpenSslErrorState(); - return NULL; - } - - int extIndex = get_ext_by_OBJ_func(x509Type, asn1.get(), -1); - if (extIndex == -1) { - JNI_TRACE("X509Type_get_ext(%p, %s) => ext not found", x509Type, oid.c_str()); - return NULL; - } - - X509_EXTENSION* ext = get_ext_func(x509Type, extIndex); - JNI_TRACE("X509Type_get_ext(%p, %s) => %p", x509Type, oid.c_str(), ext); - return ext; -} - -template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int), - X509_EXTENSION* (*get_ext_func)(T*, int)> -static jbyteArray X509Type_get_ext_oid(JNIEnv* env, T* x509Type, jstring oidString) { - X509_EXTENSION* ext = X509Type_get_ext<T, get_ext_by_OBJ_func, get_ext_func>(env, x509Type, - oidString); - if (ext == NULL) { - JNI_TRACE("X509Type_get_ext_oid(%p, %p) => fetching extension failed", x509Type, oidString); - return NULL; - } - - JNI_TRACE("X509Type_get_ext_oid(%p, %p) => %p", x509Type, oidString, ext->value); - return ASN1ToByteArray<ASN1_OCTET_STRING, i2d_ASN1_OCTET_STRING>(env, ext->value); -} - -static jint NativeCrypto_X509_CRL_get_ext(JNIEnv* env, jclass, jlong x509CrlRef, jstring oid) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_get_ext(%p, %p)", crl, oid); - X509_EXTENSION* ext = X509Type_get_ext<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>( - env, crl, oid); - JNI_TRACE("X509_CRL_get_ext(%p, %p) => %p", crl, oid, ext); - return reinterpret_cast<uintptr_t>(ext); -} - -static jint NativeCrypto_X509_REVOKED_get_ext(JNIEnv* env, jclass, jlong x509RevokedRef, - jstring oid) { - X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); - JNI_TRACE("X509_REVOKED_get_ext(%p, %p)", revoked, oid); - X509_EXTENSION* ext = X509Type_get_ext<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ, - X509_REVOKED_get_ext>(env, revoked, oid); - JNI_TRACE("X509_REVOKED_get_ext(%p, %p) => %p", revoked, oid, ext); - return reinterpret_cast<uintptr_t>(ext); -} - -static jlong NativeCrypto_X509_REVOKED_dup(JNIEnv* env, jclass, jlong x509RevokedRef) { - X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); - JNI_TRACE("X509_REVOKED_dup(%p)", revoked); - - if (revoked == NULL) { - jniThrowNullPointerException(env, "revoked == null"); - JNI_TRACE("X509_REVOKED_dup(%p) => revoked == null", revoked); - return 0; - } - - X509_REVOKED* dup = X509_REVOKED_dup(revoked); - JNI_TRACE("X509_REVOKED_dup(%p) => %p", revoked, dup); - return reinterpret_cast<uintptr_t>(dup); -} - -static jlong NativeCrypto_get_X509_REVOKED_revocationDate(JNIEnv* env, jclass, jlong x509RevokedRef) { - X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); - JNI_TRACE("get_X509_REVOKED_revocationDate(%p)", revoked); - - if (revoked == NULL) { - jniThrowNullPointerException(env, "revoked == null"); - JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => revoked == null", revoked); - return 0; - } - - JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => %p", revoked, revoked->revocationDate); - return reinterpret_cast<uintptr_t>(revoked->revocationDate); -} - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wwrite-strings" -static void NativeCrypto_X509_REVOKED_print(JNIEnv* env, jclass, jlong bioRef, jlong x509RevokedRef) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); - JNI_TRACE("X509_REVOKED_print(%p, %p)", bio, revoked); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - JNI_TRACE("X509_REVOKED_print(%p, %p) => bio == null", bio, revoked); - return; - } - - if (revoked == NULL) { - jniThrowNullPointerException(env, "revoked == null"); - JNI_TRACE("X509_REVOKED_print(%p, %p) => revoked == null", bio, revoked); - return; - } - - BIO_printf(bio, "Serial Number: "); - i2a_ASN1_INTEGER(bio, revoked->serialNumber); - BIO_printf(bio, "\nRevocation Date: "); - ASN1_TIME_print(bio, revoked->revocationDate); - BIO_printf(bio, "\n"); - X509V3_extensions_print(bio, "CRL entry extensions", revoked->extensions, 0, 0); -} -#pragma GCC diagnostic pop - -static jbyteArray NativeCrypto_get_X509_CRL_crl_enc(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("get_X509_CRL_crl_enc(%p)", crl); - return ASN1ToByteArray<X509_CRL_INFO, i2d_X509_CRL_INFO>(env, crl->crl); -} - -static void NativeCrypto_X509_CRL_verify(JNIEnv* env, jclass, jlong x509CrlRef, jlong pkeyRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("X509_CRL_verify(%p, %p)", crl, pkey); - - if (crl == NULL) { - jniThrowNullPointerException(env, "crl == null"); - JNI_TRACE("X509_CRL_verify(%p, %p) => crl == null", crl, pkey); - return; - } - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - JNI_TRACE("X509_CRL_verify(%p, %p) => pkey == null", crl, pkey); - return; - } - - if (X509_CRL_verify(crl, pkey) != 1) { - throwExceptionIfNecessary(env, "X509_CRL_verify"); - JNI_TRACE("X509_CRL_verify(%p, %p) => verify failure", crl, pkey); - } else { - JNI_TRACE("X509_CRL_verify(%p, %p) => verify success", crl, pkey); - } -} - -static jlong NativeCrypto_X509_CRL_get_lastUpdate(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_get_lastUpdate(%p)", crl); - - if (crl == NULL) { - jniThrowNullPointerException(env, "crl == null"); - JNI_TRACE("X509_CRL_get_lastUpdate(%p) => crl == null", crl); - return 0; - } - - ASN1_TIME* lastUpdate = X509_CRL_get_lastUpdate(crl); - JNI_TRACE("X509_CRL_get_lastUpdate(%p) => %p", crl, lastUpdate); - return reinterpret_cast<uintptr_t>(lastUpdate); -} - -static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x509CrlRef) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_get_nextUpdate(%p)", crl); - - if (crl == NULL) { - jniThrowNullPointerException(env, "crl == null"); - JNI_TRACE("X509_CRL_get_nextUpdate(%p) => crl == null", crl); - return 0; - } - - ASN1_TIME* nextUpdate = X509_CRL_get_nextUpdate(crl); - JNI_TRACE("X509_CRL_get_nextUpdate(%p) => %p", crl, nextUpdate); - return reinterpret_cast<uintptr_t>(nextUpdate); -} - -static jbyteArray NativeCrypto_i2d_X509_REVOKED(JNIEnv* env, jclass, jlong x509RevokedRef) { - X509_REVOKED* x509Revoked = - reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); - JNI_TRACE("i2d_X509_REVOKED(%p)", x509Revoked); - return ASN1ToByteArray<X509_REVOKED, i2d_X509_REVOKED>(env, x509Revoked); -} - -static jint NativeCrypto_X509_supported_extension(JNIEnv* env, jclass, jlong x509ExtensionRef) { - X509_EXTENSION* ext = reinterpret_cast<X509_EXTENSION*>(static_cast<uintptr_t>(x509ExtensionRef)); - - if (ext == NULL) { - jniThrowNullPointerException(env, "ext == NULL"); - return 0; - } - - return X509_supported_extension(ext); -} - -static inline void get_ASN1_TIME_data(char **data, int* output, size_t len) { - char c = **data; - **data = '\0'; - *data -= len; - *output = atoi(*data); - *(*data + len) = c; -} - -static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1TimeRef, jobject calendar) { - ASN1_TIME* asn1Time = reinterpret_cast<ASN1_TIME*>(static_cast<uintptr_t>(asn1TimeRef)); - JNI_TRACE("ASN1_TIME_to_Calendar(%p, %p)", asn1Time, calendar); - - if (asn1Time == NULL) { - jniThrowNullPointerException(env, "asn1Time == null"); - return; - } - - Unique_ASN1_GENERALIZEDTIME gen(ASN1_TIME_to_generalizedtime(asn1Time, NULL)); - if (gen.get() == NULL) { - jniThrowNullPointerException(env, "asn1Time == null"); - return; - } - - if (gen->length < 14 || gen->data == NULL) { - jniThrowNullPointerException(env, "gen->length < 14 || gen->data == NULL"); - return; - } - - int sec, min, hour, mday, mon, year; - - char *p = (char*) &gen->data[14]; - - get_ASN1_TIME_data(&p, &sec, 2); - get_ASN1_TIME_data(&p, &min, 2); - get_ASN1_TIME_data(&p, &hour, 2); - get_ASN1_TIME_data(&p, &mday, 2); - get_ASN1_TIME_data(&p, &mon, 2); - get_ASN1_TIME_data(&p, &year, 4); - - env->CallVoidMethod(calendar, calendar_setMethod, year, mon - 1, mday, hour, min, sec); -} - -static jstring NativeCrypto_OBJ_txt2nid_oid(JNIEnv* env, jclass, jstring oidStr) { - JNI_TRACE("OBJ_txt2nid_oid(%p)", oidStr); - - ScopedUtfChars oid(env, oidStr); - if (oid.c_str() == NULL) { - return NULL; - } - - JNI_TRACE("OBJ_txt2nid_oid(%s)", oid.c_str()); - - int nid = OBJ_txt2nid(oid.c_str()); - if (nid == NID_undef) { - JNI_TRACE("OBJ_txt2nid_oid(%s) => NID_undef", oid.c_str()); - freeOpenSslErrorState(); - return NULL; - } - - Unique_ASN1_OBJECT obj(OBJ_nid2obj(nid)); - if (obj.get() == NULL) { - throwExceptionIfNecessary(env, "OBJ_nid2obj"); - return NULL; - } - - ScopedLocalRef<jstring> ouputStr(env, ASN1_OBJECT_to_OID_string(env, obj.get())); - JNI_TRACE("OBJ_txt2nid_oid(%s) => %p", oid.c_str(), ouputStr.get()); - return ouputStr.release(); -} - -static jstring NativeCrypto_X509_NAME_print_ex(JNIEnv* env, jclass, jlong x509NameRef, jlong jflags) { - X509_NAME* x509name = reinterpret_cast<X509_NAME*>(static_cast<uintptr_t>(x509NameRef)); - unsigned long flags = static_cast<unsigned long>(jflags); - JNI_TRACE("X509_NAME_print_ex(%p, %ld)", x509name, flags); - - if (x509name == NULL) { - jniThrowNullPointerException(env, "x509name == null"); - JNI_TRACE("X509_NAME_print_ex(%p, %ld) => x509name == null", x509name, flags); - return NULL; - } - - return X509_NAME_to_jstring(env, x509name, flags); -} - -template <typename T, T* (*d2i_func)(BIO*, T**)> -static jlong d2i_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("d2i_ASN1Object_to_jlong(%p)", bio); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - return 0; - } - - T* x = d2i_func(bio, NULL); - if (x == NULL) { - throwExceptionIfNecessary(env, "d2i_ASN1Object_to_jlong"); - return 0; - } - - return reinterpret_cast<uintptr_t>(x); -} - -static jlong NativeCrypto_d2i_X509_CRL_bio(JNIEnv* env, jclass, jlong bioRef) { - return d2i_ASN1Object_to_jlong<X509_CRL, d2i_X509_CRL_bio>(env, bioRef); -} - -static jlong NativeCrypto_d2i_X509_bio(JNIEnv* env, jclass, jlong bioRef) { - return d2i_ASN1Object_to_jlong<X509, d2i_X509_bio>(env, bioRef); -} - -static jlong NativeCrypto_d2i_X509(JNIEnv* env, jclass, jbyteArray certBytes) { - X509* x = ByteArrayToASN1<X509, d2i_X509>(env, certBytes); - return reinterpret_cast<uintptr_t>(x); -} - -static jbyteArray NativeCrypto_i2d_X509(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("i2d_X509(%p)", x509); - return ASN1ToByteArray<X509, i2d_X509>(env, x509); -} - -static jbyteArray NativeCrypto_i2d_X509_PUBKEY(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("i2d_X509_PUBKEY(%p)", x509); - return ASN1ToByteArray<X509_PUBKEY, i2d_X509_PUBKEY>(env, X509_get_X509_PUBKEY(x509)); -} - - -template<typename T, T* (*PEM_read_func)(BIO*, T**, pem_password_cb*, void*)> -static jlong PEM_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("PEM_ASN1Object_to_jlong(%p)", bio); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => bio == null", bio); - return 0; - } - - T* x = PEM_read_func(bio, NULL, NULL, NULL); - if (x == NULL) { - throwExceptionIfNecessary(env, "PEM_ASN1Object_to_jlong"); - // Sometimes the PEM functions fail without pushing an error - if (!env->ExceptionCheck()) { - jniThrowRuntimeException(env, "Failure parsing PEM"); - } - JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => threw exception", bio); - return 0; - } - - JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => %p", bio, x); - return reinterpret_cast<uintptr_t>(x); -} - -static jlong NativeCrypto_PEM_read_bio_X509(JNIEnv* env, jclass, jlong bioRef) { - JNI_TRACE("PEM_read_bio_X509(0x%llx)", bioRef); - return PEM_ASN1Object_to_jlong<X509, PEM_read_bio_X509>(env, bioRef); -} - -static jlong NativeCrypto_PEM_read_bio_X509_CRL(JNIEnv* env, jclass, jlong bioRef) { - JNI_TRACE("PEM_read_bio_X509_CRL(0x%llx)", bioRef); - return PEM_ASN1Object_to_jlong<X509_CRL, PEM_read_bio_X509_CRL>(env, bioRef); -} - -static STACK_OF(X509)* PKCS7_get_certs(PKCS7* pkcs7) { - if (PKCS7_type_is_signed(pkcs7)) { - return pkcs7->d.sign->cert; - } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) { - return pkcs7->d.signed_and_enveloped->cert; - } else { - JNI_TRACE("PKCS7_get_certs(%p) => unknown PKCS7 type", pkcs7); - return NULL; - } -} - -static STACK_OF(X509_CRL)* PKCS7_get_CRLs(PKCS7* pkcs7) { - if (PKCS7_type_is_signed(pkcs7)) { - return pkcs7->d.sign->crl; - } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) { - return pkcs7->d.signed_and_enveloped->crl; - } else { - JNI_TRACE("PKCS7_get_CRLs(%p) => unknown PKCS7 type", pkcs7); - return NULL; - } -} - -template <typename T, typename T_stack> -static jlongArray PKCS7_to_ItemArray(JNIEnv* env, T_stack* stack, T* (*dup_func)(T*)) -{ - if (stack == NULL) { - return NULL; - } - - ScopedLocalRef<jlongArray> ref_array(env, NULL); - size_t size = sk_num(reinterpret_cast<_STACK*>(stack)); - ref_array.reset(env->NewLongArray(size)); - ScopedLongArrayRW items(env, ref_array.get()); - for (size_t i = 0; i < size; i++) { - T* item = reinterpret_cast<T*>(sk_value(reinterpret_cast<_STACK*>(stack), i)); - items[i] = reinterpret_cast<uintptr_t>(dup_func(item)); - } - - JNI_TRACE("PKCS7_to_ItemArray(%p) => %p [size=%d]", stack, ref_array.get(), size); - return ref_array.release(); -} - -#define PKCS7_CERTS 1 -#define PKCS7_CRLS 2 - -static jlongArray NativeCrypto_PEM_read_bio_PKCS7(JNIEnv* env, jclass, jlong bioRef, jint which) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p)", bio); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => bio == null", bio); - return 0; - } - - Unique_PKCS7 pkcs7(PEM_read_bio_PKCS7(bio, NULL, NULL, NULL)); - if (pkcs7.get() == NULL) { - throwExceptionIfNecessary(env, "PEM_read_bio_PKCS7_CRLs"); - JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => threw exception", bio); - return 0; - } - - switch (which) { - case PKCS7_CERTS: - return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup); - case PKCS7_CRLS: - return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()), - X509_CRL_dup); - default: - jniThrowRuntimeException(env, "unknown PKCS7 field"); - return NULL; - } -} - -static jlongArray NativeCrypto_d2i_PKCS7_bio(JNIEnv* env, jclass, jlong bioRef, jint which) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("d2i_PKCS7_bio(%p, %d)", bio, which); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - JNI_TRACE("d2i_PKCS7_bio(%p, %d) => bio == null", bio, which); - return 0; - } - - Unique_PKCS7 pkcs7(d2i_PKCS7_bio(bio, NULL)); - if (pkcs7.get() == NULL) { - throwExceptionIfNecessary(env, "d2i_PKCS7_bio"); - JNI_TRACE("d2i_PKCS7_bio(%p, %d) => threw exception", bio, which); - return 0; - } - - switch (which) { - case PKCS7_CERTS: - return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup); - case PKCS7_CRLS: - return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()), - X509_CRL_dup); - default: - jniThrowRuntimeException(env, "unknown PKCS7 field"); - return NULL; - } -} - -static jbyteArray NativeCrypto_i2d_PKCS7(JNIEnv* env, jclass, jlongArray certsArray) { - JNI_TRACE("i2d_PKCS7(%p)", certsArray); - - Unique_PKCS7 pkcs7(PKCS7_new()); - if (pkcs7.get() == NULL) { - jniThrowNullPointerException(env, "pkcs7 == null"); - JNI_TRACE("i2d_PKCS7(%p) => pkcs7 == null", certsArray); - return NULL; - } - - if (PKCS7_set_type(pkcs7.get(), NID_pkcs7_signed) != 1) { - throwExceptionIfNecessary(env, "PKCS7_set_type"); - return NULL; - } - - ScopedLongArrayRO certs(env, certsArray); - for (size_t i = 0; i < certs.size(); i++) { - X509* item = reinterpret_cast<X509*>(certs[i]); - if (PKCS7_add_certificate(pkcs7.get(), item) != 1) { - throwExceptionIfNecessary(env, "i2d_PKCS7"); - return NULL; - } - } - - JNI_TRACE("i2d_PKCS7(%p) => %d certs", certsArray, certs.size()); - return ASN1ToByteArray<PKCS7, i2d_PKCS7>(env, pkcs7.get()); -} - -typedef STACK_OF(X509) PKIPATH; - -ASN1_ITEM_TEMPLATE(PKIPATH) = - ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, PkiPath, X509) -ASN1_ITEM_TEMPLATE_END(PKIPATH) - -static jlongArray NativeCrypto_ASN1_seq_unpack_X509_bio(JNIEnv* env, jclass, jlong bioRef) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - JNI_TRACE("ASN1_seq_unpack_X509_bio(%p)", bio); - - Unique_sk_X509 path((PKIPATH*) ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKIPATH), bio, NULL)); - if (path.get() == NULL) { - throwExceptionIfNecessary(env, "ASN1_seq_unpack_X509_bio"); - return NULL; - } - - size_t size = sk_X509_num(path.get()); - - ScopedLocalRef<jlongArray> certArray(env, env->NewLongArray(size)); - ScopedLongArrayRW certs(env, certArray.get()); - for (size_t i = 0; i < size; i++) { - X509* item = reinterpret_cast<X509*>(sk_X509_shift(path.get())); - certs[i] = reinterpret_cast<uintptr_t>(item); - } - - JNI_TRACE("ASN1_seq_unpack_X509_bio(%p) => returns %d items", bio, size); - return certArray.release(); -} - -static jbyteArray NativeCrypto_ASN1_seq_pack_X509(JNIEnv* env, jclass, jlongArray certs) { - JNI_TRACE("ASN1_seq_pack_X509(%p)", certs); - ScopedLongArrayRO certsArray(env, certs); - if (certsArray.get() == NULL) { - JNI_TRACE("ASN1_seq_pack_X509(%p) => failed to get certs array", certs); - return NULL; - } - - Unique_sk_X509 certStack(sk_X509_new_null()); - if (certStack.get() == NULL) { - JNI_TRACE("ASN1_seq_pack_X509(%p) => failed to make cert stack", certs); - return NULL; - } - - for (size_t i = 0; i < certsArray.size(); i++) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(certsArray[i])); - sk_X509_push(certStack.get(), X509_dup_nocopy(x509)); - } - - int len; - Unique_OPENSSL_str encoded(ASN1_seq_pack( - reinterpret_cast<STACK_OF(OPENSSL_BLOCK)*>( - reinterpret_cast<uintptr_t>(certStack.get())), - reinterpret_cast<int (*)(void*, unsigned char**)>(i2d_X509), NULL, &len)); - if (encoded.get() == NULL) { - JNI_TRACE("ASN1_seq_pack_X509(%p) => trouble encoding", certs); - return NULL; - } - - ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(len)); - if (byteArray.get() == NULL) { - JNI_TRACE("ASN1_seq_pack_X509(%p) => creating byte array failed", certs); - return NULL; - } - - ScopedByteArrayRW bytes(env, byteArray.get()); - if (bytes.get() == NULL) { - JNI_TRACE("ASN1_seq_pack_X509(%p) => using byte array failed", certs); - return NULL; - } - - unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get()); - memcpy(p, encoded.get(), len); - - return byteArray.release(); -} - -static void NativeCrypto_X509_free(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_free(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("X509_free(%p) => x509 == null", x509); - return; - } - - X509_free(x509); -} - -static jint NativeCrypto_X509_cmp(JNIEnv* env, jclass, jlong x509Ref1, jlong x509Ref2) { - X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1)); - X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2)); - JNI_TRACE("X509_cmp(%p, %p)", x509_1, x509_2); - - if (x509_1 == NULL) { - jniThrowNullPointerException(env, "x509_1 == null"); - JNI_TRACE("X509_cmp(%p, %p) => x509_1 == null", x509_1, x509_2); - return -1; - } - - if (x509_2 == NULL) { - jniThrowNullPointerException(env, "x509_2 == null"); - JNI_TRACE("X509_cmp(%p, %p) => x509_2 == null", x509_1, x509_2); - return -1; - } - - int ret = X509_cmp(x509_1, x509_2); - JNI_TRACE("X509_cmp(%p, %p) => %d", x509_1, x509_2, ret); - return ret; -} - -static jint NativeCrypto_get_X509_hashCode(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_hashCode(%p) => x509 == null", x509); - return 0; - } - - // Force caching extensions. - X509_check_ca(x509); - - jint hashCode = 0L; - for (int i = 0; i < SHA_DIGEST_LENGTH; i++) { - hashCode = 31 * hashCode + x509->sha1_hash[i]; - } - return hashCode; -} - -static void NativeCrypto_X509_print_ex(JNIEnv* env, jclass, jlong bioRef, jlong x509Ref, - jlong nmflagJava, jlong certflagJava) { - BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - long nmflag = static_cast<long>(nmflagJava); - long certflag = static_cast<long>(certflagJava); - JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld)", bio, x509, nmflag, certflag); - - if (bio == NULL) { - jniThrowNullPointerException(env, "bio == null"); - JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => bio == null", bio, x509, nmflag, certflag); - return; - } - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => x509 == null", bio, x509, nmflag, certflag); - return; - } - - if (!X509_print_ex(bio, x509, nmflag, certflag)) { - throwExceptionIfNecessary(env, "X509_print_ex"); - JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => threw error", bio, x509, nmflag, certflag); - } else { - JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => success", bio, x509, nmflag, certflag); - } -} - -static jlong NativeCrypto_X509_get_pubkey(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_pubkey(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("X509_get_pubkey(%p) => x509 == null", x509); - return 0; - } - - Unique_EVP_PKEY pkey(X509_get_pubkey(x509)); - if (pkey.get() == NULL) { - throwExceptionIfNecessary(env, "X509_get_pubkey"); - return 0; - } - - return reinterpret_cast<uintptr_t>(pkey.release()); -} - -static jbyteArray NativeCrypto_X509_get_issuer_name(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_issuer_name(%p)", x509); - return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_get_issuer_name(x509)); -} - -static jbyteArray NativeCrypto_X509_get_subject_name(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_subject_name(%p)", x509); - return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_get_subject_name(x509)); -} - -static jstring NativeCrypto_get_X509_pubkey_oid(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_pubkey_oid(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_pubkey_oid(%p) => x509 == null", x509); - return NULL; - } - - X509_PUBKEY* pubkey = X509_get_X509_PUBKEY(x509); - return ASN1_OBJECT_to_OID_string(env, pubkey->algor->algorithm); -} - -static jstring NativeCrypto_get_X509_sig_alg_oid(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_sig_alg_oid(%p)", x509); - - if (x509 == NULL || x509->sig_alg == NULL) { - jniThrowNullPointerException(env, "x509 == NULL || x509->sig_alg == NULL"); - JNI_TRACE("get_X509_sig_alg_oid(%p) => x509 == NULL", x509); - return NULL; - } - - return ASN1_OBJECT_to_OID_string(env, x509->sig_alg->algorithm); -} - -static jbyteArray NativeCrypto_get_X509_sig_alg_parameter(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_sig_alg_parameter(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_sig_alg_parameter(%p) => x509 == null", x509); - return NULL; - } - - if (x509->sig_alg->parameter == NULL) { - JNI_TRACE("get_X509_sig_alg_parameter(%p) => null", x509); - return NULL; - } - - return ASN1ToByteArray<ASN1_TYPE, i2d_ASN1_TYPE>(env, x509->sig_alg->parameter); -} - -static jbooleanArray NativeCrypto_get_X509_issuerUID(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_issuerUID(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_issuerUID(%p) => x509 == null", x509); - return NULL; - } - - if (x509->cert_info->issuerUID == NULL) { - JNI_TRACE("get_X509_issuerUID(%p) => null", x509); - return NULL; - } - - return ASN1BitStringToBooleanArray(env, x509->cert_info->issuerUID); -} -static jbooleanArray NativeCrypto_get_X509_subjectUID(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_subjectUID(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_subjectUID(%p) => x509 == null", x509); - return NULL; - } - - if (x509->cert_info->subjectUID == NULL) { - JNI_TRACE("get_X509_subjectUID(%p) => null", x509); - return NULL; - } - - return ASN1BitStringToBooleanArray(env, x509->cert_info->subjectUID); -} - -static jbooleanArray NativeCrypto_get_X509_ex_kusage(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_ex_kusage(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_ex_kusage(%p) => x509 == null", x509); - return NULL; - } - - Unique_ASN1_BIT_STRING bitStr(static_cast<ASN1_BIT_STRING*>( - X509_get_ext_d2i(x509, NID_key_usage, NULL, NULL))); - if (bitStr.get() == NULL) { - JNI_TRACE("get_X509_ex_kusage(%p) => null", x509); - return NULL; - } - - return ASN1BitStringToBooleanArray(env, bitStr.get()); -} - -static jobjectArray NativeCrypto_get_X509_ex_xkusage(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_ex_xkusage(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_ex_xkusage(%p) => x509 == null", x509); - return NULL; - } - - Unique_sk_ASN1_OBJECT objArray(static_cast<STACK_OF(ASN1_OBJECT)*>( - X509_get_ext_d2i(x509, NID_ext_key_usage, NULL, NULL))); - if (objArray.get() == NULL) { - JNI_TRACE("get_X509_ex_xkusage(%p) => null", x509); - return NULL; - } - - size_t size = sk_ASN1_OBJECT_num(objArray.get()); - ScopedLocalRef<jobjectArray> exKeyUsage(env, env->NewObjectArray(size, stringClass, NULL)); - if (exKeyUsage.get() == NULL) { - return NULL; - } - - for (size_t i = 0; i < size; i++) { - ScopedLocalRef<jstring> oidStr(env, ASN1_OBJECT_to_OID_string(env, - sk_ASN1_OBJECT_value(objArray.get(), i))); - env->SetObjectArrayElement(exKeyUsage.get(), i, oidStr.get()); - } - - JNI_TRACE("get_X509_ex_xkusage(%p) => success (%d entries)", x509, size); - return exKeyUsage.release(); -} - -static jint NativeCrypto_get_X509_ex_pathlen(JNIEnv* env, jclass, jlong x509Ref) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509_ex_pathlen(%p)", x509); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509_ex_pathlen(%p) => x509 == null", x509); - return 0; - } - - /* Just need to do this to cache the ex_* values. */ - X509_check_ca(x509); - - JNI_TRACE("get_X509_ex_pathlen(%p) => %ld", x509, x509->ex_pathlen); - return x509->ex_pathlen; -} - -static jbyteArray NativeCrypto_X509_get_ext_oid(JNIEnv* env, jclass, jlong x509Ref, - jstring oidString) { - X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("X509_get_ext_oid(%p, %p)", x509, oidString); - return X509Type_get_ext_oid<X509, X509_get_ext_by_OBJ, X509_get_ext>(env, x509, oidString); -} - -static jbyteArray NativeCrypto_X509_CRL_get_ext_oid(JNIEnv* env, jclass, jlong x509CrlRef, - jstring oidString) { - X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); - JNI_TRACE("X509_CRL_get_ext_oid(%p, %p)", crl, oidString); - return X509Type_get_ext_oid<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>(env, crl, - oidString); -} - -static jbyteArray NativeCrypto_X509_REVOKED_get_ext_oid(JNIEnv* env, jclass, jlong x509RevokedRef, - jstring oidString) { - X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); - JNI_TRACE("X509_REVOKED_get_ext_oid(%p, %p)", revoked, oidString); - return X509Type_get_ext_oid<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ, X509_REVOKED_get_ext>( - env, revoked, oidString); -} - -template<typename T, int (*get_ext_by_critical_func)(T*, int, int), X509_EXTENSION* (*get_ext_func)(T*, int)> -static jobjectArray get_X509Type_ext_oids(JNIEnv* env, jlong x509Ref, jint critical) { - T* x509 = reinterpret_cast<T*>(static_cast<uintptr_t>(x509Ref)); - JNI_TRACE("get_X509Type_ext_oids(%p, %d)", x509, critical); - - if (x509 == NULL) { - jniThrowNullPointerException(env, "x509 == null"); - JNI_TRACE("get_X509Type_ext_oids(%p, %d) => x509 == null", x509, critical); - return NULL; - } - - int lastPos = -1; - int count = 0; - while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) { - count++; - } - - JNI_TRACE("get_X509Type_ext_oids(%p, %d) has %d entries", x509, critical, count); - - ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, stringClass, NULL)); - if (joa.get() == NULL) { - JNI_TRACE("get_X509Type_ext_oids(%p, %d) => fail to allocate result array", x509, critical); - return NULL; - } - - lastPos = -1; - count = 0; - while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) { - X509_EXTENSION* ext = get_ext_func(x509, lastPos); - - ScopedLocalRef<jstring> extOid(env, ASN1_OBJECT_to_OID_string(env, ext->object)); - if (extOid.get() == NULL) { - JNI_TRACE("get_X509Type_ext_oids(%p) => couldn't get OID", x509); - return NULL; - } - - env->SetObjectArrayElement(joa.get(), count++, extOid.get()); - } - - JNI_TRACE("get_X509Type_ext_oids(%p, %d) => success", x509, critical); - return joa.release(); -} - -static jobjectArray NativeCrypto_get_X509_ext_oids(JNIEnv* env, jclass, jlong x509Ref, - jint critical) { - JNI_TRACE("get_X509_ext_oids(0x%llx, %d)", x509Ref, critical); - return get_X509Type_ext_oids<X509, X509_get_ext_by_critical, X509_get_ext>(env, x509Ref, - critical); -} - -static jobjectArray NativeCrypto_get_X509_CRL_ext_oids(JNIEnv* env, jclass, jlong x509CrlRef, - jint critical) { - JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", x509CrlRef, critical); - return get_X509Type_ext_oids<X509_CRL, X509_CRL_get_ext_by_critical, X509_CRL_get_ext>(env, - x509CrlRef, critical); -} - -static jobjectArray NativeCrypto_get_X509_REVOKED_ext_oids(JNIEnv* env, jclass, jlong x509RevokedRef, - jint critical) { - JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", x509RevokedRef, critical); - return get_X509Type_ext_oids<X509_REVOKED, X509_REVOKED_get_ext_by_critical, - X509_REVOKED_get_ext>(env, x509RevokedRef, critical); -} - -#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 references - */ -static jlongArray getCertificateRefs(JNIEnv* env, const STACK_OF(X509)* chain) -{ - if (chain == NULL) { - // Chain can be NULL if the associated cipher doesn't do certs. - return NULL; - } - ssize_t count = sk_X509_num(chain); - if (count <= 0) { - return NULL; - } - ScopedLocalRef<jlongArray> refArray(env, env->NewLongArray(count)); - ScopedLongArrayRW refs(env, refArray.get()); - if (refs.get() == NULL) { - return NULL; - } - for (ssize_t i = 0; i < count; i++) { - refs[i] = reinterpret_cast<uintptr_t>(X509_dup_nocopy(sk_X509_value(chain, i))); - } - return refArray.release(); -} - -/** - * 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; - } - - ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, byteArrayClass, NULL)); - if (joa.get() == NULL) { - return NULL; - } - - for (int i = 0; i < count; i++) { - X509_NAME* principal = sk_X509_NAME_value(names, i); - - ScopedLocalRef<jbyteArray> byteArray(env, ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, - principal)); - if (byteArray.get() == NULL) { - return NULL; - } - env->SetObjectArrayElement(joa.get(), i, byteArray.get()); - } - - return joa.release(); -} - -/** - * Our additional application data needed for getting synchronization right. - * This maybe warrants a bit of lengthy prose: - * - * (1) We use a flag to reflect whether we consider the SSL connection alive. - * Any read or write attempt loops will be cancelled once this flag becomes 0. - * - * (2) We use an int to count the number of threads that are blocked by the - * underlying socket. This may be at most two (one reader and one writer), since - * the Java layer ensures that no more threads will enter the native code at the - * same time. - * - * (3) The pipe is used primarily as a means of cancelling a blocking select() - * when we want to close the connection (aka "emergency button"). It is also - * necessary for dealing with a possible race condition situation: There might - * be cases where both threads see an SSL_ERROR_WANT_READ or - * SSL_ERROR_WANT_WRITE. Both will enter a select() with the proper argument. - * If one leaves the select() successfully before the other enters it, the - * "success" event is already consumed and the second thread will be blocked, - * possibly forever (depending on network conditions). - * - * The idea for solving the problem looks like this: Whenever a thread is - * successful in moving around data on the network, and it knows there is - * another thread stuck in a select(), it will write a byte to the pipe, waking - * up the other thread. A thread that returned from select(), on the other hand, - * knows whether it's been woken up by the pipe. If so, it will consume the - * byte, and the original state of affairs has been restored. - * - * The pipe may seem like a bit of overhead, but it fits in nicely with the - * other file descriptors of the select(), so there's only one condition to wait - * for. - * - * (4) Finally, a mutex is needed to make sure that at most one thread is in - * either SSL_read() or SSL_write() at any given time. This is an OpenSSL - * requirement. We use the same mutex to guard the field for counting the - * waiting threads. - * - * Note: The current implementation assumes that we don't have to deal with - * problems induced by multiple cores or processors and their respective - * memory caches. One possible problem is that of inconsistent views on the - * "aliveAndKicking" field. This could be worked around by also enclosing all - * accesses to that field inside a lock/unlock sequence of our mutex, but - * currently this seems a bit like overkill. Marking volatile at the very least. - * - * During handshaking, additional fields are used to up-call into - * Java to perform certificate verification and handshake - * completion. These are also used in any renegotiation. - * - * (5) the JNIEnv so we can invoke the Java callback - * - * (6) a NativeCrypto.SSLHandshakeCallbacks instance for callbacks from native to Java - * - * (7) a java.io.FileDescriptor wrapper to check for socket close - * - * We store the NPN protocols list so we can either send it (from the server) or - * select a protocol (on the client). We eagerly acquire a pointer to the array - * data so the callback doesn't need to acquire resources that it cannot - * release. - * - * Because renegotiation can be requested by the peer at any time, - * care should be taken to maintain an appropriate JNIEnv on any - * downcall to openssl since it could result in an upcall to Java. The - * current code does try to cover these cases by conditionally setting - * the JNIEnv on calls that can read and write to the SSL such as - * SSL_do_handshake, SSL_read, SSL_write, and SSL_shutdown. - * - * Finally, we have two emphemeral keys setup by OpenSSL callbacks: - * - * (8) a set of ephemeral RSA keys that is lazily generated if a peer - * wants to use an exportable RSA cipher suite. - * - * (9) a set of ephemeral EC keys that is lazily generated if a peer - * wants to use an TLS_ECDHE_* cipher suite. - * - */ -class AppData { - public: - volatile int aliveAndKicking; - int waitingThreads; - int fdsEmergency[2]; - MUTEX_TYPE mutex; - JNIEnv* env; - jobject sslHandshakeCallbacks; - jobject fileDescriptor; - jbyteArray npnProtocolsArray; - jbyte* npnProtocolsData; - size_t npnProtocolsLength; - jbyteArray alpnProtocolsArray; - jbyte* alpnProtocolsData; - size_t alpnProtocolsLength; - Unique_RSA ephemeralRsa; - Unique_EC_KEY ephemeralEc; - - /** - * Creates the application data context for the SSL*. - */ - public: - static AppData* create() { - UniquePtr<AppData> appData(new AppData()); - if (pipe(appData.get()->fdsEmergency) == -1) { - ALOGE("AppData::create pipe(2) failed: %s", strerror(errno)); - return NULL; - } - if (!setBlocking(appData.get()->fdsEmergency[0], false)) { - ALOGE("AppData::create fcntl(2) failed: %s", strerror(errno)); - return NULL; - } - if (MUTEX_SETUP(appData.get()->mutex) == -1) { - ALOGE("pthread_mutex_init(3) failed: %s", strerror(errno)); - return NULL; - } - return appData.release(); - } - - ~AppData() { - aliveAndKicking = 0; - if (fdsEmergency[0] != -1) { - close(fdsEmergency[0]); - } - if (fdsEmergency[1] != -1) { - close(fdsEmergency[1]); - } - MUTEX_CLEANUP(mutex); - } - - private: - AppData() : - aliveAndKicking(1), - waitingThreads(0), - env(NULL), - sslHandshakeCallbacks(NULL), - npnProtocolsArray(NULL), - npnProtocolsData(NULL), - npnProtocolsLength(-1), - alpnProtocolsArray(NULL), - alpnProtocolsData(NULL), - alpnProtocolsLength(-1), - ephemeralRsa(NULL), - ephemeralEc(NULL) { - fdsEmergency[0] = -1; - fdsEmergency[1] = -1; - } - - public: - /** - * Used to set the SSL-to-Java callback state before each SSL_* - * call that may result in a callback. It should be cleared after - * the operation returns with clearCallbackState. - * - * @param env The JNIEnv - * @param shc The SSLHandshakeCallbacks - * @param fd The FileDescriptor - * @param npnProtocols NPN protocols so that they may be advertised (by the - * server) or selected (by the client). Has no effect - * unless NPN is enabled. - * @param alpnProtocols ALPN protocols so that they may be advertised (by the - * server) or selected (by the client). Passing non-NULL - * enables ALPN. - */ - bool setCallbackState(JNIEnv* e, jobject shc, jobject fd, jbyteArray npnProtocols, - jbyteArray alpnProtocols) { - NetFd netFd(e, fd); - if (netFd.isClosed()) { - return false; - } - env = e; - sslHandshakeCallbacks = shc; - fileDescriptor = fd; - if (npnProtocols != NULL) { - npnProtocolsArray = npnProtocols; - npnProtocolsLength = e->GetArrayLength(npnProtocols); - npnProtocolsData = e->GetByteArrayElements(npnProtocols, NULL); - if (npnProtocolsData == NULL) { - return false; - } - } - if (alpnProtocols != NULL) { - alpnProtocolsArray = alpnProtocols; - alpnProtocolsLength = e->GetArrayLength(alpnProtocols); - alpnProtocolsData = e->GetByteArrayElements(alpnProtocols, NULL); - if (alpnProtocolsData == NULL) { - return false; - } - } - return true; - } - - void clearCallbackState() { - sslHandshakeCallbacks = NULL; - fileDescriptor = NULL; - if (npnProtocolsArray != NULL) { - env->ReleaseByteArrayElements(npnProtocolsArray, npnProtocolsData, JNI_ABORT); - npnProtocolsArray = NULL; - npnProtocolsData = NULL; - npnProtocolsLength = -1; - } - if (alpnProtocolsArray != NULL) { - env->ReleaseByteArrayElements(alpnProtocolsArray, alpnProtocolsData, JNI_ABORT); - alpnProtocolsArray = NULL; - alpnProtocolsData = NULL; - alpnProtocolsLength = -1; - } - env = NULL; - } - -}; - -/** - * Dark magic helper function that checks, for a given SSL session, whether it - * can SSL_read() or SSL_write() without blocking. Takes into account any - * concurrent attempts to close the SSLSocket from the Java side. This is - * needed to get rid of the hangs that occur when thread #1 closes the SSLSocket - * while thread #2 is sitting in a blocking read or write. The type argument - * specifies whether we are waiting for readability or writability. It expects - * to be passed either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, since we - * only need to wait in case one of these problems occurs. - * - * @param env - * @param type Either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE - * @param fdObject The FileDescriptor, since appData->fileDescriptor should be NULL - * @param appData The application data structure with mutex info etc. - * @param timeout_millis The timeout value for select call, with the special value - * 0 meaning no timeout at all (wait indefinitely). Note: This is - * the Java semantics of the timeout value, not the usual - * select() semantics. - * @return The result of the inner select() call, - * THROW_SOCKETEXCEPTION if a SocketException was thrown, -1 on - * additional errors - */ -static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData, int timeout_millis) { - // This loop is an expanded version of the NET_FAILURE_RETRY - // macro. It cannot simply be used in this case because select - // cannot be restarted without recreating the fd_sets and timeout - // structure. - int result; - fd_set rfds; - fd_set wfds; - do { - NetFd fd(env, fdObject); - if (fd.isClosed()) { - result = THROWN_EXCEPTION; - break; - } - int intFd = fd.get(); - JNI_TRACE("sslSelect type=%s fd=%d appData=%p timeout_millis=%d", - (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", intFd, appData, timeout_millis); - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - - if (type == SSL_ERROR_WANT_READ) { - FD_SET(intFd, &rfds); - } else { - FD_SET(intFd, &wfds); - } - - FD_SET(appData->fdsEmergency[0], &rfds); - - int maxFd = (intFd > appData->fdsEmergency[0]) ? intFd : appData->fdsEmergency[0]; - - // Build a struct for the timeout data if we actually want a timeout. - timeval tv; - timeval* ptv; - if (timeout_millis > 0) { - tv.tv_sec = timeout_millis / 1000; - tv.tv_usec = (timeout_millis % 1000) * 1000; - ptv = &tv; - } else { - ptv = NULL; - } - - AsynchronousSocketCloseMonitor monitor(intFd); - result = select(maxFd + 1, &rfds, &wfds, NULL, ptv); - JNI_TRACE("sslSelect %s fd=%d appData=%p timeout_millis=%d => %d", - (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", - fd.get(), appData, timeout_millis, result); - if (result == -1) { - if (fd.isClosed()) { - result = THROWN_EXCEPTION; - break; - } - if (errno != EINTR) { - break; - } - } - } while (result == -1); - - if (MUTEX_LOCK(appData->mutex) == -1) { - return -1; - } - - if (result > 0) { - // We have been woken up by a token in the emergency pipe. We - // can't be sure the token is still in the pipe at this point - // because it could have already been read by the thread that - // originally wrote it if it entered sslSelect and acquired - // the mutex before we did. Thus we cannot safely read from - // the pipe in a blocking way (so we make the pipe - // non-blocking at creation). - if (FD_ISSET(appData->fdsEmergency[0], &rfds)) { - char token; - do { - read(appData->fdsEmergency[0], &token, 1); - } while (errno == EINTR); - } - } - - // Tell the world that there is now one thread less waiting for the - // underlying network. - appData->waitingThreads--; - - MUTEX_UNLOCK(appData->mutex); - - return result; -} - -/** - * Helper function that wakes up a thread blocked in select(), in case there is - * one. Is being called by sslRead() and sslWrite() as well as by JNI glue - * before closing the connection. - * - * @param data The application data structure with mutex info etc. - */ -static void sslNotify(AppData* appData) { - // Write a byte to the emergency pipe, so a concurrent select() can return. - // Note we have to restore the errno of the original system call, since the - // caller relies on it for generating error messages. - int errnoBackup = errno; - char token = '*'; - do { - errno = 0; - write(appData->fdsEmergency[1], &token, 1); - } while (errno == EINTR); - errno = errnoBackup; -} - -static AppData* toAppData(const SSL* ssl) { - return reinterpret_cast<AppData*>(SSL_get_app_data(ssl)); -} - -/** - * Verify the X509 certificate via SSL_CTX_set_cert_verify_callback - */ -static int cert_verify_callback(X509_STORE_CTX* x509_store_ctx, void* arg __attribute__ ((unused))) -{ - /* Get the correct index to the SSLobject stored into X509_STORE_CTX. */ - SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(x509_store_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx())); - JNI_TRACE("ssl=%p cert_verify_callback x509_store_ctx=%p arg=%p", ssl, x509_store_ctx, arg); - - AppData* appData = toAppData(ssl); - JNIEnv* env = appData->env; - if (env == NULL) { - ALOGE("AppData->env missing in cert_verify_callback"); - JNI_TRACE("ssl=%p cert_verify_callback => 0", ssl); - return 0; - } - jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; - - jclass cls = env->GetObjectClass(sslHandshakeCallbacks); - jmethodID methodID - = env->GetMethodID(cls, "verifyCertificateChain", "([JLjava/lang/String;)V"); - - jlongArray refArray = getCertificateRefs(env, x509_store_ctx->untrusted); - - const char* authMethod = SSL_authentication_method(ssl); - JNI_TRACE("ssl=%p cert_verify_callback calling verifyCertificateChain authMethod=%s", - ssl, authMethod); - jstring authMethodString = env->NewStringUTF(authMethod); - env->CallVoidMethod(sslHandshakeCallbacks, methodID, refArray, authMethodString); - - int result = (env->ExceptionCheck()) ? 0 : 1; - JNI_TRACE("ssl=%p cert_verify_callback => %d", ssl, result); - return result; -} - -/** - * Call back to watch for handshake to be completed. This is necessary - * for SSL_MODE_HANDSHAKE_CUTTHROUGH support, since SSL_do_handshake - * returns before the handshake is completed in this case. - */ -static void info_callback(const SSL* ssl, int where, int ret __attribute__ ((unused))) { - JNI_TRACE("ssl=%p info_callback where=0x%x ret=%d", ssl, where, ret); -#ifdef WITH_JNI_TRACE - info_callback_LOG(ssl, where, ret); -#endif - if (!(where & SSL_CB_HANDSHAKE_DONE)) { - JNI_TRACE("ssl=%p info_callback ignored", ssl); - return; - } - - AppData* appData = toAppData(ssl); - JNIEnv* env = appData->env; - if (env == NULL) { - ALOGE("AppData->env missing in info_callback"); - JNI_TRACE("ssl=%p info_callback env error", ssl); - return; - } - if (env->ExceptionCheck()) { - JNI_TRACE("ssl=%p info_callback already pending exception", ssl); - return; - } - - jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; - - jclass cls = env->GetObjectClass(sslHandshakeCallbacks); - jmethodID methodID = env->GetMethodID(cls, "handshakeCompleted", "()V"); - - JNI_TRACE("ssl=%p info_callback calling handshakeCompleted", ssl); - env->CallVoidMethod(sslHandshakeCallbacks, methodID); - - if (env->ExceptionCheck()) { - JNI_TRACE("ssl=%p info_callback exception", ssl); - } - JNI_TRACE("ssl=%p info_callback completed", ssl); -} - -/** - * Call back to ask for a client certificate. There are three possible exit codes: - * - * 1 is success. x509Out and pkeyOut should point to the correct private key and certificate. - * 0 is unable to find key. x509Out and pkeyOut should be NULL. - * -1 is error and it doesn't matter what x509Out and pkeyOut are. - */ -static int client_cert_cb(SSL* ssl, X509** x509Out, EVP_PKEY** pkeyOut) { - JNI_TRACE("ssl=%p client_cert_cb x509Out=%p pkeyOut=%p", ssl, x509Out, pkeyOut); - - /* Clear output of key and certificate in case of early exit due to error. */ - *x509Out = NULL; - *pkeyOut = NULL; - - AppData* appData = toAppData(ssl); - JNIEnv* env = appData->env; - if (env == NULL) { - ALOGE("AppData->env missing in client_cert_cb"); - JNI_TRACE("ssl=%p client_cert_cb env error => 0", ssl); - return 0; - } - if (env->ExceptionCheck()) { - JNI_TRACE("ssl=%p client_cert_cb already pending exception => 0", ssl); - return -1; - } - jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; - - jclass cls = env->GetObjectClass(sslHandshakeCallbacks); - jmethodID methodID - = env->GetMethodID(cls, "clientCertificateRequested", "([B[[B)V"); - - // Call Java callback which can use SSL_use_certificate and SSL_use_PrivateKey to set values - char ssl2_ctype = SSL3_CT_RSA_SIGN; - const char* ctype = NULL; - int ctype_num = 0; - jobjectArray issuers = NULL; - switch (ssl->version) { - case SSL2_VERSION: - ctype = &ssl2_ctype; - ctype_num = 1; - break; - case SSL3_VERSION: - case TLS1_VERSION: - case TLS1_1_VERSION: - case TLS1_2_VERSION: - case DTLS1_VERSION: - ctype = ssl->s3->tmp.ctype; - ctype_num = ssl->s3->tmp.ctype_num; - issuers = getPrincipalBytes(env, ssl->s3->tmp.ca_names); - break; - } -#ifdef WITH_JNI_TRACE - for (int i = 0; i < ctype_num; i++) { - JNI_TRACE("ssl=%p clientCertificateRequested keyTypes[%d]=%d", ssl, i, ctype[i]); - } -#endif - - jbyteArray keyTypes = env->NewByteArray(ctype_num); - if (keyTypes == NULL) { - JNI_TRACE("ssl=%p client_cert_cb bytes == null => 0", ssl); - return 0; - } - env->SetByteArrayRegion(keyTypes, 0, ctype_num, reinterpret_cast<const jbyte*>(ctype)); - - JNI_TRACE("ssl=%p clientCertificateRequested calling clientCertificateRequested " - "keyTypes=%p issuers=%p", ssl, keyTypes, issuers); - env->CallVoidMethod(sslHandshakeCallbacks, methodID, keyTypes, issuers); - - if (env->ExceptionCheck()) { - JNI_TRACE("ssl=%p client_cert_cb exception => 0", ssl); - return -1; - } - - // Check for values set from Java - X509* certificate = SSL_get_certificate(ssl); - EVP_PKEY* privatekey = SSL_get_privatekey(ssl); - int result = 0; - if (certificate != NULL && privatekey != NULL) { - *x509Out = certificate; - *pkeyOut = privatekey; - result = 1; - } else { - // Some error conditions return NULL, so make sure it doesn't linger. - freeOpenSslErrorState(); - } - JNI_TRACE("ssl=%p client_cert_cb => *x509=%p *pkey=%p %d", ssl, *x509Out, *pkeyOut, result); - return result; -} - -static RSA* rsaGenerateKey(int keylength) { - Unique_BIGNUM bn(BN_new()); - if (bn.get() == NULL) { - return NULL; - } - int setWordResult = BN_set_word(bn.get(), RSA_F4); - if (setWordResult != 1) { - return NULL; - } - Unique_RSA rsa(RSA_new()); - if (rsa.get() == NULL) { - return NULL; - } - int generateResult = RSA_generate_key_ex(rsa.get(), keylength, bn.get(), NULL); - if (generateResult != 1) { - return NULL; - } - return rsa.release(); -} - -/** - * Call back to ask for an ephemeral RSA key for SSL_RSA_EXPORT_WITH_RC4_40_MD5 (aka EXP-RC4-MD5) - */ -static RSA* tmp_rsa_callback(SSL* ssl __attribute__ ((unused)), - int is_export __attribute__ ((unused)), - int keylength) { - JNI_TRACE("ssl=%p tmp_rsa_callback is_export=%d keylength=%d", ssl, is_export, keylength); - - AppData* appData = toAppData(ssl); - if (appData->ephemeralRsa.get() == NULL) { - JNI_TRACE("ssl=%p tmp_rsa_callback generating ephemeral RSA key", ssl); - appData->ephemeralRsa.reset(rsaGenerateKey(keylength)); - } - JNI_TRACE("ssl=%p tmp_rsa_callback => %p", ssl, appData->ephemeralRsa.get()); - return appData->ephemeralRsa.get(); -} - -static DH* dhGenerateParameters(int keylength) { - - /* - * The SSL_CTX_set_tmp_dh_callback(3SSL) man page discusses two - * different options for generating DH keys. One is generating the - * keys using a single set of DH parameters. However, generating - * DH parameters is slow enough (minutes) that they suggest doing - * it once at install time. The other is to generate DH keys from - * DSA parameters. Generating DSA parameters is faster than DH - * parameters, but to prevent small subgroup attacks, they needed - * to be regenerated for each set of DH keys. Setting the - * SSL_OP_SINGLE_DH_USE option make sure OpenSSL will call back - * for new DH parameters every type it needs to generate DH keys. - */ -#if 0 - // Slow path that takes minutes but could be cached - Unique_DH dh(DH_new()); - if (!DH_generate_parameters_ex(dh.get(), keylength, 2, NULL)) { - return NULL; - } - return dh.release(); -#else - // Faster path but must have SSL_OP_SINGLE_DH_USE set - Unique_DSA dsa(DSA_new()); - if (!DSA_generate_parameters_ex(dsa.get(), keylength, NULL, 0, NULL, NULL, NULL)) { - return NULL; - } - DH* dh = DSA_dup_DH(dsa.get()); - return dh; -#endif -} - -/** - * Call back to ask for Diffie-Hellman parameters - */ -static DH* tmp_dh_callback(SSL* ssl __attribute__ ((unused)), - int is_export __attribute__ ((unused)), - int keylength) { - JNI_TRACE("ssl=%p tmp_dh_callback is_export=%d keylength=%d", ssl, is_export, keylength); - DH* tmp_dh = dhGenerateParameters(keylength); - JNI_TRACE("ssl=%p tmp_dh_callback => %p", ssl, tmp_dh); - return tmp_dh; -} - -static EC_KEY* ecGenerateKey(int keylength __attribute__ ((unused))) { - // TODO selected curve based on keylength - Unique_EC_KEY ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); - if (ec.get() == NULL) { - return NULL; - } - return ec.release(); -} - -/** - * Call back to ask for an ephemeral EC key for TLS_ECDHE_* cipher suites - */ -static EC_KEY* tmp_ecdh_callback(SSL* ssl __attribute__ ((unused)), - int is_export __attribute__ ((unused)), - int keylength) { - JNI_TRACE("ssl=%p tmp_ecdh_callback is_export=%d keylength=%d", ssl, is_export, keylength); - AppData* appData = toAppData(ssl); - if (appData->ephemeralEc.get() == NULL) { - JNI_TRACE("ssl=%p tmp_ecdh_callback generating ephemeral EC key", ssl); - appData->ephemeralEc.reset(ecGenerateKey(keylength)); - } - JNI_TRACE("ssl=%p tmp_ecdh_callback => %p", ssl, appData->ephemeralEc.get()); - return appData->ephemeralEc.get(); -} - -/* - * public static native int SSL_CTX_new(); - */ -static jlong NativeCrypto_SSL_CTX_new(JNIEnv* env, jclass) { - Unique_SSL_CTX sslCtx(SSL_CTX_new(SSLv23_method())); - if (sslCtx.get() == NULL) { - throwExceptionIfNecessary(env, "SSL_CTX_new"); - return 0; - } - SSL_CTX_set_options(sslCtx.get(), - SSL_OP_ALL - // Note: We explicitly do not allow SSLv2 to be used. - | SSL_OP_NO_SSLv2 - // We also disable session tickets for better compatibility b/2682876 - | SSL_OP_NO_TICKET - // We also disable compression for better compatibility b/2710492 b/2710497 - | SSL_OP_NO_COMPRESSION - // Because dhGenerateParameters uses DSA_generate_parameters_ex - | SSL_OP_SINGLE_DH_USE - // Because ecGenerateParameters uses a fixed named curve - | SSL_OP_SINGLE_ECDH_USE); - - int mode = SSL_CTX_get_mode(sslCtx.get()); - /* - * Turn on "partial write" mode. This means that SSL_write() will - * behave like Posix write() and possibly return after only - * writing a partial buffer. Note: The alternative, perhaps - * surprisingly, is not that SSL_write() always does full writes - * but that it will force you to retry write calls having - * preserved the full state of the original call. (This is icky - * and undesirable.) - */ - mode |= SSL_MODE_ENABLE_PARTIAL_WRITE; - - // Reuse empty buffers within the SSL_CTX to save memory - mode |= SSL_MODE_RELEASE_BUFFERS; - - SSL_CTX_set_mode(sslCtx.get(), mode); - - SSL_CTX_set_cert_verify_callback(sslCtx.get(), cert_verify_callback, NULL); - SSL_CTX_set_info_callback(sslCtx.get(), info_callback); - SSL_CTX_set_client_cert_cb(sslCtx.get(), client_cert_cb); - SSL_CTX_set_tmp_rsa_callback(sslCtx.get(), tmp_rsa_callback); - SSL_CTX_set_tmp_dh_callback(sslCtx.get(), tmp_dh_callback); - SSL_CTX_set_tmp_ecdh_callback(sslCtx.get(), tmp_ecdh_callback); - - JNI_TRACE("NativeCrypto_SSL_CTX_new => %p", sslCtx.get()); - return (jlong) sslCtx.release(); -} - -/** - * public static native void SSL_CTX_free(int ssl_ctx) - */ -static void NativeCrypto_SSL_CTX_free(JNIEnv* env, - jclass, jlong ssl_ctx_address) -{ - SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_free", ssl_ctx); - if (ssl_ctx == NULL) { - return; - } - SSL_CTX_free(ssl_ctx); -} - -static void NativeCrypto_SSL_CTX_set_session_id_context(JNIEnv* env, jclass, - jlong ssl_ctx_address, jbyteArray sid_ctx) -{ - SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context sid_ctx=%p", ssl_ctx, sid_ctx); - if (ssl_ctx == NULL) { - return; - } - - ScopedByteArrayRO buf(env, sid_ctx); - if (buf.get() == NULL) { - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => threw exception", ssl_ctx); - return; - } - - unsigned int length = buf.size(); - if (length > SSL_MAX_SSL_SESSION_ID_LENGTH) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "length > SSL_MAX_SSL_SESSION_ID_LENGTH"); - JNI_TRACE("NativeCrypto_SSL_CTX_set_session_id_context => length = %d", length); - return; - } - const unsigned char* bytes = reinterpret_cast<const unsigned char*>(buf.get()); - int result = SSL_CTX_set_session_id_context(ssl_ctx, bytes, length); - if (result == 0) { - throwExceptionIfNecessary(env, "NativeCrypto_SSL_CTX_set_session_id_context"); - return; - } - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => ok", ssl_ctx); -} - -/** - * public static native int SSL_new(int ssl_ctx) throws SSLException; - */ -static jlong NativeCrypto_SSL_new(JNIEnv* env, jclass, jlong ssl_ctx_address) -{ - SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new", ssl_ctx); - if (ssl_ctx == NULL) { - return 0; - } - Unique_SSL ssl(SSL_new(ssl_ctx)); - if (ssl.get() == NULL) { - throwSSLExceptionWithSslErrors(env, NULL, SSL_ERROR_NONE, - "Unable to create SSL structure"); - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); - return 0; - } - - /* Java code in class OpenSSLSocketImpl does the verification. Meaning of - * SSL_VERIFY_NONE flag in client mode: if not using an anonymous cipher - * (by default disabled), the server will send a certificate which will - * be checked. The result of the certificate verification process can be - * checked after the TLS/SSL handshake using the SSL_get_verify_result(3) - * function. The handshake will be continued regardless of the - * verification result. - */ - SSL_set_verify(ssl.get(), SSL_VERIFY_NONE, NULL); - - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => ssl=%p", ssl_ctx, ssl.get()); - return (jlong) ssl.release(); -} - - -static void NativeCrypto_SSL_enable_tls_channel_id(JNIEnv* env, jclass, jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_enable_tls_channel_id", ssl); - if (ssl == NULL) { - return; - } - - long ret = SSL_enable_tls_channel_id(ssl); - if (ret != 1L) { - ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error enabling Channel ID"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_enable_tls_channel_id => error", ssl); - return; - } -} - -static jbyteArray NativeCrypto_SSL_get_tls_channel_id(JNIEnv* env, jclass, jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_get_tls_channel_id", ssl); - if (ssl == NULL) { - return NULL; - } - - // Channel ID is 64 bytes long. Unfortunately, OpenSSL doesn't declare this length - // as a constant anywhere. - jbyteArray javaBytes = env->NewByteArray(64); - ScopedByteArrayRW bytes(env, javaBytes); - if (bytes.get() == NULL) { - JNI_TRACE("NativeCrypto_SSL_get_tls_channel_id(%p) => NULL", ssl); - return NULL; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get()); - // Unfortunately, the SSL_get_tls_channel_id method below always returns 64 (upon success) - // regardless of the number of bytes copied into the output buffer "tmp". Thus, the correctness - // of this code currently relies on the "tmp" buffer being exactly 64 bytes long. - long ret = SSL_get_tls_channel_id(ssl, tmp, 64); - if (ret == 0) { - // Channel ID either not set or did not verify - JNI_TRACE("NativeCrypto_SSL_get_tls_channel_id(%p) => not available", ssl); - return NULL; - } else if (ret != 64) { - ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error getting Channel ID"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_tls_channel_id => error, returned %ld", ssl, ret); - return NULL; - } - - JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_get_tls_channel_id() => %p", ssl, javaBytes); - return javaBytes; -} - -static void NativeCrypto_SSL_set1_tls_channel_id(JNIEnv* env, jclass, - jlong ssl_address, jlong pkeyRef) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("ssl=%p SSL_set1_tls_channel_id privatekey=%p", ssl, pkey); - if (ssl == NULL) { - return; - } - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => pkey == null", ssl); - return; - } - - // SSL_set1_tls_channel_id requires ssl->server to be set to 0. - // Unfortunately, the default value is 1 and it's only changed to 0 just - // before the handshake starts (see NativeCrypto_SSL_do_handshake). - ssl->server = 0; - long ret = SSL_set1_tls_channel_id(ssl, pkey); - - if (ret != 1L) { - ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); - throwSSLExceptionWithSslErrors( - env, ssl, SSL_ERROR_NONE, "Error setting private key for Channel ID"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => error", ssl); - return; - } - // SSL_set1_tls_channel_id expects to take ownership of the EVP_PKEY, but - // we have an external reference from the caller such as an OpenSSLKey, - // so we manually increment the reference count here. - CRYPTO_add(&pkey->references,+1,CRYPTO_LOCK_EVP_PKEY); - - JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => ok", ssl); -} - -static void NativeCrypto_SSL_use_PrivateKey(JNIEnv* env, jclass, jlong ssl_address, jlong pkeyRef) { - SSL* ssl = to_SSL(env, ssl_address, true); - EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); - JNI_TRACE("ssl=%p SSL_use_PrivateKey privatekey=%p", ssl, pkey); - if (ssl == NULL) { - return; - } - - if (pkey == NULL) { - jniThrowNullPointerException(env, "pkey == null"); - JNI_TRACE("ssl=%p SSL_use_PrivateKey => pkey == null", ssl); - return; - } - - int ret = SSL_use_PrivateKey(ssl, pkey); - if (ret != 1) { - ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting private key"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p SSL_use_PrivateKey => error", ssl); - return; - } - // SSL_use_PrivateKey expects to take ownership of the EVP_PKEY, - // but we have an external reference from the caller such as an - // OpenSSLKey, so we manually increment the reference count here. - CRYPTO_add(&pkey->references,+1,CRYPTO_LOCK_EVP_PKEY); - - JNI_TRACE("ssl=%p SSL_use_PrivateKey => ok", ssl); -} - -static void NativeCrypto_SSL_use_certificate(JNIEnv* env, jclass, - jlong ssl_address, jlongArray certificatesJava) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate certificates=%p", ssl, certificatesJava); - if (ssl == NULL) { - return; - } - - if (certificatesJava == NULL) { - jniThrowNullPointerException(env, "certificates == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates == null", ssl); - return; - } - - size_t length = env->GetArrayLength(certificatesJava); - if (length == 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", "certificates.length == 0"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates.length == 0", ssl); - return; - } - - ScopedLongArrayRO certificates(env, certificatesJava); - if (certificates.get() == NULL) { - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates == null", ssl); - return; - } - - Unique_X509 serverCert( - X509_dup_nocopy(reinterpret_cast<X509*>(static_cast<uintptr_t>(certificates[0])))); - if (serverCert.get() == NULL) { - // Note this shouldn't happen since we checked the number of certificates above. - jniThrowOutOfMemory(env, "Unable to allocate local certificate chain"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => chain allocation error", ssl); - return; - } - - Unique_sk_X509 chain(sk_X509_new_null()); - if (chain.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate local certificate chain"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => chain allocation error", ssl); - return; - } - - for (size_t i = 1; i < length; i++) { - Unique_X509 cert( - X509_dup_nocopy(reinterpret_cast<X509*>(static_cast<uintptr_t>(certificates[i])))); - if (cert.get() == NULL || !sk_X509_push(chain.get(), cert.get())) { - ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing certificate"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates parsing error", ssl); - return; - } - OWNERSHIP_TRANSFERRED(cert); - } - - int ret = SSL_use_certificate(ssl, serverCert.get()); - if (ret != 1) { - ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate error", ssl); - return; - } - OWNERSHIP_TRANSFERRED(serverCert); - - int chainResult = SSL_use_certificate_chain(ssl, chain.get()); - if (chainResult == 0) { - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate chain"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate_chain error", - ssl); - return; - } - OWNERSHIP_TRANSFERRED(chain); - - JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => ok", ssl); -} - -static void NativeCrypto_SSL_check_private_key(JNIEnv* env, jclass, jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key", ssl); - if (ssl == NULL) { - return; - } - int ret = SSL_check_private_key(ssl); - if (ret != 1) { - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error checking private key"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key => error", ssl); - return; - } - JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key => ok", ssl); -} - -static void NativeCrypto_SSL_set_client_CA_list(JNIEnv* env, jclass, - jlong ssl_address, jobjectArray principals) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list principals=%p", ssl, principals); - if (ssl == NULL) { - return; - } - - if (principals == NULL) { - jniThrowNullPointerException(env, "principals == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals == null", ssl); - return; - } - - int length = env->GetArrayLength(principals); - if (length == 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", "principals.length == 0"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals.length == 0", ssl); - return; - } - - Unique_sk_X509_NAME principalsStack(sk_X509_NAME_new_null()); - if (principalsStack.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate principal stack"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => stack allocation error", ssl); - return; - } - for (int i = 0; i < length; i++) { - ScopedLocalRef<jbyteArray> principal(env, - reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(principals, i))); - if (principal.get() == NULL) { - jniThrowNullPointerException(env, "principals element == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals element null", ssl); - return; - } - - ScopedByteArrayRO buf(env, principal.get()); - if (buf.get() == NULL) { - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => threw exception", ssl); - return; - } - const unsigned char* tmp = reinterpret_cast<const unsigned char*>(buf.get()); - Unique_X509_NAME principalX509Name(d2i_X509_NAME(NULL, &tmp, buf.size())); - - if (principalX509Name.get() == NULL) { - ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing principal"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals parsing error", - ssl); - return; - } - - if (!sk_X509_NAME_push(principalsStack.get(), principalX509Name.release())) { - jniThrowOutOfMemory(env, "Unable to push principal"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principal push error", ssl); - return; - } - } - - SSL_set_client_CA_list(ssl, principalsStack.release()); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => ok", ssl); -} - -/** - * public static native long SSL_get_mode(int ssl); - */ -static jlong NativeCrypto_SSL_get_mode(JNIEnv* env, jclass, jlong ssl_address) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode", ssl); - if (ssl == NULL) { - return 0; - } - long mode = SSL_get_mode(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode => 0x%lx", ssl, mode); - return mode; -} - -/** - * public static native long SSL_set_mode(int ssl, long mode); - */ -static jlong NativeCrypto_SSL_set_mode(JNIEnv* env, jclass, - jlong ssl_address, jlong mode) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode mode=0x%llx", ssl, mode); - if (ssl == NULL) { - return 0; - } - long result = SSL_set_mode(ssl, mode); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode => 0x%lx", ssl, result); - return result; -} - -/** - * public static native long SSL_clear_mode(int ssl, long mode); - */ -static jlong NativeCrypto_SSL_clear_mode(JNIEnv* env, jclass, - jlong ssl_address, jlong mode) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode mode=0x%llx", ssl, mode); - if (ssl == NULL) { - return 0; - } - long result = SSL_clear_mode(ssl, mode); - JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode => 0x%lx", ssl, result); - return result; -} - -/** - * public static native long SSL_get_options(int ssl); - */ -static jlong NativeCrypto_SSL_get_options(JNIEnv* env, jclass, - jlong ssl_address) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options", ssl); - if (ssl == NULL) { - return 0; - } - long options = SSL_get_options(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options => 0x%lx", ssl, options); - return options; -} - -/** - * public static native long SSL_set_options(int ssl, long options); - */ -static jlong NativeCrypto_SSL_set_options(JNIEnv* env, jclass, - jlong ssl_address, jlong options) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options options=0x%llx", ssl, options); - if (ssl == NULL) { - return 0; - } - long result = SSL_set_options(ssl, options); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options => 0x%lx", ssl, result); - return result; -} - -/** - * public static native long SSL_clear_options(int ssl, long options); - */ -static jlong NativeCrypto_SSL_clear_options(JNIEnv* env, jclass, - jlong ssl_address, jlong options) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options options=0x%llx", ssl, options); - if (ssl == NULL) { - return 0; - } - long result = SSL_clear_options(ssl, options); - JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options => 0x%lx", ssl, result); - return result; -} - -/** - * Sets the ciphers suites that are enabled in the SSL - */ -static void NativeCrypto_SSL_set_cipher_lists(JNIEnv* env, jclass, - jlong ssl_address, jobjectArray cipherSuites) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuites=%p", ssl, cipherSuites); - if (ssl == NULL) { - return; - } - if (cipherSuites == NULL) { - jniThrowNullPointerException(env, "cipherSuites == null"); - return; - } - - Unique_sk_SSL_CIPHER cipherstack(sk_SSL_CIPHER_new_null()); - if (cipherstack.get() == NULL) { - jniThrowRuntimeException(env, "sk_SSL_CIPHER_new_null failed"); - return; - } - - const SSL_METHOD* ssl_method = ssl->method; - int num_ciphers = ssl_method->num_ciphers(); - - int length = env->GetArrayLength(cipherSuites); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists length=%d", ssl, length); - for (int i = 0; i < length; i++) { - ScopedLocalRef<jstring> cipherSuite(env, - reinterpret_cast<jstring>(env->GetObjectArrayElement(cipherSuites, i))); - ScopedUtfChars c(env, cipherSuite.get()); - if (c.c_str() == NULL) { - return; - } - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuite=%s", ssl, c.c_str()); - bool found = false; - for (int j = 0; j < num_ciphers; j++) { - const SSL_CIPHER* cipher = ssl_method->get_cipher(j); - if ((strcmp(c.c_str(), cipher->name) == 0) - && (strcmp(SSL_CIPHER_get_version(cipher), "SSLv2"))) { - if (!sk_SSL_CIPHER_push(cipherstack.get(), cipher)) { - jniThrowOutOfMemory(env, "Unable to push cipher"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists => cipher push error", ssl); - return; - } - found = true; - } - } - if (!found) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "Could not find cipher suite."); - return; - } - } - - int rc = SSL_set_cipher_lists(ssl, cipherstack.get()); - if (rc == 0) { - freeOpenSslErrorState(); - jniThrowException(env, "java/lang/IllegalArgumentException", - "Illegal cipher suite strings."); - } else { - OWNERSHIP_TRANSFERRED(cipherstack); - } -} - -/** - * Sets certificate expectations, especially for server to request client auth - */ -static void NativeCrypto_SSL_set_verify(JNIEnv* env, - jclass, jlong ssl_address, jint mode) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_verify mode=%x", ssl, mode); - if (ssl == NULL) { - return; - } - SSL_set_verify(ssl, (int)mode, NULL); -} - -/** - * Sets the ciphers suites that are enabled in the SSL - */ -static void NativeCrypto_SSL_set_session(JNIEnv* env, jclass, - jlong ssl_address, jlong ssl_session_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, false); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session ssl_session=%p", ssl, ssl_session); - if (ssl == NULL) { - return; - } - - int ret = SSL_set_session(ssl, ssl_session); - if (ret != 1) { - /* - * Translate the error, and throw if it turns out to be a real - * problem. - */ - int sslErrorCode = SSL_get_error(ssl, ret); - if (sslErrorCode != SSL_ERROR_ZERO_RETURN) { - throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "SSL session set"); - SSL_clear(ssl); - } - } -} - -/** - * Sets the ciphers suites that are enabled in the SSL - */ -static void NativeCrypto_SSL_set_session_creation_enabled(JNIEnv* env, jclass, - jlong ssl_address, jboolean creation_enabled) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session_creation_enabled creation_enabled=%d", - ssl, creation_enabled); - if (ssl == NULL) { - return; - } - SSL_set_session_creation_enabled(ssl, creation_enabled); -} - -static void NativeCrypto_SSL_set_tlsext_host_name(JNIEnv* env, jclass, - jlong ssl_address, jstring hostname) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name hostname=%p", - ssl, hostname); - if (ssl == NULL) { - return; - } - - ScopedUtfChars hostnameChars(env, hostname); - if (hostnameChars.c_str() == NULL) { - return; - } - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name hostnameChars=%s", - ssl, hostnameChars.c_str()); - - int ret = SSL_set_tlsext_host_name(ssl, hostnameChars.c_str()); - if (ret != 1) { - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting host name"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name => error", ssl); - return; - } - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name => ok", ssl); -} - -static jstring NativeCrypto_SSL_get_servername(JNIEnv* env, jclass, jlong ssl_address) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_servername", ssl); - if (ssl == NULL) { - return NULL; - } - const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_servername => %s", ssl, servername); - return env->NewStringUTF(servername); -} - -/** - * A common selection path for both NPN and ALPN since they're essentially the - * same protocol. The list of protocols in "primary" is considered the order - * which should take precedence. - */ -static int proto_select(SSL* ssl __attribute__ ((unused)), - unsigned char **out, unsigned char *outLength, - const unsigned char *primary, const unsigned int primaryLength, - const unsigned char *secondary, const unsigned int secondaryLength) { - if (primary != NULL) { - JNI_TRACE("primary=%p, length=%d", primary, primaryLength); - - int status = SSL_select_next_proto(out, outLength, primary, primaryLength, secondary, - secondaryLength); - switch (status) { - case OPENSSL_NPN_NEGOTIATED: - JNI_TRACE("ssl=%p proto_select NPN/ALPN negotiated", ssl); - break; - case OPENSSL_NPN_UNSUPPORTED: - JNI_TRACE("ssl=%p proto_select NPN/ALPN unsupported", ssl); - break; - case OPENSSL_NPN_NO_OVERLAP: - JNI_TRACE("ssl=%p proto_select NPN/ALPN no overlap", ssl); - break; - } - } else { - JNI_TRACE("protocols=NULL"); - } - return SSL_TLSEXT_ERR_OK; -} - -/** - * Callback for the server to select an ALPN protocol. - */ -static int alpn_select_callback(SSL* ssl, const unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, void *) { - JNI_TRACE("ssl=%p alpn_select_callback", ssl); - - AppData* appData = toAppData(ssl); - JNI_TRACE("AppData=%p", appData); - - return proto_select(ssl, const_cast<unsigned char **>(out), outlen, - reinterpret_cast<unsigned char*>(appData->alpnProtocolsData), - appData->alpnProtocolsLength, in, inlen); -} - -/** - * Callback for the client to select an NPN protocol. - */ -static int next_proto_select_callback(SSL* ssl, unsigned char** out, unsigned char* outlen, - const unsigned char* in, unsigned int inlen, void*) -{ - JNI_TRACE("ssl=%p next_proto_select_callback", ssl); - - AppData* appData = toAppData(ssl); - JNI_TRACE("AppData=%p", appData); - - // Enable False Start on the client if the server understands NPN - // http://www.imperialviolet.org/2012/04/11/falsestart.html - SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH); - - return proto_select(ssl, out, outlen, in, inlen, - reinterpret_cast<unsigned char*>(appData->npnProtocolsData), - appData->npnProtocolsLength); -} - -/** - * Callback for the server to advertise available protocols. - */ -static int next_protos_advertised_callback(SSL* ssl, - const unsigned char **out, unsigned int *outlen, void *) -{ - JNI_TRACE("ssl=%p next_protos_advertised_callback", ssl); - AppData* appData = toAppData(ssl); - unsigned char* npnProtocols = reinterpret_cast<unsigned char*>(appData->npnProtocolsData); - if (npnProtocols != NULL) { - *out = npnProtocols; - *outlen = appData->npnProtocolsLength; - } - return SSL_TLSEXT_ERR_OK; -} - -static void NativeCrypto_SSL_CTX_enable_npn(JNIEnv* env, jclass, jlong ssl_ctx_address) -{ - SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); - if (ssl_ctx == NULL) { - return; - } - SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL); // client - SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_protos_advertised_callback, NULL); // server -} - -static void NativeCrypto_SSL_CTX_disable_npn(JNIEnv* env, jclass, jlong ssl_ctx_address) -{ - SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); - if (ssl_ctx == NULL) { - return; - } - SSL_CTX_set_next_proto_select_cb(ssl_ctx, NULL, NULL); // client - SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, NULL, NULL); // server -} - -static jbyteArray NativeCrypto_SSL_get_npn_negotiated_protocol(JNIEnv* env, jclass, - jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_npn_negotiated_protocol", ssl); - if (ssl == NULL) { - return NULL; - } - const jbyte* npn; - unsigned npnLength; - SSL_get0_next_proto_negotiated(ssl, reinterpret_cast<const unsigned char**>(&npn), &npnLength); - if (npnLength == 0) { - return NULL; - } - jbyteArray result = env->NewByteArray(npnLength); - if (result != NULL) { - env->SetByteArrayRegion(result, 0, npnLength, npn); - } - return result; -} - -static int NativeCrypto_SSL_CTX_set_alpn_protos(JNIEnv* env, jclass, jlong ssl_ctx_address, - jbyteArray protos) { - SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); - if (ssl_ctx == NULL) { - return 0; - } - - JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=%p", ssl_ctx, protos); - - if (protos == NULL) { - JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=NULL", ssl_ctx); - return 1; - } - - ScopedByteArrayRO protosBytes(env, protos); - if (protosBytes.get() == NULL) { - JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=%p => protosBytes == NULL", ssl_ctx, - protos); - return 0; - } - - const unsigned char *tmp = reinterpret_cast<const unsigned char*>(protosBytes.get()); - int ret = SSL_CTX_set_alpn_protos(ssl_ctx, tmp, protosBytes.size()); - JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=%p => ret=%d", ssl_ctx, protos, ret); - return ret; -} - -static jbyteArray NativeCrypto_SSL_get0_alpn_selected(JNIEnv* env, jclass, - jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p SSL_get0_alpn_selected", ssl); - if (ssl == NULL) { - return NULL; - } - const jbyte* npn; - unsigned npnLength; - SSL_get0_alpn_selected(ssl, reinterpret_cast<const unsigned char**>(&npn), &npnLength); - if (npnLength == 0) { - return NULL; - } - jbyteArray result = env->NewByteArray(npnLength); - if (result != NULL) { - env->SetByteArrayRegion(result, 0, npnLength, npn); - } - return result; -} - -#ifdef WITH_JNI_TRACE_KEYS -static inline char hex_char(unsigned char in) -{ - if (in < 10) { - return '0' + in; - } else if (in <= 0xF0) { - return 'A' + in - 10; - } else { - return '?'; - } -} - -static void hex_string(char **dest, unsigned char* input, int len) -{ - *dest = (char*) malloc(len * 2 + 1); - char *output = *dest; - for (int i = 0; i < len; i++) { - *output++ = hex_char(input[i] >> 4); - *output++ = hex_char(input[i] & 0xF); - } - *output = '\0'; -} - -static void debug_print_session_key(SSL_SESSION* session) -{ - char *session_id_str; - char *master_key_str; - const char *key_type; - char *keyline; - - hex_string(&session_id_str, session->session_id, session->session_id_length); - hex_string(&master_key_str, session->master_key, session->master_key_length); - - X509* peer = SSL_SESSION_get0_peer(session); - EVP_PKEY* pkey = X509_PUBKEY_get(peer->cert_info->key); - switch (EVP_PKEY_type(pkey->type)) { - case EVP_PKEY_RSA: - key_type = "RSA"; - break; - case EVP_PKEY_DSA: - key_type = "DSA"; - break; - case EVP_PKEY_EC: - key_type = "EC"; - break; - default: - key_type = "Unknown"; - break; - } - - asprintf(&keyline, "%s Session-ID:%s Master-Key:%s\n", key_type, session_id_str, - master_key_str); - JNI_TRACE("ssl_session=%p %s", session, keyline); - - free(session_id_str); - free(master_key_str); - free(keyline); -} -#endif /* WITH_JNI_TRACE_KEYS */ - -/** - * Perform SSL handshake - */ -static jlong NativeCrypto_SSL_do_handshake(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject, - jobject shc, jint timeout_millis, jboolean client_mode, jbyteArray npnProtocols, - jbyteArray alpnProtocols) { - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd=%p shc=%p timeout_millis=%d client_mode=%d npn=%p", - ssl, fdObject, shc, timeout_millis, client_mode, npnProtocols); - if (ssl == NULL) { - return 0; - } - if (fdObject == NULL) { - jniThrowNullPointerException(env, "fd == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd == null => 0", ssl); - return 0; - } - if (shc == NULL) { - jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake sslHandshakeCallbacks == null => 0", ssl); - return 0; - } - - NetFd fd(env, fdObject); - if (fd.isClosed()) { - // SocketException thrown by NetFd.isClosed - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd.isClosed() => 0", ssl); - return 0; - } - - int ret = SSL_set_fd(ssl, fd.get()); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake s=%d", ssl, fd.get()); - - if (ret != 1) { - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, - "Error setting the file descriptor"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake SSL_set_fd => 0", ssl); - return 0; - } - - /* - * Make socket non-blocking, so SSL_connect SSL_read() and SSL_write() don't hang - * forever and we can use select() to find out if the socket is ready. - */ - if (!setBlocking(fd.get(), false)) { - throwSSLExceptionStr(env, "Unable to make socket non blocking"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake setBlocking => 0", ssl); - return 0; - } - - /* - * Create our special application data. - */ - AppData* appData = AppData::create(); - if (appData == NULL) { - throwSSLExceptionStr(env, "Unable to create application data"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake appData => 0", ssl); - return 0; - } - - SSL_set_app_data(ssl, reinterpret_cast<char*>(appData)); - JNI_TRACE("ssl=%p AppData::create => %p", ssl, appData); - - if (client_mode) { - SSL_set_connect_state(ssl); - } else { - SSL_set_accept_state(ssl); - if (alpnProtocols != NULL) { - SSL_CTX_set_alpn_select_cb(SSL_get_SSL_CTX(ssl), alpn_select_callback, NULL); - } - } - - ret = 0; - while (appData->aliveAndKicking) { - errno = 0; - - if (!appData->setCallbackState(env, shc, fdObject, npnProtocols, alpnProtocols)) { - // SocketException thrown by NetFd.isClosed - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake setCallbackState => 0", ssl); - return 0; - } - ret = SSL_do_handshake(ssl); - appData->clearCallbackState(); - // cert_verify_callback threw exception - if (env->ExceptionCheck()) { - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake exception => 0", ssl); - return 0; - } - // success case - if (ret == 1) { - break; - } - // retry case - if (errno == EINTR) { - continue; - } - // error case - int sslError = SSL_get_error(ssl, ret); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake ret=%d errno=%d sslError=%d timeout_millis=%d", - ssl, ret, errno, sslError, timeout_millis); - - /* - * If SSL_do_handshake doesn't succeed due to the socket being - * either unreadable or unwritable, we use sslSelect to - * wait for it to become ready. If that doesn't happen - * before the specified timeout or an error occurs, we - * cancel the handshake. Otherwise we try the SSL_connect - * again. - */ - if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) { - appData->waitingThreads++; - int selectResult = sslSelect(env, sslError, fdObject, appData, timeout_millis); - - if (selectResult == THROWN_EXCEPTION) { - // SocketException thrown by NetFd.isClosed - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake sslSelect => 0", ssl); - return 0; - } - if (selectResult == -1) { - throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_SYSCALL, "handshake error"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake selectResult == -1 => 0", ssl); - return 0; - } - if (selectResult == 0) { - throwSocketTimeoutException(env, "SSL handshake timed out"); - SSL_clear(ssl); - freeOpenSslErrorState(); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake selectResult == 0 => 0", ssl); - return 0; - } - } else { - // ALOGE("Unknown error %d during handshake", error); - break; - } - } - - // clean error. See SSL_do_handshake(3SSL) man page. - if (ret == 0) { - /* - * The other side closed the socket before the handshake could be - * completed, but everything is within the bounds of the TLS protocol. - * We still might want to find out the real reason of the failure. - */ - int sslError = SSL_get_error(ssl, ret); - if (sslError == SSL_ERROR_NONE || (sslError == SSL_ERROR_SYSCALL && errno == 0)) { - throwSSLExceptionStr(env, "Connection closed by peer"); - } else { - throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL handshake terminated"); - } - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake clean error => 0", ssl); - return 0; - } - - // unclean error. See SSL_do_handshake(3SSL) man page. - if (ret < 0) { - /* - * Translate the error and throw exception. We are sure it is an error - * at this point. - */ - int sslError = SSL_get_error(ssl, ret); - throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL handshake aborted"); - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake unclean error => 0", ssl); - return 0; - } - SSL_SESSION* ssl_session = SSL_get1_session(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => ssl_session=%p", ssl, ssl_session); -#ifdef WITH_JNI_TRACE_KEYS - debug_print_session_key(ssl_session); -#endif - return (jlong) ssl_session; -} - -/** - * Perform SSL renegotiation - */ -static void NativeCrypto_SSL_renegotiate(JNIEnv* env, jclass, jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate", ssl); - if (ssl == NULL) { - return; - } - int result = SSL_renegotiate(ssl); - if (result != 1) { - throwSSLExceptionStr(env, "Problem with SSL_renegotiate"); - return; - } - // first call asks client to perform renegotiation - int ret = SSL_do_handshake(ssl); - if (ret != 1) { - int sslError = SSL_get_error(ssl, ret); - throwSSLExceptionWithSslErrors(env, ssl, sslError, - "Problem with SSL_do_handshake after SSL_renegotiate"); - return; - } - // if client agrees, set ssl state and perform renegotiation - ssl->state = SSL_ST_ACCEPT; - SSL_do_handshake(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate =>", ssl); -} - -/** - * public static native byte[][] SSL_get_certificate(int ssl); - */ -static jlongArray NativeCrypto_SSL_get_certificate(JNIEnv* env, jclass, jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate", ssl); - if (ssl == NULL) { - return NULL; - } - X509* certificate = SSL_get_certificate(ssl); - if (certificate == NULL) { - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); - // SSL_get_certificate can return NULL during an error as well. - freeOpenSslErrorState(); - return NULL; - } - - Unique_sk_X509 chain(sk_X509_new_null()); - if (chain.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate local certificate chain"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => threw exception", ssl); - return NULL; - } - if (!sk_X509_push(chain.get(), X509_dup_nocopy(certificate))) { - jniThrowOutOfMemory(env, "Unable to push local certificate"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); - return NULL; - } - STACK_OF(X509)* cert_chain = SSL_get_certificate_chain(ssl, certificate); - for (int i=0; i<sk_X509_num(cert_chain); i++) { - if (!sk_X509_push(chain.get(), X509_dup_nocopy(sk_X509_value(cert_chain, i)))) { - jniThrowOutOfMemory(env, "Unable to push local certificate chain"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); - return NULL; - } - } - - jlongArray refArray = getCertificateRefs(env, chain.get()); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => %p", ssl, refArray); - return refArray; -} - -// Fills a long[] with the peer certificates in the chain. -static jlongArray NativeCrypto_SSL_get_peer_cert_chain(JNIEnv* env, jclass, jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain", ssl); - if (ssl == NULL) { - return NULL; - } - STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl); - Unique_sk_X509 chain_copy(NULL); - if (ssl->server) { - X509* x509 = SSL_get_peer_certificate(ssl); - if (x509 == NULL) { - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => NULL", ssl); - return NULL; - } - chain_copy.reset(sk_X509_new_null()); - if (chain_copy.get() == NULL) { - jniThrowOutOfMemory(env, "Unable to allocate peer certificate chain"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate dup error", ssl); - return NULL; - } - size_t chain_size = sk_X509_num(chain); - for (size_t i = 0; i < chain_size; i++) { - if (!sk_X509_push(chain_copy.get(), X509_dup_nocopy(sk_X509_value(chain, i)))) { - jniThrowOutOfMemory(env, "Unable to push server's peer certificate chain"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate chain push error", ssl); - return NULL; - } - } - if (!sk_X509_push(chain_copy.get(), X509_dup_nocopy(x509))) { - jniThrowOutOfMemory(env, "Unable to push server's peer certificate"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate push error", ssl); - return NULL; - } - chain = chain_copy.get(); - } - jlongArray refArray = getCertificateRefs(env, chain); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => %p", ssl, refArray); - return refArray; -} - -/** - * Helper function which does the actual reading. The Java layer guarantees that - * at most one thread will enter this function at any given time. - * - * @param ssl non-null; the SSL context - * @param buf non-null; buffer to read into - * @param len length of the buffer, in bytes - * @param sslReturnCode original SSL return code - * @param sslErrorCode filled in with the SSL error code in case of error - * @return number of bytes read on success, -1 if the connection was - * cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown. - */ -static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* buf, jint len, - int* sslReturnCode, int* sslErrorCode, int read_timeout_millis) { - JNI_TRACE("ssl=%p sslRead buf=%p len=%d", ssl, buf, len); - - if (len == 0) { - // Don't bother doing anything in this case. - return 0; - } - - BIO* bio = SSL_get_rbio(ssl); - - AppData* appData = toAppData(ssl); - if (appData == NULL) { - return THROW_SSLEXCEPTION; - } - - while (appData->aliveAndKicking) { - errno = 0; - - if (MUTEX_LOCK(appData->mutex) == -1) { - return -1; - } - - unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio); - - if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) { - MUTEX_UNLOCK(appData->mutex); - return THROWN_EXCEPTION; - } - int result = SSL_read(ssl, buf, len); - appData->clearCallbackState(); - // callbacks can happen if server requests renegotiation - if (env->ExceptionCheck()) { - SSL_clear(ssl); - JNI_TRACE("ssl=%p sslRead => THROWN_EXCEPTION", ssl); - return THROWN_EXCEPTION; - } - int sslError = SSL_ERROR_NONE; - if (result <= 0) { - sslError = SSL_get_error(ssl, result); - freeOpenSslErrorState(); - } - JNI_TRACE("ssl=%p sslRead SSL_read result=%d sslError=%d", ssl, result, sslError); -#ifdef WITH_JNI_TRACE_DATA - for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) { - int n = result - i; - if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) { - n = WITH_JNI_TRACE_DATA_CHUNK_SIZE; - } - JNI_TRACE("ssl=%p sslRead data: %d:\n%.*s", ssl, n, n, buf+i); - } -#endif - - // If we have been successful in moving data around, check whether it - // might make sense to wake up other blocked threads, so they can give - // it a try, too. - if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved - && appData->waitingThreads > 0) { - sslNotify(appData); - } - - // If we are blocked by the underlying socket, tell the world that - // there will be one more waiting thread now. - if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) { - appData->waitingThreads++; - } - - MUTEX_UNLOCK(appData->mutex); - - switch (sslError) { - // Successfully read at least one byte. - case SSL_ERROR_NONE: { - return result; - } - - // Read zero bytes. End of stream reached. - case SSL_ERROR_ZERO_RETURN: { - return -1; - } - - // Need to wait for availability of underlying layer, then retry. - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: { - int selectResult = sslSelect(env, sslError, fdObject, appData, read_timeout_millis); - if (selectResult == THROWN_EXCEPTION) { - return THROWN_EXCEPTION; - } - if (selectResult == -1) { - *sslReturnCode = -1; - *sslErrorCode = sslError; - return THROW_SSLEXCEPTION; - } - if (selectResult == 0) { - return THROW_SOCKETTIMEOUTEXCEPTION; - } - - break; - } - - // A problem occurred during a system call, but this is not - // necessarily an error. - case SSL_ERROR_SYSCALL: { - // Connection closed without proper shutdown. Tell caller we - // have reached end-of-stream. - if (result == 0) { - return -1; - } - - // System call has been interrupted. Simply retry. - if (errno == EINTR) { - break; - } - - // Note that for all other system call errors we fall through - // to the default case, which results in an Exception. - } - - // Everything else is basically an error. - default: { - *sslReturnCode = result; - *sslErrorCode = sslError; - return THROW_SSLEXCEPTION; - } - } - } - - return -1; -} - -/** - * OpenSSL read function (2): read into buffer at offset n chunks. - * Returns 1 (success) or value <= 0 (failure). - */ -static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject, - jobject shc, jbyteArray b, jint offset, jint len, - jint read_timeout_millis) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d read_timeout_millis=%d", - ssl, fdObject, shc, b, offset, len, read_timeout_millis); - if (ssl == NULL) { - return 0; - } - if (fdObject == NULL) { - jniThrowNullPointerException(env, "fd == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_read => fd == null", ssl); - return 0; - } - if (shc == NULL) { - jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_read => sslHandshakeCallbacks == null", ssl); - return 0; - } - - ScopedByteArrayRW bytes(env, b); - if (bytes.get() == NULL) { - JNI_TRACE("ssl=%p NativeCrypto_SSL_read => threw exception", ssl); - return 0; - } - int returnCode = 0; - int sslErrorCode = SSL_ERROR_NONE;; - - int ret = sslRead(env, ssl, fdObject, shc, reinterpret_cast<char*>(bytes.get() + offset), len, - &returnCode, &sslErrorCode, read_timeout_millis); - - int result; - switch (ret) { - case THROW_SSLEXCEPTION: - // See sslRead() regarding improper failure to handle normal cases. - throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Read error"); - result = -1; - break; - case THROW_SOCKETTIMEOUTEXCEPTION: - throwSocketTimeoutException(env, "Read timed out"); - result = -1; - break; - case THROWN_EXCEPTION: - // SocketException thrown by NetFd.isClosed - // or RuntimeException thrown by callback - result = -1; - break; - default: - result = ret; - break; - } - - JNI_TRACE("ssl=%p NativeCrypto_SSL_read => %d", ssl, result); - return result; -} - -/** - * Helper function which does the actual writing. The Java layer guarantees that - * at most one thread will enter this function at any given time. - * - * @param ssl non-null; the SSL context - * @param buf non-null; buffer to write - * @param len length of the buffer, in bytes - * @param sslReturnCode original SSL return code - * @param sslErrorCode filled in with the SSL error code in case of error - * @return number of bytes read on success, -1 if the connection was - * cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown. - */ -static int sslWrite(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, const char* buf, jint len, - int* sslReturnCode, int* sslErrorCode, int write_timeout_millis) { - JNI_TRACE("ssl=%p sslWrite buf=%p len=%d write_timeout_millis=%d", - ssl, buf, len, write_timeout_millis); - - if (len == 0) { - // Don't bother doing anything in this case. - return 0; - } - - BIO* bio = SSL_get_wbio(ssl); - - AppData* appData = toAppData(ssl); - if (appData == NULL) { - return THROW_SSLEXCEPTION; - } - - int count = len; - - while (appData->aliveAndKicking && ((len > 0) || (ssl->s3->wbuf.left > 0))) { - errno = 0; - - if (MUTEX_LOCK(appData->mutex) == -1) { - return -1; - } - - unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio); - - if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) { - MUTEX_UNLOCK(appData->mutex); - return THROWN_EXCEPTION; - } - JNI_TRACE("ssl=%p sslWrite SSL_write len=%d left=%d", ssl, len, ssl->s3->wbuf.left); - int result = SSL_write(ssl, buf, len); - appData->clearCallbackState(); - // callbacks can happen if server requests renegotiation - if (env->ExceptionCheck()) { - SSL_clear(ssl); - JNI_TRACE("ssl=%p sslWrite exception => THROWN_EXCEPTION", ssl); - return THROWN_EXCEPTION; - } - int sslError = SSL_ERROR_NONE; - if (result <= 0) { - sslError = SSL_get_error(ssl, result); - freeOpenSslErrorState(); - } - JNI_TRACE("ssl=%p sslWrite SSL_write result=%d sslError=%d left=%d", - ssl, result, sslError, ssl->s3->wbuf.left); -#ifdef WITH_JNI_TRACE_DATA - for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) { - int n = result - i; - if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) { - n = WITH_JNI_TRACE_DATA_CHUNK_SIZE; - } - JNI_TRACE("ssl=%p sslWrite data: %d:\n%.*s", ssl, n, n, buf+i); - } -#endif - - // If we have been successful in moving data around, check whether it - // might make sense to wake up other blocked threads, so they can give - // it a try, too. - if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved - && appData->waitingThreads > 0) { - sslNotify(appData); - } - - // If we are blocked by the underlying socket, tell the world that - // there will be one more waiting thread now. - if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) { - appData->waitingThreads++; - } - - MUTEX_UNLOCK(appData->mutex); - - switch (sslError) { - // Successfully wrote at least one byte. - case SSL_ERROR_NONE: { - buf += result; - len -= result; - break; - } - - // Wrote zero bytes. End of stream reached. - case SSL_ERROR_ZERO_RETURN: { - return -1; - } - - // Need to wait for availability of underlying layer, then retry. - // The concept of a write timeout doesn't really make sense, and - // it's also not standard Java behavior, so we wait forever here. - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: { - int selectResult = sslSelect(env, sslError, fdObject, appData, write_timeout_millis); - if (selectResult == THROWN_EXCEPTION) { - return THROWN_EXCEPTION; - } - if (selectResult == -1) { - *sslReturnCode = -1; - *sslErrorCode = sslError; - return THROW_SSLEXCEPTION; - } - if (selectResult == 0) { - return THROW_SOCKETTIMEOUTEXCEPTION; - } - - break; - } - - // A problem occurred during a system call, but this is not - // necessarily an error. - case SSL_ERROR_SYSCALL: { - // Connection closed without proper shutdown. Tell caller we - // have reached end-of-stream. - if (result == 0) { - return -1; - } - - // System call has been interrupted. Simply retry. - if (errno == EINTR) { - break; - } - - // Note that for all other system call errors we fall through - // to the default case, which results in an Exception. - } - - // Everything else is basically an error. - default: { - *sslReturnCode = result; - *sslErrorCode = sslError; - return THROW_SSLEXCEPTION; - } - } - } - JNI_TRACE("ssl=%p sslWrite => count=%d", ssl, count); - - return count; -} - -/** - * OpenSSL write function (2): write into buffer at offset n chunks. - */ -static void NativeCrypto_SSL_write(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject, - jobject shc, jbyteArray b, jint offset, jint len, jint write_timeout_millis) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_write fd=%p shc=%p b=%p offset=%d len=%d write_timeout_millis=%d", - ssl, fdObject, shc, b, offset, len, write_timeout_millis); - if (ssl == NULL) { - return; - } - if (fdObject == NULL) { - jniThrowNullPointerException(env, "fd == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_write => fd == null", ssl); - return; - } - if (shc == NULL) { - jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_write => sslHandshakeCallbacks == null", ssl); - return; - } - - ScopedByteArrayRO bytes(env, b); - if (bytes.get() == NULL) { - JNI_TRACE("ssl=%p NativeCrypto_SSL_write => threw exception", ssl); - return; - } - int returnCode = 0; - int sslErrorCode = SSL_ERROR_NONE; - int ret = sslWrite(env, ssl, fdObject, shc, reinterpret_cast<const char*>(bytes.get() + offset), - len, &returnCode, &sslErrorCode, write_timeout_millis); - - switch (ret) { - case THROW_SSLEXCEPTION: - // See sslWrite() regarding improper failure to handle normal cases. - throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Write error"); - break; - case THROW_SOCKETTIMEOUTEXCEPTION: - throwSocketTimeoutException(env, "Write timed out"); - break; - case THROWN_EXCEPTION: - // SocketException thrown by NetFd.isClosed - break; - default: - break; - } -} - -/** - * Interrupt any pending I/O before closing the socket. - */ -static void NativeCrypto_SSL_interrupt( - JNIEnv* env, jclass, jlong ssl_address) { - SSL* ssl = to_SSL(env, ssl_address, false); - JNI_TRACE("ssl=%p NativeCrypto_SSL_interrupt", ssl); - if (ssl == NULL) { - return; - } - - /* - * Mark the connection as quasi-dead, then send something to the emergency - * file descriptor, so any blocking select() calls are woken up. - */ - AppData* appData = toAppData(ssl); - if (appData != NULL) { - appData->aliveAndKicking = 0; - - // At most two threads can be waiting. - sslNotify(appData); - sslNotify(appData); - } -} - -/** - * OpenSSL close SSL socket function. - */ -static void NativeCrypto_SSL_shutdown(JNIEnv* env, jclass, jlong ssl_address, - jobject fdObject, jobject shc) { - SSL* ssl = to_SSL(env, ssl_address, false); - JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown fd=%p shc=%p", ssl, fdObject, shc); - if (ssl == NULL) { - return; - } - if (fdObject == NULL) { - jniThrowNullPointerException(env, "fd == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => fd == null", ssl); - return; - } - if (shc == NULL) { - jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); - JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => sslHandshakeCallbacks == null", ssl); - return; - } - - AppData* appData = toAppData(ssl); - if (appData != NULL) { - if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) { - // SocketException thrown by NetFd.isClosed - SSL_clear(ssl); - freeOpenSslErrorState(); - return; - } - - /* - * Try to make socket blocking again. OpenSSL literature recommends this. - */ - int fd = SSL_get_fd(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown s=%d", ssl, fd); - if (fd != -1) { - setBlocking(fd, true); - } - - int ret = SSL_shutdown(ssl); - appData->clearCallbackState(); - // callbacks can happen if server requests renegotiation - if (env->ExceptionCheck()) { - SSL_clear(ssl); - JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => exception", ssl); - return; - } - switch (ret) { - case 0: - /* - * Shutdown was not successful (yet), but there also - * is no error. Since we can't know whether the remote - * server is actually still there, and we don't want to - * get stuck forever in a second SSL_shutdown() call, we - * simply return. This is not security a problem as long - * as we close the underlying socket, which we actually - * do, because that's where we are just coming from. - */ - break; - case 1: - /* - * Shutdown was successful. We can safely return. Hooray! - */ - break; - default: - /* - * Everything else is a real error condition. We should - * let the Java layer know about this by throwing an - * exception. - */ - int sslError = SSL_get_error(ssl, ret); - throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL shutdown failed"); - break; - } - } - - SSL_clear(ssl); - freeOpenSslErrorState(); -} - -/** - * public static native void SSL_free(int ssl); - */ -static void NativeCrypto_SSL_free(JNIEnv* env, jclass, jlong ssl_address) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_free", ssl); - if (ssl == NULL) { - return; - } - - AppData* appData = toAppData(ssl); - SSL_set_app_data(ssl, NULL); - delete appData; - SSL_free(ssl); -} - -/** - * Gets and returns in a byte array the ID of the actual SSL session. - */ -static jbyteArray NativeCrypto_SSL_SESSION_session_id(JNIEnv* env, jclass, - jlong ssl_session_address) { - SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id", ssl_session); - if (ssl_session == NULL) { - return NULL; - } - jbyteArray result = env->NewByteArray(ssl_session->session_id_length); - if (result != NULL) { - jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id); - env->SetByteArrayRegion(result, 0, ssl_session->session_id_length, src); - } - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id => %p session_id_length=%d", - ssl_session, result, ssl_session->session_id_length); - return result; -} - -/** - * Gets and returns in a long integer the creation's time of the - * actual SSL session. - */ -static jlong NativeCrypto_SSL_SESSION_get_time(JNIEnv* env, jclass, jlong ssl_session_address) { - SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time", ssl_session); - if (ssl_session == NULL) { - return 0; - } - // result must be jlong, not long or *1000 will overflow - jlong result = SSL_SESSION_get_time(ssl_session); - result *= 1000; // OpenSSL uses seconds, Java uses milliseconds. - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time => %lld", ssl_session, result); - return result; -} - -/** - * Gets and returns in a string the version of the SSL protocol. If it - * returns the string "unknown" it means that no connection is established. - */ -static jstring NativeCrypto_SSL_SESSION_get_version(JNIEnv* env, jclass, jlong ssl_session_address) { - SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version", ssl_session); - if (ssl_session == NULL) { - return NULL; - } - const char* protocol = SSL_SESSION_get_version(ssl_session); - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version => %s", ssl_session, protocol); - return env->NewStringUTF(protocol); -} - -/** - * Gets and returns in a string the cipher negotiated for the SSL session. - */ -static jstring NativeCrypto_SSL_SESSION_cipher(JNIEnv* env, jclass, jlong ssl_session_address) { - SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher", ssl_session); - if (ssl_session == NULL) { - return NULL; - } - const SSL_CIPHER* cipher = ssl_session->cipher; - const char* name = SSL_CIPHER_get_name(cipher); - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher => %s", ssl_session, name); - return env->NewStringUTF(name); -} - -/** - * Frees the SSL session. - */ -static void NativeCrypto_SSL_SESSION_free(JNIEnv* env, jclass, jlong ssl_session_address) { - SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); - JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_free", ssl_session); - if (ssl_session == NULL) { - return; - } - SSL_SESSION_free(ssl_session); -} - - -/** - * Serializes the native state of the session (ID, cipher, and keys but - * not certificates). Returns a byte[] containing the DER-encoded state. - * See apache mod_ssl. - */ -static jbyteArray NativeCrypto_i2d_SSL_SESSION(JNIEnv* env, jclass, jlong ssl_session_address) { - SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); - JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION", ssl_session); - if (ssl_session == NULL) { - return NULL; - } - return ASN1ToByteArray<SSL_SESSION, i2d_SSL_SESSION>(env, ssl_session); -} - -/** - * Deserialize the session. - */ -static jlong NativeCrypto_d2i_SSL_SESSION(JNIEnv* env, jclass, jbyteArray javaBytes) { - JNI_TRACE("NativeCrypto_d2i_SSL_SESSION bytes=%p", javaBytes); - - ScopedByteArrayRO bytes(env, javaBytes); - if (bytes.get() == NULL) { - JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => threw exception"); - return 0; - } - const unsigned char* ucp = reinterpret_cast<const unsigned char*>(bytes.get()); - SSL_SESSION* ssl_session = d2i_SSL_SESSION(NULL, &ucp, bytes.size()); - - // Initialize SSL_SESSION cipher field based on cipher_id http://b/7091840 - if (ssl_session != NULL) { - // based on ssl_get_prev_session - uint32_t cipher_id_network_order = htonl(ssl_session->cipher_id); - uint8_t* cipher_id_byte_pointer = reinterpret_cast<uint8_t*>(&cipher_id_network_order); - if (ssl_session->ssl_version >= SSL3_VERSION_MAJOR) { - cipher_id_byte_pointer += 2; // skip first two bytes for SSL3+ - } else { - cipher_id_byte_pointer += 1; // skip first byte for SSL2 - } - ssl_session->cipher = SSLv23_method()->get_cipher_by_char(cipher_id_byte_pointer); - JNI_TRACE("NativeCrypto_d2i_SSL_SESSION cipher_id=%lx hton=%x 0=%x 1=%x cipher=%s", - ssl_session->cipher_id, cipher_id_network_order, - cipher_id_byte_pointer[0], cipher_id_byte_pointer[1], - SSL_CIPHER_get_name(ssl_session->cipher)); - } else { - freeOpenSslErrorState(); - } - - JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => %p", ssl_session); - return reinterpret_cast<uintptr_t>(ssl_session); -} - -static jlong NativeCrypto_ERR_peek_last_error(JNIEnv*, jclass) { - return ERR_peek_last_error(); -} - -#define FILE_DESCRIPTOR "Ljava/io/FileDescriptor;" -#define SSL_CALLBACKS "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto$SSLHandshakeCallbacks;" -static JNINativeMethod sNativeCryptoMethods[] = { - NATIVE_METHOD(NativeCrypto, clinit, "()V"), - NATIVE_METHOD(NativeCrypto, ENGINE_load_dynamic, "()V"), - NATIVE_METHOD(NativeCrypto, ENGINE_by_id, "(Ljava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, ENGINE_add, "(J)I"), - NATIVE_METHOD(NativeCrypto, ENGINE_init, "(J)I"), - NATIVE_METHOD(NativeCrypto, ENGINE_finish, "(J)I"), - NATIVE_METHOD(NativeCrypto, ENGINE_free, "(J)I"), - NATIVE_METHOD(NativeCrypto, ENGINE_load_private_key, "(JLjava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, ENGINE_get_id, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, ENGINE_ctrl_cmd_string, "(JLjava/lang/String;Ljava/lang/String;I)I"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_DSA, "([B[B[B[B[B)J"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_RSA, "([B[B[B[B[B[B[B[B)J"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_EC_KEY, "(JJ[B)J"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_mac_key, "(I[B)J"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_type, "(J)I"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_size, "(J)I"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_public, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_private, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, EVP_PKEY_cmp, "(JJ)I"), - NATIVE_METHOD(NativeCrypto, i2d_PKCS8_PRIV_KEY_INFO, "(J)[B"), - NATIVE_METHOD(NativeCrypto, d2i_PKCS8_PRIV_KEY_INFO, "([B)J"), - NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(J)[B"), - NATIVE_METHOD(NativeCrypto, d2i_PUBKEY, "([B)J"), - NATIVE_METHOD(NativeCrypto, RSA_generate_key_ex, "(I[B)J"), - NATIVE_METHOD(NativeCrypto, RSA_size, "(J)I"), - NATIVE_METHOD(NativeCrypto, RSA_private_encrypt, "(I[B[BJI)I"), - NATIVE_METHOD(NativeCrypto, RSA_public_decrypt, "(I[B[BJI)I"), - NATIVE_METHOD(NativeCrypto, RSA_public_encrypt, "(I[B[BJI)I"), - NATIVE_METHOD(NativeCrypto, RSA_private_decrypt, "(I[B[BJI)I"), - NATIVE_METHOD(NativeCrypto, get_RSA_private_params, "(J)[[B"), - NATIVE_METHOD(NativeCrypto, get_RSA_public_params, "(J)[[B"), - NATIVE_METHOD(NativeCrypto, DSA_generate_key, "(I[B[B[B[B)J"), - NATIVE_METHOD(NativeCrypto, get_DSA_params, "(J)[[B"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_new_by_curve_name, "(Ljava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_new_curve, "(I[B[B[B)J"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_dup, "(J)J"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_set_asn1_flag, "(JI)V"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_set_point_conversion_form, "(JI)V"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_get_curve_name, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_get_curve, "(J)[[B"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_get_order, "(J)[B"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_get_degree, "(J)I"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_get_cofactor, "(J)[B"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_clear_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_cmp, "(JJ)Z"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_get_generator, "(J)J"), - NATIVE_METHOD(NativeCrypto, EC_GROUP_set_generator, "(JJ[B[B)V"), - NATIVE_METHOD(NativeCrypto, get_EC_GROUP_type, "(J)I"), - NATIVE_METHOD(NativeCrypto, EC_POINT_new, "(J)J"), - NATIVE_METHOD(NativeCrypto, EC_POINT_clear_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, EC_POINT_cmp, "(JJJ)Z"), - NATIVE_METHOD(NativeCrypto, EC_POINT_set_affine_coordinates, "(JJ[B[B)V"), - NATIVE_METHOD(NativeCrypto, EC_POINT_get_affine_coordinates, "(JJ)[[B"), - NATIVE_METHOD(NativeCrypto, EC_KEY_generate_key, "(J)J"), - NATIVE_METHOD(NativeCrypto, EC_KEY_get0_group, "(J)J"), - NATIVE_METHOD(NativeCrypto, EC_KEY_get_private_key, "(J)[B"), - NATIVE_METHOD(NativeCrypto, EC_KEY_get_public_key, "(J)J"), - NATIVE_METHOD(NativeCrypto, ECDH_compute_key, "([BIJJ)I"), - NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_create, "()J"), - NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_init, "(J)V"), - NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_destroy, "(J)V"), - NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_copy, "(J)J"), - NATIVE_METHOD(NativeCrypto, EVP_DigestFinal, "(J[BI)I"), - NATIVE_METHOD(NativeCrypto, EVP_DigestInit, "(J)J"), - NATIVE_METHOD(NativeCrypto, EVP_get_digestbyname, "(Ljava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, EVP_MD_block_size, "(J)I"), - NATIVE_METHOD(NativeCrypto, EVP_MD_size, "(J)I"), - NATIVE_METHOD(NativeCrypto, EVP_DigestUpdate, "(J[BII)V"), - NATIVE_METHOD(NativeCrypto, EVP_SignInit, "(Ljava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, EVP_SignUpdate, "(J[BII)V"), - NATIVE_METHOD(NativeCrypto, EVP_SignFinal, "(J[BIJ)I"), - NATIVE_METHOD(NativeCrypto, EVP_VerifyInit, "(Ljava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, EVP_VerifyUpdate, "(J[BII)V"), - NATIVE_METHOD(NativeCrypto, EVP_VerifyFinal, "(J[BIIJ)I"), - NATIVE_METHOD(NativeCrypto, EVP_DigestSignInit, "(JJJ)V"), - NATIVE_METHOD(NativeCrypto, EVP_DigestSignUpdate, "(J[B)V"), - NATIVE_METHOD(NativeCrypto, EVP_DigestSignFinal, "(J)[B"), - NATIVE_METHOD(NativeCrypto, EVP_get_cipherbyname, "(Ljava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, EVP_CipherInit_ex, "(JJ[B[BZ)V"), - NATIVE_METHOD(NativeCrypto, EVP_CipherUpdate, "(J[BI[BII)I"), - NATIVE_METHOD(NativeCrypto, EVP_CipherFinal_ex, "(J[BI)I"), - NATIVE_METHOD(NativeCrypto, EVP_CIPHER_iv_length, "(J)I"), - NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_new, "()J"), - NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_block_size, "(J)I"), - NATIVE_METHOD(NativeCrypto, get_EVP_CIPHER_CTX_buf_len, "(J)I"), - NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_padding, "(JZ)V"), - NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_key_length, "(JI)V"), - NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_cleanup, "(J)V"), - NATIVE_METHOD(NativeCrypto, RAND_seed, "([B)V"), - NATIVE_METHOD(NativeCrypto, RAND_load_file, "(Ljava/lang/String;J)I"), - NATIVE_METHOD(NativeCrypto, RAND_bytes, "([B)V"), - NATIVE_METHOD(NativeCrypto, OBJ_txt2nid, "(Ljava/lang/String;)I"), - NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_longName, "(Ljava/lang/String;)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_oid, "(Ljava/lang/String;)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, create_BIO_InputStream, ("(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream;)J")), - NATIVE_METHOD(NativeCrypto, create_BIO_OutputStream, "(Ljava/io/OutputStream;)J"), - NATIVE_METHOD(NativeCrypto, BIO_read, "(J[B)I"), - NATIVE_METHOD(NativeCrypto, BIO_write, "(J[BII)V"), - NATIVE_METHOD(NativeCrypto, BIO_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, X509_NAME_print_ex, "(JJ)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, d2i_X509_bio, "(J)J"), - NATIVE_METHOD(NativeCrypto, d2i_X509, "([B)J"), - NATIVE_METHOD(NativeCrypto, i2d_X509, "(J)[B"), - NATIVE_METHOD(NativeCrypto, i2d_X509_PUBKEY, "(J)[B"), - NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509, "(J)J"), - NATIVE_METHOD(NativeCrypto, PEM_read_bio_PKCS7, "(JI)[J"), - NATIVE_METHOD(NativeCrypto, d2i_PKCS7_bio, "(JI)[J"), - NATIVE_METHOD(NativeCrypto, i2d_PKCS7, "([J)[B"), - NATIVE_METHOD(NativeCrypto, ASN1_seq_unpack_X509_bio, "(J)[J"), - NATIVE_METHOD(NativeCrypto, ASN1_seq_pack_X509, "([J)[B"), - NATIVE_METHOD(NativeCrypto, X509_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, X509_cmp, "(JJ)I"), - NATIVE_METHOD(NativeCrypto, get_X509_hashCode, "(J)I"), - NATIVE_METHOD(NativeCrypto, X509_print_ex, "(JJJJ)V"), - NATIVE_METHOD(NativeCrypto, X509_get_pubkey, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_get_issuer_name, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_get_subject_name, "(J)[B"), - NATIVE_METHOD(NativeCrypto, get_X509_pubkey_oid, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_oid, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_parameter, "(J)[B"), - NATIVE_METHOD(NativeCrypto, get_X509_issuerUID, "(J)[Z"), - NATIVE_METHOD(NativeCrypto, get_X509_subjectUID, "(J)[Z"), - NATIVE_METHOD(NativeCrypto, get_X509_ex_kusage, "(J)[Z"), - NATIVE_METHOD(NativeCrypto, get_X509_ex_xkusage, "(J)[Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, get_X509_ex_pathlen, "(J)I"), - NATIVE_METHOD(NativeCrypto, X509_get_ext_oid, "(JLjava/lang/String;)[B"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext_oid, "(JLjava/lang/String;)[B"), - NATIVE_METHOD(NativeCrypto, get_X509_CRL_crl_enc, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_CRL_verify, "(JJ)V"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get_lastUpdate, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get_nextUpdate, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext_oid, "(JLjava/lang/String;)[B"), - NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_serialNumber, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_REVOKED_print, "(JJ)V"), - NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_revocationDate, "(J)J"), - NATIVE_METHOD(NativeCrypto, get_X509_ext_oids, "(JI)[Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, get_X509_CRL_ext_oids, "(JI)[Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_ext_oids, "(JI)[Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, get_X509_GENERAL_NAME_stack, "(JI)[[Ljava/lang/Object;"), - NATIVE_METHOD(NativeCrypto, X509_get_notBefore, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_get_notAfter, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_get_version, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_get_serialNumber, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_verify, "(JJ)V"), - NATIVE_METHOD(NativeCrypto, get_X509_cert_info_enc, "(J)[B"), - NATIVE_METHOD(NativeCrypto, get_X509_signature, "(J)[B"), - NATIVE_METHOD(NativeCrypto, get_X509_CRL_signature, "(J)[B"), - NATIVE_METHOD(NativeCrypto, get_X509_ex_flags, "(J)I"), - NATIVE_METHOD(NativeCrypto, X509_check_issued, "(JJ)I"), - NATIVE_METHOD(NativeCrypto, d2i_X509_CRL_bio, "(J)J"), - NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509_CRL, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_cert, "(JJ)J"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_serial, "(J[B)J"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get_REVOKED, "(J)[J"), - NATIVE_METHOD(NativeCrypto, i2d_X509_CRL, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_CRL_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, X509_CRL_print, "(JJ)V"), - NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_oid, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_parameter, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get_issuer_name, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get_version, "(J)J"), - NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext, "(JLjava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext, "(JLjava/lang/String;)J"), - NATIVE_METHOD(NativeCrypto, X509_REVOKED_dup, "(J)J"), - NATIVE_METHOD(NativeCrypto, i2d_X509_REVOKED, "(J)[B"), - NATIVE_METHOD(NativeCrypto, X509_supported_extension, "(J)I"), - NATIVE_METHOD(NativeCrypto, ASN1_TIME_to_Calendar, "(JLjava/util/Calendar;)V"), - NATIVE_METHOD(NativeCrypto, SSL_CTX_new, "()J"), - NATIVE_METHOD(NativeCrypto, SSL_CTX_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_CTX_set_session_id_context, "(J[B)V"), - NATIVE_METHOD(NativeCrypto, SSL_new, "(J)J"), - NATIVE_METHOD(NativeCrypto, SSL_enable_tls_channel_id, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_get_tls_channel_id, "(J)[B"), - NATIVE_METHOD(NativeCrypto, SSL_set1_tls_channel_id, "(JJ)V"), - NATIVE_METHOD(NativeCrypto, SSL_use_PrivateKey, "(JJ)V"), - NATIVE_METHOD(NativeCrypto, SSL_use_certificate, "(J[J)V"), - NATIVE_METHOD(NativeCrypto, SSL_check_private_key, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_set_client_CA_list, "(J[[B)V"), - NATIVE_METHOD(NativeCrypto, SSL_get_mode, "(J)J"), - NATIVE_METHOD(NativeCrypto, SSL_set_mode, "(JJ)J"), - NATIVE_METHOD(NativeCrypto, SSL_clear_mode, "(JJ)J"), - NATIVE_METHOD(NativeCrypto, SSL_get_options, "(J)J"), - NATIVE_METHOD(NativeCrypto, SSL_set_options, "(JJ)J"), - NATIVE_METHOD(NativeCrypto, SSL_clear_options, "(JJ)J"), - NATIVE_METHOD(NativeCrypto, SSL_set_cipher_lists, "(J[Ljava/lang/String;)V"), - NATIVE_METHOD(NativeCrypto, SSL_set_verify, "(JI)V"), - NATIVE_METHOD(NativeCrypto, SSL_set_session, "(JJ)V"), - NATIVE_METHOD(NativeCrypto, SSL_set_session_creation_enabled, "(JZ)V"), - NATIVE_METHOD(NativeCrypto, SSL_set_tlsext_host_name, "(JLjava/lang/String;)V"), - NATIVE_METHOD(NativeCrypto, SSL_get_servername, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, SSL_do_handshake, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "IZ[B[B)I"), - NATIVE_METHOD(NativeCrypto, SSL_renegotiate, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_get_certificate, "(J)[J"), - NATIVE_METHOD(NativeCrypto, SSL_get_peer_cert_chain, "(J)[J"), - NATIVE_METHOD(NativeCrypto, SSL_read, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)I"), - NATIVE_METHOD(NativeCrypto, SSL_write, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)V"), - NATIVE_METHOD(NativeCrypto, SSL_interrupt, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_shutdown, "(J" FILE_DESCRIPTOR SSL_CALLBACKS ")V"), - NATIVE_METHOD(NativeCrypto, SSL_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_SESSION_session_id, "(J)[B"), - NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_time, "(J)J"), - NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_version, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, SSL_SESSION_cipher, "(J)Ljava/lang/String;"), - NATIVE_METHOD(NativeCrypto, SSL_SESSION_free, "(J)V"), - NATIVE_METHOD(NativeCrypto, i2d_SSL_SESSION, "(J)[B"), - NATIVE_METHOD(NativeCrypto, d2i_SSL_SESSION, "([B)J"), - NATIVE_METHOD(NativeCrypto, SSL_CTX_enable_npn, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_CTX_disable_npn, "(J)V"), - NATIVE_METHOD(NativeCrypto, SSL_get_npn_negotiated_protocol, "(J)[B"), - NATIVE_METHOD(NativeCrypto, SSL_CTX_set_alpn_protos, "(J[B)I"), - NATIVE_METHOD(NativeCrypto, SSL_get0_alpn_selected, "(J)[B"), - NATIVE_METHOD(NativeCrypto, ERR_peek_last_error, "()J"), -}; - -static void initialize_conscrypt(JNIEnv* env) { - jniRegisterNativeMethods(env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto", - sNativeCryptoMethods, NELEM(sNativeCryptoMethods)); - - ScopedLocalRef<jclass> localClass(env, - env->FindClass(TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream")); - openSslOutputStreamClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get())); - if (openSslOutputStreamClass == NULL) { - ALOGE("failed to find class OpenSSLBIOInputStream"); - abort(); - } - - calendar_setMethod = env->GetMethodID(calendarClass, "set", "(IIIIII)V"); - inputStream_readMethod = env->GetMethodID(inputStreamClass, "read", "([B)I"); - integer_valueOfMethod = env->GetStaticMethodID(integerClass, "valueOf", - "(I)Ljava/lang/Integer;"); - openSslInputStream_readLineMethod = env->GetMethodID(openSslOutputStreamClass, "gets", - "([B)I"); - outputStream_writeMethod = env->GetMethodID(outputStreamClass, "write", "([B)V"); - outputStream_flushMethod = env->GetMethodID(outputStreamClass, "flush", "()V"); -} - -static jclass findClass(JNIEnv* env, const char* name) { - ScopedLocalRef<jclass> localClass(env, env->FindClass(name)); - jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get())); - if (result == NULL) { - ALOGE("failed to find class '%s'", name); - abort(); - } - return result; -} - -// Use JNI_OnLoad for when we're standalone -int JNI_OnLoad(JavaVM *vm, void*) { - JNI_TRACE("JNI_OnLoad NativeCrypto"); - gJavaVM = vm; - - JNIEnv *env; - if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { - ALOGE("Could not get JNIEnv"); - return JNI_ERR; - } - - byteArrayClass = findClass(env, "[B"); - calendarClass = findClass(env, "java/util/Calendar"); - inputStreamClass = findClass(env, "java/io/InputStream"); - integerClass = findClass(env, "java/lang/Integer"); - objectClass = findClass(env, "java/lang/Object"); - objectArrayClass = findClass(env, "[Ljava/lang/Object;"); - outputStreamClass = findClass(env, "java/io/OutputStream"); - stringClass = findClass(env, "java/lang/String"); - - initialize_conscrypt(env); - return JNI_VERSION_1_6; -} diff --git a/crypto/src/main/native/sub.mk b/crypto/src/main/native/sub.mk deleted file mode 100644 index 62f8672..0000000 --- a/crypto/src/main/native/sub.mk +++ /dev/null @@ -1,18 +0,0 @@ -# -*- mode: makefile -*- -# This file is included by the top-level libcore Android.mk. -# It's not a normal makefile, so we don't include CLEAR_VARS -# or BUILD_*_LIBRARY. - -LOCAL_SRC_FILES := \ - org_conscrypt_NativeCrypto.cpp - -LOCAL_C_INCLUDES += \ - libcore/luni/src/main/native - -# Any shared/static libs that are listed here must also -# be listed in libs/nativehelper/Android.mk. -# TODO: fix this requirement - -#LOCAL_SHARED_LIBRARIES += - -#LOCAL_STATIC_LIBRARIES += diff --git a/crypto/src/test/java/org/conscrypt/CertPinManagerTest.java b/crypto/src/test/java/org/conscrypt/CertPinManagerTest.java deleted file mode 100644 index 04890f6..0000000 --- a/crypto/src/test/java/org/conscrypt/CertPinManagerTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.File; -import java.io.FileWriter; -import java.security.cert.X509Certificate; -import java.security.KeyStore; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.List; -import junit.framework.TestCase; -import libcore.java.security.TestKeyStore; - -public class CertPinManagerTest extends TestCase { - - private X509Certificate[] chain; - private List<X509Certificate> shortChain; - private List<X509Certificate> longChain; - private String shortPin; - private String longPin; - private List<File> tmpFiles = new ArrayList<File>(); - - private String writeTmpPinFile(String text) throws Exception { - File tmp = File.createTempFile("pins", null); - FileWriter fstream = new FileWriter(tmp); - fstream.write(text); - fstream.close(); - tmpFiles.add(tmp); - return tmp.getPath(); - } - - private static String getFingerprint(X509Certificate cert) throws NoSuchAlgorithmException { - MessageDigest dgst = MessageDigest.getInstance("SHA512"); - byte[] encoded = cert.getPublicKey().getEncoded(); - byte[] fingerprint = dgst.digest(encoded); - return IntegralToString.bytesToHexString(fingerprint, false); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - // build some valid chains - KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); - chain = (X509Certificate[]) pke.getCertificateChain(); - X509Certificate root = chain[2]; - X509Certificate server = chain[0]; - - // build the short and long chains - shortChain = new ArrayList<X509Certificate>(); - shortChain.add(root); - longChain = new ArrayList<X509Certificate>(); - longChain.add(server); - - // we'll use the root as the pin for the short entry and the server as the pin for the long - shortPin = getFingerprint(root); - longPin = getFingerprint(server); - } - - @Override - public void tearDown() throws Exception { - try { - for (File f : tmpFiles) { - f.delete(); - } - tmpFiles.clear(); - } finally { - super.tearDown(); - } - } - - public void testPinFileMaximumLookup() throws Exception { - - // write a pinfile with two entries, one longer than the other - String shortEntry = "*.google.com=true|" + shortPin; - String longEntry = "*.clients.google.com=true|" + longPin; - - // create the pinFile - String path = writeTmpPinFile(shortEntry + "\n" + longEntry); - CertPinManager pf = new CertPinManager(path, new TrustedCertificateStore()); - - // verify that the shorter chain doesn't work for a name matching the longer - assertTrue("short chain long uri failed", - pf.chainIsNotPinned("android.clients.google.com", shortChain)); - // verify that the longer chain doesn't work for a name matching the shorter - assertTrue("long chain short uri failed", - pf.chainIsNotPinned("android.google.com", longChain)); - // verify that the shorter chain works for the shorter domain - assertTrue("short chain short uri failed", - !pf.chainIsNotPinned("android.google.com", shortChain)); - // and the same for the longer - assertTrue("long chain long uri failed", - !pf.chainIsNotPinned("android.clients.google.com", longChain)); - } - - public void testPinEntryMalformedEntry() throws Exception { - // set up the pinEntry with a bogus entry - String entry = "*.google.com="; - try { - new PinListEntry(entry, new TrustedCertificateStore()); - fail("Accepted an empty pin list entry."); - } catch (PinEntryException expected) { - } - } - - public void testPinEntryNull() throws Exception { - // set up the pinEntry with a bogus entry - String entry = null; - try { - new PinListEntry(entry, new TrustedCertificateStore()); - fail("Accepted a basically wholly bogus entry."); - } catch (NullPointerException expected) { - } - } - - public void testPinEntryEmpty() throws Exception { - // set up the pinEntry with a bogus entry - try { - new PinListEntry("", new TrustedCertificateStore()); - fail("Accepted an empty entry."); - } catch (PinEntryException expected) { - } - } - - public void testPinEntryPinFailure() throws Exception { - // write a pinfile with two entries, one longer than the other - String shortEntry = "*.google.com=true|" + shortPin; - - // set up the pinEntry with a pinlist that doesn't match what we'll give it - PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore()); - assertTrue("Not enforcing!", e.getEnforcing()); - // verify that it doesn't accept - boolean retval = e.chainIsNotPinned(longChain); - assertTrue("Accepted an incorrect pinning, this is very bad", retval); - } - - public void testPinEntryPinSuccess() throws Exception { - // write a pinfile with two entries, one longer than the other - String shortEntry = "*.google.com=true|" + shortPin; - - // set up the pinEntry with a pinlist that matches what we'll give it - PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore()); - assertTrue("Not enforcing!", e.getEnforcing()); - // verify that it accepts - boolean retval = e.chainIsNotPinned(shortChain); - assertTrue("Failed on a correct pinning, this is very bad", !retval); - } - - public void testPinEntryNonEnforcing() throws Exception { - // write a pinfile with two entries, one longer than the other - String shortEntry = "*.google.com=false|" + shortPin; - - // set up the pinEntry with a pinlist that matches what we'll give it - PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore()); - assertFalse("Enforcing!", e.getEnforcing()); - // verify that it accepts - boolean retval = e.chainIsNotPinned(shortChain); - assertTrue("Failed on an unenforced pinning, this is bad-ish", !retval); - } -} diff --git a/crypto/src/test/java/org/conscrypt/ChainStrengthAnalyzerTest.java b/crypto/src/test/java/org/conscrypt/ChainStrengthAnalyzerTest.java deleted file mode 100644 index 7663789..0000000 --- a/crypto/src/test/java/org/conscrypt/ChainStrengthAnalyzerTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2011 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import junit.framework.TestCase; - -public class ChainStrengthAnalyzerTest extends TestCase { - - //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \ - //-newkey rsa:2048 -sha256 -keyout k.pem -out good.pem - private static final String GOOD_PEM = "" + - "-----BEGIN CERTIFICATE-----\n" + - "MIIDYTCCAkmgAwIBAgIJAPFX8KGuEZcgMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV\n" + - "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" + - "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xMjEwMTUyMTQ0MTBaFw0xMzEwMTUyMTQ0MTBa\n" + - "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" + - "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" + - "ADCCAQoCggEBAM44hz3eTINuAIS9OYmg6DkUIj3MItn5dgbcMEdbXrhNpeWY93ho\n" + - "WQFfsqcSSx28NzqKJmnX+cyinzIUfVde/qciP9P7fxRDokRsf34DJ6gXQplz6P2t\n" + - "s4CWjYM+WXJrvEUgLUQ3CBV0CCrtYvG1B9wYsBdAdWkVaMxTvEt7aVxcvJYzp+KU\n" + - "ME7HDg0PVxptvUExIskcqKVmW7i748AgBLhd0r1nFWLuH20d42Aowja0Wi19fWl2\n" + - "SEMErDRjG8jIPUdSoOLPVLGTktEpex51xnAaZ+I7hy6zs55dq8ua/hE/v2cXIkiQ\n" + - "ZXpWyvI/MaKEfeydLnNpa7J3GpH3KW93HQcCAwEAAaNQME4wHQYDVR0OBBYEFA0M\n" + - "RI+3hIPCSpVVArisr3Y3/sheMB8GA1UdIwQYMBaAFA0MRI+3hIPCSpVVArisr3Y3\n" + - "/sheMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFgUNyuy2qaJvgDO\n" + - "plYudTrJR38O3id1B5oKOzgTEgRrfmHHfyloY4fL5gjAGNp7vdlDKSHC2Ebo23/X\n" + - "Wg535MJ2296R855jaTMdkSE0+4ASpdmon1D007H0FhLyojlKVta3pqMAF1zsp0YF\n" + - "Mf3V/rVMDxCOnbSnqAX0+1nW8Qm4Jgrr3AAMafZk6ypq0xuNQn+sUWuIWw3Xv5Jl\n" + - "KehjnuKtMgVYkn2ItRNnUdhm2dQK+Phdb5Yg8WHXN/r9sZQdORg8FQS9TfQJmimB\n" + - "CVYuqA9Dt0JJZPuO/Pd1yAxWP4NpxX1xr3lNQ5jrTO702QA3gOrscluULLzrYR50\n" + - "FoAjeos=\n" + - "-----END CERTIFICATE-----"; - - //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \ - //-newkey rsa:2048 -md5 -keyout k.pem -out md5.pem - private static final String MD5_PEM = "" + - "-----BEGIN CERTIFICATE-----\n" + - "MIIDYTCCAkmgAwIBAgIJAJsffMf2cyx0MA0GCSqGSIb3DQEBBAUAMEcxCzAJBgNV\n" + - "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" + - "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xMjEwMTUyMTQzMzZaFw0xMzEwMTUyMTQzMzZa\n" + - "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" + - "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" + - "ADCCAQoCggEBAOJyiUwgf/VsdbTTdx6dsb742adeBFBY1FpSWCeQW/JVtdMephbK\n" + - "AA00nu8Xq3dNx9bp8AqvzeyHi/RBsZOtb2eAsOXE3RbFy28ehDTHdG34fRQNT6kp\n" + - "RUHw8wrUGovMVqS8j+iW8HfAy3sjArje0ygz2NIETlNQbEOifAJtY+AEfZwZE0/0\n" + - "IMVP4hwTmIgyReJBDmAx31clwsWZSPar9x+WQfeJ3rfy5LBCtf3RUbdgnvynBHFk\n" + - "FjucwoqgOOXviCWxIa0F+ZAmZJBj5+pLN/V92RXOu0c2fR3Mf68J67OJ+K4ueo1N\n" + - "nBhRsulWMmGqIVjYOZQxiNzWYcOVXj3DTRMCAwEAAaNQME4wHQYDVR0OBBYEFJbY\n" + - "TU06RuJaiMBs2vzx5y0MbaQOMB8GA1UdIwQYMBaAFJbYTU06RuJaiMBs2vzx5y0M\n" + - "baQOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAFEky0jLTmKefDVX\n" + - "8O84KoupmQ2qQQBaQF3F5GEuhi0qJRwnmsWkCmsxPP55S67WDFp3JH+LX14UxL4T\n" + - "fbG2CXHt/BF1yU3Z8JBwx3bDmfUnUOAFkO3nmByb11FyZTHMzq4jp03DexWREv4q\n" + - "Ai5+5Xb56VECgCH/hnGqhQeFGhlZUcSXobVhAU+39L6azWELXxk1K4bpVxYFGn1N\n" + - "uZ+dWmb6snPKDzG6J5IIX8QIs6G8H6ptj+QNoU/qTcZEnuzMJxpqMsyq10AA+bY/\n" + - "VAYyXeZm3XZrtqYosDeiUdmcL0jjmyQtyOcAoVUQWj1EJuRjXg4BvI6xxRAIPWYT\n" + - "EDeWHJE=\n" + - "-----END CERTIFICATE-----"; - - //openssl req -x509 -nodes -days 365 -subj '/C=US/ST=Testsota/L=Testville/CN=test.com' \ - //-newkey rsa:512 -sha256 -keyout k.pem -out short.pem - private static final String SHORT_PEM = "" + - "-----BEGIN CERTIFICATE-----\n" + - "MIIB1zCCAYGgAwIBAgIJAOxaz9TreDNIMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV\n" + - "BAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVzdHZpbGxlMREw\n" + - "DwYDVQQDDAh0ZXN0LmNvbTAeFw0xMjEwMTUyMTQzMjNaFw0xMzEwMTUyMTQzMjNa\n" + - "MEcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhUZXN0c290YTESMBAGA1UEBwwJVGVz\n" + - "dHZpbGxlMREwDwYDVQQDDAh0ZXN0LmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC\n" + - "QQCoMgxK9HG0L+hXEht1mKq6ApN3+3lmIEVUcWQKL7EMmn9+L6rVSJyOAGwpTVG7\n" + - "eZ5uulC0Lkm5/bzKFSrCf1jlAgMBAAGjUDBOMB0GA1UdDgQWBBTda66RZsgUvR4e\n" + - "2RSsq65K1xcz0jAfBgNVHSMEGDAWgBTda66RZsgUvR4e2RSsq65K1xcz0jAMBgNV\n" + - "HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAZWYgoNDn6yEzcmWgsYnG3w2BT6fL\n" + - "Npi0+APKWkwxnEJk1kgpdeSTMgaHAphQ8qksHnSgeBAJSs2ZCQMinVPgOg==\n" + - "-----END CERTIFICATE-----"; - - public void testMD5() throws Exception { - assertBad(MD5_PEM, "Weak hash check did not fail as expected"); - } - - public void test512() throws Exception { - assertBad(SHORT_PEM, "Short modulus check did not fail as expected"); - } - - public void testGoodChain() throws Exception { - assertGood(GOOD_PEM); - } - - private static void assertBad(String pem, String msg) throws Exception { - try { - check(createCert(pem)); - fail(msg); - } catch (CertificateException expected) { - } - } - - private static void assertGood(String pem) throws Exception { - check(createCert(pem)); - } - - private static void check(X509Certificate cert) throws Exception { - X509Certificate[] chain = {cert}; - ChainStrengthAnalyzer.check(chain); - } - - private static X509Certificate createCert(String pem) throws Exception { - CertificateFactory cf = CertificateFactory.getInstance("X509"); - InputStream pemInput = new ByteArrayInputStream(pem.getBytes()); - return (X509Certificate) cf.generateCertificate(pemInput); - } -} diff --git a/crypto/src/test/java/org/conscrypt/CipherSuiteTest.java b/crypto/src/test/java/org/conscrypt/CipherSuiteTest.java deleted file mode 100644 index 970ad34..0000000 --- a/crypto/src/test/java/org/conscrypt/CipherSuiteTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2010 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import javax.crypto.Cipher; -import javax.crypto.Mac; -import junit.framework.TestCase; -import libcore.java.security.StandardNames; - -public class CipherSuiteTest extends TestCase { - public void test_getByName() throws Exception { - for (String name : StandardNames.CIPHER_SUITES) { - if (name.equals(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION)) { - assertNull(CipherSuite.getByName(name)); - } else { - test_CipherSuite(name); - } - } - - assertNull(CipherSuite.getByName("bogus")); - try { - CipherSuite.getByName(null); - fail(); - } catch (NullPointerException expected) { - } - } - - private void test_CipherSuite(String name) throws Exception { - CipherSuite cs = CipherSuite.getByName(name); - assertNotNull(name, cs); - assertEquals(name, cs.getName()); - test_CipherSuite(cs); - } - - private void test_CipherSuite(CipherSuite cs) throws Exception { - assertNotNull(cs); - - String name = cs.getName(); - assertNotNull(name); - assertSame(name, cs, CipherSuite.getByName(name)); - assertTrue(name, StandardNames.CIPHER_SUITES.contains(name)); - assertTrue(name, name.startsWith("SSL_") || name.startsWith("TLS_")); - - assertEquals(cs.isAnonymous(), name.contains("_anon_")); - - byte[] bytes = cs.toBytes(); - assertNotNull(name, bytes); - assertEquals(name, 2, bytes.length); - assertTrue(name + bytes[0], bytes[0] == (byte) 0x00 || bytes[0] == (byte) 0xc0); - assertSame(name, cs, CipherSuite.getByCode(bytes[0], bytes[1])); - assertSame(name, cs, CipherSuite.getByCode((byte) 0, bytes[0], bytes[1])); - - assertTrue(name, cs.toString().contains(name)); - - String bulkEncryptionAlgorithm = cs.getBulkEncryptionAlgorithm(); - int blockSize = cs.getBlockSize(); - if (bulkEncryptionAlgorithm == null) { - assertTrue(name, name.contains("_NULL_")); - assertEquals(name, 0, blockSize); - } else { - assertNotNull(name, Cipher.getInstance(cs.getBulkEncryptionAlgorithm())); - assertTrue(name, blockSize == 0 || blockSize == 8 || blockSize == 16); - } - - String hmacName = cs.getHmacName(); - assertNotNull(name, hmacName); - assertNotNull(name, Mac.getInstance(hmacName)); - - String hashName = cs.getHashName(); - assertNotNull(name, hashName); - assertNotNull(name, MessageDigest.getInstance(hashName)); - - int macLength = cs.getMACLength(); - assertTrue(name, macLength == 0 || macLength == 16 || macLength == 20); - - assertTrue(name, - cs.isExportable() == name.contains("_EXPORT_") - || cs.isExportable() == name.contains("_NULL_")); - - String keyType = cs.getServerKeyType(); - assertEquals(name, cs.isAnonymous(), keyType == null); - assertTrue(name, keyType == null || StandardNames.KEY_TYPES.contains(keyType)); - } - - public void test_getByCode() { - // CipherSuite.getByCode is also covered by test_CipherSuite - assertUnknown(CipherSuite.getByCode((byte) 0x12, (byte) 0x34)); - assertUnknown(CipherSuite.getByCode((byte) 0x12, (byte) 0x34, (byte) 0x56)); - assertUnknown(CipherSuite.getByCode((byte) -1, (byte) -1)); - assertUnknown(CipherSuite.getByCode((byte) -1, (byte) -1, (byte) -1)); - } - private void assertUnknown(CipherSuite cs) { - assertNotNull(cs); - assertNotNull(cs.getName().contains("UNKNOWN")); - } - - public void test_getSupported() throws Exception { - CipherSuite[] suites = CipherSuite.getSupported(); - List<String> names = new ArrayList<String>(suites.length); - for (CipherSuite cs : suites) { - test_CipherSuite(cs); - names.add(cs.getName()); - } - assertEquals(Arrays.asList(CipherSuite.getSupportedCipherSuiteNames()), names); - } - - public void test_getSupportedCipherSuiteNames() throws Exception { - String[] names = CipherSuite.getSupportedCipherSuiteNames(); - StandardNames.assertSupportedCipherSuites(StandardNames.CIPHER_SUITES_SSLENGINE, names); - for (String name : names) { - test_CipherSuite(name); - } - } - - public void test_getClientKeyType() throws Exception { - byte b = Byte.MIN_VALUE; - do { - String byteString = Byte.toString(b); - String keyType = CipherSuite.getClientKeyType(b); - switch (b) { - case 1: - assertEquals(byteString, "RSA", keyType); - break; - case 2: - assertEquals(byteString, "DSA", keyType); - break; - case 3: - assertEquals(byteString, "DH_RSA", keyType); - break; - case 4: - assertEquals(byteString, "DH_DSA", keyType); - break; - case 64: - assertEquals(byteString, "EC", keyType); - break; - case 65: - assertEquals(byteString, "EC_RSA", keyType); - break; - case 66: - assertEquals(byteString, "EC_EC", keyType); - break; - default: - assertNull(byteString, keyType); - } - b++; - } while (b != Byte.MIN_VALUE); - } -} diff --git a/crypto/src/test/java/org/conscrypt/ClientSessionContextTest.java b/crypto/src/test/java/org/conscrypt/ClientSessionContextTest.java deleted file mode 100644 index 93037db..0000000 --- a/crypto/src/test/java/org/conscrypt/ClientSessionContextTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Set; -import javax.net.ssl.SSLSession; -import junit.framework.TestCase; -import libcore.javax.net.ssl.FakeSSLSession; - -public final class ClientSessionContextTest extends TestCase { - - public void testSimpleAddition() { - ClientSessionContext context = new ClientSessionContext(); - SSLSession a = new ValidSSLSession("a"); - SSLSession b = new ValidSSLSession("b"); - - context.putSession(a); - assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b }); - - context.putSession(b); - assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[0]); - } - - public void testTrimToSize() { - ClientSessionContext context = new ClientSessionContext(); - ValidSSLSession a = new ValidSSLSession("a"); - ValidSSLSession b = new ValidSSLSession("b"); - ValidSSLSession c = new ValidSSLSession("c"); - ValidSSLSession d = new ValidSSLSession("d"); - - context.putSession(a); - assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b, c, d }); - - context.putSession(b); - assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[] { c, d }); - - context.putSession(c); - assertSessionContextContents(context, new SSLSession[] { a, b, c }, new SSLSession[] { d }); - - context.putSession(d); - assertSessionContextContents(context, new SSLSession[] { a, b, c, d }, new SSLSession[0]); - - context.setSessionCacheSize(2); - assertSessionContextContents(context, new SSLSession[] { c, d }, new SSLSession[] { a, b }); - } - - public void testImplicitRemovalOfOldest() { - ClientSessionContext context = new ClientSessionContext(); - context.setSessionCacheSize(2); - ValidSSLSession a = new ValidSSLSession("a"); - ValidSSLSession b = new ValidSSLSession("b"); - ValidSSLSession c = new ValidSSLSession("c"); - ValidSSLSession d = new ValidSSLSession("d"); - - context.putSession(a); - assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b, c, d }); - - context.putSession(b); - assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[] { c, d }); - - context.putSession(c); - assertSessionContextContents(context, new SSLSession[] { b, c }, new SSLSession[] { a, d }); - - context.putSession(d); - assertSessionContextContents(context, new SSLSession[] { c, d }, new SSLSession[] { a, b }); - } - - private static void assertSessionContextContents(ClientSessionContext context, - SSLSession[] contains, - SSLSession[] exludes) { - assertEquals(contains.length, context.size()); - - for (SSLSession s : contains) { - assertSame(s.getPeerHost(), s, context.getSession(s.getId())); - assertSame(s.getPeerHost(), s, context.getSession(s.getPeerHost(), 443)); - } - for (SSLSession s : exludes) { - assertNull(s.getPeerHost(), context.getSession(s.getId())); - assertNull(s.getPeerHost(), context.getSession(s.getPeerHost(), 443)); - } - - Set<SSLSession> sessions = new HashSet<SSLSession>(); - Enumeration<byte[]> ids = context.getIds(); - while (ids.hasMoreElements()) { - byte[] id = ids.nextElement(); - sessions.add(context.getSession(id)); - } - - Set<SSLSession> expected = new HashSet<SSLSession>(); - for (SSLSession s : sessions) { - expected.add(s); - } - assertEquals(expected, sessions); - } - - static class ValidSSLSession extends FakeSSLSession { - ValidSSLSession(String host) { - super(host); - } - @Override public boolean isValid() { - return true; - } - } -} diff --git a/crypto/src/test/java/org/conscrypt/FileClientSessionCacheTest.java b/crypto/src/test/java/org/conscrypt/FileClientSessionCacheTest.java deleted file mode 100644 index 9d7e2ec..0000000 --- a/crypto/src/test/java/org/conscrypt/FileClientSessionCacheTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2009 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.File; -import java.io.IOException; -import junit.framework.TestCase; -import libcore.javax.net.ssl.FakeSSLSession; - -public class FileClientSessionCacheTest extends TestCase { - - public void testMaxSize() throws IOException, InterruptedException { - String tmpDir = System.getProperty("java.io.tmpdir"); - if (tmpDir == null) { - fail("Please set 'java.io.tmpdir' system property."); - } - File cacheDir = new File(tmpDir - + "/" + FileClientSessionCacheTest.class.getName() + "/cache"); - final SSLClientSessionCache cache - = FileClientSessionCache.usingDirectory(cacheDir); - Thread[] threads = new Thread[10]; - final int iterations = FileClientSessionCache.MAX_SIZE * 10; - for (int i = 0; i < threads.length; i++) { - final int id = i; - threads[i] = new Thread() { - @Override - public void run() { - for (int i = 0; i < iterations; i++) { - cache.putSessionData(new FakeSSLSession(id + "" + i), new byte[10]); - } - } - }; - } - for (Thread thread : threads) { - thread.start(); - } - for (Thread thread : threads) { - thread.join(); - } - assertEquals(FileClientSessionCache.MAX_SIZE, cacheDir.list().length); - } -} diff --git a/crypto/src/test/java/org/conscrypt/MacTest.java b/crypto/src/test/java/org/conscrypt/MacTest.java deleted file mode 100644 index 304ecdb..0000000 --- a/crypto/src/test/java/org/conscrypt/MacTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.Provider; -import java.security.Security; -import java.util.Arrays; - -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import junit.framework.TestCase; - -public class MacTest extends TestCase { - public void test_getInstance_OpenSSL_ENGINE() throws Exception { - final String secret = "-HMAC-test1"; - final byte[] testString = "testing123".getBytes(); - - Provider p = Security.getProvider(OpenSSLProvider.PROVIDER_NAME); - NativeCryptoTest.loadTestEngine(); - OpenSSLEngine engine = OpenSSLEngine.getInstance(NativeCryptoTest.TEST_ENGINE_ID); - - /* - * The "-HMAC-" prefix is a special prefix recognized by - * test_openssl_engine.cpp - */ - SecretKey key1 = engine.getSecretKeyById(secret, "HmacSHA256"); - SecretKey key1dupe = engine.getSecretKeyById(secret, "HmacSHA256"); - - /* Non-ENGINE-based SecretKey */ - SecretKey key2 = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); - - /* The one that is ENGINE-based can't be equal to a non-ENGINE one. */ - assertFalse(key1.equals(key2)); - assertEquals(key1, key1dupe); - assertNull(key1.getFormat()); - assertNull(key1.getEncoded()); - assertEquals("RAW", key2.getFormat()); - assertEquals(Arrays.toString(secret.getBytes()), Arrays.toString(key2.getEncoded())); - - Mac mac1 = Mac.getInstance("HmacSHA256", p); - mac1.init(key1); - mac1.update(testString); - byte[] output1 = mac1.doFinal(); - assertEquals(mac1.getMacLength(), output1.length); - - Mac mac2 = Mac.getInstance("HmacSHA256", p); - mac2.init(key2); - mac2.update(testString); - byte[] output2 = mac2.doFinal(); - - assertEquals(Arrays.toString(output2), Arrays.toString(output1)); - } -} diff --git a/crypto/src/test/java/org/conscrypt/NativeCryptoTest.java b/crypto/src/test/java/org/conscrypt/NativeCryptoTest.java deleted file mode 100644 index 88a00eb..0000000 --- a/crypto/src/test/java/org/conscrypt/NativeCryptoTest.java +++ /dev/null @@ -1,2658 +0,0 @@ -/* - * Copyright (C) 2010 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import dalvik.system.BaseDexClassLoader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileDescriptor; -import java.io.IOException; -import java.math.BigInteger; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketTimeoutException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.KeyStore; -import java.security.KeyStore.PrivateKeyEntry; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.ECPrivateKeySpec; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLProtocolException; -import javax.security.auth.x500.X500Principal; -import junit.framework.TestCase; -import libcore.io.IoUtils; -import libcore.java.security.StandardNames; -import libcore.java.security.TestKeyStore; -import org.conscrypt.NativeCrypto.SSLHandshakeCallbacks; -import static org.conscrypt.NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH; - -public class NativeCryptoTest extends TestCase { - /** Corresponds to the native test library "libjavacoretests.so" */ - public static final String TEST_ENGINE_ID = "javacoretests"; - - private static final long NULL = 0; - private static final FileDescriptor INVALID_FD = new FileDescriptor(); - private static final SSLHandshakeCallbacks DUMMY_CB - = new TestSSLHandshakeCallbacks(null, 0, null); - - private static final long TIMEOUT_SECONDS = 5; - - private static OpenSSLKey SERVER_PRIVATE_KEY; - private static OpenSSLX509Certificate[] SERVER_CERTIFICATES_HOLDER; - private static long[] SERVER_CERTIFICATES; - private static OpenSSLKey CLIENT_PRIVATE_KEY; - private static OpenSSLX509Certificate[] CLIENT_CERTIFICATES_HOLDER; - private static long[] CLIENT_CERTIFICATES; - private static byte[][] CA_PRINCIPALS; - private static OpenSSLKey CHANNEL_ID_PRIVATE_KEY; - private static byte[] CHANNEL_ID; - - @Override - protected void tearDown() throws Exception { - assertEquals(0, NativeCrypto.ERR_peek_last_error()); - } - - private static OpenSSLKey getServerPrivateKey() { - initCerts(); - return SERVER_PRIVATE_KEY; - } - - private static long[] getServerCertificates() { - initCerts(); - return SERVER_CERTIFICATES; - } - - private static OpenSSLKey getClientPrivateKey() { - initCerts(); - return CLIENT_PRIVATE_KEY; - } - - private static long[] getClientCertificates() { - initCerts(); - return CLIENT_CERTIFICATES; - } - - private static byte[][] getCaPrincipals() { - initCerts(); - return CA_PRINCIPALS; - } - - /** - * Lazily create shared test certificates. - */ - private static synchronized void initCerts() { - if (SERVER_PRIVATE_KEY != null) { - return; - } - - try { - PrivateKeyEntry serverPrivateKeyEntry - = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); - SERVER_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(serverPrivateKeyEntry.getPrivateKey()); - SERVER_CERTIFICATES_HOLDER = encodeCertificateList( - serverPrivateKeyEntry.getCertificateChain()); - SERVER_CERTIFICATES = getCertificateReferences(SERVER_CERTIFICATES_HOLDER); - - PrivateKeyEntry clientPrivateKeyEntry - = TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA"); - CLIENT_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(clientPrivateKeyEntry.getPrivateKey()); - CLIENT_CERTIFICATES_HOLDER = encodeCertificateList( - clientPrivateKeyEntry.getCertificateChain()); - CLIENT_CERTIFICATES = getCertificateReferences(CLIENT_CERTIFICATES_HOLDER); - - KeyStore ks = TestKeyStore.getClient().keyStore; - String caCertAlias = ks.aliases().nextElement(); - X509Certificate certificate = (X509Certificate) ks.getCertificate(caCertAlias); - X500Principal principal = certificate.getIssuerX500Principal(); - CA_PRINCIPALS = new byte[][] { principal.getEncoded() }; - initChannelIdKey(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static long[] getCertificateReferences(OpenSSLX509Certificate[] certs) { - final long[] certRefs = new long[certs.length]; - for (int i = 0; i < certs.length; i++) { - certRefs[i] = certs[i].getContext(); - } - return certRefs; - } - - private static OpenSSLX509Certificate[] encodeCertificateList(Certificate[] chain) - throws CertificateEncodingException { - final OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[chain.length]; - for (int i = 0; i < chain.length; i++) { - openSslCerts[i] = OpenSSLX509Certificate.fromCertificate(chain[i]); - } - return openSslCerts; - } - - private static synchronized void initChannelIdKey() throws Exception { - if (CHANNEL_ID_PRIVATE_KEY != null) { - return; - } - - // NIST P-256 aka SECG secp256r1 aka X9.62 prime256v1 - OpenSSLECGroupContext openSslSpec = OpenSSLECGroupContext.getCurveByName("prime256v1"); - BigInteger s = new BigInteger( - "229cdbbf489aea584828a261a23f9ff8b0f66f7ccac98bf2096ab3aee41497c5", 16); - CHANNEL_ID_PRIVATE_KEY = new OpenSSLECPrivateKey( - new ECPrivateKeySpec(s, openSslSpec.getECParameterSpec())).getOpenSSLKey(); - - // Channel ID is the concatenation of the X and Y coordinates of the public key. - CHANNEL_ID = new BigInteger( - "702b07871fd7955c320b26f15e244e47eed60272124c92b9ebecf0b42f90069b" + - "ab53592ebfeb4f167dbf3ce61513afb0e354c479b1c1b69874fa471293494f77", - 16).toByteArray(); - } - - public static void assertEqualSessions(long expected, long actual) { - assertEqualByteArrays(NativeCrypto.SSL_SESSION_session_id(expected), - NativeCrypto.SSL_SESSION_session_id(actual)); - } - public static void assertEqualByteArrays(byte[] expected, byte[] actual) { - assertEquals(Arrays.toString(expected), Arrays.toString(actual)); - } - - public static void assertEqualPrincipals(byte[][] expected, byte[][] actual) { - assertEqualByteArrays(expected, actual); - } - - public static void assertEqualCertificateChains(long[] expected, long[] actual) { - assertEquals(expected.length, actual.length); - for (int i = 0; i < expected.length; i++) { - NativeCrypto.X509_cmp(expected[i], actual[i]); - } - } - - public static void assertEqualByteArrays(byte[][] expected, byte[][] actual) { - assertEquals(Arrays.deepToString(expected), Arrays.deepToString(actual)); - } - - public void test_EVP_PKEY_cmp() throws Exception { - try { - NativeCrypto.EVP_PKEY_cmp(NULL, NULL); - fail("Should throw NullPointerException when arguments are NULL"); - } catch (NullPointerException expected) { - } - - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(512); - - KeyPair kp1 = kpg.generateKeyPair(); - RSAPrivateCrtKey privKey1 = (RSAPrivateCrtKey) kp1.getPrivate(); - - KeyPair kp2 = kpg.generateKeyPair(); - RSAPrivateCrtKey privKey2 = (RSAPrivateCrtKey) kp2.getPrivate(); - - long pkey1 = 0, pkey1_copy = 0, pkey2 = 0; - try { - pkey1 = NativeCrypto.EVP_PKEY_new_RSA(privKey1.getModulus().toByteArray(), - privKey1.getPublicExponent().toByteArray(), - privKey1.getPrivateExponent().toByteArray(), - privKey1.getPrimeP().toByteArray(), - privKey1.getPrimeQ().toByteArray(), - privKey1.getPrimeExponentP().toByteArray(), - privKey1.getPrimeExponentQ().toByteArray(), - privKey1.getCrtCoefficient().toByteArray()); - assertNotSame(NULL, pkey1); - - pkey1_copy = NativeCrypto.EVP_PKEY_new_RSA(privKey1.getModulus().toByteArray(), - privKey1.getPublicExponent().toByteArray(), - privKey1.getPrivateExponent().toByteArray(), - privKey1.getPrimeP().toByteArray(), - privKey1.getPrimeQ().toByteArray(), - privKey1.getPrimeExponentP().toByteArray(), - privKey1.getPrimeExponentQ().toByteArray(), - privKey1.getCrtCoefficient().toByteArray()); - assertNotSame(NULL, pkey1_copy); - - pkey2 = NativeCrypto.EVP_PKEY_new_RSA(privKey2.getModulus().toByteArray(), - privKey2.getPublicExponent().toByteArray(), - privKey2.getPrivateExponent().toByteArray(), - privKey2.getPrimeP().toByteArray(), - privKey2.getPrimeQ().toByteArray(), - privKey2.getPrimeExponentP().toByteArray(), - privKey2.getPrimeExponentQ().toByteArray(), - privKey2.getCrtCoefficient().toByteArray()); - assertNotSame(NULL, pkey2); - - try { - NativeCrypto.EVP_PKEY_cmp(pkey1, NULL); - fail("Should throw NullPointerException when arguments are NULL"); - } catch (NullPointerException expected) { - } - - try { - NativeCrypto.EVP_PKEY_cmp(NULL, pkey1); - fail("Should throw NullPointerException when arguments are NULL"); - } catch (NullPointerException expected) { - } - - assertEquals("Same keys should be the equal", 1, - NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1)); - - assertEquals("Same keys should be the equal", 1, - NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1_copy)); - - assertEquals("Different keys should not be equal", 0, - NativeCrypto.EVP_PKEY_cmp(pkey1, pkey2)); - } finally { - if (pkey1 != 0) { - NativeCrypto.EVP_PKEY_free(pkey1); - } - if (pkey1_copy != 0) { - NativeCrypto.EVP_PKEY_free(pkey1_copy); - } - if (pkey2 != 0) { - NativeCrypto.EVP_PKEY_free(pkey2); - } - } - } - - public void test_SSL_CTX_new() throws Exception { - long c = NativeCrypto.SSL_CTX_new(); - assertTrue(c != NULL); - long c2 = NativeCrypto.SSL_CTX_new(); - assertTrue(c != c2); - NativeCrypto.SSL_CTX_free(c); - NativeCrypto.SSL_CTX_free(c2); - } - - public void test_SSL_CTX_free() throws Exception { - try { - NativeCrypto.SSL_CTX_free(NULL); - fail(); - } catch (NullPointerException expected) { - } - - NativeCrypto.SSL_CTX_free(NativeCrypto.SSL_CTX_new()); - } - - public void test_SSL_CTX_set_session_id_context() throws Exception { - byte[] empty = new byte[0]; - try { - NativeCrypto.SSL_CTX_set_session_id_context(NULL, empty); - fail(); - } catch (NullPointerException expected) { - } - long c = NativeCrypto.SSL_CTX_new(); - try { - NativeCrypto.SSL_CTX_set_session_id_context(c, null); - fail(); - } catch (NullPointerException expected) { - } - NativeCrypto.SSL_CTX_set_session_id_context(c, empty); - NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[32]); - try { - NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[33]); - } catch (IllegalArgumentException expected) { - } - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_new() throws Exception { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - assertTrue(s != NULL); - assertTrue((NativeCrypto.SSL_get_options(s) & 0x01000000L) != 0); // SSL_OP_NO_SSLv2 - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1) == 0); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1_1) == 0); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1_2) == 0); - - long s2 = NativeCrypto.SSL_new(c); - assertTrue(s != s2); - NativeCrypto.SSL_free(s2); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_use_certificate() throws Exception { - try { - NativeCrypto.SSL_use_certificate(NULL, null); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - try { - NativeCrypto.SSL_use_certificate(s, null); - fail(); - } catch (NullPointerException expected) { - } - - NativeCrypto.SSL_use_certificate(s, getServerCertificates()); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_use_PrivateKey_for_tls_channel_id() throws Exception { - initChannelIdKey(); - - try { - NativeCrypto.SSL_set1_tls_channel_id(NULL, NULL); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - try { - NativeCrypto.SSL_set1_tls_channel_id(s, NULL); - fail(); - } catch (NullPointerException expected) { - } - - // Use the key natively. This works because the initChannelIdKey method ensures that the - // key is backed by OpenSSL. - NativeCrypto.SSL_set1_tls_channel_id(s, CHANNEL_ID_PRIVATE_KEY.getPkeyContext()); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_use_PrivateKey() throws Exception { - try { - NativeCrypto.SSL_use_PrivateKey(NULL, NULL); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - try { - NativeCrypto.SSL_use_PrivateKey(s, NULL); - fail(); - } catch (NullPointerException expected) { - } - - NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getPkeyContext()); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_check_private_key_null() throws Exception { - try { - NativeCrypto.SSL_check_private_key(NULL); - fail(); - } catch (NullPointerException expected) { - } - } - - public void test_SSL_check_private_key_no_key_no_cert() throws Exception { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - // neither private or certificate set - try { - NativeCrypto.SSL_check_private_key(s); - fail(); - } catch (SSLException expected) { - } - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_check_private_key_cert_then_key() throws Exception { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - // first certificate, then private - NativeCrypto.SSL_use_certificate(s, getServerCertificates()); - - try { - NativeCrypto.SSL_check_private_key(s); - fail(); - } catch (SSLException expected) { - } - - NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getPkeyContext()); - NativeCrypto.SSL_check_private_key(s); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - public void test_SSL_check_private_key_key_then_cert() throws Exception { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - // first private, then certificate - NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getPkeyContext()); - - try { - NativeCrypto.SSL_check_private_key(s); - fail(); - } catch (SSLException expected) { - } - - NativeCrypto.SSL_use_certificate(s, getServerCertificates()); - NativeCrypto.SSL_check_private_key(s); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_get_mode() throws Exception { - try { - NativeCrypto.SSL_get_mode(NULL); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - assertTrue(NativeCrypto.SSL_get_mode(s) != 0); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_set_mode_and_clear_mode() throws Exception { - try { - NativeCrypto.SSL_set_mode(NULL, 0); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - // check SSL_MODE_HANDSHAKE_CUTTHROUGH off by default - assertEquals(0, NativeCrypto.SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH); - // set SSL_MODE_HANDSHAKE_CUTTHROUGH on - NativeCrypto.SSL_set_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH); - assertTrue((NativeCrypto.SSL_get_mode(s) - & SSL_MODE_HANDSHAKE_CUTTHROUGH) != 0); - // clear SSL_MODE_HANDSHAKE_CUTTHROUGH off - NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH); - assertTrue((NativeCrypto.SSL_get_mode(s) - & SSL_MODE_HANDSHAKE_CUTTHROUGH) == 0); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_get_options() throws Exception { - try { - NativeCrypto.SSL_get_options(NULL); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - assertTrue(NativeCrypto.SSL_get_options(s) != 0); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_set_options() throws Exception { - try { - NativeCrypto.SSL_set_options(NULL, 0); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); - NativeCrypto.SSL_set_options(s, NativeCrypto.SSL_OP_NO_SSLv3); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) != 0); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_clear_options() throws Exception { - try { - NativeCrypto.SSL_clear_options(NULL, 0); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); - NativeCrypto.SSL_set_options(s, NativeCrypto.SSL_OP_NO_SSLv3); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) != 0); - NativeCrypto.SSL_clear_options(s, NativeCrypto.SSL_OP_NO_SSLv3); - assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_set_cipher_lists() throws Exception { - try { - NativeCrypto.SSL_set_cipher_lists(NULL, null); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - try { - NativeCrypto.SSL_set_cipher_lists(s, null); - fail(); - } catch (NullPointerException expected) { - } - - NativeCrypto.SSL_set_cipher_lists(s, new String[] {}); - - try { - NativeCrypto.SSL_set_cipher_lists(s, new String[] { null }); - fail(); - } catch (NullPointerException expected) { - } - - // see OpenSSL ciphers man page - String[] illegals = new String[] { - // empty - "", - // never standardized - "EXP1024-DES-CBC-SHA", "EXP1024-RC4-SHA", "DHE-DSS-RC4-SHA", - // IDEA - "IDEA-CBC-SHA", "IDEA-CBC-MD5" - }; - - for (String illegal : illegals) { - try { - NativeCrypto.SSL_set_cipher_lists(s, new String[] { illegal }); - fail(illegal); - } catch (IllegalArgumentException expected) { - } - } - - List<String> ciphers - = new ArrayList<String>(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.keySet()); - NativeCrypto.SSL_set_cipher_lists(s, ciphers.toArray(new String[ciphers.size()])); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_set_verify() throws Exception { - try { - NativeCrypto.SSL_set_verify(NULL, 0); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_NONE); - NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER); - NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT); - NativeCrypto.SSL_set_verify(s, (NativeCrypto.SSL_VERIFY_PEER - | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT)); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - private static final boolean DEBUG = false; - - public static class Hooks { - private OpenSSLKey channelIdPrivateKey; - - public long getContext() throws SSLException { - return NativeCrypto.SSL_CTX_new(); - } - public long beforeHandshake(long context) throws SSLException { - long s = NativeCrypto.SSL_new(context); - // without this SSL_set_cipher_lists call the tests were - // negotiating DHE-RSA-AES256-SHA by default which had - // very slow ephemeral RSA key generation - NativeCrypto.SSL_set_cipher_lists(s, new String[] { "RC4-MD5" }); - - if (channelIdPrivateKey != null) { - NativeCrypto.SSL_set1_tls_channel_id(s, channelIdPrivateKey.getPkeyContext()); - } - return s; - } - public void clientCertificateRequested(long s) {} - public void afterHandshake(long session, long ssl, long context, - Socket socket, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - if (session != NULL) { - NativeCrypto.SSL_SESSION_free(session); - } - if (ssl != NULL) { - try { - NativeCrypto.SSL_shutdown(ssl, fd, callback); - } catch (IOException e) { - } - NativeCrypto.SSL_free(ssl); - } - if (context != NULL) { - NativeCrypto.SSL_CTX_free(context); - } - if (socket != null) { - socket.close(); - } - } - } - - public static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks { - private final Socket socket; - private final long sslNativePointer; - private final Hooks hooks; - - public TestSSLHandshakeCallbacks(Socket socket, - long sslNativePointer, - Hooks hooks) { - this.socket = socket; - this.sslNativePointer = sslNativePointer; - this.hooks = hooks; - } - - public long[] certificateChainRefs; - public String authMethod; - public boolean verifyCertificateChainCalled; - - public void verifyCertificateChain(long[] certChainRefs, String authMethod) - throws CertificateException { - if (DEBUG) { - System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) - + " verifyCertificateChain" - + " asn1DerEncodedCertificateChain=" - + Arrays.toString(certChainRefs) - + " authMethod=" + authMethod); - } - this.certificateChainRefs = certChainRefs; - this.authMethod = authMethod; - this.verifyCertificateChainCalled = true; - } - - public byte[] keyTypes; - public byte[][] asn1DerEncodedX500Principals; - public boolean clientCertificateRequestedCalled; - public void clientCertificateRequested(byte[] keyTypes, - byte[][] asn1DerEncodedX500Principals) { - if (DEBUG) { - System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) - + " clientCertificateRequested" - + " keyTypes=" + keyTypes - + " asn1DerEncodedX500Principals=" - + asn1DerEncodedX500Principals); - } - this.keyTypes = keyTypes; - this.asn1DerEncodedX500Principals = asn1DerEncodedX500Principals; - this.clientCertificateRequestedCalled = true; - if (hooks != null ) { - hooks.clientCertificateRequested(sslNativePointer); - } - } - - public boolean handshakeCompletedCalled; - public void handshakeCompleted() { - if (DEBUG) { - System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) - + " handshakeCompleted"); - } - this.handshakeCompletedCalled = true; - } - - public Socket getSocket() { - return socket; - } - } - - public static class ServerHooks extends Hooks { - private final OpenSSLKey privateKey; - private final long[] certificates; - private boolean channelIdEnabled; - private byte[] channelIdAfterHandshake; - private Throwable channelIdAfterHandshakeException; - - public ServerHooks(OpenSSLKey privateKey, long[] certificates) { - this.privateKey = privateKey; - this.certificates = certificates; - } - - @Override - public long beforeHandshake(long c) throws SSLException { - long s = super.beforeHandshake(c); - if (privateKey != null) { - NativeCrypto.SSL_use_PrivateKey(s, privateKey.getPkeyContext()); - } - if (certificates != null) { - NativeCrypto.SSL_use_certificate(s, certificates); - } - if (channelIdEnabled) { - NativeCrypto.SSL_enable_tls_channel_id(s); - } - return s; - } - - @Override - public void afterHandshake(long session, long ssl, long context, - Socket socket, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - if (channelIdEnabled) { - try { - channelIdAfterHandshake = NativeCrypto.SSL_get_tls_channel_id(ssl); - } catch (Exception e) { - channelIdAfterHandshakeException = e; - } - } - super.afterHandshake(session, ssl, context, socket, fd, callback); - } - - public void clientCertificateRequested(long s) { - fail("Server asked for client certificates"); - } - } - - public static Future<TestSSLHandshakeCallbacks> handshake(final ServerSocket listener, - final int timeout, final boolean client, final Hooks hooks, final byte[] npnProtocols, - final byte[] alpnProtocols) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Future<TestSSLHandshakeCallbacks> future = executor.submit( - new Callable<TestSSLHandshakeCallbacks>() { - @Override public TestSSLHandshakeCallbacks call() throws Exception { - Socket socket = (client - ? new Socket(listener.getInetAddress(), - listener.getLocalPort()) - : listener.accept()); - if (timeout == -1) { - return new TestSSLHandshakeCallbacks(socket, 0, null); - } - FileDescriptor fd = socket.getFileDescriptor$(); - long c = hooks.getContext(); - long s = hooks.beforeHandshake(c); - TestSSLHandshakeCallbacks callback - = new TestSSLHandshakeCallbacks(socket, s, hooks); - if (DEBUG) { - System.out.println("ssl=0x" + Long.toString(s, 16) - + " handshake" - + " context=0x" + Long.toString(c, 16) - + " socket=" + socket - + " fd=" + fd - + " timeout=" + timeout - + " client=" + client); - } - long session = NULL; - try { - session = NativeCrypto.SSL_do_handshake(s, fd, callback, timeout, client, - npnProtocols, alpnProtocols); - if (DEBUG) { - System.out.println("ssl=0x" + Long.toString(s, 16) - + " handshake" - + " session=0x" + Long.toString(session, 16)); - } - } finally { - // Ensure afterHandshake is called to free resources - hooks.afterHandshake(session, s, c, socket, fd, callback); - } - return callback; - } - }); - executor.shutdown(); - return future; - } - - public void test_SSL_do_handshake_NULL_SSL() throws Exception { - try { - NativeCrypto.SSL_do_handshake(NULL, null, null, 0, false, null, null); - fail(); - } catch (NullPointerException expected) { - } - } - - public void test_SSL_do_handshake_null_args() throws Exception { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - try { - NativeCrypto.SSL_do_handshake(s, null, null, 0, true, null, null); - fail(); - } catch (NullPointerException expected) { - } - - try { - NativeCrypto.SSL_do_handshake(s, INVALID_FD, null, 0, true, null, null); - fail(); - } catch (NullPointerException expected) { - } - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - public void test_SSL_do_handshake_normal() throws Exception { - // normal client and server case - final ServerSocket listener = new ServerSocket(0); - Hooks cHooks = new Hooks(); - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - assertTrue(clientCallback.verifyCertificateChainCalled); - assertEqualCertificateChains(getServerCertificates(), - clientCallback.certificateChainRefs); - assertEquals("RSA", clientCallback.authMethod); - assertFalse(serverCallback.verifyCertificateChainCalled); - assertFalse(clientCallback.clientCertificateRequestedCalled); - assertFalse(serverCallback.clientCertificateRequestedCalled); - assertTrue(clientCallback.handshakeCompletedCalled); - assertTrue(serverCallback.handshakeCompletedCalled); - } - - public void test_SSL_do_handshake_optional_client_certificate() throws Exception { - // optional client certificate case - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public void clientCertificateRequested(long s) { - super.clientCertificateRequested(s); - NativeCrypto.SSL_use_PrivateKey(s, getClientPrivateKey().getPkeyContext()); - NativeCrypto.SSL_use_certificate(s, getClientCertificates()); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public long beforeHandshake(long c) throws SSLException { - long s = super.beforeHandshake(c); - NativeCrypto.SSL_set_client_CA_list(s, getCaPrincipals()); - NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER); - return s; - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - assertTrue(clientCallback.verifyCertificateChainCalled); - assertEqualCertificateChains(getServerCertificates(), - clientCallback.certificateChainRefs); - assertEquals("RSA", clientCallback.authMethod); - assertTrue(serverCallback.verifyCertificateChainCalled); - assertEqualCertificateChains(getClientCertificates(), - serverCallback.certificateChainRefs); - assertEquals("RSA", serverCallback.authMethod); - - assertTrue(clientCallback.clientCertificateRequestedCalled); - assertNotNull(clientCallback.keyTypes); - // this depends on the SSL_set_cipher_lists call in beforeHandshake - // the three returned are the non-ephemeral cases. - assertEquals(3, clientCallback.keyTypes.length); - assertEquals("RSA", CipherSuite.getClientKeyType(clientCallback.keyTypes[0])); - assertEquals("DSA", CipherSuite.getClientKeyType(clientCallback.keyTypes[1])); - assertEquals("EC", CipherSuite.getClientKeyType(clientCallback.keyTypes[2])); - assertEqualPrincipals(getCaPrincipals(), - clientCallback.asn1DerEncodedX500Principals); - assertFalse(serverCallback.clientCertificateRequestedCalled); - - assertTrue(clientCallback.handshakeCompletedCalled); - assertTrue(serverCallback.handshakeCompletedCalled); - } - - public void test_SSL_do_handshake_missing_required_certificate() throws Exception { - // required client certificate negative case - final ServerSocket listener = new ServerSocket(0); - try { - Hooks cHooks = new Hooks(); - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public long beforeHandshake(long c) throws SSLException { - long s = super.beforeHandshake(c); - NativeCrypto.SSL_set_client_CA_list(s, getCaPrincipals()); - NativeCrypto.SSL_set_verify(s, - NativeCrypto.SSL_VERIFY_PEER - | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT); - return s; - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, - null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, - null); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - fail(); - } catch (ExecutionException expected) { - assertEquals(SSLProtocolException.class, expected.getCause().getClass()); - } - } - - /** - * Usually if a RuntimeException is thrown by the - * clientCertificateRequestedCalled callback, the caller sees it - * during the call to NativeCrypto_SSL_do_handshake. However, IIS - * does not request client certs until after the initial - * handshake. It does an SSL renegotiation, which means we need to - * be able to deliver the callback's exception in cases like - * SSL_read, SSL_write, and SSL_shutdown. - */ - public void test_SSL_do_handshake_clientCertificateRequested_throws_after_renegotiate() - throws Exception { - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public long beforeHandshake(long context) throws SSLException { - long s = super.beforeHandshake(context); - NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH); - return s; - } - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0); - fail(); - super.afterHandshake(session, s, c, sock, fd, callback); - } - @Override - public void clientCertificateRequested(long s) { - super.clientCertificateRequested(s); - throw new RuntimeException("expected"); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - try { - NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER); - NativeCrypto.SSL_set_options( - s, NativeCrypto.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - NativeCrypto.SSL_renegotiate(s); - NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1, - (int) ((TIMEOUT_SECONDS * 1000) / 2)); - } catch (IOException expected) { - } finally { - super.afterHandshake(session, s, c, sock, fd, callback); - } - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - try { - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (ExecutionException e) { - if (!"expected".equals(e.getCause().getMessage())) { - throw e; - } - } - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_do_handshake_client_timeout() throws Exception { - // client timeout - final ServerSocket listener = new ServerSocket(0); - Socket serverSocket = null; - try { - Hooks cHooks = new Hooks(); - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 1, true, cHooks, null, - null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, -1, false, sHooks, null, - null); - serverSocket = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket(); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - fail(); - } catch (ExecutionException expected) { - if (SocketTimeoutException.class != expected.getCause().getClass()) { - expected.printStackTrace(); - } - assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); - } finally { - // Manually close peer socket when testing timeout - IoUtils.closeQuietly(serverSocket); - } - } - - public void test_SSL_do_handshake_server_timeout() throws Exception { - // server timeout - final ServerSocket listener = new ServerSocket(0); - Socket clientSocket = null; - try { - Hooks cHooks = new Hooks(); - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, -1, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 1, false, sHooks, null, null); - clientSocket = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket(); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - fail(); - } catch (ExecutionException expected) { - assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); - } finally { - // Manually close peer socket when testing timeout - IoUtils.closeQuietly(clientSocket); - } - } - - public void test_SSL_do_handshake_with_channel_id_normal() throws Exception { - initChannelIdKey(); - - // Normal handshake with TLS Channel ID. - final ServerSocket listener = new ServerSocket(0); - Hooks cHooks = new Hooks(); - cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY; - ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - sHooks.channelIdEnabled = true; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - assertTrue(clientCallback.verifyCertificateChainCalled); - assertEqualCertificateChains(getServerCertificates(), - clientCallback.certificateChainRefs); - assertEquals("RSA", clientCallback.authMethod); - assertFalse(serverCallback.verifyCertificateChainCalled); - assertFalse(clientCallback.clientCertificateRequestedCalled); - assertFalse(serverCallback.clientCertificateRequestedCalled); - assertTrue(clientCallback.handshakeCompletedCalled); - assertTrue(serverCallback.handshakeCompletedCalled); - assertNull(sHooks.channelIdAfterHandshakeException); - assertEqualByteArrays(CHANNEL_ID, sHooks.channelIdAfterHandshake); - } - - public void test_SSL_do_handshake_with_channel_id_not_supported_by_server() throws Exception { - initChannelIdKey(); - - // Client tries to use TLS Channel ID but the server does not enable/offer the extension. - final ServerSocket listener = new ServerSocket(0); - Hooks cHooks = new Hooks(); - cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY; - ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - sHooks.channelIdEnabled = false; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - assertTrue(clientCallback.verifyCertificateChainCalled); - assertEqualCertificateChains(getServerCertificates(), - clientCallback.certificateChainRefs); - assertEquals("RSA", clientCallback.authMethod); - assertFalse(serverCallback.verifyCertificateChainCalled); - assertFalse(clientCallback.clientCertificateRequestedCalled); - assertFalse(serverCallback.clientCertificateRequestedCalled); - assertTrue(clientCallback.handshakeCompletedCalled); - assertTrue(serverCallback.handshakeCompletedCalled); - assertNull(sHooks.channelIdAfterHandshakeException); - assertNull(sHooks.channelIdAfterHandshake); - } - - public void test_SSL_do_handshake_with_channel_id_not_enabled_by_client() throws Exception { - initChannelIdKey(); - - // Client does not use TLS Channel ID when the server has the extension enabled/offered. - final ServerSocket listener = new ServerSocket(0); - Hooks cHooks = new Hooks(); - cHooks.channelIdPrivateKey = null; - ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - sHooks.channelIdEnabled = true; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - assertTrue(clientCallback.verifyCertificateChainCalled); - assertEqualCertificateChains(getServerCertificates(), - clientCallback.certificateChainRefs); - assertEquals("RSA", clientCallback.authMethod); - assertFalse(serverCallback.verifyCertificateChainCalled); - assertFalse(clientCallback.clientCertificateRequestedCalled); - assertFalse(serverCallback.clientCertificateRequestedCalled); - assertTrue(clientCallback.handshakeCompletedCalled); - assertTrue(serverCallback.handshakeCompletedCalled); - assertNull(sHooks.channelIdAfterHandshakeException); - assertNull(sHooks.channelIdAfterHandshake); - } - - public void test_SSL_set_session() throws Exception { - try { - NativeCrypto.SSL_set_session(NULL, NULL); - fail(); - } catch (NullPointerException expected) { - } - - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - NativeCrypto.SSL_set_session(s, NULL); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - { - final long clientContext = NativeCrypto.SSL_CTX_new(); - final long serverContext = NativeCrypto.SSL_CTX_new(); - final ServerSocket listener = new ServerSocket(0); - final long[] clientSession = new long[] { NULL }; - final long[] serverSession = new long[] { NULL }; - { - Hooks cHooks = new Hooks() { - @Override - public long getContext() throws SSLException { - return clientContext; - } - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - super.afterHandshake(NULL, s, NULL, sock, fd, callback); - clientSession[0] = session; - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public long getContext() throws SSLException { - return serverContext; - } - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - super.afterHandshake(NULL, s, NULL, sock, fd, callback); - serverSession[0] = session; - } - }; - Future<TestSSLHandshakeCallbacks> client - = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server - = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - assertEqualSessions(clientSession[0], serverSession[0]); - { - Hooks cHooks = new Hooks() { - @Override - public long getContext() throws SSLException { - return clientContext; - } - @Override - public long beforeHandshake(long c) throws SSLException { - long s = NativeCrypto.SSL_new(clientContext); - NativeCrypto.SSL_set_session(s, clientSession[0]); - return s; - } - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - assertEqualSessions(clientSession[0], session); - super.afterHandshake(NULL, s, NULL, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public long getContext() throws SSLException { - return serverContext; - } - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - assertEqualSessions(serverSession[0], session); - super.afterHandshake(NULL, s, NULL, sock, fd, callback); - } - }; - Future<TestSSLHandshakeCallbacks> client - = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server - = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - NativeCrypto.SSL_SESSION_free(clientSession[0]); - NativeCrypto.SSL_SESSION_free(serverSession[0]); - NativeCrypto.SSL_CTX_free(serverContext); - NativeCrypto.SSL_CTX_free(clientContext); - } - } - - public void test_SSL_set_session_creation_enabled() throws Exception { - try { - NativeCrypto.SSL_set_session_creation_enabled(NULL, false); - fail(); - } catch (NullPointerException expected) { - } - - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - NativeCrypto.SSL_set_session_creation_enabled(s, false); - NativeCrypto.SSL_set_session_creation_enabled(s, true); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - final ServerSocket listener = new ServerSocket(0); - - // negative test case for SSL_set_session_creation_enabled(false) on client - try { - Hooks cHooks = new Hooks() { - @Override - public long beforeHandshake(long c) throws SSLException { - long s = super.beforeHandshake(c); - NativeCrypto.SSL_set_session_creation_enabled(s, false); - return s; - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, - null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, - null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - fail(); - } catch (ExecutionException expected) { - assertEquals(SSLProtocolException.class, expected.getCause().getClass()); - } - - // negative test case for SSL_set_session_creation_enabled(false) on server - try { - Hooks cHooks = new Hooks(); - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public long beforeHandshake(long c) throws SSLException { - long s = super.beforeHandshake(c); - NativeCrypto.SSL_set_session_creation_enabled(s, false); - return s; - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, - null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, - null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - fail(); - } catch (ExecutionException expected) { - assertEquals(SSLProtocolException.class, expected.getCause().getClass()); - } - } - - public void test_SSL_set_tlsext_host_name() throws Exception { - // NULL SSL - try { - NativeCrypto.SSL_set_tlsext_host_name(NULL, null); - fail(); - } catch (NullPointerException expected) { - } - - final String hostname = "www.android.com"; - - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - - // null hostname - try { - NativeCrypto.SSL_set_tlsext_host_name(s, null); - fail(); - } catch (NullPointerException expected) { - } - - // too long hostname - try { - char[] longHostname = new char[256]; - Arrays.fill(longHostname, 'w'); - NativeCrypto.SSL_set_tlsext_host_name(s, new String(longHostname)); - fail(); - } catch (SSLException expected) { - } - - assertNull(NativeCrypto.SSL_get_servername(s)); - NativeCrypto.SSL_set_tlsext_host_name(s, new String(hostname)); - assertEquals(hostname, NativeCrypto.SSL_get_servername(s)); - - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - final ServerSocket listener = new ServerSocket(0); - - // normal - Hooks cHooks = new Hooks() { - @Override - public long beforeHandshake(long c) throws SSLException { - long s = super.beforeHandshake(c); - NativeCrypto.SSL_set_tlsext_host_name(s, hostname); - return s; - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - assertEquals(hostname, NativeCrypto.SSL_get_servername(s)); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_NpnNegotiateSuccess() throws Exception { - final byte[] clientNpnProtocols = new byte[] { - 8, 'h', 't', 't', 'p', '/', '1', '.', '1', - 3, 'f', 'o', 'o', - 6, 's', 'p', 'd', 'y', '/', '2', - }; - final byte[] serverNpnProtocols = new byte[] { - 6, 's', 'p', 'd', 'y', '/', '2', - 3, 'f', 'o', 'o', - 3, 'b', 'a', 'r', - }; - - Hooks cHooks = new Hooks() { - @Override public long beforeHandshake(long context) throws SSLException { - NativeCrypto.SSL_CTX_enable_npn(context); - return super.beforeHandshake(context); - } - @Override public void afterHandshake(long session, long ssl, long context, Socket socket, - FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { - byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl); - assertEquals("spdy/2", new String(negotiated)); - assertTrue("NPN should enable cutthrough on the client", - 0 != (NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH)); - super.afterHandshake(session, ssl, context, socket, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override public long beforeHandshake(long context) throws SSLException { - NativeCrypto.SSL_CTX_enable_npn(context); - return super.beforeHandshake(context); - } - @Override public void afterHandshake(long session, long ssl, long c, Socket sock, - FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { - byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl); - assertEquals("spdy/2", new String(negotiated)); - assertEquals("NPN should not enable cutthrough on the server", - 0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH); - super.afterHandshake(session, ssl, c, sock, fd, callback); - } - }; - - ServerSocket listener = new ServerSocket(0); - Future<TestSSLHandshakeCallbacks> client - = handshake(listener, 0, true, cHooks, clientNpnProtocols, null); - Future<TestSSLHandshakeCallbacks> server - = handshake(listener, 0, false, sHooks, serverNpnProtocols, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_AlpnNegotiateSuccess() throws Exception { - final byte[] clientAlpnProtocols = new byte[] { - 8, 'h', 't', 't', 'p', '/', '1', '.', '1', - 3, 'f', 'o', 'o', - 6, 's', 'p', 'd', 'y', '/', '2', - }; - final byte[] serverAlpnProtocols = new byte[] { - 6, 's', 'p', 'd', 'y', '/', '2', - 3, 'f', 'o', 'o', - 3, 'b', 'a', 'r', - }; - - Hooks cHooks = new Hooks() { - @Override public long beforeHandshake(long context) throws SSLException { - NativeCrypto.SSL_CTX_set_alpn_protos(context, clientAlpnProtocols); - return super.beforeHandshake(context); - } - @Override public void afterHandshake(long session, long ssl, long context, Socket socket, - FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { - byte[] negotiated = NativeCrypto.SSL_get0_alpn_selected(ssl); - assertEquals("spdy/2", new String(negotiated)); - /* - * There is no callback on the client, so we can't enable - * cut-through - */ - assertEquals("ALPN should not enable cutthrough on the client", 0, - NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH); - super.afterHandshake(session, ssl, context, socket, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override public void afterHandshake(long session, long ssl, long c, Socket sock, - FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { - byte[] negotiated = NativeCrypto.SSL_get0_alpn_selected(ssl); - assertEquals("spdy/2", new String(negotiated)); - assertEquals("ALPN should not enable cutthrough on the server", - 0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH); - super.afterHandshake(session, ssl, c, sock, fd, callback); - } - }; - - ServerSocket listener = new ServerSocket(0); - Future<TestSSLHandshakeCallbacks> client - = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server - = handshake(listener, 0, false, sHooks, null, serverAlpnProtocols); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_get_servername_null() throws Exception { - // NULL SSL - try { - NativeCrypto.SSL_get_servername(NULL); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - assertNull(NativeCrypto.SSL_get_servername(s)); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - - // additional positive testing by test_SSL_set_tlsext_host_name - } - - public void test_SSL_renegotiate() throws Exception { - try { - NativeCrypto.SSL_renegotiate(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - byte[] buffer = new byte[1]; - NativeCrypto.SSL_read(s, fd, callback, buffer, 0, 1, 0); - assertEquals(42, buffer[0]); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - NativeCrypto.SSL_renegotiate(s); - NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1, 0); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_get_certificate() throws Exception { - try { - NativeCrypto.SSL_get_certificate(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - assertNull(NativeCrypto.SSL_get_certificate(s)); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - assertEqualCertificateChains( - getServerCertificates(), - NativeCrypto.SSL_get_certificate(s)); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_get_peer_cert_chain() throws Exception { - try { - NativeCrypto.SSL_get_peer_cert_chain(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - long[] cc = NativeCrypto.SSL_get_peer_cert_chain(s); - assertEqualCertificateChains(getServerCertificates(), cc); - for (long ref : cc) { - NativeCrypto.X509_free(ref); - } - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - final byte[] BYTES = new byte[] { 2, -3, 5, 127, 0, -128 }; - - public void test_SSL_read() throws Exception { - - // NULL ssl - try { - NativeCrypto.SSL_read(NULL, null, null, null, 0, 0, 0); - fail(); - } catch (NullPointerException expected) { - } - - // null FileDescriptor - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_read(s, null, DUMMY_CB, null, 0, 0, 0); - fail(); - } catch (NullPointerException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - // null SSLHandshakeCallbacks - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_read(s, INVALID_FD, null, null, 0, 0, 0); - fail(); - } catch (NullPointerException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - // null byte array - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, null, 0, 0, 0); - fail(); - } catch (NullPointerException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - // handshaking not yet performed - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0); - fail(); - } catch (SSLException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - final ServerSocket listener = new ServerSocket(0); - - // normal case - { - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - byte[] in = new byte[256]; - assertEquals(BYTES.length, - NativeCrypto.SSL_read(s, - fd, - callback, - in, - 0, - BYTES.length, - 0)); - for (int i = 0; i < BYTES.length; i++) { - assertEquals(BYTES[i], in[i]); - } - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - NativeCrypto.SSL_write(s, fd, callback, BYTES, 0, BYTES.length, 0); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, - null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, - null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - // timeout case - try { - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 1); - fail(); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, - null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, - null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - fail(); - } catch (ExecutionException expected) { - assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); - } - } - - public void test_SSL_write() throws Exception { - try { - NativeCrypto.SSL_write(NULL, null, null, null, 0, 0, 0); - fail(); - } catch (NullPointerException expected) { - } - - // null FileDescriptor - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1, 0); - fail(); - } catch (NullPointerException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - // null SSLHandshakeCallbacks - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1, 0); - fail(); - } catch (NullPointerException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - // null byte array - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1, 0); - fail(); - } catch (NullPointerException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - // handshaking not yet performed - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0); - fail(); - } catch (SSLException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - // positively tested by test_SSL_read - } - - public void test_SSL_interrupt() throws Exception { - // SSL_interrupt is a rare case that tolerates a null SSL argument - NativeCrypto.SSL_interrupt(NULL); - - // also works without handshaking - { - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - NativeCrypto.SSL_interrupt(s); - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - } - - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { - @Override - public void afterHandshake(long session, final long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - new Thread() { - public void run() { - try { - Thread.sleep(1*1000); - NativeCrypto.SSL_interrupt(s); - } catch (Exception e) { - } - } - }.start(); - assertEquals(-1, NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0)); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_shutdown() throws Exception { - - // null FileDescriptor - try { - NativeCrypto.SSL_shutdown(NULL, null, DUMMY_CB); - } catch (NullPointerException expected) { - } - - // null SSLHandshakeCallbacks - try { - NativeCrypto.SSL_shutdown(NULL, INVALID_FD, null); - } catch (NullPointerException expected) { - } - - // SSL_shutdown is a rare case that tolerates a null SSL argument - NativeCrypto.SSL_shutdown(NULL, INVALID_FD, DUMMY_CB); - - // handshaking not yet performed - long c = NativeCrypto.SSL_CTX_new(); - long s = NativeCrypto.SSL_new(c); - try { - NativeCrypto.SSL_shutdown(s, INVALID_FD, DUMMY_CB); - } catch (SSLProtocolException expected) { - } - NativeCrypto.SSL_free(s); - NativeCrypto.SSL_CTX_free(c); - - // positively tested elsewhere because handshake uses use - // SSL_shutdown to ensure SSL_SESSIONs are reused. - } - - public void test_SSL_free() throws Exception { - try { - NativeCrypto.SSL_free(NULL); - fail(); - } catch (NullPointerException expected) { - } - - long c = NativeCrypto.SSL_CTX_new(); - NativeCrypto.SSL_free(NativeCrypto.SSL_new(c)); - NativeCrypto.SSL_CTX_free(c); - - // additional positive testing elsewhere because handshake - // uses use SSL_free to cleanup in afterHandshake. - } - - public void test_SSL_SESSION_session_id() throws Exception { - try { - NativeCrypto.SSL_SESSION_session_id(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - byte[] id = NativeCrypto.SSL_SESSION_session_id(session); - assertNotNull(id); - assertEquals(32, id.length); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_SESSION_get_time() throws Exception { - try { - NativeCrypto.SSL_SESSION_get_time(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - - { - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - long time = NativeCrypto.SSL_SESSION_get_time(session); - assertTrue(time != 0); - assertTrue(time < System.currentTimeMillis()); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, - null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, - null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - } - - public void test_SSL_SESSION_get_version() throws Exception { - try { - NativeCrypto.SSL_SESSION_get_version(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - String v = NativeCrypto.SSL_SESSION_get_version(session); - assertTrue(StandardNames.SSL_SOCKET_PROTOCOLS.contains(v)); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_SESSION_cipher() throws Exception { - try { - NativeCrypto.SSL_SESSION_cipher(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - String a = NativeCrypto.SSL_SESSION_cipher(session); - assertTrue(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.containsKey(a)); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_SSL_SESSION_free() throws Exception { - try { - NativeCrypto.SSL_SESSION_free(NULL); - fail(); - } catch (NullPointerException expected) { - } - - // additional positive testing elsewhere because handshake - // uses use SSL_SESSION_free to cleanup in afterHandshake. - } - - public void test_i2d_SSL_SESSION() throws Exception { - try { - NativeCrypto.i2d_SSL_SESSION(NULL); - fail(); - } catch (NullPointerException expected) { - } - - final ServerSocket listener = new ServerSocket(0); - - Hooks cHooks = new Hooks() { - @Override - public void afterHandshake(long session, long s, long c, - Socket sock, FileDescriptor fd, - SSLHandshakeCallbacks callback) - throws Exception { - byte[] b = NativeCrypto.i2d_SSL_SESSION(session); - assertNotNull(b); - long session2 = NativeCrypto.d2i_SSL_SESSION(b); - assertTrue(session2 != NULL); - - // Make sure d2i_SSL_SESSION retores SSL_SESSION_cipher value http://b/7091840 - assertTrue(NativeCrypto.SSL_SESSION_cipher(session2) != null); - assertEquals(NativeCrypto.SSL_SESSION_cipher(session), - NativeCrypto.SSL_SESSION_cipher(session2)); - - NativeCrypto.SSL_SESSION_free(session2); - super.afterHandshake(session, s, c, sock, fd, callback); - } - }; - Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); - Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); - Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null); - client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); - } - - public void test_d2i_SSL_SESSION() throws Exception { - try { - NativeCrypto.d2i_SSL_SESSION(null); - fail(); - } catch (NullPointerException expected) { - } - - assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[0])); - assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[1])); - - // positive testing by test_i2d_SSL_SESSION - } - - public void test_X509_NAME_hashes() { - // ensure these hash functions are stable over time since the - // /system/etc/security/cacerts CA filenames have to be - // consistent with the output. - X500Principal name = new X500Principal("CN=localhost"); - assertEquals(-1372642656, NativeCrypto.X509_NAME_hash(name)); // SHA1 - assertEquals(-1626170662, NativeCrypto.X509_NAME_hash_old(name)); // MD5 - } - - public void test_ENGINE_by_id_Failure() throws Exception { - NativeCrypto.ENGINE_load_dynamic(); - - long engine = NativeCrypto.ENGINE_by_id("non-existent"); - if (engine != 0) { - NativeCrypto.ENGINE_finish(engine); - fail("should not acquire reference to non-existent engine"); - } - } - - /** - * Loads the test OpenSSL ENGINE. If it's already loaded, returns - * immediately. - */ - public static void loadTestEngine() throws Exception { - long testEngine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID); - if (testEngine != 0) { - NativeCrypto.ENGINE_finish(testEngine); - return; - } - - NativeCrypto.ENGINE_load_dynamic(); - long dynEngine = NativeCrypto.ENGINE_by_id("dynamic"); - try { - ClassLoader loader = NativeCryptoTest.class.getClassLoader(); - - final String libraryPaths; - if (loader instanceof BaseDexClassLoader) { - libraryPaths = ((BaseDexClassLoader) loader).getLdLibraryPath(); - } else { - libraryPaths = System.getProperty("java.library.path"); - } - assertNotNull(libraryPaths); - - String[] libraryPathArray = libraryPaths.split(":"); - for (String path : libraryPathArray) { - assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "DIR_ADD", path, 0)); - } - - // We must add this to the list of ENGINEs - assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "LIST_ADD", "2", 0)); - - // Do a direct load of the ENGINE. - assertEquals(1, - NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "ID", TEST_ENGINE_ID, 0)); - assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "LOAD", null, 0)); - } finally { - NativeCrypto.ENGINE_finish(dynEngine); - } - - testEngine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID); - if (testEngine == 0) { - fail("could not load test engine"); - } - NativeCrypto.ENGINE_finish(testEngine); - } - - public void test_ENGINE_by_id_TestEngine() throws Exception { - loadTestEngine(); - - long engine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID); - assertTrue(engine != 0); - NativeCrypto.ENGINE_add(engine); - - long pkey = NULL; - try { - final String rsaPem = - "-----BEGIN RSA PRIVATE KEY-----\n" - + "MIICXAIBAAKBgQCvvsYz1VKhU9PT0NHlotX22tcCjeaiVFNg0JrkjoK2XuMb+7a6\n" - + "R5bzgIr24+OnBB0LqgaKnHwxZTA73lo/Wy/Ms5Kvg4yX9UMkNE+PvH5vzcQBbFdI\n" - + "lwETFPvFokHO5OyOcEY+iVWG2fDloteH2JsrKYLh9Sx3Br5pHFCCm5qT5wIDAQAB\n" - + "AoGAWDxoNs371pPH3qkROUIwOuhU2ytziDzeP9V8bxQ9/GJXlE0kyRH4b/kxzBNO\n" - + "0SP3kUukTSOUFxi+xtA0b2rQ7Be2txtjzW1TGOHSCWbFrJAdTqeBcmQJSaZay8n1\n" - + "LOpk4/zvBl7VScBth1IgXP44v6lOzthsrDhMlUYs07ymwYECQQDonaLOhkmVThPa\n" - + "CIThdE5CN/wF5UDzGOz+ZBz3dt8D8QQMu0aZaPzibq9BC462j/fWeWS5OFzbq2+T\n" - + "+cor3nwPAkEAwWmTQdra6GMPEc40zNsM5ehF2FjOpX8aU8267eG56y0Y+GbHx2BN\n" - + "zAHfPxGBBH8cZ0cLhk4RSo/po7Vv+cRyqQJAAQz1N0mT+4Cmxk1TjFEiKVpnYP9w\n" - + "E6kBKQT6vINk7negNQ6Dex3mRn+Jexm6Q0jTLbzOn6eJg9R6ZIi0SQ5wMQJAKX2n\n" - + "fGohqdaORgiRZRzcsHlaemXatsAEetPYdO2Gf7/l6mvKEahEKC6CoLn1jmxiQHmK\n" - + "LF6U8QTcXyUuB0uwOQJBAIwWWjQGGc2sAQ1HW0C2wwCQbWneeBkiRBedonDBHtiB\n" - + "Wz0zS2CMCtBPNeHQmmsXH2Ca+ADdh53sKTuperLiuiw=\n" - + "-----END RSA PRIVATE KEY-----"; - pkey = NativeCrypto.ENGINE_load_private_key(engine, rsaPem); - assertTrue(pkey != 0); - } finally { - if (pkey != NULL) { - NativeCrypto.EVP_PKEY_free(pkey); - } - - NativeCrypto.ENGINE_free(engine); - NativeCrypto.ENGINE_finish(engine); - } - } - - public void test_RAND_bytes_Success() throws Exception { - byte[] output = new byte[128]; - NativeCrypto.RAND_bytes(output); - - boolean isZero = true; - for (int i = 0; i < output.length; i++) { - isZero &= (output[i] == 0); - } - - assertFalse("Random output was zero. This is a very low probability event (1 in 2^128) " - + "and probably indicates an error.", isZero); - } - - public void test_RAND_bytes_Null_Failure() throws Exception { - byte[] output = null; - try { - NativeCrypto.RAND_bytes(output); - fail("Should be an error on null buffer input"); - } catch (RuntimeException expected) { - } - } - - public void test_EVP_get_digestbyname() throws Exception { - assertTrue(NativeCrypto.EVP_get_digestbyname("sha256") != NULL); - - try { - NativeCrypto.EVP_get_digestbyname(null); - fail(); - } catch (NullPointerException expected) { - } - - try { - NativeCrypto.EVP_get_digestbyname(""); - NativeCrypto.EVP_get_digestbyname("foobar"); - fail(); - } catch (RuntimeException expected) { - } - } - - public void test_EVP_SignInit() throws Exception { - final long ctx = NativeCrypto.EVP_SignInit("RSA-SHA256"); - assertTrue(ctx != NULL); - NativeCrypto.EVP_MD_CTX_destroy(ctx); - - try { - NativeCrypto.EVP_SignInit("foobar"); - fail(); - } catch (RuntimeException expected) { - } - } - - public void test_get_RSA_private_params() throws Exception { - try { - NativeCrypto.get_RSA_private_params(NULL); - } catch (NullPointerException expected) { - } - - try { - NativeCrypto.get_RSA_private_params(NULL); - } catch (NullPointerException expected) { - } - - // Test getting params for the wrong kind of key. - final byte[] seed = new byte[20]; - long ctx = 0; - try { - ctx = NativeCrypto.DSA_generate_key(2048, seed, dsa2048_g, dsa2048_p, dsa2048_q); - assertTrue(ctx != NULL); - try { - NativeCrypto.get_RSA_private_params(ctx); - fail(); - } catch (RuntimeException expected) { - } - } finally { - if (ctx != 0) { - NativeCrypto.EVP_PKEY_free(ctx); - } - } - } - - public void test_get_RSA_public_params() throws Exception { - try { - NativeCrypto.get_RSA_public_params(NULL); - } catch (NullPointerException expected) { - } - - try { - NativeCrypto.get_RSA_public_params(NULL); - } catch (NullPointerException expected) { - } - - // Test getting params for the wrong kind of key. - final byte[] seed = new byte[20]; - long ctx = 0; - try { - ctx = NativeCrypto.DSA_generate_key(2048, seed, dsa2048_g, dsa2048_p, dsa2048_q); - assertTrue(ctx != NULL); - try { - NativeCrypto.get_RSA_public_params(ctx); - fail(); - } catch (RuntimeException expected) { - } - } finally { - if (ctx != 0) { - NativeCrypto.EVP_PKEY_free(ctx); - } - } - } - - final byte[] dsa2048_p = { - (byte) 0xC3, (byte) 0x16, (byte) 0xD4, (byte) 0xBA, (byte) 0xDC, (byte) 0x0E, - (byte) 0xB8, (byte) 0xFC, (byte) 0x40, (byte) 0xDB, (byte) 0xB0, (byte) 0x76, - (byte) 0x47, (byte) 0xB8, (byte) 0x8D, (byte) 0xC1, (byte) 0xF1, (byte) 0xAB, - (byte) 0x9B, (byte) 0x80, (byte) 0x9D, (byte) 0xDC, (byte) 0x55, (byte) 0x33, - (byte) 0xEC, (byte) 0xB6, (byte) 0x09, (byte) 0x8F, (byte) 0xB7, (byte) 0xD9, - (byte) 0xA5, (byte) 0x7F, (byte) 0xC1, (byte) 0xE3, (byte) 0xAD, (byte) 0xE1, - (byte) 0x7A, (byte) 0x58, (byte) 0xF4, (byte) 0x2D, (byte) 0xB9, (byte) 0x61, - (byte) 0xCF, (byte) 0x5B, (byte) 0xCA, (byte) 0x41, (byte) 0x9F, (byte) 0x73, - (byte) 0x8D, (byte) 0x81, (byte) 0x62, (byte) 0xD2, (byte) 0x19, (byte) 0x7D, - (byte) 0x18, (byte) 0xDB, (byte) 0xB3, (byte) 0x04, (byte) 0xE7, (byte) 0xB2, - (byte) 0x28, (byte) 0x59, (byte) 0x14, (byte) 0x73, (byte) 0x43, (byte) 0xF1, - (byte) 0x45, (byte) 0xC7, (byte) 0x47, (byte) 0xCC, (byte) 0xD1, (byte) 0x12, - (byte) 0x8E, (byte) 0x19, (byte) 0x00, (byte) 0x2C, (byte) 0xD0, (byte) 0x86, - (byte) 0x54, (byte) 0x64, (byte) 0x2D, (byte) 0x42, (byte) 0x6C, (byte) 0x6B, - (byte) 0x5C, (byte) 0x2D, (byte) 0x4D, (byte) 0x97, (byte) 0x6A, (byte) 0x1D, - (byte) 0x89, (byte) 0xB1, (byte) 0x2C, (byte) 0xA0, (byte) 0x05, (byte) 0x2B, - (byte) 0x3C, (byte) 0xDB, (byte) 0x1F, (byte) 0x89, (byte) 0x03, (byte) 0x03, - (byte) 0x92, (byte) 0x63, (byte) 0xB6, (byte) 0x08, (byte) 0x32, (byte) 0x50, - (byte) 0xB2, (byte) 0x54, (byte) 0xA3, (byte) 0xFE, (byte) 0x6C, (byte) 0x35, - (byte) 0x17, (byte) 0x2F, (byte) 0x7F, (byte) 0x54, (byte) 0xA4, (byte) 0xAE, - (byte) 0x96, (byte) 0x1E, (byte) 0x31, (byte) 0x83, (byte) 0xF1, (byte) 0x3F, - (byte) 0x9E, (byte) 0xB9, (byte) 0x5D, (byte) 0xD3, (byte) 0xA9, (byte) 0xCB, - (byte) 0xE5, (byte) 0x2F, (byte) 0xBC, (byte) 0xA4, (byte) 0x1A, (byte) 0x31, - (byte) 0x41, (byte) 0x91, (byte) 0x2C, (byte) 0xA0, (byte) 0xF4, (byte) 0x83, - (byte) 0xAC, (byte) 0xD5, (byte) 0xBA, (byte) 0x3D, (byte) 0x19, (byte) 0xED, - (byte) 0xF1, (byte) 0x6C, (byte) 0xD9, (byte) 0x3F, (byte) 0x30, (byte) 0xDA, - (byte) 0x80, (byte) 0x06, (byte) 0x56, (byte) 0x3A, (byte) 0x8C, (byte) 0x74, - (byte) 0x63, (byte) 0xF2, (byte) 0xED, (byte) 0x1E, (byte) 0xE3, (byte) 0x86, - (byte) 0x95, (byte) 0x64, (byte) 0x2A, (byte) 0xC4, (byte) 0x5F, (byte) 0xB2, - (byte) 0x64, (byte) 0x40, (byte) 0x9D, (byte) 0xA6, (byte) 0xB8, (byte) 0xF5, - (byte) 0x84, (byte) 0x03, (byte) 0x2E, (byte) 0x4A, (byte) 0x7A, (byte) 0x1A, - (byte) 0xB0, (byte) 0x0E, (byte) 0xBA, (byte) 0xB1, (byte) 0xF5, (byte) 0xD2, - (byte) 0xE7, (byte) 0x65, (byte) 0xCE, (byte) 0xEE, (byte) 0x2C, (byte) 0x7C, - (byte) 0x68, (byte) 0x20, (byte) 0x50, (byte) 0x53, (byte) 0x0F, (byte) 0x60, - (byte) 0x92, (byte) 0x81, (byte) 0xC0, (byte) 0x2C, (byte) 0x2A, (byte) 0xEA, - (byte) 0xE9, (byte) 0xB3, (byte) 0x2A, (byte) 0x81, (byte) 0xDA, (byte) 0x0F, - (byte) 0xBB, (byte) 0xFA, (byte) 0x5B, (byte) 0x47, (byte) 0xDA, (byte) 0x57, - (byte) 0x4E, (byte) 0xFC, (byte) 0x05, (byte) 0x2C, (byte) 0x6A, (byte) 0x90, - (byte) 0xA0, (byte) 0x99, (byte) 0x88, (byte) 0x71, (byte) 0x8A, (byte) 0xCC, - (byte) 0xD2, (byte) 0x97, (byte) 0x11, (byte) 0xB1, (byte) 0xCE, (byte) 0xF7, - (byte) 0x47, (byte) 0x53, (byte) 0x53, (byte) 0x68, (byte) 0xE1, (byte) 0x2A, - (byte) 0x56, (byte) 0xD5, (byte) 0x3D, (byte) 0xDF, (byte) 0x08, (byte) 0x16, - (byte) 0x1F, (byte) 0xAA, (byte) 0x54, (byte) 0x15, - }; - - final byte[] dsa2048_q = { - (byte) 0xAA, (byte) 0xDD, (byte) 0xE2, (byte) 0xCE, (byte) 0x08, (byte) 0xC0, - (byte) 0x0E, (byte) 0x91, (byte) 0x8C, (byte) 0xD9, (byte) 0xBC, (byte) 0x1E, - (byte) 0x05, (byte) 0x70, (byte) 0x07, (byte) 0x3B, (byte) 0xB5, (byte) 0xA9, - (byte) 0xB5, (byte) 0x8B, (byte) 0x21, (byte) 0x68, (byte) 0xA2, (byte) 0x76, - (byte) 0x53, (byte) 0x1E, (byte) 0x68, (byte) 0x1B, (byte) 0x4F, (byte) 0x88, - (byte) 0x6D, (byte) 0xCF, - }; - - final byte[] dsa2048_g = { - (byte) 0x6B, (byte) 0x4D, (byte) 0x21, (byte) 0x92, (byte) 0x24, (byte) 0x76, - (byte) 0xE5, (byte) 0xA2, (byte) 0xCE, (byte) 0x02, (byte) 0x85, (byte) 0x32, - (byte) 0x73, (byte) 0x70, (byte) 0xFF, (byte) 0xB9, (byte) 0xD4, (byte) 0x51, - (byte) 0xBA, (byte) 0x22, (byte) 0x8B, (byte) 0x75, (byte) 0x29, (byte) 0xE3, - (byte) 0xF2, (byte) 0x2E, (byte) 0x20, (byte) 0xF5, (byte) 0x6A, (byte) 0xD9, - (byte) 0x75, (byte) 0xA0, (byte) 0xC0, (byte) 0x3B, (byte) 0x12, (byte) 0x2F, - (byte) 0x4F, (byte) 0x9A, (byte) 0xF8, (byte) 0x5D, (byte) 0x45, (byte) 0xC5, - (byte) 0x80, (byte) 0x6C, (byte) 0x9B, (byte) 0x56, (byte) 0xBE, (byte) 0x8E, - (byte) 0x40, (byte) 0xF9, (byte) 0x0A, (byte) 0xF0, (byte) 0x3D, (byte) 0xD7, - (byte) 0x7C, (byte) 0xDE, (byte) 0x22, (byte) 0x10, (byte) 0x24, (byte) 0xCC, - (byte) 0xAE, (byte) 0x8A, (byte) 0xC0, (byte) 0x05, (byte) 0xCD, (byte) 0xDC, - (byte) 0x10, (byte) 0x29, (byte) 0x4D, (byte) 0xFC, (byte) 0xEC, (byte) 0xEF, - (byte) 0x51, (byte) 0x4B, (byte) 0xF9, (byte) 0xCC, (byte) 0x99, (byte) 0x84, - (byte) 0x1B, (byte) 0x14, (byte) 0x68, (byte) 0xEC, (byte) 0xF0, (byte) 0x5E, - (byte) 0x07, (byte) 0x10, (byte) 0x09, (byte) 0xA9, (byte) 0x2C, (byte) 0x04, - (byte) 0xD0, (byte) 0x14, (byte) 0xBF, (byte) 0x88, (byte) 0x9E, (byte) 0xBB, - (byte) 0xE3, (byte) 0x3F, (byte) 0xDE, (byte) 0x92, (byte) 0xE1, (byte) 0x64, - (byte) 0x07, (byte) 0x28, (byte) 0xC1, (byte) 0xCA, (byte) 0x48, (byte) 0xC1, - (byte) 0x1D, (byte) 0x33, (byte) 0xE4, (byte) 0x35, (byte) 0xBE, (byte) 0xDF, - (byte) 0x5E, (byte) 0x50, (byte) 0xF9, (byte) 0xC2, (byte) 0x0E, (byte) 0x25, - (byte) 0x0D, (byte) 0x20, (byte) 0x8C, (byte) 0x01, (byte) 0x0A, (byte) 0x23, - (byte) 0xD4, (byte) 0x6E, (byte) 0x42, (byte) 0x47, (byte) 0xE1, (byte) 0x9E, - (byte) 0x36, (byte) 0x91, (byte) 0xC8, (byte) 0x65, (byte) 0x44, (byte) 0xE0, - (byte) 0x04, (byte) 0x86, (byte) 0x2F, (byte) 0xD4, (byte) 0x90, (byte) 0x16, - (byte) 0x09, (byte) 0x14, (byte) 0xB1, (byte) 0xC5, (byte) 0x7D, (byte) 0xB2, - (byte) 0x7C, (byte) 0x36, (byte) 0x0D, (byte) 0x9C, (byte) 0x1F, (byte) 0x83, - (byte) 0x57, (byte) 0x94, (byte) 0x26, (byte) 0x32, (byte) 0x9C, (byte) 0x86, - (byte) 0x8E, (byte) 0xE5, (byte) 0x80, (byte) 0x3A, (byte) 0xA9, (byte) 0xAF, - (byte) 0x4A, (byte) 0x95, (byte) 0x78, (byte) 0x8D, (byte) 0xE6, (byte) 0xC3, - (byte) 0x0C, (byte) 0x78, (byte) 0x83, (byte) 0x4B, (byte) 0xF5, (byte) 0x40, - (byte) 0x04, (byte) 0x20, (byte) 0x90, (byte) 0x5C, (byte) 0xA1, (byte) 0x19, - (byte) 0xEB, (byte) 0x95, (byte) 0x70, (byte) 0x2B, (byte) 0x94, (byte) 0xA3, - (byte) 0x43, (byte) 0xDD, (byte) 0xEB, (byte) 0xD4, (byte) 0x0C, (byte) 0xBC, - (byte) 0xBD, (byte) 0x58, (byte) 0x2D, (byte) 0x75, (byte) 0xB0, (byte) 0x8D, - (byte) 0x8B, (byte) 0x70, (byte) 0xB9, (byte) 0xE7, (byte) 0xA3, (byte) 0xCC, - (byte) 0x8C, (byte) 0xB4, (byte) 0xCD, (byte) 0xBB, (byte) 0x4B, (byte) 0xB1, - (byte) 0x15, (byte) 0x18, (byte) 0x79, (byte) 0xDF, (byte) 0x22, (byte) 0xA6, - (byte) 0x5C, (byte) 0x90, (byte) 0x7C, (byte) 0x1F, (byte) 0xEA, (byte) 0x1B, - (byte) 0xF2, (byte) 0x89, (byte) 0x87, (byte) 0xB2, (byte) 0xEC, (byte) 0x57, - (byte) 0xFF, (byte) 0xB2, (byte) 0xDA, (byte) 0xF5, (byte) 0xAD, (byte) 0x73, - (byte) 0xC0, (byte) 0xA0, (byte) 0x20, (byte) 0x8B, (byte) 0x78, (byte) 0xA1, - (byte) 0x5D, (byte) 0x04, (byte) 0x0A, (byte) 0x29, (byte) 0xE3, (byte) 0xD7, - (byte) 0x37, (byte) 0xF6, (byte) 0xA2, (byte) 0xCA, - }; - - public void test_DSA_generate_key() throws Exception { - final byte[] seed = new byte[20]; - - // Real key - { - long ctx = 0; - try { - ctx = NativeCrypto.DSA_generate_key(2048, seed, dsa2048_g, dsa2048_p, dsa2048_q); - assertTrue(ctx != NULL); - } finally { - if (ctx != 0) { - NativeCrypto.EVP_PKEY_free(ctx); - } - } - } - - // Real key with minimum bit size (should be 512 bits) - { - long ctx = 0; - try { - ctx = NativeCrypto.DSA_generate_key(0, null, null, null, null); - assertTrue(ctx != NULL); - } finally { - if (ctx != 0) { - NativeCrypto.EVP_PKEY_free(ctx); - } - } - } - - // Bad DSA params. - { - long ctx = 0; - try { - ctx = NativeCrypto.DSA_generate_key(0, null, new byte[] {}, new byte[] {}, - new byte[] {}); - fail(); - } catch (RuntimeException expected) { - } finally { - if (ctx != 0) { - NativeCrypto.EVP_PKEY_free(ctx); - } - } - } - } - - /* - * Test vector generation: - * openssl rand -hex 16 - */ - private static final byte[] AES_128_KEY = new byte[] { - (byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2, - (byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29, - (byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f, - }; - - private static final byte[] AES_IV_ZEROES = new byte[] { - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - }; - - public void testEC_GROUP() throws Exception { - /* Test using NIST's P-256 curve */ - check_EC_GROUP(NativeCrypto.EC_CURVE_GFP, "prime256v1", - "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", - "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", - "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", - "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", - "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", - "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", - 1L); - - check_EC_GROUP(NativeCrypto.EC_CURVE_GF2M, "sect283r1", - "0800000000000000000000000000000000000000000000000000000000000000000010A1", - "000000000000000000000000000000000000000000000000000000000000000000000001", - "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", - "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053", - "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", - "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", - 2L); - } - - private void check_EC_GROUP(int type, String name, String pStr, String aStr, String bStr, - String xStr, String yStr, String nStr, long hLong) throws Exception { - long group1 = NULL, group2 = NULL, point1 = NULL, point2 = NULL, key1 = NULL; - try { - group1 = NativeCrypto.EC_GROUP_new_by_curve_name(name); - assertTrue(group1 != NULL); - assertEquals(NativeCrypto.OBJ_txt2nid_longName(name), - NativeCrypto.EC_GROUP_get_curve_name(group1)); - assertEquals(type, NativeCrypto.get_EC_GROUP_type(group1)); - - // prime - BigInteger p = new BigInteger(pStr, 16); - // first coefficient - BigInteger a = new BigInteger(aStr, 16); - // second coefficient - BigInteger b = new BigInteger(bStr, 16); - // x affine coordinate of generator - BigInteger x = new BigInteger(xStr, 16); - // y affine coordinate of generator - BigInteger y = new BigInteger(yStr, 16); - // order of the generator - BigInteger n = new BigInteger(nStr, 16); - // cofactor of generator - BigInteger h = BigInteger.valueOf(hLong); - - group2 = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), - a.toByteArray(), b.toByteArray()); - assertEquals(type, NativeCrypto.get_EC_GROUP_type(group2)); - - point2 = NativeCrypto.EC_POINT_new(group2); - - NativeCrypto.EC_POINT_set_affine_coordinates(group2, point2, x.toByteArray(), - y.toByteArray()); - - NativeCrypto.EC_GROUP_set_generator(group2, point2, n.toByteArray(), h.toByteArray()); - - point1 = NativeCrypto.EC_GROUP_get_generator(group2); - assertTrue(NativeCrypto.EC_POINT_cmp(group1, point1, point2)); - - byte[][] pab = NativeCrypto.EC_GROUP_get_curve(group2); - assertEquals(3, pab.length); - - BigInteger p2 = new BigInteger(pab[0]); - assertEquals(p, p2); - - BigInteger a2 = new BigInteger(pab[1]); - assertEquals(a, a2); - - BigInteger b2 = new BigInteger(pab[2]); - assertEquals(b, b2); - - byte[][] xy = NativeCrypto.EC_POINT_get_affine_coordinates(group2, point2); - assertEquals(2, xy.length); - - BigInteger x2 = new BigInteger(xy[0]); - assertEquals(x, x2); - - BigInteger y2 = new BigInteger(xy[1]); - assertEquals(y, y2); - - BigInteger n2 = new BigInteger(NativeCrypto.EC_GROUP_get_order(group1)); - assertEquals(n, n2); - - BigInteger h2 = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(group2)); - assertEquals(h, h2); - - assertTrue(NativeCrypto.EC_GROUP_cmp(group1, group2)); - - key1 = NativeCrypto.EC_KEY_generate_key(group1); - long groupTmp = NativeCrypto.EC_KEY_get0_group(key1); - assertEquals(NativeCrypto.EC_GROUP_get_curve_name(group1), - NativeCrypto.EC_GROUP_get_curve_name(groupTmp)); - - } finally { - if (group1 != NULL) { - NativeCrypto.EC_GROUP_clear_free(group1); - } - - if (group2 != NULL) { - NativeCrypto.EC_GROUP_clear_free(group2); - } - - if (point1 != NULL) { - NativeCrypto.EC_POINT_clear_free(point1); - } - - if (point2 != NULL) { - NativeCrypto.EC_POINT_clear_free(point2); - } - - if (key1 != NULL) { - NativeCrypto.EVP_PKEY_free(key1); - } - } - } - - public void test_EVP_CipherInit_ex_Null_Failure() throws Exception { - final long ctx = NativeCrypto.EVP_CIPHER_CTX_new(); - try { - final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); - - try { - NativeCrypto.EVP_CipherInit_ex(NULL, evpCipher, null, null, true); - fail("Null context should throw NullPointerException"); - } catch (NullPointerException expected) { - } - - /* Initialize encrypting. */ - NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, true); - NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, true); - - /* Initialize decrypting. */ - NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, false); - NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, false); - } finally { - NativeCrypto.EVP_CIPHER_CTX_cleanup(ctx); - } - } - - public void test_EVP_CipherInit_ex_Success() throws Exception { - final long ctx = NativeCrypto.EVP_CIPHER_CTX_new(); - try { - final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); - NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, AES_128_KEY, null, true); - } finally { - NativeCrypto.EVP_CIPHER_CTX_cleanup(ctx); - } - } - - public void test_EVP_CIPHER_iv_length() throws Exception { - long aes128ecb = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); - assertEquals(0, NativeCrypto.EVP_CIPHER_iv_length(aes128ecb)); - - long aes128cbc = NativeCrypto.EVP_get_cipherbyname("aes-128-cbc"); - assertEquals(16, NativeCrypto.EVP_CIPHER_iv_length(aes128cbc)); - } - - public void test_OpenSSLKey_toJava() throws Exception { - OpenSSLKey key1; - - BigInteger e = BigInteger.valueOf(65537); - key1 = new OpenSSLKey(NativeCrypto.RSA_generate_key_ex(1024, e.toByteArray())); - assertTrue(key1.getPublicKey() instanceof RSAPublicKey); - - key1 = new OpenSSLKey(NativeCrypto.DSA_generate_key(1024, null, null, null, null)); - assertTrue(key1.getPublicKey() instanceof DSAPublicKey); - - long group1 = NULL; - try { - group1 = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1"); - assertTrue(group1 != NULL); - key1 = new OpenSSLKey(NativeCrypto.EC_KEY_generate_key(group1)); - } finally { - if (group1 != NULL) { - NativeCrypto.EC_GROUP_clear_free(group1); - } - } - assertTrue(key1.getPublicKey() instanceof ECPublicKey); - } - - public void test_create_BIO_InputStream() throws Exception { - byte[] actual = "Test".getBytes(); - ByteArrayInputStream is = new ByteArrayInputStream(actual); - - long ctx = NativeCrypto.create_BIO_InputStream(new OpenSSLBIOInputStream(is)); - try { - byte[] buffer = new byte[1024]; - int numRead = NativeCrypto.BIO_read(ctx, buffer); - assertEquals(actual.length, numRead); - assertEquals(Arrays.toString(actual), - Arrays.toString(Arrays.copyOfRange(buffer, 0, numRead))); - } finally { - NativeCrypto.BIO_free(ctx); - } - - } - - public void test_create_BIO_OutputStream() throws Exception { - byte[] actual = "Test".getBytes(); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - - long ctx = NativeCrypto.create_BIO_OutputStream(os); - try { - NativeCrypto.BIO_write(ctx, actual, 0, actual.length); - assertEquals(actual.length, os.size()); - assertEquals(Arrays.toString(actual), Arrays.toString(os.toByteArray())); - } finally { - NativeCrypto.BIO_free(ctx); - } - } -} diff --git a/crypto/src/test/java/org/conscrypt/OpenSSLSignatureTest.java b/crypto/src/test/java/org/conscrypt/OpenSSLSignatureTest.java deleted file mode 100644 index 045c509..0000000 --- a/crypto/src/test/java/org/conscrypt/OpenSSLSignatureTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2010 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.NoSuchAlgorithmException; -import junit.framework.TestCase; - -public class OpenSSLSignatureTest extends TestCase { - - public void test_getInstance() throws Exception { - try { - OpenSSLSignature.getInstance("SHA1WITHDSA"); - OpenSSLSignature.getInstance("MD5WITHRSAENCRYPTION"); - OpenSSLSignature.getInstance("SHA1WITHRSAENCRYPTION"); - OpenSSLSignature.getInstance("SHA256WITHRSAENCRYPTION"); - OpenSSLSignature.getInstance("SHA384WITHRSAENCRYPTION"); - OpenSSLSignature.getInstance("SHA512WITHRSAENCRYPTION"); - } catch (NoSuchAlgorithmException e) { - fail("getInstance is not case insensitive"); - } - } -} diff --git a/crypto/src/test/java/org/conscrypt/SignatureTest.java b/crypto/src/test/java/org/conscrypt/SignatureTest.java deleted file mode 100644 index d6679c4..0000000 --- a/crypto/src/test/java/org/conscrypt/SignatureTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2012 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.PublicKey; -import java.security.Security; -import java.security.Signature; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.X509EncodedKeySpec; -import java.util.Set; -import junit.framework.TestCase; - -public class SignatureTest extends TestCase { - // 20 bytes for DSA - private final byte[] DATA = new byte[20]; - - public void test_getInstance_OpenSSL_ENGINE() throws Exception { - final String pem_private = "-----BEGIN RSA PRIVATE KEY-----\n" - + "MIICXAIBAAKBgQDpm4KamxulJnycEzNONGM7p0CvAaoZxJEd5Dvio5b6BROdCtRN\n" - + "lEsB+9vtB5thkyDVC7N+IW0AjtyDE6h2QP+AWa+c4dh0RM2uNVXkUWPrA8C++GHv\n" - + "EDlxZzRGiQEMuippYfIyBVkO+4+GRvnkG4dKjzxrQYPqKUK3C4PgFW2FewIDAQAB\n" - + "AoGAGUTSBsk6X03fcr588TundD9uNr/2V1002Ufj1msdnKPJ8FXIiy+8QVWt/2Cw\n" - + "RQi2J3VhkAYrlUDex2rr8Qas3E9uuwKgg/MZ4EsJbnKKgkd7uBZfmZ2ogcNJ82u7\n" - + "teVijFpdsVLDa9aczEppt5sZzyTaBrovrRb+AIRDpMw3I0ECQQD3JkWeQUA9Is1V\n" - + "z0X/ly/kaQKQLlrwYNdiKF0qOpyTLAguI7asAS72Zj7fThk5bHLM+mmgYwkicIIb\n" - + "67J32GQbAkEA8fkXqEnwMFYSkRmT9M/qUkwWUsMW12/AoZFI5gwKNDHZYxytGGLw\n" - + "mC//0qKnyeUG00vz06vLApe4/Sq4ODe6IQJBALEGastF9ZtUuDsEciD2y8kRJlLb\n" - + "wSt4Ug3u13yN6uTHnzxdPFTLrDW1WsdcC1lEQp5rpwjIpxxR9f/FvVl2V40CQHOY\n" - + "F6EhkUjGFaCTo4b0PHCMQK3Q3PyWOmP0z+p2HfnJRpx+eoKH4YASjhfF9HoSmywd\n" - + "wKGCFD1s1ca7vb29gYECQH86GmYZsDoLNWurEVJbkmCr7X1+xwim6umdrNKR27P7\n" - + "F1y0Sa3YY+LiiRb+IRSWE/onlP+28LIzWGF4lcTfDMc=\n" - + "-----END RSA PRIVATE KEY-----"; - - final byte[] der_public = new byte[] { - (byte) 0x30, (byte) 0x81, (byte) 0x9F, (byte) 0x30, (byte) 0x0D, (byte) 0x06, - (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, - (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, - (byte) 0x03, (byte) 0x81, (byte) 0x8D, (byte) 0x00, (byte) 0x30, (byte) 0x81, - (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xE9, - (byte) 0x9B, (byte) 0x82, (byte) 0x9A, (byte) 0x9B, (byte) 0x1B, (byte) 0xA5, - (byte) 0x26, (byte) 0x7C, (byte) 0x9C, (byte) 0x13, (byte) 0x33, (byte) 0x4E, - (byte) 0x34, (byte) 0x63, (byte) 0x3B, (byte) 0xA7, (byte) 0x40, (byte) 0xAF, - (byte) 0x01, (byte) 0xAA, (byte) 0x19, (byte) 0xC4, (byte) 0x91, (byte) 0x1D, - (byte) 0xE4, (byte) 0x3B, (byte) 0xE2, (byte) 0xA3, (byte) 0x96, (byte) 0xFA, - (byte) 0x05, (byte) 0x13, (byte) 0x9D, (byte) 0x0A, (byte) 0xD4, (byte) 0x4D, - (byte) 0x94, (byte) 0x4B, (byte) 0x01, (byte) 0xFB, (byte) 0xDB, (byte) 0xED, - (byte) 0x07, (byte) 0x9B, (byte) 0x61, (byte) 0x93, (byte) 0x20, (byte) 0xD5, - (byte) 0x0B, (byte) 0xB3, (byte) 0x7E, (byte) 0x21, (byte) 0x6D, (byte) 0x00, - (byte) 0x8E, (byte) 0xDC, (byte) 0x83, (byte) 0x13, (byte) 0xA8, (byte) 0x76, - (byte) 0x40, (byte) 0xFF, (byte) 0x80, (byte) 0x59, (byte) 0xAF, (byte) 0x9C, - (byte) 0xE1, (byte) 0xD8, (byte) 0x74, (byte) 0x44, (byte) 0xCD, (byte) 0xAE, - (byte) 0x35, (byte) 0x55, (byte) 0xE4, (byte) 0x51, (byte) 0x63, (byte) 0xEB, - (byte) 0x03, (byte) 0xC0, (byte) 0xBE, (byte) 0xF8, (byte) 0x61, (byte) 0xEF, - (byte) 0x10, (byte) 0x39, (byte) 0x71, (byte) 0x67, (byte) 0x34, (byte) 0x46, - (byte) 0x89, (byte) 0x01, (byte) 0x0C, (byte) 0xBA, (byte) 0x2A, (byte) 0x69, - (byte) 0x61, (byte) 0xF2, (byte) 0x32, (byte) 0x05, (byte) 0x59, (byte) 0x0E, - (byte) 0xFB, (byte) 0x8F, (byte) 0x86, (byte) 0x46, (byte) 0xF9, (byte) 0xE4, - (byte) 0x1B, (byte) 0x87, (byte) 0x4A, (byte) 0x8F, (byte) 0x3C, (byte) 0x6B, - (byte) 0x41, (byte) 0x83, (byte) 0xEA, (byte) 0x29, (byte) 0x42, (byte) 0xB7, - (byte) 0x0B, (byte) 0x83, (byte) 0xE0, (byte) 0x15, (byte) 0x6D, (byte) 0x85, - (byte) 0x7B, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01 - }; - - // We only need to test this on the OpenSSL provider. - Provider p = Security.getProvider(OpenSSLProvider.PROVIDER_NAME); - - /* ENGINE-based private key */ - NativeCryptoTest.loadTestEngine(); - OpenSSLEngine engine = OpenSSLEngine.getInstance(NativeCryptoTest.TEST_ENGINE_ID); - PrivateKey privKey = engine.getPrivateKeyById(pem_private); - assertTrue(privKey instanceof RSAPrivateKey); - - /* Non-ENGINE-based public key */ - KeyFactory kf = KeyFactory.getInstance("RSA", p); - PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(der_public)); - - KeyPair kp = new KeyPair(pubKey, privKey); - - Set<Provider.Service> services = p.getServices(); - for (Provider.Service service : services) { - if ("Signature".equals(service.getType()) && service.getAlgorithm().contains("RSA")) { - Signature sig1 = Signature.getInstance(service.getAlgorithm(), p); - test_Signature(sig1, kp); - } - } - } - - private void test_Signature(Signature sig, KeyPair keyPair) throws Exception { - sig.initSign(keyPair.getPrivate()); - sig.update(DATA); - byte[] signature = sig.sign(); - assertNotNull(sig.getAlgorithm(), signature); - assertTrue(sig.getAlgorithm(), signature.length > 0); - - sig.initVerify(keyPair.getPublic()); - sig.update(DATA); - assertTrue(sig.getAlgorithm(), sig.verify(signature)); - - // After verify, should be reusable as if we are after initVerify - sig.update(DATA); - assertTrue(sig.getAlgorithm(), sig.verify(signature)); - - // Calling Signature.verify a second time should not throw - // http://code.google.com/p/android/issues/detail?id=34933 - sig.verify(signature); - } -} diff --git a/crypto/src/test/java/org/conscrypt/TrustManagerImplTest.java b/crypto/src/test/java/org/conscrypt/TrustManagerImplTest.java deleted file mode 100644 index 639ed95..0000000 --- a/crypto/src/test/java/org/conscrypt/TrustManagerImplTest.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2011 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.File; -import java.io.FileWriter; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.security.KeyStore; -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; -import junit.framework.TestCase; -import libcore.java.security.TestKeyStore; - -public class TrustManagerImplTest extends TestCase { - - private List<File> tmpFiles = new ArrayList<File>(); - - private String getFingerprint(X509Certificate cert) throws Exception { - MessageDigest dgst = MessageDigest.getInstance("SHA512"); - byte[] encoded = cert.getPublicKey().getEncoded(); - byte[] fingerprint = dgst.digest(encoded); - return IntegralToString.bytesToHexString(fingerprint, false); - } - - private String writeTmpPinFile(String text) throws Exception { - File tmp = File.createTempFile("pins", null); - FileWriter fstream = new FileWriter(tmp); - fstream.write(text); - fstream.close(); - tmpFiles.add(tmp); - return tmp.getPath(); - } - - @Override - public void tearDown() throws Exception { - try { - for (File f : tmpFiles) { - f.delete(); - } - tmpFiles.clear(); - } finally { - super.tearDown(); - } - } - - /** - * Ensure that our non-standard behavior of learning to trust new - * intermediate CAs does not regress. http://b/3404902 - */ - public void testLearnIntermediate() throws Exception { - // chain3 should be server/intermediate/root - KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); - X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain(); - X509Certificate root = chain3[2]; - X509Certificate intermediate = chain3[1]; - X509Certificate server = chain3[0]; - X509Certificate[] chain2 = new X509Certificate[] { server, intermediate }; - X509Certificate[] chain1 = new X509Certificate[] { server }; - - // Normal behavior - assertValid(chain3, trustManager(root)); - assertValid(chain2, trustManager(root)); - assertInvalid(chain1, trustManager(root)); - assertValid(chain3, trustManager(intermediate)); - assertValid(chain2, trustManager(intermediate)); - assertValid(chain1, trustManager(intermediate)); - assertValid(chain3, trustManager(server)); - assertValid(chain2, trustManager(server)); - assertValid(chain1, trustManager(server)); - - // non-standard behavior - X509TrustManager tm = trustManager(root); - // fail on short chain with only root trusted - assertInvalid(chain1, tm); - // succeed on longer chain, learn intermediate - assertValid(chain2, tm); - // now we can validate the short chain - assertValid(chain1, tm); - } - - // We should ignore duplicate cruft in the certificate chain - // See https://code.google.com/p/android/issues/detail?id=52295 http://b/8313312 - public void testDuplicateInChain() throws Exception { - // chain3 should be server/intermediate/root - KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); - X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain(); - X509Certificate root = chain3[2]; - X509Certificate intermediate = chain3[1]; - X509Certificate server = chain3[0]; - - X509Certificate[] chain4 = new X509Certificate[] { server, intermediate, - server, intermediate - }; - assertValid(chain4, trustManager(root)); - } - - public void testGetFullChain() throws Exception { - // build the trust manager - KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); - X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain(); - X509Certificate root = chain3[2]; - X509TrustManager tm = trustManager(root); - - // build the chains we'll use for testing - X509Certificate intermediate = chain3[1]; - X509Certificate server = chain3[0]; - X509Certificate[] chain2 = new X509Certificate[] { server, intermediate }; - X509Certificate[] chain1 = new X509Certificate[] { server }; - - assertTrue(tm instanceof TrustManagerImpl); - TrustManagerImpl tmi = (TrustManagerImpl) tm; - List<X509Certificate> certs = tmi.checkServerTrusted(chain2, "RSA", "purple.com"); - assertEquals(Arrays.asList(chain3), certs); - certs = tmi.checkServerTrusted(chain1, "RSA", "purple.com"); - assertEquals(Arrays.asList(chain3), certs); - } - - public void testCertPinning() throws Exception { - // chain3 should be server/intermediate/root - KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); - X509Certificate[] chain3 = (X509Certificate[]) pke.getCertificateChain(); - X509Certificate root = chain3[2]; - X509Certificate intermediate = chain3[1]; - X509Certificate server = chain3[0]; - X509Certificate[] chain2 = new X509Certificate[] { server, intermediate }; - X509Certificate[] chain1 = new X509Certificate[] { server }; - - // test without a hostname, expecting failure - assertInvalidPinned(chain1, trustManager(root, "gugle.com", root), null); - // test without a hostname, expecting success - assertValidPinned(chain3, trustManager(root, "gugle.com", root), null, chain3); - // test an unpinned hostname that should fail - assertInvalidPinned(chain1, trustManager(root, "gugle.com", root), "purple.com"); - // test an unpinned hostname that should succeed - assertValidPinned(chain3, trustManager(root, "gugle.com", root), "purple.com", chain3); - // test a pinned hostname that should fail - assertInvalidPinned(chain1, trustManager(intermediate, "gugle.com", root), "gugle.com"); - // test a pinned hostname that should succeed - assertValidPinned(chain2, trustManager(intermediate, "gugle.com", server), "gugle.com", - chain2); - } - - private X509TrustManager trustManager(X509Certificate ca) throws Exception { - KeyStore keyStore = TestKeyStore.createKeyStore(); - keyStore.setCertificateEntry("alias", ca); - - String algorithm = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); - tmf.init(keyStore); - return (X509TrustManager) tmf.getTrustManagers()[0]; - } - - private TrustManagerImpl trustManager(X509Certificate ca, String hostname, X509Certificate pin) - throws Exception { - // build the cert pin manager - CertPinManager cm = certManager(hostname, pin); - // insert it into the trust manager - KeyStore keyStore = TestKeyStore.createKeyStore(); - keyStore.setCertificateEntry("alias", ca); - return new TrustManagerImpl(keyStore, cm); - } - - private CertPinManager certManager(String hostname, X509Certificate pin) throws Exception { - String pinString = ""; - if (pin != null) { - pinString = hostname + "=true|" + getFingerprint(pin); - } - // write it to a pinfile - String path = writeTmpPinFile(pinString); - // build the certpinmanager - return new CertPinManager(path, new TrustedCertificateStore()); - } - - private void assertValid(X509Certificate[] chain, X509TrustManager tm) throws Exception { - if (tm instanceof TrustManagerImpl) { - TrustManagerImpl tmi = (TrustManagerImpl) tm; - tmi.checkServerTrusted(chain, "RSA"); - } - tm.checkServerTrusted(chain, "RSA"); - } - - private void assertValidPinned(X509Certificate[] chain, X509TrustManager tm, String hostname, - X509Certificate[] fullChain) throws Exception { - if (tm instanceof TrustManagerImpl) { - TrustManagerImpl tmi = (TrustManagerImpl) tm; - List<X509Certificate> checkedChain = tmi.checkServerTrusted(chain, "RSA", hostname); - assertEquals(checkedChain, Arrays.asList(fullChain)); - } - tm.checkServerTrusted(chain, "RSA"); - } - - private void assertInvalid(X509Certificate[] chain, X509TrustManager tm) { - try { - tm.checkClientTrusted(chain, "RSA"); - fail(); - } catch (CertificateException expected) { - } - try { - tm.checkServerTrusted(chain, "RSA"); - fail(); - } catch (CertificateException expected) { - } - } - - private void assertInvalidPinned(X509Certificate[] chain, X509TrustManager tm, String hostname) - throws Exception { - assertTrue(tm.getClass().getName(), tm instanceof TrustManagerImpl); - try { - TrustManagerImpl tmi = (TrustManagerImpl) tm; - tmi.checkServerTrusted(chain, "RSA", hostname); - fail(); - } catch (CertificateException expected) { - } - } -} diff --git a/crypto/src/test/java/org/conscrypt/TrustedCertificateStoreTest.java b/crypto/src/test/java/org/conscrypt/TrustedCertificateStoreTest.java deleted file mode 100644 index a8e9475..0000000 --- a/crypto/src/test/java/org/conscrypt/TrustedCertificateStoreTest.java +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright (C) 2011 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.conscrypt; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Set; -import javax.security.auth.x500.X500Principal; -import junit.framework.TestCase; -import libcore.java.security.TestKeyStore; - -public class TrustedCertificateStoreTest extends TestCase { - - private static final File DIR_TEMP = new File(System.getProperty("java.io.tmpdir")); - private static final File DIR_TEST = new File(DIR_TEMP, "test"); - private static final File DIR_SYSTEM = new File(DIR_TEST, "system"); - private static final File DIR_ADDED = new File(DIR_TEST, "added"); - private static final File DIR_DELETED = new File(DIR_TEST, "removed"); - - private static X509Certificate CA1; - private static X509Certificate CA2; - - private static KeyStore.PrivateKeyEntry PRIVATE; - private static X509Certificate[] CHAIN; - - private static X509Certificate CA3_WITH_CA1_SUBJECT; - private static String ALIAS_SYSTEM_CA1; - private static String ALIAS_SYSTEM_CA2; - private static String ALIAS_USER_CA1; - private static String ALIAS_USER_CA2; - - private static String ALIAS_SYSTEM_CHAIN0; - private static String ALIAS_SYSTEM_CHAIN1; - private static String ALIAS_SYSTEM_CHAIN2; - private static String ALIAS_USER_CHAIN0; - private static String ALIAS_USER_CHAIN1; - private static String ALIAS_USER_CHAIN2; - - private static String ALIAS_SYSTEM_CA3; - private static String ALIAS_SYSTEM_CA3_COLLISION; - private static String ALIAS_USER_CA3; - private static String ALIAS_USER_CA3_COLLISION; - - private static X509Certificate getCa1() { - initCerts(); - return CA1; - } - private static X509Certificate getCa2() { - initCerts(); - return CA2; - } - - private static KeyStore.PrivateKeyEntry getPrivate() { - initCerts(); - return PRIVATE; - } - private static X509Certificate[] getChain() { - initCerts(); - return CHAIN; - } - - private static X509Certificate getCa3WithCa1Subject() { - initCerts(); - return CA3_WITH_CA1_SUBJECT; - } - - private static String getAliasSystemCa1() { - initCerts(); - return ALIAS_SYSTEM_CA1; - } - private static String getAliasSystemCa2() { - initCerts(); - return ALIAS_SYSTEM_CA2; - } - private static String getAliasUserCa1() { - initCerts(); - return ALIAS_USER_CA1; - } - private static String getAliasUserCa2() { - initCerts(); - return ALIAS_USER_CA2; - } - - private static String getAliasSystemChain0() { - initCerts(); - return ALIAS_SYSTEM_CHAIN0; - } - private static String getAliasSystemChain1() { - initCerts(); - return ALIAS_SYSTEM_CHAIN1; - } - private static String getAliasSystemChain2() { - initCerts(); - return ALIAS_SYSTEM_CHAIN2; - } - private static String getAliasUserChain0() { - initCerts(); - return ALIAS_USER_CHAIN0; - } - private static String getAliasUserChain1() { - initCerts(); - return ALIAS_USER_CHAIN1; - } - private static String getAliasUserChain2() { - initCerts(); - return ALIAS_USER_CHAIN2; - } - - private static String getAliasSystemCa3() { - initCerts(); - return ALIAS_SYSTEM_CA3; - } - private static String getAliasSystemCa3Collision() { - initCerts(); - return ALIAS_SYSTEM_CA3_COLLISION; - } - private static String getAliasUserCa3() { - initCerts(); - return ALIAS_USER_CA3; - } - private static String getAliasUserCa3Collision() { - initCerts(); - return ALIAS_USER_CA3_COLLISION; - } - - /** - * Lazily create shared test certificates. - */ - private static synchronized void initCerts() { - if (CA1 != null) { - return; - } - try { - CA1 = TestKeyStore.getClient().getRootCertificate("RSA"); - CA2 = TestKeyStore.getClientCA2().getRootCertificate("RSA"); - PRIVATE = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); - CHAIN = (X509Certificate[]) PRIVATE.getCertificateChain(); - CA3_WITH_CA1_SUBJECT = new TestKeyStore.Builder() - .aliasPrefix("unused") - .subject(CA1.getSubjectX500Principal()) - .ca(true) - .build().getRootCertificate("RSA"); - - - ALIAS_SYSTEM_CA1 = alias(false, CA1, 0); - ALIAS_SYSTEM_CA2 = alias(false, CA2, 0); - ALIAS_USER_CA1 = alias(true, CA1, 0); - ALIAS_USER_CA2 = alias(true, CA2, 0); - - ALIAS_SYSTEM_CHAIN0 = alias(false, getChain()[0], 0); - ALIAS_SYSTEM_CHAIN1 = alias(false, getChain()[1], 0); - ALIAS_SYSTEM_CHAIN2 = alias(false, getChain()[2], 0); - ALIAS_USER_CHAIN0 = alias(true, getChain()[0], 0); - ALIAS_USER_CHAIN1 = alias(true, getChain()[1], 0); - ALIAS_USER_CHAIN2 = alias(true, getChain()[2], 0); - - ALIAS_SYSTEM_CA3 = alias(false, CA3_WITH_CA1_SUBJECT, 0); - ALIAS_SYSTEM_CA3_COLLISION = alias(false, CA3_WITH_CA1_SUBJECT, 1); - ALIAS_USER_CA3 = alias(true, CA3_WITH_CA1_SUBJECT, 0); - ALIAS_USER_CA3_COLLISION = alias(true, CA3_WITH_CA1_SUBJECT, 1); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private TrustedCertificateStore store; - - @Override protected void setUp() { - setupStore(); - } - - private void setupStore() { - DIR_SYSTEM.mkdirs(); - createStore(); - } - - private void createStore() { - store = new TrustedCertificateStore(DIR_SYSTEM, DIR_ADDED, DIR_DELETED); - } - - @Override protected void tearDown() { - cleanStore(); - } - - private void cleanStore() { - for (File dir : new File[] { DIR_SYSTEM, DIR_ADDED, DIR_DELETED, DIR_TEST }) { - File[] files = dir.listFiles(); - if (files == null) { - continue; - } - for (File file : files) { - assertTrue(file.delete()); - } - } - store = null; - } - - private void resetStore() { - cleanStore(); - setupStore(); - } - - public void testEmptyDirectories() throws Exception { - assertEmpty(); - } - - public void testOneSystemOneDeleted() throws Exception { - install(getCa1(), getAliasSystemCa1()); - store.deleteCertificateEntry(getAliasSystemCa1()); - assertEmpty(); - assertDeleted(getCa1(), getAliasSystemCa1()); - } - - public void testTwoSystemTwoDeleted() throws Exception { - install(getCa1(), getAliasSystemCa1()); - store.deleteCertificateEntry(getAliasSystemCa1()); - install(getCa2(), getAliasSystemCa2()); - store.deleteCertificateEntry(getAliasSystemCa2()); - assertEmpty(); - assertDeleted(getCa1(), getAliasSystemCa1()); - assertDeleted(getCa2(), getAliasSystemCa2()); - } - - public void testPartialFileIsIgnored() throws Exception { - File file = file(getAliasSystemCa1()); - OutputStream os = new FileOutputStream(file); - os.write(0); - os.close(); - assertTrue(file.exists()); - assertEmpty(); - assertTrue(file.exists()); - } - - private void assertEmpty() throws Exception { - try { - store.getCertificate(null); - fail(); - } catch (NullPointerException expected) { - } - assertNull(store.getCertificate("")); - - try { - store.getCreationDate(null); - fail(); - } catch (NullPointerException expected) { - } - assertNull(store.getCreationDate("")); - - Set<String> s = store.aliases(); - assertNotNull(s); - assertTrue(s.isEmpty()); - assertAliases(); - - Set<String> u = store.userAliases(); - assertNotNull(u); - assertTrue(u.isEmpty()); - - try { - store.containsAlias(null); - fail(); - } catch (NullPointerException expected) { - } - assertFalse(store.containsAlias("")); - - assertNull(store.getCertificateAlias(null)); - assertNull(store.getCertificateAlias(getCa1())); - - try { - store.isTrustAnchor(null); - fail(); - } catch (NullPointerException expected) { - } - assertFalse(store.isTrustAnchor(getCa1())); - - try { - store.findIssuer(null); - fail(); - } catch (NullPointerException expected) { - } - assertNull(store.findIssuer(getCa1())); - - try { - store.installCertificate(null); - fail(); - } catch (NullPointerException expected) { - } - - store.deleteCertificateEntry(null); - store.deleteCertificateEntry(""); - - String[] userFiles = DIR_ADDED.list(); - assertTrue(userFiles == null || userFiles.length == 0); - } - - public void testTwoSystem() throws Exception { - testTwo(getCa1(), getAliasSystemCa1(), - getCa2(), getAliasSystemCa2()); - } - - public void testTwoUser() throws Exception { - testTwo(getCa1(), getAliasUserCa1(), - getCa2(), getAliasUserCa2()); - } - - public void testOneSystemOneUser() throws Exception { - testTwo(getCa1(), getAliasSystemCa1(), - getCa2(), getAliasUserCa2()); - } - - public void testTwoSystemSameSubject() throws Exception { - testTwo(getCa1(), getAliasSystemCa1(), - getCa3WithCa1Subject(), getAliasSystemCa3Collision()); - } - - public void testTwoUserSameSubject() throws Exception { - testTwo(getCa1(), getAliasUserCa1(), - getCa3WithCa1Subject(), getAliasUserCa3Collision()); - - store.deleteCertificateEntry(getAliasUserCa1()); - assertDeleted(getCa1(), getAliasUserCa1()); - assertTombstone(getAliasUserCa1()); - assertRootCa(getCa3WithCa1Subject(), getAliasUserCa3Collision()); - assertAliases(getAliasUserCa3Collision()); - - store.deleteCertificateEntry(getAliasUserCa3Collision()); - assertDeleted(getCa3WithCa1Subject(), getAliasUserCa3Collision()); - assertNoTombstone(getAliasUserCa3Collision()); - assertNoTombstone(getAliasUserCa1()); - assertEmpty(); - } - - public void testOneSystemOneUserSameSubject() throws Exception { - testTwo(getCa1(), getAliasSystemCa1(), - getCa3WithCa1Subject(), getAliasUserCa3()); - testTwo(getCa1(), getAliasUserCa1(), - getCa3WithCa1Subject(), getAliasSystemCa3()); - } - - private void testTwo(X509Certificate x1, String alias1, - X509Certificate x2, String alias2) { - install(x1, alias1); - install(x2, alias2); - assertRootCa(x1, alias1); - assertRootCa(x2, alias2); - assertAliases(alias1, alias2); - } - - - public void testOneSystemOneUserOneDeleted() throws Exception { - install(getCa1(), getAliasSystemCa1()); - store.installCertificate(getCa2()); - store.deleteCertificateEntry(getAliasSystemCa1()); - assertDeleted(getCa1(), getAliasSystemCa1()); - assertRootCa(getCa2(), getAliasUserCa2()); - assertAliases(getAliasUserCa2()); - } - - public void testOneSystemOneUserOneDeletedSameSubject() throws Exception { - install(getCa1(), getAliasSystemCa1()); - store.installCertificate(getCa3WithCa1Subject()); - store.deleteCertificateEntry(getAliasSystemCa1()); - assertDeleted(getCa1(), getAliasSystemCa1()); - assertRootCa(getCa3WithCa1Subject(), getAliasUserCa3()); - assertAliases(getAliasUserCa3()); - } - - public void testUserMaskingSystem() throws Exception { - install(getCa1(), getAliasSystemCa1()); - install(getCa1(), getAliasUserCa1()); - assertMasked(getCa1(), getAliasSystemCa1()); - assertRootCa(getCa1(), getAliasUserCa1()); - assertAliases(getAliasSystemCa1(), getAliasUserCa1()); - } - - public void testChain() throws Exception { - testChain(getAliasSystemChain1(), getAliasSystemChain2()); - testChain(getAliasSystemChain1(), getAliasUserChain2()); - testChain(getAliasUserChain1(), getAliasSystemCa1()); - testChain(getAliasUserChain1(), getAliasUserChain2()); - } - - private void testChain(String alias1, String alias2) throws Exception { - install(getChain()[1], alias1); - install(getChain()[2], alias2); - assertIntermediateCa(getChain()[1], alias1); - assertRootCa(getChain()[2], alias2); - assertAliases(alias1, alias2); - assertEquals(getChain()[2], store.findIssuer(getChain()[1])); - assertEquals(getChain()[1], store.findIssuer(getChain()[0])); - - X509Certificate[] expected = getChain(); - List<X509Certificate> actualList = store.getCertificateChain(expected[0]); - - assertEquals("Generated CA list should be same length", expected.length, actualList.size()); - for (int i = 0; i < expected.length; i++) { - assertEquals("Chain value should be the same for position " + i, expected[i], - actualList.get(i)); - } - resetStore(); - } - - public void testMissingSystemDirectory() throws Exception { - cleanStore(); - createStore(); - assertEmpty(); - } - - public void testWithExistingUserDirectories() throws Exception { - DIR_ADDED.mkdirs(); - DIR_DELETED.mkdirs(); - install(getCa1(), getAliasSystemCa1()); - assertRootCa(getCa1(), getAliasSystemCa1()); - assertAliases(getAliasSystemCa1()); - } - - public void testIsTrustAnchorWithReissuedgetCa() throws Exception { - PublicKey publicKey = getPrivate().getCertificate().getPublicKey(); - PrivateKey privateKey = getPrivate().getPrivateKey(); - String name = "CN=CA4"; - X509Certificate ca1 = TestKeyStore.createCa(publicKey, privateKey, name); - Thread.sleep(1 * 1000); // wait to ensure CAs vary by expiration - X509Certificate ca2 = TestKeyStore.createCa(publicKey, privateKey, name); - assertFalse(ca1.equals(ca2)); - - String systemAlias = alias(false, ca1, 0); - install(ca1, systemAlias); - assertRootCa(ca1, systemAlias); - assertTrue(store.isTrustAnchor(ca2)); - assertEquals(ca1, store.findIssuer(ca2)); - resetStore(); - - String userAlias = alias(true, ca1, 0); - store.installCertificate(ca1); - assertRootCa(ca1, userAlias); - assertTrue(store.isTrustAnchor(ca2)); - assertEquals(ca1, store.findIssuer(ca2)); - resetStore(); - } - - public void testInstallEmpty() throws Exception { - store.installCertificate(getCa1()); - assertRootCa(getCa1(), getAliasUserCa1()); - assertAliases(getAliasUserCa1()); - - // reinstalling should not change anything - store.installCertificate(getCa1()); - assertRootCa(getCa1(), getAliasUserCa1()); - assertAliases(getAliasUserCa1()); - } - - public void testInstallEmptySystemExists() throws Exception { - install(getCa1(), getAliasSystemCa1()); - assertRootCa(getCa1(), getAliasSystemCa1()); - assertAliases(getAliasSystemCa1()); - - // reinstalling should not affect system CA - store.installCertificate(getCa1()); - assertRootCa(getCa1(), getAliasSystemCa1()); - assertAliases(getAliasSystemCa1()); - - } - - public void testInstallEmptyDeletedSystemExists() throws Exception { - install(getCa1(), getAliasSystemCa1()); - store.deleteCertificateEntry(getAliasSystemCa1()); - assertEmpty(); - assertDeleted(getCa1(), getAliasSystemCa1()); - - // installing should restore deleted system CA - store.installCertificate(getCa1()); - assertRootCa(getCa1(), getAliasSystemCa1()); - assertAliases(getAliasSystemCa1()); - } - - public void testDeleteEmpty() throws Exception { - store.deleteCertificateEntry(getAliasSystemCa1()); - assertEmpty(); - assertDeleted(getCa1(), getAliasSystemCa1()); - } - - public void testDeleteUser() throws Exception { - store.installCertificate(getCa1()); - assertRootCa(getCa1(), getAliasUserCa1()); - assertAliases(getAliasUserCa1()); - - store.deleteCertificateEntry(getAliasUserCa1()); - assertEmpty(); - assertDeleted(getCa1(), getAliasUserCa1()); - assertNoTombstone(getAliasUserCa1()); - } - - public void testDeleteSystem() throws Exception { - install(getCa1(), getAliasSystemCa1()); - assertRootCa(getCa1(), getAliasSystemCa1()); - assertAliases(getAliasSystemCa1()); - - store.deleteCertificateEntry(getAliasSystemCa1()); - assertEmpty(); - assertDeleted(getCa1(), getAliasSystemCa1()); - - // deleting again should not change anything - store.deleteCertificateEntry(getAliasSystemCa1()); - assertEmpty(); - assertDeleted(getCa1(), getAliasSystemCa1()); - } - - public void testIsUserAddedCertificate() throws Exception { - assertFalse(store.isUserAddedCertificate(getCa1())); - assertFalse(store.isUserAddedCertificate(getCa2())); - install(getCa1(), getAliasSystemCa1()); - assertFalse(store.isUserAddedCertificate(getCa1())); - assertFalse(store.isUserAddedCertificate(getCa2())); - install(getCa1(), getAliasUserCa1()); - assertTrue(store.isUserAddedCertificate(getCa1())); - assertFalse(store.isUserAddedCertificate(getCa2())); - install(getCa2(), getAliasUserCa2()); - assertTrue(store.isUserAddedCertificate(getCa1())); - assertTrue(store.isUserAddedCertificate(getCa2())); - store.deleteCertificateEntry(getAliasUserCa1()); - assertFalse(store.isUserAddedCertificate(getCa1())); - assertTrue(store.isUserAddedCertificate(getCa2())); - store.deleteCertificateEntry(getAliasUserCa2()); - assertFalse(store.isUserAddedCertificate(getCa1())); - assertFalse(store.isUserAddedCertificate(getCa2())); - } - - private void assertRootCa(X509Certificate x, String alias) { - assertIntermediateCa(x, alias); - assertEquals(x, store.findIssuer(x)); - } - - private void assertTrusted(X509Certificate x, String alias) { - assertEquals(x, store.getCertificate(alias)); - assertEquals(file(alias).lastModified(), store.getCreationDate(alias).getTime()); - assertTrue(store.containsAlias(alias)); - assertTrue(store.isTrustAnchor(x)); - } - - private void assertIntermediateCa(X509Certificate x, String alias) { - assertTrusted(x, alias); - assertEquals(alias, store.getCertificateAlias(x)); - } - - private void assertMasked(X509Certificate x, String alias) { - assertTrusted(x, alias); - assertFalse(alias.equals(store.getCertificateAlias(x))); - } - - private void assertDeleted(X509Certificate x, String alias) { - assertNull(store.getCertificate(alias)); - assertFalse(store.containsAlias(alias)); - assertNull(store.getCertificateAlias(x)); - assertFalse(store.isTrustAnchor(x)); - assertEquals(store.allSystemAliases().contains(alias), - store.getCertificate(alias, true) != null); - } - - private void assertTombstone(String alias) { - assertTrue(TrustedCertificateStore.isUser(alias)); - File file = file(alias); - assertTrue(file.exists()); - assertEquals(0, file.length()); - } - - private void assertNoTombstone(String alias) { - assertTrue(TrustedCertificateStore.isUser(alias)); - assertFalse(file(alias).exists()); - } - - private void assertAliases(String... aliases) { - Set<String> expected = new HashSet<String>(Arrays.asList(aliases)); - Set<String> actual = new HashSet<String>(); - for (String alias : store.aliases()) { - boolean system = TrustedCertificateStore.isSystem(alias); - boolean user = TrustedCertificateStore.isUser(alias); - if (system || user) { - assertEquals(system, store.allSystemAliases().contains(alias)); - assertEquals(user, store.userAliases().contains(alias)); - actual.add(alias); - } else { - throw new AssertionError(alias); - } - } - assertEquals(expected, actual); - } - - /** - * format a certificate alias - */ - private static String alias(boolean user, X509Certificate x, int index) { - String prefix = user ? "user:" : "system:"; - - X500Principal subject = x.getSubjectX500Principal(); - int intHash = NativeCrypto.X509_NAME_hash_old(subject); - String strHash = IntegralToString.intToHexString(intHash, false, 8); - - return prefix + strHash + '.' + index; - } - - /** - * Install certificate under specified alias - */ - private static void install(X509Certificate x, String alias) { - try { - File file = file(alias); - file.getParentFile().mkdirs(); - OutputStream out = new FileOutputStream(file); - out.write(x.getEncoded()); - out.close(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Compute file for an alias - */ - private static File file(String alias) { - File dir; - if (TrustedCertificateStore.isSystem(alias)) { - dir = DIR_SYSTEM; - } else if (TrustedCertificateStore.isUser(alias)) { - dir = DIR_ADDED; - } else { - throw new IllegalArgumentException(alias); - } - - int index = alias.lastIndexOf(":"); - if (index == -1) { - throw new IllegalArgumentException(alias); - } - String filename = alias.substring(index+1); - - return new File(dir, filename); - } -} |