Commit dffa3949 authored by Christian Heimes's avatar Christian Heimes

Issue #27744: Add AF_ALG (Linux Kernel crypto) to socket module.

parent 92a6c170
......@@ -131,6 +131,22 @@ created. Socket addresses are represented as follows:
string format. (ex. ``b'12:23:34:45:56:67'``) This protocol is not
supported under FreeBSD.
- :const:`AF_ALG` is a Linux-only socket based interface to Kernel
cryptography. An algorithm socket is configured with a tuple of two to four
elements ``(type, name [, feat [, mask]])``, where:
- *type* is the algorithm type as string, e.g. ``aead``, ``hash``,
``skcipher`` or ``rng``.
- *name* is the algorithm name and operation mode as string, e.g.
``sha256``, ``hmac(sha256)``, ``cbc(aes)`` or ``drbg_nopr_ctr_aes256``.
- *feat* and *mask* are unsigned 32bit integers.
Availability Linux 2.6.38, some algorithm types require more recent Kernels.
.. versionadded:: 3.6
- Certain other address families (:const:`AF_PACKET`, :const:`AF_CAN`)
support specific representations.
......@@ -350,6 +366,16 @@ Constants
TIPC related constants, matching the ones exported by the C socket API. See
the TIPC documentation for more information.
.. data:: AF_ALG
SOL_ALG
ALG_*
Constants for Linux Kernel cryptography.
Availability: Linux >= 2.6.38.
.. versionadded:: 3.6
.. data:: AF_LINK
Availability: BSD, OSX.
......@@ -1294,6 +1320,15 @@ to sockets.
an exception, the method now retries the system call instead of raising
an :exc:`InterruptedError` exception (see :pep:`475` for the rationale).
.. method:: socket.sendmsg_afalg([msg], *, op[, iv[, assoclen[, flags]]])
Specialized version of :meth:`~socket.sendmsg` for :const:`AF_ALG` socket.
Set mode, IV, AEAD associated data length and flags for :const:`AF_ALG` socket.
Availability: Linux >= 2.6.38
.. versionadded:: 3.6
.. method:: socket.sendfile(file, offset=0, count=None)
Send a file until EOF is reached by using high-performance
......@@ -1342,21 +1377,29 @@ to sockets.
For further information, please consult the :ref:`notes on socket timeouts <socket-timeouts>`.
.. method:: socket.setsockopt(level, optname, value)
.. method:: socket.setsockopt(level, optname, value: int)
.. method:: socket.setsockopt(level, optname, value: buffer)
.. method:: socket.setsockopt(level, optname, None, optlen: int)
.. index:: module: struct
Set the value of the given socket option (see the Unix manual page
:manpage:`setsockopt(2)`). The needed symbolic constants are defined in the
:mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer or
a :term:`bytes-like object` representing a buffer. In the latter case it is
up to the caller to
ensure that the bytestring contains the proper bits (see the optional built-in
module :mod:`struct` for a way to encode C structures as bytestrings).
:mod:`socket` module (:const:`SO_\*` etc.). The value can be an integer,
None or a :term:`bytes-like object` representing a buffer. In the later
case it is up to the caller to ensure that the bytestring contains the
proper bits (see the optional built-in module :mod:`struct` for a way to
encode C structures as bytestrings). When value is set to None,
optlen argument is required. It's equivalent to call setsockopt C
function with optval=NULL and optlen=optlen.
.. versionchanged:: 3.5
Writable :term:`bytes-like object` is now accepted.
.. versionchanged:: 3.6
setsockopt(level, optname, None, optlen: int) form added.
.. method:: socket.shutdown(how)
......
......@@ -5325,6 +5325,170 @@ class SendfileUsingSendfileTest(SendfileUsingSendTest):
def meth_from_sock(self, sock):
return getattr(sock, "_sendfile_use_sendfile")
@unittest.skipUnless(hasattr(socket, "AF_ALG"), 'AF_ALG required')
class LinuxKernelCryptoAPI(unittest.TestCase):
# tests for AF_ALG
def create_alg(self, typ, name):
sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
sock.bind((typ, name))
return sock
def test_sha256(self):
expected = bytes.fromhex("ba7816bf8f01cfea414140de5dae2223b00361a396"
"177a9cb410ff61f20015ad")
with self.create_alg('hash', 'sha256') as algo:
op, _ = algo.accept()
with op:
op.sendall(b"abc")
self.assertEqual(op.recv(512), expected)
op, _ = algo.accept()
with op:
op.send(b'a', socket.MSG_MORE)
op.send(b'b', socket.MSG_MORE)
op.send(b'c', socket.MSG_MORE)
op.send(b'')
self.assertEqual(op.recv(512), expected)
def test_hmac_sha1(self):
expected = bytes.fromhex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")
with self.create_alg('hash', 'hmac(sha1)') as algo:
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, b"Jefe")
op, _ = algo.accept()
with op:
op.sendall(b"what do ya want for nothing?")
self.assertEqual(op.recv(512), expected)
def test_aes_cbc(self):
key = bytes.fromhex('06a9214036b8a15b512e03d534120006')
iv = bytes.fromhex('3dafba429d9eb430b422da802c9fac41')
msg = b"Single block msg"
ciphertext = bytes.fromhex('e353779c1079aeb82708942dbe77181a')
msglen = len(msg)
with self.create_alg('skcipher', 'cbc(aes)') as algo:
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
op, _ = algo.accept()
with op:
op.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, iv=iv,
flags=socket.MSG_MORE)
op.sendall(msg)
self.assertEqual(op.recv(msglen), ciphertext)
op, _ = algo.accept()
with op:
op.sendmsg_afalg([ciphertext],
op=socket.ALG_OP_DECRYPT, iv=iv)
self.assertEqual(op.recv(msglen), msg)
# long message
multiplier = 1024
longmsg = [msg] * multiplier
op, _ = algo.accept()
with op:
op.sendmsg_afalg(longmsg,
op=socket.ALG_OP_ENCRYPT, iv=iv)
enc = op.recv(msglen * multiplier)
self.assertEqual(len(enc), msglen * multiplier)
self.assertTrue(enc[:msglen], ciphertext)
op, _ = algo.accept()
with op:
op.sendmsg_afalg([enc],
op=socket.ALG_OP_DECRYPT, iv=iv)
dec = op.recv(msglen * multiplier)
self.assertEqual(len(dec), msglen * multiplier)
self.assertEqual(dec, msg * multiplier)
@support.requires_linux_version(3, 19)
def test_aead_aes_gcm(self):
key = bytes.fromhex('c939cc13397c1d37de6ae0e1cb7c423c')
iv = bytes.fromhex('b3d8cc017cbb89b39e0f67e2')
plain = bytes.fromhex('c3b3c41f113a31b73d9a5cd432103069')
assoc = bytes.fromhex('24825602bd12a984e0092d3e448eda5f')
expected_ct = bytes.fromhex('93fe7d9e9bfd10348a5606e5cafa7354')
expected_tag = bytes.fromhex('0032a1dc85f1c9786925a2e71d8272dd')
taglen = len(expected_tag)
assoclen = len(assoc)
with self.create_alg('aead', 'gcm(aes)') as algo:
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_AEAD_AUTHSIZE,
None, taglen)
# send assoc, plain and tag buffer in separate steps
op, _ = algo.accept()
with op:
op.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, iv=iv,
assoclen=assoclen, flags=socket.MSG_MORE)
op.sendall(assoc, socket.MSG_MORE)
op.sendall(plain, socket.MSG_MORE)
op.sendall(b'\x00' * taglen)
res = op.recv(assoclen + len(plain) + taglen)
self.assertEqual(expected_ct, res[assoclen:-taglen])
self.assertEqual(expected_tag, res[-taglen:])
# now with msg
op, _ = algo.accept()
with op:
msg = assoc + plain + b'\x00' * taglen
op.sendmsg_afalg([msg], op=socket.ALG_OP_ENCRYPT, iv=iv,
assoclen=assoclen)
res = op.recv(assoclen + len(plain) + taglen)
self.assertEqual(expected_ct, res[assoclen:-taglen])
self.assertEqual(expected_tag, res[-taglen:])
# create anc data manually
pack_uint32 = struct.Struct('I').pack
op, _ = algo.accept()
with op:
msg = assoc + plain + b'\x00' * taglen
op.sendmsg(
[msg],
([socket.SOL_ALG, socket.ALG_SET_OP, pack_uint32(socket.ALG_OP_ENCRYPT)],
[socket.SOL_ALG, socket.ALG_SET_IV, pack_uint32(len(iv)) + iv],
[socket.SOL_ALG, socket.ALG_SET_AEAD_ASSOCLEN, pack_uint32(assoclen)],
)
)
res = op.recv(len(msg))
self.assertEqual(expected_ct, res[assoclen:-taglen])
self.assertEqual(expected_tag, res[-taglen:])
# decrypt and verify
op, _ = algo.accept()
with op:
msg = assoc + expected_ct + expected_tag
op.sendmsg_afalg([msg], op=socket.ALG_OP_DECRYPT, iv=iv,
assoclen=assoclen)
res = op.recv(len(msg))
self.assertEqual(plain, res[assoclen:-taglen])
def test_drbg_pr_sha256(self):
# deterministic random bit generator, prediction resistance, sha256
with self.create_alg('rng', 'drbg_pr_sha256') as algo:
extra_seed = os.urandom(32)
algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, extra_seed)
op, _ = algo.accept()
with op:
rn = op.recv(32)
self.assertEqual(len(rn), 32)
def test_sendmsg_afalg_args(self):
sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
with self.assertRaises(TypeError):
sock.sendmsg_afalg()
with self.assertRaises(TypeError):
sock.sendmsg_afalg(op=None)
with self.assertRaises(TypeError):
sock.sendmsg_afalg(1)
with self.assertRaises(TypeError):
sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=None)
with self.assertRaises(TypeError):
sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=-1)
def test_main():
tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest,
......@@ -5352,6 +5516,7 @@ def test_main():
tests.extend([TIPCTest, TIPCThreadableTest])
tests.extend([BasicCANTest, CANTest])
tests.extend([BasicRDSTest, RDSTest])
tests.append(LinuxKernelCryptoAPI)
tests.extend([
CmsgMacroTests,
SendmsgUDPTest,
......
......@@ -77,6 +77,8 @@ Core and Builtins
Library
-------
- Issue #27744: Add AF_ALG (Linux Kernel crypto) to socket module.
- Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0.
- Issue #11620: Fix support for SND_MEMORY in winsound.PlaySound. Based on a
......
This diff is collapsed.
......@@ -775,7 +775,6 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
......@@ -886,7 +885,6 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
......@@ -1139,15 +1137,6 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
......@@ -1285,7 +1274,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir runstatedir
libdir localedir mandir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
......@@ -1438,7 +1427,6 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
......@@ -13062,6 +13050,41 @@ $as_echo "#define HAVE_SOCKADDR_STORAGE 1" >>confdefs.h
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_alg" >&5
$as_echo_n "checking for sockaddr_alg... " >&6; }
if ${ac_cv_struct_sockaddr_alg+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
# include <sys/types.h>
# include <sys/socket.h>
# include <linux/if_alg.h>
int
main ()
{
struct sockaddr_alg s
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_struct_sockaddr_alg=yes
else
ac_cv_struct_sockaddr_alg=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_alg" >&5
$as_echo "$ac_cv_struct_sockaddr_alg" >&6; }
if test $ac_cv_struct_sockaddr_alg = yes; then
$as_echo "#define HAVE_SOCKADDR_ALG 1" >>confdefs.h
fi
# checks for compiler characteristics
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5
......
......@@ -3862,6 +3862,19 @@ if test $ac_cv_struct_sockaddr_storage = yes; then
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [struct sockaddr_storage (sys/socket.h)])
fi
AC_MSG_CHECKING(for sockaddr_alg)
AC_CACHE_VAL(ac_cv_struct_sockaddr_alg,
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
# include <sys/types.h>
# include <sys/socket.h>
# include <linux/if_alg.h>]], [[struct sockaddr_alg s]])],
[ac_cv_struct_sockaddr_alg=yes],
[ac_cv_struct_sockaddr_alg=no]))
AC_MSG_RESULT($ac_cv_struct_sockaddr_alg)
if test $ac_cv_struct_sockaddr_alg = yes; then
AC_DEFINE(HAVE_SOCKADDR_ALG, 1, [struct sockaddr_alg (linux/if_alg.h)])
fi
# checks for compiler characteristics
AC_C_CHAR_UNSIGNED
......
......@@ -892,6 +892,9 @@
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* struct sockaddr_alg (linux/if_alg.h) */
#undef HAVE_SOCKADDR_ALG
/* Define if sockaddr has sa_len member */
#undef HAVE_SOCKADDR_SA_LEN
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment