Draft: draft-ietf-ace-mqtt-tls-profile

Commentary: Some of these go a bit farther than just being " editorial " . I tried to keep to the spirit of ( my understanding of ) what the intended behavior is , though .
Messages are published under a Topic Name, and subscribers subscribe
to the Topic Names to receive the corresponding messages.  The Broker
uses the Topic Name in a published message to determine which
subscribers to relay the messages.  In this document, topics, more
specifically, Topic Names, are treated as resources.  The Clients are
assumed to have identified the publish/subscribe topics of interest
out-of-band (topic discovery is not a feature of the MQTT protocol).
A Resource Owner can pre-configure policies at the Authorisation
Server (AS) that give Clients publish or subscribe permissions to
different topics.
Messages are published under a Topic Name, and subscribers subscribe
to the Topic Names to receive the corresponding messages.  The Broker
uses the Topic Name in a published message to determine which
subscribers to relay the messages to.  In this document, topics, more
specifically, Topic Names, are treated as resources.  The Clients are
assumed to have identified the publish/subscribe topics of interest
out-of-band (topic discovery is not a feature of the MQTT protocol).
A Resource Owner can pre-configure policies at the Authorisation
Server (AS) that give Clients publish or subscribe permissions to
different topics.
A stateful interaction between a Client and a Broker.  Some
Sessions last only as long as the network connection, others can
span multiple network connections.
The data carried by the MQTT protocol.  The data has an associated
Quality-of-Service (QoS) level and a Topic Name.
The level of assurance for the delivery of an Application Message.
The QoS level can be 0-2, where "0" indicates "At most once
delivery", "1" "At least once delivery", and "2" "Exactly once
delivery".
A stateful interaction between a Client and a Broker.  Some
Sessions last only as long as the network connection; others can
span multiple network connections.
The data carried by the MQTT protocol.  The data has an associated
Quality-of-Service (QoS) level and Topic Name.
The level of assurance for the delivery of an Application Message.
The QoS level can be 0-2, where 0 indicates "At most once
delivery", 1 "At least once delivery", and 2 "Exactly once
delivery".
The last field of the Variable Header is a set of properties for
several MQTT control messages (e.g.  CONNECT, CONNACK) .  A
Property consists of an Identifier which defines its usage and
data type, followed by a value.  The Identifier is encoded as a
Variable Byte Integer.  For example, "Authentication Data"
property with an Identifier 22.
The last field of the Variable Header is a set of properties for
several MQTT control messages (e.g.  CONNECT, CONNACK) .  A
Property consists of an Identifier which defines its usage and
data type, followed by a value.  The Identifier is encoded as a
Variable Byte Integer.  For example, the "Authentication Data"
property uses the Identifier 22.
The Broker connection acknowledgment.  CONNACK packets contain
return codes indicating either a success or an error state in
response to a Client's CONNECT packet.
The Broker connection acknowledgment.  CONNACK packets contain
return codes indicating either a success or an error state in
response to a Client's CONNECT packet and any subsequent AUTH
packets.
This section specifies how Client connections are authorized by the
MQTT Broker. protocol_flow shows the basic protocol flow during
connection set-up.  The token request and response use the token
endpoint at the AS, specified in Section 5.8 of the I-D.ietf-ace-
oauth-authz.  Steps (D) and (E) are optional and use the
introspection endpoint, specified in Section 5.9 of the ACE
framework.  The Client and the Broker use HTTPS to communicate to AS
via these endpoints.  The Client and the Broker use MQTT to
communicate between them.  The C-AS and Broker-AS communication MAY
be implemented using protocols other than HTTPS, e.g.  CoAP or MQTT.
This section specifies how Client connections are authorized by the
MQTT Broker. protocol_flow shows the basic protocol flow during
connection set-up.  The token request and response use the token
endpoint at the AS, specified in Section 5.8 of the I-D.ietf-ace-
oauth-authz.  Steps (D) and (E) are optional and use the
introspection endpoint, specified in Section 5.9 of the ACE
framework.  The discussion in this document assumes that Client and
the Broker use HTTPS to communicate with the AS via these endpoints.
The Client and the Broker use MQTT to communicate between them.  The
C-AS and Broker-AS communication MAY be implemented using protocols
other than HTTPS, e.g.  CoAP or MQTT.  Whatever protocol is used for
C-AS and Broker-AS communications must provide mutual authentication,
confidentiality protection, and integrity protection.
The first step in the protocol flow (Figure 1 (A)) is the token
acquisition by the Client from the AS.  The Client and the AS MUST
perform mutual authentication.  The Client requests an access token
from the AS as described in Section 5.8.1 of the I-D.ietf-ace-oauth-
authz.  The media format is 'application/ace+json'.  The AS uses JSON
in the payload of its responses to the Client and the RS.
If the AS successfully verifies the access token request and
authorizes the Client for the indicated audience (i.e.  RS) and
scopes (i.e. publish/subscribe permissions over topics as described
in scope), the AS issues an access token (Figure 1 (B)).  The
response includes the parameters described in Section 5.8.2 of I-
D.ietf-ace-oauth-authz, and specifically, the "ace_profile" parameter
is set to "mqtt_tls".  The returned token is a Proof-of-Possession
(PoP) token by default.  This document follows RFC7800 for PoP
semantics for JWTs.  The PoP token includes a 'cnf' parameter with a
symmetric or asymmetric PoP key.  Note that the 'cnf' parameter in
the web tokens are to be consumed by the RS and not the Client.  For
the asymmetric case, the PoP token may include the 'rs_cnf' parameter
containing the information about the public key to be used by the RS
to authenticate as described in I-D.ietf-ace-oauth-params.
The first step in the protocol flow (Figure 1 (A)) is the token
acquisition by the Client from the AS.  The Client and the AS MUST
perform mutual authentication.  The Client requests an access token
from the AS as described in Section 5.8.1 of the I-D.ietf-ace-oauth-
authz.  The media type is 'application/ace+json'.  The AS uses JSON
in the payload of its responses to the Client and the RS.
If the AS successfully verifies the access token request and
authorizes the Client for the indicated audience (i.e., RS) and
scopes (i.e., publish/subscribe permissions over topics as described
in scope), the AS issues an access token (Figure 1 (B)).  The
response includes the parameters described in Section 5.8.2 of I-
D.ietf-ace-oauth-authz, and specifically, the "ace_profile" parameter
is set to "mqtt_tls".  The returned token is a Proof-of-Possession
(PoP) token by default.  This document follows RFC7800 for PoP
semantics for JWTs.  The PoP token includes a 'cnf' parameter with a
symmetric or asymmetric PoP key.  Note that the contents of the web
tokens (including the 'cnf' parameter) are to be consumed by the RS
and not the Client (the Client obtains the key information in a
different manner).  For the asymmetric case, the PoP token may
include the 'rs_cnf' parameter containing the information about the
public key to be used by the RS to authenticate as described in I-
D.ietf-ace-oauth-params.
The Broker MUST support "TLS:Anon-MQTT:ace".  To support Clients with
different capabilities, the Broker MAY provide multiple client
authentication options, e.g. support "TLS:Known(RPK)-MQTT:none" and
"TLS:Anon-MQTT:None", to enable RPK-based client authentication, but
fall back to "TLS:Anon-MQTT:ace" if the Client does not send a client
certificate (i.e. it sends an empty Certificate message) during the
TLS handshake.
The Broker MUST support "TLS:Anon-MQTT:ace".  To support Clients with
different capabilities, the Broker MAY provide multiple client
authentication options, e.g. support "TLS:Known(RPK)-MQTT:none" and
"TLS:Anon-MQTT:None", to enable RPK-based client authentication, but
fall back to "TLS:Anon-MQTT:ace" if the Client does not send a client
certificate (i.e., it sends an empty Certificate message) during the
TLS handshake.
In the cases when the Client MUST transport the token to the Broker
first, the Client connects to the Broker to publish its token to the
"authz-info" topic.  The "authz-info" topic MUST be publish-only
(i.e. the Clients are not allowed to subscribe to it).  "authz-info"
is not protected, and hence, the Client uses the "TLS:Anon-MQTT:None"
option over a TLS connection.  After publishing the token, the Client
disconnects from the Broker and is expected to reconnect using client
authentication over TLS (i.e.  TLS:Known(RPK/PSK)-MQTT:none).
In the cases when the Client MUST transport the token to the Broker
first, the Client connects to the Broker to publish its token to the
"authz-info" topic.  The "authz-info" topic MUST be publish-only
(i.e., the Clients are not allowed to subscribe to it).  "authz-info"
is not protected, and hence, the Client uses the "TLS:Anon-MQTT:None"
option over a TLS connection.  After publishing the token, the Client
disconnects from the Broker and is expected to reconnect using client
authentication over TLS (i.e., TLS:Known(RPK/PSK)-MQTT:none).
The Broker MUST verify the validity of the token (i.e. through local
validation or introspection, if the token is a reference) as
described in token_validation.  If the token is not valid, the Broker
MUST discard the token.  Depending on the QoS level of the PUBLISH
message, the Broker returns the error response as a PUBACK or a
DISCONNECT message as explained below.
The Broker MUST verify the validity of the token (i.e., through local
validation or introspection, if the token is a reference) as
described in token_validation.  If the token is not valid, the Broker
MUST discard the token.  Depending on the QoS level of the PUBLISH
message, the Broker returns the error response as a PUBACK or a
DISCONNECT message as explained below.
If the QoS level of the PUBLISH message is greater than or equal to
1, the Broker MUST return 'Not authorized' in PUBACK.  If the PUBLISH
payload does not parse to a token, the PUBACK reason code is '0x99
(Payload format invalid)'.
If the QoS level of the PUBLISH message is greater than or equal to
1, and the token is invalid or the claims cannot be obtained in the
case of an introspected token, the Broker MUST send the reason code
0x87 ('Not authorized') in the PUBACK.  If the PUBLISH payload does
not parse to a token, the PUBACK reason code is '0x99 (Payload format
invalid)'.
The CONNECT message flags are Username, Password, Will retain, Will
QoS, Will Flag, Clean Start, and Reserved.  mqttv5_connect_flags
shows how the flags MUST be set to use AUTH packets for
authentication and authorisation, i.e. the username and password
flags MUST be set to 0.  An MQTT v5.0 RS MAY also support token
transport using Username and Password to provide a security option
for MQTT v3.1.1 clients, as described in MQTTv311.
The CONNECT message flags are Username, Password, Will retain, Will
QoS, Will Flag, Clean Start, and Reserved.  mqttv5_connect_flags
shows how the flags MUST be set to use AUTH packets for
authentication and authorisation, i.e., the username and password
flags MUST be set to 0.  An MQTT v5.0 RS MAY also support token
transport using Username and Password to provide a security option
for MQTT v3.1.1 clients, as described in MQTTv311.
In MQTT v5.0, the Client signals a clean session (i.e. the session
does not continue an existing session), by setting the Clean Start
Flag to 1 and, the Session Expiry Interval to 0 in the CONNECT
message.  In this profile, the Broker SHOULD always start with a
clean session regardless of how these parameters are set.  Starting a
clean session helps the Broker avoid keeping unnecessary session
state for unauthorised clients.  If the Broker starts a clean
session, the Broker MUST set the Session Present flag to 0 in the
CONNACK packet to signal this to the Client.
In MQTT v5.0, the Client signals a clean session (i.e., the session
does not continue an existing session), by setting the Clean Start
Flag to 1 and, the Session Expiry Interval to 0 in the CONNECT
message.  In this profile, the Broker SHOULD always start with a
clean session regardless of how these parameters are set.  Starting a
clean session helps the Broker avoid keeping unnecessary session
state for unauthorised clients.  If the Broker starts a clean
session, the Broker MUST set the Session Present flag to 0 in the
CONNACK packet to signal this to the Client.
The Broker MAY support session continuation e.g., if the Broker
requires it for QoS reasons.  With session continuation, the Broker
maintains and uses client state from the existing session.  The
session state kept at the server MAY include token and its
introspection result (for reference tokens) in addition to the MQTT
session state.  The MQTT session state is identified by the Client
identifier and includes state on client subscriptions; messages with
QoS levels 1 and 2, and which have not been completely acknowledged
or pending transmission to the Client; and if the Session is
currently not connected, the time at which the Session will end and
Session State will be discarded.
The Broker MAY support session continuation e.g., if the Broker
requires it for QoS reasons.  With session continuation, the Broker
maintains and uses client state from the existing session.  The
session state kept at the server MAY include token and its
introspection result (for reference tokens) in addition to the MQTT
session state.  The MQTT session state is identified by the Client
identifier and includes state on client subscriptions; messages with
QoS levels 1 and 2, and which have not been completely acknowledged
or are pending transmission to the Client; and if the Session is
currently not connected, the time at which the Session will end and
Session State will be discarded.  The token/introspection state is
not part of the MQTT session state, and proof-of-possession is
required for each new connection, regardless of whether MQTT session
continuation is used.
When reconnecting to a Broker that supports session continuation, the
Client MUST still provide a token, in addition to using the same
Client identifier, setting the Clean Start to 0 and supplying a
Session Expiry interval in the CONNECT message.  The Broker MUST
perform proof-of-possession validation on the provided token.  If the
token matches the stored state, the Broker MAY skip introspecting a
token by reference, and use the stored introspection result.  The
Broker MUST also verify the Client is authorized to receive or send
packets that are pending transmission.  When a Client connects with a
long Session Expiry Interval, the Broker may need to maintain
Client's MQTT session state after it disconnects for an extended
period.  Brokers SHOULD implement administrative policies to limit
misuse.
When reconnecting to a Broker that supports session continuation, the
Client MUST still provide a token, in addition to using the same
Client identifier, setting the Clean Start to 0 and supplying a
Session Expiry interval in the CONNECT message.  The Broker MUST
perform proof-of-possession validation on the provided token.  If the
token matches the stored state, the Broker MAY skip introspecting a
token by reference, and use the stored introspection result.  The
Broker MUST also verify the Client is authorized to receive or send
MQTT packets that are pending transmission.  When a Client connects
with a long Session Expiry Interval, the Broker may need to maintain
Client's MQTT session state after it disconnects for an extended
period.  Brokers SHOULD implement administrative policies to limit
misuse.
Note that, according to the MQTT standard, the Broker uses the Client
identifier to identify the session state.  In the case of a Client
identifier collision, a client may take over another client's
session.  Given that clients provide a token at each connection,
clients will only send or receive messages to their authorized
topics.  Therefore, while this issue is not expected to affect
security, it may affect QoS (i.e.  PUBLISH or QoS messages saved for
Client A may be delivered to a Client B).  In addition, if this
Client identifier represents a Client already connected to the
Broker, the Broker sends a DISCONNECT packet to the existing Client
with Reason Code of '0x8E (Session taken over)', and closes the
connection to the client.
Note that, according to the MQTT standard, the Broker uses the Client
identifier to identify the session state.  In the case of a Client
identifier collision, a client may take over another client's
session.  Given that clients provide a token at each connection,
clients will only send or receive messages to their authorized
topics.  Therefore, while this issue is not expected to affect
security, it may affect QoS (i.e., PUBLISH or QoS messages saved for
Client A may be delivered to a Client B).  In addition, if this
Client identifier represents a Client already connected to the
Broker, the Broker sends a DISCONNECT packet to the existing Client
with Reason Code of '0x8E (Session taken over)', and closes the
connection to the client.
For this option, the Authentication Data MUST contain the two-byte
integer token length, the token, and the keyed message digest (MAC)
or the Client signature (as shown in authdata_tlsexporter).  The
Proof-of-Possession key in the token is used to calculate the keyed
message digest (MAC) or the Client signature based on the content
obtained from the TLS exporter (RFC5705 for TLS 1.2 and for TLS 1.3,
Section 7.5 of RFC8446).  This content is exported from the TLS
session using the exporter label 'EXPORTER-ACE-MQTT-Sign-Challenge',
an empty context, and length of 32 bytes.  The token is also
validated as described in token_validation and the server responds
with a CONNACK with the appropriate response code.  The client cannot
reauthenticate using this method during the same session ( see
reauthentication).
For this option, the Authentication Data MUST contain the two-byte
integer token length, the token, and the keyed message digest (MAC)
or the Client signature (as shown in authdata_tlsexporter).  The
Proof-of-Possession key in the token is used to calculate the keyed
message digest (MAC) or the Client signature based on the content
obtained from the TLS exporter (RFC5705 for TLS 1.2, and Section 7.5
of RFC8446) for TLS 1.3.  This content is exported from the TLS
session using the exporter label 'EXPORTER-ACE-MQTT-Sign-Challenge',
an empty context, and length of 32 bytes.  The token is also
validated as described in token_validation and the server responds
with a CONNACK with the appropriate response code.  The client cannot
reauthenticate using this method during the same session ( see
reauthentication).
Based on the validation result (obtained either via local inspection
or using the /introspection interface of the AS), the Broker MUST
send a CONNACK message to the Client.
The Broker MAY also trigger AS discovery, and include a User Property
(identified by 38 (0x26)) in the CONNACK for the AS Request Creation
Hints.  The User Property is a UTF-8 string pair, composed of a name
and a value.  The name of the User Property MUST be set to
"ace_as_hint".  The value of the user property is a UTF-8 encoded
JSON string containing the mandatory "AS" parameter, and the optional
parameters "audience", "kid", "cnonce", and "scope" as defined in
Section 5.3 of the I-D.ietf-ace-oauth-authz.
Based on the validation result (obtained either via local inspection
or using the introspection interface of the AS), the Broker MUST send
a CONNACK message to the Client.
If the Client does not provide a valid token or omits the
Authentication Data field, or the token or Authentication data are
malformed, authentication fails.  The Broker responds with the
CONNACK reason code "0x87 (Not Authorized)" or any other applicable
reason code.
The Broker MAY also trigger AS discovery, and include a User Property
(identified as property type 38 (0x26)) in the CONNACK for the AS
Request Creation Hints.  The User Property is a UTF-8 string pair,
composed of a name and a value.  The name of the User Property MUST
be set to "ace_as_hint".  The value of the user property is a UTF-8
encoded JSON string containing the mandatory "AS" parameter, and the
optional parameters "audience", "kid", "cnonce", and "scope" as
defined in Section 5.3 of the I-D.ietf-ace-oauth-authz.
If the Will Flag is set, then the Broker MUST check that the token
allows the publication of the Will message (i.e. the Will Topic
filter is in the scope array).
On receiving the PUBLISH message, the Broker MUST use the type of
message (i.e.  PUBLISH) and the Topic name in the message header to
match against the scope array items in the cached token or its
introspection result.  Following the example in the previous section,
a client sending a PUBLISH message to 'topic2/a' would be allowed, as
the scope array includes the '["topic2/#",["pub"]]'.
If the Will Flag is set, then the Broker MUST check that the token
allows the publication of the Will message (i.e., the Will Topic
filter is in the scope array).
On receiving the PUBLISH message, the Broker MUST use the type of
message (i.e., PUBLISH) and the Topic name in the message header to
match against the scope array items in the cached token or its
introspection result.  Following the example in the previous section,
a client sending a PUBLISH message to 'topic2/a' would be allowed, as
the scope array includes the '["topic2/#",["pub"]]'.
If the Client is allowed to publish to the topic, the Broker
publishes the message to all valid subscribers of the topic.  In the
case of an authorization failure, the Broker MUST return an error, if
the Client has set the QoS level of the PUBLISH message to greater
than or equal to 1.  Depending on the QoS level, the Broker responds
with either a PUBACK or PUBREC packet with reason code '0x87 (Not
authorized)'.  On receiving an acknowledgement with '0x87 (Not
authorized)', the Client MAY reauthenticate by providing a new token
as described in reauthentication.
If the Client is allowed to publish to the topic, the Broker
publishes the message to all valid subscribers of the topic.  In the
case of an authorization failure, the Broker MUST return an error if
the Client has set the QoS level of the PUBLISH message to greater
than or equal to 1.  Depending on the QoS level, the Broker responds
with either a PUBACK or PUBREC packet with reason code '0x87 (Not
authorized)'.  On receiving an acknowledgement with '0x87 (Not
authorized)', the Client MAY reauthenticate by providing a new token
as described in reauthentication.
To forward PUBLISH messages to the subscribing Clients, the Broker
identifies all the subscribers that have valid matching topic
subscriptions (i.e. the tokens are valid, and token scopes allow a
subscription to the particular topic).  The Broker sends a PUBLISH
message with the Topic name to all the valid subscribers.
To forward PUBLISH messages to the subscribing Clients, the Broker
identifies all the subscribers that have valid matching topic
subscriptions (i.e., the tokens are valid, and token scopes allow a
subscription to the particular topic).  The Broker sends a PUBLISH
message with the Topic name to all the valid subscribers.
If the Client used the challenge-respose PoP as defined in
pop_challenge, the Client MAY reauthenticate as a response to the
PUBACK and SUBACK that signal loss of authorization.  The Clients MAY
also proactively update their tokens, i.e. before they receive a
message with a "Not authorized" return code.  To start
reauthentication, the Client MUST send an AUTH packet with the reason
code "0x19 (Re-authentication)".  The Client MUST set the
Authentication Method as "ace" and transport the new token in the
Authentication Data.  The Broker accepts reauthentication requests if
the Client has already submitted a token (may be expired) and
validated via the challenge-response PoP.  Otherwise, the Broker MUST
deny the request.  If the reauthentication fails, the Broker MUST
send a DISCONNECT with the reason code "0x87 (Not Authorized)".
If the Client used the challenge-respose PoP as defined in
pop_challenge, the Client MAY reauthenticate as a response to the
PUBACK and SUBACK that signal loss of authorization.  The Clients MAY
also proactively update their tokens, i.e., before they receive a
message with a "Not authorized" return code.  To start
reauthentication, the Client MUST send an AUTH packet with the reason
code "0x19 (Re-authentication)".  The Client MUST set the
Authentication Method as "ace" and transport the new token in the
Authentication Data.  The Broker accepts reauthentication requests if
the Client has already submitted a token (may be expired) and
validated via the challenge-response PoP.  Otherwise, the Broker MUST
deny the request.  If the reauthentication fails, the Broker MUST
send a DISCONNECT with the reason code "0x87 (Not Authorized)".
Handling errors are more primitive in MQTT v3.1.1 due to not having
appropriate error fields, error codes, and server-side DISCONNECTs.
Therefore, the broker will disconnect on almost any error and may not
keep session state, necessitating clients to make a greater effort to
ensure that tokens remain valid and not attempt to publish to topics
that they do not have permissions for.  The following lists how the
broker responds to specific errors.
Error handling is more primitive in MQTT v3.1.1 due to not having
appropriate error fields, error codes, and server-side DISCONNECTs.
Therefore, the broker will disconnect on almost any error and may not
keep session state, necessitating that clients make a greater effort
to ensure that tokens remain valid and not attempt to publish to
topics that they do not have permissions for.  The following lists
how the broker responds to specific errors.