Skip to content

Commit

Permalink
Support OpenSSL Symcrypt provider and engine #54
Browse files Browse the repository at this point in the history
Upgrade the Debian release to Bookworm and upgrade the submodules.
Support OpenSSL Symcrypt provider and engine
  • Loading branch information
xumia authored May 21, 2024
2 parents fe7eb30 + a40039b commit 1012763
Show file tree
Hide file tree
Showing 38 changed files with 733 additions and 243 deletions.
2 changes: 1 addition & 1 deletion .azure-pipelines/Dockerfile.j2
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% set prefix = DEFAULT_CONTAINER_REGISTRY %}
{%- if ARCH == "armhf" %}
FROM {{ prefix }}multiarch/qemu-user-static:x86_64-arm-6.1.0-8 as qemu
FROM {{ prefix }}multiarch/debian-debootstrap:armhf-{{ DIST }}
FROM --platform=linux/arm/v7 {{ prefix }}debian:{{ DIST }}
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
{%- elif ARCH == "arm64" %}
FROM {{ prefix }}multiarch/qemu-user-static:x86_64-aarch64-6.1.0-8 as qemu
Expand Down
36 changes: 27 additions & 9 deletions .azure-pipelines/build-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ parameters:
default: amd64
- name: image
type: string
default: publicmirror.azurecr.io/debian:bullseye
default: publicmirror.azurecr.io/debian:bookworm
- name: buildOthers
type: boolean
default: true
Expand Down Expand Up @@ -43,24 +43,24 @@ jobs:
sudo chown $USER $HOME
sudo apt-get update
sudo apt-get install -y git python3-pip
sudo apt-get install -y cmake git make build-essential quilt debhelper bc python3 python3-pip sudo libssl-dev libgcc-10-dev
sudo apt-get install -y cmake git make build-essential quilt debhelper bc python3 python3-pip sudo libssl-dev libgcc-12-dev
sudo apt-get install -y clang
sudo apt-get install -y openssl libssl-dev libssl1.1
sudo apt-get install -y openssl libssl-dev libssl3
sudo apt-get install -y dh-exec dh-runit libaudit-dev libedit-dev libfido2-dev libgtk-3-dev libkrb5-dev
sudo apt-get install -y libwrap-dev pkg-config
sudo apt-get install -y libwrap0-dev pkg-config
sudo apt-get install -y libpam-dev libselinux1-dev libsystemd-dev libwrap0-dev
# Build Golang
sudo apt-get install -y golang
# Build Python
sudo apt-get install -y lsb-release sharutils libreadline-dev libncursesw5-dev libbz2-dev liblzma-dev libgdbm-dev libdb-dev tk-dev blt-dev libexpat1-dev libmpdec-dev libbluetooth-dev locales-all libsqlite3-dev media-types
sudo apt-get install -y lsb-release sharutils libreadline-dev libncursesw5-dev libbz2-dev liblzma-dev libgdbm-dev libdb-dev tk-dev blt-dev libexpat1-dev libbluetooth-dev locales-all libsqlite3-dev media-types
sudo apt-get install -y time net-tools xvfb systemtap-sdt-dev python3-sphinx python3-docs-theme texinfo

# Build krb5
sudo apt-get install -y ss-dev libldap2-dev libc6-dev libkeyutils-dev byacc docbook-to-man libsasl2-dev libverto-dev python3-cheetah python3-lxml doxygen doxygen-latex tex-gyre

sudo pip3 install blurb
sudo pip3 install --break-system-packages blurb

