Skip to content

Commit dd7fd50

Browse files
Merge branch 'main' into add-ssl-security-callback
2 parents 1a21132 + 6f246af commit dd7fd50

32 files changed

Lines changed: 1371 additions & 432 deletions

.github/workflows/aws-lc-rs.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,11 @@ jobs:
310310
run: |
311311
set -ex
312312
# Wine binfmt allows the kernel to transparently run .exe files through
313-
# Wine. This is needed for the FIPS build, which runs fips_empty_main.exe
314-
# at build time to capture the integrity hash.
313+
# Wine. The FIPS build itself no longer needs Wine (inject_hash.go
314+
# patches the integrity hash directly into crypto.dll using the
315+
# linker map), but we still need Wine to run the FIPS sanity test
316+
# below, which loads the cross-built DLL so the .CRT$XCU initializer
317+
# can trigger the power-on self-test.
315318
#
316319
# Ubuntu 24.04's wine64 (9.0) does not properly execute .CRT$XCU
317320
# initializers in cross-compiled DLLs, which prevents the FIPS

CMakeLists.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,14 @@ if(GENERATE_RUST_BINDINGS)
217217
message(STATUS "Found bindgen-cli: ${BINDGEN_EXECUTABLE} (version ${BINDGEN_VERSION})")
218218
message(STATUS "Rust bindings target version: ${RUST_BINDINGS_TARGET_VERSION}")
219219

220-
# Check for rustfmt (required for --formatter rustfmt option)
220+
# Check for rustfmt (optional: used to format the generated bindings if available)
221221
find_program(RUSTFMT_EXECUTABLE NAMES rustfmt)
222-
if(NOT RUSTFMT_EXECUTABLE)
223-
message(FATAL_ERROR "GENERATE_RUST_BINDINGS requires rustfmt but it was not found. "
224-
"Install it with: rustup component add rustfmt")
222+
if(RUSTFMT_EXECUTABLE)
223+
message(STATUS "Found rustfmt: ${RUSTFMT_EXECUTABLE}")
224+
else()
225+
message(STATUS "rustfmt not found; generated Rust bindings will not be formatted. "
226+
"Install it with: rustup component add rustfmt")
225227
endif()
226-
message(STATUS "Found rustfmt: ${RUSTFMT_EXECUTABLE}")
227228
endif()
228229

229230
if(DISABLE_CPU_JITTER_ENTROPY)

cmake/rust_bindings.cmake

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,12 @@ function(generate_rust_bindings)
165165
"--with-derive-eq"
166166
"--generate" "functions,types,vars,methods,constructors,destructors"
167167
"--rust-target" "${RUST_BINDINGS_TARGET_VERSION}"
168-
"--formatter" "rustfmt"
169168
)
169+
# Use rustfmt as the formatter only if it was discovered. Otherwise fall back
170+
# to bindgen's default ("prettyplease") so the build doesn't require rustfmt.
171+
if(RUSTFMT_EXECUTABLE)
172+
list(APPEND _bindgen_args "--formatter" "rustfmt")
173+
endif()
170174
# Add symbol prefix if specified. See module-level comment for why we use
171175
# --prefix-link-name instead of including the prefix symbols header.
172176
if(ARG_PREFIX AND NOT ARG_PREFIX STREQUAL "")

