]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Big and little-endian load and store support
authorViktor Dukhovni <openssl-users@dukhovni.org>
Fri, 10 Jan 2025 08:00:15 +0000 (19:00 +1100)
committerMatt Caswell <matt@openssl.org>
Tue, 14 Jan 2025 12:14:54 +0000 (12:14 +0000)
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)

CHANGES.md
doc/build.info
doc/man3/OPENSSL_load_u16_le.pod [new file with mode: 0644]
include/openssl/byteorder.h [new file with mode: 0644]
test/build.info
test/byteorder_test.c [new file with mode: 0644]
test/recipes/02-test_byteorder.t [new file with mode: 0644]
util/find-doc-nits
util/other.syms

index 5745c4f2b86743c1d49bf7f75527b23daf4b43f1..dc3c1ae372d1447a87aaa1f6787b73835415d2fa 100644 (file)
@@ -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.
index 6ad291201dc82947122fe9fb01ce576965b4ff06..9003540be42e41385420ac2adc00ffcce1956641 100644 (file)
@@ -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 (file)
index 0000000..197eee5
--- /dev/null
@@ -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 (file)
index 0000000..cce67be
--- /dev/null
@@ -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
index ffb16c7775abfbe23c49eefdbe8e89bb9603452a..71ae915253f31269312c8c7da9075d90bef37461 100644 (file)
@@ -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 (file)
index 0000000..4bb7f59
--- /dev/null
@@ -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 (file)
index 0000000..c67cfd7
--- /dev/null
@@ -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");
index 8a5c26fb61b12e38dc647093e769fe7a6324a91b..b69891807f79b40ca9a69f74b42ac5b8ac234f57 100755 (executable)
@@ -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
index 094a365a21d998ed684e657f482646ff59944765..f8177792822a04ee5426a25717b562e4a0c2adcf 100644 (file)
@@ -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