From 6e8c9598d925ab3001605150c2bc5edd6b135622 Mon Sep 17 00:00:00 2001 From: Robert Sloan Date: Mon, 3 Dec 2018 11:20:49 -0800 Subject: external/boringssl: Sync to 0f5ecd3a854546d943104e1f7421e489b7f4d5aa. This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/9113e0996fd445ce187ae9dfeabfc95805b947a2..0f5ecd3a854546d943104e1f7421e489b7f4d5aa Test: atest CtsLibcoreTestCases Change-Id: I819426d5e00485d972f3c17335f7c3ed7ac4e6ff --- src/CMakeLists.txt | 3 + src/crypto/CMakeLists.txt | 2 +- src/crypto/fipsmodule/aes/asm/aesni-x86.pl | 47 +++++---- src/crypto/fipsmodule/aes/internal.h | 2 +- src/crypto/perlasm/x86asm.pl | 17 ++- src/crypto/stack/stack_test.cc | 4 +- src/crypto/thread_win.c | 14 ++- src/crypto/x509/asn1_gen.c | 3 +- src/crypto/x509v3/internal.h | 51 +++++++++ src/crypto/x509v3/v3_akey.c | 7 +- src/crypto/x509v3/v3_alt.c | 23 ++-- src/crypto/x509v3/v3_conf.c | 3 +- src/crypto/x509v3/v3_cpols.c | 5 +- src/crypto/x509v3/v3_pci.c | 3 +- src/crypto/x509v3/v3_skey.c | 7 +- src/crypto/x509v3/v3_utl.c | 15 +-- src/include/openssl/x509v3.h | 4 - src/util/ar/ar.go | 8 +- src/util/ar/ar_test.go | 118 +++++++++++++++++++++ src/util/ar/testdata/linux/bar.cc.o | Bin 0 -> 1616 bytes src/util/ar/testdata/linux/foo.c.o | Bin 0 -> 1464 bytes src/util/ar/testdata/linux/libsample.a | Bin 0 -> 3328 bytes src/util/ar/testdata/mac/bar.cc.o | Bin 0 -> 860 bytes src/util/ar/testdata/mac/foo.c.o | Bin 0 -> 684 bytes src/util/ar/testdata/mac/libsample.a | Bin 0 -> 1864 bytes src/util/ar/testdata/sample/CMakeLists.txt | 3 + src/util/ar/testdata/sample/bar.cc | 15 +++ src/util/ar/testdata/sample/foo.c | 7 ++ src/util/ar/testdata/windows/bar.cc.obj | Bin 0 -> 3299 bytes src/util/ar/testdata/windows/foo.c.obj | Bin 0 -> 1910 bytes src/util/ar/testdata/windows/sample.lib | Bin 0 -> 5710 bytes src/util/make_prefix_headers.go | 18 +++- src/util/read_symbols.go | 162 ++++++++++++++++++++++------- 33 files changed, 437 insertions(+), 104 deletions(-) create mode 100644 src/crypto/x509v3/internal.h create mode 100644 src/util/ar/ar_test.go create mode 100644 src/util/ar/testdata/linux/bar.cc.o create mode 100644 src/util/ar/testdata/linux/foo.c.o create mode 100644 src/util/ar/testdata/linux/libsample.a create mode 100644 src/util/ar/testdata/mac/bar.cc.o create mode 100644 src/util/ar/testdata/mac/foo.c.o create mode 100644 src/util/ar/testdata/mac/libsample.a create mode 100644 src/util/ar/testdata/sample/CMakeLists.txt create mode 100644 src/util/ar/testdata/sample/bar.cc create mode 100644 src/util/ar/testdata/sample/foo.c create mode 100644 src/util/ar/testdata/windows/bar.cc.obj create mode 100644 src/util/ar/testdata/windows/foo.c.obj create mode 100644 src/util/ar/testdata/windows/sample.lib (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd2d9378..bfde5d58 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,9 @@ endif() if(BORINGSSL_PREFIX AND BORINGSSL_PREFIX_SYMBOLS) add_definitions(-DBORINGSSL_PREFIX=${BORINGSSL_PREFIX}) + # CMake automatically connects include_directories to the NASM command-line, + # but not add_definitions. + set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -DBORINGSSL_PREFIX=${BORINGSSL_PREFIX}") # Use "symbol_prefix_include" to store generated header files include_directories(${CMAKE_CURRENT_BINARY_DIR}/symbol_prefix_include) diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index ee9626a1..b1ca70e1 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -53,7 +53,7 @@ if(NOT OPENSSL_NO_ASM) set(PERLASM_STYLE win32n) set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2") endif() - set(CMAKE_ASM_NASM_FLAGS "-gcv8") + set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -gcv8") # On Windows, we use the NASM output, specifically built with Yasm. set(ASM_EXT asm) diff --git a/src/crypto/fipsmodule/aes/asm/aesni-x86.pl b/src/crypto/fipsmodule/aes/asm/aesni-x86.pl index cf1a51e0..aff2b408 100644 --- a/src/crypto/fipsmodule/aes/asm/aesni-x86.pl +++ b/src/crypto/fipsmodule/aes/asm/aesni-x86.pl @@ -67,9 +67,10 @@ # Goldmont 3.84/1.39 1.39 1.63 1.31 1.70 # Bulldozer 5.80/0.98 1.05 1.24 0.93 1.23 -$PREFIX="aesni"; # if $PREFIX is set to "AES", the script +$PREFIX="aes_hw"; # if $PREFIX is set to "AES", the script # generates drop-in replacement for # crypto/aes/asm/aes-586.pl:-) +$AESNI_PREFIX="aes_hw"; $inline=1; # inline _aesni_[en|de]crypt $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; @@ -85,7 +86,7 @@ open OUT,">$output"; &external_label("OPENSSL_ia32cap_P"); &static_label("key_const"); -if ($PREFIX eq "aesni") { $movekey=\&movups; } +if ($PREFIX eq $AESNI_PREFIX) { $movekey=\&movups; } else { $movekey=\&movups; } $len="eax"; @@ -414,21 +415,21 @@ sub aesni_generate6 &ret(); &function_end_B("_aesni_${p}rypt6"); } -&aesni_generate2("enc") if ($PREFIX eq "aesni"); +&aesni_generate2("enc") if ($PREFIX eq $AESNI_PREFIX); &aesni_generate2("dec"); -&aesni_generate3("enc") if ($PREFIX eq "aesni"); +&aesni_generate3("enc") if ($PREFIX eq $AESNI_PREFIX); &aesni_generate3("dec"); -&aesni_generate4("enc") if ($PREFIX eq "aesni"); +&aesni_generate4("enc") if ($PREFIX eq $AESNI_PREFIX); &aesni_generate4("dec"); -&aesni_generate6("enc") if ($PREFIX eq "aesni"); +&aesni_generate6("enc") if ($PREFIX eq $AESNI_PREFIX); &aesni_generate6("dec"); -if ($PREFIX eq "aesni") { +if ($PREFIX eq $AESNI_PREFIX) { ###################################################################### -# void aesni_ecb_encrypt (const void *in, void *out, +# void aes_hw_ecb_encrypt (const void *in, void *out, # size_t length, const AES_KEY *key, # int enc); -&function_begin("aesni_ecb_encrypt"); +&function_begin("${PREFIX}_ecb_encrypt"); &mov ($inp,&wparam(0)); &mov ($out,&wparam(1)); &mov ($len,&wparam(2)); @@ -647,10 +648,10 @@ if ($PREFIX eq "aesni") { &pxor ("xmm5","xmm5"); &pxor ("xmm6","xmm6"); &pxor ("xmm7","xmm7"); -&function_end("aesni_ecb_encrypt"); +&function_end("${PREFIX}_ecb_encrypt"); ###################################################################### -# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out, +# void aes_hw_ccm64_[en|de]crypt_blocks (const void *in, void *out, # size_t blocks, const AES_KEY *key, # const char *ivec,char *cmac); # @@ -659,7 +660,7 @@ if ($PREFIX eq "aesni") { # (see engine/eng_aesni.c for details) # { my $cmac=$inout1; -&function_begin("aesni_ccm64_encrypt_blocks"); +&function_begin("${PREFIX}_ccm64_encrypt_blocks"); &mov ($inp,&wparam(0)); &mov ($out,&wparam(1)); &mov ($len,&wparam(2)); @@ -745,9 +746,9 @@ if ($PREFIX eq "aesni") { &pxor ("xmm5","xmm5"); &pxor ("xmm6","xmm6"); &pxor ("xmm7","xmm7"); -&function_end("aesni_ccm64_encrypt_blocks"); +&function_end("${PREFIX}_ccm64_encrypt_blocks"); -&function_begin("aesni_ccm64_decrypt_blocks"); +&function_begin("${PREFIX}_ccm64_decrypt_blocks"); &mov ($inp,&wparam(0)); &mov ($out,&wparam(1)); &mov ($len,&wparam(2)); @@ -854,11 +855,11 @@ if ($PREFIX eq "aesni") { &pxor ("xmm5","xmm5"); &pxor ("xmm6","xmm6"); &pxor ("xmm7","xmm7"); -&function_end("aesni_ccm64_decrypt_blocks"); +&function_end("${PREFIX}_ccm64_decrypt_blocks"); } ###################################################################### -# void aesni_ctr32_encrypt_blocks (const void *in, void *out, +# void aes_hw_ctr32_encrypt_blocks (const void *in, void *out, # size_t blocks, const AES_KEY *key, # const char *ivec); # @@ -873,7 +874,7 @@ if ($PREFIX eq "aesni") { # 64 2nd triplet of counter vector # 80 saved %esp -&function_begin("aesni_ctr32_encrypt_blocks"); +&function_begin("${PREFIX}_ctr32_encrypt_blocks"); &mov ($inp,&wparam(0)); &mov ($out,&wparam(1)); &mov ($len,&wparam(2)); @@ -1115,16 +1116,16 @@ if ($PREFIX eq "aesni") { &movdqa (&QWP(64,"esp"),"xmm0"); &pxor ("xmm7","xmm7"); &mov ("esp",&DWP(80,"esp")); -&function_end("aesni_ctr32_encrypt_blocks"); +&function_end("${PREFIX}_ctr32_encrypt_blocks"); ###################################################################### -# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# void aes_hw_xts_[en|de]crypt(const char *inp,char *out,size_t len, # const AES_KEY *key1, const AES_KEY *key2 # const unsigned char iv[16]); # { my ($tweak,$twtmp,$twres,$twmask)=($rndkey1,$rndkey0,$inout0,$inout1); -&function_begin("aesni_xts_encrypt"); +&function_begin("${PREFIX}_xts_encrypt"); &mov ($key,&wparam(4)); # key2 &mov ($inp,&wparam(5)); # clear-text tweak @@ -1470,9 +1471,9 @@ if ($PREFIX eq "aesni") { &pxor ("xmm7","xmm7"); &movdqa (&QWP(16*5,"esp"),"xmm0"); &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp -&function_end("aesni_xts_encrypt"); +&function_end("${PREFIX}_xts_encrypt"); -&function_begin("aesni_xts_decrypt"); +&function_begin("${PREFIX}_xts_decrypt"); &mov ($key,&wparam(4)); # key2 &mov ($inp,&wparam(5)); # clear-text tweak @@ -1846,7 +1847,7 @@ if ($PREFIX eq "aesni") { &pxor ("xmm7","xmm7"); &movdqa (&QWP(16*5,"esp"),"xmm0"); &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp -&function_end("aesni_xts_decrypt"); +&function_end("${PREFIX}_xts_decrypt"); } } diff --git a/src/crypto/fipsmodule/aes/internal.h b/src/crypto/fipsmodule/aes/internal.h index 7c19b9c5..a9f8a8c7 100644 --- a/src/crypto/fipsmodule/aes/internal.h +++ b/src/crypto/fipsmodule/aes/internal.h @@ -26,7 +26,7 @@ extern "C" { #if !defined(OPENSSL_NO_ASM) -#if defined(OPENSSL_X86_64) +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) #define HWAES #define HWAES_ECB diff --git a/src/crypto/perlasm/x86asm.pl b/src/crypto/perlasm/x86asm.pl index c9f645e0..3d2943bc 100644 --- a/src/crypto/perlasm/x86asm.pl +++ b/src/crypto/perlasm/x86asm.pl @@ -262,7 +262,20 @@ $comment This file is generated from a similarly-named Perl script in the Boring $comment source tree. Do not edit by hand. ___ - print "#if defined(__i386__)\n" unless ($win32 || $netware); + if ($win32 || $netware) { + print <<___ unless $masm; +%ifdef BORINGSSL_PREFIX +%include "boringssl_prefix_symbols_nasm.inc" +%endif +___ + } else { + print <<___; +#if defined(__i386__) +#if defined(BORINGSSL_PREFIX) +#include +#endif +___ + } print @out; print "#endif\n" unless ($win32 || $netware); } @@ -288,7 +301,7 @@ sub ::asm_init #elsif (($type eq "nw-mwasm")) #{ $netware=1; $mwerks=1; require "x86nasm.pl"; } elsif (($type eq "win32")) - { $win32=1; require "x86masm.pl"; } + { $win32=1; $masm=1; require "x86masm.pl"; } elsif (($type eq "macosx")) { $aout=1; $macosx=1; require "x86gas.pl"; } elsif (($type eq "android")) diff --git a/src/crypto/stack/stack_test.cc b/src/crypto/stack/stack_test.cc index 8b269719..7be84ed0 100644 --- a/src/crypto/stack/stack_test.cc +++ b/src/crypto/stack/stack_test.cc @@ -31,9 +31,9 @@ using TEST_INT = int; static void TEST_INT_free(TEST_INT *x) { OPENSSL_free(x); } -namespace bssl { +BSSL_NAMESPACE_BEGIN BORINGSSL_MAKE_DELETER(TEST_INT, TEST_INT_free) -} // namespace bssl +BSSL_NAMESPACE_END static bssl::UniquePtr TEST_INT_new(int x) { bssl::UniquePtr ret( diff --git a/src/crypto/thread_win.c b/src/crypto/thread_win.c index 8b2b2da5..45011650 100644 --- a/src/crypto/thread_win.c +++ b/src/crypto/thread_win.c @@ -146,12 +146,18 @@ static void NTAPI thread_local_destructor(PVOID module, DWORD reason, // if it's not already there. (E.g. if __declspec(thread) is not used). Force // a reference to p_thread_callback_boringssl to prevent whole program // optimization from discarding the variable. +// +// Note, in the prefixed build, |p_thread_callback_boringssl| may be a macro. +#define STRINGIFY(x) #x +#define EXPAND_AND_STRINGIFY(x) STRINGIFY(x) #ifdef _WIN64 -#pragma comment(linker, "/INCLUDE:_tls_used") -#pragma comment(linker, "/INCLUDE:p_thread_callback_boringssl") +__pragma(comment(linker, "/INCLUDE:_tls_used")) +__pragma(comment( + linker, "/INCLUDE:" EXPAND_AND_STRINGIFY(p_thread_callback_boringssl))) #else -#pragma comment(linker, "/INCLUDE:__tls_used") -#pragma comment(linker, "/INCLUDE:_p_thread_callback_boringssl") +__pragma(comment(linker, "/INCLUDE:__tls_used")) +__pragma(comment( + linker, "/INCLUDE:_" EXPAND_AND_STRINGIFY(p_thread_callback_boringssl))) #endif // .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are diff --git a/src/crypto/x509/asn1_gen.c b/src/crypto/x509/asn1_gen.c index 5b74cd1e..98a6facd 100644 --- a/src/crypto/x509/asn1_gen.c +++ b/src/crypto/x509/asn1_gen.c @@ -65,6 +65,7 @@ #include #include "../internal.h" +#include "../x509v3/internal.h" /* * Although this file is in crypto/x509 for layering purposes, it emits @@ -769,7 +770,7 @@ static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype) if (format == ASN1_GEN_FORMAT_HEX) { - if (!(rdata = string_to_hex((char *)str, &rdlen))) { + if (!(rdata = x509v3_hex_to_bytes((char *)str, &rdlen))) { OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_HEX); goto bad_str; } diff --git a/src/crypto/x509v3/internal.h b/src/crypto/x509v3/internal.h new file mode 100644 index 00000000..e6be6841 --- /dev/null +++ b/src/crypto/x509v3/internal.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2018, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_X509V3_INTERNAL_H +#define OPENSSL_HEADER_X509V3_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +// x509v3_bytes_to_hex encodes |len| bytes from |buffer| to hex and returns a +// newly-allocated NUL-terminated string containing the result, or NULL on +// allocation error. +// +// Note this function was historically named |hex_to_string| in OpenSSL, not +// |string_to_hex|. +char *x509v3_bytes_to_hex(const unsigned char *buffer, long len); + +// x509v3_hex_string_to_bytes decodes |str| in hex and returns a newly-allocated +// array containing the result, or NULL on error. On success, it sets |*len| to +// the length of the result. Colon separators between bytes in the input are +// allowed and ignored. +// +// Note this function was historically named |string_to_hex| in OpenSSL, not +// |hex_to_string|. +unsigned char *x509v3_hex_to_bytes(const char *str, long *len); + +// x509v3_name_cmp returns zero if |name| is equal to |cmp| or begins with |cmp| +// followed by '.'. Otherwise, it returns a non-zero number. +int x509v3_name_cmp(const char *name, const char *cmp); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_X509V3_INTERNAL_H */ diff --git a/src/crypto/x509v3/v3_akey.c b/src/crypto/x509v3/v3_akey.c index 4503e615..30c02e2c 100644 --- a/src/crypto/x509v3/v3_akey.c +++ b/src/crypto/x509v3/v3_akey.c @@ -66,6 +66,9 @@ #include #include +#include "internal.h" + + static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) @@ -92,14 +95,14 @@ static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, { char *tmp; if (akeyid->keyid) { - tmp = hex_to_string(akeyid->keyid->data, akeyid->keyid->length); + tmp = x509v3_bytes_to_hex(akeyid->keyid->data, akeyid->keyid->length); X509V3_add_value("keyid", tmp, &extlist); OPENSSL_free(tmp); } if (akeyid->issuer) extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist); if (akeyid->serial) { - tmp = hex_to_string(akeyid->serial->data, akeyid->serial->length); + tmp = x509v3_bytes_to_hex(akeyid->serial->data, akeyid->serial->length); X509V3_add_value("serial", tmp, &extlist); OPENSSL_free(tmp); } diff --git a/src/crypto/x509v3/v3_alt.c b/src/crypto/x509v3/v3_alt.c index b78a4105..5a4fadf9 100644 --- a/src/crypto/x509v3/v3_alt.c +++ b/src/crypto/x509v3/v3_alt.c @@ -64,6 +64,9 @@ #include #include +#include "internal.h" + + static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); @@ -261,7 +264,7 @@ static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, } for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { cnf = sk_CONF_VALUE_value(nval, i); - if (!name_cmp(cnf->name, "issuer") && cnf->value && + if (!x509v3_name_cmp(cnf->name, "issuer") && cnf->value && !strcmp(cnf->value, "copy")) { if (!copy_issuer(ctx, gens)) goto err; @@ -331,11 +334,11 @@ static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, } for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { cnf = sk_CONF_VALUE_value(nval, i); - if (!name_cmp(cnf->name, "email") && cnf->value && + if (!x509v3_name_cmp(cnf->name, "email") && cnf->value && !strcmp(cnf->value, "copy")) { if (!copy_email(ctx, gens, 0)) goto err; - } else if (!name_cmp(cnf->name, "email") && cnf->value && + } else if (!x509v3_name_cmp(cnf->name, "email") && cnf->value && !strcmp(cnf->value, "move")) { if (!copy_email(ctx, gens, 1)) goto err; @@ -545,19 +548,19 @@ GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, return NULL; } - if (!name_cmp(name, "email")) + if (!x509v3_name_cmp(name, "email")) type = GEN_EMAIL; - else if (!name_cmp(name, "URI")) + else if (!x509v3_name_cmp(name, "URI")) type = GEN_URI; - else if (!name_cmp(name, "DNS")) + else if (!x509v3_name_cmp(name, "DNS")) type = GEN_DNS; - else if (!name_cmp(name, "RID")) + else if (!x509v3_name_cmp(name, "RID")) type = GEN_RID; - else if (!name_cmp(name, "IP")) + else if (!x509v3_name_cmp(name, "IP")) type = GEN_IPADD; - else if (!name_cmp(name, "dirName")) + else if (!x509v3_name_cmp(name, "dirName")) type = GEN_DIRNAME; - else if (!name_cmp(name, "otherName")) + else if (!x509v3_name_cmp(name, "otherName")) type = GEN_OTHERNAME; else { OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_OPTION); diff --git a/src/crypto/x509v3/v3_conf.c b/src/crypto/x509v3/v3_conf.c index ff2eae14..e98d0fcd 100644 --- a/src/crypto/x509v3/v3_conf.c +++ b/src/crypto/x509v3/v3_conf.c @@ -69,6 +69,7 @@ #include #include "../internal.h" +#include "internal.h" static int v3_check_critical(char **value); static int v3_check_generic(char **value); @@ -278,7 +279,7 @@ static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, } if (gen_type == 1) - ext_der = string_to_hex(value, &ext_len); + ext_der = x509v3_hex_to_bytes(value, &ext_len); else if (gen_type == 2) ext_der = generic_asn1(value, ctx, &ext_len); diff --git a/src/crypto/x509v3/v3_cpols.c b/src/crypto/x509v3/v3_cpols.c index 4def530a..18d260b5 100644 --- a/src/crypto/x509v3/v3_cpols.c +++ b/src/crypto/x509v3/v3_cpols.c @@ -69,6 +69,7 @@ #include #include +#include "internal.h" #include "pcy_int.h" /* Certificate policies extension support: this one is a bit complex... */ @@ -231,7 +232,7 @@ static POLICYINFO *policy_section(X509V3_CTX *ctx, } pol->policyid = pobj; - } else if (!name_cmp(cnf->name, "CPS")) { + } else if (!x509v3_name_cmp(cnf->name, "CPS")) { if (!pol->qualifiers) pol->qualifiers = sk_POLICYQUALINFO_new_null(); if (!(qual = POLICYQUALINFO_new())) @@ -251,7 +252,7 @@ static POLICYINFO *policy_section(X509V3_CTX *ctx, if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value, strlen(cnf->value))) goto merr; - } else if (!name_cmp(cnf->name, "userNotice")) { + } else if (!x509v3_name_cmp(cnf->name, "userNotice")) { STACK_OF(CONF_VALUE) *unot; if (*cnf->value != '@') { OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXPECTED_A_SECTION_NAME); diff --git a/src/crypto/x509v3/v3_pci.c b/src/crypto/x509v3/v3_pci.c index 4352abee..f9031c04 100644 --- a/src/crypto/x509v3/v3_pci.c +++ b/src/crypto/x509v3/v3_pci.c @@ -44,6 +44,7 @@ #include #include "../internal.h" +#include "internal.h" static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext, @@ -123,7 +124,7 @@ static int process_pci_value(CONF_VALUE *val, } if (strncmp(val->value, "hex:", 4) == 0) { unsigned char *tmp_data2 = - string_to_hex(val->value + 4, &val_len); + x509v3_hex_to_bytes(val->value + 4, &val_len); if (!tmp_data2) { OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_HEX_DIGIT); diff --git a/src/crypto/x509v3/v3_skey.c b/src/crypto/x509v3/v3_skey.c index 65f8287c..6a16e78e 100644 --- a/src/crypto/x509v3/v3_skey.c +++ b/src/crypto/x509v3/v3_skey.c @@ -63,6 +63,9 @@ #include #include +#include "internal.h" + + static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); const X509V3_EXT_METHOD v3_skey_id = { @@ -76,7 +79,7 @@ const X509V3_EXT_METHOD v3_skey_id = { char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct) { - return hex_to_string(oct->data, oct->length); + return x509v3_bytes_to_hex(oct->data, oct->length); } ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, @@ -90,7 +93,7 @@ ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, return NULL; } - if (!(oct->data = string_to_hex(str, &length))) { + if (!(oct->data = x509v3_hex_to_bytes(str, &length))) { M_ASN1_OCTET_STRING_free(oct); return NULL; } diff --git a/src/crypto/x509v3/v3_utl.c b/src/crypto/x509v3/v3_utl.c index 589e296d..2a293dc8 100644 --- a/src/crypto/x509v3/v3_utl.c +++ b/src/crypto/x509v3/v3_utl.c @@ -72,6 +72,7 @@ #include "../conf/internal.h" #include "../internal.h" +#include "internal.h" static char *strip_spaces(char *name); @@ -446,7 +447,7 @@ static char *strip_spaces(char *name) * on EBCDIC machines) */ -char *hex_to_string(const unsigned char *buffer, long len) +char *x509v3_bytes_to_hex(const unsigned char *buffer, long len) { char *tmp, *q; const unsigned char *p; @@ -469,11 +470,7 @@ char *hex_to_string(const unsigned char *buffer, long len) return tmp; } -/* - * Give a string of hex digits convert to a buffer - */ - -unsigned char *string_to_hex(const char *str, long *len) +unsigned char *x509v3_hex_to_bytes(const char *str, long *len) { unsigned char *hexbuf, *q; unsigned char ch, cl, *p; @@ -533,11 +530,7 @@ unsigned char *string_to_hex(const char *str, long *len) } -/* - * V2I name comparison function: returns zero if 'name' matches cmp or cmp.* - */ - -int name_cmp(const char *name, const char *cmp) +int x509v3_name_cmp(const char *name, const char *cmp) { int len, ret; char c; diff --git a/src/include/openssl/x509v3.h b/src/include/openssl/x509v3.h index 4a654b54..d2d39f8e 100644 --- a/src/include/openssl/x509v3.h +++ b/src/include/openssl/x509v3.h @@ -666,10 +666,6 @@ OPENSSL_EXPORT int X509V3_EXT_free(int nid, void *ext_data); OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); OPENSSL_EXPORT int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags); -char *hex_to_string(const unsigned char *buffer, long len); -unsigned char *string_to_hex(const char *str, long *len); -int name_cmp(const char *name, const char *cmp); - OPENSSL_EXPORT void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, int ml); OPENSSL_EXPORT int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent); diff --git a/src/util/ar/ar.go b/src/util/ar/ar.go index f5dee622..756caf53 100644 --- a/src/util/ar/ar.go +++ b/src/util/ar/ar.go @@ -102,7 +102,9 @@ func ParseAR(r io.Reader) (map[string][]byte, error) { } filename := longFilenameTable[offset:] - if i := bytes.IndexByte(filename, '/'); i < 0 { + // Windows terminates filenames with NUL characters, + // while sysv/GNU uses /. + if i := bytes.IndexAny(filename, "/\x00"); i < 0 { return nil, errors.New("ar: unterminated filename in table") } else { filename = filename[:i] @@ -141,6 +143,10 @@ func ParseAR(r io.Reader) (map[string][]byte, error) { name = name[:null] } + if name == "__.SYMDEF" || name == "__.SYMDEF SORTED" { + continue + } + ret[name] = contents } diff --git a/src/util/ar/ar_test.go b/src/util/ar/ar_test.go new file mode 100644 index 00000000..ef37d795 --- /dev/null +++ b/src/util/ar/ar_test.go @@ -0,0 +1,118 @@ +// Copyright (c) 2018, Google Inc. +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +package ar + +import ( + "bytes" + "flag" + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +var testDataDir = flag.String("testdata", "testdata", "The path to the test data directory.") + +type arTest struct { + name string + in string + out map[string]string + // allowPadding is true if the contents may have trailing newlines at end. + // On macOS, ar calls ranlib which pads all inputs up to eight bytes with + // newlines. Unlike ar's native padding up to two bytes, this padding is + // included in the size field, so it is not removed when decoding. + allowPadding bool +} + +func (test *arTest) Path(file string) string { + return filepath.Join(*testDataDir, test.name, file) +} + +func removeTrailingNewlines(in []byte) []byte { + for len(in) > 0 && in[len(in)-1] == '\n' { + in = in[:len(in)-1] + } + return in +} + +var arTests = []arTest{ + { + "linux", + "libsample.a", + map[string]string{ + "foo.c.o": "foo.c.o", + "bar.cc.o": "bar.cc.o", + }, + false, + }, + { + "mac", + "libsample.a", + map[string]string{ + "foo.c.o": "foo.c.o", + "bar.cc.o": "bar.cc.o", + }, + true, + }, + { + "windows", + "sample.lib", + map[string]string{ + "CMakeFiles\\sample.dir\\foo.c.obj": "foo.c.obj", + "CMakeFiles\\sample.dir\\bar.cc.obj": "bar.cc.obj", + }, + false, + }, +} + +func TestAR(t *testing.T) { + for _, test := range arTests { + t.Run(test.name, func(t *testing.T) { + in, err := os.Open(test.Path(test.in)) + if err != nil { + t.Fatalf("opening input failed: %s", err) + } + defer in.Close() + + ret, err := ParseAR(in) + if err != nil { + t.Fatalf("reading input failed: %s", err) + } + + for file, contentsPath := range test.out { + expected, err := ioutil.ReadFile(test.Path(contentsPath)) + if err != nil { + t.Fatalf("error reading %s: %s", contentsPath, err) + } + got, ok := ret[file] + if test.allowPadding { + got = removeTrailingNewlines(got) + expected = removeTrailingNewlines(got) + } + if !ok { + t.Errorf("file %s missing from output", file) + } else if !bytes.Equal(got, expected) { + t.Errorf("contents for file %s did not match", file) + } + } + + for file, _ := range ret { + if _, ok := test.out[file]; !ok { + t.Errorf("output contained unexpected file %q", file) + } + } + }) + } +} diff --git a/src/util/ar/testdata/linux/bar.cc.o b/src/util/ar/testdata/linux/bar.cc.o new file mode 100644 index 00000000..92e83a9a Binary files /dev/null and b/src/util/ar/testdata/linux/bar.cc.o differ diff --git a/src/util/ar/testdata/linux/foo.c.o b/src/util/ar/testdata/linux/foo.c.o new file mode 100644 index 00000000..6423c1d4 Binary files /dev/null and b/src/util/ar/testdata/linux/foo.c.o differ diff --git a/src/util/ar/testdata/linux/libsample.a b/src/util/ar/testdata/linux/libsample.a new file mode 100644 index 00000000..cae6ae70 Binary files /dev/null and b/src/util/ar/testdata/linux/libsample.a differ diff --git a/src/util/ar/testdata/mac/bar.cc.o b/src/util/ar/testdata/mac/bar.cc.o new file mode 100644 index 00000000..9c607985 Binary files /dev/null and b/src/util/ar/testdata/mac/bar.cc.o differ diff --git a/src/util/ar/testdata/mac/foo.c.o b/src/util/ar/testdata/mac/foo.c.o new file mode 100644 index 00000000..0f96a0a0 Binary files /dev/null and b/src/util/ar/testdata/mac/foo.c.o differ diff --git a/src/util/ar/testdata/mac/libsample.a b/src/util/ar/testdata/mac/libsample.a new file mode 100644 index 00000000..b7d8eb5c Binary files /dev/null and b/src/util/ar/testdata/mac/libsample.a differ diff --git a/src/util/ar/testdata/sample/CMakeLists.txt b/src/util/ar/testdata/sample/CMakeLists.txt new file mode 100644 index 00000000..9ea2fe8e --- /dev/null +++ b/src/util/ar/testdata/sample/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.0) +project(Sample) +add_library(sample STATIC foo.c bar.cc) diff --git a/src/util/ar/testdata/sample/bar.cc b/src/util/ar/testdata/sample/bar.cc new file mode 100644 index 00000000..a0ac7e14 --- /dev/null +++ b/src/util/ar/testdata/sample/bar.cc @@ -0,0 +1,15 @@ +extern "C" { +void foo(); +void bar() {} +} + +namespace bar_namespace { + +void SomeExternalFunction(); + +void SomeFunction() { + foo(); + SomeExternalFunction(); +} + +} // namespace bar_namespace diff --git a/src/util/ar/testdata/sample/foo.c b/src/util/ar/testdata/sample/foo.c new file mode 100644 index 00000000..fed596cb --- /dev/null +++ b/src/util/ar/testdata/sample/foo.c @@ -0,0 +1,7 @@ +extern void external_symbol(void); +extern void bar(void); + +void foo(void) { + external_symbol(); + bar(); +} diff --git a/src/util/ar/testdata/windows/bar.cc.obj b/src/util/ar/testdata/windows/bar.cc.obj new file mode 100644 index 00000000..4a315cdd Binary files /dev/null and b/src/util/ar/testdata/windows/bar.cc.obj differ diff --git a/src/util/ar/testdata/windows/foo.c.obj b/src/util/ar/testdata/windows/foo.c.obj new file mode 100644 index 00000000..9b4aad7a Binary files /dev/null and b/src/util/ar/testdata/windows/foo.c.obj differ diff --git a/src/util/ar/testdata/windows/sample.lib b/src/util/ar/testdata/windows/sample.lib new file mode 100644 index 00000000..efeebb24 Binary files /dev/null and b/src/util/ar/testdata/windows/sample.lib differ diff --git a/src/util/make_prefix_headers.go b/src/util/make_prefix_headers.go index a5e5441f..b536f14c 100644 --- a/src/util/make_prefix_headers.go +++ b/src/util/make_prefix_headers.go @@ -172,16 +172,32 @@ func writeNASMHeader(symbols []string, path string) error { ; OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ; CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +; 32-bit Windows adds underscores to C functions, while 64-bit Windows does not. +%ifidn __OUTPUT_FORMAT__, win32 `); err != nil { return err } for _, symbol := range symbols { - if _, err := fmt.Fprintf(f, "%%define %s BORINGSSL_PREFIX %%+ %s\n", symbol, symbol); err != nil { + if _, err := fmt.Fprintf(f, "%%xdefine _%s _ %%+ BORINGSSL_PREFIX %%+ _%s\n", symbol, symbol); err != nil { return err } } + if _, err := fmt.Fprintf(f, "%%else\n"); err != nil { + return err + } + + for _, symbol := range symbols { + if _, err := fmt.Fprintf(f, "%%xdefine %s BORINGSSL_PREFIX %%+ _%s\n", symbol, symbol); err != nil { + return err + } + } + + if _, err := fmt.Fprintf(f, "%%endif\n"); err != nil { + return err + } + return nil } diff --git a/src/util/read_symbols.go b/src/util/read_symbols.go index 5e3a1776..791ea5d1 100644 --- a/src/util/read_symbols.go +++ b/src/util/read_symbols.go @@ -12,7 +12,7 @@ // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// read_symbols.go scans one or more .a files and, for each object contained in +// read_symbols scans one or more .a files and, for each object contained in // the .a files, reads the list of symbols in that object file. package main @@ -20,6 +20,7 @@ import ( "bytes" "debug/elf" "debug/macho" + "debug/pe" "flag" "fmt" "os" @@ -33,10 +34,13 @@ import ( const ( ObjFileFormatELF = "elf" ObjFileFormatMachO = "macho" + ObjFileFormatPE = "pe" ) -var outFlag = flag.String("out", "-", "File to write output symbols") -var objFileFormat = flag.String("obj-file-format", defaultObjFileFormat(runtime.GOOS), "Object file format to expect (options are elf, macho)") +var ( + outFlag = flag.String("out", "-", "File to write output symbols") + objFileFormat = flag.String("obj-file-format", defaultObjFileFormat(runtime.GOOS), "Object file format to expect (options are elf, macho, pe)") +) func defaultObjFileFormat(goos string) string { switch goos { @@ -44,6 +48,8 @@ func defaultObjFileFormat(goos string) string { return ObjFileFormatELF case "darwin": return ObjFileFormatMachO + case "windows": + return ObjFileFormatPE default: // By returning a value here rather than panicking, the user can still // cross-compile from an unsupported platform to a supported platform by @@ -53,11 +59,16 @@ func defaultObjFileFormat(goos string) string { } } +func printAndExit(format string, args ...interface{}) { + s := fmt.Sprintf(format, args...) + fmt.Fprintln(os.Stderr, s) + os.Exit(1) +} + func main() { flag.Parse() if flag.NArg() < 1 { - fmt.Fprintf(os.Stderr, "Usage: %s [-out OUT] [-obj-file-format FORMAT] ARCHIVE_FILE [ARCHIVE_FILE [...]]\n", os.Args[0]) - os.Exit(1) + printAndExit("Usage: %s [-out OUT] [-obj-file-format FORMAT] ARCHIVE_FILE [ARCHIVE_FILE [...]]", os.Args[0]) } archiveFiles := flag.Args() @@ -65,61 +76,109 @@ func main() { if *outFlag != "-" { var err error out, err = os.Create(*outFlag) - nilOrPanic(err, "failed to open output file") + if err != nil { + printAndExit("Error opening %q: %s", *outFlag, err) + } defer out.Close() } var symbols []string // Only add first instance of any symbol; keep track of them in this map. - added := make(map[string]bool) + added := make(map[string]struct{}) for _, archive := range archiveFiles { f, err := os.Open(archive) - nilOrPanic(err, "failed to open archive file %s", archive) + if err != nil { + printAndExit("Error opening %s: %s", archive, err) + } objectFiles, err := ar.ParseAR(f) - nilOrPanic(err, "failed to read archive file %s", archive) + f.Close() + if err != nil { + printAndExit("Error parsing %s: %s", archive, err) + } for name, contents := range objectFiles { - if !strings.HasSuffix(name, ".o") { - continue + syms, err := listSymbols(contents) + if err != nil { + printAndExit("Error listing symbols from %q in %q: %s", name, archive, err) } - for _, s := range listSymbols(name, contents) { - if !added[s] { - added[s] = true + for _, s := range syms { + if _, ok := added[s]; !ok { + added[s] = struct{}{} symbols = append(symbols, s) } } } } + sort.Strings(symbols) for _, s := range symbols { - // Filter out C++ mangled names. - prefix := "_Z" - if runtime.GOOS == "darwin" { - prefix = "__Z" + var skipSymbols = []string{ + // Inline functions, etc., from the compiler or language + // runtime will naturally end up in the library, to be + // deduplicated against other object files. Such symbols + // should not be prefixed. It is a limitation of this + // symbol-prefixing strategy that we cannot distinguish + // our own inline symbols (which should be prefixed) + // from the system's (which should not), so we blacklist + // known system symbols. + "__local_stdio_printf_options", + "__local_stdio_scanf_options", + "_vscprintf", + "_vscprintf_l", + "_vsscanf_l", + "_xmm", + "sscanf", + "vsnprintf", + // sdallocx is a weak symbol and intended to merge with + // the real one, if present. + "sdallocx", } - if !strings.HasPrefix(s, prefix) { - fmt.Fprintln(out, s) + var skip bool + for _, sym := range skipSymbols { + if sym == s { + skip = true + break + } + } + if skip || isCXXSymbol(s) || strings.HasPrefix(s, "__real@") || strings.HasPrefix(s, "__x86.get_pc_thunk.") { + continue + } + if _, err := fmt.Fprintln(out, s); err != nil { + printAndExit("Error writing to %s: %s", *outFlag, err) } } } +func isCXXSymbol(s string) bool { + if *objFileFormat == ObjFileFormatPE { + return strings.HasPrefix(s, "?") + } + return strings.HasPrefix(s, "_Z") +} + // listSymbols lists the exported symbols from an object file. -func listSymbols(name string, contents []byte) []string { +func listSymbols(contents []byte) ([]string, error) { switch *objFileFormat { case ObjFileFormatELF: - return listSymbolsELF(name, contents) + return listSymbolsELF(contents) case ObjFileFormatMachO: - return listSymbolsMachO(name, contents) + return listSymbolsMachO(contents) + case ObjFileFormatPE: + return listSymbolsPE(contents) default: - panic(fmt.Errorf("unsupported object file format %v", *objFileFormat)) + return nil, fmt.Errorf("unsupported object file format %q", *objFileFormat) } } -func listSymbolsELF(name string, contents []byte) []string { +func listSymbolsELF(contents []byte) ([]string, error) { f, err := elf.NewFile(bytes.NewReader(contents)) - nilOrPanic(err, "failed to parse ELF file %s", name) + if err != nil { + return nil, err + } syms, err := f.Symbols() - nilOrPanic(err, "failed to read symbol names from ELF file %s", name) + if err != nil { + return nil, err + } var names []string for _, sym := range syms { @@ -128,14 +187,16 @@ func listSymbolsELF(name string, contents []byte) []string { names = append(names, sym.Name) } } - return names + return names, nil } -func listSymbolsMachO(name string, contents []byte) []string { +func listSymbolsMachO(contents []byte) ([]string, error) { f, err := macho.NewFile(bytes.NewReader(contents)) - nilOrPanic(err, "failed to parse Mach-O file %s", name) + if err != nil { + return nil, err + } if f.Symtab == nil { - return nil + return nil, nil } var names []string for _, sym := range f.Symtab.Syms { @@ -155,16 +216,47 @@ func listSymbolsMachO(name string, contents []byte) []string { // Only include exported, defined symbols. if sym.Type&N_EXT != 0 && sym.Type&N_TYPE != N_UNDF { if len(sym.Name) == 0 || sym.Name[0] != '_' { - panic(fmt.Errorf("unexpected symbol without underscore prefix: %v", sym.Name)) + return nil, fmt.Errorf("unexpected symbol without underscore prefix: %q", sym.Name) } names = append(names, sym.Name[1:]) } } - return names + return names, nil } -func nilOrPanic(err error, f string, args ...interface{}) { +func listSymbolsPE(contents []byte) ([]string, error) { + f, err := pe.NewFile(bytes.NewReader(contents)) if err != nil { - panic(fmt.Errorf(f+": %v", append(args, err)...)) + return nil, err + } + var ret []string + for _, sym := range f.Symbols { + const ( + // https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#section-number-values + IMAGE_SYM_UNDEFINED = 0 + // https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#storage-class + IMAGE_SYM_CLASS_EXTERNAL = 2 + ) + if sym.SectionNumber != IMAGE_SYM_UNDEFINED && sym.StorageClass == IMAGE_SYM_CLASS_EXTERNAL { + name := sym.Name + if f.Machine == pe.IMAGE_FILE_MACHINE_I386 { + // On 32-bit Windows, C symbols are decorated by calling + // convention. + // https://msdn.microsoft.com/en-us/library/56h2zst2.aspx#FormatC + if strings.HasPrefix(name, "_") || strings.HasPrefix(name, "@") { + // __cdecl, __stdcall, or __fastcall. Remove the prefix and + // suffix, if present. + name = name[1:] + if idx := strings.LastIndex(name, "@"); idx >= 0 { + name = name[:idx] + } + } else if idx := strings.LastIndex(name, "@@"); idx >= 0 { + // __vectorcall. Remove the suffix. + name = name[:idx] + } + } + ret = append(ret, name) + } } + return ret, nil } -- cgit v1.2.3