crypto/CMakeLists.txt

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -638,34 +638,22 @@ if(FIPS_SHARED)
638638
# Rewrite libcrypto.so, libcrypto.dylib, or crypto.dll to inject the correct module
639639
# hash value. For now we support the FIPS build only on Linux, macOS, iOS, and Windows.
640640
if(MSVC)
641-
# On Windows we use capture_hash.go: build crypto.dll with a placeholder
642-
# hash, then run fips_empty_main.exe (which triggers the integrity check
643-
# and prints the correct hash), then patch the placeholder in crypto.dll.
644-
#
645-
# The fips_integrity target (marked ALL) ensures the hash injection runs
646-
# before 'install' copies crypto.dll. Without this, Cargo builds (which
647-
# run 'cmake --build --target install') would skip the hash injection
648-
# because fips_empty_main is not in crypto's dependency chain.
641+
# On Windows, inject_hash.go parses the linker map file and the PE to locate
642+
# module boundaries, computes the integrity hash, and patches it directly
643+
# into the DLL. This matches the Linux/Apple approach and does not require
644+
# running a binary, enabling cross-compilation without Wine.
645+
set(CRYPTO_MAP_FILE "${CMAKE_CURRENT_BINARY_DIR}/fips_crypto.map")
649646
build_libcrypto(NAME crypto MODULE_SOURCE $<TARGET_OBJECTS:fipsmodule> SET_OUTPUT_NAME)
650-
651-
add_executable(fips_empty_main fipsmodule/fips_empty_main.c)
652-
target_link_libraries(fips_empty_main PUBLIC crypto)
653-
target_add_awslc_include_paths(TARGET fips_empty_main SCOPE PRIVATE)
647+
target_link_options(crypto PRIVATE "/MAP:${CRYPTO_MAP_FILE}")
654648

655649
add_custom_command(
656-
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fips_hash_injected.stamp
650+
TARGET crypto POST_BUILD
657651
COMMAND ${GO_EXECUTABLE} run
658-
${AWSLC_SOURCE_DIR}/util/fipstools/capture_hash/capture_hash.go
659-
-in-executable $<TARGET_FILE:fips_empty_main>
660-
-patch-dll $<TARGET_FILE:crypto>
661-
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/fips_hash_injected.stamp
662-
DEPENDS fips_empty_main crypto
663-
${AWSLC_SOURCE_DIR}/util/fipstools/capture_hash/capture_hash.go
652+
${AWSLC_SOURCE_DIR}/util/fipstools/inject_hash/inject_hash.go
653+
-o $<TARGET_FILE:crypto> -in-object $<TARGET_FILE:crypto>
654+
-map ${CRYPTO_MAP_FILE} -windows
664655
WORKING_DIRECTORY ${AWSLC_SOURCE_DIR}
665656
)
666-
add_custom_target(fips_integrity ALL
667-
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/fips_hash_injected.stamp
668-
)
669657
else()
670658
# On Apple and Linux platforms inject_hash.go can parse libcrypto and inject
671659
# the hash directly into the final library.

crypto/bio/pair.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ static int bio_new(BIO *bio) {
4242
return 1;
4343
}
4444

