blob: 978238d41104fd6d8acbfa883d8b682f04a5210c [file] [edit]
// Copyright 2026 The BoringSSL Authors
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"bytes"
_ "embed"
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"boringssl.googlesource.com/boringssl.git/util/fipstools/fipscommon"
)
//go:embed testdata/test.o
var testObj []byte
//go:embed testdata/empty.o
var emptyObj []byte
func TestInjectHashTextAndROData(t *testing.T) {
tmpDir := t.TempDir()
inPath := filepath.Join(tmpDir, "input.o")
outPath := filepath.Join(tmpDir, "output.o")
if err := os.WriteFile(inPath, testObj, 0644); err != nil {
t.Fatalf("failed to write input file: %s", err)
}
if err := do(outPath, inPath, "", "", false); err != nil {
t.Fatalf("do() failed: %s", err)
}
outBytes, err := os.ReadFile(outPath)
if err != nil {
t.Fatalf("failed to read output file: %s", err)
}
if len(outBytes) != len(testObj) {
t.Fatalf("output length %d does not match input length %d", len(outBytes), len(testObj))
}
hashOffset := bytes.Index(testObj, fipscommon.UninitHashValue[:])
if hashOffset < 0 {
t.Fatalf("could not find uninit hash value in testObj")
}
// Verify all surrounding bytes before the hash are strictly unchanged.
if !bytes.Equal(outBytes[:hashOffset], testObj[:hashOffset]) {
t.Errorf("bytes before the hash value were modified")
}
// Verify all surrounding bytes after the hash are strictly unchanged.
if !bytes.Equal(outBytes[hashOffset+32:], testObj[hashOffset+32:]) {
t.Errorf("bytes after the hash value were modified")
}
// Verify the placeholder was overwritten with the expected hash.
const wantHash = "28369e972bef5e55f32607c72f3434d94b621e141f32f4d196c73183b15c9297"
gotHash := fmt.Sprintf("%x", outBytes[hashOffset:hashOffset+32])
if gotHash != wantHash {
t.Errorf("injected hash mismatch:\n got: %s\n want: %s", gotHash, wantHash)
}
}
func TestIgnoreMissing(t *testing.T) {
noHashObj := bytes.ReplaceAll(testObj, fipscommon.UninitHashValue[:], make([]byte, 32))
tests := []struct {
name string
inputBytes []byte
wantErr string
}{
{
name: "MissingSymbols",
inputBytes: emptyObj,
wantErr: "could not find .text module boundaries",
},
{
name: "MissingUninitHash",
inputBytes: noHashObj,
wantErr: "did not find uninitialised hash value",
},
{
name: "NonELFInput",
inputBytes: []byte("THIS_IS_A_TEXT_FILE_NOT_AN_ELF_OBJECT"),
wantErr: "failed to parse object",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tmpDir := t.TempDir()
inPath := filepath.Join(tmpDir, "input.o")
outPath := filepath.Join(tmpDir, "output.o")
if err := os.WriteFile(inPath, tc.inputBytes, 0644); err != nil {
t.Fatalf("failed to write input file: %s", err)
}
// Without ignoreMissing: must fail with expected error
err := do(outPath, inPath, "", "", false)
if err == nil || !strings.Contains(err.Error(), tc.wantErr) {
t.Errorf("expected error containing %q, got: %v", tc.wantErr, err)
}
// With ignoreMissing: must succeed and keep output byte-identical to input
if err := do(outPath, inPath, "", "", true); err != nil {
t.Fatalf("do(ignoreMissing=true) failed: %s", err)
}
outBytes, err := os.ReadFile(outPath)
if err != nil {
t.Fatalf("failed to read output file: %s", err)
}
if !bytes.Equal(outBytes, tc.inputBytes) {
t.Errorf("output was modified when ignoring missing symbols/hashes")
}
})
}
}