xref: /openbsd/lib/libkeynote/keynote.5 (revision 09467b48)
1.\" $OpenBSD: keynote.5,v 1.25 2015/11/20 16:31:05 mmcc 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: November 20 2015 $
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 ( Sq # ,
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 .
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\en followed by one space."
171        "this string contains a newline\en \e
172        followed by one space."
173        "this str\e
174           ing contains a \e
175             newline\en followed by one space."
176        "this string contains a newline\e012\e040followed 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.Qq Bo a-zA-Z Bc Ns Bo a-zA-Z0-9_- Bc Ns * .
339The IANA (or some other appropriate authority) will provide a registry of
340reserved algorithm identifiers.
341.Pp
342.Qq ENCODEDBITS
343is a substring of characters representing the key's bits, the encoding and
344format of which depends on the ALGORITHM.
345By convention, hexadecimal encoded keys use lower-case ASCII characters.
346.Pp
347Cryptographic Principal Identifiers are converted to a normalized
348canonical form for the purposes of any internal comparisons between
349them; see RFC 2704 for more details.
350.Sh KEYNOTE-VERSION FIELD
351The KeyNote-Version field identifies the version of the KeyNote
352assertion language under which the assertion was written.
353The KeyNote-Version field is of the form:
354.Bd -literal
355       <VersionField>:: "KeyNote-Version:" <VersionString> ;
356       <VersionString>:: <StringLiteral>
357                       | <IntegerLiteral> ;
358.Ed
359.Pp
360.Aq VersionString
361is an ASCII-encoded string.
362Assertions in production versions of KeyNote use decimal digits in the version
363representing the version number of the KeyNote language under which they are
364to be interpreted.
365Assertions written to conform with this document should be identified with the
366version string
367.Qq 2
368(or the integer 2).
369The KeyNote-Version field, if included, should appear first.
370.Sh LOCAL-CONSTANTS FIELD
371This field adds or overrides action attributes in the current
372assertion only.
373This mechanism allows the use of short names for (frequently lengthy)
374cryptographic principal identifiers, especially to make the Licensees field
375more readable.
376The Local-Constants field is of the form:
377.Bd -literal
378       <LocalConstantsField>:: "Local-Constants:" <Assignments> ;
379       <Assignments>:: /* can be empty */
380                     | <AttributeID> "=" <StringLiteral> <Assignments> ;
381.Ed
382.Pp
383.Aq AttributeID
384is an attribute name from the action attribute namespace.
385The name is available for use as an attribute in any subsequent field.
386If the Local-Constants field defines more than one identifier, it can occupy
387more than one line and be indented.
388.Aq StringLiteral
389is a string literal as described previously.
390Attributes defined in the Local-Constants field override any attributes with
391the same name passed in with the action attribute set.
392.Pp
393An attribute may be initialized at most once in the Local-Constants field.
394If an attribute is initialized more than once in an assertion, the entire
395assertion is considered invalid and is not considered by the KeyNote
396compliance checker in evaluating queries.
397.Sh AUTHORIZER FIELD
398The Authorizer identifies the Principal issuing the assertion.
399This field is of the form:
400.Bd -literal
401       <AuthField>:: "Authorizer:" <AuthID> ;
402       <AuthID>:: <PrincipalIdentifier>
403                | <DerefAttribute> ;
404.Ed
405.Pp
406The Principal Identifier may be given directly or by reference to the
407attribute namespace.
408.Sh LICENSEES FIELD
409The Licensees field identifies the principals authorized by the
410assertion.
411More than one principal can be authorized, and authorization can be
412distributed across several principals through the use of
413.Sq and
414and threshold constructs.
415This field is of the form:
416.Bd -literal
417       <LicenseesField>:: "Licensees:" <LicenseesExpr> ;
418
419       <LicenseesExpr>::      /* can be empty */
420                         | <PrincExpr> ;
421
422       <PrincExpr>:: "(" <PrincExpr> ")"
423                     | <PrincExpr> "&&" <PrincExpr>
424                     | <PrincExpr> "||" <PrincExpr>
425                     | <K>"-of(" <PrincList> ")"        /* Threshold */
426                     | <PrincipalIdentifier>
427                     | <DerefAttribute> ;
428
429       <PrincList>:: <PrincipalIdentifier>
430                   | <DerefAttribute>
431                   | <PrincList> "," <PrincList> ;
432
433       <K>:: {Decimal number starting with a digit from 1 to 9} ;
434.Ed
435.Pp
436The
437.Qq &&
438operator has higher precedence than the
439.Qq ||
440operator.
441.Aq K
442is an ASCII-encoded positive decimal integer.
443If a
444.Aq PrincList
445contains fewer than
446.Aq K
447principals, the entire assertion is omitted from processing.
448.Sh CONDITIONS FIELD
449This field gives the
450.Sq conditions
451under which the Authorizer trusts the Licensees to perform an action.
452.Sq Conditions
453are predicates that operate on the action attribute set.
454The Conditions field is of the form:
455.Bd -literal
456    <ConditionsField>:: "Conditions:" <ConditionsProgram> ;
457
458    <ConditionsProgram>:: /* Can be empty */
459                          | <Clause> ";" <ConditionsProgram> ;
460
461    <Clause>:: <Test> "->" "{" <ConditionsProgram> "}"
462             | <Test> "->" <Value>
463             | <Test> ;
464
465    <Value>:: <StrEx> ;
466
467    <Test>:: <RelExpr> ;
468
469    <RelExpr>:: "(" <RelExpr> ")"        /* Parentheses */
470              | <RelExpr> "&&" <RelExpr> /* Logical AND */
471              | <RelExpr> "||" <RelExpr> /* Logical OR */
472              | "!" <RelExpr>         /* Logical NOT */
473              | <IntRelExpr>
474              | <FloatRelExpr>
475              | <StringRelExpr>
476              | "true"        /* case insensitive */
477              | "false" ;     /* case insensitive */
478
479    <IntRelExpr>:: <IntEx> "==" <IntEx>
480                 | <IntEx> "!=" <IntEx>
481                 | <IntEx> "<" <IntEx>
482                 | <IntEx> ">" <IntEx>
483                 | <IntEx> "<=" <IntEx>
484                 | <IntEx> ">=" <IntEx> ;
485
486    <FloatRelExpr>:: <FloatEx> "<" <FloatEx>
487                   | <FloatEx> ">" <FloatEx>
488                   | <FloatEx> "<=" <FloatEx>
489                   | <FloatEx> ">=" <FloatEx> ;
490
491    <StringRelExpr>:: <StrEx> "==" <StrEx>  /* String equality */
492                    | <StrEx> "!=" <StrEx>  /* String inequality */
493                    | <StrEx> "<" <StrEx>   /* Alphanum. comparisons */
494                    | <StrEx> ">" <StrEx>
495                    | <StrEx> "<=" <StrEx>
496                    | <StrEx> ">=" <StrEx>
497                    | <StrEx> "~=" <RegExpr> ; /* Reg. expr. matching */
498
499    <IntEx>:: <IntEx> "+" <IntEx>        /* Integer */
500            | <IntEx> "-" <IntEx>
501            | <IntEx> "*" <IntEx>
502            | <IntEx> "/" <IntEx>
503            | <IntEx> "%" <IntEx>
504            | <IntEx> "^" <IntEx>        /* Exponentiation */
505            | "-" <IntEx>
506            | "(" <IntEx> ")"
507            | <IntegerLiteral>
508            | "@" <StrEx> ;
509
510    <FloatEx>:: <FloatEx> "+" <FloatEx>  /* Floating point */
511              | <FloatEx> "-" <FloatEx>
512              | <FloatEx> "*" <FloatEx>
513              | <FloatEx> "/" <FloatEx>
514              | <FloatEx> "^" <FloatEx> /* Exponentiation */
515              | "-" <FloatEx>
516              | "(" <FloatEx> ")"
517              | <FloatLiteral>
518              | "&" <StrEx> ;
519
520    <IntegerLiteral>:: {Decimal number of at least one digit} ;
521    <FloatLiteral>:: <IntegerLiteral>"."<IntegerLiteral> ;
522
523    <StringLiteral> is a quoted string as defined in previously
524    <AttributeID> is defined previously.
525.Ed
526.Pp
527The operation precedence classes are (from highest to lowest):
528.Bd -literal
529        { (, ) }
530        {unary -, @, &, $}
531        {^}
532        {*, /, %}
533        {+, -, .}
534.Ed
535.Pp
536Operators in the same precedence class are evaluated left-to-right.
537.Pp
538Note the inability to test for floating point equality, as most
539floating point implementations (hardware or otherwise) do not
540guarantee accurate equality testing.
541.Pp
542Also note that integer and floating point expressions can only be used
543within clauses of condition fields, but in no other KeyNote field.
544.Pp
545The keywords
546.Qq true
547and
548.Qq false
549are not reserved; they can be used as attribute or principal identifier
550names (although this practice makes assertions difficult to understand
551and is discouraged).
552.Pp
553.Aq RegExpr
554is a standard regular expression, conforming to the
555.St -p1003.2
556regular expression syntax and semantics (see
557.Xr regex 3 ) .
558.Pp
559Any string expression (or attribute) containing the ASCII
560representation of a numeric value can be converted to an integer or
561float with the use of the
562.Qq @
563and
564.Qq &
565operators, respectively.
566Any fractional component of an attribute value dereferenced as an integer
567is rounded down.
568If an attribute dereferenced as a number cannot be properly converted
569(e.g., it contains invalid characters or is empty) its value is considered
570to be zero.
571.Sh COMMENT FIELD
572The Comment field allows assertions to be annotated with information
573describing their purpose.
574It is of the form:
575.Pp
576.Dl <CommentField>:: \&"Comment:\&" <text>\ \&;
577.Pp
578No interpretation of the contents of this field is performed by
579KeyNote.
580Note that this is one of two mechanisms for including
581comments in KeyNote assertions; comments can also be inserted anywhere
582in an assertion's body by preceding them with the
583.Qq #
584character (except inside string literals).
585.Sh SIGNATURE FIELD
586The Signature field identifies a signed assertion and gives the
587encoded digital signature of the principal identified in the
588Authorizer field.
589The Signature field is of the form:
590.Bd -literal
591       <SignatureField>:: "Signature:" <Signature> ;
592       <Signature>:: <StrEx> ;
593.Ed
594.Pp
595The <Signature> string should be of the form:
596.Pp
597.Dl <IDString>:: <ALGORITHM>":"<ENCODEDBITS>\ \&;
598.Pp
599The formats of the
600.Qq ALGORITHM
601and
602.Qq ENCODEDBITS
603substrings are as described for Cryptographic Principal Identifiers.
604The algorithm name should be the same as that of the principal appearing
605in the Authorizer field.
606The IANA (or some other suitable authority) will provide a registry of
607reserved names.
608It is not necessary that the encodings of the signature and the authorizer
609key be the same.
610.Pp
611If the signature field is included, the principal named in the
612Authorizer field must be a Cryptographic Principal Identifier, the
613algorithm must be known to the KeyNote implementation, and the
614signature must be correct for the assertion body and authorizer key.
615.Pp
616The signature is computed over the assertion text, beginning with the
617first field (including the field identifier string), up to (but not
618including) the Signature field identifier.
619The newline preceding the signature field identifier is the last character
620included in signature calculation.
621The signature is always the last field in a KeyNote assertion.
622Text following this field is not considered part of the assertion.
623.Sh EXAMPLES
624Note that the keys and signatures in these examples are fictional, and
625generally much shorter than would be required for real security, in
626the interest of readability.
627.Bd -literal
628           Authorizer: "POLICY"
629           Licensees: "RSA:abc123"
630
631           KeyNote-Version: 2
632           Local-Constants: Alice="DSA:4401ff92"  # Alice's key
633                            Bob="RSA:d1234f"      # Bob's key
634           Authorizer: "RSA:abc123"
635           Licensees: Alice || Bob
636           Conditions: (app_domain == "RFC822-EMAIL") &&
637                       (address ~=   # only applies to one domain
638                         "^.*@keynote\e.research\e.att\e.com$") ->
639			"true";
640           Signature: "RSA-SHA1:213354f9"
641
642           KeyNote-Version: 2
643           Authorizer: "DSA:4401ff92"  # the Alice CA
644           Licensees: "DSA:12340987"   # mab's key
645           Conditions: ((app_domain == "RFC822-EMAIL") -> {
646	                        (name == "M. Blaze" || name == "") &&
647		                (address ==
648                                    "mab@keynote.research.att.com"));
649				(name == "anonymous") -> "logandaccept";
650			}
651
652           Signature: "DSA-SHA1:ab23487"
653
654           KeyNote-Version: "2"
655           Authorizer: "DSA:4401ff92"   # the Alice CA
656           Licensees: "DSA:abc991" ||   # jf's DSA key
657                      "RSA:cde773" ||   # jf's RSA key
658                      "BFIK:fd091a"     # jf's BFIK key
659           Conditions: ((app_domain == "RFC822-EMAIL") &&
660                        (name == "J. Feigenbaum" || name == "") &&
661                        (address == "jf@keynote.research.att.com"));
662           Signature: "DSA-SHA1:8912aa"
663.Ed
664.Sh SEE ALSO
665.Xr keynote 1 ,
666.Xr keynote 3 ,
667.Xr keynote 4
668.Rs
669.%A M. Blaze
670.%A J. Feigenbaum
671.%A J. Lacy
672.%D 1996
673.%J IEEE Symposium on Security and Privacy
674.%T Decentralized Trust Management
675.Re
676.Rs
677.%A M. Blaze
678.%A J. Feigenbaum
679.%A M. Strauss
680.%D 1998
681.%J Financial Crypto Conference
682.%T Compliance-Checking in the PolicyMaker Trust Management System
683.Re
684.Sh STANDARDS
685.Rs
686.%A M. Blaze
687.%A J. Feigenbaum
688.%A J. Ioannidis
689.%A A. Keromytis
690.%D September 1999
691.%R RFC 2704
692.%T The KeyNote Trust-Management System Version 2
693.Re
694.Sh AUTHORS
695.An Angelos D. Keromytis Aq Mt angelos@cs.columbia.edu
696.Sh WEB PAGE
697.Lk http://www1.cs.columbia.edu/~angelos/keynote.html
698