security_layer — Implementations to negotiate stream security¶
This module provides different implementations of the security layer (TLS+SASL).
These are coupled, as different SASL features might need different TLS features
(such as channel binding or client cert authentication). The preferred method
to construct a SecurityLayer is using the make() function.
SecurityLayer objects are needed to establish an XMPP connection,
for example using aioxmpp.Client.
-
aioxmpp.security_layer.make(password_provider, *, pin_store=None, pin_type=<PinType.PUBLIC_KEY: 0>, post_handshake_deferred_failure=None, anonymous=False, ssl_context_factory=<function default_ssl_context>, no_verify=False)[source]¶ Construct a
SecurityLayer. Depending on the arguments passed, different features are enabled or disabled.Warning
When using any argument except password_provider, be sure to read its documentation below the following overview carefully. Many arguments can be used to shoot yourself in the foot easily, while violating all security expectations.
Parameters: password_provider (
stror coroutine function) – Password source to authenticate with.Keyword Arguments: - pin_store (
dictorAbstractPinStore) – Enable use of certificate/public key pinning. pin_type controls the type of store used when a dict is passed instead of a pin store object. - pin_type (
PinType) – Type of pin store to create when pin_store is a dict. - post_handshake_deferred_failure (coroutine function) – Coroutine callback to invoke when using certificate pinning and the verification of the certificate was not possible using either PKIX or the pin store.
- anonymous (
str,NoneorFalse) – trace token for SASL ANONYMOUS (RFC 4505); passing a non-Falsevalue enables ANONYMOUS authentication. - ssl_context_factory (function) – Factory function to create the SSL
context used to establish transport layer security. Defaults to
aioxmpp.security_layer.default_ssl_context(). - no_verify (
bool) – Disable all certificate verification. Usage is strongly discouraged outside controlled test environments. See below for alternatives.
Raises: RuntimeError– if anonymous is notFalseand the version ofaiosasldoes not support ANONYMOUS authentication.Returns: - object holding the entire security layer
configuration
Return type: password_provider must either be a coroutine function or a
str. As a coroutine function, it is called during authentication with the JID we are trying to authenticate against as the first, and the sequence number of the authentication attempt as second argument. The sequence number starts at 0. The coroutine is expected to returnNoneor a password. SeePasswordSASLProviderfor details. If password_provider is astr, a coroutine which returns the string on the first andNoneon subsequent attempts is created and used.If pin_store is not
None,PinningPKIXCertificateVerifieris used instead of the defaultPKIXCertificateVerifier. The pin_store argument determines the pinned certificates: if it is a dictionary, aAbstractPinStoreaccording to thePinTypepassed as pin_type argument is created and initialised with the data from the dictionary using itsimport_from_json()method. Otherwise, pin_store must be aAbstractPinStoreinstance which is passed to the verifier.post_handshake_deferred_callback is used only if pin_store is not
None. It is passed to the equally-named argument ofPinningPKIXCertificateVerifier, see the documentation there for details on the semantics. If post_handshake_deferred_callback isNonewhile pin_store is not, a coroutine which returnsFalseis substituted.ssl_context_factory can be a callable taking no arguments and returning a
OpenSSL.SSL.Contextobject. If given, the factory will be used to obtain an SSL context when the stream negotiates transport layer security via TLS. By default,aioxmpp.security_layer.default_ssl_context()is used, which should be fine for most applications.Warning
The
default_ssl_context()implementation sets important defaults. It is strongly recommended to use the context returned bydefault_ssl_context()and modify it, instead of creating a new context from scratch when implementing your own factory.If no_verify is true, none of the above regarding certificate verifiers matters. The internal null verifier is used, which disables certificate verification completely.
Warning
Disabling certificate verification makes your application vulnerable to trivial Man-in-the-Middle attacks. Do not use this outside controlled test environments or when you know exactly what you’re doing!
If you need to handle certificates which cannot be verified using the public key infrastructure, consider making use of the pin_store argument instead.
anonymous may be a string or
False. If it is notFalse,AnonymousSASLProvideris used before password based authentication is attempted. In addition, it is allowed to set password_provider toNone. anonymous is the trace token to use, and SHOULD be the empty string (as specified by XEP-0175). This requiresaiosasl0.3 or newer.Note
Falseand""are treated differently for the anonymous argument, despite both being false-y values!Note
If anonymous is not
Falseand password_provider is notNone, both authentication types are attempted. Anonymous authentication is, in that case, preferred over password-based authentication.If you need to reverse the order, you have to construct your own
SecurityLayerobject.Warning
Take the security and privacy considerations from RFC 4505 (which specifies the ANONYMOUS SASL mechanism) and XEP-0175 (which discusses the ANONYMOUS SASL mechanism in the XMPP context) into account before using anonymous.
The versatility and simplicity of use of this function make (pun intended) it the preferred way to construct
SecurityLayerinstances.New in version 0.8: Support for SASL ANONYMOUS was added.
New in version 0.11: Support for ssl_context_factory.
- pin_store (
-
class
aioxmpp.security_layer.PinType[source]¶ Enumeration to control which pinning is used by
make().-
PUBLIC_KEY¶ Public keys are stored in the pin store.
PublicKeyPinStoreis used.
-
CERTIFICATE¶ Whole certificates are stored in the pin store.
CertificatePinStoreis used.
-
-
aioxmpp.security_layer.tls_with_password_based_authentication(password_provider[, ssl_context_factory][, max_auth_attempts=3])[source]¶ Produce a commonly used
SecurityLayer, which uses TLS and password-based SASL authentication. If ssl_context_factory is not provided, an SSL context with TLSv1+ is used.password_provider must be a coroutine which is called with the jid as first and the number of attempt as second argument. It must return the password to us, or
Noneto abort.Return a
SecurityLayerinstance.Deprecated since version 0.7: Use
make()instead.
-
class
aioxmpp.security_layer.SecurityLayer(ssl_context_factory, certificate_verifier_factory, tls_required, sasl_providers)[source]¶ A security layer defines the security properties used for an XML stream. This includes TLS settings and SASL providers. The arguments are used to initialise the attributes of the same name.
SecurityLayerinstances are required to construct aaioxmpp.Client.New in version 0.6.
See also
make()- A powerful function which can be used to create a configured
SecurityLayerinstance.
-
ssl_context_factory¶ This is a callable returning a
OpenSSL.SSL.Contextinstance which is to be used for any SSL operations for the connection.The
OpenSSL.SSL.Contextinstances should not be resued between connection attempts, as the certificate verifiers may set options which cannot be disabled anymore.
-
certificate_verifier_factory¶ This is a callable which returns a fresh
CertificateVerifieron each call (it must be a fresh instance sinceCertificateVerifierobjects are allowed to keep state andSecurityLayerobjects are reusable between connection attempts).
-
tls_required¶ A boolean which indicates whether TLS is required. If it is set to true, connectors (see
aioxmpp.connector) will abort the connection if TLS (or something equivalent) is not available on the transport.Note
Disabling this makes your application vulnerable to STARTTLS stripping attacks.
-
sasl_providers¶ A sequence of
SASLProviderinstances. As SASL providers are stateless, it is not necessary to create new providers for each connection.
-
coroutine
aioxmpp.security_layer.negotiate_sasl(transport, xmlstream, sasl_providers, negotiation_timeout, jid, features)[source]¶ Perform SASL authentication on the given
protocol.XMLStreamstream. transport must be theasyncio.Transportover which the stream runs. It is used to detect whether TLS is used and may be required by some SASL mechanisms.sasl_providers must be an iterable of
SASLProviderobjects. They will be tried in iteration order to authenticate against the server. If one of the sasl_providers fails with aaiosasl.AuthenticationFailureexception, the other providers are still tried; only if all providers fail, the lastaiosasl.AuthenticationFailureexception is re-raised.If no mechanism was able to authenticate but not due to authentication failures (other failures include no matching mechanism on the server side),
aiosasl.SASLUnavailableis raised.Return the
nonza.StreamFeaturesobtained after resetting the stream after successful SASL authentication.New in version 0.6.
Deprecated since version 0.10: The negotiation_timeout argument is ignored. The timeout is controlled using the
deadtime_hard_limittimeout of the stream.The argument will be removed in version 1.0. To prepare for this, please pass jid and features as keyword arguments.
Certificate verifiers¶
To verify the peer certificate provided by the server, different
CertificateVerifiers are available:
-
class
aioxmpp.security_layer.PKIXCertificateVerifier[source]¶ This verifier enables the default PKIX based verification of certificates as implemented by OpenSSL.
The
verify_callback()checks that the certificate subject matches the domain name of the JID of the connection.
To implement your own verifiers, see the documentation at the base class for certificate verifiers:
-
class
aioxmpp.security_layer.CertificateVerifier[source]¶ A certificate verifier hooks into the two mechanisms provided by
aioopenssl.STARTTLSTransportfor certificate verification.On the one hand, the verify callback provided by
OpenSSL.SSL.Contextis used and forwarded toverify_callback(). On the other hand, the post handshake coroutine is set topost_handshake(). See the documentation ofaioopenssl.STARTTLSTransportfor the semantics of that coroutine.In addition to these two hooks into the TLS handshake, a third coroutine which is called before STARTTLS is intiiated is provided.
This baseclass provides a bit of boilerplate.
Certificate and key pinning¶
Often in the XMPP world, we need certificate or public key pinning, as most XMPP servers do not have certificates trusted by the usual certificate stores. This module also provide certificate verifiers which can be used for that purpose, as well as stores for saving the pinned information.
-
class
aioxmpp.security_layer.PinningPKIXCertificateVerifier(query_pin, post_handshake_deferred_failure, post_handshake_success=None)[source]¶ The
PinningPKIXCertificateVerifieris a subclass of theHookablePKIXCertificateVerifierwhich uses the hooks to implement certificate or public key pinning.It does not store the pins itself. Instead, the user must pass a callable to the query_pin argument. That callable will be called with two arguments: the servername and the x509. The x509 is a
OpenSSL.crypto.X509instance, which is the leaf certificate which attempts to identify the host. The servername is the name of the server we try to connect to (the identifying name, like the domain part of the JID). The callable must returnTrue(to accept the certificate),False(to reject the certificate) orNone(to defer the decision to the post_handshake_deferred_failure callback). query_pin must not block; if it needs to do blocking operations, it should defer.The other two arguments are coroutines with semantics identical to those of the same-named arguments in
HookablePKIXCertificateVerifier.See also
AbstractPinStore.query()is a method which can be passed as query_pin callback.
-
class
aioxmpp.security_layer.CertificatePinStore[source]¶ This pin store stores the whole certificates which are passed to its
pin()method.
-
class
aioxmpp.security_layer.PublicKeyPinStore[source]¶ This pin store stores the public keys of the X.509 objects which are passed to its
pin()method.
Base classes¶
For future expansion or customization, the base classes of the above utilities can be subclassed and extended:
-
class
aioxmpp.security_layer.HookablePKIXCertificateVerifier(quick_check, post_handshake_deferred_failure, post_handshake_success)[source]¶ This PKIX-based verifier has several hooks which allow overriding of the checking process, for example to implement key or certificate pinning.
It provides three callbacks:
quick_check is a synchronous callback (and must be a plain function) which is called from
verify_callback(). It is only called if the certificate fails full PKIX verification, and only for certain cases. For example, expired certificates do not get a second chance and are rejected immediately.It is called with the leaf certificate as its only argument. It must return
Trueif the certificate is known good and should pass the verification. If the certificate is known bad and should fail the verification immediately, it must returnFalse.If the certificate is unknown and the check should be deferred to the post_handshake_deferred_failure callback,
Nonemust be returned.Passing
Noneto quick_check is the same as if a callable passed to quick_check would returnNonealways (i.e. the decision is deferred).post_handshake_deferred_failure must be a coroutine. It is called after the handshake is done but before the STARTTLS negotiation has finished and allows the application to take more time to decide on a certificate and possibly request user input.
The coroutine receives the verifier instance as its argument and can make use of all the verification attributes to present the user with a sensible choice.
If post_handshake_deferred_failure is
None, the result is identical to returningFalsefrom the callback.post_handshake_success is only called if the certificate has passed the verification (either because it flawlessly passed by OpenSSL or the quick_check callback returned
True).You may pass
Noneto this argument to disable the callback without any further side effects.
The following attributes are available when the post handshake callbacks are called:
-
recorded_errors¶ This is a
setwith tuples consisting of aOpenSSL.crypto.X509instance, an OpenSSL error number and the depth of the certificate in the verification chain (0 is the leaf certificate).It is a collection of all errors which were passed into
verify_callback()by OpenSSL.
-
hostname_matches¶ This is
Trueif the host name in the leaf certificate matches the domain part of the JID for which we are connecting (i.e. the usual server name check).
-
leaf_x509¶ The
OpenSSL.crypto.X509object which represents the leaf certificate.
-
class
aioxmpp.security_layer.AbstractPinStore[source]¶ This is the abstract base class for both
PublicKeyPinStoreandCerificatePinStore. The interface for both types of pinning is identical; the only difference is in which information is stored.-
pin(hostname, x509)[source]¶ Pin an
OpenSSL.crypto.X509object x509 for use with the given hostname. Which information exactly is used to identify the certificate depends_x509_key().
-
query(hostname, x509)[source]¶ Return true if the given
OpenSSL.crypto.X509object x509 has previously been pinned for use with the given hostname andNoneotherwise.Returning
Noneallows this method to be used withPinningPKIXCertificateVerifier.
-
get_pinned_for_host(hostname)[source]¶ Return the set of hashable values which are used to identify the X.509 certificates which are accepted for the given hostname.
If no values have previously been pinned, this returns the empty set.
-
export_to_json()[source]¶ Return a JSON dictionary which contains all the pins stored in this store.
-
import_from_json(data, *, override=False)[source]¶ Import a JSON dictionary which must have the same format as exported by
export().If override is true, the existing data in the pin store will be overriden with the data from data. Otherwise, the data will be merged into the store.
For subclasses:
-
_encode_key(key)[source]¶ Encode the key (which has previously been obtained from
_x509_key()) into a string which is both JSON compatible and can be used as XML text (which means that it must not contain control characters, for example).The method is called by
export_to_json(). The default implementation returns key.
-
_decode_key(obj)[source]¶ Decode the obj into a key which is compatible to the values returned by
_x509_key().The method is called by
import_from_json(). The default implementation returns obj.
-
_x509_key(key)[source]¶ Return a hashable value which identifies the given x509 certificate for the purposes of the key store. See the implementations
PublicKeyPinStore._x509_key()andCertificatePinStore._x509_key()for details on what is stored for the respective subclasses.This method is abstract and must be implemented in subclasses.
-
SASL providers¶
As elements of the sasl_providers argument to SecurityLayer,
instances of the following classes can be used:
-
class
aioxmpp.security_layer.PasswordSASLProvider(password_provider, *, max_auth_attempts=3, **kwargs)[source]¶ Perform password-based SASL authentication.
Parameters: - password_provider (coroutine function) – A coroutine function returning the password to authenticate with.
- max_auth_attempts (positive
int) – Maximum number of authentication attempts with a single mechansim.
password_provider must be a coroutine taking two arguments, a JID and an integer number. The first argument is the JID which is trying to authenticate and the second argument is the number of the authentication attempt, starting at 0. On each attempt, the number is increased, up to max_auth_attempts-1. If the coroutine returns
None, the authentication process is aborted. If the number of attempts are exceeded, the authentication process is also aborted. In both cases, anaiosasl.AuthenticationFailureerror will be raised.The SASL mechanisms used depend on whether TLS has been negotiated successfully before. In any case,
aiosasl.SCRAMis used. If TLS has been negotiated,aiosasl.PLAINis also supported.See also
SASLProvider- for the public interface of this class.
-
class
aioxmpp.security_layer.AnonymousSASLProvider(token)[source]¶ Perform the
ANONYMOUSSASL mechanism (RFC 4505).Parameters: token ( str) – The trace token for theANONYMOUSmechanismtoken SHOULD be the empty string in the XMPP context (see XEP-0175).
See also
SASLProvider- for the public interface of this class.
Warning
Take the security and privacy considerations from RFC 4505 (which specifies the ANONYMOUS SASL mechanism) and XEP-0175 (which discusses the ANONYMOUS SASL mechanism in the XMPP context) into account before using this provider.
Note
This class requires
aiosasl.ANONYMOUS, which is available withaiosasl0.3 or newer. Ifaiosasl.ANONYMOUSis not provided, this class is replaced withNone.New in version 0.8.
Note
Patches welcome for additional SASLProvider implementations.
Abstract base classes¶
For implementation of custom SASL providers, the following base class can be used:
-
class
aioxmpp.security_layer.SASLProvider[source]¶ Base class to implement a SASL provider.
SASL providers are used in
SecurityLayerto authenticate the local user with a service. The credentials required depend on the specific SASL provider, and it is recommended to acquire means to get these credentials via constructor parameters (see for examplePasswordSASLProvider).The following methods must be implemented by subclasses:
-
coroutine
execute(client_jid, features, xmlstream, tls_transport)[source]¶ Perform SASL negotiation.
Parameters: - client_jid (
aioxmpp.JID) – The JID the client attempts to authenticate for - features (
StreamFeatures) – Current stream features nonza - xmlstream (
XMLStream) – The XML stream to authenticate over - tls_transport (
asyncio.TransportorNone) – The TLS transport orNoneif no TLS has been negotiated
Raises: - aiosasl.AuthenticationFailure – if authentication failed due to bad credentials
- aiosasl.SASLFailure – on other SASL-related errors
Returns: true if the negotiation was successful, false if no common mechanisms could be found or all mechanisms failed for reasons unrelated to the credentials themselves.
Return type: The implementation depends on the specific
SASLProvidersubclass in use.This coroutine returns
Trueif the negotiation was successful. If no common mechanisms could be found,Falseis returned. This is useful to chain several SASL providers (e.g. a provider supportingEXTERNALin front of password-based providers).Any other error case, such as no SASL support on the remote side or authentication failure results in an
aiosasl.SASLFailureexception to be raised.- client_jid (
The following methods are intended to be re-used by subclasses:
-
coroutine
_execute(intf, mechanism, token)[source]¶ Execute a SASL authentication process.
Parameters: - intf (
SASLXMPPInterface) – SASL interface to use - mechanism (
aiosasl.SASLMechanism) – SASL mechanism to use - token (not
None) – The opaque token argument for the mechanism
Raises: - aiosasl.AuthenticationFailure – if authentication failed due to bad credentials
- aiosasl.SASLFailure – on other SASL error conditions (such as protocol violations)
Returns: true if authentication succeeded, false if the mechanism has to be disabled
Return type: This executes the SASL authentication process. The more specific exceptions are generated by inspecting the
aiosasl.SASLFailure.opaque_erroron exceptinos raised from theSASLXMPPInterface. Otheraiosasl.SASLFailureexceptions are re-raised without modification.- intf (
-
_find_supported(features, mechanism_classes)[source]¶ Find the first mechansim class which supports a mechanism announced in the given stream features.
Parameters: - features (
StreamFeatures) – Current XMPP stream features - mechanism_classes (iterable of
SASLMechanismsubclasses) – SASL mechanism classes to use
Raises: aioxmpp.errors.SASLUnavailable – if the peer does not announce SASL support
Returns: the
SASLMechanismsubclass to use and a tokenReturn type: pair
Return a supported SASL mechanism class, by looking the given stream features features.
If no matching mechanism is found,
(None, None)is returned. Otherwise, a pair consisting of the mechanism class and the value returned by the respectiveany_supported()method is returned. The latter is an opaque token which must be passed to the token argument of_execute()oraiosasl.SASLMechanism.authenticate().- features (
-
coroutine
Deprecated functionality¶
In pre-0.6 code, you might find use of the following things:
-
aioxmpp.security_layer.security_layer(tls_provider, sasl_providers)[source]¶ Deprecated since version 0.6: Replaced by
SecurityLayer.Return a configured
SecurityLayer. tls_provider must be aSTARTTLSProvider.The return value can be passed to the constructor of
Client.Some very basic checking on the input is also performed.
-
class
aioxmpp.security_layer.STARTTLSProvider(ssl_context_factory, certificate_verifier_factory=<class 'aioxmpp.security_layer.PKIXCertificateVerifier'>, *, require_starttls=True)[source]¶ Deprecated since version 0.6: Do not use this. This is a shim class which provides backward-compatibility for versions older than 0.6.