Email: justin@affinix.com
JID: justin@andbit.net
The protocol flow is as follows:
Example 1. Server Offers Ack Feature
<stream:features>
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
<ack xmlns='http://affinix.com/jabber/ack'/>
</stream:features>
Example 2. Connecting Client or Server Enables Acking
<enable xmlns='http://affinix.com/jabber/ack'/>
Example 3. Server Acknowledges Request
<enabled xmlns='http://affinix.com/jabber/ack'/>
From this point on, both entities MUST acknowledge every stanza received by using the 'a' element. Note that only stanzas ('message', 'presence', and 'iq', in the jabber:client or jabber:server namespaces) are to be acknowledged. Non-stanza elements, such as those related to authentication or other stream-level purposes are not to be acknowledged using this protocol.
Example 4. Sending a Stanza
<message to='a@example.com' from='b@example.com'>
<body>Hello there.</body>
</message>
Example 5. Acking the Stanza
<a xmlns='http://affinix.com/jabber/ack'/>
It is also possible to ack several stanzas at once using the 'n' attribute as a shortcut:
Example 6. Acking Five Stanzas
<a xmlns='http://affinix.com/jabber/ack' n='5'/>
An ack indicates stanza acceptance, in that the stanza is now safe in the receiver's hands and that the receiver will "take care of it from here". Acks do not indicate successful delivery to a remote entity beyond the receiver. The sender does not have to wait for an ack to continue sending stanzas.
Acks SHOULD be sent as soon as possible, and MUST NOT be withheld for any condition other than a timeout. For example, a client with a slow connection might want to collect many stanzas over a period of time before acking, and a server might want to throttle incoming stanzas. As acks indicate stanza acceptance, a server that is throttling stanzas MUST defer the acks until the client is no longer being penalized.
Either entity can also ping the other, useful for ensuring that the TCP connection is still up and working, and also determining latency. The procedure should replace the legacy behavior of sending whitespace. Pinging is done by sending a 'ping' element:
Example 7. Pinging the Peer
<ping xmlns='http://affinix.com/jabber/ack'/>
The peer then MUST reply immediately with a 'pong' element.
Example 8. Replying to a Ping
<pong xmlns='http://affinix.com/jabber/ack'/>
A server that is throttling stanzas (and thus withholding acks until later) SHOULD still immediately reply to pings.
Example 1. Server Offers Address Feature
<stream:features>
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
<address xmlns='http://affinix.com/jabber/address'>160.33.26.10</address>
</stream:features>
Server offers PGP auth feature:
<stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> <pgpauth xmlns='http://affinix.com/jabber/pgp'/> <stream:features>
The feature must only be offered if TLS has not been negotiated yet. The client can utilize the feature by generating a self-signed certificate on-the-fly and then PGP-signing it (using a detached signature). The certificate and signature are sent in the <bindcert> element. The certificate is then used again during TLS negotiation, which follows the bindcert request. Both the certificate and signature are formatted in Base64'd DER.
Client prepares PGP auth:
<bindcert xmlns='http://affinix.com/jabber/pgp'>
<cert>
MIIDbjCCAtegAwIBAgIBADANBgkqhkiG9w0BAQQFADCBhzELMAkGA1UEBhMCVVMx
EzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNVBAcTBklydmluZTEYMBYGA1UEChMP
RXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtleGFtcGxlLmNvbTEiMCAGCSqGSIb3
DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbTAeFw0wMzA3MjQwNzMwMDBaFw0wMzA4
MjMwNzMwMDBaMIGHMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEP
MA0GA1UEBxMGSXJ2aW5lMRgwFgYDVQQKEw9FeGFtcGxlIENvbXBhbnkxFDASBgNV
BAMTC2V4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu
Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCobzCF268K2sRp473gvBTT
4AgSL1kjeF8N57vxS1P8zWrWMXNs4LuH0NRZmKTajeboy0br8xw+smIy3AbaKAwW
WZToesxebu3m9VeA8dqWyOaUMjoxAcgVYesgVaMpjRe7fcWdJnX1wJoVVPuIcO8m
a+AAPByfTORbzpSTmXAQAwIDAQABo4HnMIHkMB0GA1UdDgQWBBTvFierzLmmYMq0
cB/+5rK1bNR56zCBtAYDVR0jBIGsMIGpgBTvFierzLmmYMq0cB/+5rK1bNR566GB
jaSBijCBhzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNV
BAcTBklydmluZTEYMBYGA1UEChMPRXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtl
eGFtcGxlLmNvbTEiMCAGCSqGSIb3DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbYIB
ADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAGqGhXf7xNOnYNtFO7gz
K6RdZGHFI5q1DAEz4hhNBC9uElh32XGX4wN7giz3zLC8v9icL/W4ff/K5NDfv3Gf
gQe/+Wo9Be3H3ul6uwPPFnx4+PIOF2a5TW99H9smyxWdNjnFtcUte4al3RszcMWG
x3iqsWosGtj6F+ridmKoqKLu
<cert>
<signature>
rjPIg7qap49/YPiI3VfcTNO6vxzS7wrNBOpET2eVwo6nhp/asgv8yvXNmMz7JOLz
3/P8vWzt/Hc3FbC6O4Xoyvqmt7UVrbl50GyCwyKujfR1NjJ9E/ylUM/MIeTpFshN
HwnuCPDjtCMX8NnEeHYa8Kzfi8/sEwkHyi/8caE8fZA=
</signature>
</bindcert>
Server responds successfully:
<success xmlns='http://affinix.com/jabber/pgp'>
Or not:
<failure xmlns='http://affinix.com/jabber/pgp'>
If the server reports success, then the client can perform starttls and use the self-signed certificate in the TLS negotiation. If the server trusts the PGP key, then it can trust the certificate. The client should then be able to complete the authentication by using SASL EXTERNAL.