mkdir -p $(Pipeline.Workspace)/target
displayName: 'Install packages'
Expand All @@ -73,26 +73,28 @@ jobs:
- script: |
set -ex
sudo mkdir -p $HOME
sudo pip3 install -r src/SymCrypt/scripts/requirements.txt
sudo pip3 install --break-system-packages -r src/SymCrypt/scripts/requirements.txt
git config --global user.name sonicbld
git config --global user.email sonicbld@microsoft.com
if [ "${{ parameters.arch }}" == armhf ]; then
ARCH=${{ parameters.arch }} SYMCRYPT_TEST=n make symcrypt
else
ARCH=${{ parameters.arch }} make symcrypt
sudo dpkg -i target/symcrypt-openssl*.deb
fi
sudo dpkg -i target/symcrypt-openssl*.deb
displayName: 'Build and install symcrypt'
- script: |
set -ex
ARCH=${{ parameters.arch }} make openssl
sudo dpkg -i target/libssl*.deb target/openssl*.deb
condition: true
displayName: 'Build and install openssl'
- script: |
set -ex
sudo mkdir -p /etc/fips
echo 1 | sudo tee /etc/fips/fips_enable
openssl engine -v | grep -i symcrypt
openssl list --providers | grep -i symcrypt
pushd src/openssl
git clean -xdf
git checkout -- .
Expand All @@ -101,10 +103,26 @@ jobs:
ARCH=${{ parameters.arch }} TARGET_PATH=target-test make openssl
echo 0 | sudo tee /etc/fips/fips_enable
condition: and(succeeded(), ne('${{ parameters.arch }}', 'armhf'))
displayName: 'Test openssl with fips enabled'
continueOnError: true
displayName: 'Test with fips enabled'
- script: |
set -ex
if [ "$(cat /etc/fips/fips_enable)" != "0" ]; then
cat src/openssl.patch/skipped-openssl-tests.conf
TESTS=$(cat src/openssl.patch/skipped-openssl-tests.conf | sed 's/^/-/' | xargs)
pushd src/openssl/build_shared
make TESTS="$TESTS" test
popd
echo 0 | sudo tee /etc/fips/fips_enable
fi
condition: and(succeeded(), ne('${{ parameters.arch }}', 'armhf'))
displayName: 'Test and skip known issues'
- script: |
set -ex
git config --global user.email sonicbld@microsoft.com
git config --global user.name mssonicbld
ARCH=${{ parameters.arch }} make all
cp src/*.deb target/
condition: and(succeeded(), ${{ eq(parameters.buildOthers, true) }})
Expand Down
19 changes: 16 additions & 3 deletions .azure-pipelines/install-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,25 @@ sudo mkdir -p $HOME
sudo chown $USER $HOME
sudo apt-get update
sudo apt-get install -y git python3-pip
sudo apt-get install -y cmake git make build-essential quilt debhelper bc python3 python3-pip sudo libssl-dev libgcc-10-dev
sudo apt-get install -y cmake git make build-essential quilt debhelper bc python3 python3-pip sudo libssl-dev libgcc-12-dev
sudo apt-get install -y clang
sudo apt-get install -y openssl libssl-dev libssl1.1
sudo apt-get install -y openssl libssl-dev libssl3
sudo apt-get install -y dh-exec dh-runit libaudit-dev libedit-dev libfido2-dev libgtk-3-dev libkrb5-dev
sudo apt-get install -y libwrap-dev pkg-config
sudo apt-get install -y libwrap0-dev pkg-config
sudo apt-get install -y libpam-dev libselinux1-dev libsystemd-dev libwrap0-dev

# Build Golang
sudo apt-get install -y golang

# Build Python
sudo apt-get install -y lsb-release sharutils libreadline-dev libncursesw5-dev libbz2-dev liblzma-dev libgdbm-dev libdb-dev tk-dev blt-dev libexpat1-dev libbluetooth-dev locales-all libsqlite3-dev media-types
sudo apt-get install -y time net-tools xvfb systemtap-sdt-dev python3-sphinx python3-docs-theme texinfo

# Build krb5
sudo apt-get install -y ss-dev libldap2-dev libc6-dev libkeyutils-dev byacc docbook-to-man libsasl2-dev libverto-dev python3-cheetah python3-lxml doxygen doxygen-latex tex-gyre

sudo pip3 install --break-system-packages blurb

[ -f src/SymCrypt/scripts/requirements.txt ] && sudo pip3 install -r src/SymCrypt/scripts/requirements.txt
if [ "$ARCH" == "armhf" ]; then
sudo apt-get install -y libc6-dev-armhf-cross
Expand Down
11 changes: 10 additions & 1 deletion .azure-pipelines/test-multiarch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,13 @@ popd

# Build the OpenSSL again with SymCrypt enabled
rm -f src/openssl/test/recipes/30-test_afalg.t
TARGET_PATH=target-test make openssl
if TARGET_PATH=target-test make openssl; then
echo "OpenSSL tests succeeded"
else
cat src/openssl.patch/skipped-openssl-tests.conf
TESTS=$(cat src/openssl.patch/skipped-openssl-tests.conf | sed 's/^/-/' | xargs)
pushd src/openssl/build_shared
make TESTS="$TESTS" test
popd
echo 0 | sudo tee /etc/fips/fips_enable
fi
9 changes: 7 additions & 2 deletions .azure-pipelines/test-template-armhf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ parameters:
default: armhf
- name: dist
type: string
default: bullseye
default: bookworm

jobs:
- template: build-template.yml
parameters:
pool: sonicbld-armhf
arch: armhf
image: sonicdev-microsoft.azurecr.io/sonic-slave-bullseye-armhf
image: sonicdev-microsoft.azurecr.io/sonic-slave-bookworm-armhf
artifactNamePrefix: test-symcrypt-
buildOthers: false
- job: QemuTest
Expand Down Expand Up @@ -59,7 +59,12 @@ jobs:
- script: |
set -ex
sudo chroot fsroot qemu-arm /root/symcryptunittest
condition: false
displayName: 'Run Symcrypt unit test'
- script: |
sleep 36000
condition: failed()
displayName: 'Waiting if failed'
- script: |
docker run --rm --privileged -t -v $(pwd):/work -w /work build-agent .azure-pipelines/test-multiarch.sh
displayName: 'Run build and test'
8 changes: 3 additions & 5 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@
[submodule "src/cpython"]
path = src/cpython
url = https://github.com/python/cpython
[submodule "src/golang"]
path = src/golang
url = https://pagure.io/go
branch = go1.15-openssl-fips
[submodule "src/golang-debian"]
path = src/golang-debian
url = https://salsa.debian.org/go-team/compiler/golang.git
branch = debian/1.15/bullseye
[submodule "src/openssl"]
path = src/openssl
url = https://salsa.debian.org/debian/openssl
[submodule "src/krb5"]
path = src/krb5
url = https://salsa.debian.org/debian/krb5
[submodule "src/golang-fips"]
path = src/golang-fips
url = https://github.com/golang-fips/go
6 changes: 5 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ stages:
- stage: build
jobs:
- template: .azure-pipelines/build-template.yml
parameters:
pool: sonicbld
- template: .azure-pipelines/build-template.yml
parameters:
pool: sonicbld-arm64
Expand All @@ -29,8 +31,10 @@ stages:
parameters:
pool: sonicbld-armhf
arch: armhf
image: sonicdev-microsoft.azurecr.io/sonic-slave-bullseye-armhf
image: sonicdev-microsoft.azurecr.io/sonic-slave-bookworm-armhf
- stage: test
variables:
CMAKE_BUILD_TYPE: Debug
dependsOn: []
jobs:
- template: .azure-pipelines/test-template-armhf.yml
7 changes: 4 additions & 3 deletions rules/golang.mk
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Python

GOLANG_MAIN_VERSION = 1.15
GOLANG_VERSOIN = 1.15.15-1~deb11u4
GOLANG_MAIN_VERSION = go1.19
GOLANGT_TAG = go1.19.8
GOLANG_VERSOIN = 1.19.8-2
GOLANG_VERSOIN_FIPS = $(GOLANG_VERSOIN)+fips
GOLANG = golang-$(GOLANG_MAIN_VERSION)_$(GOLANG_VERSOIN_FIPS)_all.deb
$(GOLANG)_SRC_PATH = $(SRC_PATH)/golang
$(GOLANG)_DEBIAN = $(SRC_PATH)/golang-debian/debian
$(GOLANG)_MAKEFILE = Makefile
$(GOLANG)_DEPENDS = $(SYMCRYPT_OPENSSL)

MAIN_TARGETS += $(GOLANG)
Expand Down
2 changes: 1 addition & 1 deletion rules/krb5.mk
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# krb5

KRB5_VERSION = 1.18.3-6+deb11u4
KRB5_VERSION = 1.20.1-2+deb12u1
KRB5_VERSION_FIPS = $(KRB5_VERSION)+fips
KRB5 = libk5crypto3_$(KRB5_VERSION_FIPS)_$(ARCH).deb
$(KRB5)_SRC_PATH = $(SRC_PATH)/krb5
Expand Down
6 changes: 3 additions & 3 deletions rules/openssh.mk
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# openssh

OPENSSH_VERSION = 8.4p1-5+deb11u2
OPENSSH_VERSION = 9.2p1-2+deb12u2
OPENSSH_VERSION_FIPS = $(OPENSSH_VERSION)+fips
OPENSSH_SERVER = openssh-server_$(OPENSSH_VERSION_FIPS)_$(ARCH).deb
$(OPENSSH_SERVER)_SRC_PATH = $(SRC_PATH)/openssh
$(OPENSSH_SERVER)_DEPENDS = $(SYMCRYPT_OPENSSL)
$(OPENSSH_SERVER)_BUILD_OPTIONS=LIBS="-lsymcryptengine -lsymcrypt -lcrypto -lssl -ledit" DEB_BUILD_PROFILES="noudeb" DEB_BUILD_OPTIONS="nocheck nostrip" DEB_CFLAGS_APPEND="-DUSE_SYMCRYPT_ENGINE"
$(OPENSSH_SERVER)_PRE_SCRIPT = sudo dpkg -i $(TARGET_PATH)/$(SYMCRYPT_OPENSSL);
#$(OPENSSH_SERVER)_BUILD_OPTIONS=LIBS="-lsymcryptengine -lsymcrypt -lcrypto -lssl -ledit" DEB_BUILD_PROFILES="noudeb" DEB_BUILD_OPTIONS="nocheck nostrip" DEB_CFLAGS_APPEND="-DUSE_SYMCRYPT_ENGINE"
#$(OPENSSH_SERVER)_PRE_SCRIPT = sudo dpkg -i $(TARGET_PATH)/$(SYMCRYPT_OPENSSL);

MAIN_TARGETS += $(OPENSSH_SERVER)
$(OPENSSH_SERVER)_DERIVED_DEBS = ssh_$(OPENSSH_VERSION_FIPS)_all.deb
Expand Down
6 changes: 3 additions & 3 deletions rules/openssl.mk
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# openssl

OPENSSL_VERSION = 1.1.1n-0+deb11u5
OPENSSL_VERSION = 3.0.11-1~deb12u2
OPENSSL_VERSION_FIPS = $(OPENSSL_VERSION)+fips
OPENSSL = openssl_$(OPENSSL_VERSION_FIPS)_$(ARCH).deb
$(OPENSSL)_SRC_PATH = $(SRC_PATH)/openssl

MAIN_TARGETS += $(OPENSSL)
$(OPENSSL)_DERIVED_DEBS = libssl1.1_$(OPENSSL_VERSION_FIPS)_$(ARCH).deb
$(OPENSSL)_DERIVED_DEBS = libssl3_$(OPENSSL_VERSION_FIPS)_$(ARCH).deb
$(OPENSSL)_DERIVED_DEBS += libssl-dev_$(OPENSSL_VERSION_FIPS)_$(ARCH).deb
$(OPENSSL)_DERIVED_DEBS += openssl-dbgsym_$(OPENSSL_VERSION_FIPS)_$(ARCH).deb
$(OPENSSL)_DERIVED_DEBS += libssl1.1-dbgsym_$(OPENSSL_VERSION_FIPS)_$(ARCH).deb
$(OPENSSL)_DERIVED_DEBS += libssl3-dbgsym_$(OPENSSL_VERSION_FIPS)_$(ARCH).deb
$(OPENSSL)_DERIVED_DEBS += libssl-doc_$(OPENSSL_VERSION_FIPS)_all.deb
4 changes: 2 additions & 2 deletions rules/python.mk
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Python

PYTHON_MAIN_VERSION = 3.9
PYTHON_VERSOIN = 3.9.2-1
PYTHON_MAIN_VERSION = 3.11
PYTHON_VERSOIN = 3.11.2-6
PYTHON_VERSOIN_FIPS = $(PYTHON_VERSOIN)+fips
PYTHON = python$(PYTHON_MAIN_VERSION)_$(PYTHON_VERSOIN_FIPS)_$(ARCH).deb
$(PYTHON)_SRC_PATH = $(SRC_PATH)/cpython
Expand Down
2 changes: 1 addition & 1 deletion rules/symcrypt-openssl.mk
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SYMCRYPT_OPENSSL

SYMCRYPT_OPENSSL_VERSION = 0.12
SYMCRYPT_OPENSSL_VERSION = 1.4.3-preview
SYMCRYPT_OPENSSL = symcrypt-openssl_$(SYMCRYPT_OPENSSL_VERSION)_$(ARCH).deb
$(SYMCRYPT_OPENSSL)_SRC_PATH = $(SRC_PATH)/SymCrypt-OpenSSL-Debian
$(SYMCRYPT_OPENSSL)_MAKEFILE = Makefile
Expand Down
2 changes: 1 addition & 1 deletion src/SymCrypt-OpenSSL
Submodule SymCrypt-OpenSSL updated 126 files
26 changes: 15 additions & 11 deletions src/SymCrypt-OpenSSL-Debian/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ LIB_INSTALL_NAME = x86_64-linux-gnu
ifeq ($(ARCH), arm64)
CMAKE_ARCH = ARM64
LIB_INSTALL_NAME = aarch64-linux-gnu
CMAKE_C_FLAGS = -mno-outline-atomics
else ifeq ($(ARCH), armhf)
CMAKE_ARCH = ARM
LIB_INSTALL_NAME = arm-linux-gnueabihf
Expand All @@ -25,16 +26,18 @@ endif
CMAKE_ARCH_LOWER = $(shell echo $(CMAKE_ARCH) | tr '[:upper:]' '[:lower:]')

INSTALL_PATH = $(BUILD_ROOT_DIR)/usr/lib/$(LIB_INSTALL_NAME)
ENGINES_PATH = $(INSTALL_PATH)/engines-1.1
ENGINES_PATH = $(INSTALL_PATH)/engines-3
PROVIDERS_PATH = $(INSTALL_PATH)/ossl-modules
DEBIAN_DIR = $(BUILD_ROOT_DIR)/DEBIAN

ROOT_PATH = $(shell realpath $(shell pwd)/../..)
DEST ?= $(ROOT_PATH)/target
LIBSYMCRYPT = $(DEST)/libsymcrypt.so
LIBSYMCRYPTENGINE = $(DEST)/libsymcryptengine.so
LIBSYMCRYPTPROVIDER = $(DEST)/symcryptprovider.so
TARGET = $(DEST)/$(SYMCRYPT_PACKAGE)

DEPENDS := $(LIBSYMCRYPT) $(LIBSYMCRYPTENGINE)
DEPENDS := $(LIBSYMCRYPT) $(LIBSYMCRYPTPROVIDER)

all: $(TARGET)

Expand All @@ -44,7 +47,7 @@ list:
$(LIBSYMCRYPT):
cd ../SymCrypt
if [ "$(ARCH)" == armhf ]; then
python3 scripts/build.py cmake --arch $(CMAKE_ARCH_LOWER) --config Release --toolchain cmake-configs/Toolchain-GCC-ARM.cmake bin
python3 scripts/build.py cmake --arch $(CMAKE_ARCH_LOWER) --config $(CMAKE_BUILD_TYPE) --toolchain cmake-configs/Toolchain-GCC-ARM.cmake bin
else
cmake -S . -B bin -DSYMCRYPT_TARGET_ARCH=$(CMAKE_ARCH) -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DCMAKE_C_FLAGS=$(CMAKE_C_FLAGS) -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build bin -j$(BUILD_JOBS)
Expand All @@ -55,27 +58,28 @@ $(LIBSYMCRYPT):
cp -a bin/module/generic/processing/libsymcrypt.so* $(DEST)/debug/
cp -r bin/exe $(DEST)/debug/

$(LIBSYMCRYPTENGINE): $(LIBSYMCRYPT)
$(LIBSYMCRYPTPROVIDER): $(LIBSYMCRYPT)
cd ../SymCrypt-OpenSSL
if [ "$(ARCH)" == armhf ] && [ ! -f cmake-toolchain/LinuxUserMode-ARM.cmake ]; then git cherry-pick 8ee9ee42c983b09dc2b9a1dbc4af1c75d92c7e83; fi
cp -P $(DEST)/libsymcrypt.so* ./
mkdir -p bin
cd bin
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake-toolchain/LinuxUserMode-$(CMAKE_ARCH).cmake -DSYMCRYPT_ROOT_DIR=$(ROOT_PATH)/src/SymCrypt -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
cmake --build .
rm ../libsymcrypt.so*
cp SymCryptEngine/dynamic/symcryptengine.so $(LIBSYMCRYPTENGINE)
cp -a SymCryptProvider/symcryptprovider.so $(LIBSYMCRYPTPROVIDER)
cp -a SymCryptEngine/dynamic/symcryptengine.so $(LIBSYMCRYPTENGINE)

$(TARGET): $(DEPENDS)
mkdir -p $(INSTALL_PATH)
mkdir -p $(ENGINES_PATH)
mkdir -p $(PROVIDERS_PATH)
mkdir -p $(DEBIAN_DIR)
mkdir -p $(BUILD_ROOT_DIR)/usr/lib/ssl
mkdir -p $(BUILD_ROOT_DIR)/etc/ssl
mkdir -p $(ENGINES_PATH)
cp -a $(DEST)/libsymcrypt.so* $(INSTALL_PATH)/
cp $(LIBSYMCRYPTENGINE) $(INSTALL_PATH)
cp $(LIBSYMCRYPTENGINE) $(INSTALL_PATH)/
cp -a $(LIBSYMCRYPTPROVIDER) $(PROVIDERS_PATH)/
ln -sf $(shell basename $(LIBSYMCRYPTENGINE)) $(INSTALL_PATH)/symcryptengine.so
ln -sf ../$(shell basename $(LIBSYMCRYPTENGINE)) $(ENGINES_PATH)/symcryptengine.so
chmod o+r $(INSTALL_PATH)/*
cp -rf debian/* $(DEBIAN_DIR)/
cp openssl.cnf $(BUILD_ROOT_DIR)/usr/lib/ssl/openssl-fips.cnf
chmod a+r -R $(INSTALL_PATH)/
fakeroot dpkg-deb --build $(BUILD_ROOT_DIR) $(TARGET)
4 changes: 2 additions & 2 deletions src/SymCrypt-OpenSSL-Debian/debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Version: 0.1
Section: devel
Priority: optional
Architecture: all
Depends:
Depends: openssl (>=3.0)
Maintainer: SONiC <sonic@microsoft.com>
Description: symcrypt openssl
Symcrypt Openssl Engine.
Symcrypt Openssl Provider and engine.
2 changes: 1 addition & 1 deletion src/cpython
Submodule cpython updated 2988 files
1 change: 0 additions & 1 deletion src/golang
Submodule golang deleted from 265c59
2 changes: 1 addition & 1 deletion src/golang-debian
Submodule golang-debian updated from 0745ef to 46bcb6
1 change: 1 addition & 0 deletions src/golang-fips
Submodule golang-fips added at c6b1ab
Loading

0 comments on commit 1012763

Please sign in to comment.