| < draft-ietf-oauth-native-apps-02.txt | draft-ietf-oauth-native-apps-03.txt > | |||
|---|---|---|---|---|
| OAuth Working Group W. Denniss | OAuth Working Group W. Denniss | |||
| Internet-Draft Google | Internet-Draft Google | |||
| Intended status: Best Current Practice J. Bradley | Intended status: Best Current Practice J. Bradley | |||
| Expires: January 3, 2017 Ping Identity | Expires: January 21, 2017 Ping Identity | |||
| July 02, 2016 | July 20, 2016 | |||
| OAuth 2.0 for Native Apps | OAuth 2.0 for Native Apps | |||
| draft-ietf-oauth-native-apps-02 | draft-ietf-oauth-native-apps-03 | |||
| Abstract | Abstract | |||
| OAuth 2.0 authorization requests from native apps should only be made | OAuth 2.0 authorization requests from native apps should only be made | |||
| through external user-agents, primarily the system browser. This | through external user-agents, primarily the system browser. This | |||
| specification details the security and usability reasons why this is | specification details the security and usability reasons why this is | |||
| the case, and how native apps and authorization servers can implement | the case, and how native apps and authorization servers can implement | |||
| this best practice. | this best practice. | |||
| Status of This Memo | Status of This Memo | |||
| skipping to change at page 1, line 35 ¶ | skipping to change at page 1, line 35 ¶ | |||
| Internet-Drafts are working documents of the Internet Engineering | Internet-Drafts are working documents of the Internet Engineering | |||
| Task Force (IETF). Note that other groups may also distribute | Task Force (IETF). Note that other groups may also distribute | |||
| working documents as Internet-Drafts. The list of current Internet- | working documents as Internet-Drafts. The list of current Internet- | |||
| Drafts is at http://datatracker.ietf.org/drafts/current/. | Drafts is at http://datatracker.ietf.org/drafts/current/. | |||
| Internet-Drafts are draft documents valid for a maximum of six months | Internet-Drafts are draft documents valid for a maximum of six months | |||
| and may be updated, replaced, or obsoleted by other documents at any | and may be updated, replaced, or obsoleted by other documents at any | |||
| time. It is inappropriate to use Internet-Drafts as reference | time. It is inappropriate to use Internet-Drafts as reference | |||
| material or to cite them other than as "work in progress." | material or to cite them other than as "work in progress." | |||
| This Internet-Draft will expire on January 3, 2017. | This Internet-Draft will expire on January 21, 2017. | |||
| Copyright Notice | Copyright Notice | |||
| Copyright (c) 2016 IETF Trust and the persons identified as the | Copyright (c) 2016 IETF Trust and the persons identified as the | |||
| document authors. All rights reserved. | document authors. All rights reserved. | |||
| This document is subject to BCP 78 and the IETF Trust's Legal | This document is subject to BCP 78 and the IETF Trust's Legal | |||
| Provisions Relating to IETF Documents | Provisions Relating to IETF Documents | |||
| (http://trustee.ietf.org/license-info) in effect on the date of | (http://trustee.ietf.org/license-info) in effect on the date of | |||
| publication of this document. Please review these documents | publication of this document. Please review these documents | |||
| skipping to change at page 2, line 34 ¶ | skipping to change at page 2, line 34 ¶ | |||
| 8.3. Phishability of In-App Browser Tabs . . . . . . . . . . . 12 | 8.3. Phishability of In-App Browser Tabs . . . . . . . . . . . 12 | |||
| 8.4. Limitations of Non-verifiable Clients . . . . . . . . . . 12 | 8.4. Limitations of Non-verifiable Clients . . . . . . . . . . 12 | |||
| 9. Other External User Agents . . . . . . . . . . . . . . . . . 12 | 9. Other External User Agents . . . . . . . . . . . . . . . . . 12 | |||
| 10. Client Authentication . . . . . . . . . . . . . . . . . . . . 13 | 10. Client Authentication . . . . . . . . . . . . . . . . . . . . 13 | |||
| 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 13 | 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 13 | |||
| 11.1. Normative References . . . . . . . . . . . . . . . . . . 13 | 11.1. Normative References . . . . . . . . . . . . . . . . . . 13 | |||
| 11.2. Informative References . . . . . . . . . . . . . . . . . 13 | 11.2. Informative References . . . . . . . . . . . . . . . . . 13 | |||
| Appendix A. Operating System Specific Implementation Details . . 15 | Appendix A. Operating System Specific Implementation Details . . 15 | |||
| A.1. iOS Implementation Details . . . . . . . . . . . . . . . 15 | A.1. iOS Implementation Details . . . . . . . . . . . . . . . 15 | |||
| A.2. Android Implementation Details . . . . . . . . . . . . . 15 | A.2. Android Implementation Details . . . . . . . . . . . . . 15 | |||
| Appendix B. Acknowledgements . . . . . . . . . . . . . . . . . . 15 | A.3. Windows Implementation Details . . . . . . . . . . . . . 16 | |||
| Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 16 | A.4. macOS Implementation Details . . . . . . . . . . . . . . 16 | |||
| Appendix B. Acknowledgements . . . . . . . . . . . . . . . . . . 17 | ||||
| Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 17 | ||||
| 1. Introduction | 1. Introduction | |||
| The OAuth 2.0 [RFC6749] authorization framework, documents two | The OAuth 2.0 [RFC6749] authorization framework, documents two | |||
| approaches in Section 9 for native apps to interact with the | approaches in Section 9 for native apps to interact with the | |||
| authorization endpoint: via an embedded user-agent, or an external | authorization endpoint: via an embedded user-agent, or an external | |||
| user-agent. | user-agent. | |||
| This document recommends external user-agents like in-app browser | This document recommends external user-agents like in-app browser | |||
| tabs as the only secure and usable choice for OAuth. It documents | tabs as the only secure and usable choice for OAuth. It documents | |||
| skipping to change at page 7, line 24 ¶ | skipping to change at page 7, line 24 ¶ | |||
| 7.1. App-declared Custom URI Scheme Redirection | 7.1. App-declared Custom URI Scheme Redirection | |||
| Most major mobile and desktop computing platforms support inter-app | Most major mobile and desktop computing platforms support inter-app | |||
| communication via URIs by allowing apps to register custom URI | communication via URIs by allowing apps to register custom URI | |||
| schemes. When the system browser or another app attempts to follow a | schemes. When the system browser or another app attempts to follow a | |||
| URI with a custom scheme, the app that registered it is launched to | URI with a custom scheme, the app that registered it is launched to | |||
| handle the request. This document is only relevant on platforms that | handle the request. This document is only relevant on platforms that | |||
| support this pattern. | support this pattern. | |||
| In particular, the custom URI scheme pattern is supported on the | In particular, the custom URI scheme pattern is supported on Android | |||
| mobile platforms Android [Android.URIScheme], iOS [iOS.URIScheme], | [Android.URIScheme], iOS [iOS.URIScheme], Windows Universal Platform | |||
| and Windows Phone [WindowsPhone.URIScheme]. Desktop operating | (UWP) [WindowsUWP.URIScheme] and macOS [macOS.URIScheme]. | |||
| systems Windows [Windows.URIScheme] and OS X [OSX.URIScheme] also | ||||
| support custom URI schemes. | ||||
| 7.1.1. Using Custom URI Schemes for Redirection | 7.1.1. Using Custom URI Schemes for Redirection | |||
| To perform an OAuth 2.0 Authorization Request on a supported | To perform an OAuth 2.0 Authorization Request on a supported | |||
| platform, the native app launches the system browser with a normal | platform, the native app launches the system browser with a normal | |||
| OAuth 2.0 Authorization Request, but provides a redirection URI that | OAuth 2.0 Authorization Request, but provides a redirection URI that | |||
| utilizes a custom URI scheme that is registered by the calling app. | utilizes a custom URI scheme that is registered by the calling app. | |||
| When the authentication server completes the request, it redirects to | When the authentication server completes the request, it redirects to | |||
| the client's redirection URI like it would any redirect URI, but as | the client's redirection URI like it would any redirect URI, but as | |||
| skipping to change at page 10, line 38 ¶ | skipping to change at page 10, line 34 ¶ | |||
| credentials than they need, potentially increasing the attack | credentials than they need, potentially increasing the attack | |||
| surface. | surface. | |||
| In typical web-view based implementations of embedded user-agents, | In typical web-view based implementations of embedded user-agents, | |||
| the host application can: log every keystroke entered in the form to | the host application can: log every keystroke entered in the form to | |||
| capture usernames and passwords; automatically submit forms and | capture usernames and passwords; automatically submit forms and | |||
| bypass user-consent; copy session cookies and use them to perform | bypass user-consent; copy session cookies and use them to perform | |||
| authenticated actions as the user. | authenticated actions as the user. | |||
| Encouraging users to enter credentials in an embedded web-view | Encouraging users to enter credentials in an embedded web-view | |||
| without the usual address bar and other identity features that | without the usual address bar and visible certificate validation | |||
| browsers have makes it impossible for the user to know if they are | features that browsers have makes it impossible for the user to know | |||
| signing in to the legitimate site, and even when they are, it trains | if they are signing in to the legitimate site, and even when they | |||
| them that it's OK to enter credentials without validating the site | are, it trains them that it's OK to enter credentials without | |||
| first. | validating the site first. | |||
| Aside from the security concerns, web-views do not share the | Aside from the security concerns, web-views do not share the | |||
| authentication state with other apps or the system browser, requiring | authentication state with other apps or the system browser, requiring | |||
| the user to login for every authorization request and leading to a | the user to login for every authorization request and leading to a | |||
| poor user experience. | poor user experience. | |||
| Due to the above, use of embedded user-agents is NOT RECOMMENDED, | Due to the above, use of embedded user-agents is NOT RECOMMENDED, | |||
| except where a trusted first-party app acts as the external user- | except where a trusted first-party app acts as the external user- | |||
| agent for other apps, or provides single sign-on for multiple first- | agent for other apps, or provides single sign-on for multiple first- | |||
| party apps. | party apps. | |||
| skipping to change at page 11, line 46 ¶ | skipping to change at page 11, line 40 ¶ | |||
| [RFC7636]) standard was created specifically to mitigate against this | [RFC7636]) standard was created specifically to mitigate against this | |||
| attack. It is a Proof of Possession extension to OAuth 2.0 that | attack. It is a Proof of Possession extension to OAuth 2.0 that | |||
| protects the code grant from being used if it is intercepted. It | protects the code grant from being used if it is intercepted. It | |||
| achieves this by having the client generate a secret verifier which | achieves this by having the client generate a secret verifier which | |||
| it passes in the initial authorization request, and which it must | it passes in the initial authorization request, and which it must | |||
| present later when redeeming the authorization code grant. An app | present later when redeeming the authorization code grant. An app | |||
| that intercepted the authorization code would not be in possession of | that intercepted the authorization code would not be in possession of | |||
| this secret, rendering the code useless. | this secret, rendering the code useless. | |||
| Both the client and the Authorization Server MUST support PKCE | Both the client and the Authorization Server MUST support PKCE | |||
| [RFC7636] to use custom URI schemes, or loopback redirects. | [RFC7636] to use custom URI schemes, or loopback IP redirects. | |||
| Authorization Servers SHOULD reject authorization requests using a | Authorization Servers SHOULD reject authorization requests using a | |||
| custom scheme, or localhost as part of the redirection URI if the | custom scheme, or loopback IP as part of the redirection URI if the | |||
| required PKCE parameters are not present, returning the error message | required PKCE parameters are not present, returning the error message | |||
| as defined in Section 4.4.1 of PKCE [RFC7636]. It is RECOMMENDED to | as defined in Section 4.4.1 of PKCE [RFC7636]. It is RECOMMENDED to | |||
| use PKCE [RFC7636] for app-claimed HTTPS redirect URIs, even though | use PKCE [RFC7636] for app-claimed HTTPS redirect URIs, even though | |||
| these are not generally subject to interception, to protect against | these are not generally subject to interception, to protect against | |||
| attacks on inter-app communication. | attacks on inter-app communication. | |||
| 8.3. Phishability of In-App Browser Tabs | 8.3. Phishability of In-App Browser Tabs | |||
| While in-app browser tabs provide a secure authentication context, as | While in-app browser tabs provide a secure authentication context, as | |||
| the user initiates the flow from a native app, it is possible for | the user initiates the flow from a native app, it is possible for | |||
| skipping to change at page 14, line 6 ¶ | skipping to change at page 14, line 6 ¶ | |||
| <http://www.rfc-editor.org/info/rfc3986>. | <http://www.rfc-editor.org/info/rfc3986>. | |||
| 11.2. Informative References | 11.2. Informative References | |||
| [RFC6819] Lodderstedt, T., Ed., McGloin, M., and P. Hunt, "OAuth 2.0 | [RFC6819] Lodderstedt, T., Ed., McGloin, M., and P. Hunt, "OAuth 2.0 | |||
| Threat Model and Security Considerations", RFC 6819, | Threat Model and Security Considerations", RFC 6819, | |||
| DOI 10.17487/RFC6819, January 2013, | DOI 10.17487/RFC6819, January 2013, | |||
| <http://www.rfc-editor.org/info/rfc6819>. | <http://www.rfc-editor.org/info/rfc6819>. | |||
| [iOS.URIScheme] | [iOS.URIScheme] | |||
| "Inter-App Communication", February 2015, <https://develop | "Inter-App Communication", July 2016, <https://developer.a | |||
| er.apple.com/library/ios/documentation/iPhone/Conceptual/ | pple.com/library/ios/documentation/iPhone/Conceptual/ | |||
| iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter- | iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter- | |||
| AppCommunication.html>. | AppCommunication.html>. | |||
| [OSX.URIScheme] | [macOS.URIScheme] | |||
| "Launch Services Concepts", February 2015, <https://develo | "Launch Services Concepts", July 2016, <https://developer. | |||
| per.apple.com/library/mac/documentation/Carbon/Conceptual/ | apple.com/library/mac/documentation/Carbon/Conceptual/Laun | |||
| LaunchServicesConcepts/LSCConcepts/LSCConcepts.html#//appl | chServicesConcepts/LSCConcepts/LSCConcepts.html#//apple_re | |||
| e_ref/doc/uid/TP30000999-CH202-CIHFEEAD>. | f/doc/uid/TP30000999-CH202-CIHFEEAD>. | |||
| [Android.URIScheme] | [Android.URIScheme] | |||
| "Intents and Intent Filters", February 2015, | "Intents and Intent Filters", July 2016, | |||
| <http://developer.android.com/guide/components/ | <http://developer.android.com/guide/components/ | |||
| intents-filters.html#ires>. | intents-filters.html#ires>. | |||
| [WindowsPhone.URIScheme] | [WindowsUWP.URIScheme] | |||
| "Auto-launching apps using file and URI associations for | "Handle URI activation", July 2016, | |||
| Windows Phone 8", February 2015, | <https://msdn.microsoft.com/en-us/windows/uwp/launch- | |||
| <https://msdn.microsoft.com/en-us/library/windows/apps/ | resume/handle-uri-activation>. | |||
| jj206987(v=vs.105).aspx>. | ||||
| [Windows.URIScheme] | ||||
| "Registering an Application to a URI Scheme", February | ||||
| 2015, <https://msdn.microsoft.com/en-us/library/ie/ | ||||
| aa767914%28v=vs.85%29.aspx>. | ||||
| [IANA.URISchemes] | [IANA.URISchemes] | |||
| "Uniform Resource Identifier (URI) Schemes", February | "Uniform Resource Identifier (URI) Schemes", July 2016, | |||
| 2015, <http://www.iana.org/assignments/uri-schemes/ | <http://www.iana.org/assignments/uri-schemes/ | |||
| uri-schemes.xhtml>. | uri-schemes.xhtml>. | |||
| [ChromeCustomTab] | [ChromeCustomTab] | |||
| "Chrome Custom Tabs", July 2015, | "Chrome Custom Tabs", July 2016, | |||
| <https://developer.chrome.com/multidevice/android/ | <https://developer.chrome.com/multidevice/android/ | |||
| customtabs>. | customtabs>. | |||
| [SFSafariViewController] | [SFSafariViewController] | |||
| "SafariServices Changes", July 2015, <https://developer.ap | "SafariServices Changes", July 2016, | |||
| ple.com/library/prerelease/ios/releasenotes/General/ | <https://developer.apple.com/library/ios/documentation/ | |||
| iOS90APIDiffs/frameworks/SafariServices.html>. | SafariServices/Reference/SFSafariViewController_Ref/>. | |||
| [Android.AppLinks] | [Android.AppLinks] | |||
| "App Links", July 2015, | "App Links", July 2015, | |||
| <https://developer.android.com/preview/features/app- | <https://developer.android.com/preview/features/app- | |||
| linking.html>. | linking.html>. | |||
| [CustomTabsService] | ||||
| "CustomTabsService", July 2016, | ||||
| <https://developer.android.com/reference/android/support/ | ||||
| customtabs/CustomTabsService.html>. | ||||
| [UniversalLinks] | ||||
| "Universal Links", July 2016, <https://developer.apple.com | ||||
| /library/ios/documentation/General/Conceptual/AppSearch/ | ||||
| UniversalLinks.html>. | ||||
| Appendix A. Operating System Specific Implementation Details | Appendix A. Operating System Specific Implementation Details | |||
| Most of this document attempts to lay out best practices in an | Most of this document attempts to lay out best practices in an | |||
| generic manner, referencing technology available on most operating | generic manner, referencing technology available on most operating | |||
| systems. This non-normative section contains OS-specific | systems. This non-normative section contains OS-specific | |||
| implementation details that are accurate at the time of authorship. | implementation details that are accurate at the time of authorship. | |||
| It is expected that this OS-specific information will change, but | It is expected that this OS-specific information will change, but | |||
| that the overall principles described in this document for using | that the overall principles described in this document for using | |||
| external user-agents will remain valid. | external user-agents will remain valid. | |||
| A.1. iOS Implementation Details | A.1. iOS Implementation Details | |||
| From iOS 9, apps can invoke the system browser without the user | Claimed HTTPS and custom URI scheme redirects are both viable choices | |||
| leaving the app through SFSafariViewController | for OAuth on iOS. Developers can claim HTTPS links using Universal | |||
| [SFSafariViewController], which implements the browser-view pattern. | Links [UniversalLinks], available since iOS 9, and can use custom URI | |||
| This class has all the properties of the system browser, and is | scheme [iOS.URIScheme] redirects for backwards compatibility. | |||
| considered an 'external user-agent', even though it is presented | Clients SHOULD use Universal Links for authorization requests on iOS | |||
| within the host app. Regardless of whether the system browser is | 9 and beyond, with the custom URI scheme redirect substituted on | |||
| opened, or SFSafariViewController, the return of the token goes | older versions. In both cases, the app claims the redirect in the | |||
| through the same system. | application manifest. | |||
| As a user experience optimisation, since iOS 9, apps can invoke the | ||||
| system browser without the user leaving the app through | ||||
| SFSafariViewController [SFSafariViewController], which implements the | ||||
| browser-view pattern. This class has all the properties of the | ||||
| system browser, and is an 'external user-agent', even though it is | ||||
| presented within the host app. Regardless of whether the user | ||||
| completes the request in the system browser (as is their choice), or | ||||
| the SFSafariViewController, the return of the token via custom URI | ||||
| scheme or claimed HTTPS link is the same. | ||||
| A.2. Android Implementation Details | A.2. Android Implementation Details | |||
| Chrome 45 introduced the concept of Chrome Custom Tab | Claimed HTTPS and custom URI scheme redirects are both viable choices | |||
| [ChromeCustomTab], which follows the browser-view pattern and allows | for OAuth on Android. Developers can claim HTTPS links using App | |||
| authentication without the user leaving the app. | Links [Android.AppLinks], available since Android 6.0 though browser | |||
| support varies, and custom URI scheme [Android.URIScheme] redirects | ||||
| are broadly supported. Clients SHOULD support custom URI scheme | ||||
| redirects for broad compatibility and MAY upgrade to using claimed | ||||
| HTTPs redirects in supported environments. For both redirect | ||||
| options, the app claims the redirect in the application manifest. | ||||
| The return of the token can go through the custom URI scheme or | As a user experience optimisation, apps SHOULD try to launch the | |||
| claimed HTTPS URI (including those registered with the App Link | authorization request in a Custom Tab. Custom Tab is an | |||
| [Android.AppLinks] system), or the navigation events can be observed | implementation of the browser-view pattern, providing a secure | |||
| by the host app. It is RECOMMENDED that the custom URI, or claimed | browser tab displayed in the context of the app. Chrome is an | |||
| HTTPS URI options be used for better portability, to allow the user | example of a browser that supports [ChromeCustomTab] CustomTabs. | |||
| to open the authorization request in the Chrome app, and to prevent | ||||
| accidental observation of intermediate tokens on URI parameters. | ||||
| At the time of writing, Android does allow apps to claim HTTPs links | Android Browser vendors SHOULD implement the CustomTabsService | |||
| (App Links), but not in a way that is usable for OAuth, the native | [CustomTabsService] to provide this functionality to their users. | |||
| app is only opened if the intent is fired from outside the browser. | ||||
| A.3. Windows Implementation Details | ||||
| Apps written on the Universal Windows Platform (UWP) can claim custom | ||||
| URI schemes [WindowsUWP.URIScheme] in their application manifest. | ||||
| This redirect choice will also open the app when the user taps the | ||||
| link. The scheme is limited to 39 characters, and may include the | ||||
| `.` character. | ||||
| UWP apps can launch the authorization request in the user's default | ||||
| browser like so: | ||||
| Uri authorizationRequest = ... | ||||
| var success = Windows.System.Launcher.LaunchUriAsync(authorizationRequest) | ||||
| The loopback IP redirect is a common choice for traditional Desktop | ||||
| apps, and listening on a loopback port is permitted by default | ||||
| Windows firewall rules. | ||||
| Traditional apps can launch the URI in the user's default browser | ||||
| like so: | ||||
| string authorizationRequest = ... | ||||
| System.Diagnostics.Process.Start(authorizationRequest); | ||||
| When using the "Process.Start" method, care must be taken that the | ||||
| input is a valid URL, including correct URI encoding of the | ||||
| parameters. This is especially important when the URL includes user- | ||||
| supplied information such as a login hint. | ||||
| A.4. macOS Implementation Details | ||||
| Both the loopback IP and custom URI scheme redirect choices are | ||||
| viable on macOS. Custom URI schemes [macOS.URIScheme] are registered | ||||
| in the application manifest. Listening on the loopback IP typically | ||||
| does not require any firewall changes. | ||||
| Apps can launch the authorization request like so: | ||||
| NSURL *authorizationRequest = ... | ||||
| BOOL success = [[NSWorkspace sharedWorkspace] openURL:authorizationRequest]; | ||||
| Appendix B. Acknowledgements | Appendix B. Acknowledgements | |||
| The author would like to acknowledge the work of Marius Scurtescu, | The author would like to acknowledge the work of Marius Scurtescu, | |||
| and Ben Wiley Sittler whose design for using custom URI schemes in | and Ben Wiley Sittler whose design for using custom URI schemes in | |||
| native OAuth 2.0 clients formed the basis of Section 7.1. | native OAuth 2.0 clients formed the basis of Section 7.1. | |||
| The following individuals contributed ideas, feedback, and wording | The following individuals contributed ideas, feedback, and wording | |||
| that shaped and formed the final specification: | that shaped and formed the final specification: | |||
| Naveen Agarwal, John Bradley, Brian Campbell, Adam Dawes, Hannes | Naveen Agarwal, Brian Campbell, Adam Dawes, Hannes Tschofenig, Ashish | |||
| Tschofenig, Ashish Jain, Paul Madsen, Breno de Medeiros, Eric Sachs, | Jain, Paul Madsen, Breno de Medeiros, Eric Sachs, Nat Sakimura, Steve | |||
| Nat Sakimura, Steve Wright, Erik Wahlstrom, Andy Zmolek, Sudhi | Wright, Erik Wahlstrom, Andy Zmolek, Sudhi Umarji. | |||
| Umarji. | ||||
| Authors' Addresses | Authors' Addresses | |||
| William Denniss | William Denniss | |||
| 1600 Amphitheatre Pkwy | 1600 Amphitheatre Pkwy | |||
| Mountain View, CA 94043 | Mountain View, CA 94043 | |||
| USA | USA | |||
| Phone: +1 650-253-0000 | Phone: +1 650-253-0000 | |||
| End of changes. 21 change blocks. | ||||
| 67 lines changed or deleted | 123 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ | ||||