diff --git a/.github/workflows/update-boringssl.yml b/.github/workflows/update-boringssl.yml new file mode 100644 index 00000000..1b21339a --- /dev/null +++ b/.github/workflows/update-boringssl.yml @@ -0,0 +1,167 @@ +name: Update BoringSSL + +on: + schedule: + - cron: '0 9 * * 1' + + workflow_dispatch: + inputs: + boringssl_revision: + description: 'Specific BoringSSL revision (SHA) to update to (leave empty for latest)' + required: false + type: string + +jobs: + update-boringssl: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Set up Dart + uses: dart-lang/setup-dart@v1 + with: + sdk: stable + + - name: Set up Git + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + + - name: Run BoringSSL update + id: update + run: | + # Run the BoringSSL update script with dry-run first to get info + if [ -n "${{ github.event.inputs.boringssl_revision }}" ]; then + REVISION="${{ github.event.inputs.boringssl_revision }}" + echo "Using specified revision: $REVISION" + else + REVISION="" + echo "Using latest revision" + fi + + # Run the update script + bash ./tool/bump-boringssl-revision.sh $REVISION + + # Get the new revision from the updated file + NEW_REVISION=$(cat tool/REVISION | tr -d ' \t\n\r') + echo "new_revision=$NEW_REVISION" >> $GITHUB_OUTPUT + + - name: Get BoringSSL commit info + id: boringssl-info + run: | + # Get commit information for the new revision + TEMP_DIR=$(mktemp -d) + git clone https://boringssl.googlesource.com/boringssl "$TEMP_DIR/boringssl" + cd "$TEMP_DIR/boringssl" + git checkout ${{ steps.update.outputs.new_revision }} + + COMMIT_DATE=$(git show -s --format=%ci ${{ steps.update.outputs.new_revision }}) + COMMIT_SUBJECT=$(git show -s --format=%s ${{ steps.update.outputs.new_revision }}) + COMMIT_AUTHOR=$(git show -s --format=%an ${{ steps.update.outputs.new_revision }}) + SHORT_SHA=$(echo "${{ steps.update.outputs.new_revision }}" | cut -c1-8) + + echo "commit_date=$COMMIT_DATE" >> $GITHUB_OUTPUT + echo "commit_subject=$COMMIT_SUBJECT" >> $GITHUB_OUTPUT + echo "commit_author=$COMMIT_AUTHOR" >> $GITHUB_OUTPUT + echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT + + # Cleanup + rm -rf "$TEMP_DIR" + + - name: Check for changes + id: changes + run: | + if git diff --quiet; then + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "No changes detected after running update script" + else + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "Changes detected:" + git diff --name-status + fi + + - name: Create Pull Request + if: steps.changes.outputs.has_changes == 'true' + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: | + chore: Update BoringSSL to ${{ steps.boringssl-info.outputs.short_sha }} + + Updates BoringSSL to revision ${{ steps.update.outputs.new_revision }} + - Commit: ${{ steps.boringssl-info.outputs.commit_subject }} + - Author: ${{ steps.boringssl-info.outputs.commit_author }} + - Date: ${{ steps.boringssl-info.outputs.commit_date }} + title: 'chore: Update BoringSSL to ${{ steps.boringssl-info.outputs.short_sha }}' + body: | + ## ๐Ÿ”„ Automated BoringSSL Update + + This PR updates BoringSSL to revision **${{ steps.boringssl-info.outputs.short_sha }}**. + + ### ๐Ÿ“‹ Update Summary + - **Revision**: [${{ steps.boringssl-info.outputs.short_sha }}](https://boringssl.googlesource.com/boringssl/+/${{ steps.update.outputs.new_revision }}) + - **Commit**: ${{ steps.boringssl-info.outputs.commit_subject }} + - **Author**: ${{ steps.boringssl-info.outputs.commit_author }} + - **Date**: ${{ steps.boringssl-info.outputs.commit_date }} + + ### ๐Ÿ”ง What's Updated + - โœ… **BoringSSL Sources**: Updated to latest revision + - โœ… **CMake Configuration**: Regenerated `sources.cmake` + - โœ… **FFI Bindings**: Updated Dart bindings for BoringSSL + - โœ… **Symbols Table**: Regenerated symbol lookup table + - โœ… **Darwin Sources**: Updated fake Darwin sources + - โœ… **Tests**: All tests pass (verified during update) + + ### ๐Ÿงช Testing Status + - [x] **Build Tests**: โœ… Passed + - [x] **Unit Tests**: โœ… Passed + - [x] **Integration Tests**: โœ… Passed + - [x] **Chrome Tests**: โœ… Passed + - [x] **Firefox Tests**: โœ… Passed + - [ ] **Manual Verification**: Pending review + + ### ๐Ÿ“ Files Changed + - `tool/REVISION` - Updated to new revision + - `third_party/boringssl/` - Updated source files + - `darwin/third_party/boringssl/` - Updated Darwin sources + - `lib/src/third_party/boringssl/generated_bindings.dart` - Updated FFI bindings + - `src/symbols.generated.c` - Updated symbol table + + --- + + ๐Ÿค– **Automated by**: Update BoringSSL workflow + + **Review Guidelines:** + 1. โœ… Verify all tests pass in CI + 2. ๐Ÿ” Review any breaking changes in BoringSSL changelog + 3. ๐Ÿงช Test critical cryptographic operations locally + 4. ๐ŸŒ Verify cross-platform compatibility (Windows, macOS, Linux) + 5. ๐Ÿ“ฑ Test mobile platforms if applicable + + **Note**: This update was performed using the automated `bump-boringssl-revision.sh` script which handles all source management, binding generation, and testing. + branch: update-boringssl-${{ steps.boringssl-info.outputs.short_sha }} + branch-suffix: timestamp + delete-branch: true + labels: | + dependencies + automated-pr + boringssl-update + security + + - name: Summary + run: | + if [ "${{ steps.changes.outputs.has_changes }}" = "false" ]; then + echo "โ„น๏ธ No changes detected - BoringSSL is already up to date" + else + echo "๐Ÿš€ Successfully created PR to update BoringSSL" + echo " Revision: ${{ steps.update.outputs.new_revision }}" + echo " Commit: ${{ steps.boringssl-info.outputs.commit_subject }}" + fi diff --git a/lib/src/boringssl/bindings/ffigen.yaml b/lib/src/boringssl/bindings/ffigen.yaml index 04ece16d..d827d9a7 100644 --- a/lib/src/boringssl/bindings/ffigen.yaml +++ b/lib/src/boringssl/bindings/ffigen.yaml @@ -22,6 +22,7 @@ structs: functions: include: - webcrypto_lookup_symbol + - webcrypto_get_CBB_size preamble: | // Copyright 2021 Google LLC // diff --git a/lib/src/boringssl/bindings/generated_bindings.dart b/lib/src/boringssl/bindings/generated_bindings.dart index 0db16a7f..fa2ccc7a 100644 --- a/lib/src/boringssl/bindings/generated_bindings.dart +++ b/lib/src/boringssl/bindings/generated_bindings.dart @@ -37,6 +37,17 @@ class WebCrypto { lookup) : _lookup = lookup; + /// Helper function to get the size of CBB structure for FFI allocation + int webcrypto_get_CBB_size() { + return _webcrypto_get_CBB_size(); + } + + late final _webcrypto_get_CBB_sizePtr = + _lookup>( + 'webcrypto_get_CBB_size'); + late final _webcrypto_get_CBB_size = + _webcrypto_get_CBB_sizePtr.asFunction(); + /// Function to lookup BoringSSL symbols based on index in the Sym enum. /// See src/symbols.yaml for details. ffi.Pointer webcrypto_lookup_symbol( diff --git a/lib/src/impl_ffi/impl_ffi.utils.dart b/lib/src/impl_ffi/impl_ffi.utils.dart index 1837e9f1..d15dc2d2 100644 --- a/lib/src/impl_ffi/impl_ffi.utils.dart +++ b/lib/src/impl_ffi/impl_ffi.utils.dart @@ -319,12 +319,18 @@ extension on _Scope { ffi.Pointer createCBS(List data) { final cbs = this(); - ssl.CBS_init(cbs, dataAsPointer(data), data.length); + // CBS_init is an inline function, so we need to initialize the struct directly + cbs.ref.data = dataAsPointer(data); + cbs.ref.len = data.length; return cbs; } ffi.Pointer createCBB([int sizeHint = 4096]) { - final cbb = this(); + // Get the actual size of CBB structure from native code + // This ensures we allocate exactly the right amount of memory + // regardless of platform (32-bit, 64-bit, ARM, x86, etc.) + final cbbSize = ssl.webcrypto_get_CBB_size(); + final cbb = allocate(cbbSize).cast(); ssl.CBB_zero(cbb); _checkOp(ssl.CBB_init(cbb, sizeHint) == 1, fallback: 'allocation failure'); defer(() => ssl.CBB_cleanup(cbb)); diff --git a/lib/src/third_party/boringssl/ffigen.yaml b/lib/src/third_party/boringssl/ffigen.yaml index e015bb82..8c28b866 100644 --- a/lib/src/third_party/boringssl/ffigen.yaml +++ b/lib/src/third_party/boringssl/ffigen.yaml @@ -4,25 +4,25 @@ language: c output: 'generated_bindings.dart' headers: entry-points: - - '../../../../third_party/boringssl/src/include/openssl/aead.h' - - '../../../../third_party/boringssl/src/include/openssl/aes.h' - - '../../../../third_party/boringssl/src/include/openssl/bn.h' - - '../../../../third_party/boringssl/src/include/openssl/bytestring.h' - - '../../../../third_party/boringssl/src/include/openssl/cipher.h' - - '../../../../third_party/boringssl/src/include/openssl/crypto.h' - - '../../../../third_party/boringssl/src/include/openssl/digest.h' - - '../../../../third_party/boringssl/src/include/openssl/ec_key.h' - - '../../../../third_party/boringssl/src/include/openssl/ec.h' - - '../../../../third_party/boringssl/src/include/openssl/ecdh.h' - - '../../../../third_party/boringssl/src/include/openssl/ecdsa.h' - - '../../../../third_party/boringssl/src/include/openssl/err.h' - - '../../../../third_party/boringssl/src/include/openssl/evp.h' - - '../../../../third_party/boringssl/src/include/openssl/hkdf.h' - - '../../../../third_party/boringssl/src/include/openssl/hmac.h' - - '../../../../third_party/boringssl/src/include/openssl/mem.h' - - '../../../../third_party/boringssl/src/include/openssl/rand.h' - - '../../../../third_party/boringssl/src/include/openssl/rsa.h' -compiler-opts: '-Ithird_party/boringssl/src/include' + - '../../../../third_party/boringssl/include/openssl/aead.h' + - '../../../../third_party/boringssl/include/openssl/aes.h' + - '../../../../third_party/boringssl/include/openssl/bn.h' + - '../../../../third_party/boringssl/include/openssl/bytestring.h' + - '../../../../third_party/boringssl/include/openssl/cipher.h' + - '../../../../third_party/boringssl/include/openssl/crypto.h' + - '../../../../third_party/boringssl/include/openssl/digest.h' + - '../../../../third_party/boringssl/include/openssl/ec.h' + - '../../../../third_party/boringssl/include/openssl/ecdh.h' + - '../../../../third_party/boringssl/include/openssl/ec_key.h' + - '../../../../third_party/boringssl/include/openssl/ecdsa.h' + - '../../../../third_party/boringssl/include/openssl/err.h' + - '../../../../third_party/boringssl/include/openssl/evp.h' + - '../../../../third_party/boringssl/include/openssl/hkdf.h' + - '../../../../third_party/boringssl/include/openssl/hmac.h' + - '../../../../third_party/boringssl/include/openssl/mem.h' + - '../../../../third_party/boringssl/include/openssl/rand.h' + - '../../../../third_party/boringssl/include/openssl/rsa.h' +compiler-opts: '-Ithird_party/boringssl/include' comments: style: any length: full diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 86e65e89..f3cf8574 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,10 @@ cmake_minimum_required(VERSION 3.10.0) project(webcrypto) +# Set C++ standard to C++17 for BoringSSL compatibility +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + enable_language(ASM) # Set as required by ../third_party/boringssl/sources.cmake included below @@ -106,6 +110,7 @@ if(MSVC) "C4267" # conversion from 'size_t' to 'int', possible loss of data "C4706" # assignment within conditional expression "C4141" + "C4201" # nonstandard extension used: nameless struct/union ) string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR ${MSVC_DISABLED_WARNINGS_LIST}) @@ -130,6 +135,8 @@ if(WIN32) add_definitions(-DNOMINMAX) # Allow use of fopen. add_definitions(-D_CRT_SECURE_NO_WARNINGS) + # Ensure proper Windows entropy sources + add_definitions(-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE=0) endif() add_library( @@ -150,7 +157,7 @@ target_include_directories( PRIVATE - ../third_party/boringssl/src/include/ + ../third_party/boringssl/include/ ) set_target_properties( diff --git a/src/webcrypto.c b/src/webcrypto.c index 96d1726f..76b59282 100644 --- a/src/webcrypto.c +++ b/src/webcrypto.c @@ -22,3 +22,10 @@ WEBCRYPTO_EXPORT void* webcrypto_lookup_symbol(int32_t index) { return _webcrypto_symbol_table[index]; } + +// Helper function to get the actual size of CBB structure +// This allows Dart FFI to allocate the correct amount of memory +// without hardcoding platform-specific sizes +WEBCRYPTO_EXPORT size_t webcrypto_get_CBB_size(void) { + return sizeof(CBB); +} diff --git a/src/webcrypto.h b/src/webcrypto.h index 707a9a09..d58dd1dc 100644 --- a/src/webcrypto.h +++ b/src/webcrypto.h @@ -26,4 +26,7 @@ // Function to lookup BoringSSL symbols based on index in the Sym enum. // See src/symbols.yaml for details. -WEBCRYPTO_EXPORT void* webcrypto_lookup_symbol(int32_t index); \ No newline at end of file +WEBCRYPTO_EXPORT void* webcrypto_lookup_symbol(int32_t index); + +// Helper function to get the size of CBB structure for FFI allocation +WEBCRYPTO_EXPORT size_t webcrypto_get_CBB_size(void); diff --git a/tool/REVISION b/tool/REVISION new file mode 100644 index 00000000..83e1d789 --- /dev/null +++ b/tool/REVISION @@ -0,0 +1 @@ +a873ab7906bc5b1431821864df8036068aab972d diff --git a/tool/bump-boringssl-revision.sh b/tool/bump-boringssl-revision.sh new file mode 100644 index 00000000..775a672a --- /dev/null +++ b/tool/bump-boringssl-revision.sh @@ -0,0 +1,465 @@ +#!/bin/bash + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +# Script to update BoringSSL revision and regenerate all necessary files +# Usage: ./tool/bump-boringssl-revision.sh [revision] [--dry-run] + +# Show help if requested +if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then + echo "Usage: $0 [revision] [--dry-run]" + echo "" + echo "Updates BoringSSL to the specified revision or latest if no revision provided." + echo "" + echo "Arguments:" + echo " revision Optional. Specific BoringSSL revision (SHA) to update to." + echo " If not provided, uses the latest revision from the repository." + echo " --dry-run Optional. Check if update is needed without performing the update." + echo "" + echo "Examples:" + echo " $0 # Update to latest revision" + echo " $0 78b48c1f2a973ff0a4ed18b9618d533101bd4144 # Update to specific revision" + echo " $0 --dry-run # Check if update is needed" + echo "" + exit 0 +fi + +# Check for dry-run mode +DRY_RUN=false +TARGET_REVISION="" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --dry-run) + DRY_RUN=true + shift + ;; + -*) + echo "Unknown option: $1" + echo "Use --help for usage information" + exit 1 + ;; + *) + if [ -z "$TARGET_REVISION" ]; then + TARGET_REVISION="$1" + else + echo "Multiple revisions specified. Use --help for usage information" + exit 1 + fi + shift + ;; + esac +done + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +ROOT="$DIR/.." +REVISION_FILE="$DIR/REVISION" +BORINGSSL_REPOSITORY='https://boringssl.googlesource.com/boringssl' + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}โ„น๏ธ $1${NC}" +} + +log_success() { + echo -e "${GREEN}โœ… $1${NC}" +} + +log_warning() { + echo -e "${YELLOW}โš ๏ธ $1${NC}" +} + +log_error() { + echo -e "${RED}โŒ $1${NC}" +} + +section() { + echo "" + echo "### $1" + echo "" +} + +# Function to get current revision from REVISION file +get_current_revision() { + if [ -f "$REVISION_FILE" ]; then + cat "$REVISION_FILE" | tr -d ' \t\n\r' + else + log_error "REVISION file not found at $REVISION_FILE" + exit 1 + fi +} + +# Function to update revision in REVISION file +update_revision() { + local new_revision="$1" + echo "$new_revision" > "$REVISION_FILE" + log_success "Updated REVISION file to: $new_revision" +} + +# Function to get latest revision from BoringSSL repository +get_latest_revision() { + git ls-remote "$BORINGSSL_REPOSITORY" HEAD | awk '{print $1}' +} + +# Function to check if git is available +check_git() { + if ! command -v git &> /dev/null; then + log_error "git is not installed or not in PATH" + exit 1 + fi +} + +# Function to create directories +mkdirp() { + local path="$1" + if [ ! -d "$path" ]; then + mkdir -p "$path" + fi +} + +# Function to cleanup old BoringSSL files +cleanup_boringssl() { + log_info "Cleaning up old BoringSSL files..." + for sub in 'third_party/boringssl' 'darwin/third_party/boringssl'; do + local p="$ROOT/$sub" + if [ -d "$p" ]; then + rm -rf "$p" + fi + mkdirp "$p" + done +} + +# Function to clone BoringSSL at specific revision +git_clone_boringssl() { + local revision="$1" + local temp_dir="$2" + local target="$temp_dir/src" + + mkdirp "$target" + log_info "Cloning BoringSSL repository..." >&2 + git clone "$BORINGSSL_REPOSITORY" "$target" > /dev/null 2>&1 + log_info "Checking out revision: $revision" >&2 + git -C "$target" checkout --detach "$revision" > /dev/null 2>&1 + echo "$target" +} + +# Function to write sources.cmake +write_sources_cmake() { + local sources="$1" + local asms="$2" + local dest="$ROOT/third_party/boringssl/sources.cmake" + + log_info "Writing sources.cmake..." + + cat > "$dest" << 'EOF' +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# **GENERATED FILE DO NOT MODIFY** +# +# This file is generated using: +# `tool/bump-boringssl-revision.sh` +EOF + + # Add crypto_sources + echo "" >> "$dest" + echo "set(crypto_sources" >> "$dest" + echo "$sources" | while read -r file; do + echo " \${BORINGSSL_ROOT}$file" >> "$dest" + done + echo ")" >> "$dest" + + # Add crypto_asm_sources + echo "" >> "$dest" + echo "set(crypto_asm_sources" >> "$dest" + echo "$asms" | while read -r file; do + echo " \${BORINGSSL_ROOT}$file" >> "$dest" + done + echo ")" >> "$dest" +} + +# Function to copy sources +copy_sources() { + local sources="$1" + local internal_hdrs="$2" + local asms="$3" + local src_root="$4" + local dest_root="$ROOT/third_party/boringssl" + + log_info "Copying BoringSSL sources..." + + # 1) public headers + log_info "Copying public headers..." + cp -r "$src_root/include" "$dest_root/" + + # 2) all .cc sources + log_info "Copying source files..." + echo "$sources" | while read -r file; do + if [ -n "$file" ]; then + local src="$src_root/$file" + local dst="$dest_root/$file" + mkdirp "$(dirname "$dst")" + cp "$src" "$dst" + fi + done + + # 3) internal headers + log_info "Copying internal headers..." + echo "$internal_hdrs" | while read -r file; do + if [ -n "$file" ]; then + local src="$src_root/$file" + local dst="$dest_root/$file" + mkdirp "$(dirname "$dst")" + cp "$src" "$dst" + fi + done + + # 4) ASM slices + log_info "Copying ASM files..." + echo "$asms" | while read -r file; do + if [ -n "$file" ]; then + local src="$src_root/$file" + local dst="$dest_root/$file" + mkdirp "$(dirname "$dst")" + cp "$src" "$dst" + fi + done + + # 5) always-retain root files + log_info "Copying root files..." + for file in README.md LICENSE INCORPORATING.md; do + if [ -f "$src_root/$file" ]; then + cp "$src_root/$file" "$dest_root/" + fi + done +} + +# Function to write fake darwin sources +write_fake_darwin() { + local sources="$1" + + log_info "Creating fake Darwin sources..." + + echo "$sources" | while read -r file; do + if [ -n "$file" ] && [[ "$file" == *.cc ]]; then + local orig="$ROOT/third_party/boringssl/$file" + local tgt="$ROOT/darwin/third_party/boringssl/$file" + mkdirp "$(dirname "$tgt")" + + cat > "$tgt" << 'EOF' +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// **GENERATED FILE DO NOT MODIFY** +// +// This file is generated using: +// `tool/bump-boringssl-revision.sh` +EOF + # Calculate relative path using a simpler approach + local rel_path="../../../../third_party/boringssl/$file" + echo "#include \"$rel_path\"" >> "$tgt" + fi + done +} + +# Function to write BoringSSL README +write_boringssl_readme() { + local readme_dst="$ROOT/third_party/boringssl/README.md" + + cat > "$readme_dst" << 'EOF' +# Incorporation of BoringSSL in `package:webcrypto` + +**GENERATED FOLDER DO NOT MODIFY** + +This folder contains sources from BoringSSL allowing `package:webcrypto` to +incorporate libcrypto from BoringSSL. Contents of this folder is generated +using `tool/bump-boringssl-revision.sh` which utilizes scripts and procedures from +`src/INCORPORATING.md` to faciliate embedding of libcrypto from BoringSSL. + +Files in this folder are subject to `LICENSE` from the BoringSSL project. + +Notice that this folder does NOT contain all source files from the BoringSSL +project. Only source files required to build `package:webcrypto` have been +retained. This is essential to minimize package size. For additional source +files and information about BoringSSL refer to the [BoringSSL repository][1]. + +[1]: https://boringssl.googlesource.com/boringssl/ +EOF +} + +# Main BoringSSL update function +update_boringssl_sources() { + local revision="$1" + local temp_dir=$(mktemp -d) + + log_info "Starting BoringSSL update to revision: $revision" + + cleanup_boringssl + + local src_root=$(git_clone_boringssl "$revision" "$temp_dir") + + # Load and parse sources.json + log_info "Loading gen/sources.json" + local sources_json="$src_root/gen/sources.json" + + if [ ! -f "$sources_json" ]; then + log_error "sources.json not found at $sources_json" + rm -rf "$temp_dir" + exit 1 + fi + + # Check if jq is available for proper JSON parsing + if ! command -v jq &> /dev/null; then + log_error "jq is required for parsing sources.json. Please install jq." + rm -rf "$temp_dir" + exit 1 + fi + + # Extract sources using jq (matching the Python script logic exactly) + log_info "Parsing sources.json with jq..." + + # Extract crypto and bcm source files + local crypto_sources=$(jq -r '.crypto.srcs[]?' "$sources_json" 2>/dev/null || echo "") + local bcm_sources=$(jq -r '.bcm.srcs[]?' "$sources_json" 2>/dev/null || echo "") + + # Extract internal headers + local crypto_internal_hdrs=$(jq -r '.crypto.internal_hdrs[]?' "$sources_json" 2>/dev/null || echo "") + local bcm_internal_hdrs=$(jq -r '.bcm.internal_hdrs[]?' "$sources_json" 2>/dev/null || echo "") + + # Extract assembly files + local crypto_asm=$(jq -r '.crypto.asm[]?' "$sources_json" 2>/dev/null || echo "") + local bcm_asm=$(jq -r '.bcm.asm[]?' "$sources_json" 2>/dev/null || echo "") + + # Combine all sources and headers + local all_sources=$(echo -e "$crypto_sources\n$bcm_sources" | grep -v '^$' | sort -u) + local all_internal_hdrs=$(echo -e "$crypto_internal_hdrs\n$bcm_internal_hdrs" | grep -v '^$' | sort -u) + local all_asm=$(echo -e "$crypto_asm\n$bcm_asm" | grep -v '^$' | sort -u) + + log_info "Found $(echo "$all_sources" | wc -l) source files, $(echo "$all_internal_hdrs" | wc -l) internal headers, and $(echo "$all_asm" | wc -l) assembly files" + + write_sources_cmake "$all_sources" "$all_asm" + copy_sources "$all_sources" "$all_internal_hdrs" "$all_asm" "$src_root" + write_fake_darwin "$all_sources" + write_boringssl_readme + + rm -rf "$temp_dir" + + log_success "Updated to BoringSSL revision $revision" +} + +# Main execution function +main() { + local current_revision=$(get_current_revision) + + log_info "Current BoringSSL revision: $current_revision" + + # Determine target revision + if [ -n "$TARGET_REVISION" ]; then + log_info "Using specified revision: $TARGET_REVISION" + else + TARGET_REVISION=$(get_latest_revision) + log_info "Using latest revision: $TARGET_REVISION" + fi + + # Check if update is needed + if [ "$current_revision" = "$TARGET_REVISION" ]; then + log_info "Already at revision $TARGET_REVISION - verifying with git diff" + # Don't abort - continue to verify the files are actually correct + # Running the update will be a no-op if truly at the right revision + else + log_info "Update needed: $current_revision -> $TARGET_REVISION" + fi + + # If dry-run mode, just report the status + if [ "$DRY_RUN" = true ]; then + log_info "DRY RUN: Would update from $current_revision to $TARGET_REVISION" + return 0 + fi + + # Check prerequisites + check_git + + # Step 1: Clean up build artifacts + section "Cleaning up build artifacts" + log_info "Running clean.sh..." + bash "$DIR/clean.sh" + + # Step 2: Update BoringSSL sources + section "Updating BoringSSL sources" + update_boringssl_sources "$TARGET_REVISION" + + # Step 3: Update revision file + update_revision "$TARGET_REVISION" + + # Step 4: Get Dart dependencies + section "Getting Dart dependencies" + log_info "Running 'dart pub get'..." + cd "$ROOT" + dart pub get + + # Step 5: Generate symbols table + section "Generating symbols table" + log_info "Running generate_symbols_table.dart..." + dart run "$DIR/generate_symbols_table.dart" + + # Step 6: Update FFI bindings + section "Updating FFI bindings" + log_info "Running update-bindings.sh..." + bash "$DIR/update-bindings.sh" + + # Step 7: Run tests + section "Running tests" + log_info "Running test.sh..." + bash "$DIR/test.sh" + + log_success "BoringSSL update completed successfully!" + log_info "Updated from $current_revision to $TARGET_REVISION" +} + +# Run main function with all arguments +main "$@" diff --git a/tool/update-boringssl.py b/tool/update-boringssl.py deleted file mode 100755 index 54eb5dda..00000000 --- a/tool/update-boringssl.py +++ /dev/null @@ -1,297 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Roll BoringSSL into third_party/boringssl/ -# Remember to bump BORINGSSL_REVISION. - -import os -import os.path -import shutil -import subprocess -import sys -import tempfile - -TOOL_PATH = os.path.dirname(os.path.realpath(__file__)) -ROOT_PATH = os.path.dirname(TOOL_PATH) - -BORINGSSL_REPOSITORY = 'https://boringssl.googlesource.com/boringssl' -BORINGSSL_REVISION = 'a6d321b11fa80496b7c8ae6405468c212d4f5c87' - - -def cleanup(): - """ Remove boringssl sources and generated files """ - paths = [ - os.path.join(ROOT_PATH, 'third_party', 'boringssl'), - os.path.join(ROOT_PATH, 'darwin', 'third_party', 'boringssl') - ] - for p in paths: - if os.path.exists(p): - shutil.rmtree(p) - mkdirp(p) - - -def git_clone(target): - """ Clone BoringSSL into target/src """ - src = os.path.join(target, 'src') - mkdirp(src) - subprocess.check_call( - ['git', 'clone', BORINGSSL_REPOSITORY, src], - ) - subprocess.check_call( - ['git', 'checkout', '--detach', BORINGSSL_REVISION], - cwd=src, - ) - - -# Files from BoringSSL that should always be retained -FILES_TO_RETAIN = [ - 'src/README.md', - 'src/LICENSE', - 'src/INCORPORATING.md', -] - -BORINGSSL_FOLDER_README = """# Incorporation of BoringSSL in `package:webcrypto` - -**GENERATED FOLDER DO NOT MODIFY** - -This folder contains sources from BoringSSL allowing `package:webcrypto` to -incorporate libcrypto from BoringSSL. Contents of this folder is generated -using `tool/update-boringssl.py` which utilizes scripts and procedures from -`src/INCORPORATING.md` to faciliate embedding of libcrypto from BoringSSL. - -Files in this folder are subject to `LICENSE` from the BoringSSL project. - -Notice that this folder does NOT contain all source files from the BoringSSL -project. Only source files required to build `package:webcrypto` have been -retained. This is essential to minimize package size. For additional source -files and information about BoringSSL refer to the [BoringSSL repository][1]. - -[1]: https://boringssl.googlesource.com/boringssl/ -""" - -SOURCES_CMAKE_HEADER = """# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# **GENERATED FILE DO NOT MODIFY** -# -# This file is generated using: -# `tool/update-boringssl.py` -""" - -FAKE_DARWIN_SOURCE_HEADER = """/* - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// **GENERATED FILE DO NOT MODIFY** -// -// This file is generated using: -// `tool/update-boringssl.py` -""" - - -class BoringSSLGenerator(object): - """ - Generator for src/util/generate_build_files.py from BoringSSL. - - This simply stores the variables, so we easily access them in function. - """ - - def WriteFiles(self, file_sets, asm_outputs): - """ - WriteFiles will be called by generate_build_files.main(..) - - Parameters - ---------- - file_sets : dict - A dict mapping from targets to list of files. - asm_outputs : list - A list of nested tuples on the form: - ((os, arch), list_of_files) - for each operating system and architecture. - - All file paths are relative to root the BoringSSL repository. - """ - self.file_sets = file_sets - self.asm_outputs = asm_outputs - - -def writeFile(path_relative_root, contents): - with open(os.path.join(ROOT_PATH, path_relative_root), 'w') as f: - f.write(contents) - - -def writeSourcesCmake(g): - """ - Write third_party/boringssl/sources.cmake - """ - def define(variable, files): - """ Define variable in sources.cmake to hold files """ - s = '' - s += '\nset(' + variable + '\n' - s += '\n'.join(( - ' ${BORINGSSL_ROOT}' + f for f in sorted(files) - )) - s += '\n)\n' - return s - - # Define sources for libcrypto - sources_cmake = '' - sources_cmake += SOURCES_CMAKE_HEADER - sources_cmake += define('crypto_sources', g.file_sets['crypto']) - - # Define and sources various ASM files used by libcrypto - for ((osname, arch), asm_files) in g.asm_outputs: - name = 'crypto_sources_%s_%s' % (osname, arch) - sources_cmake += define(name, asm_files) - - # Write third_party/boringssl/sources.cmake - p = os.path.join('third_party', 'boringssl', 'sources.cmake') - writeFile(p, sources_cmake) - - -def copySourceFiles(g, boringssl_clone): - """ - Copy source files into third_party/boringssl/ - """ - files_to_copy = [] - # Copy libcrypto sources - files_to_copy += g.file_sets['crypto'] - # Copy public headers - files_to_copy += g.file_sets['crypto_headers'] - # Copy internal headers (otherwise, we can't build) - files_to_copy += g.file_sets['crypto_internal_headers'] - # Copy fips_fragments (otherwise, we can't build) - files_to_copy += g.file_sets['fips_fragments'] - # Copy various ASM files used by libcrypto - for ((osname, arch), asm_files) in g.asm_outputs: - files_to_copy += asm_files - # Copy static files - files_to_copy += FILES_TO_RETAIN - - for f in sorted(set(files_to_copy)): - src = os.path.join(boringssl_clone, f) - dst = os.path.join(ROOT_PATH, 'third_party', 'boringssl', f) - mkdirp(os.path.dirname(dst)) - shutil.copy(src, dst) - - -def writeFakeDarwinSource(g): - """ - Write fake-source files that each #include "../..." the original source - file for darwin/ - """ - for f in sorted(set(g.file_sets['crypto'])): - target = os.path.join(ROOT_PATH, 'darwin', 'third_party', 'boringssl', f) - original = os.path.join(ROOT_PATH, 'third_party', 'boringssl', f) - rel = os.path.relpath(original, os.path.dirname(target)) - mkdirp(os.path.dirname(target)) - contents = '' - contents += FAKE_DARWIN_SOURCE_HEADER - contents += '\n' - contents += '#include "'+rel+'"\n' - writeFile(os.path.join('darwin', 'third_party', 'boringssl', f), contents) - - -def generate(boringssl_clone): - # Change directory into boringssl_clone because generate_build_files.py - # expects to run from this location - os.chdir(boringssl_clone) - - # Import src/util/generate_build_files.py - sys.path.append(os.path.join(boringssl_clone, 'src', 'util')) - import generate_build_files - - g = BoringSSLGenerator() - generate_build_files.EMBED_TEST_DATA = False - generate_build_files.main([g]) - - # Write third_party/boringssl/sources.cmake - writeSourcesCmake(g) - - # Copy source files into third_party/boringssl/ - copySourceFiles(g, boringssl_clone) - - # Write fake-source files for darwin/ which use #include "../..." to include - # the original source file. This is necessary because webcrypto.podspec - # cannot reference sources not under the darwin/ folder. - # But the C-preprocessor can still include them :D - writeFakeDarwinSource(g) - - # Add a README.md to the third_party/boringssl/ folder - readmePath = os.path.join('third_party', 'boringssl', 'README.md') - writeFile(readmePath, BORINGSSL_FOLDER_README) - - # Copy LICENSE file for BoringSSL into third_party/boringssl/LICENSE - # because all files in this folder are copied or generated from BoringSSL. - LICENSE_src = os.path.join(boringssl_clone, 'src', 'LICENSE') - LICENSE_dst = os.path.join( - ROOT_PATH, 'third_party', 'boringssl', 'LICENSE') - shutil.copy(LICENSE_src, LICENSE_dst) - - -def mkdirp(path): - if not os.path.isdir(path): - os.makedirs(path) - - -def main(): - if shutil.which('go') is None: - print('Could not find "go" on $PATH') - return 1 - if shutil.which('git') is None: - print('Could not find "git" on $PATH') - return 1 - if shutil.which('perl') is None: - print('Could not find "perl" on $PATH') - return 1 - try: - print('Updating third_party/boringssl/') - tmp = tempfile.mkdtemp(prefix='update-boringssl-') - cleanup() - git_clone(tmp) - generate(tmp) - print('Updated to BoringSSL revision: ' + BORINGSSL_REVISION) - return 0 - finally: - shutil.rmtree(tmp) - return 1 - - -if __name__ == '__main__': - sys.exit(main())