45+
// bio_destroy_pair unlinks the two halves of a BIO pair. Concurrent calls to
46+
// BIO_free on both halves from separate threads are the caller's responsibility
47+
// to synchronize. As in OpenSSL, the BIO pair API does not provide internal
48+
// locking.
4549
static void bio_destroy_pair(BIO *bio) {
4650
struct bio_bio_st *b = bio->ptr;
4751
BIO *peer_bio;

crypto/fipsmodule/CMakeLists.txt

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -619,26 +619,30 @@ elseif(FIPS_SHARED)
619619
separate_arguments(FIPS_MARKER_C_FLAGS NATIVE_COMMAND "${CMAKE_C_FLAGS}")
620620
add_custom_command(
621621
OUTPUT fips_msvc_start.obj
622-
COMMAND ${CMAKE_C_COMPILER} ${FIPS_MARKER_C_FLAGS} -w /nologo /c /DAWSLC_FIPS_SHARED_START /Fo:fips_msvc_start.obj ${CMAKE_CURRENT_SOURCE_DIR}/fips_shared_library_marker.c
622+
COMMAND ${CMAKE_C_COMPILER} ${FIPS_MARKER_C_FLAGS} -w /nologo /c /DAWSLC_FIPS_SHARED_START /Fofips_msvc_start.obj ${CMAKE_CURRENT_SOURCE_DIR}/fips_shared_library_marker.c
623623
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/fips_shared_library_marker.c
624624
)
625625
add_custom_command(
626626
OUTPUT fips_msvc_end.obj
627-
COMMAND ${CMAKE_C_COMPILER} ${FIPS_MARKER_C_FLAGS} -w /nologo /c /DAWSLC_FIPS_SHARED_END /Fo:fips_msvc_end.obj ${CMAKE_CURRENT_SOURCE_DIR}/fips_shared_library_marker.c
627+
COMMAND ${CMAKE_C_COMPILER} ${FIPS_MARKER_C_FLAGS} -w /nologo /c /DAWSLC_FIPS_SHARED_END /Fofips_msvc_end.obj ${CMAKE_CURRENT_SOURCE_DIR}/fips_shared_library_marker.c
628628
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/fips_shared_library_marker.c
629629
)
630630
631-
if(CMAKE_AR)
632-
set(MSVC_LIB "${CMAKE_AR}")
633-
else()
634-
get_filename_component(MSVC_BIN ${CMAKE_LINKER} DIRECTORY)
635-
set(MSVC_LIB "${MSVC_BIN}/lib.exe")
631+
get_filename_component(MSVC_BIN ${CMAKE_LINKER} DIRECTORY)
632+
find_program(MSVC_LIB NAMES lib lib.exe llvm-lib llvm-lib.exe
633+
HINTS ${MSVC_BIN} NO_DEFAULT_PATH)
634+
if(NOT MSVC_LIB)
635+
find_program(MSVC_LIB NAMES lib lib.exe llvm-lib llvm-lib.exe)
636+
endif()
637+
if(NOT MSVC_LIB)
638+
message(FATAL_ERROR "Could not find lib.exe or llvm-lib for creating bcm.lib")
636639
endif()
637640
641+
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/bcm_objects.rsp"
642+
CONTENT "\"$<JOIN:$<TARGET_OBJECTS:bcm_library>,\"\n\">\"")
638643
add_custom_command(
639644
OUTPUT ${BCM_NAME}
640-
COMMAND ${MSVC_LIB} /nologo fips_msvc_start.obj $<TARGET_OBJECTS:bcm_library> fips_msvc_end.obj /OUT:${BCM_NAME}
641-
COMMAND_EXPAND_LISTS
645+
COMMAND ${MSVC_LIB} /nologo fips_msvc_start.obj @bcm_objects.rsp fips_msvc_end.obj /OUT:${BCM_NAME}
642646
DEPENDS fips_msvc_start.obj fips_msvc_end.obj bcm_library
643647
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
644648
)

crypto/fipsmodule/FIPS.md

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -173,20 +173,10 @@ The Shared Windows FIPS integrity test differs in two key ways:
173173
2. How the correct integrity hash is calculated
174174

