external/boringssl: Sync to 171b54.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/8ca0b4127da11d766067ea6ec4122017ba0edb0e..171b5403ee767fa0f3aecd377867db6533c3eb8f
This also updates the build file to build as C99, so BoringSSL can use
variables in for loops.
Change-Id: I48ae985fd1bed244f7ed327aefc9a13e5b17b185
diff --git a/Android.mk b/Android.mk
index 3e3ef2a..0533986 100644
--- a/Android.mk
+++ b/Android.mk
@@ -4,6 +4,21 @@
LOCAL_PATH := $(call my-dir)
+boringssl_cflags := \
+ -fvisibility=hidden \
+ -DBORINGSSL_SHARED_LIBRARY \
+ -DBORINGSSL_IMPLEMENTATION \
+ -DOPENSSL_SMALL \
+ -D_XOPEN_SOURCE=700 \
+ -Wno-unused-parameter
+
+boringssl_cppflags := \
+ -Wall \
+ -Werror
+
+boringssl_conlyflags := \
+ -std=c99
+
## libcrypto
# Target static library
@@ -13,7 +28,9 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/crypto-sources.mk
LOCAL_SDK_VERSION := 9
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
# sha256-armv4.S does not compile with clang.
LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
LOCAL_CLANG_ASFLAGS_arm64 += -march=armv8-a+crypto
@@ -26,8 +43,10 @@
LOCAL_MODULE := libcrypto
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/crypto-sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
LOCAL_SDK_VERSION := 9
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
# sha256-armv4.S does not compile with clang.
LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
LOCAL_CLANG_ASFLAGS_arm64 += -march=armv8-a+crypto
@@ -36,12 +55,13 @@
# Target static tool
include $(CLEAR_VARS)
-LOCAL_CFLAGS += -Wall -Werror -std=c++0x
LOCAL_CPP_EXTENSION := cc
LOCAL_MODULE := bssl
LOCAL_MODULE_TAGS := optional
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
LOCAL_SHARED_LIBRARIES=libcrypto libssl
include $(LOCAL_PATH)/sources.mk
LOCAL_SRC_FILES = $(tool_sources)
@@ -54,7 +74,9 @@
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/crypto-sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
LOCAL_CXX_STL := none
# Windows and Macs both have problems with assembly files
LOCAL_CFLAGS_darwin += -DOPENSSL_NO_ASM
@@ -75,7 +97,9 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_MULTILIB := both
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/crypto-sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
# Windows and Macs both have problems with assembly files
LOCAL_CFLAGS_darwin += -DOPENSSL_NO_ASM
LOCAL_CFLAGS_windows += -DOPENSSL_NO_ASM
@@ -95,7 +119,9 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/ssl-sources.mk
LOCAL_SDK_VERSION := 9
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
include $(LOCAL_PATH)/ssl-sources.mk
include $(BUILD_STATIC_LIBRARY)
@@ -105,7 +131,9 @@
LOCAL_MODULE := libssl
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/ssl-sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
LOCAL_SHARED_LIBRARIES=libcrypto
LOCAL_SDK_VERSION := 9
include $(LOCAL_PATH)/ssl-sources.mk
@@ -117,7 +145,9 @@
LOCAL_MODULE := libssl_static-host
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/ssl-sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
LOCAL_CXX_STL := none
# TODO: b/26097626. ASAN breaks use of this library in JVM.
# Re-enable sanitization when the issue with making clients of this library
@@ -131,12 +161,13 @@
# Host static tool (for linux only).
ifeq ($(HOST_OS), linux)
include $(CLEAR_VARS)
-LOCAL_CFLAGS += -Wall -Werror -std=c++0x
LOCAL_CPP_EXTENSION := cc
LOCAL_MODULE := bssl
LOCAL_MODULE_TAGS := optional
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
LOCAL_SHARED_LIBRARIES=libcrypto-host libssl-host
# Needed for clock_gettime.
LOCAL_LDFLAGS := -lrt
@@ -152,7 +183,9 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/src/include
LOCAL_MULTILIB := both
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/ssl-sources.mk
-LOCAL_CFLAGS += -fvisibility=hidden -DBORINGSSL_SHARED_LIBRARY -DBORINGSSL_IMPLEMENTATION -DOPENSSL_SMALL -Wno-unused-parameter
+LOCAL_CFLAGS := $(boringssl_cflags)
+LOCAL_CPPFLAGS := $(boringssl_cppflags)
+LOCAL_CONLYFLAGS := $(boringssl_conlyflags)
LOCAL_CXX_STL := none
LOCAL_SHARED_LIBRARIES += libcrypto-host
include $(LOCAL_PATH)/ssl-sources.mk
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index 9a5595e..7d2e238 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-8ca0b4127da11d766067ea6ec4122017ba0edb0e
+171b5403ee767fa0f3aecd377867db6533c3eb8f
diff --git a/linux-x86/crypto/chacha/chacha-x86.S b/linux-x86/crypto/chacha/chacha-x86.S
index f28459e..d3c39ac 100644
--- a/linux-x86/crypto/chacha/chacha-x86.S
+++ b/linux-x86/crypto/chacha/chacha-x86.S
@@ -261,13 +261,11 @@
xorl 36(%ebx),%esi
xorl 48(%ebx),%edx
xorl 56(%ebx),%edi
- movl %ebp,16(%esp)
- movl (%esp),%ebp
- movl %ecx,32(%esp)
- movl %esi,36(%esp)
- movl %edx,48(%esp)
- movl %edi,56(%esp)
- movl %ebp,(%eax)
+ movl %ebp,16(%eax)
+ movl %ecx,32(%eax)
+ movl %esi,36(%eax)
+ movl %edx,48(%eax)
+ movl %edi,56(%eax)
movl 4(%esp),%ebp
movl 8(%esp),%ecx
movl 12(%esp),%esi
@@ -284,42 +282,34 @@
xorl 20(%ebx),%edx
xorl 24(%ebx),%edi
movl %ebp,4(%eax)
- movl 16(%esp),%ebp
movl %ecx,8(%eax)
movl %esi,12(%eax)
- movl %ebp,16(%eax)
movl %edx,20(%eax)
movl %edi,24(%eax)
- movl 28(%esp),%ecx
- movl 32(%esp),%edx
- movl 36(%esp),%edi
- addl 92(%esp),%ecx
- movl 40(%esp),%ebp
- xorl 28(%ebx),%ecx
+ movl 28(%esp),%ebp
+ movl 40(%esp),%ecx
movl 44(%esp),%esi
- movl %ecx,28(%eax)
- movl %edx,32(%eax)
- movl %edi,36(%eax)
- addl 104(%esp),%ebp
- addl 108(%esp),%esi
- xorl 40(%ebx),%ebp
- xorl 44(%ebx),%esi
- movl %ebp,40(%eax)
- movl %esi,44(%eax)
- movl 48(%esp),%ecx
- movl 56(%esp),%esi
movl 52(%esp),%edx
movl 60(%esp),%edi
+ addl 92(%esp),%ebp
+ addl 104(%esp),%ecx
+ addl 108(%esp),%esi
addl 116(%esp),%edx
addl 124(%esp),%edi
+ xorl 28(%ebx),%ebp
+ xorl 40(%ebx),%ecx
+ xorl 44(%ebx),%esi
xorl 52(%ebx),%edx
xorl 60(%ebx),%edi
leal 64(%ebx),%ebx
- movl %ecx,48(%eax)
+ movl %ebp,28(%eax)
+ movl (%esp),%ebp
+ movl %ecx,40(%eax)
movl 160(%esp),%ecx
+ movl %esi,44(%eax)
movl %edx,52(%eax)
- movl %esi,56(%eax)
movl %edi,60(%eax)
+ movl %ebp,(%eax)
leal 64(%eax),%eax
subl $64,%ecx
jnz .L003outer_loop
@@ -715,14 +705,24 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,-128(%ebx)
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 16(%esi),%esi
+ pxor %xmm0,%xmm4
movdqa -64(%ebx),%xmm0
- movdqa %xmm1,-112(%ebx)
- movdqa %xmm6,-96(%ebx)
- movdqa %xmm3,-80(%ebx)
+ pxor %xmm1,%xmm5
movdqa -48(%ebx),%xmm1
+ pxor %xmm2,%xmm6
movdqa -32(%ebx),%xmm2
+ pxor %xmm3,%xmm7
movdqa -16(%ebx),%xmm3
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 16(%edi),%edi
paddd -64(%ebp),%xmm0
paddd -48(%ebp),%xmm1
paddd -32(%ebp),%xmm2
@@ -739,14 +739,24 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,-64(%ebx)
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 16(%esi),%esi
+ pxor %xmm0,%xmm4
movdqa (%ebx),%xmm0
- movdqa %xmm1,-48(%ebx)
- movdqa %xmm6,-32(%ebx)
- movdqa %xmm3,-16(%ebx)
+ pxor %xmm1,%xmm5
movdqa 16(%ebx),%xmm1
+ pxor %xmm2,%xmm6
movdqa 32(%ebx),%xmm2
+ pxor %xmm3,%xmm7
movdqa 48(%ebx),%xmm3
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 16(%edi),%edi
paddd (%ebp),%xmm0
paddd 16(%ebp),%xmm1
paddd 32(%ebp),%xmm2
@@ -763,14 +773,24 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,(%ebx)
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 16(%esi),%esi
+ pxor %xmm0,%xmm4
movdqa 64(%ebx),%xmm0
- movdqa %xmm1,16(%ebx)
- movdqa %xmm6,32(%ebx)
- movdqa %xmm3,48(%ebx)
+ pxor %xmm1,%xmm5
movdqa 80(%ebx),%xmm1
+ pxor %xmm2,%xmm6
movdqa 96(%ebx),%xmm2
+ pxor %xmm3,%xmm7
movdqa 112(%ebx),%xmm3
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 16(%edi),%edi
paddd 64(%ebp),%xmm0
paddd 80(%ebp),%xmm1
paddd 96(%ebp),%xmm2
@@ -787,60 +807,20 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,64(%ebx)
- movdqa %xmm1,80(%ebx)
- movdqa %xmm6,96(%ebx)
- movdqa %xmm3,112(%ebx)
- movdqu -128(%esi),%xmm0
- movdqu -112(%esi),%xmm1
- movdqu -96(%esi),%xmm2
- movdqu -80(%esi),%xmm3
- pxor -128(%ebx),%xmm0
- pxor -64(%ebx),%xmm1
- pxor (%ebx),%xmm2
- pxor 64(%ebx),%xmm3
- movdqu %xmm0,-128(%edi)
- movdqu %xmm1,-112(%edi)
- movdqu %xmm2,-96(%edi)
- movdqu %xmm3,-80(%edi)
- movdqu -64(%esi),%xmm0
- movdqu -48(%esi),%xmm1
- movdqu -32(%esi),%xmm2
- movdqu -16(%esi),%xmm3
- pxor -112(%ebx),%xmm0
- pxor -48(%ebx),%xmm1
- pxor 16(%ebx),%xmm2
- pxor 80(%ebx),%xmm3
- movdqu %xmm0,-64(%edi)
- movdqu %xmm1,-48(%edi)
- movdqu %xmm2,-32(%edi)
- movdqu %xmm3,-16(%edi)
- movdqu (%esi),%xmm0
- movdqu 16(%esi),%xmm1
- movdqu 32(%esi),%xmm2
- movdqu 48(%esi),%xmm3
- pxor -96(%ebx),%xmm0
- pxor -32(%ebx),%xmm1
- pxor 32(%ebx),%xmm2
- pxor 96(%ebx),%xmm3
- movdqu %xmm0,(%edi)
- movdqu %xmm1,16(%edi)
- movdqu %xmm2,32(%edi)
- movdqu %xmm3,48(%edi)
- movdqu 64(%esi),%xmm0
- movdqu 80(%esi),%xmm1
- movdqu 96(%esi),%xmm2
- movdqu 112(%esi),%xmm3
- pxor -80(%ebx),%xmm0
- pxor -16(%ebx),%xmm1
- pxor 48(%ebx),%xmm2
- pxor 112(%ebx),%xmm3
- movdqu %xmm0,64(%edi)
- movdqu %xmm1,80(%edi)
- movdqu %xmm2,96(%edi)
- movdqu %xmm3,112(%edi)
- leal 256(%esi),%esi
- leal 256(%edi),%edi
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 208(%esi),%esi
+ pxor %xmm0,%xmm4
+ pxor %xmm1,%xmm5
+ pxor %xmm2,%xmm6
+ pxor %xmm3,%xmm7
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 208(%edi),%edi
subl $256,%ecx
jnc .L009outer_loop
addl $256,%ecx
diff --git a/mac-x86/crypto/chacha/chacha-x86.S b/mac-x86/crypto/chacha/chacha-x86.S
index 9bd31b8..5de98a3 100644
--- a/mac-x86/crypto/chacha/chacha-x86.S
+++ b/mac-x86/crypto/chacha/chacha-x86.S
@@ -260,13 +260,11 @@
xorl 36(%ebx),%esi
xorl 48(%ebx),%edx
xorl 56(%ebx),%edi
- movl %ebp,16(%esp)
- movl (%esp),%ebp
- movl %ecx,32(%esp)
- movl %esi,36(%esp)
- movl %edx,48(%esp)
- movl %edi,56(%esp)
- movl %ebp,(%eax)
+ movl %ebp,16(%eax)
+ movl %ecx,32(%eax)
+ movl %esi,36(%eax)
+ movl %edx,48(%eax)
+ movl %edi,56(%eax)
movl 4(%esp),%ebp
movl 8(%esp),%ecx
movl 12(%esp),%esi
@@ -283,42 +281,34 @@
xorl 20(%ebx),%edx
xorl 24(%ebx),%edi
movl %ebp,4(%eax)
- movl 16(%esp),%ebp
movl %ecx,8(%eax)
movl %esi,12(%eax)
- movl %ebp,16(%eax)
movl %edx,20(%eax)
movl %edi,24(%eax)
- movl 28(%esp),%ecx
- movl 32(%esp),%edx
- movl 36(%esp),%edi
- addl 92(%esp),%ecx
- movl 40(%esp),%ebp
- xorl 28(%ebx),%ecx
+ movl 28(%esp),%ebp
+ movl 40(%esp),%ecx
movl 44(%esp),%esi
- movl %ecx,28(%eax)
- movl %edx,32(%eax)
- movl %edi,36(%eax)
- addl 104(%esp),%ebp
- addl 108(%esp),%esi
- xorl 40(%ebx),%ebp
- xorl 44(%ebx),%esi
- movl %ebp,40(%eax)
- movl %esi,44(%eax)
- movl 48(%esp),%ecx
- movl 56(%esp),%esi
movl 52(%esp),%edx
movl 60(%esp),%edi
+ addl 92(%esp),%ebp
+ addl 104(%esp),%ecx
+ addl 108(%esp),%esi
addl 116(%esp),%edx
addl 124(%esp),%edi
+ xorl 28(%ebx),%ebp
+ xorl 40(%ebx),%ecx
+ xorl 44(%ebx),%esi
xorl 52(%ebx),%edx
xorl 60(%ebx),%edi
leal 64(%ebx),%ebx
- movl %ecx,48(%eax)
+ movl %ebp,28(%eax)
+ movl (%esp),%ebp
+ movl %ecx,40(%eax)
movl 160(%esp),%ecx
+ movl %esi,44(%eax)
movl %edx,52(%eax)
- movl %esi,56(%eax)
movl %edi,60(%eax)
+ movl %ebp,(%eax)
leal 64(%eax),%eax
subl $64,%ecx
jnz L003outer_loop
@@ -712,14 +702,24 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,-128(%ebx)
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 16(%esi),%esi
+ pxor %xmm0,%xmm4
movdqa -64(%ebx),%xmm0
- movdqa %xmm1,-112(%ebx)
- movdqa %xmm6,-96(%ebx)
- movdqa %xmm3,-80(%ebx)
+ pxor %xmm1,%xmm5
movdqa -48(%ebx),%xmm1
+ pxor %xmm2,%xmm6
movdqa -32(%ebx),%xmm2
+ pxor %xmm3,%xmm7
movdqa -16(%ebx),%xmm3
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 16(%edi),%edi
paddd -64(%ebp),%xmm0
paddd -48(%ebp),%xmm1
paddd -32(%ebp),%xmm2
@@ -736,14 +736,24 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,-64(%ebx)
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 16(%esi),%esi
+ pxor %xmm0,%xmm4
movdqa (%ebx),%xmm0
- movdqa %xmm1,-48(%ebx)
- movdqa %xmm6,-32(%ebx)
- movdqa %xmm3,-16(%ebx)
+ pxor %xmm1,%xmm5
movdqa 16(%ebx),%xmm1
+ pxor %xmm2,%xmm6
movdqa 32(%ebx),%xmm2
+ pxor %xmm3,%xmm7
movdqa 48(%ebx),%xmm3
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 16(%edi),%edi
paddd (%ebp),%xmm0
paddd 16(%ebp),%xmm1
paddd 32(%ebp),%xmm2
@@ -760,14 +770,24 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,(%ebx)
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 16(%esi),%esi
+ pxor %xmm0,%xmm4
movdqa 64(%ebx),%xmm0
- movdqa %xmm1,16(%ebx)
- movdqa %xmm6,32(%ebx)
- movdqa %xmm3,48(%ebx)
+ pxor %xmm1,%xmm5
movdqa 80(%ebx),%xmm1
+ pxor %xmm2,%xmm6
movdqa 96(%ebx),%xmm2
+ pxor %xmm3,%xmm7
movdqa 112(%ebx),%xmm3
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 16(%edi),%edi
paddd 64(%ebp),%xmm0
paddd 80(%ebp),%xmm1
paddd 96(%ebp),%xmm2
@@ -784,60 +804,20 @@
punpcklqdq %xmm7,%xmm6
punpckhqdq %xmm2,%xmm1
punpckhqdq %xmm7,%xmm3
- movdqa %xmm0,64(%ebx)
- movdqa %xmm1,80(%ebx)
- movdqa %xmm6,96(%ebx)
- movdqa %xmm3,112(%ebx)
- movdqu -128(%esi),%xmm0
- movdqu -112(%esi),%xmm1
- movdqu -96(%esi),%xmm2
- movdqu -80(%esi),%xmm3
- pxor -128(%ebx),%xmm0
- pxor -64(%ebx),%xmm1
- pxor (%ebx),%xmm2
- pxor 64(%ebx),%xmm3
- movdqu %xmm0,-128(%edi)
- movdqu %xmm1,-112(%edi)
- movdqu %xmm2,-96(%edi)
- movdqu %xmm3,-80(%edi)
- movdqu -64(%esi),%xmm0
- movdqu -48(%esi),%xmm1
- movdqu -32(%esi),%xmm2
- movdqu -16(%esi),%xmm3
- pxor -112(%ebx),%xmm0
- pxor -48(%ebx),%xmm1
- pxor 16(%ebx),%xmm2
- pxor 80(%ebx),%xmm3
- movdqu %xmm0,-64(%edi)
- movdqu %xmm1,-48(%edi)
- movdqu %xmm2,-32(%edi)
- movdqu %xmm3,-16(%edi)
- movdqu (%esi),%xmm0
- movdqu 16(%esi),%xmm1
- movdqu 32(%esi),%xmm2
- movdqu 48(%esi),%xmm3
- pxor -96(%ebx),%xmm0
- pxor -32(%ebx),%xmm1
- pxor 32(%ebx),%xmm2
- pxor 96(%ebx),%xmm3
- movdqu %xmm0,(%edi)
- movdqu %xmm1,16(%edi)
- movdqu %xmm2,32(%edi)
- movdqu %xmm3,48(%edi)
- movdqu 64(%esi),%xmm0
- movdqu 80(%esi),%xmm1
- movdqu 96(%esi),%xmm2
- movdqu 112(%esi),%xmm3
- pxor -80(%ebx),%xmm0
- pxor -16(%ebx),%xmm1
- pxor 48(%ebx),%xmm2
- pxor 112(%ebx),%xmm3
- movdqu %xmm0,64(%edi)
- movdqu %xmm1,80(%edi)
- movdqu %xmm2,96(%edi)
- movdqu %xmm3,112(%edi)
- leal 256(%esi),%esi
- leal 256(%edi),%edi
+ movdqu -128(%esi),%xmm4
+ movdqu -64(%esi),%xmm5
+ movdqu (%esi),%xmm2
+ movdqu 64(%esi),%xmm7
+ leal 208(%esi),%esi
+ pxor %xmm0,%xmm4
+ pxor %xmm1,%xmm5
+ pxor %xmm2,%xmm6
+ pxor %xmm3,%xmm7
+ movdqu %xmm4,-128(%edi)
+ movdqu %xmm5,-64(%edi)
+ movdqu %xmm6,(%edi)
+ movdqu %xmm7,64(%edi)
+ leal 208(%edi),%edi
subl $256,%ecx
jnc L009outer_loop
addl $256,%ecx
diff --git a/sources.mk b/sources.mk
index 7ed59a1..14bf8f1 100644
--- a/sources.mk
+++ b/sources.mk
@@ -293,21 +293,19 @@
ssl_sources := \
src/ssl/custom_extensions.c\
src/ssl/d1_both.c\
- src/ssl/d1_clnt.c\
src/ssl/d1_lib.c\
src/ssl/d1_meth.c\
src/ssl/d1_pkt.c\
src/ssl/d1_srtp.c\
- src/ssl/d1_srvr.c\
src/ssl/dtls_record.c\
+ src/ssl/handshake_client.c\
+ src/ssl/handshake_server.c\
src/ssl/pqueue/pqueue.c\
src/ssl/s3_both.c\
- src/ssl/s3_clnt.c\
src/ssl/s3_enc.c\
src/ssl/s3_lib.c\
src/ssl/s3_meth.c\
src/ssl/s3_pkt.c\
- src/ssl/s3_srvr.c\
src/ssl/ssl_aead_ctx.c\
src/ssl/ssl_asn1.c\
src/ssl/ssl_buffer.c\
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3c5db63..bd7f432 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -98,9 +98,18 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
endif()
-if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR
- CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_XOPEN_SOURCE=700")
+if(CMAKE_COMPILER_IS_GNUCXX)
+ if ((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR
+ CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
+ else()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
+ endif()
+endif()
+
+# pthread_rwlock_t requires a feature flag.
+if(NOT WIN32)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_XOPEN_SOURCE=700")
endif()
if(FUZZ)
diff --git a/src/STYLE.md b/src/STYLE.md
index 4d2c5de..17295b4 100644
--- a/src/STYLE.md
+++ b/src/STYLE.md
@@ -14,10 +14,10 @@
given rule. Module-wide deviations on naming should be respected while
integer and return value conventions take precedence over consistency.
-Some modules have seen few changes, so they still retain the original
-indentation style for now. When editing these, try to retain the
-original style. For Emacs, `doc/c-indentation.el` from OpenSSL may be
-helpful in this.
+Modules from OpenSSL's legacy ASN.1 and X.509 stack are retained for
+compatibility and left largely unmodified. To ease importing patches from
+upstream, they match OpenSSL's new indentation style. For Emacs,
+`doc/openssl-c-indent.el` from OpenSSL may be helpful in this.
## Language
diff --git a/src/crypto/asn1/a_strnid.c b/src/crypto/asn1/a_strnid.c
index ba1224e..c558bce 100644
--- a/src/crypto/asn1/a_strnid.c
+++ b/src/crypto/asn1/a_strnid.c
@@ -247,6 +247,7 @@
}
tmp->flags = flags | STABLE_FLAGS_MALLOC;
tmp->nid = nid;
+ tmp->minsize = tmp->maxsize = -1;
new_nid = 1;
} else
tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags;
diff --git a/src/crypto/asn1/bio_asn1.c b/src/crypto/asn1/bio_asn1.c
index 03cc9a6..45ad7e5 100644
--- a/src/crypto/asn1/bio_asn1.c
+++ b/src/crypto/asn1/bio_asn1.c
@@ -165,10 +165,12 @@
ctx->copylen = 0;
ctx->asn1_class = V_ASN1_UNIVERSAL;
ctx->asn1_tag = V_ASN1_OCTET_STRING;
- ctx->ex_buf = 0;
- ctx->ex_pos = 0;
+ ctx->ex_buf = NULL;
ctx->ex_len = 0;
+ ctx->ex_pos = 0;
ctx->state = ASN1_STATE_START;
+ ctx->prefix = ctx->prefix_free = ctx->suffix = ctx->suffix_free = NULL;
+ ctx->ex_arg = NULL;
return 1;
}
diff --git a/src/crypto/asn1/bio_ndef.c b/src/crypto/asn1/bio_ndef.c
index 81a8aa7..488457b 100644
--- a/src/crypto/asn1/bio_ndef.c
+++ b/src/crypto/asn1/bio_ndef.c
@@ -139,6 +139,7 @@
ndef_aux->ndef_bio = sarg.ndef_bio;
ndef_aux->boundary = sarg.boundary;
ndef_aux->out = out;
+ ndef_aux->derbuf = NULL;
BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc
index 3615ab4..f2eb20b 100644
--- a/src/crypto/bio/bio_test.cc
+++ b/src/crypto/bio/bio_test.cc
@@ -27,10 +27,10 @@
#include <unistd.h>
#else
#include <io.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/bio.h>
diff --git a/src/crypto/bio/connect.c b/src/crypto/bio/connect.c
index 01d49b1..7e54447 100644
--- a/src/crypto/bio/connect.c
+++ b/src/crypto/bio/connect.c
@@ -66,10 +66,10 @@
#include <arpa/inet.h>
#include <unistd.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/buf.h>
@@ -538,6 +538,12 @@
return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
}
+int BIO_set_conn_int_port(BIO *bio, const int *port) {
+ char buf[DECIMAL_SIZE(int) + 1];
+ BIO_snprintf(buf, sizeof(buf), "%d", *port);
+ return BIO_set_conn_port(bio, buf);
+}
+
int BIO_set_nbio(BIO *bio, int on) {
return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
}
diff --git a/src/crypto/bio/fd.c b/src/crypto/bio/fd.c
index 7d94843..13833df 100644
--- a/src/crypto/bio/fd.c
+++ b/src/crypto/bio/fd.c
@@ -63,9 +63,9 @@
#include <unistd.h>
#else
#include <io.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/buf.h>
diff --git a/src/crypto/bio/internal.h b/src/crypto/bio/internal.h
index eb6b26f..4ec77fa 100644
--- a/src/crypto/bio/internal.h
+++ b/src/crypto/bio/internal.h
@@ -67,9 +67,9 @@
#include <sys/types.h>
#include <sys/socket.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
typedef int socklen_t;
#endif
diff --git a/src/crypto/bio/socket.c b/src/crypto/bio/socket.c
index 3ef6967..0520c3e 100644
--- a/src/crypto/bio/socket.c
+++ b/src/crypto/bio/socket.c
@@ -63,9 +63,9 @@
#if !defined(OPENSSL_WINDOWS)
#include <unistd.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma comment(lib, "Ws2_32.lib")
#endif
diff --git a/src/crypto/bio/socket_helper.c b/src/crypto/bio/socket_helper.c
index 4ddc094..9500788 100644
--- a/src/crypto/bio/socket_helper.c
+++ b/src/crypto/bio/socket_helper.c
@@ -26,10 +26,10 @@
#include <netdb.h>
#include <unistd.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include "internal.h"
diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc
index fe8cfd0..d909ee2 100644
--- a/src/crypto/bn/bn_test.cc
+++ b/src/crypto/bn/bn_test.cc
@@ -850,11 +850,17 @@
return false;
}
BN_ULONG s = b->d[0];
+ BN_ULONG rmod = BN_mod_word(b.get(), s);
BN_ULONG r = BN_div_word(b.get(), s);
if (r == (BN_ULONG)-1) {
return false;
}
+ if (rmod != r) {
+ fprintf(stderr, "Mod (word) test failed!\n");
+ return false;
+ }
+
if (fp != NULL) {
BN_print_fp(fp, a.get());
puts_fp(fp, " / ");
diff --git a/src/crypto/bn/div.c b/src/crypto/bn/div.c
index 6f67291..e824458 100644
--- a/src/crypto/bn/div.c
+++ b/src/crypto/bn/div.c
@@ -644,6 +644,20 @@
return (BN_ULONG) -1;
}
+#ifndef BN_ULLONG
+ /* If |w| is too long and we don't have |BN_ULLONG| then we need to fall back
+ * to using |BN_div_word|. */
+ if (w > ((BN_ULONG)1 << BN_BITS4)) {
+ BIGNUM *tmp = BN_dup(a);
+ if (tmp == NULL) {
+ return (BN_ULONG)-1;
+ }
+ ret = BN_div_word(tmp, w);
+ BN_free(tmp);
+ return ret;
+ }
+#endif
+
w &= BN_MASK2;
for (i = a->top - 1; i >= 0; i--) {
#ifndef BN_ULLONG
diff --git a/src/crypto/bn/internal.h b/src/crypto/bn/internal.h
index 0a2982c..8b1c866 100644
--- a/src/crypto/bn/internal.h
+++ b/src/crypto/bn/internal.h
@@ -126,9 +126,9 @@
#include <openssl/base.h>
#if defined(OPENSSL_X86_64) && defined(_MSC_VER)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <intrin.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma intrinsic(__umulh, _umul128)
#endif
diff --git a/src/crypto/bytestring/bytestring_test.cc b/src/crypto/bytestring/bytestring_test.cc
index 84ecffc..e1d16f4 100644
--- a/src/crypto/bytestring/bytestring_test.cc
+++ b/src/crypto/bytestring/bytestring_test.cc
@@ -43,7 +43,7 @@
}
static bool TestGetUint() {
- static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
uint8_t u8;
uint16_t u16;
uint32_t u32;
@@ -58,7 +58,10 @@
u32 == 0x40506 &&
CBS_get_u32(&data, &u32) &&
u32 == 0x708090a &&
- !CBS_get_u8(&data, &u8);
+ CBS_get_last_u8(&data, &u8) &&
+ u8 == 0xb &&
+ !CBS_get_u8(&data, &u8) &&
+ !CBS_get_last_u8(&data, &u8);
}
static bool TestGetPrefixed() {
diff --git a/src/crypto/bytestring/cbs.c b/src/crypto/bytestring/cbs.c
index ed54b49..c86afbd 100644
--- a/src/crypto/bytestring/cbs.c
+++ b/src/crypto/bytestring/cbs.c
@@ -128,6 +128,15 @@
return cbs_get_u(cbs, out, 4);
}
+int CBS_get_last_u8(CBS *cbs, uint8_t *out) {
+ if (cbs->len == 0) {
+ return 0;
+ }
+ *out = cbs->data[cbs->len - 1];
+ cbs->len--;
+ return 1;
+}
+
int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) {
const uint8_t *v;
if (!cbs_get(cbs, &v, len)) {
diff --git a/src/crypto/chacha/asm/chacha-x86.pl b/src/crypto/chacha/asm/chacha-x86.pl
index e576029..edce43d 100755
--- a/src/crypto/chacha/asm/chacha-x86.pl
+++ b/src/crypto/chacha/asm/chacha-x86.pl
@@ -19,13 +19,13 @@
# P4 18.6/+84%
# Core2 9.56/+89% 4.83
# Westmere 9.50/+45% 3.35
-# Sandy Bridge 10.7/+47% 3.24
-# Haswell 8.22/+50% 2.89
-# Silvermont 17.8/+36% 8.53
+# Sandy Bridge 10.5/+47% 3.20
+# Haswell 8.15/+50% 2.83
+# Silvermont 17.4/+36% 8.35
# Sledgehammer 10.2/+54%
-# Bulldozer 13.5/+50% 4.39(*)
+# Bulldozer 13.4/+50% 4.38(*)
#
-# (*) Bulldozer actually executes 4xXOP code path that delivers 3.50;
+# (*) Bulldozer actually executes 4xXOP code path that delivers 3.55;
#
# Modified from upstream OpenSSL to remove the XOP code.
@@ -224,20 +224,18 @@
&xor ($a, &DWP(4*0,$b)); # xor with input
&xor ($b_,&DWP(4*4,$b));
- &mov (&DWP(4*0,"esp"),$a); # off-load for later write
+ &mov (&DWP(4*0,"esp"),$a);
&mov ($a,&wparam(0)); # load output pointer
&xor ($c, &DWP(4*8,$b));
&xor ($c_,&DWP(4*9,$b));
&xor ($d, &DWP(4*12,$b));
&xor ($d_,&DWP(4*14,$b));
- &mov (&DWP(4*4,"esp"),$b_);
- &mov ($b_,&DWP(4*0,"esp"));
- &mov (&DWP(4*8,"esp"),$c);
- &mov (&DWP(4*9,"esp"),$c_);
- &mov (&DWP(4*12,"esp"),$d);
- &mov (&DWP(4*14,"esp"),$d_);
+ &mov (&DWP(4*4,$a),$b_); # write output
+ &mov (&DWP(4*8,$a),$c);
+ &mov (&DWP(4*9,$a),$c_);
+ &mov (&DWP(4*12,$a),$d);
+ &mov (&DWP(4*14,$a),$d_);
- &mov (&DWP(4*0,$a),$b_); # write output in order
&mov ($b_,&DWP(4*1,"esp"));
&mov ($c, &DWP(4*2,"esp"));
&mov ($c_,&DWP(4*3,"esp"));
@@ -254,45 +252,35 @@
&xor ($d, &DWP(4*5,$b));
&xor ($d_,&DWP(4*6,$b));
&mov (&DWP(4*1,$a),$b_);
- &mov ($b_,&DWP(4*4,"esp"));
&mov (&DWP(4*2,$a),$c);
&mov (&DWP(4*3,$a),$c_);
- &mov (&DWP(4*4,$a),$b_);
&mov (&DWP(4*5,$a),$d);
&mov (&DWP(4*6,$a),$d_);
- &mov ($c,&DWP(4*7,"esp"));
- &mov ($d,&DWP(4*8,"esp"));
- &mov ($d_,&DWP(4*9,"esp"));
- &add ($c,&DWP(64+4*7,"esp"));
- &mov ($b_, &DWP(4*10,"esp"));
- &xor ($c,&DWP(4*7,$b));
+ &mov ($b_,&DWP(4*7,"esp"));
+ &mov ($c, &DWP(4*10,"esp"));
&mov ($c_,&DWP(4*11,"esp"));
- &mov (&DWP(4*7,$a),$c);
- &mov (&DWP(4*8,$a),$d);
- &mov (&DWP(4*9,$a),$d_);
-
- &add ($b_, &DWP(64+4*10,"esp"));
- &add ($c_,&DWP(64+4*11,"esp"));
- &xor ($b_, &DWP(4*10,$b));
- &xor ($c_,&DWP(4*11,$b));
- &mov (&DWP(4*10,$a),$b_);
- &mov (&DWP(4*11,$a),$c_);
-
- &mov ($c,&DWP(4*12,"esp"));
- &mov ($c_,&DWP(4*14,"esp"));
&mov ($d, &DWP(4*13,"esp"));
&mov ($d_,&DWP(4*15,"esp"));
+ &add ($b_,&DWP(64+4*7,"esp"));
+ &add ($c, &DWP(64+4*10,"esp"));
+ &add ($c_,&DWP(64+4*11,"esp"));
&add ($d, &DWP(64+4*13,"esp"));
&add ($d_,&DWP(64+4*15,"esp"));
+ &xor ($b_,&DWP(4*7,$b));
+ &xor ($c, &DWP(4*10,$b));
+ &xor ($c_,&DWP(4*11,$b));
&xor ($d, &DWP(4*13,$b));
&xor ($d_,&DWP(4*15,$b));
&lea ($b,&DWP(4*16,$b));
- &mov (&DWP(4*12,$a),$c);
+ &mov (&DWP(4*7,$a),$b_);
+ &mov ($b_,&DWP(4*0,"esp"));
+ &mov (&DWP(4*10,$a),$c);
&mov ($c,&wparam(2)); # len
+ &mov (&DWP(4*11,$a),$c_);
&mov (&DWP(4*13,$a),$d);
- &mov (&DWP(4*14,$a),$c_);
&mov (&DWP(4*15,$a),$d_);
+ &mov (&DWP(4*0,$a),$b_);
&lea ($a,&DWP(4*16,$a));
&sub ($c,64);
&jnz (&label("outer_loop"));
@@ -567,12 +555,12 @@
my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
- for($i=0;$i<256;$i+=64) {
- #&movdqa ($xa0,&QWP($i+16*0-128,"ebx")); # it's there
- &movdqa ($xa1,&QWP($i+16*1-128,"ebx"));
- &movdqa ($xa2,&QWP($i+16*2-128,"ebx"));
- &movdqa ($xa3,&QWP($i+16*3-128,"ebx"));
+ #&movdqa ($xa0,&QWP(16*0-128,"ebx")); # it's there
+ &movdqa ($xa1,&QWP(16*1-128,"ebx"));
+ &movdqa ($xa2,&QWP(16*2-128,"ebx"));
+ &movdqa ($xa3,&QWP(16*3-128,"ebx"));
+ for($i=0;$i<256;$i+=64) {
&paddd ($xa0,&QWP($i+16*0-128,"ebp")); # accumulate key material
&paddd ($xa1,&QWP($i+16*1-128,"ebp"));
&paddd ($xa2,&QWP($i+16*2-128,"ebp"));
@@ -593,29 +581,25 @@
#($xa2,$xt2)=($xt2,$xa2);
- &movdqa (&QWP($i+16*0-128,"ebx"),$xa0);
+ &movdqu ($xt0,&QWP(64*0-128,$inp)); # load input
+ &movdqu ($xt1,&QWP(64*1-128,$inp));
+ &movdqu ($xa2,&QWP(64*2-128,$inp));
+ &movdqu ($xt3,&QWP(64*3-128,$inp));
+ &lea ($inp,&QWP($i<192?16:(64*4-16*3),$inp));
+ &pxor ($xt0,$xa0);
&movdqa ($xa0,&QWP($i+16*4-128,"ebx")) if ($i<192);
- &movdqa (&QWP($i+16*1-128,"ebx"),$xa1);
- &movdqa (&QWP($i+16*2-128,"ebx"),$xt2);
- &movdqa (&QWP($i+16*3-128,"ebx"),$xa3);
+ &pxor ($xt1,$xa1);
+ &movdqa ($xa1,&QWP($i+16*5-128,"ebx")) if ($i<192);
+ &pxor ($xt2,$xa2);
+ &movdqa ($xa2,&QWP($i+16*6-128,"ebx")) if ($i<192);
+ &pxor ($xt3,$xa3);
+ &movdqa ($xa3,&QWP($i+16*7-128,"ebx")) if ($i<192);
+ &movdqu (&QWP(64*0-128,$out),$xt0); # store output
+ &movdqu (&QWP(64*1-128,$out),$xt1);
+ &movdqu (&QWP(64*2-128,$out),$xt2);
+ &movdqu (&QWP(64*3-128,$out),$xt3);
+ &lea ($out,&QWP($i<192?16:(64*4-16*3),$out));
}
- for($i=0;$i<256;$i+=64) {
- my $j = 16*($i/64);
- &movdqu ($xa0,&QWP($i+16*0-128,$inp)); # load input
- &movdqu ($xa1,&QWP($i+16*1-128,$inp));
- &movdqu ($xa2,&QWP($i+16*2-128,$inp));
- &movdqu ($xa3,&QWP($i+16*3-128,$inp));
- &pxor ($xa0,&QWP($j+64*0-128,"ebx"));
- &pxor ($xa1,&QWP($j+64*1-128,"ebx"));
- &pxor ($xa2,&QWP($j+64*2-128,"ebx"));
- &pxor ($xa3,&QWP($j+64*3-128,"ebx"));
- &movdqu (&QWP($i+16*0-128,$out),$xa0); # write output
- &movdqu (&QWP($i+16*1-128,$out),$xa1);
- &movdqu (&QWP($i+16*2-128,$out),$xa2);
- &movdqu (&QWP($i+16*3-128,$out),$xa3);
- }
- &lea ($inp,&DWP(256,$inp));
- &lea ($out,&DWP(256,$out));
&sub ($len,64*4);
&jnc (&label("outer_loop"));
diff --git a/src/crypto/chacha/chacha.c b/src/crypto/chacha/chacha.c
index afe1b2a..1562089 100644
--- a/src/crypto/chacha/chacha.c
+++ b/src/crypto/chacha/chacha.c
@@ -16,10 +16,13 @@
#include <openssl/chacha.h>
+#include <assert.h>
#include <string.h>
#include <openssl/cpu.h>
+#include "../internal.h"
+
#define U8TO32_LITTLE(p) \
(((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
@@ -36,8 +39,9 @@
void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
const uint8_t key[32], const uint8_t nonce[12],
uint32_t counter) {
- uint32_t counter_nonce[4];
- counter_nonce[0] = counter;
+ assert(!buffers_alias(out, in_len, in, in_len) || in == out);
+
+ uint32_t counter_nonce[4]; counter_nonce[0] = counter;
counter_nonce[1] = U8TO32_LITTLE(nonce + 0);
counter_nonce[2] = U8TO32_LITTLE(nonce + 4);
counter_nonce[3] = U8TO32_LITTLE(nonce + 8);
@@ -118,6 +122,8 @@
void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
const uint8_t key[32], const uint8_t nonce[12],
uint32_t counter) {
+ assert(!buffers_alias(out, in_len, in, in_len) || in == out);
+
uint32_t input[16];
uint8_t buf[64];
size_t todo, i;
diff --git a/src/crypto/chacha/chacha_test.cc b/src/crypto/chacha/chacha_test.cc
index f364f98..0a5972f 100644
--- a/src/crypto/chacha/chacha_test.cc
+++ b/src/crypto/chacha/chacha_test.cc
@@ -218,25 +218,16 @@
std::unique_ptr<uint8_t[]> buf(new uint8_t[len]);
CRYPTO_chacha_20(buf.get(), kInput, len, kKey, kNonce, kCounter);
if (memcmp(buf.get(), kOutput, len) != 0) {
- fprintf(stderr, "Mismatch at length %u.\n", static_cast<unsigned>(len));
+ fprintf(stderr, "Mismatch at length %zu.\n", len);
return false;
}
- // Test in-place at various offsets.
- static const size_t kOffsets[] = {
- 0, 1, 2, 8, 15, 16, 17, 31, 32, 33, 63,
- 64, 65, 95, 96, 97, 127, 128, 129, 255, 256, 257,
- };
- for (size_t offset : kOffsets) {
- buf.reset(new uint8_t[len + offset]);
- memcpy(buf.get() + offset, kInput, len);
- CRYPTO_chacha_20(buf.get(), buf.get() + offset, len, kKey, kNonce,
- kCounter);
- if (memcmp(buf.get(), kOutput, len) != 0) {
- fprintf(stderr, "Mismatch at length %u with in-place offset %u.\n",
- static_cast<unsigned>(len), static_cast<unsigned>(offset));
- return false;
- }
+ // Test in-place.
+ memcpy(buf.get(), kInput, len);
+ CRYPTO_chacha_20(buf.get(), buf.get(), len, kKey, kNonce, kCounter);
+ if (memcmp(buf.get(), kOutput, len) != 0) {
+ fprintf(stderr, "Mismatch at length %zu, in-place.\n", len);
+ return false;
}
return true;
diff --git a/src/crypto/cipher/aead.c b/src/crypto/cipher/aead.c
index b1db83d..57eecc1 100644
--- a/src/crypto/cipher/aead.c
+++ b/src/crypto/cipher/aead.c
@@ -20,6 +20,7 @@
#include <openssl/err.h>
#include "internal.h"
+#include "../internal.h"
size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; }
@@ -80,21 +81,15 @@
ctx->aead = NULL;
}
-/* check_alias returns 0 if |out| points within the buffer determined by |in|
- * and |in_len| and 1 otherwise.
- *
- * When processing, there's only an issue if |out| points within in[:in_len]
- * and isn't equal to |in|. If that's the case then writing the output will
- * stomp input that hasn't been read yet.
- *
- * This function checks for that case. */
-static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out) {
- if (out <= in) {
- return 1;
- } else if (in + in_len <= out) {
+/* check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If
+ * |in| and |out| alias, we require that |in| == |out|. */
+static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out,
+ size_t out_len) {
+ if (!buffers_alias(in, in_len, out, out_len)) {
return 1;
}
- return 0;
+
+ return in == out;
}
int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
@@ -108,7 +103,7 @@
goto error;
}
- if (!check_alias(in, in_len, out)) {
+ if (!check_alias(in, in_len, out, max_out_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
goto error;
}
@@ -130,7 +125,7 @@
size_t max_out_len, const uint8_t *nonce,
size_t nonce_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
- if (!check_alias(in, in_len, out)) {
+ if (!check_alias(in, in_len, out, max_out_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
goto error;
}
diff --git a/src/crypto/cipher/aead_test.cc b/src/crypto/cipher/aead_test.cc
index f21291e..8bad93f 100644
--- a/src/crypto/cipher/aead_test.cc
+++ b/src/crypto/cipher/aead_test.cc
@@ -225,84 +225,65 @@
return false;
}
- // First test with out > in, which we expect to fail.
- for (auto offset : offsets) {
- if (offset == 0) {
- // Will be tested in the next loop.
- continue;
- }
+ // Test with out != in which we expect to fail.
+ std::vector<uint8_t> buffer(2 + valid_encryption_len);
+ uint8_t *in = buffer.data() + 1;
+ uint8_t *out1 = buffer.data();
+ uint8_t *out2 = buffer.data() + 2;
- std::vector<uint8_t> buffer(offset + valid_encryption_len);
- memcpy(buffer.data(), kPlaintext, sizeof(kPlaintext));
- uint8_t *out = buffer.data() + offset;
+ memcpy(in, kPlaintext, sizeof(kPlaintext));
+ size_t out_len;
+ if (EVP_AEAD_CTX_seal(ctx.get(), out1, &out_len,
+ sizeof(kPlaintext) + max_overhead, nonce.data(),
+ nonce_len, in, sizeof(kPlaintext), nullptr, 0) ||
+ EVP_AEAD_CTX_seal(ctx.get(), out2, &out_len,
+ sizeof(kPlaintext) + max_overhead, nonce.data(),
+ nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_seal unexpectedly succeeded.\n");
+ return false;
+ }
+ ERR_clear_error();
- size_t out_len;
- if (!EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
- sizeof(kPlaintext) + max_overhead, nonce.data(),
- nonce_len, buffer.data(), sizeof(kPlaintext),
- nullptr, 0)) {
- // We expect offsets where the output is greater than the input to fail.
- ERR_clear_error();
- } else {
- fprintf(stderr,
- "EVP_AEAD_CTX_seal unexpectedly succeeded for offset %u.\n",
- static_cast<unsigned>(offset));
- return false;
- }
+ memcpy(in, valid_encryption.data(), valid_encryption_len);
+ if (EVP_AEAD_CTX_open(ctx.get(), out1, &out_len, valid_encryption_len,
+ nonce.data(), nonce_len, in, valid_encryption_len,
+ nullptr, 0) ||
+ EVP_AEAD_CTX_open(ctx.get(), out2, &out_len, valid_encryption_len,
+ nonce.data(), nonce_len, in, valid_encryption_len,
+ nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_open unexpectedly succeeded.\n");
+ return false;
+ }
+ ERR_clear_error();
- memcpy(buffer.data(), valid_encryption.data(), valid_encryption_len);
- if (!EVP_AEAD_CTX_open(ctx.get(), out, &out_len, valid_encryption_len,
- nonce.data(), nonce_len, buffer.data(),
- valid_encryption_len, nullptr, 0)) {
- // We expect offsets where the output is greater than the input to fail.
- ERR_clear_error();
- } else {
- fprintf(stderr,
- "EVP_AEAD_CTX_open unexpectedly succeeded for offset %u.\n",
- static_cast<unsigned>(offset));
- ERR_print_errors_fp(stderr);
- return false;
- }
+ // Test with out == in, which we expect to work.
+ memcpy(in, kPlaintext, sizeof(kPlaintext));
+
+ if (!EVP_AEAD_CTX_seal(ctx.get(), in, &out_len,
+ sizeof(kPlaintext) + max_overhead, nonce.data(),
+ nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_seal failed in-place.\n");
+ return false;
}
- // Test with out <= in, which we expect to work.
- for (auto offset : offsets) {
- std::vector<uint8_t> buffer(offset + valid_encryption_len);
- uint8_t *const out = buffer.data();
- uint8_t *const in = buffer.data() + offset;
- memcpy(in, kPlaintext, sizeof(kPlaintext));
+ if (out_len != valid_encryption_len ||
+ memcmp(in, valid_encryption.data(), out_len) != 0) {
+ fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output in-place.\n");
+ return false;
+ }
- size_t out_len;
- if (!EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
- sizeof(kPlaintext) + max_overhead, nonce.data(),
- nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
- fprintf(stderr, "EVP_AEAD_CTX_seal failed for offset -%u.\n",
- static_cast<unsigned>(offset));
- return false;
- }
+ memcpy(in, valid_encryption.data(), valid_encryption_len);
+ if (!EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len,
+ nonce.data(), nonce_len, in, valid_encryption_len,
+ nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_open failed in-place.\n");
+ return false;
+ }
- if (out_len != valid_encryption_len ||
- memcmp(out, valid_encryption.data(), out_len) != 0) {
- fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output for offset -%u.\n",
- static_cast<unsigned>(offset));
- return false;
- }
-
- memcpy(in, valid_encryption.data(), valid_encryption_len);
- if (!EVP_AEAD_CTX_open(ctx.get(), out, &out_len,
- offset + valid_encryption_len, nonce.data(),
- nonce_len, in, valid_encryption_len, nullptr, 0)) {
- fprintf(stderr, "EVP_AEAD_CTX_open failed for offset -%u.\n",
- static_cast<unsigned>(offset));
- return false;
- }
-
- if (out_len != sizeof(kPlaintext) ||
- memcmp(out, kPlaintext, out_len) != 0) {
- fprintf(stderr, "EVP_AEAD_CTX_open produced bad output for offset -%u.\n",
- static_cast<unsigned>(offset));
- return false;
- }
+ if (out_len != sizeof(kPlaintext) ||
+ memcmp(in, kPlaintext, out_len) != 0) {
+ fprintf(stderr, "EVP_AEAD_CTX_open produced bad output in-place.\n");
+ return false;
}
return true;
diff --git a/src/crypto/cipher/e_aes.c b/src/crypto/cipher/e_aes.c
index d61d048..24c4d8a 100644
--- a/src/crypto/cipher/e_aes.c
+++ b/src/crypto/cipher/e_aes.c
@@ -67,9 +67,7 @@
#endif
-#if defined(_MSC_VER)
-#pragma warning(disable: 4702) /* Unreachable code. */
-#endif
+OPENSSL_MSVC_PRAGMA(warning(disable: 4702)) /* Unreachable code. */
typedef struct {
union {
diff --git a/src/crypto/cipher/test/aes_128_gcm_tests.txt b/src/crypto/cipher/test/aes_128_gcm_tests.txt
index 0e33c91..eac9aa9 100644
--- a/src/crypto/cipher/test/aes_128_gcm_tests.txt
+++ b/src/crypto/cipher/test/aes_128_gcm_tests.txt
@@ -1,4 +1,4 @@
-# The AES-128-GCM test cases from cipher_test.txt have been merged into this
+# The AES-128-GCM test cases from cipher_tests.txt have been merged into this
# file.
KEY: d480429666d48b400633921c5407d1d1
diff --git a/src/crypto/cipher/test/aes_256_gcm_tests.txt b/src/crypto/cipher/test/aes_256_gcm_tests.txt
index dbcee81..30fd422 100644
--- a/src/crypto/cipher/test/aes_256_gcm_tests.txt
+++ b/src/crypto/cipher/test/aes_256_gcm_tests.txt
@@ -1,4 +1,4 @@
-# The AES-256-GCM test cases from cipher_test.txt have been merged into this
+# The AES-256-GCM test cases from cipher_tests.txt have been merged into this
# file.
KEY: e5ac4a32c67e425ac4b143c83c6f161312a97d88d634afdf9f4da5bd35223f01
diff --git a/src/crypto/cipher/test/cipher_test.txt b/src/crypto/cipher/test/cipher_tests.txt
similarity index 100%
rename from src/crypto/cipher/test/cipher_test.txt
rename to src/crypto/cipher/test/cipher_tests.txt
diff --git a/src/crypto/cpu-intel.c b/src/crypto/cpu-intel.c
index 431e1e1..f2e0c4c 100644
--- a/src/crypto/cpu-intel.c
+++ b/src/crypto/cpu-intel.c
@@ -69,10 +69,10 @@
#include <string.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <immintrin.h>
#include <intrin.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include "internal.h"
diff --git a/src/crypto/curve25519/x25519-x86_64.c b/src/crypto/curve25519/x25519-x86_64.c
index 9776c75..1bd86a0 100644
--- a/src/crypto/curve25519/x25519-x86_64.c
+++ b/src/crypto/curve25519/x25519-x86_64.c
@@ -1,3 +1,24 @@
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
+ * 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
+ * public domain but this file has the ISC license just to keep licencing
+ * simple.
+ *
+ * The field functions are shared by Ed25519 and X25519 where possible. */
+
#include <openssl/curve25519.h>
#include <string.h>
diff --git a/src/crypto/dsa/dsa.c b/src/crypto/dsa/dsa.c
index fe29aa0..1de0071 100644
--- a/src/crypto/dsa/dsa.c
+++ b/src/crypto/dsa/dsa.c
@@ -845,6 +845,7 @@
goto err;
}
+ BN_set_flags(&kq, BN_FLG_CONSTTIME);
K = &kq;
if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p)) {
diff --git a/src/crypto/err/err.c b/src/crypto/err/err.c
index c4e4b13..48d631f 100644
--- a/src/crypto/err/err.c
+++ b/src/crypto/err/err.c
@@ -114,9 +114,9 @@
#include <string.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/mem.h>
diff --git a/src/crypto/evp/evp.c b/src/crypto/evp/evp.c
index 79993aa..bc1585e 100644
--- a/src/crypto/evp/evp.c
+++ b/src/crypto/evp/evp.c
@@ -356,6 +356,8 @@
void OpenSSL_add_all_algorithms(void) {}
+void OpenSSL_add_all_algorithms_conf(void) {}
+
void OpenSSL_add_all_ciphers(void) {}
void OpenSSL_add_all_digests(void) {}
diff --git a/src/crypto/evp/evp_test.cc b/src/crypto/evp/evp_test.cc
index a7dac2b..b01d1e4 100644
--- a/src/crypto/evp/evp_test.cc
+++ b/src/crypto/evp/evp_test.cc
@@ -51,30 +51,27 @@
* ====================================================================
*/
+#include <openssl/evp.h>
+
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable: 4702)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(push))
+OPENSSL_MSVC_PRAGMA(warning(disable: 4702))
#include <map>
#include <string>
#include <utility>
#include <vector>
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(pop))
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/digest.h>
#include <openssl/err.h>
-#include <openssl/evp.h>
#include "../test/file_test.h"
#include "../test/scoped_types.h"
diff --git a/src/crypto/internal.h b/src/crypto/internal.h
index 433072c..e35fb7b 100644
--- a/src/crypto/internal.h
+++ b/src/crypto/internal.h
@@ -123,9 +123,9 @@
#if defined(OPENSSL_NO_THREADS)
#elif defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#else
#include <pthread.h>
#endif
@@ -152,6 +152,19 @@
#endif
+/* buffers_alias returns one if |a| and |b| alias and zero otherwise. */
+static inline int buffers_alias(const uint8_t *a, size_t a_len,
+ const uint8_t *b, size_t b_len) {
+ /* Cast |a| and |b| to integers. In C, pointer comparisons between unrelated
+ * objects are undefined whereas pointer to integer conversions are merely
+ * implementation-defined. We assume the implementation defined it in a sane
+ * way. */
+ uintptr_t a_u = (uintptr_t)a;
+ uintptr_t b_u = (uintptr_t)b;
+ return a_u + a_len > b_u && b_u + b_len > a_u;
+}
+
+
/* Constant-time utility functions.
*
* The following methods return a bitmask of all ones (0xff...f) for true and 0
diff --git a/src/crypto/mem.c b/src/crypto/mem.c
index 7d73c73..ca4c559 100644
--- a/src/crypto/mem.c
+++ b/src/crypto/mem.c
@@ -66,9 +66,9 @@
#include <string.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#else
#include <strings.h>
#endif
@@ -118,12 +118,11 @@
}
int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len) {
- size_t i;
const uint8_t *a = in_a;
const uint8_t *b = in_b;
uint8_t x = 0;
- for (i = 0; i < len; i++) {
+ for (size_t i = 0; i < len; i++) {
x |= a[i] ^ b[i];
}
diff --git a/src/crypto/modes/internal.h b/src/crypto/modes/internal.h
index b46e836..430d040 100644
--- a/src/crypto/modes/internal.h
+++ b/src/crypto/modes/internal.h
@@ -121,9 +121,9 @@
#endif
#elif defined(_MSC_VER)
#if _MSC_VER >= 1300
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <intrin.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
#define BSWAP8(x) _byteswap_uint64((uint64_t)(x))
#define BSWAP4(x) _byteswap_ulong((uint32_t)(x))
diff --git a/src/crypto/newhope/CMakeLists.txt b/src/crypto/newhope/CMakeLists.txt
index 5d339ba..7787cce 100644
--- a/src/crypto/newhope/CMakeLists.txt
+++ b/src/crypto/newhope/CMakeLists.txt
@@ -19,6 +19,13 @@
)
add_executable(
+ newhope_statistical_test
+
+ newhope_statistical_test.cc
+ $<TARGET_OBJECTS:test_support>
+)
+
+add_executable(
newhope_vectors_test
newhope_vectors_test.cc
@@ -26,6 +33,8 @@
)
target_link_libraries(newhope_test crypto)
+target_link_libraries(newhope_statistical_test crypto)
target_link_libraries(newhope_vectors_test crypto)
add_dependencies(all_tests newhope_test)
+add_dependencies(all_tests newhope_statistical_test)
add_dependencies(all_tests newhope_vectors_test)
diff --git a/src/crypto/newhope/internal.h b/src/crypto/newhope/internal.h
index 5c82d68..efc5adf 100644
--- a/src/crypto/newhope/internal.h
+++ b/src/crypto/newhope/internal.h
@@ -43,12 +43,6 @@
* |seed|. (In the reference implementation this was done with SHAKE-128.) */
void newhope_poly_uniform(NEWHOPE_POLY* a, const uint8_t* seed);
-/* newhope_poly_getnoise sets |r| to a random polynomial where the coefficients
- * are
- * sampled from the noise distribution. (In the reference implementation, this
- * is given a random seed and a nonce.)*/
-void newhope_poly_getnoise(NEWHOPE_POLY* r);
-
void newhope_helprec(NEWHOPE_POLY* c, const NEWHOPE_POLY* v,
const uint8_t rbits[32]);
@@ -58,9 +52,6 @@
void newhope_reconcile(uint8_t* key, const NEWHOPE_POLY* v,
const NEWHOPE_POLY* c);
-/* newhope_poly_ntt performs NTT(r) in-place. */
-void newhope_poly_ntt(NEWHOPE_POLY* r);
-
/* newhope_poly_invntt performs the inverse of NTT(r) in-place. */
void newhope_poly_invntt(NEWHOPE_POLY* r);
diff --git a/src/crypto/newhope/newhope.c b/src/crypto/newhope/newhope.c
index c590cfa..7edb7eb 100644
--- a/src/crypto/newhope/newhope.c
+++ b/src/crypto/newhope/newhope.c
@@ -47,8 +47,7 @@
}
void NEWHOPE_offer(uint8_t *offermsg, NEWHOPE_POLY *s) {
- newhope_poly_getnoise(s);
- newhope_poly_ntt(s);
+ NEWHOPE_POLY_noise_ntt(s);
/* The first part of the offer message is the seed, which compactly encodes
* a. */
@@ -58,8 +57,7 @@
newhope_poly_uniform(&a, seed);
NEWHOPE_POLY e;
- newhope_poly_getnoise(&e);
- newhope_poly_ntt(&e);
+ NEWHOPE_POLY_noise_ntt(&e);
/* The second part of the offer message is the polynomial pk = a*s+e */
NEWHOPE_POLY pk;
@@ -78,17 +76,13 @@
/* Decode the |offermsg|, generating the same |a| as the peer, from the peer's
* seed. */
NEWHOPE_POLY pk, a;
- const uint8_t *seed = &offermsg[NEWHOPE_POLY_LENGTH];
- newhope_poly_uniform(&a, seed);
- NEWHOPE_POLY_frombytes(&pk, offermsg);
+ NEWHOPE_offer_frommsg(&pk, &a, offermsg);
/* Generate noise polynomials used to generate our key. */
NEWHOPE_POLY sp, ep, epp;
- newhope_poly_getnoise(&sp);
- newhope_poly_ntt(&sp);
- newhope_poly_getnoise(&ep);
- newhope_poly_ntt(&ep);
- newhope_poly_getnoise(&epp); /* intentionally not NTT */
+ NEWHOPE_POLY_noise_ntt(&sp);
+ NEWHOPE_POLY_noise_ntt(&ep);
+ NEWHOPE_POLY_noise(&epp); /* intentionally not NTT */
/* Generate random bytes used for reconciliation. (The reference
* implementation calls ChaCha20 here.) */
@@ -171,3 +165,10 @@
newhope_poly_invntt(&v);
newhope_reconcile(k, &v, reconciliation);
}
+
+void NEWHOPE_offer_frommsg(NEWHOPE_POLY *out_pk, NEWHOPE_POLY *out_a,
+ const uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH]) {
+ NEWHOPE_POLY_frombytes(out_pk, offermsg);
+ const uint8_t *seed = offermsg + NEWHOPE_POLY_LENGTH;
+ newhope_poly_uniform(out_a, seed);
+}
diff --git a/src/crypto/newhope/newhope_statistical_test.cc b/src/crypto/newhope/newhope_statistical_test.cc
new file mode 100644
index 0000000..44fac48
--- /dev/null
+++ b/src/crypto/newhope/newhope_statistical_test.cc
@@ -0,0 +1,156 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <string>
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+
+#include "../test/scoped_types.h"
+#include "internal.h"
+
+
+static const unsigned kNumTests = 1000;
+
+static bool TestNoise(void) {
+ printf("noise distribution:\n");
+
+ size_t buckets[1 + 2 * PARAM_K];
+ memset(buckets, 0, sizeof(buckets));
+ for (size_t i = 0; i < kNumTests; i++) {
+ NEWHOPE_POLY s;
+ NEWHOPE_POLY_noise(&s);
+ for (int j = 0; j < PARAM_N; j++) {
+ uint16_t value = (s.coeffs[j] + PARAM_K) % PARAM_Q;
+ buckets[value]++;
+ }
+ }
+
+ int64_t sum = 0, square_sum = 0;
+ for (int64_t i = 0; i < 1 + 2 * PARAM_K; i++) {
+ sum += (i - PARAM_K) * (int64_t) buckets[i];
+ square_sum += (i - PARAM_K) * (i - PARAM_K) * (int64_t) buckets[i];
+ }
+ double mean = double(sum) / double(PARAM_N * kNumTests);
+
+ double expected_variance = 0.5 * 0.5 * double(PARAM_K * 2);
+ double variance = double(square_sum) / double(PARAM_N * kNumTests) - mean * mean;
+
+ for (size_t i = 0; i < 1 + 2 * PARAM_K; i++) {
+ std::string dots;
+ for (size_t j = 0; j < 79 * buckets[i] / buckets[PARAM_K]; j++) {
+ dots += "+";
+ }
+ printf("%+zd\t%zd\t%s\n", i - PARAM_K, buckets[i], dots.c_str());
+ }
+ printf("mean: got %f, want %f\n", mean, 0.0);
+ printf("variance: got %f, want %f\n", variance, expected_variance);
+ printf("\n");
+
+ if (mean < -0.5 || 0.5 < mean) {
+ fprintf(stderr, "mean out of range: %f\n", mean);
+ return false;
+ }
+
+ if (variance < expected_variance - 1.0 || expected_variance + 1.0 < variance) {
+ fprintf(stderr, "variance out of range: got %f, want %f\n", variance,
+ expected_variance);
+ return false;
+ }
+ return true;
+}
+
+static int Hamming32(const uint8_t key[NEWHOPE_KEY_LENGTH]) {
+ static int kHamming[256] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+ };
+
+ int r = 0;
+ for(int i = 0; i < NEWHOPE_KEY_LENGTH; i++) {
+ r += kHamming[key[i]];
+ }
+ return r;
+}
+
+static bool TestKeys(void) {
+ printf("keys (prior to whitening):\n");
+
+ uint8_t key[NEWHOPE_KEY_LENGTH];
+ uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH];
+
+ ScopedNEWHOPE_POLY sk(NEWHOPE_POLY_new()), pk(NEWHOPE_POLY_new()),
+ sp(NEWHOPE_POLY_new()), ep(NEWHOPE_POLY_new()), epp(NEWHOPE_POLY_new()),
+ a(NEWHOPE_POLY_new()), bp(NEWHOPE_POLY_new()), rec(NEWHOPE_POLY_new());
+
+ int ones = 0;
+ for (size_t i = 0; i < kNumTests; i++) {
+ NEWHOPE_offer(offermsg, sk.get());
+ NEWHOPE_offer_frommsg(pk.get(), a.get(), offermsg);
+
+ NEWHOPE_POLY_noise_ntt(sp.get());
+ NEWHOPE_POLY_noise_ntt(ep.get());
+ NEWHOPE_POLY_noise(epp.get()); /* intentionally not NTT */
+
+ uint8_t rand[32];
+ RAND_bytes(rand, 32);
+
+ NEWHOPE_accept_computation(key, bp.get(), rec.get(),
+ sp.get(), ep.get(), epp.get(), rand,
+ pk.get(), a.get());
+ ones += Hamming32(key);
+ }
+
+ int bits = NEWHOPE_KEY_LENGTH * 8 * kNumTests;
+ int diff = bits - 2 * ones;
+ double fraction = (double) abs(diff) / bits;
+ printf("ones: %d\n", ones);
+ printf("zeroes: %d\n", (bits - ones));
+ printf("diff: got %d (%f), want 0\n", diff, fraction);
+ printf("\n");
+
+ if (fraction > 0.01) {
+ fprintf(stderr, "key bias is too high (%f)\n", fraction);
+ return false;
+ }
+
+ return true;
+}
+
+int main(void) {
+ if (!TestKeys() ||
+ !TestNoise()) {
+ return 1;
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/src/crypto/newhope/newhope_test.txt b/src/crypto/newhope/newhope_tests.txt
similarity index 100%
rename from src/crypto/newhope/newhope_test.txt
rename to src/crypto/newhope/newhope_tests.txt
diff --git a/src/crypto/newhope/poly.c b/src/crypto/newhope/poly.c
index a84bdeb..44cd383 100644
--- a/src/crypto/newhope/poly.c
+++ b/src/crypto/newhope/poly.c
@@ -126,7 +126,7 @@
}
}
-void newhope_poly_getnoise(NEWHOPE_POLY* r) {
+void NEWHOPE_POLY_noise(NEWHOPE_POLY* r) {
#if PARAM_K != 16
#error "poly_getnoise in poly.c only supports k=16"
#endif
@@ -171,7 +171,13 @@
}
}
-void newhope_poly_ntt(NEWHOPE_POLY* r) {
+void NEWHOPE_POLY_noise_ntt(NEWHOPE_POLY* r) {
+ NEWHOPE_POLY_noise(r);
+ /* Forward NTT transformation. Because we're operating on a noise polynomial,
+ * we can regard the bits as already reversed and skip the bit-reversal
+ * step:
+ *
+ * newhope_bitrev_vector(r->coeffs); */
newhope_mul_coefficients(r->coeffs, newhope_psis_bitrev_montgomery);
newhope_ntt((uint16_t *) r->coeffs, newhope_omegas_montgomery);
}
diff --git a/src/crypto/poly1305/poly1305_test.txt b/src/crypto/poly1305/poly1305_tests.txt
similarity index 100%
rename from src/crypto/poly1305/poly1305_test.txt
rename to src/crypto/poly1305/poly1305_tests.txt
diff --git a/src/crypto/rand/windows.c b/src/crypto/rand/windows.c
index 9d7dd78..5a9a96b 100644
--- a/src/crypto/rand/windows.c
+++ b/src/crypto/rand/windows.c
@@ -19,7 +19,7 @@
#include <limits.h>
#include <stdlib.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
@@ -30,7 +30,7 @@
#include <ntsecapi.h>
#undef SystemFunction036
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#include "internal.h"
diff --git a/src/crypto/test/file_test.h b/src/crypto/test/file_test.h
index e90cc86..a859127 100644
--- a/src/crypto/test/file_test.h
+++ b/src/crypto/test/file_test.h
@@ -20,19 +20,15 @@
#include <stdint.h>
#include <stdio.h>
-#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable: 4702)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(push))
+OPENSSL_MSVC_PRAGMA(warning(disable: 4702))
#include <string>
#include <map>
#include <set>
#include <vector>
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(pop))
// File-based test framework.
//
diff --git a/src/crypto/thread.c b/src/crypto/thread.c
index 8837115..373f8db 100644
--- a/src/crypto/thread.c
+++ b/src/crypto/thread.c
@@ -61,9 +61,9 @@
#if !defined(OPENSSL_WINDOWS)
#include <errno.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/mem.h>
@@ -74,6 +74,11 @@
void CRYPTO_set_locking_callback(void (*func)(int mode, int lock_num,
const char *file, int line)) {}
+void (*CRYPTO_get_locking_callback(void))(int mode, int lock_num,
+ const char *file, int line) {
+ return NULL;
+}
+
void CRYPTO_set_add_lock_callback(int (*func)(int *num, int mount, int lock_num,
const char *file, int line)) {}
@@ -99,3 +104,19 @@
void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)(
struct CRYPTO_dynlock_value *l, const char *file, int line)) {}
+
+struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))(
+ const char *file, int line) {
+ return NULL;
+}
+
+void (*CRYPTO_get_dynlock_lock_callback(void))(int mode,
+ struct CRYPTO_dynlock_value *l,
+ const char *file, int line) {
+ return NULL;
+}
+
+void (*CRYPTO_get_dynlock_destroy_callback(void))(
+ struct CRYPTO_dynlock_value *l, const char *file, int line) {
+ return NULL;
+}
diff --git a/src/crypto/thread_test.c b/src/crypto/thread_test.c
index 92a5373..12ca2ec 100644
--- a/src/crypto/thread_test.c
+++ b/src/crypto/thread_test.c
@@ -21,9 +21,9 @@
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
typedef HANDLE thread_t;
diff --git a/src/crypto/thread_win.c b/src/crypto/thread_win.c
index 9f7d82b..c7a90f7 100644
--- a/src/crypto/thread_win.c
+++ b/src/crypto/thread_win.c
@@ -16,9 +16,9 @@
#if defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#include <stdlib.h>
#include <string.h>
diff --git a/src/crypto/x509/x509_txt.c b/src/crypto/x509/x509_txt.c
index 86af3fe..17e6cdb 100644
--- a/src/crypto/x509/x509_txt.c
+++ b/src/crypto/x509/x509_txt.c
@@ -199,6 +199,11 @@
case X509_V_ERR_IP_ADDRESS_MISMATCH:
return ("IP address mismatch");
+ case X509_V_ERR_INVALID_CALL:
+ return ("Invalid certificate verification context");
+ case X509_V_ERR_STORE_LOOKUP:
+ return ("Issuer certificate lookup error");
+
default:
BIO_snprintf(buf, sizeof buf, "error number %ld", n);
return (buf);
diff --git a/src/crypto/x509/x509_vfy.c b/src/crypto/x509/x509_vfy.c
index 2ed2f03..520408f 100644
--- a/src/crypto/x509/x509_vfy.c
+++ b/src/crypto/x509/x509_vfy.c
@@ -198,6 +198,7 @@
STACK_OF(X509) *sktmp = NULL;
if (ctx->cert == NULL) {
OPENSSL_PUT_ERROR(X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
+ ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
if (ctx->chain != NULL) {
@@ -206,6 +207,7 @@
* cannot do another one.
*/
OPENSSL_PUT_ERROR(X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
@@ -218,6 +220,7 @@
ctx->chain = sk_X509_new_null();
if (ctx->chain == NULL || !sk_X509_push(ctx->chain, ctx->cert)) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
goto end;
}
X509_up_ref(ctx->cert);
@@ -227,6 +230,7 @@
if (ctx->untrusted != NULL
&& (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
goto end;
}
@@ -250,8 +254,10 @@
*/
if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) {
ok = ctx->get_issuer(&xtmp, ctx, x);
- if (ok < 0)
+ if (ok < 0) {
+ ctx->error = X509_V_ERR_STORE_LOOKUP;
goto end;
+ }
/*
* If successful for now free up cert so it will be picked up
* again later.
@@ -268,6 +274,7 @@
if (xtmp != NULL) {
if (!sk_X509_push(ctx->chain, xtmp)) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = 0;
goto end;
}
@@ -349,14 +356,17 @@
break;
ok = ctx->get_issuer(&xtmp, ctx, x);
- if (ok < 0)
+ if (ok < 0) {
+ ctx->error = X509_V_ERR_STORE_LOOKUP;
goto end;
+ }
if (ok == 0)
break;
x = xtmp;
if (!sk_X509_push(ctx->chain, x)) {
X509_free(xtmp);
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = 0;
goto end;
}
@@ -493,6 +503,10 @@
sk_X509_free(sktmp);
if (chain_ss != NULL)
X509_free(chain_ss);
+
+ /* Safety net, error returns must set ctx->error */
+ if (ok <= 0 && ctx->error == X509_V_OK)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
return ok;
}
@@ -709,12 +723,19 @@
NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc;
if (nc) {
rv = NAME_CONSTRAINTS_check(x, nc);
- if (rv != X509_V_OK) {
+ switch (rv) {
+ case X509_V_OK:
+ continue;
+ case X509_V_ERR_OUT_OF_MEM:
+ ctx->error = rv;
+ return 0;
+ default:
ctx->error = rv;
ctx->error_depth = i;
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0;
+ break;
}
}
}
@@ -1605,6 +1626,7 @@
ctx->param->policies, ctx->param->flags);
if (ret == 0) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
return 0;
}
/* Invalid or inconsistent extensions */
@@ -1633,7 +1655,12 @@
if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) {
ctx->current_cert = NULL;
- ctx->error = X509_V_OK;
+ /*
+ * Verification errors need to be "sticky", a callback may have allowed
+ * an SSL handshake to continue despite an error, and we must then
+ * remain in an error state. Therefore, we MUST NOT clear earlier
+ * verification errors by setting the error to X509_V_OK.
+ */
if (!ctx->verify_cb(2, ctx))
return 0;
}
diff --git a/src/decrepit/cast/cast.c b/src/decrepit/cast/cast.c
index 94b0710..75ea656 100644
--- a/src/decrepit/cast/cast.c
+++ b/src/decrepit/cast/cast.c
@@ -57,9 +57,9 @@
#include <openssl/cast.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <intrin.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include "internal.h"
diff --git a/src/include/openssl/aead.h b/src/include/openssl/aead.h
index d9a640c..7895825 100644
--- a/src/include/openssl/aead.h
+++ b/src/include/openssl/aead.h
@@ -226,7 +226,7 @@
* insufficient, zero will be returned. (In this case, |*out_len| is set to
* zero.)
*
- * If |in| and |out| alias then |out| must be <= |in|. */
+ * If |in| and |out| alias then |out| must be == |in|. */
OPENSSL_EXPORT int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
size_t *out_len, size_t max_out_len,
const uint8_t *nonce, size_t nonce_len,
@@ -251,7 +251,7 @@
* insufficient, zero will be returned. (In this case, |*out_len| is set to
* zero.)
*
- * If |in| and |out| alias then |out| must be <= |in|. */
+ * If |in| and |out| alias then |out| must be == |in|. */
OPENSSL_EXPORT int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
size_t *out_len, size_t max_out_len,
const uint8_t *nonce, size_t nonce_len,
diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h
index d4a4eac..7a3adfb 100644
--- a/src/include/openssl/base.h
+++ b/src/include/openssl/base.h
@@ -161,6 +161,13 @@
#define OPENSSL_PRINTF_FORMAT_FUNC(string_index, first_to_check)
#endif
+/* OPENSSL_MSVC_PRAGMA emits a pragma on MSVC and nothing on other compilers. */
+#if defined(_MSC_VER)
+#define OPENSSL_MSVC_PRAGMA(arg) __pragma(arg)
+#else
+#define OPENSSL_MSVC_PRAGMA(arg)
+#endif
+
/* CRYPTO_THREADID is a dummy value. */
typedef int CRYPTO_THREADID;
diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h
index 3e547ac..5416c65 100644
--- a/src/include/openssl/bio.h
+++ b/src/include/openssl/bio.h
@@ -562,6 +562,10 @@
* will connect to. It returns one on success and zero otherwise. */
OPENSSL_EXPORT int BIO_set_conn_port(BIO *bio, const char *port_str);
+/* BIO_set_conn_int_port sets |*port| as the port that |bio| will connect to.
+ * It returns one on success and zero otherwise. */
+OPENSSL_EXPORT int BIO_set_conn_int_port(BIO *bio, const int *port);
+
/* BIO_set_nbio sets whether |bio| will use non-blocking I/O operations. It
* returns one on success and zero otherwise. */
OPENSSL_EXPORT int BIO_set_nbio(BIO *bio, int on);
@@ -583,8 +587,12 @@
#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in
the previous write operation. */
-#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT \
- 45 /* Next DTLS handshake timeout to adjust socket timeouts */
+/* BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT sets a read deadline to drive
+ * retransmits. The |parg| argument to |BIO_ctrl| will be a pointer to a
+ * |timeval| struct. If the structure is all zeros, it clears the read
+ * deadline. Otherwise, |BIO_read| must fail with a temporary error
+ * (e.g. |EAGAIN|) after the deadline. */
+#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45
#define BIO_CTRL_DGRAM_GET_PEER 46
@@ -710,6 +718,8 @@
#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */
#define BIO_CTRL_SET 4 /* man - set the 'IO' type */
#define BIO_CTRL_GET 5 /* man - get the 'IO' type */
+#define BIO_CTRL_PUSH 6
+#define BIO_CTRL_POP 7
#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */
#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */
#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */
@@ -720,10 +730,8 @@
#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */
#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */
-/* These are never used, but exist to allow code to compile more easily. */
-#define BIO_CTRL_DUP 100
-#define BIO_CTRL_PUSH 101
-#define BIO_CTRL_POP 102
+/* BIO_CTRL_DUP is never used, but exists to allow code to compile more easily. */
+#define BIO_CTRL_DUP 12
/* Android compatibility section.
diff --git a/src/include/openssl/bytestring.h b/src/include/openssl/bytestring.h
index 68ede2d..3a8d4e5 100644
--- a/src/include/openssl/bytestring.h
+++ b/src/include/openssl/bytestring.h
@@ -95,6 +95,10 @@
* and advances |cbs|. It returns one on success and zero on error. */
OPENSSL_EXPORT int CBS_get_u32(CBS *cbs, uint32_t *out);
+/* CBS_get_last_u8 sets |*out| to the last uint8_t from |cbs| and shortens
+ * |cbs|. It returns one on success and zero on error. */
+OPENSSL_EXPORT int CBS_get_last_u8(CBS *cbs, uint8_t *out);
+
/* CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances
* |cbs|. It returns one on success and zero on error. */
OPENSSL_EXPORT int CBS_get_bytes(CBS *cbs, CBS *out, size_t len);
diff --git a/src/include/openssl/chacha.h b/src/include/openssl/chacha.h
index 64713c2..3d035e6 100644
--- a/src/include/openssl/chacha.h
+++ b/src/include/openssl/chacha.h
@@ -23,8 +23,8 @@
/* CRYPTO_chacha_20 encrypts |in_len| bytes from |in| with the given key and
- * nonce and writes the result to |out|, which may be equal to |in|. The
- * initial block counter is specified by |counter|. */
+ * nonce and writes the result to |out|. If |in| and |out| alias, they must be
+ * equal. The initial block counter is specified by |counter|. */
OPENSSL_EXPORT void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in,
size_t in_len, const uint8_t key[32],
const uint8_t nonce[12], uint32_t counter);
diff --git a/src/include/openssl/evp.h b/src/include/openssl/evp.h
index 398c741..faf160f 100644
--- a/src/include/openssl/evp.h
+++ b/src/include/openssl/evp.h
@@ -654,6 +654,9 @@
/* OpenSSL_add_all_algorithms does nothing. */
OPENSSL_EXPORT void OpenSSL_add_all_algorithms(void);
+/* OpenSSL_add_all_algorithms_conf does nothing. */
+OPENSSL_EXPORT void OpenSSL_add_all_algorithms_conf(void);
+
/* OpenSSL_add_all_ciphers does nothing. */
OPENSSL_EXPORT void OpenSSL_add_all_ciphers(void);
diff --git a/src/include/openssl/newhope.h b/src/include/openssl/newhope.h
index 31d559f..487e03f 100644
--- a/src/include/openssl/newhope.h
+++ b/src/include/openssl/newhope.h
@@ -89,6 +89,14 @@
/* Lower-level functions. */
+/* NEWHOPE_POLY_noise sets |r| to a random polynomial where the coefficients are
+ * sampled from the noise distribution. */
+OPENSSL_EXPORT void NEWHOPE_POLY_noise(NEWHOPE_POLY* r);
+
+/* NEWHOPE_POLY_noise_ntt sets |r| to an output of NEWHOPE_POLY_noise, and then
+ * applies NTT(r) in-place. */
+OPENSSL_EXPORT void NEWHOPE_POLY_noise_ntt(NEWHOPE_POLY* r);
+
/* NEWHOPE_offer_computation is the work of |NEWHOPE_offer|, less the encoding
* parts. The inputs are the noise polynomials |s| and |e|, and random
* polynomial |a|. The output is the polynomial |pk|. */
@@ -125,6 +133,12 @@
OPENSSL_EXPORT void NEWHOPE_POLY_tobytes(uint8_t r[NEWHOPE_POLY_LENGTH],
const NEWHOPE_POLY* p);
+/* NEWHOPE_offer_frommsg decodes an offer message |msg| into its constituent
+ * polynomials |out_pk| and |a|. */
+OPENSSL_EXPORT void NEWHOPE_offer_frommsg(
+ NEWHOPE_POLY *out_pk, NEWHOPE_POLY *out_a,
+ const uint8_t msg[NEWHOPE_OFFERMSG_LENGTH]);
+
#if defined(__cplusplus)
} /* extern "C" */
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 3770c6e..03a4ea5 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -1095,6 +1095,9 @@
/* SSL_CIPHER_is_ECDSA returns one if |cipher| uses ECDSA. */
OPENSSL_EXPORT int SSL_CIPHER_is_ECDSA(const SSL_CIPHER *cipher);
+/* SSL_CIPHER_is_DHE returns one if |cipher| uses DHE. */
+OPENSSL_EXPORT int SSL_CIPHER_is_DHE(const SSL_CIPHER *cipher);
+
/* SSL_CIPHER_is_ECDHE returns one if |cipher| uses ECDHE. */
OPENSSL_EXPORT int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher);
@@ -2725,6 +2728,13 @@
OPENSSL_EXPORT void SSL_CTX_set_keylog_callback(
SSL_CTX *ctx, void (*cb)(const SSL *ssl, const char *line));
+/* SSL_CTX_set_current_time_cb configures a callback to retrieve the current
+ * time, which should be set in |*out_clock|. This can be used for testing
+ * purposes; for example, a callback can be configured that returns a time
+ * set explicitly by the test. */
+OPENSSL_EXPORT void SSL_CTX_set_current_time_cb(
+ SSL_CTX *ctx, void (*cb)(const SSL *ssl, struct timeval *out_clock));
+
enum ssl_renegotiate_mode_t {
ssl_renegotiate_never = 0,
ssl_renegotiate_once,
@@ -3822,7 +3832,8 @@
void (*keylog_callback)(const SSL *ssl, const char *line);
/* current_time_cb, if not NULL, is the function to use to get the current
- * time. It sets |*out_clock| to the current time. */
+ * time. It sets |*out_clock| to the current time. See
+ * |SSL_CTX_set_current_time_cb|. */
void (*current_time_cb)(const SSL *ssl, struct timeval *out_clock);
/* quiet_shutdown is true if the connection should not send a close_notify on
@@ -4173,13 +4184,10 @@
uint16_t received;
} custom_extensions;
- /* SNI extension */
-
/* should_ack_sni is used by a server and indicates that the SNI extension
* should be echoed in the ServerHello. */
unsigned should_ack_sni:1;
-
/* Client-only: cert_req determines if a client certificate is to be sent.
* This is 0 if no client Certificate message is to be sent, 1 if there is
* a client certificate, and 2 to send an empty client Certificate
diff --git a/src/include/openssl/ssl3.h b/src/include/openssl/ssl3.h
index 64e1d31..1da5de7 100644
--- a/src/include/openssl/ssl3.h
+++ b/src/include/openssl/ssl3.h
@@ -399,7 +399,7 @@
#define SSL3_MT_CERTIFICATE 11
#define SSL3_MT_SERVER_KEY_EXCHANGE 12
#define SSL3_MT_CERTIFICATE_REQUEST 13
-#define SSL3_MT_SERVER_DONE 14
+#define SSL3_MT_SERVER_HELLO_DONE 14
#define SSL3_MT_CERTIFICATE_VERIFY 15
#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
#define SSL3_MT_FINISHED 20
@@ -409,8 +409,9 @@
#define SSL3_MT_CHANNEL_ID_ENCRYPTED_EXTENSIONS 203
#define DTLS1_MT_HELLO_VERIFY_REQUEST 3
-/* SSL3_MT_NEWSESSION_TICKET is a legacy alias for |SSL3_MT_NEW_SESSION_TICKET|
- * for consumers which use |SSL_CTX_set_msg_callback|. */
+/* The following are legacy aliases for consumers which use
+ * |SSL_CTX_set_msg_callback|. */
+#define SSL3_MT_SERVER_DONE SSL3_MT_SERVER_HELLO_DONE
#define SSL3_MT_NEWSESSION_TICKET SSL3_MT_NEW_SESSION_TICKET
diff --git a/src/include/openssl/thread.h b/src/include/openssl/thread.h
index 02539e8..9a96fb4 100644
--- a/src/include/openssl/thread.h
+++ b/src/include/openssl/thread.h
@@ -101,7 +101,11 @@
typedef uint32_t CRYPTO_refcount_t;
-/* Deprecated functions */
+/* Deprecated functions.
+ *
+ * Historically, OpenSSL required callers to provide locking callbacks.
+ * BoringSSL is thread-safe by default, but some old code calls these functions
+ * and so no-op implementations are provided. */
/* These defines do nothing but are provided to make old code easier to
* compile. */
@@ -123,6 +127,11 @@
OPENSSL_EXPORT void CRYPTO_set_add_lock_callback(int (*func)(
int *num, int amount, int lock_num, const char *file, int line));
+/* CRYPTO_get_locking_callback returns NULL. */
+OPENSSL_EXPORT void (*CRYPTO_get_locking_callback(void))(int mode, int lock_num,
+ const char *file,
+ int line);
+
/* CRYPTO_get_lock_name returns a fixed, dummy string. */
OPENSSL_EXPORT const char *CRYPTO_get_lock_name(int lock_num);
@@ -140,14 +149,6 @@
/* CRYPTO_THREADID_current does nothing. */
OPENSSL_EXPORT void CRYPTO_THREADID_current(CRYPTO_THREADID *id);
-
-/* Private functions.
- *
- * Some old code calls these functions and so no-op implementations are
- * provided.
- *
- * TODO(fork): cleanup callers and remove. */
-
OPENSSL_EXPORT void CRYPTO_set_id_callback(unsigned long (*func)(void));
typedef struct {
@@ -166,6 +167,15 @@
void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l,
const char *file, int line));
+OPENSSL_EXPORT struct CRYPTO_dynlock_value *(
+ *CRYPTO_get_dynlock_create_callback(void))(const char *file, int line);
+
+OPENSSL_EXPORT void (*CRYPTO_get_dynlock_lock_callback(void))(
+ int mode, struct CRYPTO_dynlock_value *l, const char *file, int line);
+
+OPENSSL_EXPORT void (*CRYPTO_get_dynlock_destroy_callback(void))(
+ struct CRYPTO_dynlock_value *l, const char *file, int line);
+
#if defined(__cplusplus)
} /* extern C */
diff --git a/src/include/openssl/tls1.h b/src/include/openssl/tls1.h
index 6ed9fa9..d195940 100644
--- a/src/include/openssl/tls1.h
+++ b/src/include/openssl/tls1.h
@@ -436,6 +436,10 @@
#define TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0x0300CCA9
#define TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0x0300CCAC
+/* PSK ciphersuites from mattsson-tls-ecdhe-psk-aead */
+#define TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256 0x0300D001
+#define TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384 0x0300D002
+
/* TODO(davidben): Remove this. Historically, the CK names for CHACHA20_POLY1305
* were missing 'WITH' and 'SHA256'. */
#define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305 \
@@ -627,6 +631,10 @@
#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 \
TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+/* PSK ciphersuites from mattsson-tls-ecdhe-psk-aead */
+#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256 "ECDHE-PSK-AES128-GCM-SHA256"
+#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_GCM_SHA384 "ECDHE-PSK-AES256-GCM-SHA384"
+
/* CECPQ1 ciphersuites. These are specific to BoringSSL and not standard. */
#define TLS1_TXT_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 \
"CECPQ1-RSA-CHACHA20-POLY1305-SHA256"
diff --git a/src/include/openssl/x509_vfy.h b/src/include/openssl/x509_vfy.h
index a9d0519..16f03d6 100644
--- a/src/include/openssl/x509_vfy.h
+++ b/src/include/openssl/x509_vfy.h
@@ -292,7 +292,7 @@
X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL)
#define X509_V_OK 0
-/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
+#define X509_V_ERR_UNSPECIFIED 1
#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2
#define X509_V_ERR_UNABLE_TO_GET_CRL 3
@@ -347,6 +347,7 @@
#define X509_V_ERR_PERMITTED_VIOLATION 47
#define X509_V_ERR_EXCLUDED_VIOLATION 48
#define X509_V_ERR_SUBTREE_MINMAX 49
+#define X509_V_ERR_APPLICATION_VERIFICATION 50
#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51
#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52
#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53
@@ -365,8 +366,10 @@
#define X509_V_ERR_EMAIL_MISMATCH 63
#define X509_V_ERR_IP_ADDRESS_MISMATCH 64
-/* The application is not happy */
-#define X509_V_ERR_APPLICATION_VERIFICATION 50
+/* Caller error */
+#define X509_V_ERR_INVALID_CALL 65
+/* Issuer lookup error */
+#define X509_V_ERR_STORE_LOOKUP 66
/* Certificate verify flags */
@@ -614,4 +617,3 @@
}
#endif
#endif
-
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt
index c82cb9b..e17e1f2 100644
--- a/src/ssl/CMakeLists.txt
+++ b/src/ssl/CMakeLists.txt
@@ -6,21 +6,19 @@
ssl
custom_extensions.c
+ handshake_server.c
+ handshake_client.c
d1_both.c
- d1_clnt.c
d1_lib.c
d1_meth.c
d1_pkt.c
d1_srtp.c
- d1_srvr.c
dtls_record.c
s3_both.c
- s3_clnt.c
s3_enc.c
s3_lib.c
s3_meth.c
s3_pkt.c
- s3_srvr.c
ssl_aead_ctx.c
ssl_asn1.c
ssl_buffer.c
diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c
index 8d8784b..78f566e 100644
--- a/src/ssl/d1_both.c
+++ b/src/ssl/d1_both.c
@@ -299,18 +299,15 @@
static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS};
int ret =
- dtls1_write_bytes(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
- sizeof(kChangeCipherSpec), use_epoch);
+ dtls1_write_record(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
+ sizeof(kChangeCipherSpec), use_epoch);
if (ret <= 0) {
return ret;
}
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(1 /* write */, ssl->version, SSL3_RT_CHANGE_CIPHER_SPEC,
- kChangeCipherSpec, sizeof(kChangeCipherSpec), ssl,
- ssl->msg_callback_arg);
- }
-
+ ssl_do_msg_callback(ssl, 1 /* write */, ssl->version,
+ SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
+ sizeof(kChangeCipherSpec));
return 1;
}
@@ -378,8 +375,8 @@
goto err;
}
- int write_ret = dtls1_write_bytes(ssl, SSL3_RT_HANDSHAKE, buf, len,
- use_epoch);
+ int write_ret =
+ dtls1_write_record(ssl, SSL3_RT_HANDSHAKE, buf, len, use_epoch);
if (write_ret <= 0) {
ret = write_ret;
goto err;
@@ -388,11 +385,9 @@
ssl->init_num -= todo;
} while (ssl->init_num > 0);
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(
- 1 /* write */, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
- (size_t)(ssl->init_off + ssl->init_num), ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 1 /* write */, ssl->version, SSL3_RT_HANDSHAKE,
+ ssl->init_buf->data,
+ (size_t)(ssl->init_off + ssl->init_num));
ssl->init_off = 0;
ssl->init_num = 0;
@@ -420,24 +415,6 @@
frag->reassembly == NULL;
}
-/* dtls1_discard_fragment_body discards a handshake fragment body of length
- * |frag_len|. It returns one on success and zero on error.
- *
- * TODO(davidben): This function will go away when ssl_read_bytes is gone from
- * the DTLS side. */
-static int dtls1_discard_fragment_body(SSL *ssl, size_t frag_len) {
- uint8_t discard[256];
- while (frag_len > 0) {
- size_t chunk = frag_len < sizeof(discard) ? frag_len : sizeof(discard);
- int ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, discard, chunk, 0);
- if (ret != (int) chunk) {
- return 0;
- }
- frag_len -= chunk;
- }
- return 1;
-}
-
/* dtls1_get_buffered_message returns the buffered message corresponding to
* |msg_hdr|. If none exists, it creates a new one and inserts it in the
* queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It
@@ -483,75 +460,92 @@
return frag;
}
-/* dtls1_process_fragment reads a handshake fragment and processes it. It
- * returns one if a fragment was successfully processed and 0 or -1 on error. */
-static int dtls1_process_fragment(SSL *ssl) {
- /* Read handshake message header. */
- uint8_t header[DTLS1_HM_HEADER_LENGTH];
- int ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, header,
- DTLS1_HM_HEADER_LENGTH, 0);
- if (ret <= 0) {
- return ret;
+/* dtls1_process_handshake_record reads a handshake record and processes it. It
+ * returns one if the record was successfully processed and 0 or -1 on error. */
+static int dtls1_process_handshake_record(SSL *ssl) {
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+
+start:
+ if (rr->length == 0) {
+ int ret = dtls1_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
}
- if (ret != DTLS1_HM_HEADER_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+
+ /* Cross-epoch records are discarded, but we may receive out-of-order
+ * application data between ChangeCipherSpec and Finished or a ChangeCipherSpec
+ * before the appropriate point in the handshake. Those must be silently
+ * discarded.
+ *
+ * However, only allow the out-of-order records in the correct epoch.
+ * Application data must come in the encrypted epoch, and ChangeCipherSpec in
+ * the unencrypted epoch (we never renegotiate). Other cases fall through and
+ * fail with a fatal error. */
+ if ((rr->type == SSL3_RT_APPLICATION_DATA &&
+ ssl->s3->aead_read_ctx != NULL) ||
+ (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC &&
+ ssl->s3->aead_read_ctx == NULL)) {
+ rr->length = 0;
+ goto start;
+ }
+
+ if (rr->type != SSL3_RT_HANDSHAKE) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
return -1;
}
- /* Parse the message fragment header. */
- struct hm_header_st msg_hdr;
- dtls1_get_message_header(header, &msg_hdr);
+ CBS cbs;
+ CBS_init(&cbs, rr->data, rr->length);
- /* TODO(davidben): dtls1_read_bytes is the wrong abstraction for DTLS. There
- * should be no need to reach into |ssl->s3->rrec.length|. */
- const size_t frag_off = msg_hdr.frag_off;
- const size_t frag_len = msg_hdr.frag_len;
- const size_t msg_len = msg_hdr.msg_len;
- if (frag_off > msg_len || frag_off + frag_len < frag_off ||
- frag_off + frag_len > msg_len ||
- msg_len > ssl_max_handshake_message_len(ssl) ||
- frag_len > ssl->s3->rrec.length) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
- }
-
- if (msg_hdr.seq < ssl->d1->handshake_read_seq ||
- msg_hdr.seq > (unsigned)ssl->d1->handshake_read_seq +
- kHandshakeBufferSize) {
- /* Ignore fragments from the past, or ones too far in the future. */
- if (!dtls1_discard_fragment_body(ssl, frag_len)) {
+ while (CBS_len(&cbs) > 0) {
+ /* Read a handshake fragment. */
+ struct hm_header_st msg_hdr;
+ CBS body;
+ if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
}
- return 1;
- }
- hm_fragment *frag = dtls1_get_buffered_message(ssl, &msg_hdr);
- if (frag == NULL) {
- return -1;
- }
- assert(frag->msg_header.msg_len == msg_len);
-
- if (frag->reassembly == NULL) {
- /* The message is already assembled. */
- if (!dtls1_discard_fragment_body(ssl, frag_len)) {
+ const size_t frag_off = msg_hdr.frag_off;
+ const size_t frag_len = msg_hdr.frag_len;
+ const size_t msg_len = msg_hdr.msg_len;
+ if (frag_off > msg_len || frag_off + frag_len < frag_off ||
+ frag_off + frag_len > msg_len ||
+ msg_len > ssl_max_handshake_message_len(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
}
- return 1;
- }
- assert(msg_len > 0);
- /* Read the body of the fragment. */
- ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, frag->fragment + frag_off,
- frag_len, 0);
- if (ret != (int) frag_len) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
- }
- dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
+ if (msg_hdr.seq < ssl->d1->handshake_read_seq ||
+ msg_hdr.seq >
+ (unsigned)ssl->d1->handshake_read_seq + kHandshakeBufferSize) {
+ /* Ignore fragments from the past, or ones too far in the future. */
+ continue;
+ }
+ hm_fragment *frag = dtls1_get_buffered_message(ssl, &msg_hdr);
+ if (frag == NULL) {
+ return -1;
+ }
+ assert(frag->msg_header.msg_len == msg_len);
+
+ if (frag->reassembly == NULL) {
+ /* The message is already assembled. */
+ continue;
+ }
+ assert(msg_len > 0);
+
+ /* Copy the body into the fragment. */
+ memcpy(frag->fragment + frag_off, CBS_data(&body), CBS_len(&body));
+ dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
+ }
+
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
return 1;
}
@@ -584,9 +578,9 @@
return ssl->init_num;
}
- /* Process fragments until one is found. */
+ /* Process handshake records until the next message is ready. */
while (!dtls1_is_next_message_complete(ssl)) {
- int ret = dtls1_process_fragment(ssl);
+ int ret = dtls1_process_handshake_record(ssl);
if (ret <= 0) {
*ok = 0;
return ret;
@@ -637,11 +631,10 @@
if (hash_message == ssl_hash_message && !ssl3_hash_current_message(ssl)) {
goto err;
}
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
- ssl->init_num + DTLS1_HM_HEADER_LENGTH, ssl,
- ssl->msg_callback_arg);
- }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, ssl->version, SSL3_RT_HANDSHAKE,
+ ssl->init_buf->data,
+ ssl->init_num + DTLS1_HM_HEADER_LENGTH);
pitem_free(item);
dtls1_hm_fragment_free(frag);
@@ -658,27 +651,6 @@
return -1;
}
-int dtls1_read_failed(SSL *ssl, int code) {
- if (code > 0) {
- assert(0);
- return 1;
- }
-
- if (!dtls1_is_timer_expired(ssl)) {
- /* not a timeout, none of our business, let higher layers handle this. In
- * fact, it's probably an error */
- return code;
- }
-
- if (!SSL_in_init(ssl)) {
- /* done, no need to send a retransmit */
- BIO_set_flags(ssl->rbio, BIO_FLAGS_READ);
- return code;
- }
-
- return DTLSv1_handle_timeout(ssl);
-}
-
static uint16_t dtls1_get_queue_priority(uint16_t seq, int is_ccs) {
assert(seq * 2 >= seq);
@@ -862,13 +834,18 @@
return kMinMTU;
}
-void dtls1_get_message_header(uint8_t *data,
- struct hm_header_st *msg_hdr) {
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
- msg_hdr->type = *(data++);
- n2l3(data, msg_hdr->msg_len);
+int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
+ CBS *out_body) {
+ memset(out_hdr, 0x00, sizeof(struct hm_header_st));
- n2s(data, msg_hdr->seq);
- n2l3(data, msg_hdr->frag_off);
- n2l3(data, msg_hdr->frag_len);
+ if (!CBS_get_u8(cbs, &out_hdr->type) ||
+ !CBS_get_u24(cbs, &out_hdr->msg_len) ||
+ !CBS_get_u16(cbs, &out_hdr->seq) ||
+ !CBS_get_u24(cbs, &out_hdr->frag_off) ||
+ !CBS_get_u24(cbs, &out_hdr->frag_len) ||
+ !CBS_get_bytes(cbs, out_body, out_hdr->frag_len)) {
+ return 0;
+ }
+
+ return 1;
}
diff --git a/src/ssl/d1_clnt.c b/src/ssl/d1_clnt.c
deleted file mode 100644
index 19ad1f8..0000000
--- a/src/ssl/d1_clnt.c
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <openssl/ssl.h>
-
-#include <assert.h>
-#include <string.h>
-
-#include <openssl/bn.h>
-#include <openssl/buf.h>
-#include <openssl/dh.h>
-#include <openssl/evp.h>
-#include <openssl/err.h>
-#include <openssl/md5.h>
-#include <openssl/mem.h>
-#include <openssl/rand.h>
-
-#include "internal.h"
-
-
-static int dtls1_get_hello_verify(SSL *ssl);
-
-int dtls1_connect(SSL *ssl) {
- BUF_MEM *buf = NULL;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
- int ret = -1;
- int new_state, state, skip = 0;
-
- assert(ssl->handshake_func == dtls1_connect);
- assert(!ssl->server);
- assert(SSL_IS_DTLS(ssl));
-
- ERR_clear_system_error();
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- for (;;) {
- state = ssl->state;
-
- switch (ssl->state) {
- case SSL_ST_CONNECT:
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_START, 1);
- }
-
- if (ssl->init_buf == NULL) {
- buf = BUF_MEM_new();
- if (buf == NULL ||
- !BUF_MEM_reserve(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
- ret = -1;
- goto end;
- }
- ssl->init_buf = buf;
- buf = NULL;
- }
- ssl->init_num = 0;
-
- if (!ssl_init_wbio_buffer(ssl)) {
- ret = -1;
- goto end;
- }
-
- ssl->state = SSL3_ST_CW_CLNT_HELLO_A;
- ssl->d1->send_cookie = 0;
- ssl->hit = 0;
- break;
-
- case SSL3_ST_CW_CLNT_HELLO_A:
- case SSL3_ST_CW_CLNT_HELLO_B:
- dtls1_start_timer(ssl);
- ret = ssl3_send_client_hello(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- if (ssl->d1->send_cookie) {
- ssl->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A;
- } else {
- ssl->s3->tmp.next_state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
- }
- ssl->state = SSL3_ST_CW_FLUSH;
- break;
-
- case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
- ret = dtls1_get_hello_verify(ssl);
- if (ret <= 0) {
- goto end;
- }
- if (ssl->d1->send_cookie) {
- /* start again, with a cookie */
- dtls1_stop_timer(ssl);
- ssl->state = SSL3_ST_CW_CLNT_HELLO_A;
- } else {
- ssl->state = SSL3_ST_CR_SRVR_HELLO_A;
- }
- break;
-
- case SSL3_ST_CR_SRVR_HELLO_A:
- ret = ssl3_get_server_hello(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- if (ssl->hit) {
- ssl->state = SSL3_ST_CR_CHANGE;
- if (ssl->tlsext_ticket_expected) {
- /* receive renewed session ticket */
- ssl->state = SSL3_ST_CR_SESSION_TICKET_A;
- }
- } else {
- ssl->state = SSL3_ST_CR_CERT_A;
- }
- break;
-
- case SSL3_ST_CR_CERT_A:
- if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
- ret = ssl3_get_server_certificate(ssl);
- if (ret <= 0) {
- goto end;
- }
- if (ssl->s3->tmp.certificate_status_expected) {
- ssl->state = SSL3_ST_CR_CERT_STATUS_A;
- } else {
- ssl->state = SSL3_ST_VERIFY_SERVER_CERT;
- }
- } else {
- skip = 1;
- ssl->state = SSL3_ST_CR_KEY_EXCH_A;
- }
- break;
-
- case SSL3_ST_VERIFY_SERVER_CERT:
- ret = ssl3_verify_server_cert(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- ssl->state = SSL3_ST_CR_KEY_EXCH_A;
- break;
-
- case SSL3_ST_CR_KEY_EXCH_A:
- ret = ssl3_get_server_key_exchange(ssl);
- if (ret <= 0) {
- goto end;
- }
- if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
- ssl->state = SSL3_ST_CR_CERT_REQ_A;
- } else {
- ssl->state = SSL3_ST_CR_SRVR_DONE_A;
- }
- break;
-
- case SSL3_ST_CR_CERT_REQ_A:
- ret = ssl3_get_certificate_request(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_CR_SRVR_DONE_A;
- break;
-
- case SSL3_ST_CR_SRVR_DONE_A:
- ret = ssl3_get_server_done(ssl);
- if (ret <= 0) {
- goto end;
- }
- dtls1_stop_timer(ssl);
- if (ssl->s3->tmp.cert_req) {
- ssl->s3->tmp.next_state = SSL3_ST_CW_CERT_A;
- } else {
- ssl->s3->tmp.next_state = SSL3_ST_CW_KEY_EXCH_A;
- }
- ssl->state = ssl->s3->tmp.next_state;
- break;
-
- case SSL3_ST_CW_CERT_A:
- case SSL3_ST_CW_CERT_B:
- case SSL3_ST_CW_CERT_C:
- case SSL3_ST_CW_CERT_D:
- dtls1_start_timer(ssl);
- ret = ssl3_send_client_certificate(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_CW_KEY_EXCH_A;
- break;
-
- case SSL3_ST_CW_KEY_EXCH_A:
- case SSL3_ST_CW_KEY_EXCH_B:
- dtls1_start_timer(ssl);
- ret = ssl3_send_client_key_exchange(ssl);
- if (ret <= 0) {
- goto end;
- }
- /* For TLS, cert_req is set to 2, so a cert chain
- * of nothing is sent, but no verify packet is sent */
- if (ssl->s3->tmp.cert_req == 1) {
- ssl->state = SSL3_ST_CW_CERT_VRFY_A;
- } else {
- ssl->state = SSL3_ST_CW_CHANGE_A;
- }
- break;
-
- case SSL3_ST_CW_CERT_VRFY_A:
- case SSL3_ST_CW_CERT_VRFY_B:
- case SSL3_ST_CW_CERT_VRFY_C:
- dtls1_start_timer(ssl);
- ret = ssl3_send_cert_verify(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_CW_CHANGE_A;
- break;
-
- case SSL3_ST_CW_CHANGE_A:
- case SSL3_ST_CW_CHANGE_B:
- if (!ssl->hit) {
- dtls1_start_timer(ssl);
- }
- ret = dtls1_send_change_cipher_spec(ssl, SSL3_ST_CW_CHANGE_A,
- SSL3_ST_CW_CHANGE_B);
- if (ret <= 0) {
- goto end;
- }
-
- ssl->state = SSL3_ST_CW_FINISHED_A;
-
- if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
- ret = -1;
- goto end;
- }
- break;
-
- case SSL3_ST_CW_FINISHED_A:
- case SSL3_ST_CW_FINISHED_B:
- if (!ssl->hit) {
- dtls1_start_timer(ssl);
- }
-
- ret = ssl3_send_finished(ssl, SSL3_ST_CW_FINISHED_A,
- SSL3_ST_CW_FINISHED_B);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_CW_FLUSH;
-
- if (ssl->hit) {
- ssl->s3->tmp.next_state = SSL_ST_OK;
- } else {
- /* Allow NewSessionTicket if ticket expected */
- if (ssl->tlsext_ticket_expected) {
- ssl->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A;
- } else {
- ssl->s3->tmp.next_state = SSL3_ST_CR_CHANGE;
- }
- }
- break;
-
- case SSL3_ST_CR_SESSION_TICKET_A:
- ret = ssl3_get_new_session_ticket(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_CR_CHANGE;
- break;
-
- case SSL3_ST_CR_CERT_STATUS_A:
- ret = ssl3_get_cert_status(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_VERIFY_SERVER_CERT;
- break;
-
- case SSL3_ST_CR_CHANGE:
- ret = ssl->method->ssl_read_change_cipher_spec(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_READ)) {
- ret = -1;
- goto end;
- }
- ssl->state = SSL3_ST_CR_FINISHED_A;
- break;
-
- case SSL3_ST_CR_FINISHED_A:
- ret = ssl3_get_finished(ssl);
- if (ret <= 0) {
- goto end;
- }
- dtls1_stop_timer(ssl);
-
- if (ssl->hit) {
- ssl->state = SSL3_ST_CW_CHANGE_A;
- } else {
- ssl->state = SSL_ST_OK;
- }
-
- break;
-
- case SSL3_ST_CW_FLUSH:
- if (BIO_flush(ssl->wbio) <= 0) {
- ssl->rwstate = SSL_WRITING;
- ret = -1;
- goto end;
- }
- ssl->state = ssl->s3->tmp.next_state;
- break;
-
- case SSL_ST_OK:
- /* clean a few things up */
- ssl3_cleanup_key_block(ssl);
-
- /* Remove write buffering now. */
- ssl_free_wbio_buffer(ssl);
-
- /* |init_buf| cannot be released because post-handshake retransmit
- * relies on that buffer being available as scratch space.
- *
- * TODO(davidben): Fix this. */
- ssl->init_num = 0;
- ssl->s3->initial_handshake_complete = 1;
-
- ssl_update_cache(ssl, SSL_SESS_CACHE_CLIENT);
-
- ret = 1;
-
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_DONE, 1);
- }
-
- /* done with handshaking */
- ssl->d1->handshake_read_seq = 0;
- ssl->d1->next_handshake_write_seq = 0;
- goto end;
-
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
- ret = -1;
- goto end;
- }
-
- /* did we do anything? */
- if (!ssl->s3->tmp.reuse_message && !skip) {
- if ((cb != NULL) && (ssl->state != state)) {
- new_state = ssl->state;
- ssl->state = state;
- cb(ssl, SSL_CB_CONNECT_LOOP, 1);
- ssl->state = new_state;
- }
- }
- skip = 0;
- }
-
-end:
- BUF_MEM_free(buf);
- if (cb != NULL) {
- cb(ssl, SSL_CB_CONNECT_EXIT, ret);
- }
- return ret;
-}
-
-static int dtls1_get_hello_verify(SSL *ssl) {
- long n;
- int al, ok = 0;
- CBS hello_verify_request, cookie;
- uint16_t server_version;
-
- n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
-
- if (!ok) {
- return n;
- }
-
- if (ssl->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
- ssl->d1->send_cookie = 0;
- ssl->s3->tmp.reuse_message = 1;
- return 1;
- }
-
- CBS_init(&hello_verify_request, ssl->init_msg, n);
-
- if (!CBS_get_u16(&hello_verify_request, &server_version) ||
- !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
- CBS_len(&hello_verify_request) != 0) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- goto f_err;
- }
-
- if (CBS_len(&cookie) > sizeof(ssl->d1->cookie)) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- goto f_err;
- }
-
- memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
- ssl->d1->cookie_len = CBS_len(&cookie);
-
- ssl->d1->send_cookie = 1;
- return 1;
-
-f_err:
- ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
- return -1;
-}
diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c
index c1c9f91..73ae4cf 100644
--- a/src/ssl/d1_lib.c
+++ b/src/ssl/d1_lib.c
@@ -350,3 +350,11 @@
int dtls1_handshake_write(SSL *ssl) {
return dtls1_do_handshake_write(ssl, dtls1_use_current_epoch);
}
+
+void dtls1_expect_flight(SSL *ssl) {
+ dtls1_start_timer(ssl);
+}
+
+void dtls1_received_flight(SSL *ssl) {
+ dtls1_stop_timer(ssl);
+}
diff --git a/src/ssl/d1_meth.c b/src/ssl/d1_meth.c
index 49a2595..32a4651 100644
--- a/src/ssl/d1_meth.c
+++ b/src/ssl/d1_meth.c
@@ -63,8 +63,6 @@
1 /* is_dtls */,
dtls1_new,
dtls1_free,
- dtls1_accept,
- dtls1_connect,
dtls1_get_message,
dtls1_read_app_data,
dtls1_read_change_cipher_spec,
@@ -75,6 +73,9 @@
DTLS1_HM_HEADER_LENGTH,
dtls1_set_handshake_header,
dtls1_handshake_write,
+ dtls1_send_change_cipher_spec,
+ dtls1_expect_flight,
+ dtls1_received_flight,
};
const SSL_METHOD *DTLS_method(void) {
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 34eeddb..b821ab3 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -114,7 +114,9 @@
#include <assert.h>
#include <string.h>
+#include <openssl/bio.h>
#include <openssl/buf.h>
+#include <openssl/bytestring.h>
#include <openssl/mem.h>
#include <openssl/evp.h>
#include <openssl/err.h>
@@ -123,13 +125,7 @@
#include "internal.h"
-static int do_dtls1_write(SSL *ssl, int type, const uint8_t *buf,
- unsigned int len, enum dtls1_use_epoch_t use_epoch);
-
-/* dtls1_get_record reads a new input record. On success, it places it in
- * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
- * more data is needed. */
-static int dtls1_get_record(SSL *ssl) {
+int dtls1_get_record(SSL *ssl) {
again:
switch (ssl->s3->recv_shutdown) {
case ssl_shutdown_none:
@@ -143,50 +139,57 @@
/* Read a new packet if there is no unconsumed one. */
if (ssl_read_buffer_len(ssl) == 0) {
- int ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
- if (ret <= 0) {
- return ret;
+ int read_ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
+ if (read_ret < 0 && dtls1_is_timer_expired(ssl)) {
+ /* For blocking BIOs, retransmits must be handled internally. */
+ int timeout_ret = DTLSv1_handle_timeout(ssl);
+ if (timeout_ret <= 0) {
+ return timeout_ret;
+ }
+ goto again;
+ }
+ if (read_ret <= 0) {
+ return read_ret;
}
}
assert(ssl_read_buffer_len(ssl) > 0);
- /* Ensure the packet is large enough to decrypt in-place. */
- if (ssl_read_buffer_len(ssl) < ssl_record_prefix_len(ssl)) {
- ssl_read_buffer_clear(ssl);
- goto again;
- }
-
- uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl);
- size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl);
+ CBS body;
uint8_t type, alert;
- size_t len, consumed;
- switch (dtls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out,
- ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) {
- case ssl_open_record_success:
- ssl_read_buffer_consume(ssl, consumed);
+ size_t consumed;
+ enum ssl_open_record_t open_ret =
+ dtls_open_record(ssl, &type, &body, &consumed, &alert,
+ ssl_read_buffer(ssl), ssl_read_buffer_len(ssl));
+ ssl_read_buffer_consume(ssl, consumed);
+ switch (open_ret) {
+ case ssl_open_record_partial:
+ /* Impossible in DTLS. */
+ break;
- if (len > 0xffff) {
+ case ssl_open_record_success:
+ if (CBS_len(&body) > 0xffff) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return -1;
}
SSL3_RECORD *rr = &ssl->s3->rrec;
rr->type = type;
- rr->length = (uint16_t)len;
- rr->data = out;
+ rr->length = (uint16_t)CBS_len(&body);
+ rr->data = (uint8_t *)CBS_data(&body);
return 1;
case ssl_open_record_discard:
- ssl_read_buffer_consume(ssl, consumed);
goto again;
+ case ssl_open_record_close_notify:
+ return 0;
+
+ case ssl_open_record_fatal_alert:
+ return -1;
+
case ssl_open_record_error:
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return -1;
-
- case ssl_open_record_partial:
- /* Impossible in DTLS. */
- break;
}
assert(0);
@@ -196,214 +199,29 @@
int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) {
assert(!SSL_in_init(ssl));
- return dtls1_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek);
-}
-int dtls1_read_change_cipher_spec(SSL *ssl) {
- uint8_t byte;
- int ret = dtls1_read_bytes(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, &byte,
- 1 /* len */, 0 /* no peek */);
- if (ret <= 0) {
- return ret;
- }
- assert(ret == 1);
+ SSL3_RECORD *rr = &ssl->s3->rrec;
- if (ssl->s3->rrec.length != 0 || byte != SSL3_MT_CCS) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
- }
-
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_CHANGE_CIPHER_SPEC, &byte, 1,
- ssl, ssl->msg_callback_arg);
- }
-
- return 1;
-}
-
-void dtls1_read_close_notify(SSL *ssl) {
- /* Bidirectional shutdown doesn't make sense for an unordered transport. DTLS
- * alerts also aren't delivered reliably, so we may even time out because the
- * peer never received our close_notify. Report to the caller that the channel
- * has fully shut down. */
- if (ssl->s3->recv_shutdown == ssl_shutdown_none) {
- ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
- }
-}
-
-/* Return up to 'len' payload bytes received in 'type' records.
- * 'type' is one of the following:
- *
- * - SSL3_RT_HANDSHAKE (when dtls1_get_message calls us)
- * - SSL3_RT_CHANGE_CIPHER_SPEC (when dtls1_read_change_cipher_spec calls us)
- * - SSL3_RT_APPLICATION_DATA (when dtls1_read_app_data calls us)
- *
- * If we don't have stored data to work from, read a DTLS record first (possibly
- * multiple records if we still don't have anything to return).
- *
- * This function must handle any surprises the peer may have for us, such as
- * Alert records (e.g. close_notify) and out of records. */
-int dtls1_read_bytes(SSL *ssl, int type, unsigned char *buf, int len, int peek) {
- int al, ret;
- unsigned int n;
- SSL3_RECORD *rr;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
-
- if ((type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE &&
- type != SSL3_RT_CHANGE_CIPHER_SPEC) ||
- (peek && type != SSL3_RT_APPLICATION_DATA)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
-start:
- /* ssl->s3->rrec.type - is the type of record
- * ssl->s3->rrec.data - data
- * ssl->s3->rrec.off - offset into 'data' for next read
- * ssl->s3->rrec.length - number of bytes. */
- rr = &ssl->s3->rrec;
-
- /* Check for timeout */
- if (DTLSv1_handle_timeout(ssl) > 0) {
- goto start;
- }
-
- /* get new packet if necessary */
+again:
if (rr->length == 0) {
- ret = dtls1_get_record(ssl);
+ int ret = dtls1_get_record(ssl);
if (ret <= 0) {
- ret = dtls1_read_failed(ssl, ret);
- /* anything other than a timeout is an error */
- if (ret <= 0) {
- return ret;
- } else {
- goto start;
- }
+ return ret;
}
}
- /* we now have a packet which can be read and processed */
-
- if (type == rr->type) {
- /* Discard empty records. */
- if (rr->length == 0) {
- goto start;
- }
-
- if (len <= 0) {
- return len;
- }
-
- if ((unsigned int)len > rr->length) {
- n = rr->length;
- } else {
- n = (unsigned int)len;
- }
-
- memcpy(buf, rr->data, n);
- if (!peek) {
- rr->length -= n;
- rr->data += n;
- if (rr->length == 0) {
- /* The record has been consumed, so we may now clear the buffer. */
- ssl_read_buffer_discard(ssl);
- }
- }
-
- return n;
- }
-
- /* If we get here, then type != rr->type. */
-
- /* If an alert record, process the alert. */
- if (rr->type == SSL3_RT_ALERT) {
- /* Alerts records may not contain fragmented or multiple alerts. */
- if (rr->length != 2) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
- goto f_err;
- }
-
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_ALERT, rr->data, 2, ssl,
- ssl->msg_callback_arg);
- }
- const uint8_t alert_level = rr->data[0];
- const uint8_t alert_descr = rr->data[1];
- rr->length -= 2;
- rr->data += 2;
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- if (cb != NULL) {
- uint16_t alert = (alert_level << 8) | alert_descr;
- cb(ssl, SSL_CB_READ_ALERT, alert);
- }
-
- if (alert_level == SSL3_AL_WARNING) {
- if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
- ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
- return 0;
- }
- } else if (alert_level == SSL3_AL_FATAL) {
- char tmp[16];
-
- OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
- BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr);
- ERR_add_error_data(2, "SSL alert number ", tmp);
- ssl->s3->recv_shutdown = ssl_shutdown_fatal_alert;
- SSL_CTX_remove_session(ssl->ctx, ssl->session);
- return 0;
- } else {
- al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
- goto f_err;
- }
-
- goto start;
- }
-
- /* Cross-epoch records are discarded, but we may receive out-of-order
- * application data between ChangeCipherSpec and Finished or a ChangeCipherSpec
- * before the appropriate point in the handshake. Those must be silently
- * discarded.
- *
- * However, only allow the out-of-order records in the correct epoch.
- * Application data must come in the encrypted epoch, and ChangeCipherSpec in
- * the unencrypted epoch (we never renegotiate). Other cases fall through and
- * fail with a fatal error. */
- if ((rr->type == SSL3_RT_APPLICATION_DATA &&
- ssl->s3->aead_read_ctx != NULL) ||
- (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC &&
- ssl->s3->aead_read_ctx == NULL)) {
- rr->length = 0;
- goto start;
- }
-
if (rr->type == SSL3_RT_HANDSHAKE) {
- if (type != SSL3_RT_APPLICATION_DATA) {
- /* Out-of-order handshake record while looking for ChangeCipherSpec. Drop
- * it silently. */
- assert(type == SSL3_RT_CHANGE_CIPHER_SPEC);
- rr->length = 0;
- goto start;
- }
-
/* Parse the first fragment header to determine if this is a pre-CCS or
* post-CCS handshake record. DTLS resets handshake message numbers on each
* handshake, so renegotiations and retransmissions are ambiguous. */
- if (rr->length < DTLS1_HM_HEADER_LENGTH) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
- goto f_err;
- }
+ CBS cbs, body;
struct hm_header_st msg_hdr;
- dtls1_get_message_header(rr->data, &msg_hdr);
+ CBS_init(&cbs, rr->data, rr->length);
+ if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
+ return -1;
+ }
if (msg_hdr.type == SSL3_MT_FINISHED) {
if (msg_hdr.frag_off == 0) {
@@ -418,19 +236,95 @@
}
rr->length = 0;
- goto start;
+ goto again;
}
/* Otherwise, this is a pre-CCS handshake message from an unsupported
* renegotiation attempt. Fall through to the error path. */
}
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ if (rr->type != SSL3_RT_APPLICATION_DATA) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ return -1;
+ }
-f_err:
- ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
- return -1;
+ /* Discard empty records. */
+ if (rr->length == 0) {
+ goto again;
+ }
+
+ if (len <= 0) {
+ return len;
+ }
+
+ if ((unsigned)len > rr->length) {
+ len = rr->length;
+ }
+
+ memcpy(buf, rr->data, len);
+ if (!peek) {
+ /* TODO(davidben): Should the record be truncated instead? This is a
+ * datagram transport. See https://crbug.com/boringssl/65. */
+ rr->length -= len;
+ rr->data += len;
+ if (rr->length == 0) {
+ /* The record has been consumed, so we may now clear the buffer. */
+ ssl_read_buffer_discard(ssl);
+ }
+ }
+
+ return len;
+}
+
+int dtls1_read_change_cipher_spec(SSL *ssl) {
+ SSL3_RECORD *rr = &ssl->s3->rrec;
+
+again:
+ if (rr->length == 0) {
+ int ret = dtls1_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ /* Drop handshake records silently. The epochs match, so this must be a
+ * retransmit of a message we already received. */
+ if (rr->type == SSL3_RT_HANDSHAKE) {
+ rr->length = 0;
+ goto again;
+ }
+
+ /* Other record types are illegal in this epoch. Note all application data
+ * records come in the encrypted epoch. */
+ if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ return -1;
+ }
+
+ if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, ssl->version,
+ SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, rr->length);
+
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
+ return 1;
+}
+
+void dtls1_read_close_notify(SSL *ssl) {
+ /* Bidirectional shutdown doesn't make sense for an unordered transport. DTLS
+ * alerts also aren't delivered reliably, so we may even time out because the
+ * peer never received our close_notify. Report to the caller that the channel
+ * has fully shut down. */
+ if (ssl->s3->recv_shutdown == ssl_shutdown_none) {
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ }
}
int dtls1_write_app_data(SSL *ssl, const void *buf_, int len) {
@@ -441,20 +335,26 @@
return -1;
}
- return dtls1_write_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf_, len,
- dtls1_use_current_epoch);
+ if (len < 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH);
+ return -1;
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ int ret = dtls1_write_record(ssl, SSL3_RT_APPLICATION_DATA, buf_, (size_t)len,
+ dtls1_use_current_epoch);
+ if (ret <= 0) {
+ return ret;
+ }
+ return len;
}
-/* Call this to write data in records of type 'type' It will return <= 0 if not
- * all data has been sent or non-blocking IO. */
-int dtls1_write_bytes(SSL *ssl, int type, const void *buf, int len,
- enum dtls1_use_epoch_t use_epoch) {
+int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len,
+ enum dtls1_use_epoch_t use_epoch) {
assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
- return do_dtls1_write(ssl, type, buf, len, use_epoch);
-}
-
-static int do_dtls1_write(SSL *ssl, int type, const uint8_t *buf,
- unsigned int len, enum dtls1_use_epoch_t use_epoch) {
/* There should never be a pending write buffer in DTLS. One can't write half
* a datagram, so the write buffer is always dropped in
* |ssl_write_buffer_flush|. */
@@ -474,10 +374,6 @@
return -1;
}
- if (len == 0) {
- return 0;
- }
-
size_t max_out = len + ssl_max_seal_overhead(ssl);
uint8_t *out;
size_t ciphertext_len;
@@ -493,13 +389,13 @@
if (ret <= 0) {
return ret;
}
- return (int)len;
+ return 1;
}
int dtls1_dispatch_alert(SSL *ssl) {
ssl->s3->alert_dispatch = 0;
- int ret = do_dtls1_write(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2,
- dtls1_use_current_epoch);
+ int ret = dtls1_write_record(ssl, SSL3_RT_ALERT, &ssl->s3->send_alert[0], 2,
+ dtls1_use_current_epoch);
if (ret <= 0) {
ssl->s3->alert_dispatch = 1;
return ret;
@@ -510,22 +406,11 @@
BIO_flush(ssl->wbio);
}
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(1 /* write */, ssl->version, SSL3_RT_ALERT,
- ssl->s3->send_alert, 2, ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 1 /* write */, ssl->version, SSL3_RT_ALERT,
+ ssl->s3->send_alert, 2);
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- if (cb != NULL) {
- int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
- cb(ssl, SSL_CB_WRITE_ALERT, alert);
- }
+ int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
+ ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, alert);
return 1;
}
diff --git a/src/ssl/d1_srvr.c b/src/ssl/d1_srvr.c
deleted file mode 100644
index 9913e73..0000000
--- a/src/ssl/d1_srvr.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <openssl/ssl.h>
-
-#include <assert.h>
-
-#include <openssl/bn.h>
-#include <openssl/buf.h>
-#include <openssl/dh.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-
-#include "internal.h"
-
-
-int dtls1_accept(SSL *ssl) {
- BUF_MEM *buf = NULL;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
- uint32_t alg_a;
- int ret = -1;
- int new_state, state, skip = 0;
-
- assert(ssl->handshake_func == dtls1_accept);
- assert(ssl->server);
- assert(SSL_IS_DTLS(ssl));
-
- ERR_clear_system_error();
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- for (;;) {
- state = ssl->state;
-
- switch (ssl->state) {
- case SSL_ST_ACCEPT:
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_START, 1);
- }
-
- if (ssl->init_buf == NULL) {
- buf = BUF_MEM_new();
- if (buf == NULL || !BUF_MEM_reserve(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
- ret = -1;
- goto end;
- }
- ssl->init_buf = buf;
- buf = NULL;
- }
-
- ssl->init_num = 0;
-
- if (!ssl_init_wbio_buffer(ssl)) {
- ret = -1;
- goto end;
- }
-
- if (!ssl3_init_handshake_buffer(ssl)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- ret = -1;
- goto end;
- }
-
- ssl->state = SSL3_ST_SR_CLNT_HELLO_A;
- break;
-
- case SSL3_ST_SR_CLNT_HELLO_A:
- case SSL3_ST_SR_CLNT_HELLO_B:
- case SSL3_ST_SR_CLNT_HELLO_C:
- ret = ssl3_get_client_hello(ssl);
- if (ret <= 0) {
- goto end;
- }
- dtls1_stop_timer(ssl);
- ssl->state = SSL3_ST_SW_SRVR_HELLO_A;
- break;
-
- case SSL3_ST_SW_SRVR_HELLO_A:
- case SSL3_ST_SW_SRVR_HELLO_B:
- dtls1_start_timer(ssl);
- ret = ssl3_send_server_hello(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- if (ssl->hit) {
- if (ssl->tlsext_ticket_expected) {
- ssl->state = SSL3_ST_SW_SESSION_TICKET_A;
- } else {
- ssl->state = SSL3_ST_SW_CHANGE_A;
- }
- } else {
- ssl->state = SSL3_ST_SW_CERT_A;
- }
- break;
-
- case SSL3_ST_SW_CERT_A:
- case SSL3_ST_SW_CERT_B:
- if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
- dtls1_start_timer(ssl);
- ret = ssl3_send_server_certificate(ssl);
- if (ret <= 0) {
- goto end;
- }
- if (ssl->s3->tmp.certificate_status_expected) {
- ssl->state = SSL3_ST_SW_CERT_STATUS_A;
- } else {
- ssl->state = SSL3_ST_SW_KEY_EXCH_A;
- }
- } else {
- skip = 1;
- ssl->state = SSL3_ST_SW_KEY_EXCH_A;
- }
- break;
-
- case SSL3_ST_SW_CERT_STATUS_A:
- case SSL3_ST_SW_CERT_STATUS_B:
- ret = ssl3_send_certificate_status(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_SW_KEY_EXCH_A;
- break;
-
- case SSL3_ST_SW_KEY_EXCH_A:
- case SSL3_ST_SW_KEY_EXCH_B:
- case SSL3_ST_SW_KEY_EXCH_C:
- alg_a = ssl->s3->tmp.new_cipher->algorithm_auth;
-
- /* Send a ServerKeyExchange message if:
- * - The key exchange is ephemeral or anonymous
- * Diffie-Hellman.
- * - There is a PSK identity hint.
- *
- * TODO(davidben): This logic is currently duplicated
- * in s3_srvr.c. Fix this. In the meantime, keep them
- * in sync. */
- if (ssl_cipher_requires_server_key_exchange(ssl->s3->tmp.new_cipher) ||
- ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) {
- dtls1_start_timer(ssl);
- ret = ssl3_send_server_key_exchange(ssl);
- if (ret <= 0) {
- goto end;
- }
- } else {
- skip = 1;
- }
-
- ssl->state = SSL3_ST_SW_CERT_REQ_A;
- break;
-
- case SSL3_ST_SW_CERT_REQ_A:
- case SSL3_ST_SW_CERT_REQ_B:
- if (ssl->s3->tmp.cert_request) {
- dtls1_start_timer(ssl);
- ret = ssl3_send_certificate_request(ssl);
- if (ret <= 0) {
- goto end;
- }
- } else {
- skip = 1;
- }
- ssl->state = SSL3_ST_SW_SRVR_DONE_A;
- break;
-
- case SSL3_ST_SW_SRVR_DONE_A:
- case SSL3_ST_SW_SRVR_DONE_B:
- dtls1_start_timer(ssl);
- ret = ssl3_send_server_done(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->s3->tmp.next_state = SSL3_ST_SR_CERT_A;
- ssl->state = SSL3_ST_SW_FLUSH;
- break;
-
- case SSL3_ST_SW_FLUSH:
- if (BIO_flush(ssl->wbio) <= 0) {
- ssl->rwstate = SSL_WRITING;
- ret = -1;
- goto end;
- }
- ssl->state = ssl->s3->tmp.next_state;
- break;
-
- case SSL3_ST_SR_CERT_A:
- if (ssl->s3->tmp.cert_request) {
- ret = ssl3_get_client_certificate(ssl);
- if (ret <= 0) {
- goto end;
- }
- }
- ssl->state = SSL3_ST_SR_KEY_EXCH_A;
- break;
-
- case SSL3_ST_SR_KEY_EXCH_A:
- case SSL3_ST_SR_KEY_EXCH_B:
- ret = ssl3_get_client_key_exchange(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_SR_CERT_VRFY_A;
- break;
-
- case SSL3_ST_SR_CERT_VRFY_A:
- ret = ssl3_get_cert_verify(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_SR_CHANGE;
- break;
-
- case SSL3_ST_SR_CHANGE:
- ret = ssl->method->ssl_read_change_cipher_spec(ssl);
- if (ret <= 0) {
- goto end;
- }
-
- if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_READ)) {
- ret = -1;
- goto end;
- }
-
- ssl->state = SSL3_ST_SR_FINISHED_A;
- break;
-
- case SSL3_ST_SR_FINISHED_A:
- ret = ssl3_get_finished(ssl);
- if (ret <= 0) {
- goto end;
- }
- dtls1_stop_timer(ssl);
- if (ssl->hit) {
- ssl->state = SSL_ST_OK;
- } else if (ssl->tlsext_ticket_expected) {
- ssl->state = SSL3_ST_SW_SESSION_TICKET_A;
- } else {
- ssl->state = SSL3_ST_SW_CHANGE_A;
- }
- break;
-
- case SSL3_ST_SW_SESSION_TICKET_A:
- case SSL3_ST_SW_SESSION_TICKET_B:
- ret = ssl3_send_new_session_ticket(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_SW_CHANGE_A;
- break;
-
- case SSL3_ST_SW_CHANGE_A:
- case SSL3_ST_SW_CHANGE_B:
- ret = dtls1_send_change_cipher_spec(ssl, SSL3_ST_SW_CHANGE_A,
- SSL3_ST_SW_CHANGE_B);
-
- if (ret <= 0) {
- goto end;
- }
-
- ssl->state = SSL3_ST_SW_FINISHED_A;
-
- if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
- ret = -1;
- goto end;
- }
- break;
-
- case SSL3_ST_SW_FINISHED_A:
- case SSL3_ST_SW_FINISHED_B:
- ret = ssl3_send_finished(ssl, SSL3_ST_SW_FINISHED_A,
- SSL3_ST_SW_FINISHED_B);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_SW_FLUSH;
- if (ssl->hit) {
- ssl->s3->tmp.next_state = SSL3_ST_SR_CHANGE;
- } else {
- ssl->s3->tmp.next_state = SSL_ST_OK;
- }
- break;
-
- case SSL_ST_OK:
- ssl3_cleanup_key_block(ssl);
-
- /* remove buffering on output */
- ssl_free_wbio_buffer(ssl);
-
- /* |init_buf| cannot be released because post-handshake retransmit
- * relies on that buffer being available as scratch space.
- *
- * TODO(davidben): Fix this. */
- ssl->init_num = 0;
- ssl->s3->initial_handshake_complete = 1;
-
- ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER);
-
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_DONE, 1);
- }
-
- ret = 1;
-
- /* done handshaking, next message is client hello */
- ssl->d1->handshake_read_seq = 0;
- /* next message is server hello */
- ssl->d1->handshake_write_seq = 0;
- ssl->d1->next_handshake_write_seq = 0;
- goto end;
-
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
- ret = -1;
- goto end;
- }
-
- if (!ssl->s3->tmp.reuse_message && !skip) {
- if (cb != NULL && ssl->state != state) {
- new_state = ssl->state;
- ssl->state = state;
- cb(ssl, SSL_CB_ACCEPT_LOOP, 1);
- ssl->state = new_state;
- }
- }
- skip = 0;
- }
-
-end:
- BUF_MEM_free(buf);
- if (cb != NULL) {
- cb(ssl, SSL_CB_ACCEPT_EXIT, ret);
- }
- return ret;
-}
diff --git a/src/ssl/dtls_record.c b/src/ssl/dtls_record.c
index eaf6df7..e784e55 100644
--- a/src/ssl/dtls_record.c
+++ b/src/ssl/dtls_record.c
@@ -118,6 +118,7 @@
#include <openssl/err.h>
#include "internal.h"
+#include "../crypto/internal.h"
/* to_u64_be treats |in| as a 8-byte big-endian integer and returns the value as
@@ -171,10 +172,12 @@
}
}
-enum ssl_open_record_t dtls_open_record(
- SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
- size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
- size_t in_len) {
+enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed,
+ uint8_t *out_alert, uint8_t *in,
+ size_t in_len) {
+ *out_consumed = 0;
+
CBS cbs;
CBS_init(&cbs, in, in_len);
@@ -195,10 +198,8 @@
return ssl_open_record_discard;
}
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in,
- DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 0 /* read */, 0, SSL3_RT_HEADER, in,
+ DTLS1_RT_HEADER_LENGTH);
uint16_t epoch = (((uint16_t)sequence[0]) << 8) | sequence[1];
if (epoch != ssl->d1->r_epoch ||
@@ -211,11 +212,9 @@
return ssl_open_record_discard;
}
- /* Decrypt the body. */
- size_t plaintext_len;
- if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, &plaintext_len, max_out,
- type, version, sequence, CBS_data(&body),
- CBS_len(&body))) {
+ /* Decrypt the body in-place. */
+ if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version, sequence,
+ (uint8_t *)CBS_data(&body), CBS_len(&body))) {
/* Bad packets are silently dropped in DTLS. See section 4.2.1 of RFC 6347.
* Clear the error queue of any errors decryption may have added. Drop the
* entire packet as it must not have come from the peer.
@@ -226,9 +225,10 @@
*out_consumed = in_len - CBS_len(&cbs);
return ssl_open_record_discard;
}
+ *out_consumed = in_len - CBS_len(&cbs);
/* Check the plaintext length. */
- if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ if (CBS_len(out) > SSL3_RT_MAX_PLAIN_LENGTH) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
*out_alert = SSL_AD_RECORD_OVERFLOW;
return ssl_open_record_error;
@@ -239,15 +239,24 @@
/* TODO(davidben): Limit the number of empty records as in TLS? This is only
* useful if we also limit discarded packets. */
+ if (type == SSL3_RT_ALERT) {
+ return ssl_process_alert(ssl, out_alert, CBS_data(out), CBS_len(out));
+ }
+
+ ssl->s3->warning_alert_count = 0;
+
*out_type = type;
- *out_len = plaintext_len;
- *out_consumed = in_len - CBS_len(&cbs);
return ssl_open_record_success;
}
int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
uint8_t type, const uint8_t *in, size_t in_len,
enum dtls1_use_epoch_t use_epoch) {
+ if (buffers_alias(in, in_len, out, max_out)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+
/* Determine the parameters for the current epoch. */
uint16_t epoch = ssl->d1->w_epoch;
SSL_AEAD_CTX *aead = ssl->s3->aead_write_ctx;
@@ -265,12 +274,6 @@
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
- /* Check the record header does not alias any part of the input.
- * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */
- if (in < out + DTLS1_RT_HEADER_LENGTH && out < in + in_len) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
- return 0;
- }
out[0] = type;
@@ -299,10 +302,8 @@
*out_len = DTLS1_RT_HEADER_LENGTH + ciphertext_len;
- if (ssl->msg_callback) {
- ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out,
- DTLS1_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 1 /* write */, 0, SSL3_RT_HEADER, out,
+ DTLS1_RT_HEADER_LENGTH);
return 1;
}
diff --git a/src/ssl/s3_clnt.c b/src/ssl/handshake_client.c
similarity index 92%
rename from src/ssl/s3_clnt.c
rename to src/ssl/handshake_client.c
index 2665f15..9b96bcd 100644
--- a/src/ssl/s3_clnt.c
+++ b/src/ssl/handshake_client.c
@@ -170,32 +170,36 @@
#include "../crypto/dh/internal.h"
+static int ssl3_send_client_hello(SSL *ssl);
+static int dtls1_get_hello_verify(SSL *ssl);
+static int ssl3_get_server_hello(SSL *ssl);
+static int ssl3_get_server_certificate(SSL *ssl);
+static int ssl3_get_cert_status(SSL *ssl);
+static int ssl3_verify_server_cert(SSL *ssl);
+static int ssl3_get_server_key_exchange(SSL *ssl);
+static int ssl3_get_certificate_request(SSL *ssl);
+static int ssl3_get_server_hello_done(SSL *ssl);
+static int ssl3_send_client_certificate(SSL *ssl);
+static int ssl3_send_client_key_exchange(SSL *ssl);
+static int ssl3_send_cert_verify(SSL *ssl);
+static int ssl3_send_next_proto(SSL *ssl);
+static int ssl3_send_channel_id(SSL *ssl);
+static int ssl3_get_new_session_ticket(SSL *ssl);
+
int ssl3_connect(SSL *ssl) {
BUF_MEM *buf = NULL;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
int ret = -1;
- int new_state, state, skip = 0;
+ int state, skip = 0;
assert(ssl->handshake_func == ssl3_connect);
assert(!ssl->server);
- assert(!SSL_IS_DTLS(ssl));
-
- ERR_clear_system_error();
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
for (;;) {
state = ssl->state;
switch (ssl->state) {
case SSL_ST_CONNECT:
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_START, 1);
- }
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
if (ssl->init_buf == NULL) {
buf = BUF_MEM_new();
@@ -215,12 +219,6 @@
goto end;
}
- if (!ssl3_init_handshake_buffer(ssl)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- ret = -1;
- goto end;
- }
-
ssl->state = SSL3_ST_CW_CLNT_HELLO_A;
break;
@@ -230,10 +228,29 @@
if (ret <= 0) {
goto end;
}
- ssl->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A;
+
+ if (!SSL_IS_DTLS(ssl) || ssl->d1->send_cookie) {
+ ssl->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A;
+ } else {
+ ssl->s3->tmp.next_state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
+ }
ssl->state = SSL3_ST_CW_FLUSH;
break;
+ case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
+ assert(SSL_IS_DTLS(ssl));
+ ret = dtls1_get_hello_verify(ssl);
+ if (ret <= 0) {
+ goto end;
+ }
+ if (ssl->d1->send_cookie) {
+ ssl->method->received_flight(ssl);
+ ssl->state = SSL3_ST_CW_CLNT_HELLO_A;
+ } else {
+ ssl->state = SSL3_ST_CR_SRVR_HELLO_A;
+ }
+ break;
+
case SSL3_ST_CR_SRVR_HELLO_A:
ret = ssl3_get_server_hello(ssl);
if (ret <= 0) {
@@ -268,6 +285,14 @@
}
break;
+ case SSL3_ST_CR_CERT_STATUS_A:
+ ret = ssl3_get_cert_status(ssl);
+ if (ret <= 0) {
+ goto end;
+ }
+ ssl->state = SSL3_ST_VERIFY_SERVER_CERT;
+ break;
+
case SSL3_ST_VERIFY_SERVER_CERT:
ret = ssl3_verify_server_cert(ssl);
if (ret <= 0) {
@@ -298,16 +323,16 @@
break;
case SSL3_ST_CR_SRVR_DONE_A:
- ret = ssl3_get_server_done(ssl);
+ ret = ssl3_get_server_hello_done(ssl);
if (ret <= 0) {
goto end;
}
+ ssl->method->received_flight(ssl);
if (ssl->s3->tmp.cert_req) {
ssl->state = SSL3_ST_CW_CERT_A;
} else {
ssl->state = SSL3_ST_CW_KEY_EXCH_A;
}
-
break;
case SSL3_ST_CW_CERT_A:
@@ -348,8 +373,8 @@
case SSL3_ST_CW_CHANGE_A:
case SSL3_ST_CW_CHANGE_B:
- ret = ssl3_send_change_cipher_spec(ssl, SSL3_ST_CW_CHANGE_A,
- SSL3_ST_CW_CHANGE_B);
+ ret = ssl->method->send_change_cipher_spec(ssl, SSL3_ST_CW_CHANGE_A,
+ SSL3_ST_CW_CHANGE_B);
if (ret <= 0) {
goto end;
}
@@ -429,6 +454,19 @@
}
break;
+ case SSL3_ST_FALSE_START:
+ /* Allow NewSessionTicket if ticket expected */
+ if (ssl->tlsext_ticket_expected) {
+ ssl->state = SSL3_ST_CR_SESSION_TICKET_A;
+ } else {
+ ssl->state = SSL3_ST_CR_CHANGE;
+ }
+ ssl->s3->tmp.in_false_start = 1;
+
+ ssl_free_wbio_buffer(ssl);
+ ret = 1;
+ goto end;
+
case SSL3_ST_CR_SESSION_TICKET_A:
ret = ssl3_get_new_session_ticket(ssl);
if (ret <= 0) {
@@ -437,14 +475,6 @@
ssl->state = SSL3_ST_CR_CHANGE;
break;
- case SSL3_ST_CR_CERT_STATUS_A:
- ret = ssl3_get_cert_status(ssl);
- if (ret <= 0) {
- goto end;
- }
- ssl->state = SSL3_ST_VERIFY_SERVER_CERT;
- break;
-
case SSL3_ST_CR_CHANGE:
ret = ssl->method->ssl_read_change_cipher_spec(ssl);
if (ret <= 0) {
@@ -463,6 +493,7 @@
if (ret <= 0) {
goto end;
}
+ ssl->method->received_flight(ssl);
if (ssl->hit) {
ssl->state = SSL3_ST_CW_CHANGE_A;
@@ -478,28 +509,24 @@
goto end;
}
ssl->state = ssl->s3->tmp.next_state;
- break;
-
- case SSL3_ST_FALSE_START:
- /* Allow NewSessionTicket if ticket expected */
- if (ssl->tlsext_ticket_expected) {
- ssl->state = SSL3_ST_CR_SESSION_TICKET_A;
- } else {
- ssl->state = SSL3_ST_CR_CHANGE;
+ if (ssl->state != SSL_ST_OK) {
+ ssl->method->expect_flight(ssl);
}
- ssl->s3->tmp.in_false_start = 1;
-
- ssl_free_wbio_buffer(ssl);
- ret = 1;
- goto end;
+ break;
case SSL_ST_OK:
/* clean a few things up */
ssl3_cleanup_key_block(ssl);
- BUF_MEM_free(ssl->init_buf);
- ssl->init_buf = NULL;
- ssl->init_num = 0;
+ /* |init_buf| cannot be released in DTLS because post-handshake
+ * retransmit relies on that buffer being available as scratch space.
+ *
+ * TODO(davidben): Fix this. */
+ if (!SSL_IS_DTLS(ssl)) {
+ BUF_MEM_free(ssl->init_buf);
+ ssl->init_buf = NULL;
+ ssl->init_num = 0;
+ }
/* Remove write buffering now. */
ssl_free_wbio_buffer(ssl);
@@ -514,13 +541,13 @@
ssl_update_cache(ssl, SSL_SESS_CACHE_CLIENT);
}
- ret = 1;
- /* ssl->server=0; */
-
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_DONE, 1);
+ if (SSL_IS_DTLS(ssl)) {
+ ssl->d1->handshake_read_seq = 0;
+ ssl->d1->next_handshake_write_seq = 0;
}
+ ret = 1;
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
goto end;
default:
@@ -529,22 +556,18 @@
goto end;
}
- if (!ssl->s3->tmp.reuse_message && !skip) {
- if (cb != NULL && ssl->state != state) {
- new_state = ssl->state;
- ssl->state = state;
- cb(ssl, SSL_CB_CONNECT_LOOP, 1);
- ssl->state = new_state;
- }
+ if (!ssl->s3->tmp.reuse_message && !skip && ssl->state != state) {
+ int new_state = ssl->state;
+ ssl->state = state;
+ ssl_do_info_callback(ssl, SSL_CB_CONNECT_LOOP, 1);
+ ssl->state = new_state;
}
skip = 0;
}
end:
BUF_MEM_free(buf);
- if (cb != NULL) {
- cb(ssl, SSL_CB_CONNECT_EXIT, ret);
- }
+ ssl_do_info_callback(ssl, SSL_CB_CONNECT_EXIT, ret);
return ret;
}
@@ -603,14 +626,14 @@
return CBB_flush(out);
}
-int ssl3_send_client_hello(SSL *ssl) {
+static int ssl3_send_client_hello(SSL *ssl) {
if (ssl->state == SSL3_ST_CW_CLNT_HELLO_B) {
return ssl_do_write(ssl);
}
- /* In DTLS, reset the handshake buffer each time a new ClientHello is
- * assembled. We may send multiple if we receive HelloVerifyRequest. */
- if (SSL_IS_DTLS(ssl) && !ssl3_init_handshake_buffer(ssl)) {
+ /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we
+ * may send multiple ClientHellos if we receive HelloVerifyRequest. */
+ if (!ssl3_init_handshake_buffer(ssl)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -694,7 +717,51 @@
return -1;
}
-int ssl3_get_server_hello(SSL *ssl) {
+static int dtls1_get_hello_verify(SSL *ssl) {
+ long n;
+ int al, ok = 0;
+ CBS hello_verify_request, cookie;
+ uint16_t server_version;
+
+ n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
+
+ if (!ok) {
+ return n;
+ }
+
+ if (ssl->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
+ ssl->d1->send_cookie = 0;
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
+ CBS_init(&hello_verify_request, ssl->init_msg, n);
+
+ if (!CBS_get_u16(&hello_verify_request, &server_version) ||
+ !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
+ CBS_len(&hello_verify_request) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ if (CBS_len(&cookie) > sizeof(ssl->d1->cookie)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ goto f_err;
+ }
+
+ memcpy(ssl->d1->cookie, CBS_data(&cookie), CBS_len(&cookie));
+ ssl->d1->cookie_len = CBS_len(&cookie);
+
+ ssl->d1->send_cookie = 1;
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ return -1;
+}
+
+static int ssl3_get_server_hello(SSL *ssl) {
STACK_OF(SSL_CIPHER) *sk;
const SSL_CIPHER *c;
CERT *ct = ssl->cert;
@@ -924,7 +991,7 @@
return ret;
}
-int ssl3_get_server_certificate(SSL *ssl) {
+static int ssl3_get_server_certificate(SSL *ssl) {
int al, ok, ret = -1;
unsigned long n;
X509 *x = NULL;
@@ -1014,7 +1081,64 @@
return ret;
}
-int ssl3_get_server_key_exchange(SSL *ssl) {
+static int ssl3_get_cert_status(SSL *ssl) {
+ int ok, al;
+ long n;
+ CBS certificate_status, ocsp_response;
+ uint8_t status_type;
+
+ n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
+
+ if (!ok) {
+ return n;
+ }
+
+ if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) {
+ /* A server may send status_request in ServerHello and then change
+ * its mind about sending CertificateStatus. */
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
+ CBS_init(&certificate_status, ssl->init_msg, n);
+ if (!CBS_get_u8(&certificate_status, &status_type) ||
+ status_type != TLSEXT_STATUSTYPE_ocsp ||
+ !CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) ||
+ CBS_len(&ocsp_response) == 0 ||
+ CBS_len(&certificate_status) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ if (!CBS_stow(&ocsp_response, &ssl->session->ocsp_response,
+ &ssl->session->ocsp_response_length)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ return 1;
+
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ return -1;
+}
+
+static int ssl3_verify_server_cert(SSL *ssl) {
+ int ret = ssl_verify_cert_chain(ssl, ssl->session->cert_chain);
+ if (ssl->verify_mode != SSL_VERIFY_NONE && ret <= 0) {
+ int al = ssl_verify_alarm_type(ssl->verify_result);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
+ } else {
+ ret = 1;
+ ERR_clear_error(); /* but we keep ssl->verify_result */
+ }
+
+ return ret;
+}
+
+static int ssl3_get_server_key_exchange(SSL *ssl) {
EVP_MD_CTX md_ctx;
int al, ok;
EVP_PKEY *pkey = NULL;
@@ -1283,7 +1407,7 @@
return X509_NAME_cmp(*a, *b);
}
-int ssl3_get_certificate_request(SSL *ssl) {
+static int ssl3_get_certificate_request(SSL *ssl) {
int ok, ret = 0;
X509_NAME *xn = NULL;
STACK_OF(X509_NAME) *ca_sk = NULL;
@@ -1296,7 +1420,7 @@
ssl->s3->tmp.cert_req = 0;
- if (ssl->s3->tmp.message_type == SSL3_MT_SERVER_DONE) {
+ if (ssl->s3->tmp.message_type == SSL3_MT_SERVER_HELLO_DONE) {
ssl->s3->tmp.reuse_message = 1;
/* If we get here we don't need the handshake buffer as we won't be doing
* client auth. */
@@ -1391,128 +1515,12 @@
return ret;
}
-int ssl3_get_new_session_ticket(SSL *ssl) {
- int ok, al;
- long n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEW_SESSION_TICKET,
- ssl_hash_message, &ok);
-
- if (!ok) {
- return n;
- }
-
- CBS new_session_ticket, ticket;
- uint32_t ticket_lifetime_hint;
- CBS_init(&new_session_ticket, ssl->init_msg, n);
- if (!CBS_get_u32(&new_session_ticket, &ticket_lifetime_hint) ||
- !CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) ||
- CBS_len(&new_session_ticket) != 0) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- goto f_err;
- }
-
- if (CBS_len(&ticket) == 0) {
- /* RFC 5077 allows a server to change its mind and send no ticket after
- * negotiating the extension. The value of |tlsext_ticket_expected| is
- * checked in |ssl_update_cache| so is cleared here to avoid an unnecessary
- * update. */
- ssl->tlsext_ticket_expected = 0;
- return 1;
- }
-
- if (ssl->hit) {
- /* The server is sending a new ticket for an existing session. Sessions are
- * immutable once established, so duplicate all but the ticket of the
- * existing session. */
- uint8_t *bytes;
- size_t bytes_len;
- if (!SSL_SESSION_to_bytes_for_ticket(ssl->session, &bytes, &bytes_len)) {
- goto err;
- }
- SSL_SESSION *new_session = SSL_SESSION_from_bytes(bytes, bytes_len);
- OPENSSL_free(bytes);
- if (new_session == NULL) {
- /* This should never happen. */
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- SSL_SESSION_free(ssl->session);
- ssl->session = new_session;
- }
-
- if (!CBS_stow(&ticket, &ssl->session->tlsext_tick,
- &ssl->session->tlsext_ticklen)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- ssl->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
-
- /* Generate a session ID for this session based on the session ticket. We use
- * the session ID mechanism for detecting ticket resumption. This also fits in
- * with assumptions elsewhere in OpenSSL.*/
- if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), ssl->session->session_id,
- &ssl->session->session_id_length, EVP_sha256(), NULL)) {
- goto err;
- }
-
- return 1;
-
-f_err:
- ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
-err:
- return -1;
-}
-
-int ssl3_get_cert_status(SSL *ssl) {
- int ok, al;
- long n;
- CBS certificate_status, ocsp_response;
- uint8_t status_type;
-
- n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
-
- if (!ok) {
- return n;
- }
-
- if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) {
- /* A server may send status_request in ServerHello and then change
- * its mind about sending CertificateStatus. */
- ssl->s3->tmp.reuse_message = 1;
- return 1;
- }
-
- CBS_init(&certificate_status, ssl->init_msg, n);
- if (!CBS_get_u8(&certificate_status, &status_type) ||
- status_type != TLSEXT_STATUSTYPE_ocsp ||
- !CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) ||
- CBS_len(&ocsp_response) == 0 ||
- CBS_len(&certificate_status) != 0) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- goto f_err;
- }
-
- if (!CBS_stow(&ocsp_response, &ssl->session->ocsp_response,
- &ssl->session->ocsp_response_length)) {
- al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto f_err;
- }
- return 1;
-
-f_err:
- ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
- return -1;
-}
-
-int ssl3_get_server_done(SSL *ssl) {
+static int ssl3_get_server_hello_done(SSL *ssl) {
int ok;
long n;
- n = ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_DONE, ssl_hash_message,
- &ok);
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_HELLO_DONE,
+ ssl_hash_message, &ok);
if (!ok) {
return n;
@@ -1528,10 +1536,105 @@
return 1;
}
+/* ssl3_has_client_certificate returns true if a client certificate is
+ * configured. */
+static int ssl3_has_client_certificate(SSL *ssl) {
+ return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl);
+}
+
+static int ssl_do_client_cert_cb(SSL *ssl, X509 **out_x509,
+ EVP_PKEY **out_pkey) {
+ if (ssl->ctx->client_cert_cb == NULL) {
+ return 0;
+ }
+
+ int ret = ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ assert(*out_x509 != NULL);
+ assert(*out_pkey != NULL);
+ return 1;
+}
+
+static int ssl3_send_client_certificate(SSL *ssl) {
+ if (ssl->state == SSL3_ST_CW_CERT_A) {
+ /* Call cert_cb to update the certificate. */
+ if (ssl->cert->cert_cb) {
+ int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+ if (ret < 0) {
+ ssl->rwstate = SSL_X509_LOOKUP;
+ return -1;
+ }
+ if (ret == 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return -1;
+ }
+ }
+
+ if (ssl3_has_client_certificate(ssl)) {
+ ssl->state = SSL3_ST_CW_CERT_C;
+ } else {
+ ssl->state = SSL3_ST_CW_CERT_B;
+ }
+ }
+
+ if (ssl->state == SSL3_ST_CW_CERT_B) {
+ /* Call client_cert_cb to update the certificate. */
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ int ret = ssl_do_client_cert_cb(ssl, &x509, &pkey);
+ if (ret < 0) {
+ ssl->rwstate = SSL_X509_LOOKUP;
+ return -1;
+ }
+
+ int setup_error = ret == 1 && (!SSL_use_certificate(ssl, x509) ||
+ !SSL_use_PrivateKey(ssl, pkey));
+ X509_free(x509);
+ EVP_PKEY_free(pkey);
+ if (setup_error) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return -1;
+ }
+
+ ssl->state = SSL3_ST_CW_CERT_C;
+ }
+
+ if (ssl->state == SSL3_ST_CW_CERT_C) {
+ if (!ssl3_has_client_certificate(ssl)) {
+ /* Without a client certificate, the handshake buffer may be released. */
+ ssl3_free_handshake_buffer(ssl);
+
+ if (ssl->version == SSL3_VERSION) {
+ /* In SSL 3.0, send no certificate by skipping both messages. */
+ ssl->s3->tmp.cert_req = 0;
+ ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
+ return 1;
+ }
+
+ /* In TLS, send an empty Certificate message. */
+ ssl->s3->tmp.cert_req = 2;
+ uint8_t *p = ssl_handshake_start(ssl);
+ l2n3(0, p);
+ if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, 3)) {
+ return -1;
+ }
+ } else if (!ssl3_output_cert_chain(ssl)) {
+ return -1;
+ }
+ ssl->state = SSL3_ST_CW_CERT_D;
+ }
+
+ assert(ssl->state == SSL3_ST_CW_CERT_D);
+ return ssl_do_write(ssl);
+}
+
OPENSSL_COMPILE_ASSERT(sizeof(size_t) >= sizeof(unsigned),
SIZE_T_IS_SMALLER_THAN_UNSIGNED);
-int ssl3_send_client_key_exchange(SSL *ssl) {
+static int ssl3_send_client_key_exchange(SSL *ssl) {
if (ssl->state == SSL3_ST_CW_KEY_EXCH_B) {
return ssl_do_write(ssl);
}
@@ -1729,7 +1832,7 @@
return -1;
}
-int ssl3_send_cert_verify(SSL *ssl) {
+static int ssl3_send_cert_verify(SSL *ssl) {
if (ssl->state == SSL3_ST_CW_CERT_VRFY_C) {
return ssl_do_write(ssl);
}
@@ -1818,86 +1921,7 @@
return -1;
}
-/* ssl3_has_client_certificate returns true if a client certificate is
- * configured. */
-static int ssl3_has_client_certificate(SSL *ssl) {
- return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl);
-}
-
-int ssl3_send_client_certificate(SSL *ssl) {
- if (ssl->state == SSL3_ST_CW_CERT_A) {
- /* Call cert_cb to update the certificate. */
- if (ssl->cert->cert_cb) {
- int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
- if (ret < 0) {
- ssl->rwstate = SSL_X509_LOOKUP;
- return -1;
- }
- if (ret == 0) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
- }
- }
-
- if (ssl3_has_client_certificate(ssl)) {
- ssl->state = SSL3_ST_CW_CERT_C;
- } else {
- ssl->state = SSL3_ST_CW_CERT_B;
- }
- }
-
- if (ssl->state == SSL3_ST_CW_CERT_B) {
- /* Call client_cert_cb to update the certificate. */
- X509 *x509 = NULL;
- EVP_PKEY *pkey = NULL;
- int ret = ssl_do_client_cert_cb(ssl, &x509, &pkey);
- if (ret < 0) {
- ssl->rwstate = SSL_X509_LOOKUP;
- return -1;
- }
-
- int setup_error = ret == 1 && (!SSL_use_certificate(ssl, x509) ||
- !SSL_use_PrivateKey(ssl, pkey));
- X509_free(x509);
- EVP_PKEY_free(pkey);
- if (setup_error) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
- }
-
- ssl->state = SSL3_ST_CW_CERT_C;
- }
-
- if (ssl->state == SSL3_ST_CW_CERT_C) {
- if (!ssl3_has_client_certificate(ssl)) {
- /* Without a client certificate, the handshake buffer may be released. */
- ssl3_free_handshake_buffer(ssl);
-
- if (ssl->version == SSL3_VERSION) {
- /* In SSL 3.0, send no certificate by skipping both messages. */
- ssl->s3->tmp.cert_req = 0;
- ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
- return 1;
- }
-
- /* In TLS, send an empty Certificate message. */
- ssl->s3->tmp.cert_req = 2;
- uint8_t *p = ssl_handshake_start(ssl);
- l2n3(0, p);
- if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, 3)) {
- return -1;
- }
- } else if (!ssl3_output_cert_chain(ssl)) {
- return -1;
- }
- ssl->state = SSL3_ST_CW_CERT_D;
- }
-
- assert(ssl->state == SSL3_ST_CW_CERT_D);
- return ssl_do_write(ssl);
-}
-
-int ssl3_send_next_proto(SSL *ssl) {
+static int ssl3_send_next_proto(SSL *ssl) {
if (ssl->state == SSL3_ST_CW_NEXT_PROTO_B) {
return ssl_do_write(ssl);
}
@@ -1928,7 +1952,7 @@
return ssl_do_write(ssl);
}
-int ssl3_send_channel_id(SSL *ssl) {
+static int ssl3_send_channel_id(SSL *ssl) {
if (ssl->state == SSL3_ST_CW_CHANNEL_ID_B) {
return ssl_do_write(ssl);
}
@@ -2009,31 +2033,75 @@
return ret;
}
-int ssl_do_client_cert_cb(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
- if (ssl->ctx->client_cert_cb == NULL) {
- return 0;
+static int ssl3_get_new_session_ticket(SSL *ssl) {
+ int ok, al;
+ long n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEW_SESSION_TICKET,
+ ssl_hash_message, &ok);
+
+ if (!ok) {
+ return n;
}
- int ret = ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey);
- if (ret <= 0) {
- return ret;
+ CBS new_session_ticket, ticket;
+ uint32_t ticket_lifetime_hint;
+ CBS_init(&new_session_ticket, ssl->init_msg, n);
+ if (!CBS_get_u32(&new_session_ticket, &ticket_lifetime_hint) ||
+ !CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) ||
+ CBS_len(&new_session_ticket) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
}
- assert(*out_x509 != NULL);
- assert(*out_pkey != NULL);
+ if (CBS_len(&ticket) == 0) {
+ /* RFC 5077 allows a server to change its mind and send no ticket after
+ * negotiating the extension. The value of |tlsext_ticket_expected| is
+ * checked in |ssl_update_cache| so is cleared here to avoid an unnecessary
+ * update. */
+ ssl->tlsext_ticket_expected = 0;
+ return 1;
+ }
+
+ if (ssl->hit) {
+ /* The server is sending a new ticket for an existing session. Sessions are
+ * immutable once established, so duplicate all but the ticket of the
+ * existing session. */
+ uint8_t *bytes;
+ size_t bytes_len;
+ if (!SSL_SESSION_to_bytes_for_ticket(ssl->session, &bytes, &bytes_len)) {
+ goto err;
+ }
+ SSL_SESSION *new_session = SSL_SESSION_from_bytes(bytes, bytes_len);
+ OPENSSL_free(bytes);
+ if (new_session == NULL) {
+ /* This should never happen. */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ SSL_SESSION_free(ssl->session);
+ ssl->session = new_session;
+ }
+
+ if (!CBS_stow(&ticket, &ssl->session->tlsext_tick,
+ &ssl->session->tlsext_ticklen)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ ssl->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
+
+ /* Generate a session ID for this session based on the session ticket. We use
+ * the session ID mechanism for detecting ticket resumption. This also fits in
+ * with assumptions elsewhere in OpenSSL.*/
+ if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), ssl->session->session_id,
+ &ssl->session->session_id_length, EVP_sha256(), NULL)) {
+ goto err;
+ }
+
return 1;
-}
-int ssl3_verify_server_cert(SSL *ssl) {
- int ret = ssl_verify_cert_chain(ssl, ssl->session->cert_chain);
- if (ssl->verify_mode != SSL_VERIFY_NONE && ret <= 0) {
- int al = ssl_verify_alarm_type(ssl->verify_result);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
- OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
- } else {
- ret = 1;
- ERR_clear_error(); /* but we keep ssl->verify_result */
- }
-
- return ret;
+f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+err:
+ return -1;
}
diff --git a/src/ssl/s3_srvr.c b/src/ssl/handshake_server.c
similarity index 95%
rename from src/ssl/s3_srvr.c
rename to src/ssl/handshake_server.c
index 50007eb..68a013e 100644
--- a/src/ssl/s3_srvr.c
+++ b/src/ssl/handshake_server.c
@@ -173,38 +173,37 @@
#include "../crypto/dh/internal.h"
+static int ssl3_get_initial_bytes(SSL *ssl);
+static int ssl3_get_v2_client_hello(SSL *ssl);
+static int ssl3_get_client_hello(SSL *ssl);
+static int ssl3_send_server_hello(SSL *ssl);
+static int ssl3_send_server_certificate(SSL *ssl);
+static int ssl3_send_certificate_status(SSL *ssl);
+static int ssl3_send_server_key_exchange(SSL *ssl);
+static int ssl3_send_certificate_request(SSL *ssl);
+static int ssl3_send_server_hello_done(SSL *ssl);
+static int ssl3_get_client_certificate(SSL *ssl);
+static int ssl3_get_client_key_exchange(SSL *ssl);
+static int ssl3_get_cert_verify(SSL *ssl);
+static int ssl3_get_next_proto(SSL *ssl);
+static int ssl3_get_channel_id(SSL *ssl);
+static int ssl3_send_new_session_ticket(SSL *ssl);
+
int ssl3_accept(SSL *ssl) {
BUF_MEM *buf = NULL;
uint32_t alg_a;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
int ret = -1;
- int new_state, state, skip = 0;
+ int state, skip = 0;
assert(ssl->handshake_func == ssl3_accept);
assert(ssl->server);
- assert(!SSL_IS_DTLS(ssl));
-
- ERR_clear_system_error();
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- if (ssl->cert == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
- return -1;
- }
for (;;) {
state = ssl->state;
switch (ssl->state) {
case SSL_ST_ACCEPT:
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_START, 1);
- }
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
if (ssl->init_buf == NULL) {
buf = BUF_MEM_new();
@@ -230,7 +229,7 @@
goto end;
}
- if (!ssl->s3->have_version) {
+ if (!ssl->s3->have_version && !SSL_IS_DTLS(ssl)) {
ssl->state = SSL3_ST_SR_INITIAL_BYTES;
} else {
ssl->state = SSL3_ST_SR_CLNT_HELLO_A;
@@ -238,6 +237,7 @@
break;
case SSL3_ST_SR_INITIAL_BYTES:
+ assert(!SSL_IS_DTLS(ssl));
ret = ssl3_get_initial_bytes(ssl);
if (ret <= 0) {
goto end;
@@ -247,6 +247,7 @@
break;
case SSL3_ST_SR_V2_CLIENT_HELLO:
+ assert(!SSL_IS_DTLS(ssl));
ret = ssl3_get_v2_client_hello(ssl);
if (ret <= 0) {
goto end;
@@ -261,6 +262,7 @@
if (ret <= 0) {
goto end;
}
+ ssl->method->received_flight(ssl);
ssl->state = SSL3_ST_SW_SRVR_HELLO_A;
break;
@@ -313,13 +315,7 @@
case SSL3_ST_SW_KEY_EXCH_C:
alg_a = ssl->s3->tmp.new_cipher->algorithm_auth;
- /* Send a ServerKeyExchange message if:
- * - The key exchange is ephemeral or anonymous
- * Diffie-Hellman.
- * - There is a PSK identity hint.
- *
- * TODO(davidben): This logic is currently duplicated in d1_srvr.c. Fix
- * this. In the meantime, keep them in sync. */
+ /* PSK ciphers send ServerKeyExchange if there is an identity hint. */
if (ssl_cipher_requires_server_key_exchange(ssl->s3->tmp.new_cipher) ||
((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) {
ret = ssl3_send_server_key_exchange(ssl);
@@ -348,7 +344,7 @@
case SSL3_ST_SW_SRVR_DONE_A:
case SSL3_ST_SW_SRVR_DONE_B:
- ret = ssl3_send_server_done(ssl);
+ ret = ssl3_send_server_hello_done(ssl);
if (ret <= 0) {
goto end;
}
@@ -356,21 +352,6 @@
ssl->state = SSL3_ST_SW_FLUSH;
break;
- case SSL3_ST_SW_FLUSH:
- /* This code originally checked to see if any data was pending using
- * BIO_CTRL_INFO and then flushed. This caused problems as documented
- * in PR#1939. The proposed fix doesn't completely resolve this issue
- * as buggy implementations of BIO_CTRL_PENDING still exist. So instead
- * we just flush unconditionally. */
- if (BIO_flush(ssl->wbio) <= 0) {
- ssl->rwstate = SSL_WRITING;
- ret = -1;
- goto end;
- }
-
- ssl->state = ssl->s3->tmp.next_state;
- break;
-
case SSL3_ST_SR_CERT_A:
if (ssl->s3->tmp.cert_request) {
ret = ssl3_get_client_certificate(ssl);
@@ -445,6 +426,7 @@
goto end;
}
+ ssl->method->received_flight(ssl);
if (ssl->hit) {
ssl->state = SSL_ST_OK;
} else if (ssl->tlsext_ticket_expected) {
@@ -452,6 +434,7 @@
} else {
ssl->state = SSL3_ST_SW_CHANGE_A;
}
+
/* If this is a full handshake with ChannelID then record the hashshake
* hashes in |ssl->session| in case we need them to verify a ChannelID
* signature on a resumption of this session in the future. */
@@ -474,8 +457,8 @@
case SSL3_ST_SW_CHANGE_A:
case SSL3_ST_SW_CHANGE_B:
- ret = ssl3_send_change_cipher_spec(ssl, SSL3_ST_SW_CHANGE_A,
- SSL3_ST_SW_CHANGE_B);
+ ret = ssl->method->send_change_cipher_spec(ssl, SSL3_ST_SW_CHANGE_A,
+ SSL3_ST_SW_CHANGE_B);
if (ret <= 0) {
goto end;
}
@@ -502,18 +485,36 @@
}
break;
+ case SSL3_ST_SW_FLUSH:
+ if (BIO_flush(ssl->wbio) <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ ret = -1;
+ goto end;
+ }
+
+ ssl->state = ssl->s3->tmp.next_state;
+ if (ssl->state != SSL_ST_OK) {
+ ssl->method->expect_flight(ssl);
+ }
+ break;
+
case SSL_ST_OK:
/* clean a few things up */
ssl3_cleanup_key_block(ssl);
- BUF_MEM_free(ssl->init_buf);
- ssl->init_buf = NULL;
- ssl->init_num = 0;
+ /* In DTLS, |init_buf| cannot be released because post-handshake
+ * retransmit relies on that buffer being available as scratch space.
+ *
+ * TODO(davidben): Fix this. */
+ if (!SSL_IS_DTLS(ssl)) {
+ BUF_MEM_free(ssl->init_buf);
+ ssl->init_buf = NULL;
+ ssl->init_num = 0;
+ }
/* remove buffering on output */
ssl_free_wbio_buffer(ssl);
-
/* If we aren't retaining peer certificates then we can discard it
* now. */
if (ssl->ctx->retain_only_sha256_of_client_certs) {
@@ -523,13 +524,17 @@
ssl->session->cert_chain = NULL;
}
+ if (SSL_IS_DTLS(ssl)) {
+ ssl->d1->handshake_read_seq = 0;
+ ssl->d1->handshake_write_seq = 0;
+ ssl->d1->next_handshake_write_seq = 0;
+ }
+
ssl->s3->initial_handshake_complete = 1;
ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER);
- if (cb != NULL) {
- cb(ssl, SSL_CB_HANDSHAKE_DONE, 1);
- }
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
ret = 1;
goto end;
@@ -540,11 +545,10 @@
goto end;
}
- if (!ssl->s3->tmp.reuse_message && !skip && cb != NULL &&
- ssl->state != state) {
- new_state = ssl->state;
+ if (!ssl->s3->tmp.reuse_message && !skip && ssl->state != state) {
+ int new_state = ssl->state;
ssl->state = state;
- cb(ssl, SSL_CB_ACCEPT_LOOP, 1);
+ ssl_do_info_callback(ssl, SSL_CB_ACCEPT_LOOP, 1);
ssl->state = new_state;
}
skip = 0;
@@ -552,13 +556,11 @@
end:
BUF_MEM_free(buf);
- if (cb != NULL) {
- cb(ssl, SSL_CB_ACCEPT_EXIT, ret);
- }
+ ssl_do_info_callback(ssl, SSL_CB_ACCEPT_EXIT, ret);
return ret;
}
-int ssl3_get_initial_bytes(SSL *ssl) {
+static int ssl3_get_initial_bytes(SSL *ssl) {
/* Read the first 5 bytes, the size of the TLS record header. This is
* sufficient to detect a V2ClientHello and ensures that we never read beyond
* the first record. */
@@ -597,7 +599,7 @@
return 1;
}
-int ssl3_get_v2_client_hello(SSL *ssl) {
+static int ssl3_get_v2_client_hello(SSL *ssl) {
const uint8_t *p;
int ret;
CBS v2_client_hello, cipher_specs, session_id, challenge;
@@ -637,10 +639,9 @@
CBS_len(&v2_client_hello))) {
return -1;
}
- if (ssl->msg_callback) {
- ssl->msg_callback(0, SSL2_VERSION, 0, CBS_data(&v2_client_hello),
- CBS_len(&v2_client_hello), ssl, ssl->msg_callback_arg);
- }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, SSL2_VERSION, 0,
+ CBS_data(&v2_client_hello), CBS_len(&v2_client_hello));
if (!CBS_get_u8(&v2_client_hello, &msg_type) ||
!CBS_get_u16(&v2_client_hello, &version) ||
@@ -724,7 +725,7 @@
return 1;
}
-int ssl3_get_client_hello(SSL *ssl) {
+static int ssl3_get_client_hello(SSL *ssl) {
int ok, al = SSL_AD_INTERNAL_ERROR, ret = -1;
long n;
const SSL_CIPHER *c;
@@ -1069,7 +1070,7 @@
return ret;
}
-int ssl3_send_server_hello(SSL *ssl) {
+static int ssl3_send_server_hello(SSL *ssl) {
if (ssl->state == SSL3_ST_SW_SRVR_HELLO_B) {
return ssl_do_write(ssl);
}
@@ -1120,7 +1121,19 @@
return ssl_do_write(ssl);
}
-int ssl3_send_certificate_status(SSL *ssl) {
+static int ssl3_send_server_certificate(SSL *ssl) {
+ if (ssl->state == SSL3_ST_SW_CERT_A) {
+ if (!ssl3_output_cert_chain(ssl)) {
+ return 0;
+ }
+ ssl->state = SSL3_ST_SW_CERT_B;
+ }
+
+ /* SSL3_ST_SW_CERT_B */
+ return ssl_do_write(ssl);
+}
+
+static int ssl3_send_certificate_status(SSL *ssl) {
if (ssl->state == SSL3_ST_SW_CERT_STATUS_A) {
CBB out, ocsp_response;
size_t length;
@@ -1146,19 +1159,7 @@
return ssl_do_write(ssl);
}
-int ssl3_send_server_done(SSL *ssl) {
- if (ssl->state == SSL3_ST_SW_SRVR_DONE_A) {
- if (!ssl_set_handshake_header(ssl, SSL3_MT_SERVER_DONE, 0)) {
- return -1;
- }
- ssl->state = SSL3_ST_SW_SRVR_DONE_B;
- }
-
- /* SSL3_ST_SW_SRVR_DONE_B */
- return ssl_do_write(ssl);
-}
-
-int ssl3_send_server_key_exchange(SSL *ssl) {
+static int ssl3_send_server_key_exchange(SSL *ssl) {
if (ssl->state == SSL3_ST_SW_KEY_EXCH_C) {
return ssl_do_write(ssl);
}
@@ -1346,7 +1347,7 @@
return -1;
}
-int ssl3_send_certificate_request(SSL *ssl) {
+static int ssl3_send_certificate_request(SSL *ssl) {
uint8_t *p, *d;
size_t i;
int j, nl, off, n;
@@ -1414,7 +1415,158 @@
return -1;
}
-int ssl3_get_client_key_exchange(SSL *ssl) {
+static int ssl3_send_server_hello_done(SSL *ssl) {
+ if (ssl->state == SSL3_ST_SW_SRVR_DONE_A) {
+ if (!ssl_set_handshake_header(ssl, SSL3_MT_SERVER_HELLO_DONE, 0)) {
+ return -1;
+ }
+ ssl->state = SSL3_ST_SW_SRVR_DONE_B;
+ }
+
+ /* SSL3_ST_SW_SRVR_DONE_B */
+ return ssl_do_write(ssl);
+}
+
+static int ssl3_get_client_certificate(SSL *ssl) {
+ int ok, al, ret = -1;
+ X509 *x = NULL;
+ unsigned long n;
+ STACK_OF(X509) *sk = NULL;
+ SHA256_CTX sha256;
+ CBS certificate_msg, certificate_list;
+ int is_first_certificate = 1;
+
+ assert(ssl->s3->tmp.cert_request);
+ n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
+
+ if (!ok) {
+ return n;
+ }
+
+ if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
+ if (ssl->version == SSL3_VERSION &&
+ ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+ /* In SSL 3.0, the Certificate message is omitted to signal no certificate. */
+ if ((ssl->verify_mode & SSL_VERIFY_PEER) &&
+ (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ goto f_err;
+ }
+
+ ssl->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+
+ CBS_init(&certificate_msg, ssl->init_msg, n);
+
+ sk = sk_X509_new_null();
+ if (sk == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!CBS_get_u24_length_prefixed(&certificate_msg, &certificate_list) ||
+ CBS_len(&certificate_msg) != 0) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ while (CBS_len(&certificate_list) > 0) {
+ CBS certificate;
+ const uint8_t *data;
+
+ if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+
+ if (is_first_certificate && ssl->ctx->retain_only_sha256_of_client_certs) {
+ /* If this is the first certificate, and we don't want to keep peer
+ * certificates in memory, then we hash it right away. */
+ SHA256_Init(&sha256);
+ SHA256_Update(&sha256, CBS_data(&certificate), CBS_len(&certificate));
+ SHA256_Final(ssl->session->peer_sha256, &sha256);
+ ssl->session->peer_sha256_valid = 1;
+ }
+ is_first_certificate = 0;
+
+ /* A u24 length cannot overflow a long. */
+ data = CBS_data(&certificate);
+ x = d2i_X509(NULL, &data, (long)CBS_len(&certificate));
+ if (x == NULL) {
+ al = SSL_AD_BAD_CERTIFICATE;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
+ goto f_err;
+ }
+ if (data != CBS_data(&certificate) + CBS_len(&certificate)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (!sk_X509_push(sk, x)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ x = NULL;
+ }
+
+ if (sk_X509_num(sk) <= 0) {
+ /* No client certificate so the handshake buffer may be discarded. */
+ ssl3_free_handshake_buffer(ssl);
+
+ /* TLS does not mind 0 certs returned */
+ if (ssl->version == SSL3_VERSION) {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED);
+ goto f_err;
+ } else if ((ssl->verify_mode & SSL_VERIFY_PEER) &&
+ (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+ /* Fail for TLS only if we required a certificate */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ goto f_err;
+ }
+ } else {
+ if (ssl_verify_cert_chain(ssl, sk) <= 0) {
+ al = ssl_verify_alarm_type(ssl->verify_result);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
+ goto f_err;
+ }
+ }
+
+ X509_free(ssl->session->peer);
+ ssl->session->peer = sk_X509_shift(sk);
+ ssl->session->verify_result = ssl->verify_result;
+
+ sk_X509_pop_free(ssl->session->cert_chain, X509_free);
+ ssl->session->cert_chain = sk;
+ /* Inconsistency alert: cert_chain does *not* include the peer's own
+ * certificate, while we do include it in s3_clnt.c */
+
+ sk = NULL;
+
+ ret = 1;
+
+ if (0) {
+ f_err:
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
+ }
+
+err:
+ X509_free(x);
+ sk_X509_pop_free(sk, X509_free);
+ return ret;
+}
+
+static int ssl3_get_client_key_exchange(SSL *ssl) {
int al;
CBS client_key_exchange;
uint32_t alg_k;
@@ -1683,7 +1835,7 @@
return -1;
}
-int ssl3_get_cert_verify(SSL *ssl) {
+static int ssl3_get_cert_verify(SSL *ssl) {
int al, ok, ret = 0;
long n;
CBS certificate_verify, signature;
@@ -1789,159 +1941,159 @@
return ret;
}
-int ssl3_get_client_certificate(SSL *ssl) {
- int ok, al, ret = -1;
- X509 *x = NULL;
- unsigned long n;
- STACK_OF(X509) *sk = NULL;
- SHA256_CTX sha256;
- CBS certificate_msg, certificate_list;
- int is_first_certificate = 1;
+/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
+ * sets the next_proto member in s if found */
+static int ssl3_get_next_proto(SSL *ssl) {
+ int ok;
+ long n;
+ CBS next_protocol, selected_protocol, padding;
- assert(ssl->s3->tmp.cert_request);
- n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok);
+ /* Clients cannot send a NextProtocol message if we didn't see the extension
+ * in their ClientHello */
+ if (!ssl->s3->next_proto_neg_seen) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
+ return -1;
+ }
+
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEXT_PROTO, ssl_hash_message,
+ &ok);
if (!ok) {
return n;
}
- if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
- if (ssl->version == SSL3_VERSION &&
- ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
- /* In SSL 3.0, the Certificate message is omitted to signal no certificate. */
- if ((ssl->verify_mode & SSL_VERIFY_PEER) &&
- (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
- al = SSL_AD_HANDSHAKE_FAILURE;
- goto f_err;
- }
+ CBS_init(&next_protocol, ssl->init_msg, n);
- ssl->s3->tmp.reuse_message = 1;
- return 1;
- }
-
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
+ /* The payload looks like:
+ * uint8 proto_len;
+ * uint8 proto[proto_len];
+ * uint8 padding_len;
+ * uint8 padding[padding_len]; */
+ if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) ||
+ !CBS_get_u8_length_prefixed(&next_protocol, &padding) ||
+ CBS_len(&next_protocol) != 0 ||
+ !CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated,
+ &ssl->s3->next_proto_negotiated_len)) {
+ return 0;
}
- CBS_init(&certificate_msg, ssl->init_msg, n);
+ return 1;
+}
- sk = sk_X509_new_null();
- if (sk == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
+static int ssl3_get_channel_id(SSL *ssl) {
+ int ret = -1, ok;
+ long n;
+ uint8_t channel_id_hash[EVP_MAX_MD_SIZE];
+ size_t channel_id_hash_len;
+ const uint8_t *p;
+ uint16_t extension_type;
+ EC_GROUP *p256 = NULL;
+ EC_KEY *key = NULL;
+ EC_POINT *point = NULL;
+ ECDSA_SIG sig;
+ BIGNUM x, y;
+ CBS encrypted_extensions, extension;
+
+ n = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID_ENCRYPTED_EXTENSIONS,
+ ssl_dont_hash_message, &ok);
+
+ if (!ok) {
+ return n;
+ }
+
+ /* Before incorporating the EncryptedExtensions message to the handshake
+ * hash, compute the hash that should have been signed. */
+ if (!tls1_channel_id_hash(ssl, channel_id_hash, &channel_id_hash_len)) {
+ return -1;
+ }
+ assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
+
+ if (!ssl3_hash_current_message(ssl)) {
+ return -1;
+ }
+
+ CBS_init(&encrypted_extensions, ssl->init_msg, n);
+
+ /* EncryptedExtensions could include multiple extensions, but the only
+ * extension that could be negotiated is ChannelID, so there can only be one
+ * entry.
+ *
+ * The payload looks like:
+ * uint16 extension_type
+ * uint16 extension_len;
+ * uint8 x[32];
+ * uint8 y[32];
+ * uint8 r[32];
+ * uint8 s[32]; */
+
+ if (!CBS_get_u16(&encrypted_extensions, &extension_type) ||
+ !CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) ||
+ CBS_len(&encrypted_extensions) != 0 ||
+ extension_type != TLSEXT_TYPE_channel_id ||
+ CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_MESSAGE);
+ return -1;
+ }
+
+ p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ if (!p256) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
+ return -1;
+ }
+
+ BN_init(&x);
+ BN_init(&y);
+ sig.r = BN_new();
+ sig.s = BN_new();
+ if (sig.r == NULL || sig.s == NULL) {
goto err;
}
- if (!CBS_get_u24_length_prefixed(&certificate_msg, &certificate_list) ||
- CBS_len(&certificate_msg) != 0) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- goto f_err;
+ p = CBS_data(&extension);
+ if (BN_bin2bn(p + 0, 32, &x) == NULL ||
+ BN_bin2bn(p + 32, 32, &y) == NULL ||
+ BN_bin2bn(p + 64, 32, sig.r) == NULL ||
+ BN_bin2bn(p + 96, 32, sig.s) == NULL) {
+ goto err;
}
- while (CBS_len(&certificate_list) > 0) {
- CBS certificate;
- const uint8_t *data;
-
- if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- goto f_err;
- }
-
- if (is_first_certificate && ssl->ctx->retain_only_sha256_of_client_certs) {
- /* If this is the first certificate, and we don't want to keep peer
- * certificates in memory, then we hash it right away. */
- SHA256_Init(&sha256);
- SHA256_Update(&sha256, CBS_data(&certificate), CBS_len(&certificate));
- SHA256_Final(ssl->session->peer_sha256, &sha256);
- ssl->session->peer_sha256_valid = 1;
- }
- is_first_certificate = 0;
-
- /* A u24 length cannot overflow a long. */
- data = CBS_data(&certificate);
- x = d2i_X509(NULL, &data, (long)CBS_len(&certificate));
- if (x == NULL) {
- al = SSL_AD_BAD_CERTIFICATE;
- OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB);
- goto f_err;
- }
- if (data != CBS_data(&certificate) + CBS_len(&certificate)) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
- goto f_err;
- }
- if (!sk_X509_push(sk, x)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- x = NULL;
+ point = EC_POINT_new(p256);
+ if (!point ||
+ !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) {
+ goto err;
}
- if (sk_X509_num(sk) <= 0) {
- /* No client certificate so the handshake buffer may be discarded. */
- ssl3_free_handshake_buffer(ssl);
-
- /* TLS does not mind 0 certs returned */
- if (ssl->version == SSL3_VERSION) {
- al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED);
- goto f_err;
- } else if ((ssl->verify_mode & SSL_VERIFY_PEER) &&
- (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
- /* Fail for TLS only if we required a certificate */
- OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
- al = SSL_AD_HANDSHAKE_FAILURE;
- goto f_err;
- }
- } else {
- if (ssl_verify_cert_chain(ssl, sk) <= 0) {
- al = ssl_verify_alarm_type(ssl->verify_result);
- OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED);
- goto f_err;
- }
+ key = EC_KEY_new();
+ if (!key || !EC_KEY_set_group(key, p256) ||
+ !EC_KEY_set_public_key(key, point)) {
+ goto err;
}
- X509_free(ssl->session->peer);
- ssl->session->peer = sk_X509_shift(sk);
- ssl->session->verify_result = ssl->verify_result;
+ /* We stored the handshake hash in |tlsext_channel_id| the first time that we
+ * were called. */
+ if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
+ ssl->s3->tlsext_channel_id_valid = 0;
+ goto err;
+ }
- sk_X509_pop_free(ssl->session->cert_chain, X509_free);
- ssl->session->cert_chain = sk;
- /* Inconsistency alert: cert_chain does *not* include the peer's own
- * certificate, while we do include it in s3_clnt.c */
-
- sk = NULL;
-
+ memcpy(ssl->s3->tlsext_channel_id, p, 64);
ret = 1;
- if (0) {
- f_err:
- ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
- }
-
err:
- X509_free(x);
- sk_X509_pop_free(sk, X509_free);
+ BN_free(&x);
+ BN_free(&y);
+ BN_free(sig.r);
+ BN_free(sig.s);
+ EC_KEY_free(key);
+ EC_POINT_free(point);
+ EC_GROUP_free(p256);
return ret;
}
-int ssl3_send_server_certificate(SSL *ssl) {
- if (ssl->state == SSL3_ST_SW_CERT_A) {
- if (!ssl3_output_cert_chain(ssl)) {
- return 0;
- }
- ssl->state = SSL3_ST_SW_CERT_B;
- }
-
- /* SSL3_ST_SW_CERT_B */
- return ssl_do_write(ssl);
-}
-
/* send a new session ticket (not necessarily for a new session) */
-int ssl3_send_new_session_ticket(SSL *ssl) {
+static int ssl3_send_new_session_ticket(SSL *ssl) {
int ret = -1;
uint8_t *session = NULL;
size_t session_len;
@@ -2071,154 +2223,3 @@
HMAC_CTX_cleanup(&hctx);
return ret;
}
-
-/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
- * sets the next_proto member in s if found */
-int ssl3_get_next_proto(SSL *ssl) {
- int ok;
- long n;
- CBS next_protocol, selected_protocol, padding;
-
- /* Clients cannot send a NextProtocol message if we didn't see the extension
- * in their ClientHello */
- if (!ssl->s3->next_proto_neg_seen) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
- return -1;
- }
-
- n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEXT_PROTO, ssl_hash_message,
- &ok);
-
- if (!ok) {
- return n;
- }
-
- CBS_init(&next_protocol, ssl->init_msg, n);
-
- /* The payload looks like:
- * uint8 proto_len;
- * uint8 proto[proto_len];
- * uint8 padding_len;
- * uint8 padding[padding_len]; */
- if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) ||
- !CBS_get_u8_length_prefixed(&next_protocol, &padding) ||
- CBS_len(&next_protocol) != 0 ||
- !CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated,
- &ssl->s3->next_proto_negotiated_len)) {
- return 0;
- }
-
- return 1;
-}
-
-/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
-int ssl3_get_channel_id(SSL *ssl) {
- int ret = -1, ok;
- long n;
- uint8_t channel_id_hash[EVP_MAX_MD_SIZE];
- size_t channel_id_hash_len;
- const uint8_t *p;
- uint16_t extension_type;
- EC_GROUP *p256 = NULL;
- EC_KEY *key = NULL;
- EC_POINT *point = NULL;
- ECDSA_SIG sig;
- BIGNUM x, y;
- CBS encrypted_extensions, extension;
-
- n = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID_ENCRYPTED_EXTENSIONS,
- ssl_dont_hash_message, &ok);
-
- if (!ok) {
- return n;
- }
-
- /* Before incorporating the EncryptedExtensions message to the handshake
- * hash, compute the hash that should have been signed. */
- if (!tls1_channel_id_hash(ssl, channel_id_hash, &channel_id_hash_len)) {
- return -1;
- }
- assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
-
- if (!ssl3_hash_current_message(ssl)) {
- return -1;
- }
-
- CBS_init(&encrypted_extensions, ssl->init_msg, n);
-
- /* EncryptedExtensions could include multiple extensions, but the only
- * extension that could be negotiated is ChannelID, so there can only be one
- * entry.
- *
- * The payload looks like:
- * uint16 extension_type
- * uint16 extension_len;
- * uint8 x[32];
- * uint8 y[32];
- * uint8 r[32];
- * uint8 s[32]; */
-
- if (!CBS_get_u16(&encrypted_extensions, &extension_type) ||
- !CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) ||
- CBS_len(&encrypted_extensions) != 0 ||
- extension_type != TLSEXT_TYPE_channel_id ||
- CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_MESSAGE);
- return -1;
- }
-
- p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
- if (!p256) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
- return -1;
- }
-
- BN_init(&x);
- BN_init(&y);
- sig.r = BN_new();
- sig.s = BN_new();
- if (sig.r == NULL || sig.s == NULL) {
- goto err;
- }
-
- p = CBS_data(&extension);
- if (BN_bin2bn(p + 0, 32, &x) == NULL ||
- BN_bin2bn(p + 32, 32, &y) == NULL ||
- BN_bin2bn(p + 64, 32, sig.r) == NULL ||
- BN_bin2bn(p + 96, 32, sig.s) == NULL) {
- goto err;
- }
-
- point = EC_POINT_new(p256);
- if (!point ||
- !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) {
- goto err;
- }
-
- key = EC_KEY_new();
- if (!key || !EC_KEY_set_group(key, p256) ||
- !EC_KEY_set_public_key(key, point)) {
- goto err;
- }
-
- /* We stored the handshake hash in |tlsext_channel_id| the first time that we
- * were called. */
- if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
- ssl->s3->tlsext_channel_id_valid = 0;
- goto err;
- }
-
- memcpy(ssl->s3->tlsext_channel_id, p, 64);
- ret = 1;
-
-err:
- BN_free(&x);
- BN_free(&y);
- BN_free(sig.r);
- BN_free(sig.s);
- EC_KEY_free(key);
- EC_POINT_free(point);
- EC_GROUP_free(p256);
- return ret;
-}
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 3b56e78..457a8b4 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -151,9 +151,9 @@
#if defined(OPENSSL_WINDOWS)
/* Windows defines struct timeval in winsock2.h. */
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#else
#include <sys/time.h>
#endif
@@ -313,21 +313,19 @@
* |SSL_AEAD_CTX_seal|. |ctx| may be NULL to denote the null cipher. */
size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *ctx);
-/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in| and
- * writes the result to |out|. It returns one on success and zero on
- * error. |ctx| may be NULL to denote the null cipher.
- *
- * If |in| and |out| alias then |out| must be <= |in| + |explicit_nonce_len|. */
-int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
- size_t max_out, uint8_t type, uint16_t wire_version,
- const uint8_t seqnum[8], const uint8_t *in,
- size_t in_len);
+/* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in|
+ * in-place. On success, it sets |*out| to the plaintext in |in| and returns
+ * one. Otherwise, it returns zero. |ctx| may be NULL to denote the null cipher.
+ * The output will always be |explicit_nonce_len| bytes ahead of |in|. */
+int SSL_AEAD_CTX_open(SSL_AEAD_CTX *ctx, CBS *out, uint8_t type,
+ uint16_t wire_version, const uint8_t seqnum[8],
+ uint8_t *in, size_t in_len);
/* SSL_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and
* writes the result to |out|. It returns one on success and zero on
* error. |ctx| may be NULL to denote the null cipher.
*
- * If |in| and |out| alias then |out| + |explicit_nonce_len| must be <= |in| */
+ * If |in| and |out| alias then |out| + |explicit_nonce_len| must be == |in|. */
int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out, uint8_t type, uint16_t wire_version,
const uint8_t seqnum[8], const uint8_t *in,
@@ -365,52 +363,60 @@
ssl_open_record_success,
ssl_open_record_discard,
ssl_open_record_partial,
+ ssl_open_record_close_notify,
+ ssl_open_record_fatal_alert,
ssl_open_record_error,
};
-/* tls_open_record decrypts a record from |in|.
- *
- * On success, it returns |ssl_open_record_success|. It sets |*out_type| to the
- * record type, |*out_len| to the plaintext length, and writes the record body
- * to |out|. It sets |*out_consumed| to the number of bytes of |in| consumed.
- * Note that |*out_len| may be zero.
- *
- * If a record was successfully processed but should be discarded, it returns
- * |ssl_open_record_discard| and sets |*out_consumed| to the number of bytes
- * consumed.
+/* tls_open_record decrypts a record from |in| in-place.
*
* If the input did not contain a complete record, it returns
* |ssl_open_record_partial|. It sets |*out_consumed| to the total number of
* bytes necessary. It is guaranteed that a successful call to |tls_open_record|
* will consume at least that many bytes.
*
- * On failure, it returns |ssl_open_record_error| and sets |*out_alert| to an
- * alert to emit.
+ * Otherwise, it sets |*out_consumed| to the number of bytes of input
+ * consumed. Note that input may be consumed on all return codes if a record was
+ * decrypted.
*
- * If |in| and |out| alias, |out| must be <= |in| + |ssl_record_prefix_len|. */
-enum ssl_open_record_t tls_open_record(
- SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
- size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
- size_t in_len);
+ * On success, it returns |ssl_open_record_success|. It sets |*out_type| to the
+ * record type and |*out| to the record body in |in|. Note that |*out| may be
+ * empty.
+ *
+ * If a record was successfully processed but should be discarded, it returns
+ * |ssl_open_record_discard|.
+ *
+ * If a record was successfully processed but is a close_notify or fatal alert,
+ * it returns |ssl_open_record_close_notify| or |ssl_open_record_fatal_alert|.
+ *
+ * On failure, it returns |ssl_open_record_error| and sets |*out_alert| to an
+ * alert to emit. */
+enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed, uint8_t *out_alert,
+ uint8_t *in, size_t in_len);
/* dtls_open_record implements |tls_open_record| for DTLS. It never returns
* |ssl_open_record_partial| but otherwise behaves analogously. */
-enum ssl_open_record_t dtls_open_record(
- SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
- size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
- size_t in_len);
+enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed,
+ uint8_t *out_alert, uint8_t *in,
+ size_t in_len);
-/* ssl_seal_prefix_len returns the length of the prefix before the ciphertext
- * when sealing a record with |ssl|. Note that this value may differ from
- * |ssl_record_prefix_len| when TLS 1.0 CBC record-splitting is enabled. Sealing
- * a small record may also result in a smaller output than this value.
+/* ssl_seal_align_prefix_len returns the length of the prefix before the start
+ * of the bulk of the ciphertext when sealing a record with |ssl|. Callers may
+ * use this to align buffers.
+ *
+ * Note when TLS 1.0 CBC record-splitting is enabled, this includes the one byte
+ * record and is the offset into second record's ciphertext. Thus this value may
+ * differ from |ssl_record_prefix_len| and sealing a small record may result in
+ * a smaller output than this value.
*
* TODO(davidben): Expose this as part of public API once the high-level
* buffer-free APIs are available. */
-size_t ssl_seal_prefix_len(const SSL *ssl);
+size_t ssl_seal_align_prefix_len(const SSL *ssl);
/* ssl_max_seal_overhead returns the maximum overhead of sealing a record with
- * |ssl|. This includes |ssl_seal_prefix_len|.
+ * |ssl|.
*
* TODO(davidben): Expose this as part of public API once the high-level
* buffer-free APIs are available. */
@@ -421,11 +427,12 @@
* and zero on error. If enabled, |tls_seal_record| implements TLS 1.0 CBC 1/n-1
* record splitting and may write two records concatenated.
*
- * For a large record, the ciphertext will begin |ssl_seal_prefix_len| bytes
- * into out. Aligning |out| appropriately may improve performance. It writes at
- * most |in_len| + |ssl_max_seal_overhead| bytes to |out|.
+ * For a large record, the bulk of the ciphertext will begin
+ * |ssl_seal_align_prefix_len| bytes into out. Aligning |out| appropriately may
+ * improve performance. It writes at most |in_len| + |ssl_max_seal_overhead|
+ * bytes to |out|.
*
- * If |in| and |out| alias, |out| + |ssl_seal_prefix_len| must be <= |in|. */
+ * |in| and |out| may not alias. */
int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
uint8_t type, const uint8_t *in, size_t in_len);
@@ -448,6 +455,13 @@
* ownership of |aead_ctx|. */
void ssl_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
+/* ssl_process_alert processes |in| as an alert and updates |ssl|'s shutdown
+ * state. It returns one of |ssl_open_record_discard|, |ssl_open_record_error|,
+ * |ssl_open_record_close_notify|, or |ssl_open_record_fatal_alert| as
+ * appropriate. */
+enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert,
+ const uint8_t *in, size_t in_len);
+
/* Private key operations. */
@@ -626,6 +640,16 @@
size_t ssl_max_handshake_message_len(const SSL *ssl);
+/* Callbacks. */
+
+/* ssl_do_info_callback calls |ssl|'s info callback, if set. */
+void ssl_do_info_callback(const SSL *ssl, int type, int value);
+
+/* ssl_do_msg_callback calls |ssl|'s message callback, if set. */
+void ssl_do_msg_callback(SSL *ssl, int is_write, int version, int content_type,
+ const void *buf, size_t len);
+
+
/* Transport buffers. */
/* ssl_read_buffer returns a pointer to contents of the read buffer. */
@@ -685,100 +709,17 @@
*
* Functions below here haven't been touched up and may be underdocumented. */
-#define c2l(c, l) \
- (l = ((unsigned long)(*((c)++))), l |= (((unsigned long)(*((c)++))) << 8), \
- l |= (((unsigned long)(*((c)++))) << 16), \
- l |= (((unsigned long)(*((c)++))) << 24))
-
-/* NOTE - c is not incremented as per c2l */
-#define c2ln(c, l1, l2, n) \
- { \
- c += n; \
- l1 = l2 = 0; \
- switch (n) { \
- case 8: \
- l2 = ((unsigned long)(*(--(c)))) << 24; \
- case 7: \
- l2 |= ((unsigned long)(*(--(c)))) << 16; \
- case 6: \
- l2 |= ((unsigned long)(*(--(c)))) << 8; \
- case 5: \
- l2 |= ((unsigned long)(*(--(c)))); \
- case 4: \
- l1 = ((unsigned long)(*(--(c)))) << 24; \
- case 3: \
- l1 |= ((unsigned long)(*(--(c)))) << 16; \
- case 2: \
- l1 |= ((unsigned long)(*(--(c)))) << 8; \
- case 1: \
- l1 |= ((unsigned long)(*(--(c)))); \
- } \
- }
-
-#define l2c(l, c) \
- (*((c)++) = (uint8_t)(((l)) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 24) & 0xff))
-
-#define n2l(c, l) \
- (l = ((unsigned long)(*((c)++))) << 24, \
- l |= ((unsigned long)(*((c)++))) << 16, \
- l |= ((unsigned long)(*((c)++))) << 8, l |= ((unsigned long)(*((c)++))))
-
#define l2n(l, c) \
(*((c)++) = (uint8_t)(((l) >> 24) & 0xff), \
*((c)++) = (uint8_t)(((l) >> 16) & 0xff), \
*((c)++) = (uint8_t)(((l) >> 8) & 0xff), \
*((c)++) = (uint8_t)(((l)) & 0xff))
-#define l2n8(l, c) \
- (*((c)++) = (uint8_t)(((l) >> 56) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 48) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 40) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 32) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 24) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 16) & 0xff), \
- *((c)++) = (uint8_t)(((l) >> 8) & 0xff), \
- *((c)++) = (uint8_t)(((l)) & 0xff))
-
-/* NOTE - c is not incremented as per l2c */
-#define l2cn(l1, l2, c, n) \
- { \
- c += n; \
- switch (n) { \
- case 8: \
- *(--(c)) = (uint8_t)(((l2) >> 24) & 0xff); \
- case 7: \
- *(--(c)) = (uint8_t)(((l2) >> 16) & 0xff); \
- case 6: \
- *(--(c)) = (uint8_t)(((l2) >> 8) & 0xff); \
- case 5: \
- *(--(c)) = (uint8_t)(((l2)) & 0xff); \
- case 4: \
- *(--(c)) = (uint8_t)(((l1) >> 24) & 0xff); \
- case 3: \
- *(--(c)) = (uint8_t)(((l1) >> 16) & 0xff); \
- case 2: \
- *(--(c)) = (uint8_t)(((l1) >> 8) & 0xff); \
- case 1: \
- *(--(c)) = (uint8_t)(((l1)) & 0xff); \
- } \
- }
-
-#define n2s(c, s) \
- ((s = (((unsigned int)(c[0])) << 8) | (((unsigned int)(c[1])))), c += 2)
-
#define s2n(s, c) \
((c[0] = (uint8_t)(((s) >> 8) & 0xff), \
c[1] = (uint8_t)(((s)) & 0xff)), \
c += 2)
-#define n2l3(c, l) \
- ((l = (((unsigned long)(c[0])) << 16) | (((unsigned long)(c[1])) << 8) | \
- (((unsigned long)(c[2])))), \
- c += 3)
-
#define l2n3(l, c) \
((c[0] = (uint8_t)(((l) >> 16) & 0xff), \
c[1] = (uint8_t)(((l) >> 8) & 0xff), \
@@ -870,8 +811,6 @@
char is_dtls;
int (*ssl_new)(SSL *ssl);
void (*ssl_free)(SSL *ssl);
- int (*ssl_accept)(SSL *ssl);
- int (*ssl_connect)(SSL *ssl);
long (*ssl_get_message)(SSL *ssl, int msg_type,
enum ssl_hash_message_t hash_message, int *ok);
int (*ssl_read_app_data)(SSL *ssl, uint8_t *buf, int len, int peek);
@@ -888,6 +827,14 @@
int (*set_handshake_header)(SSL *ssl, int type, unsigned long len);
/* Write out handshake message */
int (*do_write)(SSL *ssl);
+ /* send_change_cipher_spec sends a ChangeCipherSpec message. */
+ int (*send_change_cipher_spec)(SSL *ssl, int a, int b);
+ /* expect_flight is called when the handshake expects a flight of messages from
+ * the peer. */
+ void (*expect_flight)(SSL *ssl);
+ /* received_flight is called when the handshake has received a flight of
+ * messages from the peer. */
+ void (*received_flight)(SSL *ssl);
};
/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
@@ -1059,9 +1006,6 @@
* |len|. It returns one on success and zero on failure. */
int ssl_fill_hello_random(uint8_t *out, size_t len, int is_server);
-int ssl3_send_server_certificate(SSL *ssl);
-int ssl3_send_new_session_ticket(SSL *ssl);
-int ssl3_send_certificate_status(SSL *ssl);
int ssl3_get_finished(SSL *ssl);
int ssl3_send_change_cipher_spec(SSL *ssl, int state_a, int state_b);
void ssl3_cleanup_key_block(SSL *ssl);
@@ -1105,30 +1049,42 @@
int ssl3_set_handshake_header(SSL *ssl, int htype, unsigned long len);
int ssl3_handshake_write(SSL *ssl);
+void ssl3_expect_flight(SSL *ssl);
+void ssl3_received_flight(SSL *ssl);
int dtls1_do_handshake_write(SSL *ssl, enum dtls1_use_epoch_t use_epoch);
+
+/* dtls1_get_record reads a new input record. On success, it places it in
+ * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
+ * more data is needed. */
+int dtls1_get_record(SSL *ssl);
+
int dtls1_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek);
int dtls1_read_change_cipher_spec(SSL *ssl);
void dtls1_read_close_notify(SSL *ssl);
-int dtls1_read_bytes(SSL *ssl, int type, uint8_t *buf, int len, int peek);
void dtls1_set_message_header(SSL *ssl, uint8_t mt, unsigned long len,
unsigned short seq_num, unsigned long frag_off,
unsigned long frag_len);
int dtls1_write_app_data(SSL *ssl, const void *buf, int len);
-int dtls1_write_bytes(SSL *ssl, int type, const void *buf, int len,
- enum dtls1_use_epoch_t use_epoch);
+
+/* dtls1_write_record sends a record. It returns one on success and <= 0 on
+ * error. */
+int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len,
+ enum dtls1_use_epoch_t use_epoch);
int dtls1_send_change_cipher_spec(SSL *ssl, int a, int b);
int dtls1_send_finished(SSL *ssl, int a, int b, const char *sender, int slen);
-int dtls1_read_failed(SSL *ssl, int code);
int dtls1_buffer_message(SSL *ssl);
int dtls1_retransmit_buffered_messages(SSL *ssl);
void dtls1_clear_record_buffer(SSL *ssl);
-void dtls1_get_message_header(uint8_t *data, struct hm_header_st *msg_hdr);
+int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
+ CBS *out_body);
int dtls1_check_timeout_num(SSL *ssl);
int dtls1_set_handshake_header(SSL *ssl, int type, unsigned long len);
int dtls1_handshake_write(SSL *ssl);
+void dtls1_expect_flight(SSL *ssl);
+void dtls1_received_flight(SSL *ssl);
int dtls1_supports_cipher(const SSL_CIPHER *cipher);
void dtls1_start_timer(SSL *ssl);
@@ -1138,37 +1094,6 @@
unsigned int dtls1_min_mtu(void);
void dtls1_hm_fragment_free(hm_fragment *frag);
-/* some client-only functions */
-int ssl3_send_client_hello(SSL *ssl);
-int ssl3_get_server_hello(SSL *ssl);
-int ssl3_get_certificate_request(SSL *ssl);
-int ssl3_get_new_session_ticket(SSL *ssl);
-int ssl3_get_cert_status(SSL *ssl);
-int ssl3_get_server_done(SSL *ssl);
-int ssl3_send_cert_verify(SSL *ssl);
-int ssl3_send_client_certificate(SSL *ssl);
-int ssl_do_client_cert_cb(SSL *ssl, X509 **px509, EVP_PKEY **ppkey);
-int ssl3_send_client_key_exchange(SSL *ssl);
-int ssl3_get_server_key_exchange(SSL *ssl);
-int ssl3_get_server_certificate(SSL *ssl);
-int ssl3_send_next_proto(SSL *ssl);
-int ssl3_send_channel_id(SSL *ssl);
-int ssl3_verify_server_cert(SSL *ssl);
-
-/* some server-only functions */
-int ssl3_get_initial_bytes(SSL *ssl);
-int ssl3_get_v2_client_hello(SSL *ssl);
-int ssl3_get_client_hello(SSL *ssl);
-int ssl3_send_server_hello(SSL *ssl);
-int ssl3_send_server_key_exchange(SSL *ssl);
-int ssl3_send_certificate_request(SSL *ssl);
-int ssl3_send_server_done(SSL *ssl);
-int ssl3_get_client_certificate(SSL *ssl);
-int ssl3_get_client_key_exchange(SSL *ssl);
-int ssl3_get_cert_verify(SSL *ssl);
-int ssl3_get_next_proto(SSL *ssl);
-int ssl3_get_channel_id(SSL *ssl);
-
int dtls1_new(SSL *ssl);
int dtls1_accept(SSL *ssl);
int dtls1_connect(SSL *ssl);
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index d5e304d..f081066 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -130,29 +130,20 @@
/* ssl3_do_write sends |ssl->init_buf| in records of type 'type'
- * (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC). It returns -1 on error, 1
- * on success or zero if the transmission is still incomplete. */
+ * (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC). It returns 1 on success
+ * and <= 0 on error. */
int ssl3_do_write(SSL *ssl, int type) {
- int n;
-
- n = ssl3_write_bytes(ssl, type, &ssl->init_buf->data[ssl->init_off],
- ssl->init_num);
- if (n < 0) {
- return -1;
+ int ret = ssl3_write_bytes(ssl, type, ssl->init_buf->data, ssl->init_num);
+ if (ret <= 0) {
+ return ret;
}
- if (n == ssl->init_num) {
- if (ssl->msg_callback) {
- ssl->msg_callback(1, ssl->version, type, ssl->init_buf->data,
- (size_t)(ssl->init_off + ssl->init_num), ssl,
- ssl->msg_callback_arg);
- }
- return 1;
- }
-
- ssl->init_off += n;
- ssl->init_num -= n;
- return 0;
+ /* ssl3_write_bytes writes the data in its entirety. */
+ assert(ret == ssl->init_num);
+ ssl_do_msg_callback(ssl, 1 /* write */, ssl->version, type,
+ ssl->init_buf->data, (size_t)ssl->init_num);
+ ssl->init_num = 0;
+ return 1;
}
int ssl3_send_finished(SSL *ssl, int a, int b) {
@@ -274,7 +265,6 @@
if (ssl->state == a) {
*((uint8_t *)ssl->init_buf->data) = SSL3_MT_CCS;
ssl->init_num = 1;
- ssl->init_off = 0;
ssl->state = b;
}
@@ -382,10 +372,8 @@
/* We have now received a complete message. */
ssl->s3->tmp.message_complete = 1;
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
- ssl->init_buf->length, ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 0 /* read */, ssl->version, SSL3_RT_HANDSHAKE,
+ ssl->init_buf->data, ssl->init_buf->length);
static const uint8_t kHelloRequest[4] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0};
if (!ssl->server && ssl->init_buf->length == sizeof(kHelloRequest) &&
@@ -491,6 +479,9 @@
case X509_V_ERR_CRL_NOT_YET_VALID:
case X509_V_ERR_CERT_UNTRUSTED:
case X509_V_ERR_CERT_REJECTED:
+ case X509_V_ERR_HOSTNAME_MISMATCH:
+ case X509_V_ERR_EMAIL_MISMATCH:
+ case X509_V_ERR_IP_ADDRESS_MISMATCH:
al = SSL_AD_BAD_CERTIFICATE;
break;
@@ -508,7 +499,10 @@
al = SSL_AD_CERTIFICATE_REVOKED;
break;
+ case X509_V_ERR_UNSPECIFIED:
case X509_V_ERR_OUT_OF_MEM:
+ case X509_V_ERR_INVALID_CALL:
+ case X509_V_ERR_STORE_LOOKUP:
al = SSL_AD_INTERNAL_ERROR;
break;
diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c
index 4cf5aa3..43dcb02 100644
--- a/src/ssl/s3_lib.c
+++ b/src/ssl/s3_lib.c
@@ -171,7 +171,6 @@
*(p++) = htype;
l2n3(len, p);
ssl->init_num = (int)len + SSL3_HM_HEADER_LENGTH;
- ssl->init_off = 0;
/* Add the message to the handshake hash. */
return ssl3_update_handshake_hash(ssl, (uint8_t *)ssl->init_buf->data,
@@ -182,6 +181,10 @@
return ssl3_do_write(ssl, SSL3_RT_HANDSHAKE);
}
+void ssl3_expect_flight(SSL *ssl) {}
+
+void ssl3_received_flight(SSL *ssl) {}
+
int ssl3_new(SSL *ssl) {
SSL3_STATE *s3;
@@ -234,214 +237,6 @@
ssl->s3 = NULL;
}
-int SSL_session_reused(const SSL *ssl) {
- return ssl->hit;
-}
-
-int SSL_total_renegotiations(const SSL *ssl) {
- return ssl->s3->total_renegotiations;
-}
-
-int SSL_num_renegotiations(const SSL *ssl) {
- return SSL_total_renegotiations(ssl);
-}
-
-int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx) {
- return 0;
-}
-
-int SSL_need_tmp_RSA(const SSL *ssl) {
- return 0;
-}
-
-int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa) {
- return 1;
-}
-
-int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa) {
- return 1;
-}
-
-int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh) {
- DH_free(ctx->cert->dh_tmp);
- ctx->cert->dh_tmp = DHparams_dup(dh);
- if (ctx->cert->dh_tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
- return 0;
- }
- return 1;
-}
-
-int SSL_set_tmp_dh(SSL *ssl, const DH *dh) {
- DH_free(ssl->cert->dh_tmp);
- ssl->cert->dh_tmp = DHparams_dup(dh);
- if (ssl->cert->dh_tmp == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
- return 0;
- }
- return 1;
-}
-
-int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) {
- if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
- return SSL_CTX_set1_curves(ctx, &nid, 1);
-}
-
-int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) {
- if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
- return SSL_set1_curves(ssl, &nid, 1);
-}
-
-int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) {
- ctx->tlsext_channel_id_enabled = 1;
- return 1;
-}
-
-int SSL_enable_tls_channel_id(SSL *ssl) {
- ssl->tlsext_channel_id_enabled = 1;
- return 1;
-}
-
-static int is_p256_key(EVP_PKEY *private_key) {
- const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(private_key);
- return ec_key != NULL &&
- EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) ==
- NID_X9_62_prime256v1;
-}
-
-int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, EVP_PKEY *private_key) {
- if (!is_p256_key(private_key)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
- return 0;
- }
-
- EVP_PKEY_free(ctx->tlsext_channel_id_private);
- ctx->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key);
- ctx->tlsext_channel_id_enabled = 1;
-
- return 1;
-}
-
-int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) {
- if (!is_p256_key(private_key)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
- return 0;
- }
-
- EVP_PKEY_free(ssl->tlsext_channel_id_private);
- ssl->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key);
- ssl->tlsext_channel_id_enabled = 1;
-
- return 1;
-}
-
-size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, size_t max_out) {
- if (!ssl->s3->tlsext_channel_id_valid) {
- return 0;
- }
- memcpy(out, ssl->s3->tlsext_channel_id, (max_out < 64) ? max_out : 64);
- return 64;
-}
-
-int SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
- OPENSSL_free(ssl->tlsext_hostname);
- ssl->tlsext_hostname = NULL;
-
- if (name == NULL) {
- return 1;
- }
-
- size_t len = strlen(name);
- if (len == 0 || len > TLSEXT_MAXLEN_host_name) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
- return 0;
- }
- ssl->tlsext_hostname = BUF_strdup(name);
- if (ssl->tlsext_hostname == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- return 1;
-}
-
-size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) {
- if (ssl->server || !ssl->s3->tmp.cert_req) {
- *out_types = NULL;
- return 0;
- }
- *out_types = ssl->s3->tmp.certificate_types;
- return ssl->s3->tmp.num_certificate_types;
-}
-
-int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len) {
- return tls1_set_curves(&ctx->supported_group_list,
- &ctx->supported_group_list_len, curves,
- curves_len);
-}
-
-int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) {
- return tls1_set_curves(&ssl->supported_group_list,
- &ssl->supported_group_list_len, curves,
- curves_len);
-}
-
-int SSL_CTX_set_tlsext_servername_callback(
- SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)) {
- ctx->tlsext_servername_callback = callback;
- return 1;
-}
-
-int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) {
- ctx->tlsext_servername_arg = arg;
- return 1;
-}
-
-int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) {
- if (out == NULL) {
- return 48;
- }
- if (len != 48) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
- return 0;
- }
- uint8_t *out_bytes = out;
- memcpy(out_bytes, ctx->tlsext_tick_key_name, 16);
- memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16);
- memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16);
- return 1;
-}
-
-int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) {
- if (in == NULL) {
- return 48;
- }
- if (len != 48) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
- return 0;
- }
- const uint8_t *in_bytes = in;
- memcpy(ctx->tlsext_tick_key_name, in_bytes, 16);
- memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16);
- memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16);
- return 1;
-}
-
-int SSL_CTX_set_tlsext_ticket_key_cb(
- SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv,
- EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
- int encrypt)) {
- ctx->tlsext_ticket_key_cb = callback;
- return 1;
-}
-
struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl) {
if (ssl->cipher_list != NULL) {
return ssl->cipher_list;
diff --git a/src/ssl/s3_meth.c b/src/ssl/s3_meth.c
index b60b5f2..8370f23 100644
--- a/src/ssl/s3_meth.c
+++ b/src/ssl/s3_meth.c
@@ -63,8 +63,6 @@
0 /* is_dtls */,
ssl3_new,
ssl3_free,
- ssl3_accept,
- ssl3_connect,
ssl3_get_message,
ssl3_read_app_data,
ssl3_read_change_cipher_spec,
@@ -75,6 +73,9 @@
SSL3_HM_HEADER_LENGTH,
ssl3_set_handshake_header,
ssl3_handshake_write,
+ ssl3_send_change_cipher_spec,
+ ssl3_expect_flight,
+ ssl3_received_flight,
};
const SSL_METHOD *TLS_method(void) {
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index c54c10b..2396a7f 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -123,15 +123,10 @@
static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len);
-/* kMaxWarningAlerts is the number of consecutive warning alerts that will be
- * processed. */
-static const uint8_t kMaxWarningAlerts = 4;
-
/* ssl3_get_record reads a new input record. On success, it places it in
* |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
* more data is needed. */
static int ssl3_get_record(SSL *ssl) {
- int ret;
again:
switch (ssl->s3->recv_shutdown) {
case ssl_shutdown_none:
@@ -143,43 +138,44 @@
return 0;
}
- /* Ensure the buffer is large enough to decrypt in-place. */
- ret = ssl_read_buffer_extend_to(ssl, ssl_record_prefix_len(ssl));
- if (ret <= 0) {
- return ret;
- }
- assert(ssl_read_buffer_len(ssl) >= ssl_record_prefix_len(ssl));
-
- uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl);
- size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl);
+ CBS body;
uint8_t type, alert;
- size_t len, consumed;
- switch (tls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out,
- ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) {
- case ssl_open_record_success:
- ssl_read_buffer_consume(ssl, consumed);
+ size_t consumed;
+ enum ssl_open_record_t open_ret =
+ tls_open_record(ssl, &type, &body, &consumed, &alert,
+ ssl_read_buffer(ssl), ssl_read_buffer_len(ssl));
+ if (open_ret != ssl_open_record_partial) {
+ ssl_read_buffer_consume(ssl, consumed);
+ }
+ switch (open_ret) {
+ case ssl_open_record_partial: {
+ int read_ret = ssl_read_buffer_extend_to(ssl, consumed);
+ if (read_ret <= 0) {
+ return read_ret;
+ }
+ goto again;
+ }
- if (len > 0xffff) {
+ case ssl_open_record_success:
+ if (CBS_len(&body) > 0xffff) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return -1;
}
SSL3_RECORD *rr = &ssl->s3->rrec;
rr->type = type;
- rr->length = (uint16_t)len;
- rr->data = out;
+ rr->length = (uint16_t)CBS_len(&body);
+ rr->data = (uint8_t *)CBS_data(&body);
return 1;
- case ssl_open_record_partial:
- ret = ssl_read_buffer_extend_to(ssl, consumed);
- if (ret <= 0) {
- return ret;
- }
+ case ssl_open_record_discard:
goto again;
- case ssl_open_record_discard:
- ssl_read_buffer_consume(ssl, consumed);
- goto again;
+ case ssl_open_record_close_notify:
+ return 0;
+
+ case ssl_open_record_fatal_alert:
+ return -1;
case ssl_open_record_error:
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
@@ -314,34 +310,46 @@
int ssl3_read_app_data(SSL *ssl, uint8_t *buf, int len, int peek) {
assert(!SSL_in_init(ssl));
+ assert(ssl->s3->initial_handshake_complete);
+
return ssl3_read_bytes(ssl, SSL3_RT_APPLICATION_DATA, buf, len, peek);
}
int ssl3_read_change_cipher_spec(SSL *ssl) {
- uint8_t byte;
- int ret = ssl3_read_bytes(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, &byte, 1 /* len */,
- 0 /* no peek */);
- if (ret <= 0) {
- return ret;
- }
- assert(ret == 1);
+ SSL3_RECORD *rr = &ssl->s3->rrec;
- if (ssl->s3->rrec.length != 0 || byte != SSL3_MT_CCS) {
+ if (rr->length == 0) {
+ int ret = ssl3_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
+ return -1;
+ }
+
+ if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
}
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_CHANGE_CIPHER_SPEC, &byte, 1,
- ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 0 /* read */, ssl->version,
+ SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, rr->length);
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
return 1;
}
void ssl3_read_close_notify(SSL *ssl) {
- ssl3_read_bytes(ssl, 0, NULL, 0, 0);
+ /* Read records until an error or close_notify. */
+ while (ssl3_get_record(ssl) > 0) {
+ ;
+ }
}
static int ssl3_can_renegotiate(SSL *ssl) {
@@ -364,9 +372,7 @@
* 'type' is one of the following:
*
* - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
- * - SSL3_RT_CHANGE_CIPHER_SPEC (when ssl3_read_change_cipher_spec calls us)
* - SSL3_RT_APPLICATION_DATA (when ssl3_read_app_data calls us)
- * - 0 (during a shutdown, no data has to be returned)
*
* If we don't have stored data to work from, read a SSL/TLS record first
* (possibly multiple records if we still don't have anything to return).
@@ -377,10 +383,8 @@
int al, i, ret;
unsigned int n;
SSL3_RECORD *rr;
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
- if ((type && type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE &&
- type != SSL3_RT_CHANGE_CIPHER_SPEC) ||
+ if ((type != SSL3_RT_APPLICATION_DATA && type != SSL3_RT_HANDSHAKE) ||
(peek && type != SSL3_RT_APPLICATION_DATA)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
@@ -403,9 +407,7 @@
/* we now have a packet which can be read and processed */
- if (type != 0 && type == rr->type) {
- ssl->s3->warning_alert_count = 0;
-
+ if (type == rr->type) {
/* Discard empty records. */
if (rr->length == 0) {
goto start;
@@ -464,18 +466,8 @@
}
ssl->s3->hello_request_len = 0;
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, kHelloRequest,
- sizeof(kHelloRequest), ssl, ssl->msg_callback_arg);
- }
-
- if (!SSL_is_init_finished(ssl) || !ssl->s3->initial_handshake_complete) {
- /* This cannot happen. If a handshake is in progress, |type| must be
- * |SSL3_RT_HANDSHAKE|. */
- assert(0);
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- goto err;
- }
+ ssl_do_msg_callback(ssl, 0 /* read */, ssl->version, SSL3_RT_HANDSHAKE,
+ kHelloRequest, sizeof(kHelloRequest));
if (ssl->renegotiate_mode == ssl_renegotiate_ignore) {
goto start;
@@ -507,79 +499,11 @@
goto start;
}
- /* If an alert record, process the alert. */
- if (rr->type == SSL3_RT_ALERT) {
- /* Alerts records may not contain fragmented or multiple alerts. */
- if (rr->length != 2) {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
- goto f_err;
- }
-
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_ALERT, rr->data, 2, ssl,
- ssl->msg_callback_arg);
- }
- const uint8_t alert_level = rr->data[0];
- const uint8_t alert_descr = rr->data[1];
- rr->length -= 2;
- rr->data += 2;
-
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- if (cb != NULL) {
- uint16_t alert = (alert_level << 8) | alert_descr;
- cb(ssl, SSL_CB_READ_ALERT, alert);
- }
-
- if (alert_level == SSL3_AL_WARNING) {
- if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
- ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
- return 0;
- }
-
- ssl->s3->warning_alert_count++;
- if (ssl->s3->warning_alert_count > kMaxWarningAlerts) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS);
- goto f_err;
- }
- } else if (alert_level == SSL3_AL_FATAL) {
- char tmp[16];
-
- OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
- BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr);
- ERR_add_error_data(2, "SSL alert number ", tmp);
- ssl->s3->recv_shutdown = ssl_shutdown_fatal_alert;
- SSL_CTX_remove_session(ssl->ctx, ssl->session);
- return 0;
- } else {
- al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
- goto f_err;
- }
-
- goto start;
- }
-
- if (type == 0) {
- /* This may only occur from read_close_notify. */
- assert(ssl->s3->send_shutdown == ssl_shutdown_close_notify);
- /* close_notify has been sent, so discard all records other than alerts. */
- rr->length = 0;
- goto start;
- }
-
al = SSL_AD_UNEXPECTED_MESSAGE;
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
f_err:
ssl3_send_alert(ssl, SSL3_AL_FATAL, al);
-err:
return -1;
}
@@ -625,22 +549,11 @@
BIO_flush(ssl->wbio);
}
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(1 /* write */, ssl->version, SSL3_RT_ALERT,
- ssl->s3->send_alert, 2, ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 1 /* write */, ssl->version, SSL3_RT_ALERT,
+ ssl->s3->send_alert, 2);
- void (*cb)(const SSL *ssl, int type, int value) = NULL;
- if (ssl->info_callback != NULL) {
- cb = ssl->info_callback;
- } else if (ssl->ctx->info_callback != NULL) {
- cb = ssl->ctx->info_callback;
- }
-
- if (cb != NULL) {
- int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
- cb(ssl, SSL_CB_WRITE_ALERT, alert);
- }
+ int alert = (ssl->s3->send_alert[0] << 8) | ssl->s3->send_alert[1];
+ ssl_do_info_callback(ssl, SSL_CB_WRITE_ALERT, alert);
return 1;
}
diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c
index 1e549ea..88daddd 100644
--- a/src/ssl/ssl_aead_ctx.c
+++ b/src/ssl/ssl_aead_ctx.c
@@ -166,22 +166,16 @@
return len;
}
-int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
- size_t max_out, uint8_t type, uint16_t wire_version,
- const uint8_t seqnum[8], const uint8_t *in,
- size_t in_len) {
+int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, CBS *out, uint8_t type,
+ uint16_t wire_version, const uint8_t seqnum[8],
+ uint8_t *in, size_t in_len) {
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
aead = NULL;
#endif
if (aead == NULL) {
/* Handle the initial NULL cipher. */
- if (in_len > max_out) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
- return 0;
- }
- memmove(out, in, in_len);
- *out_len = in_len;
+ CBS_init(out, in, in_len);
return 1;
}
@@ -239,8 +233,14 @@
}
}
- return EVP_AEAD_CTX_open(&aead->ctx, out, out_len, max_out, nonce, nonce_len,
- in, in_len, ad, ad_len);
+ /* Decrypt in-place. */
+ size_t len;
+ if (!EVP_AEAD_CTX_open(&aead->ctx, in, &len, in_len, nonce, nonce_len,
+ in, in_len, ad, ad_len)) {
+ return 0;
+ }
+ CBS_init(out, in, len);
+ return 1;
}
int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
diff --git a/src/ssl/ssl_buffer.c b/src/ssl/ssl_buffer.c
index 272b13b..a3cf360 100644
--- a/src/ssl/ssl_buffer.c
+++ b/src/ssl/ssl_buffer.c
@@ -162,8 +162,6 @@
return -1;
}
- ERR_clear_system_error();
-
int ret;
if (SSL_IS_DTLS(ssl)) {
/* |len| is ignored for a datagram transport. */
@@ -184,14 +182,13 @@
SSL3_BUFFER *buf = &ssl->s3->read_buffer;
consume_buffer(buf, len);
- if (!SSL_IS_DTLS(ssl)) {
- /* The TLS stack never reads beyond the current record, so there will never
- * be unconsumed data. If read-ahead is ever reimplemented,
- * |ssl_read_buffer_discard| will require a |memcpy| to shift the excess
- * back to the front of the buffer, to ensure there is enough space for the
- * next record. */
- assert(buf->len == 0);
- }
+
+ /* The TLS stack never reads beyond the current record, so there will never be
+ * unconsumed data. If read-ahead is ever reimplemented,
+ * |ssl_read_buffer_discard| will require a |memcpy| to shift the excess back
+ * to the front of the buffer, to ensure there is enough space for the next
+ * record. */
+ assert(SSL_IS_DTLS(ssl) || len == 0 || buf->len == 0);
}
void ssl_read_buffer_discard(SSL *ssl) {
@@ -227,7 +224,7 @@
return 0;
}
- size_t header_len = ssl_seal_prefix_len(ssl);
+ size_t header_len = ssl_seal_align_prefix_len(ssl);
/* TODO(davidben): This matches the original behavior in keeping the malloc
* size consistent. Does this matter? |cap| could just be |max_len|. */
@@ -301,7 +298,6 @@
OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
return -1;
}
- ERR_clear_system_error();
if (SSL_IS_DTLS(ssl)) {
return dtls_write_buffer_flush(ssl);
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index dcee293..e78374b 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -662,6 +662,28 @@
SSL_HANDSHAKE_MAC_SHA256,
},
+ /* Cipher D001 */
+ {
+ TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ SSL_kECDHE,
+ SSL_aPSK,
+ SSL_AES128GCM,
+ SSL_SHA256,
+ SSL_HANDSHAKE_MAC_SHA256,
+ },
+
+ /* Cipher D002 */
+ {
+ TLS1_TXT_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
+ TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
+ SSL_kECDHE,
+ SSL_aPSK,
+ SSL_AES256GCM,
+ SSL_SHA384,
+ SSL_HANDSHAKE_MAC_SHA384,
+ },
+
};
static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]);
@@ -1669,6 +1691,10 @@
return (cipher->algorithm_auth & SSL_aECDSA) != 0;
}
+int SSL_CIPHER_is_DHE(const SSL_CIPHER *cipher) {
+ return (cipher->algorithm_mkey & SSL_kDHE) != 0;
+}
+
int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher) {
return (cipher->algorithm_mkey & SSL_kECDHE) != 0;
}
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 8e9b196..7f7bf5a 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -514,13 +514,13 @@
void SSL_set_connect_state(SSL *ssl) {
ssl->server = 0;
ssl->state = SSL_ST_CONNECT;
- ssl->handshake_func = ssl->method->ssl_connect;
+ ssl->handshake_func = ssl3_connect;
}
void SSL_set_accept_state(SSL *ssl) {
ssl->server = 1;
ssl->state = SSL_ST_ACCEPT;
- ssl->handshake_func = ssl->method->ssl_accept;
+ ssl->handshake_func = ssl3_accept;
}
void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio) {
@@ -559,6 +559,7 @@
ssl->rwstate = SSL_NOTHING;
/* Functions which use SSL_get_error must clear the error queue on entry. */
ERR_clear_error();
+ ERR_clear_system_error();
if (ssl->handshake_func == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
@@ -578,8 +579,6 @@
SSL_set_connect_state(ssl);
}
- assert(ssl->handshake_func == ssl->method->ssl_connect);
-
return SSL_do_handshake(ssl);
}
@@ -589,8 +588,6 @@
SSL_set_accept_state(ssl);
}
- assert(ssl->handshake_func == ssl->method->ssl_accept);
-
return SSL_do_handshake(ssl);
}
@@ -665,6 +662,7 @@
ssl->rwstate = SSL_NOTHING;
/* Functions which use SSL_get_error must clear the error queue on entry. */
ERR_clear_error();
+ ERR_clear_system_error();
if (ssl->handshake_func == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNINITIALIZED);
@@ -1184,6 +1182,10 @@
return SSL_in_init(ssl) && ssl->s3->initial_handshake_complete;
}
+int SSL_total_renegotiations(const SSL *ssl) {
+ return ssl->s3->total_renegotiations;
+}
+
size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx) {
return ctx->max_cert_list;
}
@@ -1268,6 +1270,77 @@
return ctx->session_cache_mode;
}
+
+int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) {
+ if (out == NULL) {
+ return 48;
+ }
+ if (len != 48) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+ return 0;
+ }
+ uint8_t *out_bytes = out;
+ memcpy(out_bytes, ctx->tlsext_tick_key_name, 16);
+ memcpy(out_bytes + 16, ctx->tlsext_tick_hmac_key, 16);
+ memcpy(out_bytes + 32, ctx->tlsext_tick_aes_key, 16);
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) {
+ if (in == NULL) {
+ return 48;
+ }
+ if (len != 48) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
+ return 0;
+ }
+ const uint8_t *in_bytes = in;
+ memcpy(ctx->tlsext_tick_key_name, in_bytes, 16);
+ memcpy(ctx->tlsext_tick_hmac_key, in_bytes + 16, 16);
+ memcpy(ctx->tlsext_tick_aes_key, in_bytes + 32, 16);
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_ticket_key_cb(
+ SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+ EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+ int encrypt)) {
+ ctx->tlsext_ticket_key_cb = callback;
+ return 1;
+}
+
+int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, size_t curves_len) {
+ return tls1_set_curves(&ctx->supported_group_list,
+ &ctx->supported_group_list_len, curves,
+ curves_len);
+}
+
+int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) {
+ return tls1_set_curves(&ssl->supported_group_list,
+ &ssl->supported_group_list_len, curves,
+ curves_len);
+}
+
+int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh) {
+ DH_free(ctx->cert->dh_tmp);
+ ctx->cert->dh_tmp = DHparams_dup(dh);
+ if (ctx->cert->dh_tmp == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
+ return 0;
+ }
+ return 1;
+}
+
+int SSL_set_tmp_dh(SSL *ssl, const DH *dh) {
+ DH_free(ssl->cert->dh_tmp);
+ ssl->cert->dh_tmp = DHparams_dup(dh);
+ if (ssl->cert->dh_tmp == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_DH_LIB);
+ return 0;
+ }
+ return 1;
+}
+
STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) {
if (ssl == NULL) {
return NULL;
@@ -1559,6 +1632,38 @@
return 1;
}
+int SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
+ OPENSSL_free(ssl->tlsext_hostname);
+ ssl->tlsext_hostname = NULL;
+
+ if (name == NULL) {
+ return 1;
+ }
+
+ size_t len = strlen(name);
+ if (len == 0 || len > TLSEXT_MAXLEN_host_name) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
+ return 0;
+ }
+ ssl->tlsext_hostname = BUF_strdup(name);
+ if (ssl->tlsext_hostname == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_servername_callback(
+ SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)) {
+ ctx->tlsext_servername_callback = callback;
+ return 1;
+}
+
+int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg) {
+ ctx->tlsext_servername_arg = arg;
+ return 1;
+}
+
int SSL_select_next_proto(uint8_t **out, uint8_t *out_len,
const uint8_t *server, unsigned server_len,
const uint8_t *client, unsigned client_len) {
@@ -1664,6 +1769,58 @@
}
}
+
+int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) {
+ ctx->tlsext_channel_id_enabled = 1;
+ return 1;
+}
+
+int SSL_enable_tls_channel_id(SSL *ssl) {
+ ssl->tlsext_channel_id_enabled = 1;
+ return 1;
+}
+
+static int is_p256_key(EVP_PKEY *private_key) {
+ const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(private_key);
+ return ec_key != NULL &&
+ EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) ==
+ NID_X9_62_prime256v1;
+}
+
+int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, EVP_PKEY *private_key) {
+ if (!is_p256_key(private_key)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
+ return 0;
+ }
+
+ EVP_PKEY_free(ctx->tlsext_channel_id_private);
+ ctx->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key);
+ ctx->tlsext_channel_id_enabled = 1;
+
+ return 1;
+}
+
+int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) {
+ if (!is_p256_key(private_key)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_NOT_P256);
+ return 0;
+ }
+
+ EVP_PKEY_free(ssl->tlsext_channel_id_private);
+ ssl->tlsext_channel_id_private = EVP_PKEY_up_ref(private_key);
+ ssl->tlsext_channel_id_enabled = 1;
+
+ return 1;
+}
+
+size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, size_t max_out) {
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ return 0;
+ }
+ memcpy(out, ssl->s3->tlsext_channel_id, (max_out < 64) ? max_out : 64);
+ return 64;
+}
+
void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
int (*cb)(X509_STORE_CTX *store_ctx,
void *arg),
@@ -1691,6 +1848,15 @@
ssl_cert_set_cert_cb(ssl->cert, cb, arg);
}
+size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) {
+ if (ssl->server || !ssl->s3->tmp.cert_req) {
+ *out_types = NULL;
+ return 0;
+ }
+ *out_types = ssl->s3->tmp.certificate_types;
+ return ssl->s3->tmp.num_certificate_types;
+}
+
void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k,
uint32_t *out_mask_a) {
uint32_t mask_k = 0;
@@ -1857,6 +2023,10 @@
return ssl->s3->aead_write_ctx->cipher;
}
+int SSL_session_reused(const SSL *ssl) {
+ return ssl->hit;
+}
+
const COMP_METHOD *SSL_get_current_compression(SSL *ssl) { return NULL; }
const COMP_METHOD *SSL_get_current_expansion(SSL *ssl) { return NULL; }
@@ -2186,6 +2356,12 @@
ctx->keylog_callback = cb;
}
+void SSL_CTX_set_current_time_cb(SSL_CTX *ctx,
+ void (*cb)(const SSL *ssl,
+ struct timeval *out_clock)) {
+ ctx->current_time_cb = cb;
+}
+
static int cbb_add_hex(CBB *cbb, const uint8_t *in, size_t in_len) {
static const char hextable[] = "0123456789abcdef";
uint8_t *out;
@@ -2535,8 +2711,6 @@
return ssl3_version_from_wire(ssl, ssl->version);
}
-int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); }
-
int SSL_is_server(SSL *ssl) { return ssl->server; }
void SSL_CTX_set_select_certificate_cb(
@@ -2709,6 +2883,27 @@
return 1;
}
+void ssl_do_info_callback(const SSL *ssl, int type, int value) {
+ void (*cb)(const SSL *ssl, int type, int value) = NULL;
+ if (ssl->info_callback != NULL) {
+ cb = ssl->info_callback;
+ } else if (ssl->ctx->info_callback != NULL) {
+ cb = ssl->ctx->info_callback;
+ }
+
+ if (cb != NULL) {
+ cb(ssl, type, value);
+ }
+}
+
+void ssl_do_msg_callback(SSL *ssl, int is_write, int version, int content_type,
+ const void *buf, size_t len) {
+ if (ssl->msg_callback != NULL) {
+ ssl->msg_callback(is_write, version, content_type, buf, len, ssl,
+ ssl->msg_callback_arg);
+ }
+}
+
int SSL_CTX_sess_connect(const SSL_CTX *ctx) { return 0; }
int SSL_CTX_sess_connect_good(const SSL_CTX *ctx) { return 0; }
int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx) { return 0; }
@@ -2720,5 +2915,33 @@
int SSL_CTX_sess_misses(const SSL_CTX *ctx) { return 0; }
int SSL_CTX_sess_timeouts(const SSL_CTX *ctx) { return 0; }
int SSL_CTX_sess_cache_full(const SSL_CTX *ctx) { return 0; }
+
+int SSL_num_renegotiations(const SSL *ssl) {
+ return SSL_total_renegotiations(ssl);
+}
+
+int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx) { return 0; }
+int SSL_need_tmp_RSA(const SSL *ssl) { return 0; }
+int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa) { return 1; }
+int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa) { return 1; }
void ERR_load_SSL_strings(void) {}
void SSL_load_error_strings(void) {}
+int SSL_cache_hit(SSL *ssl) { return SSL_session_reused(ssl); }
+
+int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key) {
+ if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
+ return SSL_CTX_set1_curves(ctx, &nid, 1);
+}
+
+int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key) {
+ if (ec_key == NULL || EC_KEY_get0_group(ec_key) == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
+ return SSL_set1_curves(ssl, &nid, 1);
+}
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 519736d..1841ece 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -28,14 +28,15 @@
#include <unistd.h>
#else
#include <io.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma comment(lib, "Ws2_32.lib")
#endif
+#include <assert.h>
#include <inttypes.h>
#include <string.h>
@@ -81,19 +82,10 @@
}
struct TestState {
- TestState() {
- // MSVC cannot initialize these inline.
- memset(&clock, 0, sizeof(clock));
- memset(&clock_delta, 0, sizeof(clock_delta));
- }
-
// async_bio is async BIO which pauses reads and writes.
BIO *async_bio = nullptr;
- // clock is the current time for the SSL connection.
- timeval clock;
- // clock_delta is how far the clock advanced in the most recent failed
- // |BIO_read|.
- timeval clock_delta;
+ // packeted_bio is the packeted BIO which simulates read timeouts.
+ BIO *packeted_bio = nullptr;
ScopedEVP_PKEY channel_id;
bool cert_ready = false;
ScopedSSL_SESSION session;
@@ -553,7 +545,7 @@
}
static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
- *out_clock = GetTestState(ssl)->clock;
+ *out_clock = PacketedBioGetClock(GetTestState(ssl)->packeted_bio);
}
static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
@@ -838,7 +830,7 @@
SSL_CTX_enable_tls_channel_id(ssl_ctx.get());
SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
- ssl_ctx->current_time_cb = CurrentTimeCallback;
+ SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
@@ -890,24 +882,15 @@
const TestConfig *config = GetTestConfig(ssl);
TestState *test_state = GetTestState(ssl);
- if (test_state->clock_delta.tv_usec != 0 ||
- test_state->clock_delta.tv_sec != 0) {
- // Process the timeout and retry.
- test_state->clock.tv_usec += test_state->clock_delta.tv_usec;
- test_state->clock.tv_sec += test_state->clock.tv_usec / 1000000;
- test_state->clock.tv_usec %= 1000000;
- test_state->clock.tv_sec += test_state->clock_delta.tv_sec;
- memset(&test_state->clock_delta, 0, sizeof(test_state->clock_delta));
+ assert(config->async);
+ if (test_state->packeted_bio != nullptr &&
+ PacketedBioAdvanceClock(test_state->packeted_bio)) {
// The DTLS retransmit logic silently ignores write failures. So the test
// may progress, allow writes through synchronously.
- if (config->async) {
- AsyncBioEnforceWriteQuota(test_state->async_bio, false);
- }
+ AsyncBioEnforceWriteQuota(test_state->async_bio, false);
int timeout_ret = DTLSv1_handle_timeout(ssl);
- if (config->async) {
- AsyncBioEnforceWriteQuota(test_state->async_bio, true);
- }
+ AsyncBioEnforceWriteQuota(test_state->async_bio, true);
if (timeout_ret < 0) {
fprintf(stderr, "Error retransmitting.\n");
@@ -1336,11 +1319,11 @@
return false;
}
if (config->is_dtls) {
- ScopedBIO packeted =
- PacketedBioCreate(&GetTestState(ssl.get())->clock_delta);
+ ScopedBIO packeted = PacketedBioCreate(!config->async);
if (!packeted) {
return false;
}
+ GetTestState(ssl.get())->packeted_bio = packeted.get();
BIO_push(packeted.get(), bio.release());
bio = std::move(packeted);
}
diff --git a/src/ssl/test/packeted_bio.cc b/src/ssl/test/packeted_bio.cc
index e831082..b0982b0 100644
--- a/src/ssl/test/packeted_bio.cc
+++ b/src/ssl/test/packeted_bio.cc
@@ -30,6 +30,46 @@
const uint8_t kOpcodeTimeout = 'T';
const uint8_t kOpcodeTimeoutAck = 't';
+struct PacketedBio {
+ explicit PacketedBio(bool advance_clock_arg)
+ : advance_clock(advance_clock_arg) {
+ memset(&timeout, 0, sizeof(timeout));
+ memset(&clock, 0, sizeof(clock));
+ memset(&read_deadline, 0, sizeof(read_deadline));
+ }
+
+ bool HasTimeout() const {
+ return timeout.tv_sec != 0 || timeout.tv_usec != 0;
+ }
+
+ bool CanRead() const {
+ if (read_deadline.tv_sec == 0 && read_deadline.tv_usec == 0) {
+ return true;
+ }
+
+ if (clock.tv_sec == read_deadline.tv_sec) {
+ return clock.tv_usec < read_deadline.tv_usec;
+ }
+ return clock.tv_sec < read_deadline.tv_sec;
+ }
+
+ timeval timeout;
+ timeval clock;
+ timeval read_deadline;
+ bool advance_clock;
+};
+
+PacketedBio *GetData(BIO *bio) {
+ if (bio->method != &g_packeted_bio_method) {
+ return NULL;
+ }
+ return (PacketedBio *)bio->ptr;
+}
+
+const PacketedBio *GetData(const BIO *bio) {
+ return GetData(const_cast<BIO*>(bio));
+}
+
// ReadAll reads |len| bytes from |bio| into |out|. It returns 1 on success and
// 0 or -1 on error.
static int ReadAll(BIO *bio, uint8_t *out, size_t len) {
@@ -79,90 +119,113 @@
}
static int PacketedRead(BIO *bio, char *out, int outl) {
+ PacketedBio *data = GetData(bio);
if (bio->next_bio == NULL) {
return 0;
}
BIO_clear_retry_flags(bio);
- // Read the opcode.
- uint8_t opcode;
- int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
- if (ret <= 0) {
- BIO_copy_next_retry(bio);
- return ret;
- }
+ for (;;) {
+ // Check if the read deadline has passed.
+ if (!data->CanRead()) {
+ BIO_set_retry_read(bio);
+ return -1;
+ }
- if (opcode == kOpcodeTimeout) {
- // Process the timeout.
- uint8_t buf[8];
- ret = ReadAll(bio->next_bio, buf, sizeof(buf));
+ // Read the opcode.
+ uint8_t opcode;
+ int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
if (ret <= 0) {
BIO_copy_next_retry(bio);
return ret;
}
- uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
- (static_cast<uint64_t>(buf[1]) << 48) |
- (static_cast<uint64_t>(buf[2]) << 40) |
- (static_cast<uint64_t>(buf[3]) << 32) |
- (static_cast<uint64_t>(buf[4]) << 24) |
- (static_cast<uint64_t>(buf[5]) << 16) |
- (static_cast<uint64_t>(buf[6]) << 8) |
- static_cast<uint64_t>(buf[7]);
- timeout /= 1000; // Convert nanoseconds to microseconds.
- timeval *out_timeout = reinterpret_cast<timeval *>(bio->ptr);
- assert(out_timeout->tv_usec == 0);
- assert(out_timeout->tv_sec == 0);
- out_timeout->tv_usec = timeout % 1000000;
- out_timeout->tv_sec = timeout / 1000000;
- // Send an ACK to the peer.
- ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
+ if (opcode == kOpcodeTimeout) {
+ // The caller is required to advance any pending timeouts before
+ // continuing.
+ if (data->HasTimeout()) {
+ fprintf(stderr, "Unprocessed timeout!\n");
+ return -1;
+ }
+
+ // Process the timeout.
+ uint8_t buf[8];
+ ret = ReadAll(bio->next_bio, buf, sizeof(buf));
+ if (ret <= 0) {
+ BIO_copy_next_retry(bio);
+ return ret;
+ }
+ uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
+ (static_cast<uint64_t>(buf[1]) << 48) |
+ (static_cast<uint64_t>(buf[2]) << 40) |
+ (static_cast<uint64_t>(buf[3]) << 32) |
+ (static_cast<uint64_t>(buf[4]) << 24) |
+ (static_cast<uint64_t>(buf[5]) << 16) |
+ (static_cast<uint64_t>(buf[6]) << 8) |
+ static_cast<uint64_t>(buf[7]);
+ timeout /= 1000; // Convert nanoseconds to microseconds.
+
+ data->timeout.tv_usec = timeout % 1000000;
+ data->timeout.tv_sec = timeout / 1000000;
+
+ // Send an ACK to the peer.
+ ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
+ if (ret <= 0) {
+ return ret;
+ }
+ assert(ret == 1);
+
+ if (!data->advance_clock) {
+ // Signal to the caller to retry the read, after advancing the clock.
+ BIO_set_retry_read(bio);
+ return -1;
+ }
+
+ PacketedBioAdvanceClock(bio);
+ continue;
+ }
+
+ if (opcode != kOpcodePacket) {
+ fprintf(stderr, "Unknown opcode, %u\n", opcode);
+ return -1;
+ }
+
+ // Read the length prefix.
+ uint8_t len_bytes[4];
+ ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
if (ret <= 0) {
+ BIO_copy_next_retry(bio);
return ret;
}
- assert(ret == 1);
- // Signal to the caller to retry the read, after processing the
- // new clock.
- BIO_set_retry_read(bio);
- return -1;
- }
+ uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
+ (len_bytes[2] << 8) | len_bytes[3];
+ uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
+ if (buf == NULL) {
+ return -1;
+ }
+ ret = ReadAll(bio->next_bio, buf, len);
+ if (ret <= 0) {
+ fprintf(stderr, "Packeted BIO was truncated\n");
+ return -1;
+ }
- if (opcode != kOpcodePacket) {
- fprintf(stderr, "Unknown opcode, %u\n", opcode);
- return -1;
+ if (outl > (int)len) {
+ outl = len;
+ }
+ memcpy(out, buf, outl);
+ OPENSSL_free(buf);
+ return outl;
}
-
- // Read the length prefix.
- uint8_t len_bytes[4];
- ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
- if (ret <= 0) {
- BIO_copy_next_retry(bio);
- return ret;
- }
-
- uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
- (len_bytes[2] << 8) | len_bytes[3];
- uint8_t *buf = (uint8_t *)OPENSSL_malloc(len);
- if (buf == NULL) {
- return -1;
- }
- ret = ReadAll(bio->next_bio, buf, len);
- if (ret <= 0) {
- fprintf(stderr, "Packeted BIO was truncated\n");
- return -1;
- }
-
- if (outl > (int)len) {
- outl = len;
- }
- memcpy(out, buf, outl);
- OPENSSL_free(buf);
- return outl;
}
static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) {
+ if (cmd == BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT) {
+ memcpy(&GetData(bio)->read_deadline, ptr, sizeof(timeval));
+ return 1;
+ }
+
if (bio->next_bio == NULL) {
return 0;
}
@@ -182,6 +245,7 @@
return 0;
}
+ delete GetData(bio);
bio->init = 0;
return 1;
}
@@ -208,11 +272,33 @@
} // namespace
-ScopedBIO PacketedBioCreate(timeval *out_timeout) {
+ScopedBIO PacketedBioCreate(bool advance_clock) {
ScopedBIO bio(BIO_new(&g_packeted_bio_method));
if (!bio) {
return nullptr;
}
- bio->ptr = out_timeout;
+ bio->ptr = new PacketedBio(advance_clock);
return bio;
}
+
+timeval PacketedBioGetClock(const BIO *bio) {
+ return GetData(bio)->clock;
+}
+
+bool PacketedBioAdvanceClock(BIO *bio) {
+ PacketedBio *data = GetData(bio);
+ if (data == nullptr) {
+ return false;
+ }
+
+ if (!data->HasTimeout()) {
+ return false;
+ }
+
+ data->clock.tv_usec += data->timeout.tv_usec;
+ data->clock.tv_sec += data->clock.tv_usec / 1000000;
+ data->clock.tv_usec %= 1000000;
+ data->clock.tv_sec += data->timeout.tv_sec;
+ memset(&data->timeout, 0, sizeof(data->timeout));
+ return true;
+}
diff --git a/src/ssl/test/packeted_bio.h b/src/ssl/test/packeted_bio.h
index 75cfa13..9bab635 100644
--- a/src/ssl/test/packeted_bio.h
+++ b/src/ssl/test/packeted_bio.h
@@ -21,24 +21,31 @@
#include "../../crypto/test/scoped_types.h"
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#else
#include <sys/time.h>
#endif
// PacketedBioCreate creates a filter BIO which implements a reliable in-order
-// blocking datagram socket. The resulting BIO, on |BIO_read|, may simulate a
-// timeout which sets |*out_timeout| to the timeout and fails the read.
-// |*out_timeout| must be zero on entry to |BIO_read|; it is an error to not
-// apply the timeout before the next |BIO_read|.
+// blocking datagram socket. It internally maintains a clock and honors
+// |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| based on it.
//
-// Note: The read timeout simulation is intended to be used with the async BIO
-// wrapper. It doesn't simulate BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, used in DTLS's
-// blocking mode.
-ScopedBIO PacketedBioCreate(timeval *out_timeout);
+// During a |BIO_read|, the peer may signal the filter BIO to simulate a
+// timeout. If |advance_clock| is true, it automatically advances the clock and
+// continues reading, subject to the read deadline. Otherwise, it fails
+// immediately. The caller must then call |PacketedBioAdvanceClock| before
+// retrying |BIO_read|.
+ScopedBIO PacketedBioCreate(bool advance_clock);
+
+// PacketedBioGetClock returns the current time for |bio|.
+timeval PacketedBioGetClock(const BIO *bio);
+
+// PacketedBioAdvanceClock advances |bio|'s internal clock and returns true if
+// there is a pending timeout. Otherwise, it returns false.
+bool PacketedBioAdvanceClock(BIO *bio);
#endif // HEADER_PACKETED_BIO
diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go
index 799f2d5..26f51b0 100644
--- a/src/ssl/test/runner/cipher_suites.go
+++ b/src/ssl/test/runner/cipher_suites.go
@@ -129,6 +129,8 @@
{TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
{TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+ {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
{TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
{TLS_PSK_WITH_RC4_128_SHA, 16, 20, 0, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil},
@@ -497,6 +499,8 @@
const (
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc13
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc14
+ TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xd001
+ TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0xd002
TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0x16b7
TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0x16b8
TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x16b9
diff --git a/src/ssl/test/runner/deterministic.go b/src/ssl/test/runner/deterministic.go
new file mode 100644
index 0000000..4a61ee0
--- /dev/null
+++ b/src/ssl/test/runner/deterministic.go
@@ -0,0 +1,37 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+package runner
+
+import (
+ "encoding/binary"
+)
+
+// Use a different key from crypto/rand/deterministic.c.
+var deterministicRandKey = []byte("runner deterministic key 0123456")
+
+type deterministicRand struct {
+ numCalls uint64
+}
+
+func (d *deterministicRand) Read(buf []byte) (int, error) {
+ for i := range buf {
+ buf[i] = 0
+ }
+ var nonce [12]byte
+ binary.LittleEndian.PutUint64(nonce[:8], d.numCalls)
+ chaCha20(buf, buf, deterministicRandKey, nonce[:], 0)
+ d.numCalls++
+ return len(buf), nil
+}
diff --git a/src/ssl/test/runner/newhope/newhope.go b/src/ssl/test/runner/newhope/newhope.go
index 36c2c85..8f7a530 100644
--- a/src/ssl/test/runner/newhope/newhope.go
+++ b/src/ssl/test/runner/newhope/newhope.go
@@ -153,24 +153,24 @@
// details of how this works.
func ntt(in *Poly, omega, preScaleBase, postScaleBase, postScale uint16) *Poly {
out := new(Poly)
- omega_to_the_i := 1
+ omega_to_the_i := uint64(1)
for i := range out {
- omegaToTheIJ := 1
- preScale := int(1)
- sum := 0
+ omegaToTheIJ := uint64(1)
+ preScale := uint64(1)
+ sum := uint64(0)
for j := range in {
- t := (int(in[j]) * preScale) % q
+ t := (uint64(in[j]) * preScale) % q
sum += (t * omegaToTheIJ) % q
omegaToTheIJ = (omegaToTheIJ * omega_to_the_i) % q
- preScale = (int(preScaleBase) * preScale) % q
+ preScale = (uint64(preScaleBase) * preScale) % q
}
- out[i] = uint16((sum * int(postScale)) % q)
+ out[i] = uint16((sum * uint64(postScale)) % q)
- omega_to_the_i = (omega_to_the_i * int(omega)) % q
- postScale = uint16((int(postScale) * int(postScaleBase)) % q)
+ omega_to_the_i = (omega_to_the_i * uint64(omega)) % q
+ postScale = uint16((uint64(postScale) * uint64(postScaleBase)) % q)
}
return out
@@ -255,7 +255,7 @@
bFreq := new(Poly)
for i := range bFreq {
- bFreq[i] = uint16((int(sFreq[i])*int(aFreq[i]) + int(eFreq[i])) % q)
+ bFreq[i] = uint16((uint64(sFreq[i])*uint64(aFreq[i]) + uint64(eFreq[i])) % q)
}
offerMsg = encodePoly(bFreq)
@@ -279,18 +279,18 @@
uFreq := new(Poly)
for i := range uFreq {
- uFreq[i] = uint16((int(sPrimeFreq[i])*int(aFreq[i]) + int(ePrimeFreq[i])) % q)
+ uFreq[i] = uint16((uint64(sPrimeFreq[i])*uint64(aFreq[i]) + uint64(ePrimeFreq[i])) % q)
}
vFreq := new(Poly)
for i := range vFreq {
- vFreq[i] = uint16((int(sPrimeFreq[i]) * int(bFreq[i])) % q)
+ vFreq[i] = uint16((uint64(sPrimeFreq[i]) * uint64(bFreq[i])) % q)
}
v := inverseNTT(vFreq)
ePrimePrime := sampleNoise(rand)
for i := range v {
- v[i] = uint16((int(v[i]) + int(ePrimePrime[i])) % q)
+ v[i] = uint16((uint64(v[i]) + uint64(ePrimePrime[i])) % q)
}
rec := helprec(rand, v)
@@ -311,7 +311,7 @@
rec := decodeRec(acceptMsg[encodedPolyLen:])
for i, u := range uFreq {
- uFreq[i] = uint16((int(u) * int(sk[i])) % q)
+ uFreq[i] = uint16((uint64(u) * uint64(sk[i])) % q)
}
u := inverseNTT(uFreq)
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index c10987e..962ac01 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -53,7 +53,8 @@
resourceDir = flag.String("resource-dir", ".", "The directory in which to find certificate and key files.")
fuzzer = flag.Bool("fuzzer", false, "If true, tests against a BoringSSL built in fuzzer mode.")
transcriptDir = flag.String("transcript-dir", "", "The directory in which to write transcripts.")
- timeout = flag.Int("timeout", 15, "The number of seconds to wait for a read or write to bssl_shim.")
+ idleTimeout = flag.Duration("idle-timeout", 15*time.Second, "The number of seconds to wait for a read or write to bssl_shim.")
+ deterministic = flag.Bool("deterministic", false, "If true, uses a deterministic PRNG in the runner.")
)
const (
@@ -315,7 +316,7 @@
}
func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) error {
- conn = &timeoutConn{conn, time.Duration(*timeout) * time.Second}
+ conn = &timeoutConn{conn, *idleTimeout}
if test.protocol == dtls {
config.Bugs.PacketAdaptor = newPacketAdaptor(conn)
@@ -765,6 +766,9 @@
if *fuzzer {
config.Bugs.NullAllCiphers = true
}
+ if *deterministic {
+ config.Rand = &deterministicRand{}
+ }
conn, err := acceptOrWait(listener, waitChan)
if err == nil {
@@ -795,6 +799,7 @@
if *fuzzer {
resumeConfig.Bugs.NullAllCiphers = true
}
+ resumeConfig.Rand = config.Rand
} else {
resumeConfig = config
}
@@ -924,6 +929,8 @@
{"ECDHE-PSK-AES128-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
{"ECDHE-PSK-AES256-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA},
{"ECDHE-PSK-CHACHA20-POLY1305", TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256},
+ {"ECDHE-PSK-AES128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256},
+ {"ECDHE-PSK-AES256-GCM-SHA384", TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384},
{"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
@@ -1770,7 +1777,7 @@
},
},
shouldFail: true,
- expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedError: ":BAD_HANDSHAKE_RECORD:",
},
{
protocol: dtls,
@@ -1781,7 +1788,7 @@
},
},
shouldFail: true,
- expectedError: ":EXCESSIVE_MESSAGE_SIZE:",
+ expectedError: ":BAD_HANDSHAKE_RECORD:",
},
{
protocol: dtls,
@@ -1792,7 +1799,7 @@
},
},
shouldFail: true,
- expectedError: ":EXCESSIVE_MESSAGE_SIZE:",
+ expectedError: ":BAD_HANDSHAKE_RECORD:",
},
{
protocol: dtls,
@@ -4685,106 +4692,137 @@
}
func addDTLSRetransmitTests() {
- // Test that this is indeed the timeout schedule. Stress all
- // four patterns of handshake.
- for i := 1; i < len(timeouts); i++ {
- number := strconv.Itoa(i)
- testCases = append(testCases, testCase{
+ // These tests work by coordinating some behavior on both the shim and
+ // the runner.
+ //
+ // TimeoutSchedule configures the runner to send a series of timeout
+ // opcodes to the shim (see packetAdaptor) immediately before reading
+ // each peer handshake flight N. The timeout opcode both simulates a
+ // timeout in the shim and acts as a synchronization point to help the
+ // runner bracket each handshake flight.
+ //
+ // We assume the shim does not read from the channel eagerly. It must
+ // first wait until it has sent flight N and is ready to receive
+ // handshake flight N+1. At this point, it will process the timeout
+ // opcode. It must then immediately respond with a timeout ACK and act
+ // as if the shim was idle for the specified amount of time.
+ //
+ // The runner then drops all packets received before the ACK and
+ // continues waiting for flight N. This ordering results in one attempt
+ // at sending flight N to be dropped. For the test to complete, the
+ // shim must send flight N again, testing that the shim implements DTLS
+ // retransmit on a timeout.
+
+ for _, async := range []bool{true, false} {
+ var tests []testCase
+
+ // Test that this is indeed the timeout schedule. Stress all
+ // four patterns of handshake.
+ for i := 1; i < len(timeouts); i++ {
+ number := strconv.Itoa(i)
+ tests = append(tests, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Client-" + number,
+ config: Config{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: timeouts[:i],
+ },
+ },
+ resumeSession: true,
+ })
+ tests = append(tests, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "DTLS-Retransmit-Server-" + number,
+ config: Config{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: timeouts[:i],
+ },
+ },
+ resumeSession: true,
+ })
+ }
+
+ // Test that exceeding the timeout schedule hits a read
+ // timeout.
+ tests = append(tests, testCase{
protocol: dtls,
- name: "DTLS-Retransmit-Client-" + number,
+ name: "DTLS-Retransmit-Timeout",
config: Config{
Bugs: ProtocolBugs{
- TimeoutSchedule: timeouts[:i],
+ TimeoutSchedule: timeouts,
},
},
resumeSession: true,
- flags: []string{"-async"},
+ shouldFail: true,
+ expectedError: ":READ_TIMEOUT_EXPIRED:",
})
- testCases = append(testCases, testCase{
+
+ if async {
+ // Test that timeout handling has a fudge factor, due to API
+ // problems.
+ tests = append(tests, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Fudge",
+ config: Config{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: []time.Duration{
+ timeouts[0] - 10*time.Millisecond,
+ },
+ },
+ },
+ resumeSession: true,
+ })
+ }
+
+ // Test that the final Finished retransmitting isn't
+ // duplicated if the peer badly fragments everything.
+ tests = append(tests, testCase{
+ testType: serverTest,
+ protocol: dtls,
+ name: "DTLS-Retransmit-Fragmented",
+ config: Config{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: []time.Duration{timeouts[0]},
+ MaxHandshakeRecordLength: 2,
+ },
+ },
+ })
+
+ // Test the timeout schedule when a shorter initial timeout duration is set.
+ tests = append(tests, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Short-Client",
+ config: Config{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-initial-timeout-duration-ms", "250"},
+ })
+ tests = append(tests, testCase{
protocol: dtls,
testType: serverTest,
- name: "DTLS-Retransmit-Server-" + number,
+ name: "DTLS-Retransmit-Short-Server",
config: Config{
Bugs: ProtocolBugs{
- TimeoutSchedule: timeouts[:i],
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
},
},
resumeSession: true,
- flags: []string{"-async"},
+ flags: []string{"-initial-timeout-duration-ms", "250"},
})
+
+ for _, test := range tests {
+ if async {
+ test.name += "-Async"
+ test.flags = append(test.flags, "-async")
+ }
+
+ testCases = append(testCases, test)
+ }
}
-
- // Test that exceeding the timeout schedule hits a read
- // timeout.
- testCases = append(testCases, testCase{
- protocol: dtls,
- name: "DTLS-Retransmit-Timeout",
- config: Config{
- Bugs: ProtocolBugs{
- TimeoutSchedule: timeouts,
- },
- },
- resumeSession: true,
- flags: []string{"-async"},
- shouldFail: true,
- expectedError: ":READ_TIMEOUT_EXPIRED:",
- })
-
- // Test that timeout handling has a fudge factor, due to API
- // problems.
- testCases = append(testCases, testCase{
- protocol: dtls,
- name: "DTLS-Retransmit-Fudge",
- config: Config{
- Bugs: ProtocolBugs{
- TimeoutSchedule: []time.Duration{
- timeouts[0] - 10*time.Millisecond,
- },
- },
- },
- resumeSession: true,
- flags: []string{"-async"},
- })
-
- // Test that the final Finished retransmitting isn't
- // duplicated if the peer badly fragments everything.
- testCases = append(testCases, testCase{
- testType: serverTest,
- protocol: dtls,
- name: "DTLS-Retransmit-Fragmented",
- config: Config{
- Bugs: ProtocolBugs{
- TimeoutSchedule: []time.Duration{timeouts[0]},
- MaxHandshakeRecordLength: 2,
- },
- },
- flags: []string{"-async"},
- })
-
- // Test the timeout schedule when a shorter initial timeout duration is set.
- testCases = append(testCases, testCase{
- protocol: dtls,
- name: "DTLS-Retransmit-Short-Client",
- config: Config{
- Bugs: ProtocolBugs{
- TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
- },
- },
- resumeSession: true,
- flags: []string{"-async", "-initial-timeout-duration-ms", "250"},
- })
- testCases = append(testCases, testCase{
- protocol: dtls,
- testType: serverTest,
- name: "DTLS-Retransmit-Short-Server",
- config: Config{
- Bugs: ProtocolBugs{
- TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
- },
- },
- resumeSession: true,
- flags: []string{"-async", "-initial-timeout-duration-ms", "250"},
- })
}
func addExportKeyingMaterialTests() {
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index b71da17..e1553e3 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -113,8 +113,10 @@
#include <openssl/bytestring.h>
#include <openssl/err.h>
+#include <openssl/mem.h>
#include "internal.h"
+#include "../crypto/internal.h"
/* kMaxEmptyRecords is the number of consecutive, empty records that will be
@@ -123,6 +125,10 @@
* forever. */
static const uint8_t kMaxEmptyRecords = 32;
+/* kMaxWarningAlerts is the number of consecutive warning alerts that will be
+ * processed. */
+static const uint8_t kMaxWarningAlerts = 4;
+
/* ssl_needs_record_splitting returns one if |ssl|'s current outgoing cipher
* state needs record-splitting and zero otherwise. */
static int ssl_needs_record_splitting(const SSL *ssl) {
@@ -154,7 +160,7 @@
}
}
-size_t ssl_seal_prefix_len(const SSL *ssl) {
+size_t ssl_seal_align_prefix_len(const SSL *ssl) {
if (SSL_IS_DTLS(ssl)) {
return DTLS1_RT_HEADER_LENGTH +
SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx);
@@ -170,23 +176,28 @@
}
size_t ssl_max_seal_overhead(const SSL *ssl) {
+ size_t ret = SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
if (SSL_IS_DTLS(ssl)) {
- return DTLS1_RT_HEADER_LENGTH +
- SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
+ ret += DTLS1_RT_HEADER_LENGTH;
} else {
- size_t ret = SSL3_RT_HEADER_LENGTH +
- SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
- if (ssl_needs_record_splitting(ssl)) {
- ret *= 2;
- }
- return ret;
+ ret += SSL3_RT_HEADER_LENGTH;
}
+ /* TLS 1.3 needs an extra byte for the encrypted record type. */
+ if (ssl->s3->have_version &&
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ ret += 1;
+ }
+ if (!SSL_IS_DTLS(ssl) && ssl_needs_record_splitting(ssl)) {
+ ret *= 2;
+ }
+ return ret;
}
-enum ssl_open_record_t tls_open_record(
- SSL *ssl, uint8_t *out_type, uint8_t *out, size_t *out_len,
- size_t *out_consumed, uint8_t *out_alert, size_t max_out, const uint8_t *in,
- size_t in_len) {
+enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
+ size_t *out_consumed, uint8_t *out_alert,
+ uint8_t *in, size_t in_len) {
+ *out_consumed = 0;
+
CBS cbs;
CBS_init(&cbs, in, in_len);
@@ -200,9 +211,9 @@
return ssl_open_record_partial;
}
- /* Check the version. */
- if ((ssl->s3->have_version && version != ssl->version) ||
- (version >> 8) != SSL3_VERSION_MAJOR) {
+ /* Check that the major version in the record matches. As of TLS 1.3, the
+ * minor version is no longer checked. */
+ if ((version >> 8) != SSL3_VERSION_MAJOR) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
*out_alert = SSL_AD_PROTOCOL_VERSION;
return ssl_open_record_error;
@@ -222,34 +233,46 @@
return ssl_open_record_partial;
}
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(0 /* read */, 0, SSL3_RT_HEADER, in,
- SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 0 /* read */, 0, SSL3_RT_HEADER, in,
+ SSL3_RT_HEADER_LENGTH);
- /* Decrypt the body. */
- size_t plaintext_len;
- if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, &plaintext_len, max_out,
- type, version, ssl->s3->read_sequence, CBS_data(&body),
+ /* Decrypt the body in-place. */
+ if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version,
+ ssl->s3->read_sequence, (uint8_t *)CBS_data(&body),
CBS_len(&body))) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
*out_alert = SSL_AD_BAD_RECORD_MAC;
return ssl_open_record_error;
}
+ *out_consumed = in_len - CBS_len(&cbs);
+
if (!ssl_record_sequence_update(ssl->s3->read_sequence, 8)) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return ssl_open_record_error;
}
+ /* TLS 1.3 hides the record type inside the encrypted data. */
+ if (ssl->s3->have_version &&
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
+ ssl->s3->aead_read_ctx != NULL) {
+ do {
+ if (!CBS_get_last_u8(out, &type)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+ *out_alert = SSL_AD_DECRYPT_ERROR;
+ return ssl_open_record_error;
+ }
+ } while (type == 0);
+ }
+
/* Check the plaintext length. */
- if (plaintext_len > SSL3_RT_MAX_PLAIN_LENGTH) {
+ if (CBS_len(out) > SSL3_RT_MAX_PLAIN_LENGTH) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
*out_alert = SSL_AD_RECORD_OVERFLOW;
return ssl_open_record_error;
}
/* Limit the number of consecutive empty records. */
- if (plaintext_len == 0) {
+ if (CBS_len(out) == 0) {
ssl->s3->empty_record_count++;
if (ssl->s3->empty_record_count > kMaxEmptyRecords) {
OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_EMPTY_FRAGMENTS);
@@ -262,9 +285,13 @@
ssl->s3->empty_record_count = 0;
}
+ if (type == SSL3_RT_ALERT) {
+ return ssl_process_alert(ssl, out_alert, CBS_data(out), CBS_len(out));
+ }
+
+ ssl->s3->warning_alert_count = 0;
+
*out_type = type;
- *out_len = plaintext_len;
- *out_consumed = in_len - CBS_len(&cbs);
return ssl_open_record_success;
}
@@ -275,20 +302,25 @@
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
- /* Check the record header does not alias any part of the input.
- * |SSL_AEAD_CTX_seal| will internally enforce other aliasing requirements. */
- if (in < out + SSL3_RT_HEADER_LENGTH && out < in + in_len) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
- return 0;
- }
+
+ /* Either |in| and |out| don't alias or |in| aligns with the
+ * ciphertext. |tls_seal_record| forbids aliasing, but TLS 1.3 aliases them
+ * internally. */
+ assert(!buffers_alias(in, in_len, out, max_out) ||
+ in ==
+ out + SSL3_RT_HEADER_LENGTH +
+ SSL_AEAD_CTX_explicit_nonce_len(ssl->s3->aead_write_ctx));
out[0] = type;
- /* Some servers hang if initial ClientHello is larger than 256 bytes and
- * record version number > TLS 1.0. */
- uint16_t wire_version = ssl->version;
- if (!ssl->s3->have_version && ssl->version > SSL3_VERSION) {
- wire_version = TLS1_VERSION;
+ /* The TLS record-layer version number is meaningless and, starting in
+ * TLS 1.3, is frozen at TLS 1.0. But for historical reasons, SSL 3.0
+ * ClientHellos should use SSL 3.0 and pre-TLS-1.3 expects the version
+ * to change after version negotiation. */
+ uint16_t wire_version = TLS1_VERSION;
+ if (ssl->version == SSL3_VERSION ||
+ (ssl->s3->have_version && ssl3_protocol_version(ssl) < TLS1_3_VERSION)) {
+ wire_version = ssl->version;
}
out[1] = wire_version >> 8;
out[2] = wire_version & 0xff;
@@ -311,31 +343,41 @@
*out_len = SSL3_RT_HEADER_LENGTH + ciphertext_len;
- if (ssl->msg_callback) {
- ssl->msg_callback(1 /* write */, 0, SSL3_RT_HEADER, out,
- SSL3_RT_HEADER_LENGTH, ssl, ssl->msg_callback_arg);
- }
-
+ ssl_do_msg_callback(ssl, 1 /* write */, 0, SSL3_RT_HEADER, out,
+ SSL3_RT_HEADER_LENGTH);
return 1;
}
int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
uint8_t type, const uint8_t *in, size_t in_len) {
+ if (buffers_alias(in, in_len, out, max_out)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+ return 0;
+ }
+
size_t frag_len = 0;
- if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 &&
- ssl_needs_record_splitting(ssl)) {
- /* |do_seal_record| will notice if it clobbers |in[0]|, but not if it
- * aliases the rest of |in|. */
- if (in + 1 <= out && out < in + in_len) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
+
+ /* TLS 1.3 hides the actual record type inside the encrypted data. */
+ if (ssl->s3->have_version &&
+ ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
+ ssl->s3->aead_read_ctx != NULL) {
+ size_t padding = SSL3_RT_HEADER_LENGTH + 1;
+
+ if (in_len > in_len + padding || max_out < in_len + padding) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
return 0;
}
- /* Ensure |do_seal_record| does not write beyond |in[0]|. */
- size_t frag_max_out = max_out;
- if (out <= in + 1 && in + 1 < out + frag_max_out) {
- frag_max_out = (size_t)(in + 1 - out);
- }
- if (!do_seal_record(ssl, out, &frag_len, frag_max_out, type, in, 1)) {
+
+ memmove(out + SSL3_RT_HEADER_LENGTH, in, in_len);
+ out[SSL3_RT_HEADER_LENGTH + in_len] = type;
+ in = out + SSL3_RT_HEADER_LENGTH;
+ type = SSL3_RT_APPLICATION_DATA;
+ in_len++;
+ }
+
+ if (type == SSL3_RT_APPLICATION_DATA && in_len > 1 &&
+ ssl_needs_record_splitting(ssl)) {
+ if (!do_seal_record(ssl, out, &frag_len, max_out, type, in, 1)) {
return 0;
}
in++;
@@ -379,3 +421,51 @@
SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
ssl->s3->aead_write_ctx = aead_ctx;
}
+
+enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert,
+ const uint8_t *in, size_t in_len) {
+ /* Alerts records may not contain fragmented or multiple alerts. */
+ if (in_len != 2) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
+ return ssl_open_record_error;
+ }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, ssl->version, SSL3_RT_ALERT, in, in_len);
+
+ const uint8_t alert_level = in[0];
+ const uint8_t alert_descr = in[1];
+
+ uint16_t alert = (alert_level << 8) | alert_descr;
+ ssl_do_info_callback(ssl, SSL_CB_READ_ALERT, alert);
+
+ if (alert_level == SSL3_AL_WARNING) {
+ if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
+ ssl->s3->recv_shutdown = ssl_shutdown_close_notify;
+ return ssl_open_record_close_notify;
+ }
+
+ ssl->s3->warning_alert_count++;
+ if (ssl->s3->warning_alert_count > kMaxWarningAlerts) {
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_WARNING_ALERTS);
+ return ssl_open_record_error;
+ }
+ return ssl_open_record_discard;
+ }
+
+ if (alert_level == SSL3_AL_FATAL) {
+ ssl->s3->recv_shutdown = ssl_shutdown_fatal_alert;
+ SSL_CTX_remove_session(ssl->ctx, ssl->session);
+
+ char tmp[16];
+ OPENSSL_PUT_ERROR(SSL, SSL_AD_REASON_OFFSET + alert_descr);
+ BIO_snprintf(tmp, sizeof(tmp), "%d", alert_descr);
+ ERR_add_error_data(2, "SSL alert number ", tmp);
+ return ssl_open_record_fatal_alert;
+ }
+
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_ALERT_TYPE);
+ return ssl_open_record_error;
+}
diff --git a/src/tool/digest.cc b/src/tool/digest.cc
index c2cee7f..2e3e608 100644
--- a/src/tool/digest.cc
+++ b/src/tool/digest.cc
@@ -31,9 +31,9 @@
#define O_BINARY 0
#endif
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#include <io.h>
#define PATH_MAX MAX_PATH
typedef int ssize_t;
diff --git a/src/tool/internal.h b/src/tool/internal.h
index 7737f4c..fd66e00 100644
--- a/src/tool/internal.h
+++ b/src/tool/internal.h
@@ -20,19 +20,15 @@
#include <string>
#include <vector>
-#if defined(_MSC_VER)
-#pragma warning(push)
+OPENSSL_MSVC_PRAGMA(warning(push))
// MSVC issues warning C4702 for unreachable code in its xtree header when
// compiling with -D_HAS_EXCEPTIONS=0. See
// https://connect.microsoft.com/VisualStudio/feedback/details/809962
-#pragma warning(disable: 4702)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(disable: 4702))
#include <map>
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(pop))
#if defined(OPENSSL_WINDOWS)
#define BORINGSSL_OPEN _open
diff --git a/src/tool/speed.cc b/src/tool/speed.cc
index 58c7382..a8eb8bf 100644
--- a/src/tool/speed.cc
+++ b/src/tool/speed.cc
@@ -30,9 +30,9 @@
#include <openssl/rsa.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#elif defined(OPENSSL_APPLE)
#include <sys/time.h>
#endif
diff --git a/src/tool/transport_common.cc b/src/tool/transport_common.cc
index be47787..01fcde4 100644
--- a/src/tool/transport_common.cc
+++ b/src/tool/transport_common.cc
@@ -33,10 +33,10 @@
#include <unistd.h>
#else
#include <io.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
typedef int ssize_t;
#pragma comment(lib, "Ws2_32.lib")
diff --git a/src/util/all_tests.json b/src/util/all_tests.json
index 9e3445c..48b540e 100644
--- a/src/util/all_tests.json
+++ b/src/util/all_tests.json
@@ -30,7 +30,7 @@
["crypto/cipher/aead_test", "des-ede3-cbc-sha1-ssl3", "crypto/cipher/test/des_ede3_cbc_sha1_ssl3_tests.txt"],
["crypto/cipher/aead_test", "aes-128-ctr-hmac-sha256", "crypto/cipher/test/aes_128_ctr_hmac_sha256.txt"],
["crypto/cipher/aead_test", "aes-256-ctr-hmac-sha256", "crypto/cipher/test/aes_256_ctr_hmac_sha256.txt"],
- ["crypto/cipher/cipher_test", "crypto/cipher/test/cipher_test.txt"],
+ ["crypto/cipher/cipher_test", "crypto/cipher/test/cipher_tests.txt"],
["crypto/cmac/cmac_test"],
["crypto/constant_time_test"],
["crypto/curve25519/ed25519_test", "crypto/curve25519/ed25519_tests.txt"],
@@ -51,11 +51,12 @@
["crypto/lhash/lhash_test"],
["crypto/modes/gcm_test"],
["crypto/newhope/newhope_test"],
- ["crypto/newhope/newhope_vectors_test", "crypto/newhope/newhope_test.txt"],
+ ["crypto/newhope/newhope_statistical_test"],
+ ["crypto/newhope/newhope_vectors_test", "crypto/newhope/newhope_tests.txt"],
["crypto/obj/obj_test"],
["crypto/pkcs8/pkcs12_test"],
["crypto/pkcs8/pkcs8_test"],
- ["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_test.txt"],
+ ["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_tests.txt"],
["crypto/refcount_test"],
["crypto/rsa/rsa_test"],
["crypto/thread_test"],
diff --git a/src/util/generate_build_files.py b/src/util/generate_build_files.py
index 663d6c7..76c390b 100644
--- a/src/util/generate_build_files.py
+++ b/src/util/generate_build_files.py
@@ -12,10 +12,9 @@
# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-"""Enumerates the BoringSSL source in src/ and either generates two gypi files
- (boringssl.gypi and boringssl_tests.gypi) for Chromium, or generates
- source-list files for Android."""
+"""Enumerates source files for consumption by various build systems."""
+import optparse
import os
import subprocess
import sys
@@ -50,6 +49,12 @@
],
}
+PREFIX = None
+
+
+def PathOf(x):
+ return x if not PREFIX else os.path.join(PREFIX, x)
+
class Android(object):
@@ -121,7 +126,7 @@
out.write('%s = [\n' % name)
for f in sorted(files):
- out.write(' "%s",\n' % f)
+ out.write(' "%s",\n' % PathOf(f))
out.write(']\n')
def WriteFiles(self, files, asm_outputs):
@@ -149,13 +154,13 @@
for filename in files['test_support']:
if os.path.basename(filename) == 'malloc.cc':
continue
- out.write(' "%s",\n' % filename)
+ out.write(' "%s",\n' % PathOf(filename))
out.write(']\n\n')
out.write('def create_tests(copts):\n')
out.write(' test_support_sources_complete = test_support_sources + \\\n')
- out.write(' native.glob(["src/crypto/test/*.h"])\n')
+ out.write(' native.glob(["%s"])\n' % PathOf("src/crypto/test/*.h"))
name_counts = {}
for test in files['tests']:
name = os.path.basename(test[0])
@@ -185,7 +190,8 @@
out.write(' native.cc_test(\n')
out.write(' name = "%s",\n' % name)
out.write(' size = "small",\n')
- out.write(' srcs = ["%s"] + test_support_sources_complete,\n' % src)
+ out.write(' srcs = ["%s"] + test_support_sources_complete,\n' %
+ PathOf(src))
data_files = []
if len(test) > 1:
@@ -193,7 +199,8 @@
out.write(' args = [\n')
for arg in test[1:]:
if '/' in arg:
- out.write(' "$(location src/%s)",\n' % arg)
+ out.write(' "$(location %s)",\n' %
+ PathOf(os.path.join('src', arg)))
data_files.append('src/%s' % arg)
else:
out.write(' "%s",\n' % arg)
@@ -204,7 +211,7 @@
if len(data_files) > 0:
out.write(' data = [\n')
for filename in data_files:
- out.write(' "%s",\n' % filename)
+ out.write(' "%s",\n' % PathOf(filename))
out.write(' ],\n')
if 'ssl/' in test[0]:
@@ -609,17 +616,20 @@
return 0
-def Usage():
- print 'Usage: python %s [android|android-standalone|bazel|gn|gyp]' % sys.argv[0]
- sys.exit(1)
-
-
if __name__ == '__main__':
- if len(sys.argv) < 2:
- Usage()
+ parser = optparse.OptionParser(usage='Usage: %prog [--prefix=<path>]'
+ ' [android|android-standalone|bazel|gn|gyp]')
+ parser.add_option('--prefix', dest='prefix',
+ help='For Bazel, prepend argument to all source files')
+ options, args = parser.parse_args(sys.argv[1:])
+ PREFIX = options.prefix
+
+ if not args:
+ parser.print_help()
+ sys.exit(1)
platforms = []
- for s in sys.argv[1:]:
+ for s in args:
if s == 'android':
platforms.append(Android())
elif s == 'android-standalone':
@@ -631,6 +641,7 @@
elif s == 'gyp':
platforms.append(GYP())
else:
- Usage()
+ parser.print_help()
+ sys.exit(1)
sys.exit(main(platforms))
diff --git a/src/util/run_android_tests.go b/src/util/run_android_tests.go
index fc94d33..6502a16 100644
--- a/src/util/run_android_tests.go
+++ b/src/util/run_android_tests.go
@@ -15,6 +15,7 @@
package main
import (
+ "bytes"
"encoding/json"
"flag"
"fmt"
@@ -23,6 +24,7 @@
"os"
"os/exec"
"path/filepath"
+ "strconv"
"strings"
)
@@ -56,6 +58,55 @@
return cmd.Run()
}
+func adbShell(shellCmd string) (int, error) {
+ var args []string
+ if len(*device) > 0 {
+ args = append([]string{"-s", *device}, args...)
+ }
+ args = append(args, "shell")
+
+ const delimiter = "___EXIT_CODE___"
+
+ // Older versions of adb and Android do not preserve the exit
+ // code, so work around this.
+ // https://code.google.com/p/android/issues/detail?id=3254
+ shellCmd += "; echo " + delimiter + " $?"
+ args = append(args, shellCmd)
+
+ cmd := exec.Command(*adbPath, args...)
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return 0, err
+ }
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ return 0, err
+ }
+
+ var stdoutBytes bytes.Buffer
+ for {
+ var buf [1024]byte
+ n, err := stdout.Read(buf[:])
+ stdoutBytes.Write(buf[:n])
+ os.Stdout.Write(buf[:n])
+ if err != nil {
+ break
+ }
+ }
+
+ if err := cmd.Wait(); err != nil {
+ return 0, err
+ }
+
+ stdoutStr := stdoutBytes.String()
+ idx := strings.LastIndex(stdoutStr, delimiter)
+ if idx < 0 {
+ return 0, fmt.Errorf("Could not find delimiter in output.")
+ }
+
+ return strconv.Atoi(strings.TrimSpace(stdoutStr[idx+len(delimiter):]))
+}
+
func goTool(args ...string) error {
cmd := exec.Command("go", args...)
cmd.Stdout = os.Stdout
@@ -227,17 +278,21 @@
os.Exit(1)
}
+ var unitTestExit int
if enableUnitTests() {
fmt.Printf("Running unit tests...\n")
- if err := adb("shell", fmt.Sprintf("cd /data/local/tmp/boringssl-tmp && ./util/all_tests -json-output results.json %s", *allTestsArgs)); err != nil {
+ unitTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp && ./util/all_tests -json-output results.json %s", *allTestsArgs))
+ if err != nil {
fmt.Printf("Failed to run unit tests: %s\n", err)
os.Exit(1)
}
}
+ var sslTestExit int
if enableSSLTests() {
fmt.Printf("Running SSL tests...\n")
- if err := adb("shell", fmt.Sprintf("cd /data/local/tmp/boringssl-tmp/ssl/test/runner && ./runner -json-output ../../../results.json %s", *runnerArgs)); err != nil {
+ sslTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp/ssl/test/runner && ./runner -json-output ../../../results.json %s", *runnerArgs))
+ if err != nil {
fmt.Printf("Failed to run SSL tests: %s\n", err)
os.Exit(1)
}
@@ -249,4 +304,12 @@
os.Exit(1)
}
}
+
+ if unitTestExit != 0 {
+ os.Exit(unitTestExit)
+ }
+
+ if sslTestExit != 0 {
+ os.Exit(sslTestExit)
+ }
}
diff --git a/win-x86/crypto/chacha/chacha-x86.asm b/win-x86/crypto/chacha/chacha-x86.asm
index 283c8e4..3ba31a2 100644
--- a/win-x86/crypto/chacha/chacha-x86.asm
+++ b/win-x86/crypto/chacha/chacha-x86.asm
@@ -272,13 +272,11 @@
xor esi,DWORD [36+ebx]
xor edx,DWORD [48+ebx]
xor edi,DWORD [56+ebx]
- mov DWORD [16+esp],ebp
- mov ebp,DWORD [esp]
- mov DWORD [32+esp],ecx
- mov DWORD [36+esp],esi
- mov DWORD [48+esp],edx
- mov DWORD [56+esp],edi
- mov DWORD [eax],ebp
+ mov DWORD [16+eax],ebp
+ mov DWORD [32+eax],ecx
+ mov DWORD [36+eax],esi
+ mov DWORD [48+eax],edx
+ mov DWORD [56+eax],edi
mov ebp,DWORD [4+esp]
mov ecx,DWORD [8+esp]
mov esi,DWORD [12+esp]
@@ -295,42 +293,34 @@
xor edx,DWORD [20+ebx]
xor edi,DWORD [24+ebx]
mov DWORD [4+eax],ebp
- mov ebp,DWORD [16+esp]
mov DWORD [8+eax],ecx
mov DWORD [12+eax],esi
- mov DWORD [16+eax],ebp
mov DWORD [20+eax],edx
mov DWORD [24+eax],edi
- mov ecx,DWORD [28+esp]
- mov edx,DWORD [32+esp]
- mov edi,DWORD [36+esp]
- add ecx,DWORD [92+esp]
- mov ebp,DWORD [40+esp]
- xor ecx,DWORD [28+ebx]
+ mov ebp,DWORD [28+esp]
+ mov ecx,DWORD [40+esp]
mov esi,DWORD [44+esp]
- mov DWORD [28+eax],ecx
- mov DWORD [32+eax],edx
- mov DWORD [36+eax],edi
- add ebp,DWORD [104+esp]
- add esi,DWORD [108+esp]
- xor ebp,DWORD [40+ebx]
- xor esi,DWORD [44+ebx]
- mov DWORD [40+eax],ebp
- mov DWORD [44+eax],esi
- mov ecx,DWORD [48+esp]
- mov esi,DWORD [56+esp]
mov edx,DWORD [52+esp]
mov edi,DWORD [60+esp]
+ add ebp,DWORD [92+esp]
+ add ecx,DWORD [104+esp]
+ add esi,DWORD [108+esp]
add edx,DWORD [116+esp]
add edi,DWORD [124+esp]
+ xor ebp,DWORD [28+ebx]
+ xor ecx,DWORD [40+ebx]
+ xor esi,DWORD [44+ebx]
xor edx,DWORD [52+ebx]
xor edi,DWORD [60+ebx]
lea ebx,[64+ebx]
- mov DWORD [48+eax],ecx
+ mov DWORD [28+eax],ebp
+ mov ebp,DWORD [esp]
+ mov DWORD [40+eax],ecx
mov ecx,DWORD [160+esp]
+ mov DWORD [44+eax],esi
mov DWORD [52+eax],edx
- mov DWORD [56+eax],esi
mov DWORD [60+eax],edi
+ mov DWORD [eax],ebp
lea eax,[64+eax]
sub ecx,64
jnz NEAR L$003outer_loop
@@ -723,14 +713,24 @@
punpcklqdq xmm6,xmm7
punpckhqdq xmm1,xmm2
punpckhqdq xmm3,xmm7
- movdqa [ebx-128],xmm0
+ movdqu xmm4,[esi-128]
+ movdqu xmm5,[esi-64]
+ movdqu xmm2,[esi]
+ movdqu xmm7,[64+esi]
+ lea esi,[16+esi]
+ pxor xmm4,xmm0
movdqa xmm0,[ebx-64]
- movdqa [ebx-112],xmm1
- movdqa [ebx-96],xmm6
- movdqa [ebx-80],xmm3
+ pxor xmm5,xmm1
movdqa xmm1,[ebx-48]
+ pxor xmm6,xmm2
movdqa xmm2,[ebx-32]
+ pxor xmm7,xmm3
movdqa xmm3,[ebx-16]
+ movdqu [edi-128],xmm4
+ movdqu [edi-64],xmm5
+ movdqu [edi],xmm6
+ movdqu [64+edi],xmm7
+ lea edi,[16+edi]
paddd xmm0,[ebp-64]
paddd xmm1,[ebp-48]
paddd xmm2,[ebp-32]
@@ -747,14 +747,24 @@
punpcklqdq xmm6,xmm7
punpckhqdq xmm1,xmm2
punpckhqdq xmm3,xmm7
- movdqa [ebx-64],xmm0
+ movdqu xmm4,[esi-128]
+ movdqu xmm5,[esi-64]
+ movdqu xmm2,[esi]
+ movdqu xmm7,[64+esi]
+ lea esi,[16+esi]
+ pxor xmm4,xmm0
movdqa xmm0,[ebx]
- movdqa [ebx-48],xmm1
- movdqa [ebx-32],xmm6
- movdqa [ebx-16],xmm3
+ pxor xmm5,xmm1
movdqa xmm1,[16+ebx]
+ pxor xmm6,xmm2
movdqa xmm2,[32+ebx]
+ pxor xmm7,xmm3
movdqa xmm3,[48+ebx]
+ movdqu [edi-128],xmm4
+ movdqu [edi-64],xmm5
+ movdqu [edi],xmm6
+ movdqu [64+edi],xmm7
+ lea edi,[16+edi]
paddd xmm0,[ebp]
paddd xmm1,[16+ebp]
paddd xmm2,[32+ebp]
@@ -771,14 +781,24 @@
punpcklqdq xmm6,xmm7
punpckhqdq xmm1,xmm2
punpckhqdq xmm3,xmm7
- movdqa [ebx],xmm0
+ movdqu xmm4,[esi-128]
+ movdqu xmm5,[esi-64]
+ movdqu xmm2,[esi]
+ movdqu xmm7,[64+esi]
+ lea esi,[16+esi]
+ pxor xmm4,xmm0
movdqa xmm0,[64+ebx]
- movdqa [16+ebx],xmm1
- movdqa [32+ebx],xmm6
- movdqa [48+ebx],xmm3
+ pxor xmm5,xmm1
movdqa xmm1,[80+ebx]
+ pxor xmm6,xmm2
movdqa xmm2,[96+ebx]
+ pxor xmm7,xmm3
movdqa xmm3,[112+ebx]
+ movdqu [edi-128],xmm4
+ movdqu [edi-64],xmm5
+ movdqu [edi],xmm6
+ movdqu [64+edi],xmm7
+ lea edi,[16+edi]
paddd xmm0,[64+ebp]
paddd xmm1,[80+ebp]
paddd xmm2,[96+ebp]
@@ -795,60 +815,20 @@
punpcklqdq xmm6,xmm7
punpckhqdq xmm1,xmm2
punpckhqdq xmm3,xmm7
- movdqa [64+ebx],xmm0
- movdqa [80+ebx],xmm1
- movdqa [96+ebx],xmm6
- movdqa [112+ebx],xmm3
- movdqu xmm0,[esi-128]
- movdqu xmm1,[esi-112]
- movdqu xmm2,[esi-96]
- movdqu xmm3,[esi-80]
- pxor xmm0,[ebx-128]
- pxor xmm1,[ebx-64]
- pxor xmm2,[ebx]
- pxor xmm3,[64+ebx]
- movdqu [edi-128],xmm0
- movdqu [edi-112],xmm1
- movdqu [edi-96],xmm2
- movdqu [edi-80],xmm3
- movdqu xmm0,[esi-64]
- movdqu xmm1,[esi-48]
- movdqu xmm2,[esi-32]
- movdqu xmm3,[esi-16]
- pxor xmm0,[ebx-112]
- pxor xmm1,[ebx-48]
- pxor xmm2,[16+ebx]
- pxor xmm3,[80+ebx]
- movdqu [edi-64],xmm0
- movdqu [edi-48],xmm1
- movdqu [edi-32],xmm2
- movdqu [edi-16],xmm3
- movdqu xmm0,[esi]
- movdqu xmm1,[16+esi]
- movdqu xmm2,[32+esi]
- movdqu xmm3,[48+esi]
- pxor xmm0,[ebx-96]
- pxor xmm1,[ebx-32]
- pxor xmm2,[32+ebx]
- pxor xmm3,[96+ebx]
- movdqu [edi],xmm0
- movdqu [16+edi],xmm1
- movdqu [32+edi],xmm2
- movdqu [48+edi],xmm3
- movdqu xmm0,[64+esi]
- movdqu xmm1,[80+esi]
- movdqu xmm2,[96+esi]
- movdqu xmm3,[112+esi]
- pxor xmm0,[ebx-80]
- pxor xmm1,[ebx-16]
- pxor xmm2,[48+ebx]
- pxor xmm3,[112+ebx]
- movdqu [64+edi],xmm0
- movdqu [80+edi],xmm1
- movdqu [96+edi],xmm2
- movdqu [112+edi],xmm3
- lea esi,[256+esi]
- lea edi,[256+edi]
+ movdqu xmm4,[esi-128]
+ movdqu xmm5,[esi-64]
+ movdqu xmm2,[esi]
+ movdqu xmm7,[64+esi]
+ lea esi,[208+esi]
+ pxor xmm4,xmm0
+ pxor xmm5,xmm1
+ pxor xmm6,xmm2
+ pxor xmm7,xmm3
+ movdqu [edi-128],xmm4
+ movdqu [edi-64],xmm5
+ movdqu [edi],xmm6
+ movdqu [64+edi],xmm7
+ lea edi,[208+edi]
sub ecx,256
jnc NEAR L$009outer_loop
add ecx,256