summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViktor Dukhovni <openssl-users@dukhovni.org>2025-01-10 09:00:15 +0100
committerMatt Caswell <matt@openssl.org>2025-01-14 13:14:54 +0100
commit92c242e8ac26e1d4cb692c5258d0aefa14e5de84 (patch)
tree47cbdc88e79b5c5e58fb2bd2489906249322256a
parentFinishing touch to perlasm update to make it work on OpenBSD (diff)
downloadopenssl-92c242e8ac26e1d4cb692c5258d0aefa14e5de84.tar.xz
openssl-92c242e8ac26e1d4cb692c5258d0aefa14e5de84.zip
Big and little-endian load and store support
These are needed in ML-KEM and ML-DSA, and are likely generally useful, so public. Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26385)
-rw-r--r--CHANGES.md7
-rw-r--r--doc/build.info6
-rw-r--r--doc/man3/OPENSSL_load_u16_le.pod84
-rw-r--r--include/openssl/byteorder.h338
-rw-r--r--test/build.info6
-rw-r--r--test/byteorder_test.c89
-rw-r--r--test/recipes/02-test_byteorder.t12
-rwxr-xr-xutil/find-doc-nits2
-rw-r--r--util/other.syms12
9 files changed, 555 insertions, 1 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 5745c4f2b8..dc3c1ae372 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -30,6 +30,13 @@ OpenSSL 3.5
### Changes between 3.4 and 3.5 [xx XXX xxxx]
+* New inline functions were added to support loads and stores of unsigned
+ 16-bit, 32-bit and 64-bit integers in either little-endian or big-endian
+ form, regardless of the host byte-order. See the `OPENSSL_load_u16_le(3)`
+ manpage for details.
+
+ *Viktor Dukhovni*
+
* All the BIO_meth_get_*() functions allowing reuse of the internal OpenSSL
BIO method implementations were deprecated. The reuse is unsafe due to
dependency on the code of the internal methods not changing.
diff --git a/doc/build.info b/doc/build.info
index 6ad291201d..9003540be4 100644
--- a/doc/build.info
+++ b/doc/build.info
@@ -1579,6 +1579,10 @@ DEPEND[html/man3/OPENSSL_load_builtin_modules.html]=man3/OPENSSL_load_builtin_mo
GENERATE[html/man3/OPENSSL_load_builtin_modules.html]=man3/OPENSSL_load_builtin_modules.pod
DEPEND[man/man3/OPENSSL_load_builtin_modules.3]=man3/OPENSSL_load_builtin_modules.pod
GENERATE[man/man3/OPENSSL_load_builtin_modules.3]=man3/OPENSSL_load_builtin_modules.pod
+DEPEND[html/man3/OPENSSL_load_u16_le.html]=man3/OPENSSL_load_u16_le.pod
+GENERATE[html/man3/OPENSSL_load_u16_le.html]=man3/OPENSSL_load_u16_le.pod
+DEPEND[man/man3/OPENSSL_load_u16_le.3]=man3/OPENSSL_load_u16_le.pod
+GENERATE[man/man3/OPENSSL_load_u16_le.3]=man3/OPENSSL_load_u16_le.pod
DEPEND[html/man3/OPENSSL_malloc.html]=man3/OPENSSL_malloc.pod
GENERATE[html/man3/OPENSSL_malloc.html]=man3/OPENSSL_malloc.pod
DEPEND[man/man3/OPENSSL_malloc.3]=man3/OPENSSL_malloc.pod
@@ -3402,6 +3406,7 @@ html/man3/OPENSSL_init_crypto.html \
html/man3/OPENSSL_init_ssl.html \
html/man3/OPENSSL_instrument_bus.html \
html/man3/OPENSSL_load_builtin_modules.html \
+html/man3/OPENSSL_load_u16_le.html \
html/man3/OPENSSL_malloc.html \
html/man3/OPENSSL_riscvcap.html \
html/man3/OPENSSL_s390xcap.html \
@@ -4066,6 +4071,7 @@ man/man3/OPENSSL_init_crypto.3 \
man/man3/OPENSSL_init_ssl.3 \
man/man3/OPENSSL_instrument_bus.3 \
man/man3/OPENSSL_load_builtin_modules.3 \
+man/man3/OPENSSL_load_u16_le.3 \
man/man3/OPENSSL_malloc.3 \
man/man3/OPENSSL_riscvcap.3 \
man/man3/OPENSSL_s390xcap.3 \
diff --git a/doc/man3/OPENSSL_load_u16_le.pod b/doc/man3/OPENSSL_load_u16_le.pod
new file mode 100644
index 0000000000..197eee53dd
--- /dev/null
+++ b/doc/man3/OPENSSL_load_u16_le.pod
@@ -0,0 +1,84 @@
+=pod
+
+=head1 NAME
+
+OPENSSL_load_u16_le, OPENSSL_load_u16_be, OPENSSL_load_u32_le,
+OPENSSL_load_u32_be, OPENSSL_load_u64_le, OPENSSL_load_u64_be,
+OPENSSL_store_u16_le, OPENSSL_store_u16_be,
+OPENSSL_store_u32_le, OPENSSL_store_u32_be,
+OPENSSL_store_u64_le, OPENSSL_store_u64_be -
+Read and write unsigned 16, 32 and 64-bit integers in a specific byte order
+
+=head1 SYNOPSIS
+
+ #include <openssl/byteorder.h>
+
+ static ossl_inline unsigned char *OPENSSL_store_u16_le(
+ unsigned char *out, uint16_t val);
+ static ossl_inline unsigned char *OPENSSL_store_u16_be(
+ unsigned char *out, uint16_t val);
+ static ossl_inline unsigned char *OPENSSL_store_u32_le(
+ unsigned char *out, uint32_t val);
+ static ossl_inline unsigned char *OPENSSL_store_u32_be(
+ unsigned char *out, uint32_t val);
+ static ossl_inline unsigned char *OPENSSL_store_u64_le(
+ unsigned char *out, uint64_t val);
+ static ossl_inline unsigned char *OPENSSL_store_u64_be(
+ unsigned char *out, uint64_t val);
+ static ossl_inline const unsigned char *OPENSSL_load_u16_le(
+ uint16_t *val, const unsigned char *in);
+ static ossl_inline const unsigned char *OPENSSL_load_u16_be(
+ uint16_t *val, const unsigned char *in);
+ static ossl_inline const unsigned char *OPENSSL_load_u32_le(
+ uint32_t *val, const unsigned char *in);
+ static ossl_inline const unsigned char *OPENSSL_load_u32_be(
+ uint32_t *val, const unsigned char *in);
+ static ossl_inline const unsigned char *OPENSSL_load_u64_le(
+ uint64_t *val, const unsigned char *in);
+ static ossl_inline const unsigned char *OPENSSL_load_u64_be(
+ uint64_t *val, const unsigned char *in);
+
+=head1 DESCRIPTION
+
+These functions read and write 16, 32 and 64 bit unsigned integers in a
+specified byte order.
+The C<_be> functions use big-endian byte order, while the C<_le> functions use
+little-endian byte order.
+They're implemented directly in the header file, and declared static. When the
+compiler supports inline functions, they're also declared inline.
+An optimising compiler will often convert these to just one or two machine
+instructions: a load or store with a possible byte swap.
+
+The C<load> functions write the decoded integer value at the address pointed to
+by I<val>, which must be a valid (possibly suitably aligned) address of an
+object of the appropriate type.
+The C<store> functions write the encoding of I<val> at the address pointed to
+by I<out>.
+
+For convenience, these functions return the updated input or output pointer,
+making it easy to continue reading or writing more data at the next memory
+location.
+
+No bounds checks are performed, the caller is responsible for making sure that
+the input or output buffers are sufficiently large for the requested read or
+write.
+
+=head1 RETURN VALUES
+
+All these functions return the next memory address following the last byte
+written or read.
+
+=head1 HISTORY
+
+These functions were added in OpenSSL 3.5.
+
+=head1 COPYRIGHT
+
+Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/byteorder.h b/include/openssl/byteorder.h
new file mode 100644
index 0000000000..cce67beb54
--- /dev/null
+++ b/include/openssl/byteorder.h
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BYTEORDER_H
+# define OPENSSL_BYTEORDER_H
+# pragma once
+
+# include <openssl/e_os2.h>
+# include <string.h>
+
+/*
+ * "Modern" compilers do a decent job of optimising these functions to just a
+ * couple of instruction ([swap +] store, or load [+ swap]) when either no
+ * swapping is required, or a suitable swap instruction is available.
+ */
+
+# if defined(_MSC_VER) && _MSC_VER>=1300
+# pragma intrinsic(_byteswap_ushort)
+# pragma intrinsic(_byteswap_ulong)
+# pragma intrinsic(_byteswap_uint64)
+# define OSSL_HTOBE16(x) _byteswap_ushort(x)
+# define OSSL_HTOBE32(x) _byteswap_ulong(x)
+# define OSSL_HTOBE64(x) _byteswap_uint64(x)
+# define OSSL_BE16TOH(x) _byteswap_ushort(x)
+# define OSSL_BE32TOH(x) _byteswap_ulong(x)
+# define OSSL_BE64TOH(x) _byteswap_uint64(x)
+# define OSSL_HTOLE16(x) (x)
+# define OSSL_HTOLE32(x) (x)
+# define OSSL_HTOLE64(x) (x)
+# define OSSL_LE16TOH(x) (x)
+# define OSSL_LE32TOH(x) (x)
+# define OSSL_LE64TOH(x) (x)
+
+# elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+# if (__GLIBC_PREREQ(2, 19)) && defined(_DEFAULT_SOURCE)
+# include <endian.h>
+# define OSSL_HTOBE16(x) htobe16(x)
+# define OSSL_HTOBE32(x) htobe32(x)
+# define OSSL_HTOBE64(x) htobe64(x)
+# define OSSL_BE16TOH(x) be16toh(x)
+# define OSSL_BE32TOH(x) be32toh(x)
+# define OSSL_BE64TOH(x) be64toh(x)
+# define OSSL_HTOLE16(x) htole16(x)
+# define OSSL_HTOLE32(x) htole32(x)
+# define OSSL_HTOLE64(x) htole64(x)
+# define OSSL_LE16TOH(x) le16toh(x)
+# define OSSL_LE32TOH(x) le32toh(x)
+# define OSSL_LE64TOH(x) le64toh(x)
+# endif
+
+# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__)
+# if defined(__OpenBSD__)
+# include <sys/types.h>
+# else
+# include <sys/endian.h>
+# endif
+# define OSSL_HTOBE16(x) htobe16(x)
+# define OSSL_HTOBE32(x) htobe32(x)
+# define OSSL_HTOBE64(x) htobe64(x)
+# define OSSL_BE16TOH(x) be16toh(x)
+# define OSSL_BE32TOH(x) be32toh(x)
+# define OSSL_BE64TOH(x) be64toh(x)
+# define OSSL_HTOLE16(x) htole16(x)
+# define OSSL_HTOLE32(x) htole32(x)
+# define OSSL_HTOLE64(x) htole64(x)
+# define OSSL_LE16TOH(x) le16toh(x)
+# define OSSL_LE32TOH(x) le32toh(x)
+# define OSSL_LE64TOH(x) le64toh(x)
+
+# elif defined(__APPLE__)
+# include <libkern/OSByteOrder.h>
+# define OSSL_HTOBE16(x) OSSwapHostToBigInt16(x)
+# define OSSL_HTOBE32(x) OSSwapHostToBigInt32(x)
+# define OSSL_HTOBE64(x) OSSwapHostToBigInt64(x)
+# define OSSL_BE16TOH(x) OSSwapBigToHostInt16(x)
+# define OSSL_BE32TOH(x) OSSwapBigToHostInt32(x)
+# define OSSL_BE64TOH(x) OSSwapBigToHostInt64(x)
+# define OSSL_HTOLE16(x) OSSwapHostToLittleInt16(x)
+# define OSSL_HTOLE32(x) OSSwapHostToLittleInt32(x)
+# define OSSL_HTOLE64(x) OSSwapHostToLittleInt64(x)
+# define OSSL_LE16TOH(x) OSSwapLittleToHostInt16(x)
+# define OSSL_LE32TOH(x) OSSwapLittleToHostInt32(x)
+# define OSSL_LE64TOH(x) OSSwapLittleToHostInt64(x)
+
+# endif
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u16_le(unsigned char *out, uint16_t val)
+{
+# ifdef OSSL_HTOLE16
+ uint16_t t = OSSL_HTOLE16(val);
+
+ memcpy(out, (unsigned char *)&t, 2);
+ return out + 2;
+# else
+ *out++ = (val & 0xff);
+ *out++ = (val >> 8) & 0xff;
+ return out;
+# endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u16_be(unsigned char *out, uint16_t val)
+{
+# ifdef OSSL_HTOBE16
+ uint16_t t = OSSL_HTOBE16(val);
+
+ memcpy(out, (unsigned char *)&t, 2);
+ return out + 2;
+# else
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val & 0xff);
+ return out;
+# endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u32_le(unsigned char *out, uint32_t val)
+{
+# ifdef OSSL_HTOLE32
+ uint32_t t = OSSL_HTOLE32(val);
+
+ memcpy(out, (unsigned char *)&t, 4);
+ return out + 4;
+# else
+ *out++ = (val & 0xff);
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 24) & 0xff;
+ return out;
+# endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u32_be(unsigned char *out, uint32_t val)
+{
+# ifdef OSSL_HTOBE32
+ uint32_t t = OSSL_HTOBE32(val);
+
+ memcpy(out, (unsigned char *)&t, 4);
+ return out + 4;
+# else
+ *out++ = (val >> 24) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val & 0xff);
+ return out;
+# endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u64_le(unsigned char *out, uint64_t val)
+{
+# ifdef OSSL_HTOLE64
+ uint64_t t = OSSL_HTOLE64(val);
+
+ memcpy(out, (unsigned char *)&t, 8);
+ return out + 8;
+# else
+ *out++ = (val & 0xff);
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 24) & 0xff;
+ *out++ = (val >> 32) & 0xff;
+ *out++ = (val >> 40) & 0xff;
+ *out++ = (val >> 48) & 0xff;
+ *out++ = (val >> 56) & 0xff;
+ return out;
+# endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u64_be(unsigned char *out, uint64_t val)
+{
+# ifdef OSSL_HTOLE64
+ uint64_t t = OSSL_HTOBE64(val);
+
+ memcpy(out, (unsigned char *)&t, 8);
+ return out + 8;
+# else
+ *out++ = (val >> 56) & 0xff;
+ *out++ = (val >> 48) & 0xff;
+ *out++ = (val >> 40) & 0xff;
+ *out++ = (val >> 32) & 0xff;
+ *out++ = (val >> 24) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val & 0xff);
+ return out;
+# endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u16_le(uint16_t *val, const unsigned char *in)
+{
+# ifdef OSSL_LE16TOH
+ uint16_t t;
+
+ memcpy((unsigned char *)&t, in, 2);
+ *val = OSSL_LE16TOH(t);
+ return in + 2;
+# else
+ uint16_t b0 = *in++;
+ uint16_t b1 = *in++;
+
+ *val = b0 | (b1 << 8);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u16_be(uint16_t *val, const unsigned char *in)
+{
+# ifdef OSSL_LE16TOH
+ uint16_t t;
+
+ memcpy((unsigned char *)&t, in, 2);
+ *val = OSSL_BE16TOH(t);
+ return in + 2;
+# else
+ uint16_t b1 = *in++;
+ uint16_t b0 = *in++;
+
+ *val = b0 | (b1 << 8);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u32_le(uint32_t *val, const unsigned char *in)
+{
+# ifdef OSSL_LE32TOH
+ uint32_t t;
+
+ memcpy((unsigned char *)&t, in, 4);
+ *val = OSSL_LE32TOH(t);
+ return in + 4;
+# else
+ uint32_t b0 = *in++;
+ uint32_t b1 = *in++;
+ uint32_t b2 = *in++;
+ uint32_t b3 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u32_be(uint32_t *val, const unsigned char *in)
+{
+# ifdef OSSL_LE32TOH
+ uint32_t t;
+
+ memcpy((unsigned char *)&t, in, 4);
+ *val = OSSL_BE32TOH(t);
+ return in + 4;
+# else
+ uint32_t b3 = *in++;
+ uint32_t b2 = *in++;
+ uint32_t b1 = *in++;
+ uint32_t b0 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u64_le(uint64_t *val, const unsigned char *in)
+{
+# ifdef OSSL_LE64TOH
+ uint64_t t;
+
+ memcpy((unsigned char *)&t, in, 8);
+ *val = OSSL_LE64TOH(t);
+ return in + 8;
+# else
+ uint64_t b0 = *in++;
+ uint64_t b1 = *in++;
+ uint64_t b2 = *in++;
+ uint64_t b3 = *in++;
+ uint64_t b4 = *in++;
+ uint64_t b5 = *in++;
+ uint64_t b6 = *in++;
+ uint64_t b7 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
+ | (b4 << 32) | (b5 << 40) | (b6 << 48) | (b7 << 56);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u64_be(uint64_t *val, const unsigned char *in)
+{
+# ifdef OSSL_LE64TOH
+ uint64_t t;
+
+ memcpy((unsigned char *)&t, in, 8);
+ *val = OSSL_BE64TOH(t);
+ return in + 8;
+# else
+ uint64_t b7 = *in++;
+ uint64_t b6 = *in++;
+ uint64_t b5 = *in++;
+ uint64_t b4 = *in++;
+ uint64_t b3 = *in++;
+ uint64_t b2 = *in++;
+ uint64_t b1 = *in++;
+ uint64_t b0 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
+ | (b4 << 32) | (b5 << 40) | (b6 << 48) | (b7 << 56);
+ return in;
+#endif
+}
+
+# undef OSSL_HTOBE16
+# undef OSSL_HTOBE32
+# undef OSSL_HTOBE64
+# undef OSSL_BE16TOH
+# undef OSSL_BE32TOH
+# undef OSSL_BE64TOH
+# undef OSSL_HTOLE16
+# undef OSSL_HTOLE32
+# undef OSSL_HTOLE64
+# undef OSSL_LE16TOH
+# undef OSSL_LE32TOH
+# undef OSSL_LE64TOH
+
+#endif
diff --git a/test/build.info b/test/build.info
index ffb16c7775..71ae915253 100644
--- a/test/build.info
+++ b/test/build.info
@@ -40,7 +40,7 @@ IF[{- !$disabled{tests} -}]
exptest pbetest localetest evp_pkey_ctx_new_from_name \
evp_pkey_provided_test evp_test evp_extra_test evp_extra_test2 \
evp_fetch_prov_test evp_libctx_test ossl_store_test \
- v3nametest v3ext punycode_test evp_byname_test \
+ v3nametest v3ext byteorder_test punycode_test evp_byname_test \
crltest danetest bad_dtls_test lhash_test sparse_array_test \
conf_include_test params_api_test params_conversion_test \
constant_time_test safe_math_test verify_extra_test clienthellotest \
@@ -409,6 +409,10 @@ IF[{- !$disabled{tests} -}]
INCLUDE[pkcs7_test]=../include ../apps/include
DEPEND[pkcs7_test]=../libcrypto libtestutil.a
+ SOURCE[byteorder_test]=byteorder_test.c
+ INCLUDE[byteorder_test]=../include ../apps/include
+ DEPEND[byteorder_test]=../libcrypto.a libtestutil.a
+
SOURCE[punycode_test]=punycode_test.c
INCLUDE[punycode_test]=../include ../apps/include
DEPEND[punycode_test]=../libcrypto.a libtestutil.a
diff --git a/test/byteorder_test.c b/test/byteorder_test.c
new file mode 100644
index 0000000000..4bb7f597eb
--- /dev/null
+++ b/test/byteorder_test.c
@@ -0,0 +1,89 @@
+#include <string.h>
+#include <openssl/e_os2.h>
+#include <openssl/byteorder.h>
+#include "testutil.h"
+#include "testutil/output.h"
+
+static int test_byteorder(void)
+{
+ const unsigned char in[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ unsigned char out[8];
+ const unsigned char *restin;
+ unsigned char *restout;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+
+ memset(out, 0xff, sizeof(out));
+ restin = OPENSSL_load_u16_le(&u16, in);
+ restout = OPENSSL_store_u16_le(out, u16);
+ if (!TEST_true(u16 == 0x0100U
+ && memcmp(in, out, (size_t) 2) == 0
+ && restin == in + 2
+ && restout == out + 2)) {
+ TEST_info("Failed byteorder.h u16 LE load/store");
+ return 0;
+ }
+
+ memset(out, 0xff, sizeof(out));
+ restin = OPENSSL_load_u16_be(&u16, in);
+ restout = OPENSSL_store_u16_be(out, u16);
+ if (!TEST_true(u16 == 0x0001U
+ && memcmp(in, out, (size_t) 2) == 0
+ && restin == in + 2
+ && restout == out + 2)) {
+ TEST_info("Failed byteorder.h u16 BE load/store");
+ return 0;
+ }
+
+ memset(out, 0xff, sizeof(out));
+ restin = OPENSSL_load_u32_le(&u32, in);
+ restout = OPENSSL_store_u32_le(out, u32);
+ if (!TEST_true(u32 == 0x03020100UL
+ && memcmp(in, out, (size_t) 4) == 0
+ && restin == in + 4
+ && restout == out + 4)) {
+ TEST_info("Failed byteorder.h u32 LE load/store");
+ return 0;
+ }
+
+ memset(out, 0xff, sizeof(out));
+ restin = OPENSSL_load_u32_be(&u32, in);
+ restout = OPENSSL_store_u32_be(out, u32);
+ if (!TEST_true(u32 == 0x00010203UL
+ && memcmp(in, out, (size_t) 4) == 0
+ && restin == in + 4
+ && restout == out + 4)) {
+ TEST_info("Failed byteorder.h u32 BE load/store");
+ return 0;
+ }
+
+ memset(out, 0xff, sizeof(out));
+ restin = OPENSSL_load_u64_le(&u64, in);
+ restout = OPENSSL_store_u64_le(out, u64);
+ if (!TEST_true(u64 == 0x0706050403020100ULL
+ && memcmp(in, out, (size_t) 8) == 0
+ && restin == in + 8
+ && restout == out + 8)) {
+ TEST_info("Failed byteorder.h u64 LE load/store");
+ return 0;
+ }
+
+ memset(out, 0xff, sizeof(out));
+ restin = OPENSSL_load_u64_be(&u64, in);
+ restout = OPENSSL_store_u64_be(out, u64);
+ if (!TEST_true(u64 == 0x0001020304050607ULL
+ && memcmp(in, out, (size_t) 8) == 0
+ && restin == in + 8
+ && restout == out + 8)) {
+ TEST_info("Failed byteorder.h u64 BE load/store");
+ return 0;
+ }
+ return 1;
+}
+
+int setup_tests(void)
+{
+ ADD_TEST(test_byteorder);
+ return 1;
+}
diff --git a/test/recipes/02-test_byteorder.t b/test/recipes/02-test_byteorder.t
new file mode 100644
index 0000000000..c67cfd77e9
--- /dev/null
+++ b/test/recipes/02-test_byteorder.t
@@ -0,0 +1,12 @@
+#! /usr/bin/env perl
+# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+#
+# Licensed under the Apache License 2.0 (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use OpenSSL::Test::Simple;
+
+simple_test("test_byteorder", "byteorder_test");
diff --git a/util/find-doc-nits b/util/find-doc-nits
index 8a5c26fb61..b69891807f 100755
--- a/util/find-doc-nits
+++ b/util/find-doc-nits
@@ -108,6 +108,8 @@ my $ignored = qr/(?| ^i2d_
| ^SKM_DEFINE_STACK_OF_INTERNAL
| ^lh_
| ^DEFINE_LHASH_OF_(INTERNAL|DEPRECATED)
+ | ^OSSL_HTO[BL]E(16|32|64) # undefed
+ | ^OSSL_[BL]E(16|32|64)TOH # undefed
)/x;
# A common regexp for C symbol names
diff --git a/util/other.syms b/util/other.syms
index 094a365a21..f817779282 100644
--- a/util/other.syms
+++ b/util/other.syms
@@ -834,3 +834,15 @@ EVP_PKEY_base_id define
SSL_set_retry_verify define
TS_VERIFY_CTX define
CMAC_CTX define
+OPENSSL_load_u16_be inline
+OPENSSL_load_u16_le inline
+OPENSSL_store_u16_be inline
+OPENSSL_store_u16_le inline
+OPENSSL_load_u32_be inline
+OPENSSL_load_u32_le inline
+OPENSSL_store_u32_be inline
+OPENSSL_store_u32_le inline
+OPENSSL_load_u64_be inline
+OPENSSL_load_u64_le inline
+OPENSSL_store_u64_be inline
+OPENSSL_store_u64_le inline