Skip to content

Commit 94b201d

Browse files
committed
Keep rolling
1 parent 5691f0f commit 94b201d

3 files changed

Lines changed: 108 additions & 284 deletions

File tree

crypto/CMakeLists.txt

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -630,31 +630,21 @@ if(FIPS_SHARED)
630630
# Rewrite libcrypto.so, libcrypto.dylib, or crypto.dll to inject the correct module
631631
# hash value. For now we support the FIPS build only on Linux, macOS, iOS, and Windows.
632632
if(MSVC)
633-
# On Windows we use capture_hash.go to capture the computed integrity value that bcm.o prints to generate the
634-
# correct value in generated_fips_shared_support.c. See FIPS.md for a full explanation of the process
635-
build_libcrypto(NAME precrypto MODULE_SOURCE $<TARGET_OBJECTS:fipsmodule>)
636-
add_executable(fips_empty_main fipsmodule/fips_empty_main.c)
637-
target_link_libraries(fips_empty_main PUBLIC precrypto)
638-
target_add_awslc_include_paths(TARGET fips_empty_main SCOPE PRIVATE)
639-
add_custom_command(OUTPUT generated_fips_shared_support.c
640-
COMMAND ${GO_EXECUTABLE} run
641-
${AWSLC_SOURCE_DIR}/util/fipstools/capture_hash/capture_hash.go
642-
-in-executable $<TARGET_FILE:fips_empty_main> > generated_fips_shared_support.c
643-
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
644-
DEPENDS fips_empty_main ${AWSLC_SOURCE_DIR}/util/fipstools/capture_hash/capture_hash.go
645-
)
646-
add_library(
647-
generated_fipsmodule
648-
649-
OBJECT
650-
651-
generated_fips_shared_support.c
652-
${AWSLC_SOURCE_DIR}/crypto/fipsmodule/cpucap/cpucap.c
653-
)
654-
target_compile_definitions(generated_fipsmodule PRIVATE BORINGSSL_IMPLEMENTATION S2N_BN_HIDE_SYMBOLS)
655-
target_add_awslc_include_paths(TARGET generated_fipsmodule SCOPE PRIVATE)
633+
# On Windows, inject_hash.go parses the PE DLL to find the .fipstx and
634+
# .fipsco sections, computes the integrity hash, and replaces the
635+
# placeholder value directly in the DLL file. This single-DLL approach
636+
# avoids the hash mismatch that occurs with the two-DLL capture_hash
637+
# method on ARM64 where mandatory ASLR causes the linker to resolve
638+
# COFF relocations to different addresses in precrypto.dll vs crypto.dll.
639+
build_libcrypto(NAME crypto MODULE_SOURCE $<TARGET_OBJECTS:fipsmodule> SET_OUTPUT_NAME)
656640

657-
build_libcrypto(NAME crypto MODULE_SOURCE $<TARGET_OBJECTS:generated_fipsmodule> SET_OUTPUT_NAME)
641+
add_custom_command(
642+
TARGET crypto POST_BUILD
643+
COMMAND ${GO_EXECUTABLE} run
644+
${AWSLC_SOURCE_DIR}/util/fipstools/inject_hash/inject_hash.go
645+
-o $<TARGET_FILE:crypto> -in-object $<TARGET_FILE:crypto>
646+
WORKING_DIRECTORY ${AWSLC_SOURCE_DIR}
647+
)
658648
else()
659649
# On Apple and Linux platforms inject_hash.go can parse libcrypto and inject
660650
# the hash directly into the final library.

crypto/fipsmodule/bcm.c

Lines changed: 3 additions & 259 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
#include <sys/mman.h>
2424
#include <unistd.h>
2525
#endif
26-
#if defined(BORINGSSL_FIPS) && defined(OPENSSL_WINDOWS)
27-
#include <windows.h>
28-
#endif
2926

