/ story-21-Composing-Algorithm-Operations.org
story-21-Composing-Algorithm-Operations.org
  1  #+TITLE: Story 21 - Composing Algorithm Operations
  2  #+AUTHOR: Le’
  3  #+OPTIONS: date:nil
  4  #+LANGUAGE: en
  5  #+CATEGORY: lesec
  6  
  7  So far, algorithm operations are set up by name, and the responsibility
  8  to provide composite algorithms (AES-CBC, HMAC-SHA256, or more complex
  9  compositions like AES-GCM-SHA256) lies entirely on the plugin, thereby
 10  presenting them as individual implementations.
 11  
 12  This is, of course, perfectly legitimate, and even sensible from the point of
 13  view that each algorithm composition is essentially a new algorithm.  This is
 14  also encouraged by the way algorithms are specified with OIDs in the protocols
 15  that are governed by ASN.1 structures, as well as TLS.
 16  
 17  However, this doesn't lend itself very well for plugins that only supplies
 18  simple algorithms and expect them to be combined with others, or for the user
 19  to experiment with new combinations that plugin authors haven't implemented.
 20  This also opens the possibility to combine implementations from different
 21  plugins without the plugin having to be aware of that[fn:: Plugins can still
 22  refuse to work with other plugins, if they prefer.  This is feasible for a
 23  FIPS plugin, since they must be entirely self contained]
 24  
 25  Is this possible to remedy?  It should be, right?
 26  
 27  I've been thinking for a while that this should be possible to specify with a
 28  minilanguage of some sort.
 29  
 30  This idea is "higher level" and therefore belongs in Le'Sec, not in Le'Sec
 31  Core.
 32  
 33  * A proposed syntax
 34  
 35  The composite algorithm specification should be a simple string, and must be
 36  possible to pass around as such.  This syntax uses delimiters that are typical
 37  for function calls, thereby implying that each algorithm is a function that
 38  uses other components, such as other algorithms.
 39  
 40  Example strings:
 41  
 42  - ~hmac(hash=sha1)~ or possibly ~hmac(sha1)~
 43  - ~cbc(cipher=aes,iv=0x123456789ABCDEF)~ or possibly ~cbc(aes,iv=0x123456789ABCDEF)~
 44  - ~gcm(cipher=cbc(cipher=aes),hash=sha256)~ or possibly ~gcm(cbc(aes),sha256)~
 45  - ~gcm(cipher=aes-cbc,hash=sha256)~ or possibly ~gcm(aes-cbc,sha256)~
 46  
 47  Syntax specification in [[https://datatracker.ietf.org/doc/html/rfc5234][IETF ABNF]] form:
 48  
 49  #+begin_src abnf
 50    ; |name| is undefined here, pending a more proper definition in another story.
 51    ; Essentially, it's assumed to be a sequence of character that won't confuse this
 52    ; grammar.  It's further assumed that if the name contains any of the characters
 53    ; "<", ">", "[", "]", "{", "}", "(", ")", they are balanced.
 54  
 55    algo    = name
 56            / ( name "(" args ")" )
 57  
 58    args    = keyarg *( "," keyarg )              ; one or more keyargs
 59            / arg *( "," arg ) *( "," keyarg )    ; one or more args + keyargs
 60    arg     = algo                                ; positional argument (see below)
 61    keyarg  = ( name "=" value )                  ; keyword argument    (see below)
 62  
 63    value   = algo
 64            / number
 65            / string
 66  
 67    number  = 1*DIGIT                             ; must not start with zero
 68            / ( "0b" 1*BIT )                      ; binary number
 69            / ( "0o" 1*DIGIT )                    ; only octal digits allowed
 70            / ( "0x" 1*HEXDIG )
 71    string  = %x22 *( WSP / VCHAR ) %x22          ; double quoted string
 72            / %x27 *( WSP / VCHAR ) %x27          ; single quoted string
 73  #+end_src
 74  
 75  * Implementation
 76  
 77  Le'Sec already has functionality to make operator objects, for example:
 78  
 79  #+begin_src C
 80    LESEC_EXPORT LE_STATUS
 81    LeSec_make_encryptor(const char *id,
 82                         LeSec_find_encryptor_implementation_filter_fn *fn,
 83                         void *user_arg,
 84                         LeSec_encryptor_t **kp,
 85                         LeSec_env_t *env);
 86  #+end_src
 87  
 88  Functions like that can be refactored to parse the the specification above and
 89  compose the final algorithm on behalf of the caller.
 90  
 91  ** How to handle arguments
 92  
 93  In this composite algorithm syntax specification, the "arguments" must be
 94  passed to the algorithm they are given for.  One way to do this is to pass
 95  them as ~LSC_param_t~ parameters.
 96  
 97  Keyword arguments should look up the keyword in a settable parameter description
 98  to find out how to specify the parameter.
 99  
100  Positional arguments should look up the parameter index that corresponds to
101  its position to find out how to specify the parameter, where the first
102  position gets parameter index 1, the second position 2, etc.
103  
104  The parameter descriptor for each argument value must be compatible with that
105  argument value.  If there are ambiguities, the parameter descriptor governs
106  the acceptable argument value, not the other way around, making it possible to
107  have an algorithm named ~0xdeadbeef~.
108  
109  Names are a bit special, as they could be passed as a string parameter
110  (~LSC_DT_utf8_string~), or as an operator object (~LSC_DT_object~).  Again,
111  this is governed by the parameter descriptor, and then leaves it to the plugin
112  to decide what to do with them.
113  
114  * What about keys?
115  
116  In the discussion above on specifying composite algorithms, not one word has
117  been said about keys.  After all, it wouldn't be /entirely/ strange to specify
118  something like this:
119  
120  ~cbc(aes(key=0x000102030405060708090a0b0c0d0e0f),iv=0x123456789ABCDEF)~
121  
122  However, this isn't quite that easy to reconcile with current structures, and
123  becomes even more confusing with something like this:
124  
125  ~cmac(aes(key=0x000102030405060708090a0b0c0d0e0f))~
126  
127  ~cmac(aes,key=0x000102030405060708090a0b0c0d0e0f)~
128  
129  Is the key an AES key or a CMAC-AES key?  This is a point of view that could
130  affect how it's passed down to the plugin, and how it's handled by the plugin,
131  and may make it too easy for the user to do bad things (shoot themselves in
132  the foot).
133  
134  Because of this uncertainty, I'm making a choice not to involve the key in the
135  composite algorithm specification and leave it to be specified separately.
136  The user will have to interact with the cretaed operation object to find out
137  what sort of key it must create, leaving the rest to the plugin.
138  
139  This emphasise: *each implementation to which it's feasible to give a key must
140  be able to take a key, even if the implementation just passes it along to
141  another implementation.*
142  
143  Each implementation will therefore also have to specify the correct key id.
144  If the key is governed by another implementation, it is that implementation's
145  key id that must be passed back to the caller.