175175
Microsoft Visual C compiler (MSVC) does not support linker scripts that add symbols to mark the start and end of the text and rodata sections, as is done on Linux. Instead, `fips_shared_library_marker.c` is compiled twice to generate two object files that contain start/end functions and variables. MSVC `pragma` segment definitions are used to place the markers in specific sections (e.g. `.fipstx$a`). This particular name format uses [Portable Executable Grouped Sections](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#grouped-sections-object-only) to control what section the code is placed in and the order within the section. With the start and end markers placed at `$a` and `$z` respectively, BCM puts everything in the `$b` section. When the final crypto.dll is built, all the code is in the `.fipstx` section, all data is in `.fipsda`, all constants are in `.fipsco`, all uninitialized items in `.fipsbs`, and everything is in the correct order.
176-
The process to generate the expected integrity fingerprint is also different from Linux. We use a single-DLL capture-and-patch approach: build `crypto.dll` once with a placeholder hash, run it to compute the real hash, then binary-patch the placeholder directly in the DLL. This avoids building two separate DLLs whose linker output may differ (e.g. mandatory ASLR on ARM64 causes different ADRP immediates, and `lld-link` used by clang-cl is not guaranteed to produce byte-identical output across two independent link operations).
177-
178-
1. Build the required object files once: `bcm.obj` from `bcm.c` and the start/end object files
179-
1. `bcm.obj` places the power-on self tests in the `.CRT$XCU` section which is run automatically by the Windows Common Runtime library (CRT) startup code
180-
2. Use MSVC's `lib.exe` (or `llvm-lib` for clang-cl) to combine the start/end object files with `bcm.obj` to create the static library `bcm.lib`.
181-
1. MSVC does not support combining multiple object files into another object file like the Apple build.
182-
3. Build `fipsmodule` which contains the placeholder integrity hash
183-
4. Build `crypto.dll` with `bcm.lib` and `fipsmodule`
184-
5. Build the small application `fips_empty_main.exe` and link it with `crypto.dll`
185-
6. `capture_hash.go` runs `fips_empty_main.exe`
186-
1. The CRT runs all functions in the `.CRT$XC*` sections in order starting with `.CRT$XCA`
187-
2. The BCM power-on tests are in `.CRT$XCU` and are run after all other Windows initialization is complete
188-
3. BCM calculates the correct integrity value which will not match the placeholder value. Before aborting the process the correct value is printed
189-
4. `capture_hash.go` reads the correct integrity value and binary-patches the 32-byte placeholder directly in `crypto.dll`
176+
The process to generate the expected integrity fingerprint follows the same approach as Linux and Apple, using `inject_hash.go` to patch the hash directly into the final binary:
177+
178+
1. Build `crypto.dll` from `bcm.c`, the start/end marker objects, and the rest of `fipsmodule`, using the `/MAP:` linker flag to produce a linker map file
179+
2. `inject_hash.go -windows` parses the linker map file and the PE to locate the FIPS module boundaries via the marker symbols, computes the integrity hash over the module text and rodata, and patches the correct value directly into `crypto.dll`
190180

191181
### Linux Static build
192182

crypto/fipsmodule/fips_empty_main.c

Lines changed: 0 additions & 20 deletions
This file was deleted.

crypto/x509/v3_ncons.c

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen,
3333
static int nc_dn(X509_NAME *sub, X509_NAME *nm);
3434
static int nc_dns(const ASN1_IA5STRING *sub, const ASN1_IA5STRING *dns,
3535
int excluding);
36-
static int nc_email(const ASN1_IA5STRING *sub, const ASN1_IA5STRING *eml);
36+
static int nc_email(const ASN1_IA5STRING *sub, const ASN1_IA5STRING *eml,
37+
int excluding);
3738
static int nc_uri(const ASN1_IA5STRING *uri, const ASN1_IA5STRING *base);
3839
static int nc_ip(const ASN1_OCTET_STRING *ip, const ASN1_OCTET_STRING *base);
3940

@@ -477,7 +478,7 @@ static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base,
477478
return nc_dns(gen->d.dNSName, base->d.dNSName, excluding);
478479

479480
case GEN_EMAIL:
480-
return nc_email(gen->d.rfc822Name, base->d.rfc822Name);
481+
return nc_email(gen->d.rfc822Name, base->d.rfc822Name, excluding);
481482

482483
case GEN_URI:
483484
return nc_uri(gen->d.uniformResourceIdentifier,
@@ -614,48 +615,120 @@ static int nc_dns(const ASN1_IA5STRING *dns, const ASN1_IA5STRING *base,
614615
return X509_V_OK;
615616
}
616617

617-
static int nc_email(const ASN1_IA5STRING *eml, const ASN1_IA5STRING *base) {
618+
// Returns 1 if |cbs| contains only characters valid in an RFC 5321 Sec.4.1.2
619+
// local-part atom (atext per RFC 5322 Sec.3.2.3). RFC 5322 allows quoted
620+
// local-parts which may contain '@' characters. Rather than parsing
621+
// quoted-strings, we reject local-parts containing non-atext characters.
622+
static int is_valid_rfc822_local_part(const CBS *cbs) {
623+
if (CBS_len(cbs) == 0) {
624+
return 0;
625+
}
626+
for (size_t i = 0; i < CBS_len(cbs); i++) {
627+
uint8_t c = CBS_data(cbs)[i];
628+
if (!(OPENSSL_isalnum(c) || c == '!' || c == '#' || c == '$' ||
629+
c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' ||
630+
c == '-' || c == '/' || c == '=' || c == '?' || c == '^' ||
631+
c == '_' || c == '`' || c == '{' || c == '|' || c == '}' ||
632+
c == '~' || c == '.')) {
633+
return 0;
634+
}
635+
}
636+
return 1;
637+
}
638+
639+
// Returns 1 if |cbs| contains only characters valid in a DNS domain label
640+
// per RFC 1034 Sec.3.5 (alphanumeric, hyphen, dot).
641+
static int is_valid_rfc822_domain(const CBS *cbs) {
642+
if (CBS_len(cbs) == 0) {
643+
return 0;
644+
}
645+
for (size_t i = 0; i < CBS_len(cbs); i++) {
646+
uint8_t c = CBS_data(cbs)[i];
647+
if (!(OPENSSL_isalnum(c) || c == '-' || c == '.')) {
648+
return 0;
649+
}
650+
}
651+
return 1;
652+
}
653+
654+
static int nc_email(const ASN1_IA5STRING *eml, const ASN1_IA5STRING *base,
655+
int excluding) {
618656
CBS eml_cbs, base_cbs;
619657
CBS_init(&eml_cbs, eml->data, eml->length);
620658
CBS_init(&base_cbs, base->data, base->length);
621659

622-
// TODO(davidben): In OpenSSL 1.1.1, this switched from the first '@' to the
623-
// last one. Match them here, or perhaps do an actual parse. Looks like
624-
// multiple '@'s may be allowed in quoted strings.
625-
CBS eml_local, base_local;
626-
if (!CBS_get_until_first(&eml_cbs, &eml_local, '@')) {
660+
CBS eml_local;
661+
if (!CBS_get_until_first(&eml_cbs, &eml_local, '@') ||
662+
!CBS_skip(&eml_cbs, 1)) {
663+
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
664+
}
665+
CBS eml_domain = eml_cbs;
666+
667+
// Reject subject emails with multiple '@'. This catches both
668+
// "a@b"@evil.example and a@b@evil.example.
669+
CBS unused;
670+
if (CBS_get_until_first(&eml_cbs, &unused, '@')) {
671+
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
672+
}
673+
674+
// Reject subject emails with characters outside RFC 5321 atext in the
675+
// local-part (rejects quoted local-parts like "user"@example.com) or
676+
// invalid domain characters.
677+
if (!is_valid_rfc822_local_part(&eml_local) ||
678+
!is_valid_rfc822_domain(&eml_domain)) {
627679
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
628680
}
681+
682+
CBS base_local;
629683
int base_has_at = CBS_get_until_first(&base_cbs, &base_local, '@');
630684

631-
// Special case: initial '.' is RHS match
632-
if (!base_has_at && starts_with(&base_cbs, '.')) {
633-
if (has_suffix_case(&eml_cbs, &base_cbs)) {
634-
return X509_V_OK;
685+
if (base_has_at) {
686+
// "@example.com" is not a valid constraint per RFC 5280 Sec.4.2.1.10.
687+
if (CBS_len(&base_local) == 0) {
688+
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
635689
}
636-
return X509_V_ERR_PERMITTED_VIOLATION;
690+
CBS_skip(&base_cbs, 1); // skip past '@'
691+
CBS base_domain = base_cbs;
692+
693+
// Reject constraints with multiple '@'.
694+
if (CBS_get_until_first(&base_cbs, &unused, '@')) {
695+
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
696+
}
697+
if (!is_valid_rfc822_local_part(&base_local) ||
698+
!is_valid_rfc822_domain(&base_domain)) {
699+
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
700+
}
701+
702+
// For excluded subtrees, compare the local-part case-insensitively.
703+
// RFC 5321 and RFC 5322 conflict on case sensitivity; for security we
704+
// err on being more strict when checking exclusions.
705+
int local_match = excluding
706+
? equal_case(&base_local, &eml_local)
707+
: CBS_mem_equal(&base_local, CBS_data(&eml_local),
708+
CBS_len(&eml_local));
709+
if (!local_match) {
710+
return X509_V_ERR_PERMITTED_VIOLATION;
711+
}
712+
if (!equal_case(&base_domain, &eml_domain)) {
713+
return X509_V_ERR_PERMITTED_VIOLATION;
714+
}
715+
return X509_V_OK;
637716
}
638717

639-
// If we have anything before '@' match local part
640-
if (base_has_at) {
641-
// TODO(davidben): This interprets a constraint of "@example.com" as
642-
// "example.com", which is not part of RFC5280.
643-
if (CBS_len(&base_local) > 0) {
644-
// Case sensitive match of local part
645-
if (!CBS_mem_equal(&base_local, CBS_data(&eml_local),
646-
CBS_len(&eml_local))) {
647-
return X509_V_ERR_PERMITTED_VIOLATION;
648-
}
718+
if (!is_valid_rfc822_domain(&base_cbs)) {
719+
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
720+
}
721+
722+
// Special case: initial '.' is RHS match
723+
if (starts_with(&base_cbs, '.')) {
724+
if (has_suffix_case(&eml_domain, &base_cbs)) {
725+
return X509_V_OK;
649726
}
650-
// Position base after '@'
651-
assert(starts_with(&base_cbs, '@'));
652-
CBS_skip(&base_cbs, 1);
727+
return X509_V_ERR_PERMITTED_VIOLATION;
653728
}
654729

655-
// Just have hostname left to match: case insensitive
656-
assert(starts_with(&eml_cbs, '@'));
657-
CBS_skip(&eml_cbs, 1);
658-
if (!equal_case(&base_cbs, &eml_cbs)) {
730+
// Domain-only constraint: case insensitive match
731+
if (!equal_case(&base_cbs, &eml_domain)) {
659732
return X509_V_ERR_PERMITTED_VIOLATION;
660733
}
661734

crypto/x509/x509_test.cc

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2773,16 +2773,34 @@ TEST(X509Test, NameConstraints) {
27732773
{GEN_EMAIL, "foo@example.com", "foo@EXAMPLE.COM", X509_V_OK,
27742774
X509_V_ERR_EXCLUDED_VIOLATION},
27752775
{GEN_EMAIL, "foo@example.com", "FOO@example.com",
2776-
X509_V_ERR_PERMITTED_VIOLATION, X509_V_OK},
2776+
X509_V_ERR_PERMITTED_VIOLATION, X509_V_ERR_EXCLUDED_VIOLATION},
27772777
{GEN_EMAIL, "foo@example.com", "bar@example.com",
27782778
X509_V_ERR_PERMITTED_VIOLATION, X509_V_OK},
2779-
// OpenSSL ignores a stray leading @.
2780-
{GEN_EMAIL, "foo@example.com", "@example.com", X509_V_OK,
2781-
X509_V_ERR_EXCLUDED_VIOLATION},
2782-
{GEN_EMAIL, "foo@example.com", "@EXAMPLE.COM", X509_V_OK,
2783-
X509_V_ERR_EXCLUDED_VIOLATION},
2779+
// "@example.com" is not a valid constraint per RFC 5280 Sec.4.2.1.10.
2780+
{GEN_EMAIL, "foo@example.com", "@example.com",
2781+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
2782+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
2783+
{GEN_EMAIL, "foo@example.com", "@EXAMPLE.COM",
2784+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
2785+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
27842786
{GEN_EMAIL, "foo@bar.example.com", "@example.com",
2785-
X509_V_ERR_PERMITTED_VIOLATION, X509_V_OK},
2787+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
2788+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
2789+
2790+
// Reject subject emails with quoted local-parts.
2791+
// A quoted local-part containing '@' would cause the parser to split
2792+
// at the wrong '@', bypassing name constraints.
2793+
{GEN_EMAIL, "\"a@b\"@evil.example", ".evil.example",
2794+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
2795+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
2796+
// Reject subject emails with multiple '@' signs.
2797+
{GEN_EMAIL, "a@b@evil.example", ".evil.example",
2798+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
2799+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
2800+
// Reject constraints with multiple '@' signs.
2801+
{GEN_EMAIL, "foo@example.com", "a@b@example.com",
2802+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
2803+
X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
27862804

27872805
// Basic syntax check.
27882806
{GEN_URI, "not-a-url", "not-a-url", X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,

0 commit comments

Comments
 (0)