3027
// On Windows place the bcm code in a specific section that uses Grouped Sections
3128
// to control the order. $b section will place bcm in between the start/end markers
@@ -299,93 +296,6 @@ static void BORINGSSL_bcm_power_on_self_test(void) {
299296
}
300297

301298
#if !defined(OPENSSL_ASAN)
302-
303-
#if defined(OPENSSL_WINDOWS) && defined(OPENSSL_AARCH64) && \
304-
defined(BORINGSSL_SHARED_LIBRARY)
305-
// On ARM64 Windows, ASLR is mandatory and cannot be disabled. The PE loader
306-
// applies base relocations to absolute address references within the .fipstx
307-
// and .fipsco sections, making the in-memory content dependent on the DLL's
308-
// load address. The FIPS build uses capture_hash.go to compute the integrity
309-
// hash from precrypto.dll loaded in one process, then embeds that hash in
310-
// crypto.dll which loads in a different process at a different ASLR address.
311-
// To make the hash deterministic we copy each FIPS section and reverse the
312-
// base relocations before hashing.
313-
//
314-
// |buf| is a copy of the section content, |buf_size| its length,
315-
// |section_rva| the section's RVA in the PE image, |delta| is
316-
// actual_base - preferred_base, and |reloc_table|/|reloc_table_size|
317-
// describe the PE base relocation directory. |out_count| receives the
318-
// number of fixups that were reversed.
319-
static void fips_undo_base_relocations(
320-
uint8_t *buf, size_t buf_size, uintptr_t section_rva, intptr_t delta,
321-
const uint8_t *reloc_table, size_t reloc_table_size,
322-
size_t *out_count) {
323-
const uint8_t *reloc_ptr = reloc_table;
324-
const uint8_t *reloc_end = reloc_table + reloc_table_size;
325-
size_t count_undone = 0;
326-
327-
while (reloc_ptr + sizeof(IMAGE_BASE_RELOCATION) <= reloc_end) {
328-
const IMAGE_BASE_RELOCATION *block = (const IMAGE_BASE_RELOCATION *)reloc_ptr;
329-
if (block->SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION) ||
330-
reloc_ptr + block->SizeOfBlock > reloc_end) {
331-
break;
332-
}
333-
334-
DWORD page_rva = block->VirtualAddress;
335-
DWORD count =
336-
(block->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
337-
const WORD *entries = (const WORD *)(reloc_ptr + sizeof(IMAGE_BASE_RELOCATION));
338-
339-
for (DWORD i = 0; i < count; i++) {
340-
int type = entries[i] >> 12;
341-
DWORD offset = entries[i] & 0xFFF;
342-
uintptr_t reloc_rva = (uintptr_t)page_rva + offset;
343-
344-
if (reloc_rva < section_rva ||
345-
reloc_rva >= section_rva + buf_size) {
346-
continue;
347-
}
348-
349-
size_t buf_offset = (size_t)(reloc_rva - section_rva);
350-
351-
switch (type) {
352-
case IMAGE_REL_BASED_ABSOLUTE:
353-
break;
354-
case IMAGE_REL_BASED_DIR64:
355-
if (buf_offset + sizeof(uint64_t) <= buf_size) {
356-
uint64_t val;
357-
memcpy(&val, buf + buf_offset, sizeof(val));
358-
val -= (uint64_t)delta;
359-
memcpy(buf + buf_offset, &val, sizeof(val));
360-
count_undone++;
361-
}
362-
break;
363-
case IMAGE_REL_BASED_HIGHLOW:
364-
if (buf_offset + sizeof(uint32_t) <= buf_size) {
365-
uint32_t val;
366-
memcpy(&val, buf + buf_offset, sizeof(val));
367-
val -= (uint32_t)delta;
368-
memcpy(buf + buf_offset, &val, sizeof(val));
369-
count_undone++;
370-
}
371-
break;
372-
default:
373-
fprintf(stderr, " RELOC: unhandled type %d at RVA 0x%llx\n",
374-
type, (unsigned long long)reloc_rva);
375-
count_undone++;
376-
break;
377-
}
378-
}
379-
380-
reloc_ptr += block->SizeOfBlock;
381-
}
382-
383-
if (out_count) {
384-
*out_count = count_undone;
385-
}
386-
}
387-
#endif // OPENSSL_WINDOWS && OPENSSL_AARCH64 && BORINGSSL_SHARED_LIBRARY
388-
389299
int BORINGSSL_integrity_test(void) {
390300
const uint8_t *const start = BORINGSSL_bcm_text_start;
391301
const uint8_t *const end = BORINGSSL_bcm_text_end;
@@ -423,42 +333,6 @@ int BORINGSSL_integrity_test(void) {
423333
assert_not_within(rodata_start, &OPENSSL_armcap_P, "OPENSSL_armcap_P", rodata_end);
424334
#endif
425335

426-
// Diagnostic output for FIPS integrity test debugging. This helps diagnose
427-
// issues where the hash captured from precrypto differs from the hash
428-
// computed at runtime from crypto (e.g. Windows ARM64 FIPS shared builds).
429-
// capture_hash.go uses pattern-based parsing, so extra output here is safe.
430-
#if defined(BORINGSSL_SHARED_LIBRARY)
431-
{
432-
const uint8_t *const hash_addr = BORINGSSL_bcm_text_hash;
433-
const int hash_in_rodata =
434-
(hash_addr >= rodata_start && hash_addr < rodata_end) ? 1 : 0;
435-
const int hash_in_text =
436-
(hash_addr >= start && hash_addr < end) ? 1 : 0;
437-
fprintf(stderr, "FIPS integrity diagnostics:\n");
438-
fprintf(stderr, " text: %p - %p (size: 0x%llx)\n",
439-
(const void *)start, (const void *)end,
440-
(unsigned long long)(end - start));
441-
fprintf(stderr, " rodata: %p - %p (size: 0x%llx)\n",
442-
(const void *)rodata_start, (const void *)rodata_end,
443-
(unsigned long long)(rodata_end - rodata_start));
444-
fprintf(stderr, " BORINGSSL_bcm_text_hash @ %p (in_rodata=%d, in_text=%d)\n",
445-
(const void *)hash_addr, hash_in_rodata, hash_in_text);
446-
fprintf(stderr, " text first 8 bytes: %02x%02x%02x%02x%02x%02x%02x%02x\n",
447-
start[0], start[1], start[2], start[3],
448-
start[4], start[5], start[6], start[7]);
449-
fprintf(stderr, " text last 8 bytes: %02x%02x%02x%02x%02x%02x%02x%02x\n",
450-
end[-8], end[-7], end[-6], end[-5],
451-
end[-4], end[-3], end[-2], end[-1]);
452-
fprintf(stderr, " rodata first 8 bytes: %02x%02x%02x%02x%02x%02x%02x%02x\n",
453-
rodata_start[0], rodata_start[1], rodata_start[2], rodata_start[3],
454-
rodata_start[4], rodata_start[5], rodata_start[6], rodata_start[7]);
455-
fprintf(stderr, " rodata last 8 bytes: %02x%02x%02x%02x%02x%02x%02x%02x\n",
456-
rodata_end[-8], rodata_end[-7], rodata_end[-6], rodata_end[-5],
457-
rodata_end[-4], rodata_end[-3], rodata_end[-2], rodata_end[-1]);
458-
fflush(stderr);
459-
}
460-
#endif
461-
462336
// Per FIPS 140-3 we have to perform the CAST of the HMAC used for integrity
463337
// check before the integrity check itself. So we first call
464338
// SHA-256 and HMAC-SHA256
@@ -485,145 +359,15 @@ int BORINGSSL_integrity_test(void) {
485359
#endif
486360
#if defined(BORINGSSL_SHARED_LIBRARY)
487361
uint64_t length = end - start;
488-
uint64_t rodata_length = rodata_end - rodata_start;
489362
uint8_t buffer[sizeof(length)];
490-
491-
#if defined(OPENSSL_WINDOWS) && defined(OPENSSL_AARCH64)
492-
// On ARM64 Windows, ASLR is mandatory. Undo PE base relocations in
493-
// temporary copies of the FIPS sections so the hash is load-address
494-
// independent. See the comment above fips_undo_base_relocations().
495-
//
496-
// IMPORTANT: The PE loader overwrites OptionalHeader.ImageBase in memory
497-
// with the actual load address, so reading it from the in-memory PE header
498-
// always gives delta==0. We must read the *original* ImageBase from the
499-
// DLL file on disk to obtain the true preferred base.
500-
uint8_t *text_copy = NULL;
501-
uint8_t *rodata_copy = NULL;
502-
const uint8_t *text_to_hash = start;
503-
const uint8_t *rodata_to_hash = rodata_start;
504-
505-
HMODULE fips_module = NULL;
506-
if (GetModuleHandleExW(
507-
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
508-
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
509-
(LPCWSTR)start, &fips_module)) {
510-
const uintptr_t actual_base = (uintptr_t)fips_module;
511-
512-
// Read the preferred ImageBase from the DLL file on disk.
513-
uintptr_t preferred_base = actual_base; // fallback: assume no relocation
514-
wchar_t dll_path[MAX_PATH];
515-
if (GetModuleFileNameW(fips_module, dll_path, MAX_PATH) != 0) {
516-
HANDLE hFile = CreateFileW(dll_path, GENERIC_READ, FILE_SHARE_READ,
517-
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
518-
NULL);
519-
if (hFile != INVALID_HANDLE_VALUE) {
520-
IMAGE_DOS_HEADER file_dos_header;
521-
DWORD bytes_read = 0;
522-
if (ReadFile(hFile, &file_dos_header, sizeof(file_dos_header),
523-
&bytes_read, NULL) &&
524-
bytes_read == sizeof(file_dos_header) &&
525-
file_dos_header.e_magic == IMAGE_DOS_SIGNATURE) {
526-
LARGE_INTEGER nt_offset;
527-
nt_offset.QuadPart = file_dos_header.e_lfanew;
528-
if (SetFilePointerEx(hFile, nt_offset, NULL, FILE_BEGIN)) {
529-
IMAGE_NT_HEADERS file_nt_headers;
530-
if (ReadFile(hFile, &file_nt_headers, sizeof(file_nt_headers),
531-
&bytes_read, NULL) &&
532-
bytes_read == sizeof(file_nt_headers) &&
533-
file_nt_headers.Signature == IMAGE_NT_SIGNATURE) {
534-
preferred_base =
535-
(uintptr_t)file_nt_headers.OptionalHeader.ImageBase;
536-
}
537-
}
538-
}
539-
CloseHandle(hFile);
540-
}
541-
}
542-
543-
const intptr_t delta = (intptr_t)(actual_base - preferred_base);
544-
const IMAGE_DOS_HEADER *dos_header =
545-
(const IMAGE_DOS_HEADER *)fips_module;
546-
const IMAGE_NT_HEADERS *nt_headers = (const IMAGE_NT_HEADERS *)(
547-
(const uint8_t *)fips_module + dos_header->e_lfanew);
548-
549-
fprintf(stderr, "FIPS reloc-undo: actual_base=%p preferred_base(file)=%p delta=0x%llx\n",
550-
(const void *)actual_base, (const void *)preferred_base,
551-
(unsigned long long)delta);
552-
553-
if (delta != 0) {
554-
const IMAGE_DATA_DIRECTORY *reloc_dir =
555-
&nt_headers->OptionalHeader
556-
.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
557-
fprintf(stderr, "FIPS reloc-undo: reloc_dir RVA=0x%lx Size=0x%lx\n",
558-
(unsigned long)reloc_dir->VirtualAddress,
559-
(unsigned long)reloc_dir->Size);
560-
if (reloc_dir->Size > 0) {
561-
const uint8_t *reloc_table =
562-
(const uint8_t *)fips_module + reloc_dir->VirtualAddress;
563-
564-
text_copy = malloc((size_t)length);
565-
rodata_copy = malloc((size_t)rodata_length);
566-
if (text_copy != NULL && rodata_copy != NULL) {
567-
memcpy(text_copy, start, (size_t)length);
568-
memcpy(rodata_copy, rodata_start, (size_t)rodata_length);
569-
570-
const uintptr_t text_rva = (uintptr_t)start - actual_base;
571-
const uintptr_t rodata_rva = (uintptr_t)rodata_start - actual_base;
572-
573-
size_t text_reloc_count = 0, rodata_reloc_count = 0;
574-
fips_undo_base_relocations(text_copy, (size_t)length, text_rva,
575-
delta, reloc_table, reloc_dir->Size,
576-
&text_reloc_count);
577-
fips_undo_base_relocations(rodata_copy, (size_t)rodata_length,
578-
rodata_rva, delta, reloc_table,
579-
reloc_dir->Size, &rodata_reloc_count);
580-
text_to_hash = text_copy;
581-
rodata_to_hash = rodata_copy;
582-
fprintf(stderr, "FIPS reloc-undo: undid %zu text + %zu rodata relocations\n",
583-
text_reloc_count, rodata_reloc_count);
584-
fprintf(stderr, "FIPS reloc-undo: text first 8 after undo: "
585-
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
586-
text_copy[0], text_copy[1], text_copy[2], text_copy[3],
587-
text_copy[4], text_copy[5], text_copy[6], text_copy[7]);
588-
fprintf(stderr, "FIPS reloc-undo: rodata first 8 after undo: "
589-
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
590-
rodata_copy[0], rodata_copy[1], rodata_copy[2], rodata_copy[3],
591-
rodata_copy[4], rodata_copy[5], rodata_copy[6], rodata_copy[7]);
592-
} else {
593-
fprintf(stderr, "FIPS reloc-undo: malloc failed\n");
594-
}
595-
}
596-
} else {
597-
fprintf(stderr, "FIPS reloc-undo: delta==0, hashing directly from memory\n");
598-
}
599-
} else {
600-
fprintf(stderr, "FIPS reloc-undo: GetModuleHandleExW failed (err=%lu)\n",
601-
GetLastError());
602-
}
603-
604-
fprintf(stderr, "FIPS reloc-undo: hashing from %s\n",
605-
(text_to_hash == start) ? "MEMORY (no undo)" : "UNRELOCATED COPY");
606-
fflush(stderr);
607-
608363
CRYPTO_store_u64_le(buffer, length);
609364
HMAC_Update(&hmac_ctx, buffer, sizeof(length));
610-
HMAC_Update(&hmac_ctx, text_to_hash, (size_t)length);
365+
HMAC_Update(&hmac_ctx, start, length);
611366

612-
CRYPTO_store_u64_le(buffer, rodata_length);
613-
HMAC_Update(&hmac_ctx, buffer, sizeof(length));
614-
HMAC_Update(&hmac_ctx, rodata_to_hash, (size_t)rodata_length);
615-
616-
free(text_copy);
617-
free(rodata_copy);
618-
#else
367+
length = rodata_end - rodata_start;
619368
CRYPTO_store_u64_le(buffer, length);
620369
HMAC_Update(&hmac_ctx, buffer, sizeof(length));
621-
HMAC_Update(&hmac_ctx, start, (size_t)length);
622-
623-
CRYPTO_store_u64_le(buffer, rodata_length);
624-
HMAC_Update(&hmac_ctx, buffer, sizeof(length));
625-
HMAC_Update(&hmac_ctx, rodata_start, (size_t)rodata_length);
626-
#endif // OPENSSL_WINDOWS && OPENSSL_AARCH64
370+
HMAC_Update(&hmac_ctx, rodata_start, length);
627371
#else
628372
HMAC_Update(&hmac_ctx, start, end - start);
629373
#endif

0 commit comments

Comments
 (0)