RFC 3653
XML-Signature XPath Filter 2.0
RFC 3653: XML-Signature XPath Filter 2.0 π
Okay bestie, this is RFC 3653, XML-Signature XPath Filter 2.0 β¨. It came out in December 2003 as part of the Network Working Group, and it's marked Informational π¦, so it shares info with the internet community without setting an Internet standard. Three authors worked on it πΈ: J. Boyer from PureEdge Solutions, M. Hughes from Betrusted, Inc., and J. Reagle from W3C. It doesn't obsolete or update any other RFC, since its header doesn't list any π .
Status of this Memo
This memo is info for the internet community. It does not specify an Internet standard of any kind π. Distribution of it is unlimited, so share away π.
Copyright Notice
Copyright (C) The Internet Society (2003). All Rights Reserved. π
Abstract
Okay so XML Signature gives you a standard way to say which info in a document gets digitally signed, and how to store those signatures in XML π§. Sometimes an app only wants to sign a piece of an XML document, and the XML Signature spec handles that with the XPath transform. The problem? That transform is kinda hard to implement efficiently with the tools we already have π. So this spec defines a brand new XML Signature transform π₯. The goal is making document subsetting easier to build efficiently, with implementations that interoperate under similar performance profiles. Iconic β¨.
This document is the W3C XML Signature XPath-Filter 2.0 Recommendation. W3C Members and other interested parties reviewed it, and the Director endorsed it as a W3C Recommendation π. It's a stable document, so you can use it as reference material or cite it as a normative reference from another document. W3C's job with a Recommendation is to draw attention to the spec and promote its widespread deployment, which makes the Web more functional and more interoperable π.
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1. Acknowledgements (Informative) . . . . . . . . . . . . 4
1.2. W3C Status . . . . . . . . . . . . . . . . . . . . . . 4
2. Terminology. . . . . . . . . . . . . . . . . . . . . . . . . 4
3. Specification of Signature Filter Transform. . . . . . . . . 5
3.1. Algorithm Identifier . . . . . . . . . . . . . . . . . 5
3.2. Syntax of Signature Filter Transform . . . . . . . . . 5
3.3. Input and Evaluation Context of Signature Filter
Transform. . . . . . . . . . . . . . . . . . . . . . . 7
3.4. Processing Model of Signature Filter Transform . . . . 7
4. Examples of Signature Filter Transform . . . . . . . . . . . 9
5. Normative References . . . . . . . . . . . . . . . . . . . . 13
6. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 14
7. Full Copyright Statement . . . . . . . . . . . . . . . . . . 15
1. Introduction π¦
Let's start with the basics. The XML Recommendation [XML] defines the syntax for a class of objects called XML documents. The Namespaces in XML Recommendation [XML-NS] adds extra syntax and semantics for XML documents π . Then the XML Signature Recommendation [XML-DSig] gives standard ways to say what info gets digitally signed, including picking out just part of an XML document to sign with an XPath transform π«Ά.
This spec describes a new signature filter transform. Like the XPath transform [XML-DSig, section 6.6.3], it gives you a way to compute the portion of a document to be signed πΈ. To keep implementations efficient and simple to build, this transform doesn't evaluate an [XPath] expression against every node of the XML parse tree (as defined by the [XPath] data model) π§ . Instead, a sequence of XPath expressions picks out the roots of document subtrees (called location sets in the [XPointer] language) π³. Those location sets get combined with set intersection, subtraction and union, and then they filter the input node-set π₯.
Here's how it's different from the XPath transform, bestie:
- A sequence of XPath operations can run in one single transform, so complex filters are easier to express and optimize β¨.
- The XPath expressions get evaluated against the input document, which gives you a set of nodes. The old way used them as a boolean test against each node of the input node-set π.
- To boost efficiency, expanding a node to include every node that has it as an ancestor is now implicit. That means it can be done by faster means than running an XPath expression for each document node π.
- The resulting node-sets can be combined with the three fundamental set operations (intersection, subtraction, and union) and then applied as a filter against the input node-set. So things like signing an entire document except for a specified subset can be expressed more clearly and efficiently π.
Just like the original XPath transform, the main goal here is making sure only specifically defined changes to the input XML document are allowed after the signature is affixed π. You do that by excluding exactly the nodes that are allowed to change once the signature is affixed, and including all the other input nodes in the output π. The signature filter transform author is responsible for making sure no nodes get excluded that could change how the transform output gets interpreted in the application context π.
Picture this motivating scenario π: an app wants to affix two enveloped signatures to the document, and any other change to the document has to make the signatures invalid. When the app creates the first signature, that signature is automatically left out of its own digest calculations. But the second signature element also needs to be excluded from the first signature's digest calculations π. This spec handles that efficiently with the set subtraction operation.
This transform can also specify a set of nodes to include in a signature, with every non-specified node excluded π. That's super useful for isolating part of a document, like one chapter, or a payload in a protocol message. You express it with the set intersection operation β¨.
Complete familiarity with the first XML Signature XPath Transform [XML-DSig, section 6.6.3] is required π.
NOTE: XPath Filter 2.0 depends on the details of XPath, so be sure to take the XPath Errata into account at <http://www.w3.org/1999/11/REC-xpath-19991116-errata> π.
1.1. Acknowledgements (Informative) π«Ά
These lovely people gave valuable feedback that made this spec way better π:
- Christian Geuer-Pollmann, Universitat Siegen
- Donald Eastlake, 3rd, Motorola
- Gregor Karlinger, IAK TU Graz
- Aleksey Sanin
1.2. W3C Status πΈ
The World Wide Web Consortium Recommendation that matches this RFC lives here:
http://www.w3.org/TR/xmldsig-filter2/
2. Terminology π
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14, RFC 2119 [Keywords]. Those are the official rule words, so read them exactly as the standard defines them π .
The XPath 1.0 Recommendation [XPath] defines the term node-set as "(an unordered collection of nodes without duplicates)" π§Ί. It also sets up a data model for representing an input XML document as a set of nodes of various types: element, attribute, namespace, text, comment, processing instruction, and root π³.
An input document is the document that contains all the nodes this transform can process π. A document subset is a portion of an XML document indicated by an XPath node-set, and it might not include every node in the document βοΈ. For example, the input node-set is a collection of XPath nodes from the input document that gets passed in as a parameter to this transform π¦. A subtree rooted by a given node is a document subset containing that node and every node that has it as an ancestor π². Subtree expansion is the process of growing a node-set to include all subtrees rooted at any node in the node-set π±. For example, if you expand a node-set holding just one element node, you get a node-set with that element, its attribute nodes, its namespace nodes, and all its descendants (including their attribute nodes and namespace nodes) π.
The XML Signature Recommendation [XML-DSig] defines a reference as a sequence of steps performed to get an octet stream to be digitally signed π§΅. A transform is an identified algorithm used as one step in the reference processing model βοΈ. A transform takes either an octet stream or an XPath node-set as input, and it produces either an octet stream or an XPath node-set as output. The reference processing model automatically converts the final output to an octet stream if it's an XPath node-set π.
3. Specification of Signature Filter Transform π
The transform works by computing a node-set that filters the input node-set π―. The output node-set holds only the nodes that are in both the input node-set and the filter node-set. In other words, the output node-set is the intersection of the input node-set and the computed filter node-set π.
The filter node-set gets computed by evaluating a sequence of XPath expressions and combining their results β¨. To start, a node-set gets created containing the entire input document π. Then, in order, each XPath expression gets evaluated, subtree-expanded, and used to transform the filter node-set using a specified set operation: intersection, subtraction, or union π§©. Once all the XPaths have been applied, the resulting node-set becomes the filter node-set π.
3.1. Algorithm Identifier π
The XML Signature Recommendation [XML-DSig] uses a [URI] to identify each algorithm that gets performed when creating or validating a signature π. The signature filter transform is identified like this π:
http://www.w3.org/2002/06/xmldsig-filter2
3.2. Syntax of Signature Filter Transform β¨
okay so the signature filter transform is basically a little stack of one or more XPath elements π Each one holds character data that's an XPath expression, and each has a Filter attribute that can be intersect, subtract, or union. That attribute picks the set operation applied to the resulting node-set when the filter node-set gets computed π¦ Here's a cute example that signs the whole input node-set EXCEPT elements with the ids foo and bar (plus everything under them, so their descendants come along too) π
<XPath Filter="subtract"
xmlns="http://www.w3.org/2002/06/xmldsig-filter2">
id("foo bar")
</XPath>
Schema Definition:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE schema
PUBLIC "-//W3C//DTD XMLSchema 200102//EN"
"http://www.w3.org/2001/XMLSchema.dtd"
[
<!ATTLIST schema
xmlns:xf CDATA #FIXED 'http://www.w3.org/2002/06/xmldsig-filter2'>
<!ENTITY xf 'http://www.w3.org/2002/06/xmldsig-filter2'>
<!ENTITY % p ''>
<!ENTITY % s ''>
]>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xf="http://www.w3.org/2002/06/xmldsig-filter2"
targetNamespace="http://www.w3.org/2002/06/xmldsig-filter2"
version="0.1" elementFormDefault="qualified">
<element name="XPath"
type="xf:XPathType"/>
<complexType name="XPathType">
<simpleContent>
<extension base="string">
<attribute name="Filter">
<simpleType>
<restriction base="string">
<enumeration value="intersect"/>
<enumeration value="subtract"/>
<enumeration value="union"/>
</restriction>
</simpleType>
</attribute>
</extension>
</simpleContent>
</complexType>
</schema>
DTD:
<!ELEMENT XPath (#PCDATA) >
<!ATTLIST XPath
Filter (intersect|subtract|union) #REQUIRED >
3.3. Input and Evaluation Context of Signature Filter Transform πΈ
so the input to this transform is an XPath node-set over the input document π If the input document is an octet stream, the application MUST convert that octet stream into an XPath node-set that holds ALL of the document nodes (comment nodes included, obviously) π The evaluation context for the XPath expressions in the filter transform is:
- A context node equal to the root node of the document whose node-set was provided as input to this transform. The root node is the parent of the document element and any comment and processing instruction nodes outside of the document element.
- A context position, initialized to 1.
- A context size, initialized to 1.
- A library of functions equal to the function set defined in [XPath] plus a function named here().
- A set of variable bindings. No means for initializing these is defined. Thus, the set of variable bindings used when evaluating the XPath expression is empty, and use of a variable reference in the XPath expression results in an error.
- The set of namespace declarations in scope for the XPath element.
the here() function is the cute one π§ Here's how it's defined:
Function: node-set here()
The here() function returns a node-set containing the attribute or processing instruction node or the parent element of the text node that directly bears the XPath expression. In this transform, this will be the XPath element. This expression results in an error if the containing XPath expression does not appear in the same XML document against which the XPath expression is being evaluated.
3.4. Processing Model of Signature Filter Transform π
okay this is the main event π₯ Using the evaluation context we just went over, the signature filter transform evaluates the XPath expressions sitting in the character content of the XPath elements, and uses them to compute a filter node-set F. That F then filters the input node-set I, giving an output node-set O:
- Initialize the filter node-set F to consist of all nodes in the input document.
- Iterate through each XPath expression, X, in sequence, and update the filter node-set F as follows:
- Evaluate the XPath expression X. The result is a node-set S.
- Compute the set S' consisting of all nodes in the input document that are either present in S or that have an ancestor in S. This is equal to the union of all the document subtrees rooted by a node in S.
- If the Filter attribute value is intersect, then compute the intersection of the selected subtrees, S', with the filter node-set F. The result will include only those nodes that are in both the filter node-set and the selected subtrees:
F' = F INTERSECT S'. - If the Filter attribute value is subtract, then compute the subtraction of the selected subtrees, S', from the filter node-set F. The result will include only those nodes that are in the filter node-set, but not the selected subtrees:
F' = F - S'. - Otherwise, if the Filter attribute value is union, then compute the union of the selected subtrees, S', with the filter node-set F. The result will include all those nodes that are in either the filter node-set, the selected subtrees, or both:
F' = F UNION S'. - Update the filter node-set F to be the new node-set F'.
- Finally, after applying all the XPath expressions, compute the output node-set O to be the intersection of the computed filter node-set, F, with the input node-set, I. The result will include all nodes from the input node-set that are also in the filter node-set:
O = I INTERSECT F. - An empty input node-set will always result in an empty output node-set.
In this processing model, the conversion from a subtree interpretation of the XPath expressions to a node-set containing all nodes that must be used during the set operation, along with actual performance of the set operation, is described explicitly. Implementors SHOULD observe that it is possible to compute the effective result of this operation in a single pass through the input document without performing subtree expansion or any set operations:
- For each XPath expression X, in sequence, evaluate the expression and store the resulting node-set, S, along with the associated set operation.
- Prepend a node-set consisting of just the document node, along with the operation union.
- Create a new, empty filter node-set.
- Process each node in the input node-set document, adding each node to the output node-set F if a flag Z is true. The flag is computed as follows:
- Z is true if and only if the node is present in any subtree-expanded union node-set and all subsequent subtree-expanded intersect node-sets but no subsequent subtree-expanded subtract node-sets, or false otherwise. If there are no subsequent intersect or subtract node-sets, then that part of the test is automatically passed.
- Presence in a subtree-expanded node-set can be efficiently determined without actually expanding the node-set, by simply maintaining a stack or count that identifies whether any nodes from that node-set are an ancestor of the node being processed.
Implementers MAY further observe that, if this transform is followed by a canonicalization operation (e.g., [XML-C14N]), the described filter computation can be efficiently commingled with the document-order canonicalization processing.
4. Examples of Signature Filter Transform π
okay bestie, let's look at some examples π«Ά the first one shows how to make an enveloped signature with the signature filter transform. the here() function identifies the XPath element, and then the location path grabs the nearest ancestor Signature element. because the Filter attribute is subtract, the output is a node-set with every node from the input node-set except the nodes in the subtree rooted by the Signature element that holds this example signature filter transform π
<XPath Filter="subtract"
xmlns="http://www.w3.org/2002/06/xmldsig-filter2"
xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
here()/ancestor::dsig:Signature[1] </XPath>
a good signature reference URI to pair with this subtract filter would be URI="" (the entire signature document, without comments), URI="#xpointer(/)" (the entire signature document, with comments), or any same-document reference that includes the signature itself π¦
now for an intersect filter! it's giving co-signing π an example is a signature that co-signs another signature. here, a Signature element identified by PrimaryBorrowSig has to be signed. the XPath expression grabs that element node, and the transform expands the output node-set so it contains all nodes from the input node-set that are also in the subtree rooted by that element node β¨
<XPath Filter="intersect"
xmlns="http://www.w3.org/2002/06/xmldsig-filter2">
id("PrimaryBorrowerSig") </XPath>
this type of intersect filter is so useful for efficiently signing subsets of a document π whether it's the same document as the signature or an external one. like, if the signature reference URI is URI="document.xml", then that document gets parsed automatically and just the identified element and its descendants get signed. iconic π
union filters on their own are not really useful, ngl π the initial filter node-set is the entire input document, so any union with that does nothing, and the output would just match the input. the union operation is meant to come after a subtract, to bring back a subtree that was removed, except for a lower subtree that's still included in the output πΈ
let's use this document, which has a same-document enveloped signature reference with an XPath filter holding three XPath operations:
<Document>
<ToBeSigned>
<!-- comment -->
<Data />
<NotToBeSigned>
<ReallyToBeSigned>
<!-- comment -->
<Data />
</ReallyToBeSigned>
</NotToBeSigned>
</ToBeSigned>
<ToBeSigned>
<Data />
<NotToBeSigned>
<Data />
</NotToBeSigned>
</ToBeSigned>
<dsig:Signature
xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"
xmlns:dsig-xpath="http://www.w3.org/2002/06/xmldsig-filter2">
<dsig:SignedInfo>
...
<dsig:Reference URI="">
<dsig:Transforms>
<dsig:Transform
Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
<dsig-xpath:XPath
Filter="intersect"> //ToBeSigned </dsig-xpath:XPath>
<dsig-xpath:XPath
Filter="subtract"> //NotToBeSigned </dsig-xpath:XPath>
<dsig-xpath:XPath
Filter="union"> //ReallyToBeSigned </dsig-xpath:XPath>
</dsig:Transform>
</dsig:Transforms>
...
</dsig:Reference>
</dsig:SignedInfo>
...
</dsig:Signature> </Document>
first up, intersect π it computes the intersection of the XPath-selected subtrees with the filter node-set. the filter node-set starts out as the whole input document, and the XPath expression lands on the two ToBeSigned elements. those get expanded to include all their descendants and then intersected with the filter node-set, which gives us:
<ToBeSigned>
<!-- comment -->
<Data />
<NotToBeSigned>
<ReallyToBeSigned>
<!-- comment -->
<Data />
</ReallyToBeSigned>
</NotToBeSigned>
</ToBeSigned><ToBeSigned>
<Data />
<NotToBeSigned>
<Data />
</NotToBeSigned>
</ToBeSigned>
next, subtract π₯ it subtracts the XPath-selected subtrees from the filter node-set. this time the XPath expression lands on the two NotToBeSigned elements. those get expanded to include all their descendants and then subtracted from the filter node-set:
<ToBeSigned>
<!-- comment -->
<Data />
</ToBeSigned><ToBeSigned>
<Data />
</ToBeSigned>
then union π it computes the union of the XPath-selected subtrees with the filter node-set. here the XPath expression lands on the ReallyToBeSigned element. that gets expanded to include all its descendants and is added back into the filter node-set:
<ToBeSigned>
<!-- comment -->
<Data />
<ReallyToBeSigned>
<!-- comment -->
<Data />
</ReallyToBeSigned>
</ToBeSigned><ToBeSigned>
<Data />
</ToBeSigned>
last step, the resulting filter node-set gets used to transform the input node-set β¨ in this example, the input node-set is the entire document with comments removed. so the transformed node-set is every node from the input document, minus comments, that is also in the filter node-set:
<ToBeSigned>
<Data />
<ReallyToBeSigned>
<Data />
</ReallyToBeSigned>
</ToBeSigned><ToBeSigned>
<Data />
</ToBeSigned>
note that the result has no nodes that weren't in the input node-set π the filter node-set had comments in it, but those weren't in the input node-set, so they don't show up in the output either.
this signature filter doesn't give you any extra power over the original XPath transform, btw π you could replicate this reference with the XPath transform like so:
<dsig:Reference URI="">
<dsig:Transforms>
<dsig:Transform
Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<dsig:XPath>
(ancestor-or-self::ToBeSigned and
not (ancestor-or-self::NotToBeSigned))
or ancestor-or-self::ReallyToBeSigned
</dsig:XPath>
</dsig:Transform>
</dsig:Transforms>
... </dsig:Reference>
the real win of the signature filter transform over the XPath transform is performance π the XPath transform has to evaluate a potentially complex expression against every node in the input set, which has proved costly in practice for lots of useful operations. this spec's filter only evaluates simple XPath expressions and then runs some basic set operations (or their equivalent), which can be implemented way more efficiently π
5. Normative References π
these are the references the spec leans on, bestie. here's the full list, exactly as written:
[Keywords] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[URI] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
Resource Identifiers (URI): Generic Syntax", RFC 2396,
August 1998.
[XML] "Extensible Markup Language (XML) 1.0 (Second Edition)",
T. Bray, E. Maler, J. Paoli, and C. M. Sperberg-
McQueen. W3C Recommendation, October 2000. Available at
<http://www.w3.org/TR/2000/REC-xml-20001006>.
[XML-C14N] Boyer, J., "Canonical XML", RFC 3076, March 2001. Also a
W3C Recommendation available at
<http://www.w3.org/TR/2001/REC-xml-c14n-20010315>.
[XML-DSig] Eastlake, J., Reagle, J. and D. Solo, "XML-Signature
Syntax and Processing", RFC 3275, March 2002. Also a W3C
Recommendation available at
<http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/>.
[XML-NS] "Namespaces in XML", T. Bray, D. Hollander, and A.
Layman. W3C Recommendation, January 1999. Available at
<http://www.w3.org/TR/1999/REC-xml-names-19990114/>.
[XPath] "XML Path Language (XPath) Version 1.0", J. Clark and S.
DeRose. W3C Recommendation, November 1999. Available at
<http://www.w3.org/TR/1999/REC-xpath-19991116>. (Note
also XPath Errata at <http://www.w3.org/1999/11/REC-
xpath-19991116-errata>.)
[XPointer] "XML Pointer Language (XPointer)", S. DeRose, R. Daniel,
and E. Maler. W3C Candidate Recommendation, January
2001. Available at <http://www.w3.org/TR/2001/CR-xptr-
20010911/>.
6. Authors' Addresses π
meet the people who wrote this, iykyk π§
John Boyer
PureEdge Solutions Inc.
4396 West Saanich Rd.
Victoria, BC, Canada V8Z 3E9
Phone: +1-888-517-2675
EMail: jboyer@PureEdge.com
Merlin Hughes
Betrusted, Inc.
11000 Broken Land Parkway Suite 900
Columbia, MD 21044
Phone: +1-443-367-7000
EMail: Merlin.Hughes@betrusted.com
Joseph M. Reagle Jr., W3C
Massachusetts Institute of Technology
Laboratory for Computer Science
NE43-350, 545 Technology Square
Cambridge, MA 02139
Phone: +1.617.258.7621
EMail: reagle@mit.edu
7. Full Copyright Statement πΈ
the legal bit, but make it cute π
Copyright (C) The Internet Society (2003). All Rights Reserved.
so, this document and its translations can be copied and handed out to others, and derivative works that comment on or explain it, or help implement it, can be written, copied, published, and distributed, in whole or in part, with no restrictions of any kind π¦ the one condition is that the copyright notice and this paragraph stay on all those copies and derivative works. the document itself, though, may not be modified in any way, like by removing the copyright notice or the references to the Internet Society or other Internet organizations. the exceptions are when it's needed for developing Internet standards (then the copyright procedures in the Internet Standards process have to be followed) or when it's translated into languages other than English π
the permissions above are perpetual and won't be revoked by the Internet Society or its successors or assignees βΎοΈ
this document and the information in it are provided on an "AS IS" basis, and the Internet Society and the Internet Engineering Task Force disclaim all warranties, as shown here:
THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Hmm, to keep it verbatim, the disclaimer sentence is: "This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
Let me restate: the disclaimer above, verbatim, is the authoritative text. Keep it as:
This document and the information contained herein is provided on an
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Acknowledgement β¨
the RFC Editor function is currently funded by the Internet Society, so big thanks to them π«Ά
π¦ where this page comes from
- ietf: rfc3653 2003-12
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms