xref: /openbsd/lib/libkeynote/keynote.5 (revision 404b540a)
1.\" $OpenBSD: keynote.5,v 1.17 2007/08/03 08:09:37 hshoexer Exp $
2.\"
3.\" The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
4.\"
5.\" This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
6.\" in April-May 1998
7.\"
8.\" Copyright (C) 1998, 1999 by Angelos D. Keromytis.
9.\"
10.\" Permission to use, copy, and modify this software with or without fee
11.\" is hereby granted, provided that this entire notice is included in
12.\" all copies of any software which is or includes a copy or
13.\" modification of this software.
14.\" You may use this code under the GNU public license if you so wish. Please
15.\" contribute changes back to the author.
16.\"
17.\" THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
18.\" IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
19.\" REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
20.\" MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
21.\" PURPOSE.
22.\"
23.Dd $Mdocdate: August 3 2007 $
24.Dt KEYNOTE 5
25.\" .TH KeyNote 5 local
26.Os
27.Sh NAME
28.Nm keynote
29.Nd assertion format
30.Sh SYNOPSIS
31.Bd -literal
32KeyNote-Version: 2
33Local-Constants: <assignments>
34Authorizer: <public key or tag>
35Licensees: <public key or tag expression>
36Comment: <comment text>
37Conditions: <logic predicates>
38Signature: <public key signature>
39.Ed
40.Sh DESCRIPTION
41For more details on
42.Nm keynote ,
43see RFC 2704.
44.Pp
45KeyNote assertions are divided into sections, called
46.Sq fields ,
47that serve various semantic functions.
48Each field starts with an
49identifying label at the beginning of a line, followed by the
50.Qq \&:
51character and the field's contents.
52There can be at most one field per line.
53.Pp
54A field may be continued over more than one line by indenting
55subsequent lines with at least one ASCII SPACE or TAB character.
56Whitespace (a SPACE, TAB, or NEWLINE character) separates tokens but
57is otherwise ignored outside of quoted strings.
58Comments with a leading octothorp character ('#') may begin in any column.
59.Pp
60One mandatory field is required in all assertions: Authorizer.
61.Pp
62Six optional fields may also appear: Comment, Conditions,
63KeyNote-Version, Licensees, Local-Constants, Signature.
64.Pp
65All field names are case-insensitive.
66The
67.Qq KeyNote-Version
68field, if present, appears first.
69The
70.Qq Signature
71field, if present, appears last.
72Otherwise, fields may appear in any order.
73Each field may appear at most once in any assertion.
74.Pp
75Blank lines are not permitted in assertions.
76Multiple assertions
77stored in a file (e.g., in application policy configurations),
78therefore, can be separated from one another unambiguously by the use
79of blank lines between them.
80.Sh COMMENTS
81The octothorp character
82.Pf ( Ns Qo # Qc ,
83ASCII 35 decimal) can be used to
84introduce comments.
85Outside of quoted strings, all characters from the
86.Qq #
87character through the end of the current line are ignored.
88However, commented text is included in the computation of assertion
89signatures.
90.Sh STRINGS
91A
92.Sq string
93is a lexical object containing a sequence of characters.
94Strings may contain any non-NUL characters, including newlines and
95nonprintable characters.
96Strings may be given as literals, computed from complex expressions,
97or dereferenced from attribute names.
98.Sh STRING LITERALS
99A string literal directly represents the value of a string.
100String literals must be quoted by preceding and following them with the
101double-quote character (ASCII 34 decimal).
102.Pp
103A printable character may be
104.Sq escaped
105inside a quoted string literal by preceding it with the backslash
106character (ASCII 92 decimal) (e.g.,
107.Qo like \&
108.No \e Ns Qo this Ns \e
109.Qc .
110.\".Pf { Qo mike Ns Qc 12
111.Qc Ns ).
112This permits the inclusion of the double-quote and backslash characters
113inside string literals.
114.Pp
115A similar escape mechanism is also used to represent non-printable
116characters.
117.Qq \en
118represents the newline character (ASCII character 10
119decimal),
120.Qq \er
121represents the carriage-return character (ASCII
122character 13 decimal),
123.Qq \et
124represents the tab character (ASCII character 9 decimal), and
125.Qq \ef
126represents the form-feed character (ASCII character 12 decimal).
127A backslash character followed by a newline suppresses all subsequent
128whitespace (including the newline) up to the next non-whitespace character
129(this allows the continuation of long string constants across lines).
130Un-escaped newline and return characters are illegal inside string literals.
131.Pp
132The constructs
133.Qq \e0o ,
134.Qq \e0oo ,
135and
136.Qq \eooo
137(where o represents any octal digit) may be used to represent any non-NUL
138ASCII characters with their corresponding octal values (thus,
139.Qq \e012
140is the same as
141.Qq \en ,
142.Qq \e101
143is
144.Qq A ,
145and
146.Qq \e377
147is the ASCII character 255 decimal).
148However, the NUL character cannot be encoded in this manner;
149.Qq \e0 ,
150.Qq \e00 ,
151and
152.Qq \e000
153are converted to the strings
154.Qq 0 ,
155.Qq 00 ,
156and
157.Qq 000
158respectively.
159Similarly, all other escaped characters have the
160leading backslash removed (e.g.,
161.Qq \ea
162becomes
163.Qq a ,
164and
165.Qq \e\e
166becomes
167.Qq \e ) .
168The following four strings are equivalent:
169.Bd -literal
170        "this string contains a newline\\n followed by one space."
171        "this string contains a newline\\n \\
172        followed by one space."
173        "this str\\
174           ing contains a \\
175             newline\\n followed by one space."
176        "this string contains a newline\\012\\040followed by one space."
177.Ed
178.Sh STRING EXPRESSIONS
179In general, anywhere a quoted string literal is allowed, a
180.Sq string expression
181can be used.
182A string expression constructs a string from string constants,
183dereferenced attributes (described below), and a string concatenation
184operator.
185String expressions may be parenthesized.
186.Bd -literal
187       <StrEx>:: <StrEx> "." <StrEx>    /* String concatenation */
188               | <StringLiteral>        /* Quoted string */
189               | "(" <StrEx> ")"
190               | <DerefAttribute>
191               | "$" <StrEx> ;
192.Ed
193.Pp
194The
195.Qq $
196operator has higher precedence than the
197.Qq .\&
198operator.
199.Sh DEREFERENCED ATTRIBUTES
200Action attributes provide the primary mechanism for applications to
201pass information to assertions.
202Attribute names are strings from a
203limited character set (see below), and attribute values are
204represented internally as strings.
205An attribute is dereferenced simply by using its name.
206In general, KeyNote allows the use of an attribute anywhere a string literal
207is permitted.
208.Pp
209Attributes are dereferenced as strings by default.
210When required,
211dereferenced attributes can be converted to integers or floating point
212numbers with the type conversion operators
213.Qq @
214and
215.Qq & .
216Thus, an attribute named
217.Qq foo
218having the value
219.Qq 1.2
220may be interpreted as the string
221.Qq 1.2
222(foo), the integer value 1 (@foo), or the floating point
223value 1.2 (&foo).
224.Pp
225Attributes converted to integer and floating point numbers are
226represented according to the ANSI C
227.Sq long
228and
229.Sq float
230types, respectively.
231In particular, integers range from -2147483648 to 2147483647, whilst floats
232range from 1.17549435E-38F to 3.40282347E+38F.
233.Pp
234Any uninitialized attribute has the empty-string value when
235dereferenced as a string and the value zero when dereferenced as an
236integer or float.
237.Pp
238Attribute names may be given literally or calculated from string
239expressions and may be recursively dereferenced.
240In the simplest case,
241an attribute is dereferenced simply by using its name outside of
242quotes; e.g., the string value of the attribute named
243.Qq foo
244is by reference to
245.Sq foo
246(outside of quotes).
247The
248.Qo $ Ns Ao StrEx
249.Ac
250.Qc
251construct dereferences the attribute named in the string expression
252.Aq StrEx .
253For example, if the attribute named
254.Qq foo
255contains the string
256.Qq bar ,
257the attribute named
258.Qq bar
259contains the string
260.Qq xyz ,
261and the attribute
262.Qq xyz
263contains the string
264.Qq qua ,
265the following string comparisons are all true:
266.Bd -literal
267    foo == "bar"
268    $("foo") == "bar"
269    $foo == "xyz"
270    $(foo) == "xyz"
271    $$foo == "qua"
272.Ed
273.Pp
274If
275.Aq StrEx
276evaluates to an invalid or uninitialized attribute name, its value is
277considered to be the empty string (or zero if used as a numeric).
278.Pp
279The
280.Aq DerefAttribute
281token is defined as:
282.Bd -literal
283      <DerefAttribute>:: <AttributeID> ;
284       <AttributeID>:: {Any string starting with a-z, A-Z, or the
285                        underscore character, followed by any number of
286                        a-z, A-Z, 0-9, or underscore characters} ;
287.Ed
288.Sh PRINCIPAL IDENTIFIERS
289Principals are represented as ASCII strings called
290.Sq Principal Identifiers .
291Principal Identifiers may be arbitrary labels whose structure is not
292interpreted by the KeyNote system or they may encode cryptographic keys
293that are used by KeyNote for credential signature verification.
294.Bd -literal
295       <PrincipalIdentifier>:: <OpaqueID>
296                             | <KeyID> ;
297.Ed
298.Sh OPAQUE PRINCIPAL IDENTIFIERS
299Principal Identifiers that are used by KeyNote only as labels are
300said to be
301.Sq opaque .
302Opaque identifiers are encoded in assertions as strings (as defined above):
303.Pp
304.Dl <OpaqueID>:: <StrEx>\ \&;
305.Pp
306Opaque identifier strings should not contain the
307.Qq \&:
308character.
309.Sh CRYPTOGRAPHIC PRINCIPAL IDENTIFIERS
310Principal Identifiers that are used by KeyNote as keys, e.g., to
311verify credential signatures, are said to be
312.Sq cryptographic .
313Cryptographic identifiers are also lexically encoded as strings:
314.Pp
315.Dl <KeyID>:: <StrEx>\ \&;
316.Pp
317Unlike Opaque Identifiers, however, Cryptographic Identifier strings
318have a special form.
319To be interpreted by KeyNote (for signature
320verification), an identifier string should be of the form:
321.Pp
322.Dl <IDString>:: <ALGORITHM>":"<ENCODEDBITS>\ \&;
323.Pp
324.Qq ALGORITHM
325is an ASCII substring that describes the algorithms to be
326used in interpreting the key's bits.
327The ALGORITHM identifies the major cryptographic algorithm (e.g., RSA
328.Bq RSA78 ,
329DSA
330.Bq DSA94 ,
331etc.),
332structured format (e.g., PKCS1
333.Bq PKCS1 ) ,
334and key bit encoding (e.g., HEX or BASE64).
335By convention, the ALGORITHM
336substring starts with an alphabetic character and can contain letters,
337digits, underscores, or dashes (i.e., it should match the regular expression
338.Qo Ns Bo a-zA-Z
339.Bc Ns Bo a-zA-Z0-9_-
340.Bc Ns *
341.Qc Ns ) .
342The IANA (or some other appropriate authority) will provide a registry of
343reserved algorithm identifiers.
344.Pp
345.Qq ENCODEDBITS
346is a substring of characters representing the key's bits, the encoding and
347format of which depends on the ALGORITHM.
348By convention, hexadecimal encoded keys use lower-case ASCII characters.
349.Pp
350Cryptographic Principal Identifiers are converted to a normalized
351canonical form for the purposes of any internal comparisons between
352them; see RFC 2704 for more details.
353.Sh KEYNOTE-VERSION FIELD
354The KeyNote-Version field identifies the version of the KeyNote
355assertion language under which the assertion was written.
356The KeyNote-Version field is of the form:
357.Bd -literal
358       <VersionField>:: "KeyNote-Version:" <VersionString> ;
359       <VersionString>:: <StringLiteral>
360                       | <IntegerLiteral> ;
361.Ed
362.Pp
363.Aq VersionString
364is an ASCII-encoded string.
365Assertions in production versions of KeyNote use decimal digits in the version
366representing the version number of the KeyNote language under which they are
367to be interpreted.
368Assertions written to conform with this document should be identified with the
369version string
370.Qq 2
371(or the integer 2).
372The KeyNote-Version field, if included, should appear first.
373.Sh LOCAL-CONSTANTS FIELD
374This field adds or overrides action attributes in the current
375assertion only.
376This mechanism allows the use of short names for (frequently lengthy)
377cryptographic principal identifiers, especially to make the Licensees field
378more readable.
379The Local-Constants field is of the form:
380.Bd -literal
381       <LocalConstantsField>:: "Local-Constants:" <Assignments> ;
382       <Assignments>:: /* can be empty */
383                     | <AttributeID> "=" <StringLiteral> <Assignments> ;
384.Ed
385.Pp
386.Aq AttributeID
387is an attribute name from the action attribute namespace.
388The name is available for use as an attribute in any subsequent field.
389If the Local-Constants field defines more than one identifier, it can occupy
390more than one line and be indented.
391.Aq StringLiteral
392is a string literal as described previously.
393Attributes defined in the Local-Constants field override any attributes with
394the same name passed in with the action attribute set.
395.Pp
396An attribute may be initialized at most once in the Local-Constants field.
397If an attribute is initialized more than once in an assertion, the entire
398assertion is considered invalid and is not considered by the KeyNote
399compliance checker in evaluating queries.
400.Sh AUTHORIZER FIELD
401The Authorizer identifies the Principal issuing the assertion.
402This field is of the form:
403.Bd -literal
404       <AuthField>:: "Authorizer:" <AuthID> ;
405       <AuthID>:: <PrincipalIdentifier>
406                | <DerefAttribute> ;
407.Ed
408.Pp
409The Principal Identifier may be given directly or by reference to the
410attribute namespace.
411.Sh LICENSEES FIELD
412The Licensees field identifies the principals authorized by the
413assertion.
414More than one principal can be authorized, and authorization can be
415distributed across several principals through the use of
416.Sq and
417and threshold constructs.
418This field is of the form:
419.Bd -literal
420       <LicenseesField>:: "Licensees:" <LicenseesExpr> ;
421
422       <LicenseesExpr>::      /* can be empty */
423                         | <PrincExpr> ;
424
425       <PrincExpr>:: "(" <PrincExpr> ")"
426                     | <PrincExpr> "&&" <PrincExpr>
427                     | <PrincExpr> "||" <PrincExpr>
428                     | <K>"-of(" <PrincList> ")"        /* Threshold */
429                     | <PrincipalIdentifier>
430                     | <DerefAttribute> ;
431
432       <PrincList>:: <PrincipalIdentifier>
433                   | <DerefAttribute>
434                   | <PrincList> "," <PrincList> ;
435
436       <K>:: {Decimal number starting with a digit from 1 to 9} ;
437.Ed
438.Pp
439The
440.Qq &&
441operator has higher precedence than the
442.Qq ||
443operator.
444.Aq K
445is an ASCII-encoded positive decimal integer.
446If a
447.Aq PrincList
448contains fewer than
449.Aq K
450principals, the entire assertion is omitted from processing.
451.Sh CONDITIONS FIELD
452This field gives the
453.Sq conditions
454under which the Authorizer trusts the Licensees to perform an action.
455.Sq Conditions
456are predicates that operate on the action attribute set.
457The Conditions field is of the form:
458.Bd -literal
459    <ConditionsField>:: "Conditions:" <ConditionsProgram> ;
460
461    <ConditionsProgram>:: /* Can be empty */
462                          | <Clause> ";" <ConditionsProgram> ;
463
464    <Clause>:: <Test> "->" "{" <ConditionsProgram> "}"
465             | <Test> "->" <Value>
466             | <Test> ;
467
468    <Value>:: <StrEx> ;
469
470    <Test>:: <RelExpr> ;
471
472    <RelExpr>:: "(" <RelExpr> ")"        /* Parentheses */
473              | <RelExpr> "&&" <RelExpr> /* Logical AND */
474              | <RelExpr> "||" <RelExpr> /* Logical OR */
475              | "!" <RelExpr>         /* Logical NOT */
476              | <IntRelExpr>
477              | <FloatRelExpr>
478              | <StringRelExpr>
479              | "true"        /* case insensitive */
480              | "false" ;     /* case insensitive */
481
482    <IntRelExpr>:: <IntEx> "==" <IntEx>
483                 | <IntEx> "!=" <IntEx>
484                 | <IntEx> "<" <IntEx>
485                 | <IntEx> ">" <IntEx>
486                 | <IntEx> "<=" <IntEx>
487                 | <IntEx> ">=" <IntEx> ;
488
489    <FloatRelExpr>:: <FloatEx> "<" <FloatEx>
490                   | <FloatEx> ">" <FloatEx>
491                   | <FloatEx> "<=" <FloatEx>
492                   | <FloatEx> ">=" <FloatEx> ;
493
494    <StringRelExpr>:: <StrEx> "==" <StrEx>  /* String equality */
495                    | <StrEx> "!=" <StrEx>  /* String inequality */
496                    | <StrEx> "<" <StrEx>   /* Alphanum. comparisons */
497                    | <StrEx> ">" <StrEx>
498                    | <StrEx> "<=" <StrEx>
499                    | <StrEx> ">=" <StrEx>
500                    | <StrEx> "~=" <RegExpr> ; /* Reg. expr. matching */
501
502    <IntEx>:: <IntEx> "+" <IntEx>        /* Integer */
503            | <IntEx> "-" <IntEx>
504            | <IntEx> "*" <IntEx>
505            | <IntEx> "/" <IntEx>
506            | <IntEx> "%" <IntEx>
507            | <IntEx> "^" <IntEx>        /* Exponentiation */
508            | "-" <IntEx>
509            | "(" <IntEx> ")"
510            | <IntegerLiteral>
511            | "@" <StrEx> ;
512
513    <FloatEx>:: <FloatEx> "+" <FloatEx>  /* Floating point */
514              | <FloatEx> "-" <FloatEx>
515              | <FloatEx> "*" <FloatEx>
516              | <FloatEx> "/" <FloatEx>
517              | <FloatEx> "^" <FloatEx> /* Exponentiation */
518              | "-" <FloatEx>
519              | "(" <FloatEx> ")"
520              | <FloatLiteral>
521              | "&" <StrEx> ;
522
523    <IntegerLiteral>:: {Decimal number of at least one digit} ;
524    <FloatLiteral>:: <IntegerLiteral>"."<IntegerLiteral> ;
525
526    <StringLiteral> is a quoted string as defined in previously
527    <AttributeID> is defined previously.
528.Ed
529.Pp
530The operation precedence classes are (from highest to lowest):
531.Bd -literal
532        { (, ) }
533        {unary -, @, &, $}
534        {^}
535        {*, /, %}
536        {+, -, .}
537.Ed
538.Pp
539Operators in the same precedence class are evaluated left-to-right.
540.Pp
541Note the inability to test for floating point equality, as most
542floating point implementations (hardware or otherwise) do not
543guarantee accurate equality testing.
544.Pp
545Also note that integer and floating point expressions can only be used
546within clauses of condition fields, but in no other KeyNote field.
547.Pp
548The keywords
549.Qq true
550and
551.Qq false
552are not reserved; they can be used as attribute or principal identifier
553names (although this practice makes assertions difficult to understand
554and is discouraged).
555.Pp
556.Aq RegExpr
557is a standard regular expression, conforming to the
558.St -p1003.2
559regular expression syntax and semantics (see
560.Xr regex 3 ) .
561.Pp
562Any string expression (or attribute) containing the ASCII
563representation of a numeric value can be converted to an integer or
564float with the use of the
565.Qq @
566and
567.Qq &
568operators, respectively.
569Any fractional component of an attribute value dereferenced as an integer
570is rounded down.
571If an attribute dereferenced as a number cannot be properly converted
572(e.g., it contains invalid characters or is empty) its value is considered
573to be zero.
574.Sh COMMENT FIELD
575The Comment field allows assertions to be annotated with information
576describing their purpose.
577It is of the form:
578.Pp
579.Dl <CommentField>:: \&"Comment:\&" <text>\ \&;
580.Pp
581No interpretation of the contents of this field is performed by
582KeyNote.
583Note that this is one of two mechanisms for including
584comments in KeyNote assertions; comments can also be inserted anywhere
585in an assertion's body by preceding them with the
586.Qq #
587character (except inside string literals).
588.Sh SIGNATURE FIELD
589The Signature field identifies a signed assertion and gives the
590encoded digital signature of the principal identified in the
591Authorizer field.
592The Signature field is of the form:
593.Bd -literal
594       <SignatureField>:: "Signature:" <Signature> ;
595       <Signature>:: <StrEx> ;
596.Ed
597.Pp
598The <Signature> string should be of the form:
599.Pp
600.Dl <IDString>:: <ALGORITHM>":"<ENCODEDBITS>\ \&;
601.Pp
602The formats of the
603.Qq ALGORITHM
604and
605.Qq ENCODEDBITS
606substrings are as described for Cryptographic Principal Identifiers.
607The algorithm name should be the same as that of the principal appearing
608in the Authorizer field.
609The IANA (or some other suitable authority) will provide a registry of
610reserved names.
611It is not necessary that the encodings of the signature and the authorizer
612key be the same.
613.Pp
614If the signature field is included, the principal named in the
615Authorizer field must be a Cryptographic Principal Identifier, the
616algorithm must be known to the KeyNote implementation, and the
617signature must be correct for the assertion body and authorizer key.
618.Pp
619The signature is computed over the assertion text, beginning with the
620first field (including the field identifier string), up to (but not
621including) the Signature field identifier.
622The newline preceding the signature field identifier is the last character
623included in signature calculation.
624The signature is always the last field in a KeyNote assertion.
625Text following this field is not considered part of the assertion.
626.Sh EXAMPLES
627Note that the keys and signatures in these examples are fictional, and
628generally much shorter than would be required for real security, in
629the interest of readability.
630.Bd -literal
631           Authorizer: "POLICY"
632           Licensees: "RSA:abc123"
633
634           KeyNote-Version: 2
635           Local-Constants: Alice="DSA:4401ff92"  # Alice's key
636                            Bob="RSA:d1234f"      # Bob's key
637           Authorizer: "RSA:abc123"
638           Licensees: Alice || Bob
639           Conditions: (app_domain == "RFC822-EMAIL") &&
640                       (address ~=   # only applies to one domain
641                         "^.*@keynote\\.research\\.att\\.com$") ->
642			"true";
643           Signature: "RSA-SHA1:213354f9"
644
645           KeyNote-Version: 2
646           Authorizer: "DSA:4401ff92"  # the Alice CA
647           Licensees: "DSA:12340987"   # mab's key
648           Conditions: ((app_domain == "RFC822-EMAIL") -> {
649	                        (name == "M. Blaze" || name == "") &&
650		                (address ==
651                                    "mab@keynote.research.att.com"));
652				(name == "anonymous") -> "logandaccept";
653			}
654
655           Signature: "DSA-SHA1:ab23487"
656
657           KeyNote-Version: "2"
658           Authorizer: "DSA:4401ff92"   # the Alice CA
659           Licensees: "DSA:abc991" ||   # jf's DSA key
660                      "RSA:cde773" ||   # jf's RSA key
661                      "BFIK:fd091a"     # jf's BFIK key
662           Conditions: ((app_domain == "RFC822-EMAIL") &&
663                        (name == "J. Feigenbaum" || name == "") &&
664                        (address == "jf@keynote.research.att.com"));
665           Signature: "DSA-SHA1:8912aa"
666.Ed
667.Sh SEE ALSO
668.Xr keynote 1 ,
669.Xr keynote 3 ,
670.Xr keynote 4
671.Rs
672.%A M. Blaze
673.%A J. Feigenbaum
674.%A A. D. Keromytis
675.%T "The KeyNote Trust-Management System, Version 2"
676.%N RFC 2704
677.%D 1999
678.Re
679.Rs
680.%A M. Blaze
681.%A J. Feigenbaum
682.%A J. Lacy
683.%T Decentralized Trust Management
684.%J IEEE Conference on Privacy and Security
685.%D 1996
686.Re
687.Rs
688.%A M. Blaze
689.%A J. Feigenbaum
690.%A M. Strauss
691.%T Compliance-Checking in the PolicyMaker Trust Management System
692.%J Financial Crypto Conference
693.%D 1998
694.Re
695.Sh AUTHORS
696.An Angelos D. Keromytis Aq angelos@cs.columbia.edu
697.Sh WEB PAGE
698.Pa http://www1.cs.columbia.edu/~angelos/keynote.html
699.Sh BUGS
700None that we know of.
701If you find any, please report them at
702.Dl Aq keynote@research.att.com
703